123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- // 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/Logger.h>
- #include <Mathematics/MinHeap.h>
- #include <Mathematics/DistPointSegment.h>
- #include <vector>
- // The continuous level of detail (CLOD) algorithm implemented here is
- // described in
- // https://www.geometrictools.com/Documentation/PolylineReduction.pdf
- // It is an algorithm to reduce incrementally the number of vertices in a
- // polyline (open or closed). The sequence of vertex collapses is based on
- // vertex weights associated with distance from vertices to polyline segments.
- namespace WwiseGTE
- {
- template <int N, typename Real>
- class CLODPolyline
- {
- public:
- // Constructor and destructor. The number of vertices must be 2 or
- // larger. The vertices are assumed to be ordered. The segments are
- // <V[i],V[i+1]> for 0 <= i <= numVertices-2 for an open polyline.
- // If the polyline is closed, an additional segment is
- // <V[numVertices-1],V[0]>.
- CLODPolyline(std::vector<Vector<N, Real>> const& vertices, bool closed)
- :
- mNumVertices(static_cast<int>(vertices.size())),
- mVertices(vertices),
- mClosed(closed),
- mNumEdges(0),
- mVMin(mClosed ? 3 : 2),
- mVMax(mNumVertices)
- {
- LogAssert(closed ? mNumVertices >= 3 : mNumVertices >= 2, "Invalid inputs.");
- // Compute the sequence of vertex collapses. The polyline starts
- // out at the full level of detail (mNumVertices equals mVMax).
- VertexCollapse collapser;
- collapser(mVertices, mClosed, mIndices, mNumEdges, mEdges);
- }
- ~CLODPolyline() = default;
- // Member access.
- inline int GetNumVertices() const
- {
- return mNumVertices;
- }
- inline std::vector<Vector<N, Real>> const& GetVertices() const
- {
- return mVertices;
- }
- inline bool GetClosed() const
- {
- return mClosed;
- }
- inline int GetNumEdges() const
- {
- return mNumEdges;
- }
- inline std::vector<int> const& GetEdges() const
- {
- return mEdges;
- }
- // Accessors to level of detail (MinLOD <= LOD <= MaxLOD is required).
- inline int GetMinLevelOfDetail() const
- {
- return mVMin;
- }
- inline int GetMaxLevelOfDetail() const
- {
- return mVMax;
- }
- inline int GetLevelOfDetail() const
- {
- return mNumVertices;
- }
- void SetLevelOfDetail(int numVertices)
- {
- if (numVertices < mVMin || numVertices > mVMax)
- {
- return;
- }
- // Decrease the level of detail.
- while (mNumVertices > numVertices)
- {
- --mNumVertices;
- mEdges[mIndices[mNumVertices]] = mEdges[2 * mNumEdges - 1];
- --mNumEdges;
- }
- // Increase the level of detail.
- while (mNumVertices < numVertices)
- {
- ++mNumEdges;
- mEdges[mIndices[mNumVertices]] = mNumVertices;
- ++mNumVertices;
- }
- }
- private:
- // Support for vertex collapses in a polyline.
- class VertexCollapse
- {
- public:
- void operator()(std::vector<Vector<N, Real>>& vertices,
- bool closed, std::vector<int>& indices, int& numEdges,
- std::vector<int>& edges)
- {
- int numVertices = static_cast<int>(vertices.size());
- indices.resize(vertices.size());
- if (closed)
- {
- numEdges = numVertices;
- edges.resize(2 * numEdges);
- if (numVertices == 3)
- {
- indices[0] = 0;
- indices[1] = 1;
- indices[2] = 3;
- edges[0] = 0; edges[1] = 1;
- edges[2] = 1; edges[3] = 2;
- edges[4] = 2; edges[5] = 0;
- return;
- }
- }
- else
- {
- numEdges = numVertices - 1;
- edges.resize(2 * numEdges);
- if (numVertices == 2)
- {
- indices[0] = 0;
- indices[1] = 1;
- edges[0] = 0; edges[1] = 1;
- return;
- }
- }
- // Create the heap of weights.
- MinHeap<int, Real> heap(numVertices);
- int qm1 = numVertices - 1;
- if (closed)
- {
- int qm2 = numVertices - 2;
- heap.Insert(0, GetWeight(qm1, 0, 1, vertices));
- heap.Insert(qm1, GetWeight(qm2, qm1, 0, vertices));
- }
- else
- {
- heap.Insert(0, std::numeric_limits<Real>::max());
- heap.Insert(qm1, std::numeric_limits<Real>::max());
- }
- for (int m = 0, z = 1, p = 2; z < qm1; ++m, ++z, ++p)
- {
- heap.Insert(z, GetWeight(m, z, p, vertices));
- }
- // Create the level of detail information for the polyline.
- std::vector<int> collapses(numVertices);
- CollapseVertices(heap, numVertices, collapses);
- ComputeEdges(numVertices, closed, collapses, indices, numEdges, edges);
- ReorderVertices(numVertices, vertices, collapses, numEdges, edges);
- }
- protected:
- // Weight calculation for vertex triple <V[m],V[z],V[p]>.
- Real GetWeight(int m, int z, int p, std::vector<Vector<N, Real>>& vertices)
- {
- Vector<N, Real> direction = vertices[p] - vertices[m];
- Real length = Normalize(direction);
- if (length > (Real)0)
- {
- Segment<N, Real> segment(vertices[m], vertices[p]);
- DCPQuery<Real, Vector<N, Real>, Segment<N, Real>> query;
- Real distance = query(vertices[z], segment).distance;
- return distance / length;
- }
- else
- {
- return std::numeric_limits<Real>::max();
- }
- }
- // Create data structures for the polyline.
- void CollapseVertices(MinHeap<int, Real>& heap,
- int numVertices, std::vector<int>& collapses)
- {
- for (int i = numVertices - 1; i >= 0; --i)
- {
- Real weight;
- heap.Remove(collapses[i], weight);
- }
- }
- void ComputeEdges(int numVertices, bool closed, std::vector<int>& collapses,
- std::vector<int>& indices, int numEdges, std::vector<int>& edges)
- {
- // Compute the edges (first to collapse is last in array). Do
- // not collapse the last line segment of an open polyline. Do
- // not collapse further when a closed polyline becomes a
- // triangle.
- int i, vIndex, eIndex = 2 * numEdges - 1;
- if (closed)
- {
- for (i = numVertices - 1; i >= 0; --i)
- {
- vIndex = collapses[i];
- edges[eIndex--] = (vIndex + 1) % numVertices;
- edges[eIndex--] = vIndex;
- }
- }
- else
- {
- for (i = numVertices - 1; i >= 2; --i)
- {
- vIndex = collapses[i];
- edges[eIndex--] = vIndex + 1;
- edges[eIndex--] = vIndex;
- }
- vIndex = collapses[0];
- edges[0] = vIndex;
- edges[1] = vIndex + 1;
- }
- // In the given edge order, find the index in the edge array
- // that corresponds to a collapse vertex and save the index
- // for the dynamic change in level of detail. This relies on
- // the assumption that a vertex is shared by at most two
- // edges.
- eIndex = 2 * numEdges - 1;
- for (i = numVertices - 1; i >= 0; --i)
- {
- vIndex = collapses[i];
- for (int e = 0; e < 2 * numEdges; ++e)
- {
- if (vIndex == edges[e])
- {
- indices[i] = e;
- edges[e] = edges[eIndex];
- break;
- }
- }
- eIndex -= 2;
- if (closed)
- {
- if (eIndex == 5)
- {
- break;
- }
- }
- else
- {
- if (eIndex == 1)
- {
- break;
- }
- }
- }
- // Restore the edge array to full level of detail.
- if (closed)
- {
- for (i = 3; i < numVertices; ++i)
- {
- edges[indices[i]] = collapses[i];
- }
- }
- else
- {
- for (i = 2; i < numVertices; ++i)
- {
- edges[indices[i]] = collapses[i];
- }
- }
- }
- void ReorderVertices(int numVertices, std::vector<Vector<N, Real>>& vertices,
- std::vector<int>& collapses, int numEdges, std::vector<int>& edges)
- {
- std::vector<int> permute(numVertices);
- std::vector<Vector<N, Real>> permutedVertex(numVertices);
- for (int i = 0; i < numVertices; ++i)
- {
- int vIndex = collapses[i];
- permute[vIndex] = i;
- permutedVertex[i] = vertices[vIndex];
- }
- for (int i = 0; i < 2 * numEdges; ++i)
- {
- edges[i] = permute[edges[i]];
- }
- vertices = permutedVertex;
- }
- };
- private:
- // The polyline vertices.
- int mNumVertices;
- std::vector<Vector<N, Real>> mVertices;
- bool mClosed;
- // The polyline edges.
- int mNumEdges;
- std::vector<int> mEdges;
- // The level of detail information.
- int mVMin, mVMax;
- std::vector<int> mIndices;
- };
- }
|