123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- // David Eberly, Geometric Tools, Redmond WA 98052
- // Copyright (c) 1998-2020
- // Distributed under the Boost Software License, Version 1.0.
- // https://www.boost.org/LICENSE_1_0.txt
- // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
- // Version: 4.0.2019.08.13
- #pragma once
- #include <Mathematics/Mesh.h>
- #include <Mathematics/FrenetFrame.h>
- #include <functional>
- #include <memory>
- namespace WwiseGTE
- {
- template <typename Real>
- class TubeMesh : public Mesh<Real>
- {
- public:
- // Create a mesh (x(u,v),y(u,v),z(u,v)) defined by the specified
- // medial curve and radial function. The mesh has torus topology
- // when 'closed' is true and has cylinder topology when 'closed' is
- // false. The client is responsible for setting the topology
- // correctly in the 'description' input. The rows correspond to
- // medial samples and the columns correspond to radial samples. The
- // medial curve is sampled according to its natural t-parameter when
- // 'sampleByArcLength' is false; otherwise, it is sampled uniformly
- // in arclength. TODO: Allow TORUS and remove the 'closed' input
- TubeMesh(MeshDescription const& description,
- std::shared_ptr<ParametricCurve<3, Real>> const& medial,
- std::function<Real(Real)> const& radial, bool closed,
- bool sampleByArcLength, Vector3<Real> upVector)
- :
- Mesh<Real>(description, { MeshTopology::CYLINDER }),
- mMedial(medial),
- mRadial(radial),
- mClosed(closed),
- mSampleByArcLength(sampleByArcLength),
- mUpVector(upVector)
- {
- if (!this->mDescription.constructed)
- {
- // The logger system will report these errors in the Mesh
- // constructor.
- mMedial = nullptr;
- return;
- }
- LogAssert(mMedial != nullptr, "A nonnull medial curve is required.");
- mCosAngle.resize(this->mDescription.numCols);
- mSinAngle.resize(this->mDescription.numCols);
- Real invRadialSamples = (Real)1 / (Real)(this->mDescription.numCols - 1);
- for (unsigned int i = 0; i < this->mDescription.numCols - 1; ++i)
- {
- Real angle = i * invRadialSamples * (Real)GTE_C_TWO_PI;
- mCosAngle[i] = std::cos(angle);
- mSinAngle[i] = std::sin(angle);
- }
- mCosAngle[this->mDescription.numCols - 1] = mCosAngle[0];
- mSinAngle[this->mDescription.numCols - 1] = mSinAngle[0];
- Real invDenom;
- if (mClosed)
- {
- invDenom = (Real)1 / (Real)this->mDescription.numRows;
- }
- else
- {
- invDenom = (Real)1 / (Real)(this->mDescription.numRows - 1);
- }
- Real factor;
- if (mSampleByArcLength)
- {
- factor = mMedial->GetTotalLength() * invDenom;
- mTSampler = [this, factor](unsigned int row)
- {
- return mMedial->GetTime(row * factor);
- };
- }
- else
- {
- factor = (mMedial->GetTMax() - mMedial->GetTMin()) * invDenom;
- mTSampler = [this, factor](unsigned int row)
- {
- return mMedial->GetTMin() + row * factor;
- };
- }
- if (mUpVector != Vector3<Real>::Zero())
- {
- mFSampler = [this](Real t)
- {
- std::array<Vector3<Real>, 4> frame;
- frame[0] = mMedial->GetPosition(t);
- frame[1] = mMedial->GetTangent(t);
- frame[3] = UnitCross(frame[1], mUpVector);
- frame[2] = UnitCross(frame[3], frame[1]);
- return frame;
- };
- }
- else
- {
- mFrenet = std::make_unique<FrenetFrame3<Real>>(mMedial);
- mFSampler = [this](Real t)
- {
- std::array<Vector3<Real>, 4> frame;
- (*mFrenet)(t, frame[0], frame[1], frame[2], frame[3]);
- return frame;
- };
- }
- if (!this->mTCoords)
- {
- mDefaultTCoords.resize(this->mDescription.numVertices);
- this->mTCoords = mDefaultTCoords.data();
- this->mTCoordStride = sizeof(Vector2<Real>);
- this->mDescription.allowUpdateFrame = this->mDescription.wantDynamicTangentSpaceUpdate;
- if (this->mDescription.allowUpdateFrame)
- {
- if (!this->mDescription.hasTangentSpaceVectors)
- {
- this->mDescription.allowUpdateFrame = false;
- }
- if (!this->mNormals)
- {
- this->mDescription.allowUpdateFrame = false;
- }
- }
- }
- this->ComputeIndices();
- InitializeTCoords();
- UpdatePositions();
- if (this->mDescription.allowUpdateFrame)
- {
- this->UpdateFrame();
- }
- else if (this->mNormals)
- {
- this->UpdateNormals();
- }
- }
- // Member access.
- inline std::shared_ptr<ParametricCurve<3, Real>> const& GetMedial() const
- {
- return mMedial;
- }
- inline std::function<Real(Real)> const& GetRadial() const
- {
- return mRadial;
- }
- inline bool IsClosed() const
- {
- return mClosed;
- }
- inline bool IsSampleByArcLength() const
- {
- return mSampleByArcLength;
- }
- inline Vector3<Real> const& GetUpVector() const
- {
- return mUpVector;
- }
- private:
- void InitializeTCoords()
- {
- Vector2<Real>tcoord;
- for (unsigned int r = 0, i = 0; r < this->mDescription.numRows; ++r)
- {
- tcoord[1] = (Real)r / (Real)this->mDescription.rMax;
- for (unsigned int c = 0; c <= this->mDescription.numCols; ++c, ++i)
- {
- tcoord[0] = (Real)c / (Real)this->mDescription.numCols;
- this->TCoord(i) = tcoord;
- }
- }
- }
- virtual void UpdatePositions() override
- {
- uint32_t row, col, v, save;
- for (row = 0, v = 0; row < this->mDescription.numRows; ++row, ++v)
- {
- Real t = mTSampler(row);
- Real radius = mRadial(t);
- // frame = (position, tangent, normal, binormal)
- std::array<Vector3<Real>, 4> frame = mFSampler(t);
- for (col = 0, save = v; col < this->mDescription.numCols; ++col, ++v)
- {
- this->Position(v) = frame[0] + radius * (mCosAngle[col] * frame[2] +
- mSinAngle[col] * frame[3]);
- }
- this->Position(v) = this->Position(save);
- }
- if (mClosed)
- {
- for (col = 0; col < this->mDescription.numCols; ++col)
- {
- uint32_t i0 = col;
- uint32_t i1 = col + this->mDescription.numCols * (this->mDescription.numRows - 1);
- this->Position(i1) = this->Position(i0);
- }
- }
- }
- std::shared_ptr<ParametricCurve<3, Real>> mMedial;
- std::function<Real(Real)> mRadial;
- bool mClosed, mSampleByArcLength;
- Vector3<Real> mUpVector;
- std::vector<Real> mCosAngle, mSinAngle;
- std::function<Real(unsigned int)> mTSampler;
- std::function<std::array<Vector3<Real>, 4>(Real)> mFSampler;
- std::unique_ptr<FrenetFrame3<Real>> mFrenet;
- // If the client does not request texture coordinates, they will be
- // computed internally for use in evaluation of the surface geometry.
- std::vector<Vector2<Real>> mDefaultTCoords;
- };
- }
|