IntpQuadraticNonuniform2.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/Delaunay2.h>
  9. #include <Mathematics/ContScribeCircle2.h>
  10. #include <Mathematics/DistPointAlignedBox.h>
  11. // Quadratic interpolation of a network of triangles whose vertices are of
  12. // the form (x,y,f(x,y)). This code is an implementation of the algorithm
  13. // found in
  14. //
  15. // Zoltan J. Cendes and Steven H. Wong,
  16. // C1 quadratic interpolation over arbitrary point sets,
  17. // IEEE Computer Graphics & Applications,
  18. // pp. 8-16, 1987
  19. //
  20. // The TriangleMesh interface must support the following:
  21. // int GetNumVertices() const;
  22. // int GetNumTriangles() const;
  23. // Vector2<Real> const* GetVertices() const;
  24. // int const* GetIndices() const;
  25. // bool GetVertices(int, std::array<Vector2<Real>, 3>&) const;
  26. // bool GetIndices(int, std::array<int, 3>&) const;
  27. // bool GetAdjacencies(int, std::array<int, 3>&) const;
  28. // bool GetBarycentrics(int, Vector2<Real> const&,
  29. // std::array<Real, 3>&) const;
  30. // int GetContainingTriangle(Vector2<Real> const&) const;
  31. namespace WwiseGTE
  32. {
  33. template <typename Real, typename TriangleMesh>
  34. class IntpQuadraticNonuniform2
  35. {
  36. public:
  37. // Construction.
  38. //
  39. // The first constructor requires only F and a measure of the rate of
  40. // change of the function values relative to changes in the spatial
  41. // variables. The df/dx and df/dy values are estimated at the sample
  42. // points using mesh normals and spatialDelta.
  43. //
  44. // The second constructor requires you to specify function values F
  45. // and first-order partial derivative values df/dx and df/dy.
  46. IntpQuadraticNonuniform2(TriangleMesh const& mesh, Real const* F, Real spatialDelta)
  47. :
  48. mMesh(&mesh),
  49. mF(F),
  50. mFX(nullptr),
  51. mFY(nullptr)
  52. {
  53. EstimateDerivatives(spatialDelta);
  54. ProcessTriangles();
  55. }
  56. IntpQuadraticNonuniform2(TriangleMesh const& mesh, Real const* F, Real const* FX, Real const* FY)
  57. :
  58. mMesh(&mesh),
  59. mF(F),
  60. mFX(FX),
  61. mFY(FY)
  62. {
  63. ProcessTriangles();
  64. }
  65. // Quadratic interpolation. The return value is 'true' if and only if
  66. // the input point is in the convex hull of the input vertices, in
  67. // which case the interpolation is valid.
  68. bool operator()(Vector2<Real> const& P, Real& F, Real& FX, Real& FY) const
  69. {
  70. int t = mMesh->GetContainingTriangle(P);
  71. if (t == -1)
  72. {
  73. // The point is outside the triangulation.
  74. return false;
  75. }
  76. // Get the vertices of the triangle.
  77. std::array<Vector2<Real>, 3> V;
  78. mMesh->GetVertices(t, V);
  79. // Get the additional information for the triangle.
  80. TriangleData const& tData = mTData[t];
  81. // Determine which of the six subtriangles contains the target
  82. // point. Theoretically, P must be in one of these subtriangles.
  83. Vector2<Real> sub0 = tData.center;
  84. Vector2<Real> sub1;
  85. Vector2<Real> sub2 = tData.intersect[2];
  86. Vector3<Real> bary;
  87. int index;
  88. Real const zero = (Real)0, one = (Real)1;
  89. AlignedBox3<Real> barybox({ zero, zero, zero }, { one, one, one });
  90. DCPQuery<Real, Vector3<Real>, AlignedBox3<Real>> pbQuery;
  91. int minIndex = 0;
  92. Real minDistance = (Real)-1;
  93. Vector3<Real> minBary{ (Real)0, (Real)0, (Real)0 };
  94. Vector2<Real> minSub0{ (Real)0, (Real)0 };
  95. Vector2<Real> minSub1{ (Real)0, (Real)0 };
  96. Vector2<Real> minSub2{ (Real)0, (Real)0 };
  97. for (index = 1; index <= 6; ++index)
  98. {
  99. sub1 = sub2;
  100. if (index % 2)
  101. {
  102. sub2 = V[index / 2];
  103. }
  104. else
  105. {
  106. sub2 = tData.intersect[index / 2 - 1];
  107. }
  108. bool valid = ComputeBarycentrics(P, sub0, sub1, sub2, &bary[0]);
  109. if (valid
  110. && zero <= bary[0] && bary[0] <= one
  111. && zero <= bary[1] && bary[1] <= one
  112. && zero <= bary[2] && bary[2] <= one)
  113. {
  114. // P is in triangle <Sub0,Sub1,Sub2>
  115. break;
  116. }
  117. // When computing with floating-point arithmetic, rounding
  118. // errors can cause us to reach this code when, theoretically,
  119. // the point is in the subtriangle. Keep track of the
  120. // (b0,b1,b2) that is closest to the barycentric cube [0,1]^3
  121. // and choose the triangle corresponding to it when all 6
  122. // tests previously fail.
  123. Real distance = pbQuery(bary, barybox).distance;
  124. if (minIndex == 0 || distance < minDistance)
  125. {
  126. minDistance = distance;
  127. minIndex = index;
  128. minBary = bary;
  129. minSub0 = sub0;
  130. minSub1 = sub1;
  131. minSub2 = sub2;
  132. }
  133. }
  134. // If the subtriangle was not found, rounding errors caused
  135. // problems. Choose the barycentric point closest to the box.
  136. if (index > 6)
  137. {
  138. index = minIndex;
  139. bary = minBary;
  140. sub0 = minSub0;
  141. sub1 = minSub1;
  142. sub2 = minSub2;
  143. }
  144. // Fetch Bezier control points.
  145. Real bez[6] =
  146. {
  147. tData.coeff[0],
  148. tData.coeff[12 + index],
  149. tData.coeff[13 + (index % 6)],
  150. tData.coeff[index],
  151. tData.coeff[6 + index],
  152. tData.coeff[1 + (index % 6)]
  153. };
  154. // Evaluate Bezier quadratic.
  155. F = bary[0] * (bez[0] * bary[0] + bez[1] * bary[1] + bez[2] * bary[2]) +
  156. bary[1] * (bez[1] * bary[0] + bez[3] * bary[1] + bez[4] * bary[2]) +
  157. bary[2] * (bez[2] * bary[0] + bez[4] * bary[1] + bez[5] * bary[2]);
  158. // Evaluate barycentric derivatives of F.
  159. Real FU = ((Real)2) * (bez[0] * bary[0] + bez[1] * bary[1] +
  160. bez[2] * bary[2]);
  161. Real FV = ((Real)2) * (bez[1] * bary[0] + bez[3] * bary[1] +
  162. bez[4] * bary[2]);
  163. Real FW = ((Real)2) * (bez[2] * bary[0] + bez[4] * bary[1] +
  164. bez[5] * bary[2]);
  165. Real duw = FU - FW;
  166. Real dvw = FV - FW;
  167. // Convert back to (x,y) coordinates.
  168. Real m00 = sub0[0] - sub2[0];
  169. Real m10 = sub0[1] - sub2[1];
  170. Real m01 = sub1[0] - sub2[0];
  171. Real m11 = sub1[1] - sub2[1];
  172. Real inv = ((Real)1) / (m00 * m11 - m10 * m01);
  173. FX = inv * (m11 * duw - m10 * dvw);
  174. FY = inv * (m00 * dvw - m01 * duw);
  175. return true;
  176. }
  177. private:
  178. void EstimateDerivatives(Real spatialDelta)
  179. {
  180. int numVertices = mMesh->GetNumVertices();
  181. Vector2<Real> const* vertices = mMesh->GetVertices();
  182. int numTriangles = mMesh->GetNumTriangles();
  183. int const* indices = mMesh->GetIndices();
  184. mFXStorage.resize(numVertices);
  185. mFYStorage.resize(numVertices);
  186. std::vector<Real> FZ(numVertices);
  187. std::fill(mFXStorage.begin(), mFXStorage.end(), (Real)0);
  188. std::fill(mFYStorage.begin(), mFYStorage.end(), (Real)0);
  189. std::fill(FZ.begin(), FZ.end(), (Real)0);
  190. mFX = &mFXStorage[0];
  191. mFY = &mFYStorage[0];
  192. // Accumulate normals at spatial locations (averaging process).
  193. for (int t = 0; t < numTriangles; ++t)
  194. {
  195. // Get three vertices of triangle.
  196. int v0 = *indices++;
  197. int v1 = *indices++;
  198. int v2 = *indices++;
  199. // Compute normal vector of triangle (with positive
  200. // z-component).
  201. Real dx1 = vertices[v1][0] - vertices[v0][0];
  202. Real dy1 = vertices[v1][1] - vertices[v0][1];
  203. Real dz1 = mF[v1] - mF[v0];
  204. Real dx2 = vertices[v2][0] - vertices[v0][0];
  205. Real dy2 = vertices[v2][1] - vertices[v0][1];
  206. Real dz2 = mF[v2] - mF[v0];
  207. Real nx = dy1 * dz2 - dy2 * dz1;
  208. Real ny = dz1 * dx2 - dz2 * dx1;
  209. Real nz = dx1 * dy2 - dx2 * dy1;
  210. if (nz < (Real)0)
  211. {
  212. nx = -nx;
  213. ny = -ny;
  214. nz = -nz;
  215. }
  216. mFXStorage[v0] += nx; mFYStorage[v0] += ny; FZ[v0] += nz;
  217. mFXStorage[v1] += nx; mFYStorage[v1] += ny; FZ[v1] += nz;
  218. mFXStorage[v2] += nx; mFYStorage[v2] += ny; FZ[v2] += nz;
  219. }
  220. // Scale the normals to form (x,y,-1).
  221. for (int i = 0; i < numVertices; ++i)
  222. {
  223. if (FZ[i] != (Real)0)
  224. {
  225. Real inv = -spatialDelta / FZ[i];
  226. mFXStorage[i] *= inv;
  227. mFYStorage[i] *= inv;
  228. }
  229. else
  230. {
  231. mFXStorage[i] = (Real)0;
  232. mFYStorage[i] = (Real)0;
  233. }
  234. }
  235. }
  236. void ProcessTriangles()
  237. {
  238. // Add degenerate triangles to boundary triangles so that
  239. // interpolation at the boundary can be treated in the same way
  240. // as interpolation in the interior.
  241. // Compute centers of inscribed circles for triangles.
  242. Vector2<Real> const* vertices = mMesh->GetVertices();
  243. int numTriangles = mMesh->GetNumTriangles();
  244. int const* indices = mMesh->GetIndices();
  245. mTData.resize(numTriangles);
  246. int t;
  247. for (t = 0; t < numTriangles; ++t)
  248. {
  249. int v0 = *indices++;
  250. int v1 = *indices++;
  251. int v2 = *indices++;
  252. Circle2<Real> circle;
  253. Inscribe(vertices[v0], vertices[v1], vertices[v2], circle);
  254. mTData[t].center = circle.center;
  255. }
  256. // Compute cross-edge intersections.
  257. for (t = 0; t < numTriangles; ++t)
  258. {
  259. ComputeCrossEdgeIntersections(t);
  260. }
  261. // Compute Bezier coefficients.
  262. for (t = 0; t < numTriangles; ++t)
  263. {
  264. ComputeCoefficients(t);
  265. }
  266. }
  267. void ComputeCrossEdgeIntersections(int t)
  268. {
  269. // Get the vertices of the triangle.
  270. std::array<Vector2<Real>, 3> V;
  271. mMesh->GetVertices(t, V);
  272. // Get the centers of adjacent triangles.
  273. TriangleData& tData = mTData[t];
  274. std::array<int, 3> adjacencies;
  275. mMesh->GetAdjacencies(t, adjacencies);
  276. for (int j0 = 2, j1 = 0; j1 < 3; j0 = j1++)
  277. {
  278. int a = adjacencies[j0];
  279. if (a >= 0)
  280. {
  281. // Get center of adjacent triangle's inscribing circle.
  282. Vector2<Real> U = mTData[a].center;
  283. Real m00 = V[j0][1] - V[j1][1];
  284. Real m01 = V[j1][0] - V[j0][0];
  285. Real m10 = tData.center[1] - U[1];
  286. Real m11 = U[0] - tData.center[0];
  287. Real r0 = m00 * V[j0][0] + m01 * V[j0][1];
  288. Real r1 = m10 * tData.center[0] + m11 * tData.center[1];
  289. Real invDet = ((Real)1) / (m00 * m11 - m01 * m10);
  290. tData.intersect[j0][0] = (m11 * r0 - m01 * r1) * invDet;
  291. tData.intersect[j0][1] = (m00 * r1 - m10 * r0) * invDet;
  292. }
  293. else
  294. {
  295. // No adjacent triangle, use center of edge.
  296. tData.intersect[j0] = (Real)0.5 * (V[j0] + V[j1]);
  297. }
  298. }
  299. }
  300. void ComputeCoefficients(int t)
  301. {
  302. // Get the vertices of the triangle.
  303. std::array<Vector2<Real>, 3> V;
  304. mMesh->GetVertices(t, V);
  305. // Get the additional information for the triangle.
  306. TriangleData& tData = mTData[t];
  307. // Get the sample data at main triangle vertices.
  308. std::array<int, 3> indices;
  309. mMesh->GetIndices(t, indices);
  310. Jet jet[3];
  311. for (int j = 0; j < 3; ++j)
  312. {
  313. int k = indices[j];
  314. jet[j].F = mF[k];
  315. jet[j].FX = mFX[k];
  316. jet[j].FY = mFY[k];
  317. }
  318. // Get centers of adjacent triangles.
  319. std::array<int, 3> adjacencies;
  320. mMesh->GetAdjacencies(t, adjacencies);
  321. Vector2<Real> U[3];
  322. for (int j0 = 2, j1 = 0; j1 < 3; j0 = j1++)
  323. {
  324. int a = adjacencies[j0];
  325. if (a >= 0)
  326. {
  327. // Get center of adjacent triangle's circumscribing
  328. // circle.
  329. U[j0] = mTData[a].center;
  330. }
  331. else
  332. {
  333. // No adjacent triangle, use center of edge.
  334. U[j0] = ((Real)0.5) * (V[j0] + V[j1]);
  335. }
  336. }
  337. // Compute intermediate terms.
  338. std::array<Real, 3> cenT, cen0, cen1, cen2;
  339. mMesh->GetBarycentrics(t, tData.center, cenT);
  340. mMesh->GetBarycentrics(t, U[0], cen0);
  341. mMesh->GetBarycentrics(t, U[1], cen1);
  342. mMesh->GetBarycentrics(t, U[2], cen2);
  343. Real alpha = (cenT[1] * cen1[0] - cenT[0] * cen1[1]) / (cen1[0] - cenT[0]);
  344. Real beta = (cenT[2] * cen2[1] - cenT[1] * cen2[2]) / (cen2[1] - cenT[1]);
  345. Real gamma = (cenT[0] * cen0[2] - cenT[2] * cen0[0]) / (cen0[2] - cenT[2]);
  346. Real oneMinusAlpha = (Real)1 - alpha;
  347. Real oneMinusBeta = (Real)1 - beta;
  348. Real oneMinusGamma = (Real)1 - gamma;
  349. Real tmp, A[9], B[9];
  350. tmp = cenT[0] * V[0][0] + cenT[1] * V[1][0] + cenT[2] * V[2][0];
  351. A[0] = (Real)0.5 * (tmp - V[0][0]);
  352. A[1] = (Real)0.5 * (tmp - V[1][0]);
  353. A[2] = (Real)0.5 * (tmp - V[2][0]);
  354. A[3] = (Real)0.5 * beta * (V[2][0] - V[0][0]);
  355. A[4] = (Real)0.5 * oneMinusGamma * (V[1][0] - V[0][0]);
  356. A[5] = (Real)0.5 * gamma * (V[0][0] - V[1][0]);
  357. A[6] = (Real)0.5 * oneMinusAlpha * (V[2][0] - V[1][0]);
  358. A[7] = (Real)0.5 * alpha * (V[1][0] - V[2][0]);
  359. A[8] = (Real)0.5 * oneMinusBeta * (V[0][0] - V[2][0]);
  360. tmp = cenT[0] * V[0][1] + cenT[1] * V[1][1] + cenT[2] * V[2][1];
  361. B[0] = (Real)0.5 * (tmp - V[0][1]);
  362. B[1] = (Real)0.5 * (tmp - V[1][1]);
  363. B[2] = (Real)0.5 * (tmp - V[2][1]);
  364. B[3] = (Real)0.5 * beta * (V[2][1] - V[0][1]);
  365. B[4] = (Real)0.5 * oneMinusGamma * (V[1][1] - V[0][1]);
  366. B[5] = (Real)0.5 * gamma * (V[0][1] - V[1][1]);
  367. B[6] = (Real)0.5 * oneMinusAlpha * (V[2][1] - V[1][1]);
  368. B[7] = (Real)0.5 * alpha * (V[1][1] - V[2][1]);
  369. B[8] = (Real)0.5 * oneMinusBeta * (V[0][1] - V[2][1]);
  370. // Compute Bezier coefficients.
  371. tData.coeff[2] = jet[0].F;
  372. tData.coeff[4] = jet[1].F;
  373. tData.coeff[6] = jet[2].F;
  374. tData.coeff[14] = jet[0].F + A[0] * jet[0].FX + B[0] * jet[0].FY;
  375. tData.coeff[7] = jet[0].F + A[3] * jet[0].FX + B[3] * jet[0].FY;
  376. tData.coeff[8] = jet[0].F + A[4] * jet[0].FX + B[4] * jet[0].FY;
  377. tData.coeff[16] = jet[1].F + A[1] * jet[1].FX + B[1] * jet[1].FY;
  378. tData.coeff[9] = jet[1].F + A[5] * jet[1].FX + B[5] * jet[1].FY;
  379. tData.coeff[10] = jet[1].F + A[6] * jet[1].FX + B[6] * jet[1].FY;
  380. tData.coeff[18] = jet[2].F + A[2] * jet[2].FX + B[2] * jet[2].FY;
  381. tData.coeff[11] = jet[2].F + A[7] * jet[2].FX + B[7] * jet[2].FY;
  382. tData.coeff[12] = jet[2].F + A[8] * jet[2].FX + B[8] * jet[2].FY;
  383. tData.coeff[5] = alpha * tData.coeff[10] + oneMinusAlpha * tData.coeff[11];
  384. tData.coeff[17] = alpha * tData.coeff[16] + oneMinusAlpha * tData.coeff[18];
  385. tData.coeff[1] = beta * tData.coeff[12] + oneMinusBeta * tData.coeff[7];
  386. tData.coeff[13] = beta * tData.coeff[18] + oneMinusBeta * tData.coeff[14];
  387. tData.coeff[3] = gamma * tData.coeff[8] + oneMinusGamma * tData.coeff[9];
  388. tData.coeff[15] = gamma * tData.coeff[14] + oneMinusGamma * tData.coeff[16];
  389. tData.coeff[0] = cenT[0] * tData.coeff[14] + cenT[1] * tData.coeff[16] + cenT[2] * tData.coeff[18];
  390. }
  391. class TriangleData
  392. {
  393. public:
  394. Vector2<Real> center;
  395. Vector2<Real> intersect[3];
  396. Real coeff[19];
  397. };
  398. class Jet
  399. {
  400. public:
  401. Real F, FX, FY;
  402. };
  403. TriangleMesh const* mMesh;
  404. Real const* mF;
  405. Real const* mFX;
  406. Real const* mFY;
  407. std::vector<Real> mFXStorage;
  408. std::vector<Real> mFYStorage;
  409. std::vector<TriangleData> mTData;
  410. };
  411. }