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>
34 #include <simgear/debug/logstream.hxx>
41 SG_USING_NAMESPACE(std);
44 //---------------------------------------------------------------------------
45 mgcLinInterp2D::mgcLinInterp2D (int _numPoints, double* x, double* y,
48 if ( (numPoints = _numPoints) < 3 )
57 SG_LOG(SG_MATH, SG_DEBUG, "[ 20%] allocating memory");
59 point = new double*[numPoints];
60 tmppoint = new double*[numPoints+3];
61 f = new unsigned int[numPoints];
63 for (i = 0; i < numPoints; i++)
64 point[i] = new double[2];
65 for (i = 0; i < numPoints+3; i++)
66 tmppoint[i] = new double[2];
67 for (i = 0; i < numPoints; i++)
69 point[i][0] = tmppoint[i][0] = x[i];
70 point[i][1] = tmppoint[i][1] = y[i];
75 SG_LOG(SG_MATH, SG_DEBUG, "[ 30%] creating delaunay diagram");
79 //---------------------------------------------------------------------------
80 mgcLinInterp2D::~mgcLinInterp2D ()
89 for (i = 0; i < numPoints; i++)
95 for (i = 0; i < numPoints+3; i++)
104 //---------------------------------------------------------------------------
105 void mgcLinInterp2D::ComputeBarycenter (Vertex& v0, Vertex& v1, Vertex& v2,
106 Vertex& ver, double c[3])
108 double a0 = v0.x-v2.x;
109 double b0 = v0.y-v2.y;
110 double a1 = v1.x-v2.x;
111 double b1 = v1.y-v2.y;
112 double a2 = ver.x-v2.x;
113 double b2 = ver.y-v2.y;
115 double m00 = a0*a0+b0*b0;
116 double m01 = a0*a1+b0*b1;
117 double m11 = a1*a1+b1*b1;
118 double r0 = a2*a0+b2*b0;
119 double r1 = a2*a1+b2*b1;
120 double det = m00*m11-m01*m01;
122 c[0] = (m11*r0-m01*r1)/det;
123 c[1] = (m00*r1-m01*r0)/det;
126 //---------------------------------------------------------------------------
127 int mgcLinInterp2D::InTriangle (Vertex& v0, Vertex& v1, Vertex& v2,
130 const double eps = 1e-08;
131 double tx, ty, nx, ny;
133 // test against normal to first edge
138 if ( tx*nx + ty*ny < -eps )
141 // test against normal to second edge
146 if ( tx*nx + ty*ny < -eps )
149 // test against normal to third edge
154 if ( tx*nx + ty*ny < -eps )
159 //---------------------------------------------------------------------------
160 int mgcLinInterp2D::Evaluate (double x, double y, EvaluateData& F)
162 Vertex ver = { x, y };
163 // determine which triangle contains the target point
167 for (i = 0; i < numTriangles; i++)
169 Triangle& t = triangle[i];
170 v0.x = point[t.vertex[0]][0];
171 v0.y = point[t.vertex[0]][1];
172 v1.x = point[t.vertex[1]][0];
173 v1.y = point[t.vertex[1]][1];
174 v2.x = point[t.vertex[2]][0];
175 v2.y = point[t.vertex[2]][1];
177 if ( InTriangle(v0,v1,v2,ver) )
181 if ( i == numTriangles ) // point is outside interpolation region
186 Triangle& t = triangle[i]; // (x,y) is in this triangle
188 // compute barycentric coordinates with respect to subtriangle
190 ComputeBarycenter(v0,v1,v2,ver,bary);
192 // compute barycentric combination of function values at vertices
193 F.index[0] = f[t.vertex[0]];
194 F.index[1] = f[t.vertex[1]];
195 F.index[2] = f[t.vertex[2]];
196 F.percentage[0] = bary[0];
197 F.percentage[1] = bary[1];
198 F.percentage[2] = bary[2];
202 //---------------------------------------------------------------------------
203 int mgcLinInterp2D::Delaunay2D ()
207 const double EPSILON = 1e-12;
208 const int TSIZE = 75;
209 const double RANGE = 10.0;
211 xmin = tmppoint[0][0];
213 ymin = tmppoint[0][1];
217 for (i = 0; i < numPoints; i++)
219 double value = tmppoint[i][0];
225 value = tmppoint[i][1];
232 double xrange = xmax-xmin, yrange = ymax-ymin;
233 double maxrange = xrange;
234 if ( maxrange < yrange )
237 // need to scale the data later to do a correct triangle count
238 double maxrange2 = maxrange*maxrange;
240 // tweak the points by very small random numbers
241 double bgs = EPSILON*maxrange;
243 for (i = 0; i < numPoints; i++)
245 tmppoint[i][0] += bgs*(0.5 - rand()/double(RAND_MAX));
246 tmppoint[i][1] += bgs*(0.5 - rand()/double(RAND_MAX));
251 { 5*RANGE, -RANGE, -RANGE },
252 { -RANGE, 5*RANGE, -RANGE }
254 for (i = 0; i < 3; i++)
256 tmppoint[numPoints+i][0] = xmin+xrange*wrk[0][i];
257 tmppoint[numPoints+i][1] = ymin+yrange*wrk[1][i];
260 int i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i11;
265 int** tmp = new int*[tsz+1];
266 tmp[0] = new int[2*(tsz+1)];
267 for (i0 = 1; i0 < tsz+1; i0++)
268 tmp[i0] = tmp[0] + 2*i0;
269 i1 = 2*(numPoints + 2);
271 int* id = new int[i1];
272 for (i0 = 0; i0 < i1; i0++)
275 int** a3s = new int*[i1];
276 a3s[0] = new int[3*i1];
277 for (i0 = 1; i0 < i1; i0++)
278 a3s[i0] = a3s[0] + 3*i0;
279 a3s[0][0] = numPoints;
280 a3s[0][1] = numPoints+1;
281 a3s[0][2] = numPoints+2;
283 double** ccr = new double*[i1]; // circumscribed centers and radii
284 ccr[0] = new double[3*i1];
285 for (i0 = 1; i0 < i1; i0++)
286 ccr[i0] = ccr[0] + 3*i0;
291 nts = 1; // number of triangles
294 SG_LOG(SG_MATH, SG_DEBUG, "[ 40%] create triangulation");
296 // compute triangulation
297 for (i0 = 0; i0 < numPoints; i0++)
301 for (i11 = 0; i11 < nts; i11++)
304 while ( a3s[i1][0] < 0 )
307 for (i2 = 0; i2 < 2; i2++)
309 double z = tmppoint[i0][i2]-ccr[i1][i2];
317 for (i2 = 0; i2 < 3; i2++)
322 for (i3 = 1; i3 < 2; i3++)
324 ii[i3] = ii[i3-1] + 1;
331 for (i3 = 0; i3 <= i8; i3++)
333 for (i5 = 0; i5 < 2; i5++)
334 if ( a3s[i1][ii[i5]] != tmp[i3][i5] )
336 for (i6 = 0; i6 < 2; i6++)
337 tmp[i3][i6] = tmp[i8][i6];
345 // temporary storage exceeded, increase TSIZE
349 for (i3 = 0; i3 < 2; i3++)
350 tmp[i7][i3] = a3s[i1][ii[i3]];
357 for (i1 = 0; i1 <= i7; i1++)
359 for (i2 = 0; i2 < 2; i2++)
360 for (wrk[i2][2] = 0, i3 = 0; i3 < 2; i3++)
362 wrk[i2][i3] = tmppoint[tmp[i1][i2]][i3]-tmppoint[i0][i3];
364 0.5*wrk[i2][i3]*(tmppoint[tmp[i1][i2]][i3]+
368 xx = wrk[0][0]*wrk[1][1]-wrk[1][0]*wrk[0][1];
369 ccr[id[i4]][0] = (wrk[0][2]*wrk[1][1]-wrk[1][2]*wrk[0][1])/xx;
370 ccr[id[i4]][1] = (wrk[0][0]*wrk[1][2]-wrk[1][0]*wrk[0][2])/xx;
372 for (ccr[id[i4]][2] = 0, i2 = 0; i2 < 2; i2++)
374 double z = tmppoint[i0][i2]-ccr[id[i4]][i2];
375 ccr[id[i4]][2] += z*z;
376 a3s[id[i4]][i2] = tmp[i1][i2];
386 // count the number of triangles
387 SG_LOG(SG_MATH, SG_DEBUG, "[ 50%] count the number of triangles");
391 for (i11 = 0; i11 < nts; i11++)
394 while ( a3s[i0][0] < 0 )
396 if ( a3s[i0][0] < numPoints )
398 for (i1 = 0; i1 < 2; i1++)
399 for (i2 = 0; i2 < 2; i2++)
401 tmppoint[a3s[i0][i1]][i2]-tmppoint[a3s[i0][2]][i2];
403 if ( fabs(wrk[0][0]*wrk[1][1]-wrk[0][1]*wrk[1][0]) > EPSILON*maxrange2 )
408 // create the triangles
409 SG_LOG(SG_MATH, SG_DEBUG, "[ 60%] create the triangles");
411 triangle = new Triangle[numTriangles];
415 for (i11 = 0; i11 < nts; i11++)
418 while ( a3s[i0][0] < 0 )
420 if ( a3s[i0][0] < numPoints )
422 for (i1 = 0; i1 < 2; i1++)
423 for (i2 = 0; i2 < 2; i2++)
425 tmppoint[a3s[i0][i1]][i2]-tmppoint[a3s[i0][2]][i2];
426 xx = wrk[0][0]*wrk[1][1]-wrk[0][1]*wrk[1][0];
427 if ( fabs(xx) > EPSILON*maxrange2 )
429 int delta = xx < 0 ? 1 : 0;
430 Triangle& tri = triangle[numTriangles];
431 tri.vertex[0] = a3s[i0][0];
432 tri.vertex[1] = a3s[i0][1+delta];
433 tri.vertex[2] = a3s[i0][2-delta];
443 SG_LOG(SG_MATH, SG_DEBUG, "[ 70%] build the edge table");
446 edge = new Edge[3*numTriangles];
449 for (i = 0; i < numTriangles; i++)
452 SG_LOG(SG_MATH, SG_BULK, "[ 7" << 10*i/numTriangles << "%] build the edge table");
454 Triangle& t = triangle[i];
456 for (j0 = 0, j1 = 1; j0 < 3; j0++, j1 = (j1+1)%3)
458 for (j = 0; j < numEdges; j++)
461 if ( (t.vertex[j0] == e.vertex[0]
462 && t.vertex[j1] == e.vertex[1])
463 || (t.vertex[j0] == e.vertex[1]
464 && t.vertex[j1] == e.vertex[0]) )
467 if ( j == numEdges ) // add edge to table
469 edge[j].vertex[0] = t.vertex[j0];
470 edge[j].vertex[1] = t.vertex[j1];
471 edge[j].triangle[0] = i;
472 edge[j].index[0] = j0;
473 edge[j].triangle[1] = -1;
476 else // edge already exists, add triangle to table
478 edge[j].triangle[1] = i;
479 edge[j].index[1] = j0;
484 // establish links between adjacent triangles
485 SG_LOG(SG_MATH, SG_DEBUG, "[ 80%] establishing links between adjacent triangles");
487 for (i = 0; i < numEdges; i++)
489 if ( edge[i].triangle[1] != -1 )
491 j0 = edge[i].triangle[0];
492 j1 = edge[i].triangle[1];
493 triangle[j0].adj[edge[i].index[0]] = j1;
494 triangle[j1].adj[edge[i].index[1]] = j0;
509 SG_LOG(SG_MATH, SG_DEBUG, "[ 90%] finsishes delauney triangulation");
513 //---------------------------------------------------------------------------
514 void mgcLinInterp2D::GetPoint (int i, double& x, double& y)
516 // assumes i is valid [can use PointCount() before passing i]
520 //---------------------------------------------------------------------------
521 void mgcLinInterp2D::GetEdge (int i, double& x0, double& y0, double& x1,
524 // assumes i is valid [can use EdgeCount() before passing i]
525 int v0 = edge[i].vertex[0], v1 = edge[i].vertex[1];
532 //---------------------------------------------------------------------------
533 void mgcLinInterp2D::GetTriangle (int i, double& x0, double& y0, double& x1,
534 double& y1, double& x2, double& y2)
536 // assumes i is valid [can use TriangleCount() before passing i]
537 int v0 = triangle[i].vertex[0];
538 int v1 = triangle[i].vertex[1];
539 int v2 = triangle[i].vertex[2];
548 //---------------------------------------------------------------------------