aboutsummaryrefslogtreecommitdiff
path: root/externals/g3dlite/G3D.lib/source/MeshAlgAdjacency.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'externals/g3dlite/G3D.lib/source/MeshAlgAdjacency.cpp')
-rw-r--r--externals/g3dlite/G3D.lib/source/MeshAlgAdjacency.cpp729
1 files changed, 0 insertions, 729 deletions
diff --git a/externals/g3dlite/G3D.lib/source/MeshAlgAdjacency.cpp b/externals/g3dlite/G3D.lib/source/MeshAlgAdjacency.cpp
deleted file mode 100644
index a8b35f32c86..00000000000
--- a/externals/g3dlite/G3D.lib/source/MeshAlgAdjacency.cpp
+++ /dev/null
@@ -1,729 +0,0 @@
-/**
- @file MeshAlgAdjacency.cpp
-
- @maintainer Morgan McGuire, matrix@graphics3d.com
- @created 2003-09-14
- @edited 2005-02-24
-
- Copyright 2000-2003, Morgan McGuire.
- All rights reserved.
-
- */
-
-#include "G3D/Table.h"
-#include "G3D/MeshAlg.h"
-#include "G3D/Set.h"
-
-
-namespace G3D {
-
-/**
- A half [i.e. directed] edge.
- */
-class MeshDirectedEdgeKey {
-public:
-
- /** vertexIndex[0] <= vertexIndex[1] */
- int vertexIndex[2];
-
- MeshDirectedEdgeKey() {}
-
- MeshDirectedEdgeKey(
- const int i0,
- const int i1) {
-
- if (i0 <= i1) {
- vertexIndex[0] = i0;
- vertexIndex[1] = i1;
- } else {
- vertexIndex[0] = i1;
- vertexIndex[1] = i0;
- }
- }
-
-
- bool operator==(const MeshDirectedEdgeKey& e2) const {
- for (int i = 0; i < 2; ++i) {
- if (vertexIndex[i] != e2.vertexIndex[i]) {
- return false;
- }
- }
- return true;
- }
-};
-
-}
-
-template<> struct HashTrait<G3D::MeshDirectedEdgeKey> {
- static size_t hashCode(const G3D::MeshDirectedEdgeKey& key) {
- return key.vertexIndex[0] + (key.vertexIndex[1] << 16);
- }
-};
-
-namespace G3D {
-
-/**
- A hashtable mapping edges to lists of indices for
- faces. This is used instead of Table because of the
- special logic in insert.
-
- Used only for MeshAlg::computeAdjacency.
-
- In the face lists, index <I>f</I> >= 0 indicates that
- <I>f</I> contains the edge as a forward edge. Index <I>f</I> < 0
- indicates that ~<I>f</I> contains the edge as a backward edge.
- */
-class MeshEdgeTable {
-public:
- typedef Table<MeshDirectedEdgeKey, Array<int> > ET;
-
-private:
-
- ET table;
-
-public:
-
- /**
- Clears the table.
- */
- void clear() {
- table.clear();
- }
-
- /**
- Inserts the faceIndex into the edge's face list.
- The index may be a negative number indicating a backface.
- */
- void insert(const MeshDirectedEdgeKey& edge, int faceIndex) {
-
- // debugAssertM((table.size() > 20) && (table.debugGetLoad() < 0.5 || table.debugGetNumBuckets() < 20),
- // "MeshEdgeTable is using a poor hash function.");
-
- if (! table.containsKey(edge)) {
- // First time
- Array<int> x(1);
- x[0] = faceIndex;
- table.set(edge, x);
- } else {
- table[edge].append(faceIndex);
- }
- }
-
- /**
- Returns the face list for a given edge
- */
- const Array<int>& get(const MeshDirectedEdgeKey& edge) {
- return table[edge];
- }
-
- ET::Iterator begin() {
- return table.begin();
- }
-
- const ET::Iterator end() const {
- return table.end();
- }
-
-};
-
-
-/**
- edgeTable[edgeKey] is a list of faces containing
-
- Used and cleared by MeshModel::computeAdjacency()
- */
-static MeshEdgeTable edgeTable;
-
-/**
- Assigns the edge index into the next unassigned edge
- index. The edge index may be negative, indicating
- a reverse edge.
- */
-static void assignEdgeIndex(MeshAlg::Face& face, int e) {
- for (int i = 0; i < 3; ++i) {
- if (face.edgeIndex[i] == MeshAlg::Face::NONE) {
- face.edgeIndex[i] = e;
- return;
- }
- }
-
- debugAssertM(false, "Face has already been assigned 3 edges");
-}
-
-
-void MeshAlg::computeAdjacency(
- const Array<Vector3>& vertexGeometry,
- const Array<int>& indexArray,
- Array<Face>& faceArray,
- Array<Edge>& edgeArray,
- Array< Array<int> >& adjacentFaceArray) {
-
- Array<Vertex> vertexArray;
-
- computeAdjacency(vertexGeometry, indexArray, faceArray, edgeArray, vertexArray);
-
- // Convert the vertexArray into adjacentFaceArray
- adjacentFaceArray.clear();
- adjacentFaceArray.resize(vertexArray.size());
- for (int v = 0; v < adjacentFaceArray.size(); ++v) {
- adjacentFaceArray[v] = vertexArray[v].faceIndex;
- }
-}
-
-
-void MeshAlg::computeAdjacency(
- const Array<Vector3>& vertexGeometry,
- const Array<int>& indexArray,
- Array<Face>& faceArray,
- Array<Edge>& edgeArray,
- Array<Vertex>& vertexArray) {
-
- edgeArray.clear();
- vertexArray.clear();
- faceArray.clear();
- edgeTable.clear();
-
- // Face normals
- Array<Vector3> faceNormal;
-
- // This array has the same size as the vertex array
- vertexArray.resize(vertexGeometry.size());
-
- // Iterate through the triangle list
- for (int q = 0; q < indexArray.size(); q += 3) {
-
- Vector3 vertex[3];
- int f = faceArray.size();
- MeshAlg::Face& face = faceArray.next();
-
- // Construct the face
- for (int j = 0; j < 3; ++j) {
- int v = indexArray[q + j];
- face.vertexIndex[j] = v;
- face.edgeIndex[j] = Face::NONE;
-
- // Store back pointers in the vertices
- vertexArray[v].faceIndex.append(f);
-
- // We'll need these vertices to find the face normal
- vertex[j] = vertexGeometry[v];
- }
-
- // Compute the face normal
- Vector3 N = (vertex[1] - vertex[0]).cross(vertex[2] - vertex[0]);
- faceNormal.append(N.directionOrZero());
-
- static const int nextIndex[] = {1, 2, 0};
-
- // Add each edge to the edge table.
- for (int j = 0; j < 3; ++j) {
- const int i0 = indexArray[q + j];
- const int i1 = indexArray[q + nextIndex[j]];
-
- const MeshDirectedEdgeKey edge(i0, i1);
-
- if (i0 == edge.vertexIndex[0]) {
- // The edge was directed in the same manner as in the face
- edgeTable.insert(edge, f);
- } else {
- // The edge was directed in the opposite manner as in the face
- edgeTable.insert(edge, ~f);
- }
- }
- }
-
- // For each edge in the edge table, create an edge in the edge array.
- // Collapse every 2 edges from adjacent faces.
-
- MeshEdgeTable::ET::Iterator cur = edgeTable.begin();
- MeshEdgeTable::ET::Iterator end = edgeTable.end();
-
- Array<Edge> tempEdgeArray;
- while (cur != end) {
- MeshDirectedEdgeKey& edgeKey = cur->key;
- Array<int>& faceIndexArray = cur->value;
-
- // Process this edge
- while (faceIndexArray.size() > 0) {
-
- // Remove the last index
- int f0 = faceIndexArray.pop();
-
- // Find the normal to that face
- const Vector3& n0 = faceNormal[(f0 >= 0) ? f0 : ~f0];
-
- bool found = false;
-
- // We try to find the matching face with the closest
- // normal. This ensures that we don't introduce a lot
- // of artificial ridges into flat parts of a mesh.
- double ndotn = -2;
- int f1 = -1, i1 = -1;
-
- // Try to Find the face with the matching edge
- for (int i = faceIndexArray.size() - 1; i >= 0; --i) {
- int f = faceIndexArray[i];
-
- if ((f >= 0) != (f0 >= 0)) {
- // This face contains the oppositely oriented edge
- // and has not been assigned too many edges
-
- const Vector3& n1 = faceNormal[(f >= 0) ? f : ~f];
- double d = n1.dot(n0);
-
- if (found) {
- // We previously found a good face; see if this
- // one is better.
- if (d > ndotn) {
- // This face is better.
- ndotn = d;
- f1 = f;
- i1 = i;
- }
- } else {
- // This is the first face we've found
- found = true;
- ndotn = d;
- f1 = f;
- i1 = i;
- }
- }
- }
-
- // Create the new edge
- int e = tempEdgeArray.size();
- Edge& edge = tempEdgeArray.next();
-
- edge.vertexIndex[0] = edgeKey.vertexIndex[0];
- edge.vertexIndex[1] = edgeKey.vertexIndex[1];
-
- if (f0 >= 0) {
- edge.faceIndex[0] = f0;
- edge.faceIndex[1] = Face::NONE;
- assignEdgeIndex(faceArray[f0], e);
- } else {
- // The face indices above are two's complemented.
- // this code restores them to regular indices.
- debugAssert((~f0) >= 0);
- edge.faceIndex[1] = ~f0;
- edge.faceIndex[0] = Face::NONE;
-
- // The edge index *does* need to be inverted, however.
- assignEdgeIndex(faceArray[~f0], ~e);
- }
-
- if (found) {
- // We found a matching face; remove both
- // faces from the active list.
- faceIndexArray.fastRemove(i1);
-
- if (f1 >= 0) {
- edge.faceIndex[0] = f1;
- assignEdgeIndex(faceArray[f1], e);
- } else {
- edge.faceIndex[1] = ~f1;
- assignEdgeIndex(faceArray[~f1], ~e);
- }
- }
- }
-
- ++cur;
- }
-
- edgeTable.clear();
-
- // Move boundary edges to the end of the list and then
- // clean up the face references into them
- {
- // Map old edge indices to new edge indices
- Array<int> newIndex(tempEdgeArray.size());
-
-
- // Index of the start and end of the edge array
- int i = 0;
- int j = tempEdgeArray.size() - 1;
-
- edgeArray.resize(tempEdgeArray.size());
- for (int e = 0; e < tempEdgeArray.size(); ++e) {
- if (tempEdgeArray[e].boundary()) {
- newIndex[e] = j;
- --j;
- } else {
- newIndex[e] = i;
- ++i;
- }
- edgeArray[newIndex[e]] = tempEdgeArray[e];
- }
-
- debugAssertM(i == j + 1, "Counting from front and back of array did not match");
-
- // Fix the faces
- for (int f = 0; f < faceArray.size(); ++f) {
- Face& face = faceArray[f];
- for (int q = 0; q < 3; ++q) {
- int e = face.edgeIndex[q];
- if (e < 0) {
- // Backwards edge; twiddle before and after conversion
- face.edgeIndex[q] = ~newIndex[~e];
- } else {
- // Regular edge; remap the index
- face.edgeIndex[q] = newIndex[e];
- }
- }
- }
- }
-
- // Now order the edge indices inside the faces correctly.
- for (int f = 0; f < faceArray.size(); ++f) {
- Face& face = faceArray[f];
- int e0 = face.edgeIndex[0];
- int e1 = face.edgeIndex[1];
- int e2 = face.edgeIndex[2];
-
- // e0 will always remain first. The only
- // question is whether e1 and e2 should be swapped.
-
- // See if e1 begins at the vertex where e1 ends.
- const int e0End = (e0 < 0) ?
- edgeArray[~e0].vertexIndex[0] :
- edgeArray[e0].vertexIndex[1];
-
- const int e1Begin = (e1 < 0) ?
- edgeArray[~e1].vertexIndex[1] :
- edgeArray[e1].vertexIndex[0];
-
- if (e0End != e1Begin) {
- // We must swap e1 and e2
- face.edgeIndex[1] = e2;
- face.edgeIndex[2] = e1;
- }
- }
-
- // Fill out the edge adjacency information in the vertex array
- for (int e = 0; e < edgeArray.size(); ++e) {
- const Edge& edge = edgeArray[e];
- vertexArray[edge.vertexIndex[0]].edgeIndex.append(e);
- vertexArray[edge.vertexIndex[1]].edgeIndex.append(~e);
- }
-}
-
-
-void MeshAlg::weldBoundaryEdges(
- Array<Face>& faceArray,
- Array<Edge>& edgeArray,
- Array<Vertex>& vertexArray) {
-
- // Copy over the original edge array
- Array<Edge> oldEdgeArray = edgeArray;
-
- // newEdgeIndex[e] is the new index of the old edge with index e
- // Note that newEdgeIndex[e] might be negative, indicating that
- // the edge switched direction between the arrays.
- Array<int> newEdgeIndex(edgeArray.size());
- edgeArray.resize(0);
-
- // boundaryEdgeIndices[v_low] is an array of the indices of
- // all boundary edges whose lower vertex is v_low.
- Table<int, Array<int> > boundaryEdgeIndices;
-
- // Copy over non-boundary edges to the new array
- for (int e = 0; e < oldEdgeArray.size(); ++e) {
- if (oldEdgeArray[e].boundary()) {
-
- // Add to the boundary table
- const int v_low = iMin(oldEdgeArray[e].vertexIndex[0], oldEdgeArray[e].vertexIndex[1]);
- if (! boundaryEdgeIndices.containsKey(v_low)) {
- boundaryEdgeIndices.set(v_low, Array<int>());
- }
- boundaryEdgeIndices[v_low].append(e);
-
- // We'll fill out newEdgeIndex[e] later, when we find pairs
-
- } else {
-
- // Copy the edge to the new array
- newEdgeIndex[e] = edgeArray.size();
- edgeArray.append(oldEdgeArray[e]);
-
- }
- }
-
-
- // Remove all edges from the table that have pairs.
- Table<int, Array<int> >::Iterator cur = boundaryEdgeIndices.begin();
- Table<int, Array<int> >::Iterator end = boundaryEdgeIndices.end();
- while (cur != end) {
- Array<int>& boundaryEdge = cur->value;
-
- for (int i = 0; i < boundaryEdge.size(); ++i) {
- int ei = boundaryEdge[i];
- const Edge& edgei = oldEdgeArray[ei];
-
- for (int j = i + 1; j < boundaryEdge.size(); ++j) {
- int ej = boundaryEdge[j];
- const Edge& edgej = oldEdgeArray[ej];
-
- // See if edge ei is the reverse (match) of edge ej.
-
- // True if the edges match
- bool match = false;
-
- // True if edgej's vertex indices are reversed from
- // edgei's (usually true).
- bool reversej = false;
-
- int u = edgei.vertexIndex[0];
- int v = edgei.vertexIndex[1];
-
- if (edgei.faceIndex[0] != Face::NONE) {
- // verts|faces
- // edgei = [u v A /]
-
- if (edgej.faceIndex[0] != Face::NONE) {
- if ((edgej.vertexIndex[0] == v) && (edgej.vertexIndex[1] == u)) {
- // This is the most common of the four cases
-
- // edgej = [v u B /]
- match = true;
- reversej = true;
- }
- } else {
- if ((edgej.vertexIndex[0] == u) && (edgej.vertexIndex[1] == v)) {
- // edgej = [u v / B]
- match = true;
- }
- }
- } else {
- // edgei = [u v / A]
- if (edgej.faceIndex[0] != Face::NONE) {
- if ((edgej.vertexIndex[0] == u) && (edgej.vertexIndex[1] == v)) {
- // edgej = [u v B /]
- match = true;
- }
- } else {
- if ((edgej.vertexIndex[0] == v) && (edgej.vertexIndex[1] == u)) {
- // edgej = [v u / B]
- match = true;
- reversej = true;
- }
- }
- }
-
- if (match) {
- // ei and ej can be paired as a single edge
- int e = edgeArray.size();
- Edge& edge = edgeArray.next();
-
- // Follow the direction of edgei.
- edge = edgei;
- newEdgeIndex[ei] = e;
-
- // Insert the face index for edgej.
- int fj = edgej.faceIndex[0];
- if (fj == Face::NONE) {
- fj = edgej.faceIndex[1];
- }
-
- if (edge.faceIndex[0] == Face::NONE) {
- edge.faceIndex[0] = fj;
- } else {
- edge.faceIndex[1] = fj;
- }
-
- if (reversej) {
- // The new edge is backwards of the old edge for ej
- newEdgeIndex[ej] = ~e;
- } else {
- newEdgeIndex[ej] = e;
- }
-
- // Remove both ei and ej from being candidates for future pairing.
- // Remove ej first since it comes later in the list (removing
- // ei would decrease the index of ej to j - 1).
- boundaryEdge.fastRemove(j);
- boundaryEdge.fastRemove(i);
-
- // Re-process element i, which is now a new edge index
- --i;
-
- // Jump out of the j for-loop
- break;
- }
- }
- }
- ++cur;
- }
-
- // Anything remaining in the table is a real boundary edge; just copy it to
- // the end of the array.
- cur = boundaryEdgeIndices.begin();
- end = boundaryEdgeIndices.end();
- while (cur != end) {
- Array<int>& boundaryEdge = cur->value;
-
- for (int b = 0; b < boundaryEdge.size(); ++b) {
- const int e = boundaryEdge[b];
-
- newEdgeIndex[e] = edgeArray.size();
- edgeArray.append(oldEdgeArray[e]);
- }
-
- ++cur;
- }
-
- // Finally, fix up edge indices in the face and vertex arrays
- for (int f = 0; f < faceArray.size(); ++f) {
- Face& face = faceArray[f];
- for (int i = 0; i < 3; ++i) {
- int e = face.edgeIndex[i];
-
- if (e < 0) {
- face.edgeIndex[i] = ~newEdgeIndex[~e];
- } else {
- face.edgeIndex[i] = newEdgeIndex[e];
- }
- }
- }
-
- for (int v = 0; v < vertexArray.size(); ++v) {
- Vertex& vertex = vertexArray[v];
- for (int i = 0; i < vertex.edgeIndex.size(); ++i) {
- int e = vertex.edgeIndex[i];
-
- if (e < 0) {
- vertex.edgeIndex[i] = ~newEdgeIndex[~e];
- } else {
- vertex.edgeIndex[i] = newEdgeIndex[e];
- }
- }
- }
-}
-
-
-void MeshAlg::weldAdjacency(
- const Array<Vector3>& originalGeometry,
- Array<Face>& faceArray,
- Array<Edge>& edgeArray,
- Array<Vertex>& vertexArray,
- double radius) {
-
- // Num vertices
- const int n = originalGeometry.size();
-
- // canonical[v] = first occurance of any vertex near oldVertexArray[v]
- Array<int> canonical(n);
-
- Array<int> toNew, toOld;
- // Throw away the new vertex array
- Array<Vector3> dummy;
- computeWeld(originalGeometry, dummy, toNew, toOld, radius);
-
- for (int v = 0; v < canonical.size(); ++v) {
- // Round-trip through the toNew/toOld process. This will give
- // us the original vertex.
- canonical[v] = toOld[toNew[v]];
- }
-
- // Destroy vertexArray (we reconstruct it below)
- vertexArray.clear();
- vertexArray.resize(n);
-
- bool hasBoundaryEdges = false;
-
- // Fix edge vertex indices
- for (int e = 0; e < edgeArray.size(); ++e) {
- Edge& edge = edgeArray[e];
-
- const int v0 = canonical[edge.vertexIndex[0]];
- const int v1 = canonical[edge.vertexIndex[1]];
-
- edge.vertexIndex[0] = v0;
- edge.vertexIndex[1] = v1;
-
- vertexArray[v0].edgeIndex.append(e);
- vertexArray[v1].edgeIndex.append(~e);
-
- hasBoundaryEdges = hasBoundaryEdges || edge.boundary();
- }
-
- // Fix face vertex indices
- for (int f = 0; f < faceArray.size(); ++f) {
- Face& face = faceArray[f];
- for (int i = 0; i < 3; ++i) {
- const int v = canonical[face.vertexIndex[i]];
-
- face.vertexIndex[i] = v;
-
- // Add the back pointer
- vertexArray[v].faceIndex.append(f);
- }
- }
-
- if (hasBoundaryEdges) {
- // As a result of the welding, some of the boundary edges at
- // the end of the array may now have mates and no longer be
- // boundaries. Try to pair these up.
-
- weldBoundaryEdges(faceArray, edgeArray, vertexArray);
- }
-}
-
-
-void MeshAlg::debugCheckConsistency(
- const Array<Face>& faceArray,
- const Array<Edge>& edgeArray,
- const Array<Vertex>& vertexArray) {
-
-#ifdef _DEBUG
- for (int v = 0; v < vertexArray.size(); ++v) {
- const MeshAlg::Vertex& vertex = vertexArray[v];
-
- for (int i = 0; i < vertex.edgeIndex.size(); ++i) {
- const int e = vertex.edgeIndex[i];
- debugAssert(edgeArray[(e >= 0) ? e : ~e].containsVertex(v));
- }
-
- for (int i = 0; i < vertex.faceIndex.size(); ++i) {
- const int f = vertex.faceIndex[i];
- debugAssert(faceArray[f].containsVertex(v));
- }
-
- }
-
- for (int e = 0; e < edgeArray.size(); ++e) {
- const MeshAlg::Edge& edge = edgeArray[e];
-
- for (int i = 0; i < 2; ++i) {
- debugAssert((edge.faceIndex[i] == MeshAlg::Face::NONE) ||
- faceArray[edge.faceIndex[i]].containsEdge(e));
-
- debugAssert(vertexArray[edge.vertexIndex[i]].inEdge(e));
- }
- }
-
- // Every face's edge must be on that face
- for (int f = 0; f < faceArray.size(); ++f) {
- const MeshAlg::Face& face = faceArray[f];
- for (int i = 0; i < 3; ++i) {
- int e = face.edgeIndex[i];
- int ei = (e >= 0) ? e : ~e;
- debugAssert(edgeArray[ei].inFace(f));
-
- // Make sure the edge is oriented appropriately
- if (e >= 0) {
- debugAssert(edgeArray[ei].faceIndex[0] == (int)f);
- } else {
- debugAssert(edgeArray[ei].faceIndex[1] == (int)f);
- }
-
- debugAssert(vertexArray[face.vertexIndex[i]].inFace(f));
- }
- }
-#else
- (void)faceArray;
- (void)edgeArray;
- (void)vertexArray;
-#endif // _DEBUG
-}
-
-} // G3D namespace