GteETManifoldMesh.cpp
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.1 (2017/01/02)
7 
8 #include <GTEnginePCH.h>
9 #include <LowLevel/GteLogger.h>
11 using namespace gte;
12 
14 {
15 }
16 
18  :
19  mECreator(eCreator ? eCreator : CreateEdge),
20  mTCreator(tCreator ? tCreator : CreateTriangle),
22 {
23 }
24 
26 {
27  *this = mesh;
28 }
29 
31 {
32  Clear();
33 
34  mECreator = mesh.mECreator;
35  mTCreator = mesh.mTCreator;
37  for (auto const& element : mesh.mTMap)
38  {
39  Insert(element.first.V[0], element.first.V[1], element.first.V[2]);
40  }
41 
42  return *this;
43 }
44 
46 {
47  return mEMap;
48 }
49 
51 {
52  return mTMap;
53 }
54 
56 {
57  std::swap(doAssert, mAssertOnNonmanifoldInsertion);
58  return doAssert; // return the previous state
59 }
60 
61 std::shared_ptr<ETManifoldMesh::Triangle> ETManifoldMesh::Insert(int v0, int v1, int v2)
62 {
63  TriangleKey<true> tkey(v0, v1, v2);
64  if (mTMap.find(tkey) != mTMap.end())
65  {
66  // The triangle already exists. Return a null pointer as a signal to
67  // the caller that the insertion failed.
68  return nullptr;
69  }
70 
71  // Create the new triangle. It will be added to mTMap at the end of the
72  // function so that if an assertion is triggered and the function returns
73  // early, the (bad) triangle will not be part of the mesh.
74  std::shared_ptr<Triangle> tri = mTCreator(v0, v1, v2);
75 
76  // Add the edges to the mesh if they do not already exist.
77  for (int i0 = 2, i1 = 0; i1 < 3; i0 = i1++)
78  {
79  EdgeKey<false> ekey(tri->V[i0], tri->V[i1]);
80  std::shared_ptr<Edge> edge;
81  auto eiter = mEMap.find(ekey);
82  if (eiter == mEMap.end())
83  {
84  // This is the first time the edge is encountered.
85  edge = mECreator(tri->V[i0], tri->V[i1]);
86  mEMap[ekey] = edge;
87 
88  // Update the edge and triangle.
89  edge->T[0] = tri;
90  tri->E[i0] = edge;
91  }
92  else
93  {
94  // This is the second time the edge is encountered.
95  edge = eiter->second;
96  if (!edge)
97  {
98  LogError("Unexpected condition.");
99  return nullptr;
100  }
101 
102  // Update the edge.
103  if (edge->T[1].lock())
104  {
106  {
107  LogInformation("The mesh must be manifold.");
108  }
109  return nullptr;
110  }
111  edge->T[1] = tri;
112 
113  // Update the adjacent triangles.
114  auto adjacent = edge->T[0].lock();
115  if (!adjacent)
116  {
117  LogError("Unexpected condition.");
118  return nullptr;
119  }
120  for (int j = 0; j < 3; ++j)
121  {
122  if (adjacent->E[j].lock() == edge)
123  {
124  adjacent->T[j] = tri;
125  break;
126  }
127  }
128 
129  // Update the triangle.
130  tri->E[i0] = edge;
131  tri->T[i0] = adjacent;
132  }
133  }
134 
135  mTMap[tkey] = tri;
136  return tri;
137 }
138 
139 bool ETManifoldMesh::Remove(int v0, int v1, int v2)
140 {
141  TriangleKey<true> tkey(v0, v1, v2);
142  auto titer = mTMap.find(tkey);
143  if (titer == mTMap.end())
144  {
145  // The triangle does not exist.
146  return false;
147  }
148 
149  // Get the triangle.
150  std::shared_ptr<Triangle> tri = titer->second;
151 
152  // Remove the edges and update adjacent triangles if necessary.
153  for (int i = 0; i < 3; ++i)
154  {
155  // Inform the edges the triangle is being deleted.
156  auto edge = tri->E[i].lock();
157  if (!edge)
158  {
159  // The triangle edge should be nonnull.
160  LogError("Unexpected condition.");
161  return false;
162  }
163 
164  if (edge->T[0].lock() == tri)
165  {
166  // One-triangle edges always have pointer at index zero.
167  edge->T[0] = edge->T[1];
168  edge->T[1].reset();
169  }
170  else if (edge->T[1].lock() == tri)
171  {
172  edge->T[1].reset();
173  }
174  else
175  {
176  LogError("Unexpected condition.");
177  return false;
178  }
179 
180  // Remove the edge if you have the last reference to it.
181  if (!edge->T[0].lock() && !edge->T[1].lock())
182  {
183  EdgeKey<false> ekey(edge->V[0], edge->V[1]);
184  mEMap.erase(ekey);
185  }
186 
187  // Inform adjacent triangles the triangle is being deleted.
188  auto adjacent = tri->T[i].lock();
189  if (adjacent)
190  {
191  for (int j = 0; j < 3; ++j)
192  {
193  if (adjacent->T[j].lock() == tri)
194  {
195  adjacent->T[j].reset();
196  break;
197  }
198  }
199  }
200  }
201 
202  mTMap.erase(tkey);
203  return true;
204 }
205 
207 {
208  mEMap.clear();
209  mTMap.clear();
210 }
211 
213 {
214  for (auto const& element : mEMap)
215  {
216  auto edge = element.second;
217  if (!edge->T[0].lock() || !edge->T[1].lock())
218  {
219  return false;
220  }
221  }
222  return true;
223 }
224 
226 {
227  for (auto const& element : mEMap)
228  {
229  auto edge = element.second;
230  if (edge->T[0].lock() && edge->T[1].lock())
231  {
232  // In each triangle, find the ordered edge that corresponds to the
233  // unordered edge element.first. Also find the vertex opposite
234  // that edge.
235  bool edgePositive[2] = { false, false };
236  int vOpposite[2] = { -1, -1 };
237  for (int j = 0; j < 2; ++j)
238  {
239  auto tri = edge->T[j].lock();
240  for (int i = 0; i < 3; ++i)
241  {
242  if (tri->V[i] == element.first.V[0])
243  {
244  int vNext = tri->V[(i + 1) % 3];
245  if (vNext == element.first.V[1])
246  {
247  edgePositive[j] = true;
248  vOpposite[j] = tri->V[(i + 2) % 3];
249  }
250  else
251  {
252  edgePositive[j] = false;
253  vOpposite[j] = vNext;
254  }
255  break;
256  }
257  }
258  }
259 
260  // To be oriented consistently, the edges must have reversed
261  // ordering and the oppositive vertices cannot match.
262  if (edgePositive[0] == edgePositive[1] || vOpposite[0] == vOpposite[1])
263  {
264  return false;
265  }
266  }
267  }
268  return true;
269 }
270 
272  std::vector<std::vector<std::shared_ptr<Triangle>>>& components) const
273 {
274  // visited: 0 (unvisited), 1 (discovered), 2 (finished)
275  std::map<std::shared_ptr<Triangle>, int> visited;
276  for (auto const& element : mTMap)
277  {
278  visited.insert(std::make_pair(element.second, 0));
279  }
280 
281  for (auto& element : mTMap)
282  {
283  auto tri = element.second;
284  if (visited[tri] == 0)
285  {
286  std::vector<std::shared_ptr<Triangle>> component;
287  DepthFirstSearch(tri, visited, component);
288  components.push_back(component);
289  }
290  }
291 }
292 
294  std::vector<std::vector<TriangleKey<true>>>& components) const
295 {
296  // visited: 0 (unvisited), 1 (discovered), 2 (finished)
297  std::map<std::shared_ptr<Triangle>, int> visited;
298  for (auto const& element : mTMap)
299  {
300  visited.insert(std::make_pair(element.second, 0));
301  }
302 
303  for (auto& element : mTMap)
304  {
305  std::shared_ptr<Triangle> tri = element.second;
306  if (visited[tri] == 0)
307  {
308  std::vector<std::shared_ptr<Triangle>> component;
309  DepthFirstSearch(tri, visited, component);
310 
311  std::vector<TriangleKey<true>> keyComponent;
312  keyComponent.reserve(component.size());
313  for (auto const& t : component)
314  {
315  keyComponent.push_back(TriangleKey<true>(t->V[0], t->V[1], t->V[2]));
316  }
317  components.push_back(keyComponent);
318  }
319  }
320 }
321 
322 void ETManifoldMesh::DepthFirstSearch(std::shared_ptr<Triangle> const& tInitial,
323  std::map<std::shared_ptr<Triangle>, int>& visited,
324  std::vector<std::shared_ptr<Triangle>>& component) const
325 {
326  // Allocate the maximum-size stack that can occur in the depth-first
327  // search. The stack is empty when the index top is -1.
328  std::vector<std::shared_ptr<Triangle>> tStack(mTMap.size());
329  int top = -1;
330  tStack[++top] = tInitial;
331  while (top >= 0)
332  {
333  std::shared_ptr<Triangle> tri = tStack[top];
334  visited[tri] = 1;
335  int i;
336  for (i = 0; i < 3; ++i)
337  {
338  std::shared_ptr<Triangle> adj = tri->T[i].lock();
339  if (adj && visited[adj] == 0)
340  {
341  tStack[++top] = adj;
342  break;
343  }
344  }
345  if (i == 3)
346  {
347  visited[tri] = 2;
348  component.push_back(tri);
349  --top;
350  }
351  }
352 }
353 
354 std::shared_ptr<ETManifoldMesh::Edge> ETManifoldMesh::CreateEdge(int v0, int v1)
355 {
356  return std::make_shared<Edge>(v0, v1);
357 }
358 
359 std::shared_ptr<ETManifoldMesh::Triangle> ETManifoldMesh::CreateTriangle(int v0, int v1, int v2)
360 {
361  return std::make_shared<Triangle>(v0, v1, v2);
362 }
363 
365 {
366 }
367 
369 {
370  V[0] = v0;
371  V[1] = v1;
372 }
373 
375 {
376 }
377 
379 {
380  V[0] = v0;
381  V[1] = v1;
382  V[2] = v2;
383 }
static std::shared_ptr< Triangle > CreateTriangle(int v0, int v1, int v2)
std::shared_ptr< Triangle >(* TCreator)(int, int, int)
ETManifoldMesh(ECreator eCreator=nullptr, TCreator tCreator=nullptr)
std::map< TriangleKey< true >, std::shared_ptr< Triangle > > TMap
EMap const & GetEdges() const
ETManifoldMesh & operator=(ETManifoldMesh const &mesh)
#define LogInformation(message)
Definition: GteLogger.h:98
GLfloat GLfloat v1
Definition: glcorearb.h:812
bool AssertOnNonmanifoldInsertion(bool doAssert)
static std::shared_ptr< Edge > CreateEdge(int v0, int v1)
#define LogError(message)
Definition: GteLogger.h:92
std::map< EdgeKey< false >, std::shared_ptr< Edge > > EMap
std::shared_ptr< Edge >(* ECreator)(int, int)
virtual std::shared_ptr< Triangle > Insert(int v0, int v1, int v2)
GLfloat v0
Definition: glcorearb.h:811
GLdouble GLdouble t
Definition: glext.h:239
void GetComponents(std::vector< std::vector< std::shared_ptr< Triangle >>> &components) const
Triangle(int v0, int v1, int v2)
void DepthFirstSearch(std::shared_ptr< Triangle > const &tInitial, std::map< std::shared_ptr< Triangle >, int > &visited, std::vector< std::shared_ptr< Triangle >> &component) const
TMap const & GetTriangles() const
virtual bool Remove(int v0, int v1, int v2)
GLfloat GLfloat GLfloat v2
Definition: glcorearb.h:813
GLenum GLenum GLuint components
Definition: glext.h:8352
GLdouble GLdouble GLdouble GLdouble top
Definition: glext.h:6472


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 03:59:59