DarbouxFrame.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  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/Matrix2x2.h>
  9. #include <Mathematics/ParametricSurface.h>
  10. #include <Mathematics/Vector3.h>
  11. #include <memory>
  12. namespace WwiseGTE
  13. {
  14. template <typename Real>
  15. class DarbouxFrame3
  16. {
  17. public:
  18. // Construction. The curve must persist as long as the DarbouxFrame3
  19. // object does.
  20. DarbouxFrame3(std::shared_ptr<ParametricSurface<3, Real>> const& surface)
  21. :
  22. mSurface(surface)
  23. {
  24. }
  25. // Get a coordinate frame, {T0, T1, N}. At a nondegenerate surface
  26. // points, dX/du and dX/dv are linearly independent tangent vectors.
  27. // The frame is constructed as
  28. // T0 = (dX/du)/|dX/du|
  29. // N = Cross(dX/du,dX/dv)/|Cross(dX/du,dX/dv)|
  30. // T1 = Cross(N, T0)
  31. // so that {T0, T1, N} is a right-handed orthonormal set.
  32. void operator()(Real u, Real v, Vector3<Real>& position, Vector3<Real>& tangent0,
  33. Vector3<Real>& tangent1, Vector3<Real>& normal) const
  34. {
  35. std::array<Vector3<Real>, 3> jet;
  36. mSurface->Evaluate(u, v, 1, jet.data());
  37. position = jet[0];
  38. tangent0 = jet[1];
  39. Normalize(tangent0);
  40. tangent1 = jet[2];
  41. Normalize(tangent1);
  42. normal = UnitCross(tangent0, tangent1);
  43. tangent1 = Cross(normal, tangent0);
  44. }
  45. // Compute the principal curvatures and principal directions.
  46. void GetPrincipalInformation(Real u, Real v, Real& curvature0, Real& curvature1,
  47. Vector3<Real>& direction0, Vector3<Real>& direction1) const
  48. {
  49. // Tangents: T0 = (x_u,y_u,z_u), T1 = (x_v,y_v,z_v)
  50. // Normal: N = Cross(T0,T1)/Length(Cross(T0,T1))
  51. // Metric Tensor: G = +- -+
  52. // | Dot(T0,T0) Dot(T0,T1) |
  53. // | Dot(T1,T0) Dot(T1,T1) |
  54. // +- -+
  55. //
  56. // Curvature Tensor: B = +- -+
  57. // | -Dot(N,T0_u) -Dot(N,T0_v) |
  58. // | -Dot(N,T1_u) -Dot(N,T1_v) |
  59. // +- -+
  60. //
  61. // Principal curvatures k are the generalized eigenvalues of
  62. //
  63. // Bw = kGw
  64. //
  65. // If k is a curvature and w=(a,b) is the corresponding solution
  66. // to Bw = kGw, then the principal direction as a 3D vector is
  67. // d = a*U+b*V.
  68. //
  69. // Let k1 and k2 be the principal curvatures. The mean curvature
  70. // is (k1+k2)/2 and the Gaussian curvature is k1*k2.
  71. // Compute derivatives.
  72. std::array<Vector3<Real>, 6> jet;
  73. mSurface->Evaluate(u, v, 2, jet.data());
  74. Vector3<Real> derU = jet[1];
  75. Vector3<Real> derV = jet[2];
  76. Vector3<Real> derUU = jet[3];
  77. Vector3<Real> derUV = jet[4];
  78. Vector3<Real> derVV = jet[5];
  79. // Compute the metric tensor.
  80. Matrix2x2<Real> metricTensor;
  81. metricTensor(0, 0) = Dot(jet[1], jet[1]);
  82. metricTensor(0, 1) = Dot(jet[1], jet[2]);
  83. metricTensor(1, 0) = metricTensor(0, 1);
  84. metricTensor(1, 1) = Dot(jet[2], jet[2]);
  85. // Compute the curvature tensor.
  86. Vector3<Real> normal = UnitCross(jet[1], jet[2]);
  87. Matrix2x2<Real> curvatureTensor;
  88. curvatureTensor(0, 0) = -Dot(normal, derUU);
  89. curvatureTensor(0, 1) = -Dot(normal, derUV);
  90. curvatureTensor(1, 0) = curvatureTensor(0, 1);
  91. curvatureTensor(1, 1) = -Dot(normal, derVV);
  92. // Characteristic polynomial is 0 = det(B-kG) = c2*k^2+c1*k+c0.
  93. Real c0 = Determinant(curvatureTensor);
  94. Real c1 = (Real)2 * curvatureTensor(0, 1) * metricTensor(0, 1) -
  95. curvatureTensor(0, 0) * metricTensor(1, 1) -
  96. curvatureTensor(1, 1) * metricTensor(0, 0);
  97. Real c2 = Determinant(metricTensor);
  98. // Principal curvatures are roots of characteristic polynomial.
  99. Real temp = std::sqrt(std::max(c1 * c1 - (Real)4 * c0 * c2, (Real)0));
  100. Real mult = (Real)0.5 / c2;
  101. curvature0 = -mult * (c1 + temp);
  102. curvature1 = -mult * (c1 - temp);
  103. // Principal directions are solutions to (B-kG)w = 0,
  104. // w1 = (b12-k1*g12,-(b11-k1*g11)) OR (b22-k1*g22,-(b12-k1*g12)).
  105. Real a0 = curvatureTensor(0, 1) - curvature0 * metricTensor(0, 1);
  106. Real a1 = curvature0 * metricTensor(0, 0) - curvatureTensor(0, 0);
  107. Real length = std::sqrt(a0 * a0 + a1 * a1);
  108. if (length > (Real)0)
  109. {
  110. direction0 = a0 * derU + a1 * derV;
  111. }
  112. else
  113. {
  114. a0 = curvatureTensor(1, 1) - curvature0 * metricTensor(1, 1);
  115. a1 = curvature0 * metricTensor(0, 1) - curvatureTensor(0, 1);
  116. length = std::sqrt(a0 * a0 + a1 * a1);
  117. if (length > (Real)0)
  118. {
  119. direction0 = a0 * derU + a1 * derV;
  120. }
  121. else
  122. {
  123. // Umbilic (surface is locally sphere, any direction
  124. // principal).
  125. direction0 = derU;
  126. }
  127. }
  128. Normalize(direction0);
  129. // Second tangent is cross product of first tangent and normal.
  130. direction1 = Cross(direction0, normal);
  131. }
  132. private:
  133. std::shared_ptr<ParametricSurface<3, Real>> mSurface;
  134. };
  135. }