TubeMesh.h 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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/Mesh.h>
  9. #include <Mathematics/FrenetFrame.h>
  10. #include <functional>
  11. #include <memory>
  12. namespace WwiseGTE
  13. {
  14. template <typename Real>
  15. class TubeMesh : public Mesh<Real>
  16. {
  17. public:
  18. // Create a mesh (x(u,v),y(u,v),z(u,v)) defined by the specified
  19. // medial curve and radial function. The mesh has torus topology
  20. // when 'closed' is true and has cylinder topology when 'closed' is
  21. // false. The client is responsible for setting the topology
  22. // correctly in the 'description' input. The rows correspond to
  23. // medial samples and the columns correspond to radial samples. The
  24. // medial curve is sampled according to its natural t-parameter when
  25. // 'sampleByArcLength' is false; otherwise, it is sampled uniformly
  26. // in arclength. TODO: Allow TORUS and remove the 'closed' input
  27. TubeMesh(MeshDescription const& description,
  28. std::shared_ptr<ParametricCurve<3, Real>> const& medial,
  29. std::function<Real(Real)> const& radial, bool closed,
  30. bool sampleByArcLength, Vector3<Real> upVector)
  31. :
  32. Mesh<Real>(description, { MeshTopology::CYLINDER }),
  33. mMedial(medial),
  34. mRadial(radial),
  35. mClosed(closed),
  36. mSampleByArcLength(sampleByArcLength),
  37. mUpVector(upVector)
  38. {
  39. if (!this->mDescription.constructed)
  40. {
  41. // The logger system will report these errors in the Mesh
  42. // constructor.
  43. mMedial = nullptr;
  44. return;
  45. }
  46. LogAssert(mMedial != nullptr, "A nonnull medial curve is required.");
  47. mCosAngle.resize(this->mDescription.numCols);
  48. mSinAngle.resize(this->mDescription.numCols);
  49. Real invRadialSamples = (Real)1 / (Real)(this->mDescription.numCols - 1);
  50. for (unsigned int i = 0; i < this->mDescription.numCols - 1; ++i)
  51. {
  52. Real angle = i * invRadialSamples * (Real)GTE_C_TWO_PI;
  53. mCosAngle[i] = std::cos(angle);
  54. mSinAngle[i] = std::sin(angle);
  55. }
  56. mCosAngle[this->mDescription.numCols - 1] = mCosAngle[0];
  57. mSinAngle[this->mDescription.numCols - 1] = mSinAngle[0];
  58. Real invDenom;
  59. if (mClosed)
  60. {
  61. invDenom = (Real)1 / (Real)this->mDescription.numRows;
  62. }
  63. else
  64. {
  65. invDenom = (Real)1 / (Real)(this->mDescription.numRows - 1);
  66. }
  67. Real factor;
  68. if (mSampleByArcLength)
  69. {
  70. factor = mMedial->GetTotalLength() * invDenom;
  71. mTSampler = [this, factor](unsigned int row)
  72. {
  73. return mMedial->GetTime(row * factor);
  74. };
  75. }
  76. else
  77. {
  78. factor = (mMedial->GetTMax() - mMedial->GetTMin()) * invDenom;
  79. mTSampler = [this, factor](unsigned int row)
  80. {
  81. return mMedial->GetTMin() + row * factor;
  82. };
  83. }
  84. if (mUpVector != Vector3<Real>::Zero())
  85. {
  86. mFSampler = [this](Real t)
  87. {
  88. std::array<Vector3<Real>, 4> frame;
  89. frame[0] = mMedial->GetPosition(t);
  90. frame[1] = mMedial->GetTangent(t);
  91. frame[3] = UnitCross(frame[1], mUpVector);
  92. frame[2] = UnitCross(frame[3], frame[1]);
  93. return frame;
  94. };
  95. }
  96. else
  97. {
  98. mFrenet = std::make_unique<FrenetFrame3<Real>>(mMedial);
  99. mFSampler = [this](Real t)
  100. {
  101. std::array<Vector3<Real>, 4> frame;
  102. (*mFrenet)(t, frame[0], frame[1], frame[2], frame[3]);
  103. return frame;
  104. };
  105. }
  106. if (!this->mTCoords)
  107. {
  108. mDefaultTCoords.resize(this->mDescription.numVertices);
  109. this->mTCoords = mDefaultTCoords.data();
  110. this->mTCoordStride = sizeof(Vector2<Real>);
  111. this->mDescription.allowUpdateFrame = this->mDescription.wantDynamicTangentSpaceUpdate;
  112. if (this->mDescription.allowUpdateFrame)
  113. {
  114. if (!this->mDescription.hasTangentSpaceVectors)
  115. {
  116. this->mDescription.allowUpdateFrame = false;
  117. }
  118. if (!this->mNormals)
  119. {
  120. this->mDescription.allowUpdateFrame = false;
  121. }
  122. }
  123. }
  124. this->ComputeIndices();
  125. InitializeTCoords();
  126. UpdatePositions();
  127. if (this->mDescription.allowUpdateFrame)
  128. {
  129. this->UpdateFrame();
  130. }
  131. else if (this->mNormals)
  132. {
  133. this->UpdateNormals();
  134. }
  135. }
  136. // Member access.
  137. inline std::shared_ptr<ParametricCurve<3, Real>> const& GetMedial() const
  138. {
  139. return mMedial;
  140. }
  141. inline std::function<Real(Real)> const& GetRadial() const
  142. {
  143. return mRadial;
  144. }
  145. inline bool IsClosed() const
  146. {
  147. return mClosed;
  148. }
  149. inline bool IsSampleByArcLength() const
  150. {
  151. return mSampleByArcLength;
  152. }
  153. inline Vector3<Real> const& GetUpVector() const
  154. {
  155. return mUpVector;
  156. }
  157. private:
  158. void InitializeTCoords()
  159. {
  160. Vector2<Real>tcoord;
  161. for (unsigned int r = 0, i = 0; r < this->mDescription.numRows; ++r)
  162. {
  163. tcoord[1] = (Real)r / (Real)this->mDescription.rMax;
  164. for (unsigned int c = 0; c <= this->mDescription.numCols; ++c, ++i)
  165. {
  166. tcoord[0] = (Real)c / (Real)this->mDescription.numCols;
  167. this->TCoord(i) = tcoord;
  168. }
  169. }
  170. }
  171. virtual void UpdatePositions() override
  172. {
  173. uint32_t row, col, v, save;
  174. for (row = 0, v = 0; row < this->mDescription.numRows; ++row, ++v)
  175. {
  176. Real t = mTSampler(row);
  177. Real radius = mRadial(t);
  178. // frame = (position, tangent, normal, binormal)
  179. std::array<Vector3<Real>, 4> frame = mFSampler(t);
  180. for (col = 0, save = v; col < this->mDescription.numCols; ++col, ++v)
  181. {
  182. this->Position(v) = frame[0] + radius * (mCosAngle[col] * frame[2] +
  183. mSinAngle[col] * frame[3]);
  184. }
  185. this->Position(v) = this->Position(save);
  186. }
  187. if (mClosed)
  188. {
  189. for (col = 0; col < this->mDescription.numCols; ++col)
  190. {
  191. uint32_t i0 = col;
  192. uint32_t i1 = col + this->mDescription.numCols * (this->mDescription.numRows - 1);
  193. this->Position(i1) = this->Position(i0);
  194. }
  195. }
  196. }
  197. std::shared_ptr<ParametricCurve<3, Real>> mMedial;
  198. std::function<Real(Real)> mRadial;
  199. bool mClosed, mSampleByArcLength;
  200. Vector3<Real> mUpVector;
  201. std::vector<Real> mCosAngle, mSinAngle;
  202. std::function<Real(unsigned int)> mTSampler;
  203. std::function<std::array<Vector3<Real>, 4>(Real)> mFSampler;
  204. std::unique_ptr<FrenetFrame3<Real>> mFrenet;
  205. // If the client does not request texture coordinates, they will be
  206. // computed internally for use in evaluation of the surface geometry.
  207. std::vector<Vector2<Real>> mDefaultTCoords;
  208. };
  209. }