2 WARNING - Do not remove this header.
4 This code is a templated version of the 'magic-software' spherical
5 interpolation code by Dave Eberly. The original (un-hacked) code can be
6 obtained from here: http://www.magic-software.com/gr_appr.htm
7 This code is derived from linintp2.h/cpp and sphrintp.h/cpp.
9 Dave Eberly says that the conditions for use are:
11 * You may distribute the original source code to others at no charge.
13 * You may modify the original source code and distribute it to others at
14 no charge. The modified code must be documented to indicate that it is
15 not part of the original package.
17 * You may use this code for non-commercial purposes. You may also
18 incorporate this code into commercial packages. However, you may not
19 sell any of your source code which contains my original and/or modified
20 source code. In such a case, you need to factor out my code and freely
23 * The original code comes with absolutely no warranty and no guarantee is
24 made that the code is bug-free.
26 This does not seem incompatible with GPL - so this modified version
27 is hereby placed under GPL along with the rest of FlightGear.
32 #include <simgear/compiler.h>
40 SG_USING_NAMESPACE(std);
43 //---------------------------------------------------------------------------
44 mgcLinInterp2D::mgcLinInterp2D (int _numPoints, double* x, double* y,
47 if ( (numPoints = _numPoints) < 3 )
56 SG_LOG(SG_MATH, SG_DEBUG, "[ 20%] allocating memory");
58 point = new double*[numPoints];
59 tmppoint = new double*[numPoints+3];
60 f = new unsigned int[numPoints];
62 for (i = 0; i < numPoints; i++)
63 point[i] = new double[2];
64 for (i = 0; i < numPoints+3; i++)
65 tmppoint[i] = new double[2];
66 for (i = 0; i < numPoints; i++)
68 point[i][0] = tmppoint[i][0] = x[i];
69 point[i][1] = tmppoint[i][1] = y[i];
74 SG_LOG(SG_MATH, SG_DEBUG, "[ 30%] creating delaunay diagram");
78 //---------------------------------------------------------------------------
79 mgcLinInterp2D::~mgcLinInterp2D ()
88 for (i = 0; i < numPoints; i++)
94 for (i = 0; i < numPoints+3; i++)
103 //---------------------------------------------------------------------------
104 void mgcLinInterp2D::ComputeBarycenter (Vertex& v0, Vertex& v1, Vertex& v2,
105 Vertex& ver, double c[3])
107 double a0 = v0.x-v2.x;
108 double b0 = v0.y-v2.y;
109 double a1 = v1.x-v2.x;
110 double b1 = v1.y-v2.y;
111 double a2 = ver.x-v2.x;
112 double b2 = ver.y-v2.y;
114 double m00 = a0*a0+b0*b0;
115 double m01 = a0*a1+b0*b1;
116 double m11 = a1*a1+b1*b1;
117 double r0 = a2*a0+b2*b0;
118 double r1 = a2*a1+b2*b1;
119 double det = m00*m11-m01*m01;
121 c[0] = (m11*r0-m01*r1)/det;
122 c[1] = (m00*r1-m01*r0)/det;
125 //---------------------------------------------------------------------------
126 int mgcLinInterp2D::InTriangle (Vertex& v0, Vertex& v1, Vertex& v2,
129 const double eps = 1e-08;
130 double tx, ty, nx, ny;
132 // test against normal to first edge
137 if ( tx*nx + ty*ny < -eps )
140 // test against normal to second edge
145 if ( tx*nx + ty*ny < -eps )
148 // test against normal to third edge
153 if ( tx*nx + ty*ny < -eps )
158 //---------------------------------------------------------------------------
159 int mgcLinInterp2D::Evaluate (double x, double y, EvaluateData& F)
161 Vertex ver = { x, y };
162 // determine which triangle contains the target point
166 for (i = 0; i < numTriangles; i++)
168 Triangle& t = triangle[i];
169 v0.x = point[t.vertex[0]][0];
170 v0.y = point[t.vertex[0]][1];
171 v1.x = point[t.vertex[1]][0];
172 v1.y = point[t.vertex[1]][1];
173 v2.x = point[t.vertex[2]][0];
174 v2.y = point[t.vertex[2]][1];
176 if ( InTriangle(v0,v1,v2,ver) )
180 if ( i == numTriangles ) // point is outside interpolation region
185 Triangle& t = triangle[i]; // (x,y) is in this triangle
187 // compute barycentric coordinates with respect to subtriangle
189 ComputeBarycenter(v0,v1,v2,ver,bary);
191 // compute barycentric combination of function values at vertices
192 F.index[0] = f[t.vertex[0]];
193 F.index[1] = f[t.vertex[1]];
194 F.index[2] = f[t.vertex[2]];
195 F.percentage[0] = bary[0];
196 F.percentage[1] = bary[1];
197 F.percentage[2] = bary[2];
201 //---------------------------------------------------------------------------
202 int mgcLinInterp2D::Delaunay2D ()
206 const double EPSILON = 1e-12;
207 const int TSIZE = 75;
208 const double RANGE = 10.0;
210 xmin = tmppoint[0][0];
212 ymin = tmppoint[0][1];
216 for (i = 0; i < numPoints; i++)
218 double value = tmppoint[i][0];
224 value = tmppoint[i][1];
231 double xrange = xmax-xmin, yrange = ymax-ymin;
232 double maxrange = xrange;
233 if ( maxrange < yrange )
236 // need to scale the data later to do a correct triangle count
237 double maxrange2 = maxrange*maxrange;
239 // tweak the points by very small random numbers
240 double bgs = EPSILON*maxrange;
242 for (i = 0; i < numPoints; i++)
244 tmppoint[i][0] += bgs*(0.5 - rand()/double(RAND_MAX));
245 tmppoint[i][1] += bgs*(0.5 - rand()/double(RAND_MAX));
250 { 5*RANGE, -RANGE, -RANGE },
251 { -RANGE, 5*RANGE, -RANGE }
253 for (i = 0; i < 3; i++)
255 tmppoint[numPoints+i][0] = xmin+xrange*wrk[0][i];
256 tmppoint[numPoints+i][1] = ymin+yrange*wrk[1][i];
259 int i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i11;
264 int** tmp = new int*[tsz+1];
265 tmp[0] = new int[2*(tsz+1)];
266 for (i0 = 1; i0 < tsz+1; i0++)
267 tmp[i0] = tmp[0] + 2*i0;
268 i1 = 2*(numPoints + 2);
270 int* id = new int[i1];
271 for (i0 = 0; i0 < i1; i0++)
274 int** a3s = new int*[i1];
275 a3s[0] = new int[3*i1];
276 for (i0 = 1; i0 < i1; i0++)
277 a3s[i0] = a3s[0] + 3*i0;
278 a3s[0][0] = numPoints;
279 a3s[0][1] = numPoints+1;
280 a3s[0][2] = numPoints+2;
282 double** ccr = new double*[i1]; // circumscribed centers and radii
283 ccr[0] = new double[3*i1];
284 for (i0 = 1; i0 < i1; i0++)
285 ccr[i0] = ccr[0] + 3*i0;
290 nts = 1; // number of triangles
293 SG_LOG(SG_MATH, SG_DEBUG, "[ 40%] create triangulation");
295 // compute triangulation
296 for (i0 = 0; i0 < numPoints; i0++)
300 for (i11 = 0; i11 < nts; i11++)
303 while ( a3s[i1][0] < 0 )
306 for (i2 = 0; i2 < 2; i2++)
308 double z = tmppoint[i0][i2]-ccr[i1][i2];
316 for (i2 = 0; i2 < 3; i2++)
321 for (i3 = 1; i3 < 2; i3++)
323 ii[i3] = ii[i3-1] + 1;
330 for (i3 = 0; i3 <= i8; i3++)
332 for (i5 = 0; i5 < 2; i5++)
333 if ( a3s[i1][ii[i5]] != tmp[i3][i5] )
335 for (i6 = 0; i6 < 2; i6++)
336 tmp[i3][i6] = tmp[i8][i6];
344 // temporary storage exceeded, increase TSIZE
348 for (i3 = 0; i3 < 2; i3++)
349 tmp[i7][i3] = a3s[i1][ii[i3]];
356 for (i1 = 0; i1 <= i7; i1++)
358 for (i2 = 0; i2 < 2; i2++)
359 for (wrk[i2][2] = 0, i3 = 0; i3 < 2; i3++)
361 wrk[i2][i3] = tmppoint[tmp[i1][i2]][i3]-tmppoint[i0][i3];
363 0.5*wrk[i2][i3]*(tmppoint[tmp[i1][i2]][i3]+
367 xx = wrk[0][0]*wrk[1][1]-wrk[1][0]*wrk[0][1];
368 ccr[id[i4]][0] = (wrk[0][2]*wrk[1][1]-wrk[1][2]*wrk[0][1])/xx;
369 ccr[id[i4]][1] = (wrk[0][0]*wrk[1][2]-wrk[1][0]*wrk[0][2])/xx;
371 for (ccr[id[i4]][2] = 0, i2 = 0; i2 < 2; i2++)
373 double z = tmppoint[i0][i2]-ccr[id[i4]][i2];
374 ccr[id[i4]][2] += z*z;
375 a3s[id[i4]][i2] = tmp[i1][i2];
385 // count the number of triangles
386 SG_LOG(SG_MATH, SG_DEBUG, "[ 50%] count the number of triangles");
390 for (i11 = 0; i11 < nts; i11++)
393 while ( a3s[i0][0] < 0 )
395 if ( a3s[i0][0] < numPoints )
397 for (i1 = 0; i1 < 2; i1++)
398 for (i2 = 0; i2 < 2; i2++)
400 tmppoint[a3s[i0][i1]][i2]-tmppoint[a3s[i0][2]][i2];
402 if ( fabs(wrk[0][0]*wrk[1][1]-wrk[0][1]*wrk[1][0]) > EPSILON*maxrange2 )
407 // create the triangles
408 SG_LOG(SG_MATH, SG_DEBUG "[ 60%] create the triangles");
410 triangle = new Triangle[numTriangles];
414 for (i11 = 0; i11 < nts; i11++)
417 while ( a3s[i0][0] < 0 )
419 if ( a3s[i0][0] < numPoints )
421 for (i1 = 0; i1 < 2; i1++)
422 for (i2 = 0; i2 < 2; i2++)
424 tmppoint[a3s[i0][i1]][i2]-tmppoint[a3s[i0][2]][i2];
425 xx = wrk[0][0]*wrk[1][1]-wrk[0][1]*wrk[1][0];
426 if ( fabs(xx) > EPSILON*maxrange2 )
428 int delta = xx < 0 ? 1 : 0;
429 Triangle& tri = triangle[numTriangles];
430 tri.vertex[0] = a3s[i0][0];
431 tri.vertex[1] = a3s[i0][1+delta];
432 tri.vertex[2] = a3s[i0][2-delta];
442 SG_LOG(SG_MATH, SG_DEBUG, "[ 70%] build the edge table");
445 edge = new Edge[3*numTriangles];
448 for (i = 0; i < numTriangles; i++)
451 SG_LOG(SG_MATH, SG_BULK, "[ 7" << 10*i/numTriangles << "%] build the edge table");
453 Triangle& t = triangle[i];
455 for (j0 = 0, j1 = 1; j0 < 3; j0++, j1 = (j1+1)%3)
457 for (j = 0; j < numEdges; j++)
460 if ( (t.vertex[j0] == e.vertex[0]
461 && t.vertex[j1] == e.vertex[1])
462 || (t.vertex[j0] == e.vertex[1]
463 && t.vertex[j1] == e.vertex[0]) )
466 if ( j == numEdges ) // add edge to table
468 edge[j].vertex[0] = t.vertex[j0];
469 edge[j].vertex[1] = t.vertex[j1];
470 edge[j].triangle[0] = i;
471 edge[j].index[0] = j0;
472 edge[j].triangle[1] = -1;
475 else // edge already exists, add triangle to table
477 edge[j].triangle[1] = i;
478 edge[j].index[1] = j0;
483 // establish links between adjacent triangles
484 SG_LOG(SG_MATH, SG_DEBUG, "[ 80%] establishing links between adjacent triangles");
486 for (i = 0; i < numEdges; i++)
488 if ( edge[i].triangle[1] != -1 )
490 j0 = edge[i].triangle[0];
491 j1 = edge[i].triangle[1];
492 triangle[j0].adj[edge[i].index[0]] = j1;
493 triangle[j1].adj[edge[i].index[1]] = j0;
508 SG_LOG(SG_MATH, SG_DEBUG, "[ 90%] finsishes delauney triangulation");
512 //---------------------------------------------------------------------------
513 void mgcLinInterp2D::GetPoint (int i, double& x, double& y)
515 // assumes i is valid [can use PointCount() before passing i]
519 //---------------------------------------------------------------------------
520 void mgcLinInterp2D::GetEdge (int i, double& x0, double& y0, double& x1,
523 // assumes i is valid [can use EdgeCount() before passing i]
524 int v0 = edge[i].vertex[0], v1 = edge[i].vertex[1];
531 //---------------------------------------------------------------------------
532 void mgcLinInterp2D::GetTriangle (int i, double& x0, double& y0, double& x1,
533 double& y1, double& x2, double& y2)
535 // assumes i is valid [can use TriangleCount() before passing i]
536 int v0 = triangle[i].vertex[0];
537 int v1 = triangle[i].vertex[1];
538 int v2 = triangle[i].vertex[2];
547 //---------------------------------------------------------------------------