GteTriangulateCDT.h
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.0 (2016/06/19)
7 
8 #pragma once
9 
12 #include <algorithm>
13 #include <memory>
14 #include <queue>
15 
16 // The triangulation is based on constrained Delaunay triangulations (CDT),
17 // which does not use divisions, so ComputeType may be chosen using BSNumber.
18 // The input constraints are relaxed compared to TriangulateEC; specifically,
19 // the inner polygons are allowed to share vertices with the outer polygons.
20 // The CDT produces a triangulation of the convex hull of the input, which
21 // includes triangles outside the top-level outer polygon and inside the
22 // inner polygons. Only the triangles relevant to the input are returned
23 // via the 'std::vector<int>& triangles', but the other triangles are
24 // retained so that you can perform linear walks in search of points inside
25 // the original polygon (nested polygon, tree of nested polygons). This is
26 // useful, for example, when subsampling the polygon triangles for
27 // interpolation of function data specified at the vertices. A linear walk
28 // does not work for a mesh consisting only of the polygon triangles, but
29 // with the additional triangles, the walk can navigate through holes in
30 // the polygon to find the containing triangle of the specified point.
31 
32 namespace gte
33 {
34 
35 template <typename InputType, typename ComputeType>
37 {
38 public:
39  // The class is a functor to support triangulating multiple polygons that
40  // share vertices in a collection of points. The interpretation of
41  // 'numPoints' and 'points' is described before each operator() function.
42  // Preconditions are numPoints >= 3 and points is a nonnull pointer to an
43  // array of at least numPoints elements. If the preconditions are
44  // satisfied, then operator() functions will return 'true'; otherwise,
45  // they return 'false'.
46  TriangulateCDT(int numPoints, Vector2<InputType> const* points);
47  TriangulateCDT(std::vector<Vector2<InputType>> const& points);
48 
49  // The triangles of the polygon triangulation.
50  inline std::vector<std::array<int, 3>> const& GetTriangles() const;
51 
52  // The triangles inside the convex hull of the points but outside the
53  // triangulation.
54  inline std::vector<std::array<int, 3>> const& GetOutsideTriangles() const;
55 
56  // The triangles of the convex hull of the inputs to the constructor.
57  inline std::vector<std::array<int, 3>> const& GetAllTriangles() const;
58 
59  // The classification of whether a triangle is part of the triangulation
60  // or outside the triangulation. These may be used in conjunction with
61  // the array returned by GetAllTriangles().
62  inline std::vector<bool> const& GetIsInside() const;
63  inline bool IsInside(int triIndex) const;
64  inline bool IsOutside(int triIndex) const;
65 
66  // The outer polygons have counterclockwise ordered vertices. The inner
67  // polygons have clockwise ordered vertices.
68  typedef std::vector<int> Polygon;
69 
70  // The input 'points' represents an array of vertices for a simple
71  // polygon. The vertices are points[0] through points[numPoints-1] and
72  // are listed in counterclockwise order.
73  bool operator()();
74 
75  // The input 'points' represents an array of vertices that contains the
76  // vertices of a simple polygon.
77  bool operator()(Polygon const& polygon);
78 
79  // The input 'points' is a shared array of vertices that contains the
80  // vertices for two simple polygons, an outer polygon and an inner
81  // polygon. The inner polygon must be strictly inside the outer polygon.
82  bool operator()(Polygon const& outer, Polygon const& inner);
83 
84  // The input 'points' is a shared array of vertices that contains the
85  // vertices for multiple simple polygons, an outer polygon and one or more
86  // inner polygons. The inner polygons must be nonoverlapping and strictly
87  // inside the outer polygon.
88  bool operator()(Polygon const& outer, std::vector<Polygon> const& inners);
89 
90  // A tree of nested polygons. The root node corresponds to an outer
91  // polygon. The children of the root correspond to inner polygons, which
92  // are nonoverlapping polygons strictly contained in the outer polygon.
93  // Each inner polygon may itself contain an outer polygon, thus leading
94  // to a hierarchy of polygons. The outer polygons have vertices listed
95  // in counterclockwise order. The inner polygons have vertices listed in
96  // clockwise order.
97  class Tree
98  {
99  public:
100  Polygon polygon;
101  std::vector<std::shared_ptr<Tree>> child;
102  };
103 
104  // The input 'positions' is a shared array of vertices that contains the
105  // vertices for multiple simple polygons in a tree of polygons.
106  bool operator()(std::shared_ptr<Tree> const& tree);
107 
108 private:
109  // Triangulate the points referenced by an operator(...) query. The
110  // mAllTriangles and mIsInside are populated by this function, but the
111  // indices of mAllTriangles are relative to the packed 'points'. After
112  // the call, the indices need to be mapped back to the original set
113  // provided by the input arrays to operator(...). The mTriangles and
114  // mOutsideTriangles are generated after the call by examining
115  // mAllTriangles and mIsInside.
116  bool TriangulatePacked(int numPoints, Vector2<InputType> const* points,
117  std::shared_ptr<Tree> const& tree,
118  std::map<std::shared_ptr<Tree>, int> const& offsets);
119 
120  int GetNumPointsAndOffsets(std::shared_ptr<Tree> const& tree,
121  std::map<std::shared_ptr<Tree>, int>& offsets) const;
122 
123  void PackPoints(std::shared_ptr<Tree> const& tree,
124  std::vector<Vector2<InputType>>& points);
125 
126  bool InsertEdges(std::shared_ptr<Tree> const& tree);
127 
128  void LookupIndex(std::shared_ptr<Tree> const& tree, int& v,
129  std::map<std::shared_ptr<Tree>, int> const& offsets) const;
130 
131  bool IsInside(std::shared_ptr<Tree> const& tree, Vector2<ComputeType> const* points,
132  Vector2<ComputeType> const& test,
133  std::map<std::shared_ptr<Tree>, int> const& offsets) const;
134 
135  // The input polygon.
138 
139  // The output triangulation and those triangle inside the hull of the
140  // points but outside the triangulation.
141  std::vector<std::array<int, 3>> mTriangles;
142  std::vector<std::array<int, 3>> mOutsideTriangles;
143  std::vector<std::array<int, 3>> mAllTriangles;
144  std::vector<bool> mIsInside;
145 
147 };
148 
149 
150 template <typename InputType, typename ComputeType>
152  :
153  mNumPoints(numPoints),
154  mPoints(points)
155 {
156  if (mNumPoints < 3 || !mPoints)
157  {
158  LogError("Invalid input.");
159  mNumPoints = 0;
160  mPoints = nullptr;
161  // The operator() functions will triangulate only when mPoints is
162  // not null. The test mNumPoints >= 3 is redundant because of the
163  // logic in the constructor.
164  }
165 }
166 
167 template <typename InputType, typename ComputeType>
169  :
170  mNumPoints(static_cast<int>(points.size())),
171  mPoints(points.data())
172 {
173  if (mNumPoints < 3 || !mPoints)
174  {
175  LogError("Invalid input.");
176  mNumPoints = 0;
177  mPoints = nullptr;
178  // The operator() functions will triangulate only when mPoints is
179  // not null. The test mNumPoints >= 3 is redundant because of the
180  // logic in the constructor.
181  }
182 }
183 
184 template <typename InputType, typename ComputeType> inline
185 std::vector<std::array<int, 3>> const& TriangulateCDT<InputType, ComputeType>::GetTriangles() const
186 {
187  return mTriangles;
188 }
189 
190 template <typename InputType, typename ComputeType> inline
191 std::vector<std::array<int, 3>> const& TriangulateCDT<InputType, ComputeType>::GetOutsideTriangles() const
192 {
193  return mOutsideTriangles;
194 }
195 
196 template <typename InputType, typename ComputeType> inline
197 std::vector<std::array<int, 3>> const& TriangulateCDT<InputType, ComputeType>::GetAllTriangles() const
198 {
199  return mAllTriangles;
200 }
201 
202 template <typename InputType, typename ComputeType> inline
204 {
205  return mIsInside;
206 }
207 
208 template <typename InputType, typename ComputeType> inline
210 {
211  if (0 <= triIndex && triIndex < static_cast<int>(mIsInside.size()))
212  {
213  return mIsInside[triIndex];
214  }
215  else
216  {
217  return false;
218  }
219 }
220 
221 template <typename InputType, typename ComputeType> inline
223 {
224  if (0 <= triIndex && triIndex < static_cast<int>(mIsInside.size()))
225  {
226  return !mIsInside[triIndex];
227  }
228  else
229  {
230  return false;
231  }
232 }
233 
234 template <typename InputType, typename ComputeType>
236 {
237  if (mPoints)
238  {
239  std::shared_ptr<Tree> tree = std::make_shared<Tree>();
240  tree->polygon.resize(mNumPoints);
241  for (int i = 0; i < mNumPoints; ++i)
242  {
243  tree->polygon[i] = i;
244  }
245 
246  return operator()(tree);
247  }
248  return false;
249 }
250 
251 template <typename InputType, typename ComputeType>
253 {
254  if (mPoints)
255  {
256  std::shared_ptr<Tree> tree = std::make_shared<Tree>();
257  tree->polygon = polygon;
258 
259  return operator()(tree);
260  }
261  return false;
262 }
263 
264 template <typename InputType, typename ComputeType>
266 {
267  if (mPoints)
268  {
269  std::shared_ptr<Tree> otree = std::make_shared<Tree>();
270  otree->polygon = outer;
271  otree->child.resize(1);
272 
273  std::shared_ptr<Tree> itree = std::make_shared<Tree>();
274  itree->polygon = inner;
275  otree->child[0] = itree;
276 
277  return operator()(otree);
278  }
279  return false;
280 }
281 
282 template <typename InputType, typename ComputeType>
283 bool TriangulateCDT<InputType, ComputeType>::operator()(Polygon const& outer, std::vector<Polygon> const& inners)
284 {
285  if (mPoints)
286  {
287  std::shared_ptr<Tree> otree = std::make_shared<Tree>();
288  otree->polygon = outer;
289  otree->child.resize(inners.size());
290 
291  std::vector<std::shared_ptr<Tree>> itree(inners.size());
292  for (size_t i = 0; i < inners.size(); ++i)
293  {
294  itree[i] = std::make_shared<Tree>();
295  itree[i]->polygon = inners[i];
296  otree->child[i] = itree[i];
297  }
298 
299  return operator()(otree);
300  }
301  return false;
302 }
303 
304 template <typename InputType, typename ComputeType>
305 bool TriangulateCDT<InputType, ComputeType>::operator()(std::shared_ptr<Tree> const& tree)
306 {
307  if (mPoints)
308  {
309  std::map<std::shared_ptr<Tree>, int> offsets;
310  int numPoints = GetNumPointsAndOffsets(tree, offsets);
311  std::vector<Vector2<InputType>> points(numPoints);
312  PackPoints(tree, points);
313 
314  if (TriangulatePacked(numPoints, &points[0], tree, offsets))
315  {
316  int numTriangles = static_cast<int>(mAllTriangles.size());
317  for (int t = 0; t < numTriangles; ++t)
318  {
319  auto& tri = mAllTriangles[t];
320  for (int j = 0; j < 3; ++j)
321  {
322  LookupIndex(tree, tri[j], offsets);
323  }
324 
325  if (mIsInside[t])
326  {
327  mTriangles.push_back(tri);
328  }
329  else
330  {
331  mOutsideTriangles.push_back(tri);
332  }
333  }
334  return true;
335  }
336  }
337 
338  return false;
339 }
340 
341 template <typename InputType, typename ComputeType>
343  Vector2<InputType> const* points, std::shared_ptr<Tree> const& tree,
344  std::map<std::shared_ptr<Tree>, int> const& offsets)
345 {
346  mTriangles.clear();
347  mOutsideTriangles.clear();
348  mAllTriangles.clear();
349  mIsInside.clear();
350 
351  mConstrainedDelaunay(numPoints, points, static_cast<InputType>(0));
352  InsertEdges(tree);
353 
354  ComputeType half = static_cast<ComputeType>(0.5);
355  ComputeType fourth = static_cast<ComputeType>(0.25);
356  auto const& query = mConstrainedDelaunay.GetQuery();
357  auto const* ctPoints = query.GetVertices();
358  int numTriangles = mConstrainedDelaunay.GetNumTriangles();
359  int const* indices = &mConstrainedDelaunay.GetIndices()[0];
360  mIsInside.resize(numTriangles);
361  for (int t = 0; t < numTriangles; ++t)
362  {
363  int v0 = *indices++;
364  int v1 = *indices++;
365  int v2 = *indices++;
366  auto ctInside = fourth * ctPoints[v0] + half * ctPoints[v1] + fourth *ctPoints[v2];
367  mIsInside[t] = IsInside(tree, ctPoints, ctInside, offsets);
368  mAllTriangles.push_back({ { v0, v1, v2 } });
369  }
370  return true;
371 }
372 
373 template <typename InputType, typename ComputeType>
375  std::shared_ptr<Tree> const& tree, std::map<std::shared_ptr<Tree>, int>& offsets) const
376 {
377  int numPoints = 0;
378  std::queue<std::shared_ptr<Tree>> treeQueue;
379  treeQueue.push(tree);
380  while (treeQueue.size() > 0)
381  {
382  std::shared_ptr<Tree> outer = treeQueue.front();
383  treeQueue.pop();
384  offsets.insert(std::make_pair(outer, numPoints));
385  numPoints += static_cast<int>(outer->polygon.size());
386 
387  int numChildren = static_cast<int>(outer->child.size());
388  for (int c = 0; c < numChildren; ++c)
389  {
390  std::shared_ptr<Tree> inner = outer->child[c];
391  offsets.insert(std::make_pair(inner, numPoints));
392  numPoints += static_cast<int>(inner->polygon.size());
393 
394  int numGrandChildren = static_cast<int>(inner->child.size());
395  for (int g = 0; g < numGrandChildren; ++g)
396  {
397  treeQueue.push(inner->child[g]);
398  }
399  }
400  }
401  return numPoints;
402 }
403 
404 template <typename InputType, typename ComputeType>
405 void TriangulateCDT<InputType, ComputeType>::PackPoints(std::shared_ptr<Tree> const& tree,
406  std::vector<Vector2<InputType>>& points)
407 {
408  int numPoints = 0;
409  std::queue<std::shared_ptr<Tree>> treeQueue;
410  treeQueue.push(tree);
411  while (treeQueue.size() > 0)
412  {
413  std::shared_ptr<Tree> outer = treeQueue.front();
414  treeQueue.pop();
415  int const numOuterIndices = static_cast<int>(outer->polygon.size());
416  int const* outerIndices = outer->polygon.data();
417  for (int i = 0; i < numOuterIndices; ++i)
418  {
419  points[numPoints++] = mPoints[outerIndices[i]];
420  }
421 
422  int numChildren = static_cast<int>(outer->child.size());
423  for (int c = 0; c < numChildren; ++c)
424  {
425  std::shared_ptr<Tree> inner = outer->child[c];
426  int const numInnerIndices = static_cast<int>(inner->polygon.size());
427  int const* innerIndices = inner->polygon.data();
428  for (int i = 0; i < numInnerIndices; ++i)
429  {
430  points[numPoints++] = mPoints[innerIndices[i]];
431  }
432 
433  int numGrandChildren = static_cast<int>(inner->child.size());
434  for (int g = 0; g < numGrandChildren; ++g)
435  {
436  treeQueue.push(inner->child[g]);
437  }
438  }
439  }
440 }
441 
442 template <typename InputType, typename ComputeType>
443 bool TriangulateCDT<InputType, ComputeType>::InsertEdges(std::shared_ptr<Tree> const& tree)
444 {
445  int numPoints = 0;
446  std::array<int, 2> edge;
447  std::vector<int> ignoreOutEdge;
448  std::queue<std::shared_ptr<Tree>> treeQueue;
449  treeQueue.push(tree);
450  while (treeQueue.size() > 0)
451  {
452  std::shared_ptr<Tree> outer = treeQueue.front();
453  treeQueue.pop();
454  int numOuter = static_cast<int>(outer->polygon.size());
455  for (int i0 = numOuter - 1, i1 = 0; i1 < numOuter; i0 = i1++)
456  {
457  edge[0] = numPoints + i0;
458  edge[1] = numPoints + i1;
459  if (!mConstrainedDelaunay.Insert(edge, ignoreOutEdge))
460  {
461  return false;
462  }
463  }
464  numPoints += numOuter;
465 
466  int numChildren = static_cast<int>(outer->child.size());
467  for (int c = 0; c < numChildren; ++c)
468  {
469  std::shared_ptr<Tree> inner = outer->child[c];
470  int numInner = static_cast<int>(inner->polygon.size());
471  for (int i0 = numInner - 1, i1 = 0; i1 < numInner; i0 = i1++)
472  {
473  edge[0] = numPoints + i0;
474  edge[1] = numPoints + i1;
475  if (!mConstrainedDelaunay.Insert(edge, ignoreOutEdge))
476  {
477  return false;
478  }
479  }
480  numPoints += numInner;
481 
482  int numGrandChildren = static_cast<int>(inner->child.size());
483  for (int g = 0; g < numGrandChildren; ++g)
484  {
485  treeQueue.push(inner->child[g]);
486  }
487  }
488  }
489  return true;
490 }
491 
492 template <typename InputType, typename ComputeType>
493 void TriangulateCDT<InputType, ComputeType>::LookupIndex(std::shared_ptr<Tree> const& tree,
494  int& v, std::map<std::shared_ptr<Tree>, int> const& offsets) const
495 {
496  std::queue<std::shared_ptr<Tree>> treeQueue;
497  treeQueue.push(tree);
498  while (treeQueue.size() > 0)
499  {
500  std::shared_ptr<Tree> outer = treeQueue.front();
501  treeQueue.pop();
502  int const numOuterIndices = static_cast<int>(outer->polygon.size());
503  int const* outerIndices = outer->polygon.data();
504  int offset = offsets.find(outer)->second;
505  if (v < offset + numOuterIndices)
506  {
507  v = outerIndices[v - offset];
508  return;
509  }
510 
511  int numChildren = static_cast<int>(outer->child.size());
512  for (int c = 0; c < numChildren; ++c)
513  {
514  std::shared_ptr<Tree> inner = outer->child[c];
515  int const numInnerIndices = static_cast<int>(inner->polygon.size());
516  int const* innerIndices = inner->polygon.data();
517  offset = offsets.find(inner)->second;
518  if (v < offset + numInnerIndices)
519  {
520  v = innerIndices[v - offset];
521  return;
522  }
523 
524  int numGrandChildren = static_cast<int>(inner->child.size());
525  for (int g = 0; g < numGrandChildren; ++g)
526  {
527  treeQueue.push(inner->child[g]);
528  }
529  }
530  }
531 }
532 
533 template <typename InputType, typename ComputeType>
534 bool TriangulateCDT<InputType, ComputeType>::IsInside(std::shared_ptr<Tree> const& tree,
536  std::map<std::shared_ptr<Tree>, int> const& offsets) const
537 {
538  std::queue<std::shared_ptr<Tree>> treeQueue;
539  treeQueue.push(tree);
540  while (treeQueue.size() > 0)
541  {
542  std::shared_ptr<Tree> outer = treeQueue.front();
543  treeQueue.pop();
544  int const numOuterIndices = static_cast<int>(outer->polygon.size());
545  int offset = offsets.find(outer)->second;
546  PointInPolygon2<ComputeType> piOuter(numOuterIndices, points + offset);
547  if (piOuter.Contains(test))
548  {
549  int numChildren = static_cast<int>(outer->child.size());
550  int c;
551  for (c = 0; c < numChildren; ++c)
552  {
553  std::shared_ptr<Tree> inner = outer->child[c];
554  int const numInnerIndices = static_cast<int>(inner->polygon.size());
555  offset = offsets.find(inner)->second;
556  PointInPolygon2<ComputeType> piInner(numInnerIndices, points + offset);
557  if (piInner.Contains(test))
558  {
559  int numGrandChildren = static_cast<int>(inner->child.size());
560  for (int g = 0; g < numGrandChildren; ++g)
561  {
562  treeQueue.push(inner->child[g]);
563  }
564  break;
565  }
566  }
567  if (c == numChildren)
568  {
569  return true;
570  }
571  }
572  }
573  return false;
574 }
575 
576 }
void LookupIndex(std::shared_ptr< Tree > const &tree, int &v, std::map< std::shared_ptr< Tree >, int > const &offsets) const
std::vector< std::array< int, 3 > > mOutsideTriangles
std::vector< int > Polygon
std::vector< std::array< int, 3 > > const & GetOutsideTriangles() const
void PackPoints(std::shared_ptr< Tree > const &tree, std::vector< Vector2< InputType >> &points)
bool IsOutside(int triIndex) const
std::vector< std::array< int, 3 > > const & GetTriangles() const
std::vector< bool > mIsInside
GLfloat GLfloat v1
Definition: glcorearb.h:812
std::vector< std::shared_ptr< Tree > > child
GLuint GLsizei const GLuint const GLintptr * offsets
Definition: glcorearb.h:2616
int GetNumPointsAndOffsets(std::shared_ptr< Tree > const &tree, std::map< std::shared_ptr< Tree >, int > &offsets) const
GLsizeiptr size
Definition: glcorearb.h:659
bool Contains(Vector2< Real > const &p) const
GLboolean GLboolean g
Definition: glcorearb.h:1217
const GLubyte * c
Definition: glext.h:11671
GLfixed GLfixed GLint GLint GLfixed points
Definition: glext.h:4927
ConstrainedDelaunay2< InputType, ComputeType > mConstrainedDelaunay
bool InsertEdges(std::shared_ptr< Tree > const &tree)
GLsizei GLenum const void * indices
Definition: glcorearb.h:401
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
#define LogError(message)
Definition: GteLogger.h:92
GLboolean * data
Definition: glcorearb.h:126
GLfloat v0
Definition: glcorearb.h:811
TriangulateCDT(int numPoints, Vector2< InputType > const *points)
GLdouble GLdouble t
Definition: glext.h:239
std::vector< std::array< int, 3 > > mTriangles
bool TriangulatePacked(int numPoints, Vector2< InputType > const *points, std::shared_ptr< Tree > const &tree, std::map< std::shared_ptr< Tree >, int > const &offsets)
const GLdouble * v
Definition: glcorearb.h:832
std::vector< std::array< int, 3 > > mAllTriangles
bool IsInside(int triIndex) const
GLfloat GLfloat GLfloat v2
Definition: glcorearb.h:813
GLintptr offset
Definition: glcorearb.h:660
std::vector< bool > const & GetIsInside() const
GLenum query
Definition: glext.h:2716
std::vector< std::array< int, 3 > > const & GetAllTriangles() const
Vector2< InputType > const * mPoints


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 04:00:01