mirror of
https://github.com/mangosfour/server.git
synced 2025-12-31 13:37:07 +00:00
+ Got rid of zip lib requirement in G3D...
Still can re-enable code by defining _HAVE_ZIP...
+ Remove silly X11 lib dependency from G3D
Code doesn't seem to do anything yet anyway, and even if, we don't want it :p
+ Fix another weird G3D build problem...
+ Remove some __asm usage in g3d, which is not available on Win64
My editor also decided to remove a ton of trailing white spaces...tss...
+ Reapply G3D fixes for 64bit VC
+ not use SSE specific header when SSE not enabled in *nix
+ Updated project files
+ New vmap_assembler VC90/VC80 Project
+ vmap assembler binaries updates
NOTE: Old vmap fikes expected work (as tests show) with new library version.
But better use new generated versions. Its different in small parts to bad or good...
(based on Lynx3d's repo commit 44798d3)
Signed-off-by: VladimirMangos <vladimir@getmangos.com>
739 lines
22 KiB
C++
739 lines
22 KiB
C++
/**
|
|
@file MeshAlgAdjacency.cpp
|
|
|
|
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
|
@created 2003-09-14
|
|
@edited 2009-04-26
|
|
|
|
Copyright 2000-2009, Morgan McGuire.
|
|
All rights reserved.
|
|
|
|
*/
|
|
|
|
#include "G3D/Table.h"
|
|
#include "G3D/MeshAlg.h"
|
|
#include "G3D/Set.h"
|
|
#include "G3D/Stopwatch.h"
|
|
#include "G3D/SmallArray.h"
|
|
|
|
namespace G3D {
|
|
|
|
/** Two-level table mapping index 0 -> index 1 -> list of face indices */
|
|
class MeshEdgeTable {
|
|
public:
|
|
|
|
/** We expect 2 faces per edge. */
|
|
typedef SmallArray<int, 2> FaceIndexArray;
|
|
|
|
class Edge {
|
|
public:
|
|
int i1;
|
|
|
|
FaceIndexArray faceIndexArray;
|
|
};
|
|
|
|
/** We expect at most 6 edges per vertex; that matches a typical regular grid mesh */
|
|
typedef SmallArray<Edge, 6> EdgeArray;
|
|
|
|
typedef Array< EdgeArray > ET;
|
|
|
|
private:
|
|
|
|
ET table;
|
|
|
|
public:
|
|
|
|
void clear() {
|
|
table.clear();
|
|
}
|
|
|
|
void resize(int maxV) {
|
|
table.resize(maxV);
|
|
}
|
|
|
|
/**
|
|
Inserts the faceIndex into the edge's face list.
|
|
The index may be a negative number indicating a backface.
|
|
|
|
\param v0 Vertex index 0
|
|
\param v1 Vertex index 1
|
|
*/
|
|
void insert(int v0, int v1, int faceIndex) {
|
|
|
|
debugAssert(v0 <= v1);
|
|
EdgeArray& edgeArray = table[v0];
|
|
for (int i = 0; i < edgeArray.size(); ++i) {
|
|
if (edgeArray[i].i1 == v1) {
|
|
edgeArray[i].faceIndexArray.push(faceIndex);
|
|
return;
|
|
}
|
|
}
|
|
|
|
Edge& p = edgeArray.next();
|
|
p.i1 = v1;
|
|
p.faceIndexArray.push(faceIndex);
|
|
}
|
|
|
|
class Iterator {
|
|
friend class MeshEdgeTable;
|
|
private:
|
|
|
|
int m_i0;
|
|
/** Pair index */
|
|
int m_p;
|
|
ET& m_array;
|
|
EdgeArray* m_edgeArray;
|
|
bool m_end;
|
|
|
|
public:
|
|
|
|
int i0() const {
|
|
return m_i0;
|
|
}
|
|
|
|
int i1() const {
|
|
return (*m_edgeArray)[m_p].i1;
|
|
}
|
|
|
|
FaceIndexArray& faceIndex() {
|
|
return (*m_edgeArray)[m_p].faceIndexArray;
|
|
}
|
|
|
|
Iterator& operator++() {
|
|
if ((m_i0 >= 0) && (m_p < m_edgeArray->size() - 1)) {
|
|
++m_p;
|
|
} else {
|
|
// Skip over elements with no face array
|
|
do {
|
|
++m_i0;
|
|
if (m_i0 == m_array.size()) {
|
|
m_end = true;
|
|
return *this;
|
|
} else {
|
|
m_edgeArray = &m_array[m_i0];
|
|
m_p = 0;
|
|
}
|
|
} while (m_edgeArray->size() == 0);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
bool hasMore() const {
|
|
return ! m_end;
|
|
}
|
|
|
|
private:
|
|
|
|
Iterator(ET& a) : m_i0(-1), m_p(-1), m_array(a), m_edgeArray(NULL), m_end(false) {
|
|
++(*this);
|
|
}
|
|
|
|
};
|
|
|
|
Iterator begin() {
|
|
return Iterator(table);
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
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) {
|
|
const SmallArray<int, 6>& src = vertexArray[v].faceIndex;
|
|
Array<int>& dst = adjacentFaceArray[v];
|
|
dst.resize(src.size());
|
|
for (int f = 0; f < dst.size(); ++f) {
|
|
dst[f] = src[f];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void MeshAlg::computeAdjacency(
|
|
const Array<Vector3>& vertexGeometry,
|
|
const Array<int>& indexArray,
|
|
Array<Face>& faceArray,
|
|
Array<Edge>& edgeArray,
|
|
Array<Vertex>& vertexArray) {
|
|
|
|
MeshEdgeTable edgeTable;
|
|
|
|
edgeArray.clear();
|
|
vertexArray.clear();
|
|
faceArray.clear();
|
|
|
|
// Face normals
|
|
Array<Vector3> faceNormal;
|
|
faceNormal.resize(indexArray.size() / 3);
|
|
faceArray.resize(faceNormal.size());
|
|
|
|
// This array has the same size as the vertex array
|
|
vertexArray.resize(vertexGeometry.size());
|
|
|
|
edgeTable.resize(vertexArray.size());
|
|
|
|
// Iterate through the triangle list
|
|
for (int q = 0, f = 0; q < indexArray.size(); ++f, q += 3) {
|
|
|
|
Vector3 vertex[3];
|
|
MeshAlg::Face& face = faceArray[f];
|
|
|
|
// 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
|
|
const Vector3& N = (vertex[1] - vertex[0]).cross(vertex[2] - vertex[0]);
|
|
faceNormal[f] = 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]];
|
|
|
|
if (i0 < i1) {
|
|
// The edge was directed in the same manner as in the face
|
|
edgeTable.insert(i0, i1, f);
|
|
} else {
|
|
// The edge was directed in the opposite manner as in the face
|
|
edgeTable.insert(i1, i0, ~f);
|
|
}
|
|
}
|
|
}
|
|
|
|
// For each edge in the edge table, create an edge in the edge array.
|
|
// Collapse every 2 edges from adjacent faces.
|
|
|
|
MeshEdgeTable::Iterator cur = edgeTable.begin();
|
|
|
|
Array<Edge> tempEdgeArray;
|
|
while (cur.hasMore()) {
|
|
MeshEdgeTable::FaceIndexArray& faceIndexArray = cur.faceIndex();
|
|
|
|
// 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.
|
|
float 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];
|
|
float 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] = cur.i0();
|
|
edge.vertexIndex[1] = cur.i1();
|
|
|
|
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;
|
|
newIndex.resize(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;
|
|
newEdgeIndex.resize(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;
|
|
canonical.resize(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
|