GteTriangulateEC.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 
10 #include <LowLevel/GteLogger.h>
12 #include <algorithm>
13 #include <limits>
14 #include <memory>
15 #include <map>
16 #include <queue>
17 #include <vector>
18 
19 // The algorithm for processing nested polygons involves a division, so the
20 // ComputeType must be rational-based, say, BSRational. If you process only
21 // triangles that are simple, you may use BSNumber for the ComputeType.
22 
23 namespace gte
24 {
25 
26 template <typename InputType, typename ComputeType>
28 {
29 public:
30  // The class is a functor to support triangulating multiple polygons that
31  // share vertices in a collection of points. The interpretation of
32  // 'numPoints' and 'points' is described before each operator() function.
33  // Preconditions are numPoints >= 3 and points is a nonnull pointer to an
34  // array of at least numPoints elements. If the preconditions are
35  // satisfied, then operator() functions will return 'true'; otherwise,
36  // they return 'false'.
37  TriangulateEC(int numPoints, Vector2<InputType> const* points);
38  TriangulateEC(std::vector<Vector2<InputType>> const& points);
39 
40  // Access the triangulation after each operator() call.
41  inline std::vector<std::array<int, 3>> const& GetTriangles() const;
42 
43  // The outer polygons have counterclockwise ordered vertices. The inner
44  // polygons have clockwise ordered vertices.
45  typedef std::vector<int> Polygon;
46 
47  // The input 'points' represents an array of vertices for a simple
48  // polygon. The vertices are points[0] through points[numPoints-1] and
49  // are listed in counterclockwise order.
50  bool operator()();
51 
52  // The input 'points' represents an array of vertices that contains the
53  // vertices of a simple polygon.
54  bool operator()(Polygon const& polygon);
55 
56  // The input 'points' is a shared array of vertices that contains the
57  // vertices for two simple polygons, an outer polygon and an inner
58  // polygon. The inner polygon must be strictly inside the outer polygon.
59  bool operator()(Polygon const& outer, Polygon const& inner);
60 
61  // The input 'points' is a shared array of vertices that contains the
62  // vertices for multiple simple polygons, an outer polygon and one or more
63  // inner polygons. The inner polygons must be nonoverlapping and strictly
64  // inside the outer polygon.
65  bool operator()(Polygon const& outer, std::vector<Polygon> const& inners);
66 
67  // A tree of nested polygons. The root node corresponds to an outer
68  // polygon. The children of the root correspond to inner polygons, which
69  // are nonoverlapping polygons strictly contained in the outer polygon.
70  // Each inner polygon may itself contain an outer polygon, thus leading
71  // to a hierarchy of polygons. The outer polygons have vertices listed
72  // in counterclockwise order. The inner polygons have vertices listed in
73  // clockwise order.
74  class Tree
75  {
76  public:
77  Polygon polygon;
78  std::vector<std::shared_ptr<Tree>> child;
79  };
80 
81  // The input 'positions' is a shared array of vertices that contains the
82  // vertices for multiple simple polygons in a tree of polygons.
83  bool operator()(std::shared_ptr<Tree> const& tree);
84 
85 private:
86  // Create the vertex objects that store the various lists required by the
87  // ear-clipping algorithm.
88  void InitializeVertices(int numVertices, int const* indices);
89 
90  // Apply ear clipping to the input polygon. Polygons with holes are
91  // preprocessed to obtain an index array that is nearly a simple polygon.
92  // This outer polygon has a pair of coincident edges per inner polygon.
93  void DoEarClipping(int numVertices, int const* indices);
94 
95  // Given an outer polygon that contains an inner polygon, this function
96  // determines a pair of visible vertices and inserts two coincident edges
97  // to generate a nearly simple polygon.
98  bool CombinePolygons(int nextElement, Polygon const& outer,
99  Polygon const& inner, std::map<int, int>& indexMap,
100  std::vector<int>& combined);
101 
102  // Given an outer polygon that contains a set of nonoverlapping inner
103  // polygons, this function determines pairs of visible vertices and
104  // inserts coincident edges to generate a nearly simple polygon. It
105  // repeatedly calls CombinePolygons for each inner polygon of the outer
106  // polygon.
107  bool ProcessOuterAndInners(int& nextElement, Polygon const& outer,
108  std::vector<Polygon> const& inners, std::map<int, int>& indexMap,
109  std::vector<int>& combined);
110 
111  // The insertion of coincident edges to obtain a nearly simple polygon
112  // requires duplication of vertices in order that the ear-clipping
113  // algorithm work correctly. After the triangulation, the indices of
114  // the duplicated vertices are converted to the original indices.
115  void RemapIndices(std::map<int, int> const& indexMap);
116 
117  // Two extra elements are needed in the position array per outer-inners
118  // polygon. This function computes the total number of extra elements
119  // needed for the input tree and it converts InputType vertices to
120  // ComputeType values.
121  int InitializeFromTree(std::shared_ptr<Tree> const& tree);
122 
123  // The input polygon.
126 
127  // The output triangulation.
128  std::vector<std::array<int, 3>> mTriangles;
129 
130  // The array of points used for geometric queries. If you want to be
131  // certain of a correct result, choose ComputeType to be BSNumber. The
132  // InputType points are convertex to ComputeType points on demand; the
133  // mIsConverted array keeps track of which input points have been
134  // converted.
135  std::vector<Vector2<ComputeType>> mComputePoints;
136  std::vector<bool> mIsConverted;
138 
139  // Doubly linked lists for storing specially tagged vertices.
140  class Vertex
141  {
142  public:
143  Vertex();
144 
145  int index; // index of vertex in position array
146  int vPrev, vNext; // vertex links for polygon
147  int sPrev, sNext; // convex/reflex vertex links (disjoint lists)
148  int ePrev, eNext; // ear links
149  bool isConvex, isEar;
150  };
151 
152  inline Vertex& V(int i);
153  bool IsConvex(int i);
154  bool IsEar(int i);
155  void InsertAfterC(int i); // insert convex vertex
156  void InsertAfterR(int i); // insert reflex vertesx
157  void InsertEndE(int i); // insert ear at end of list
158  void InsertAfterE(int i); // insert ear after efirst
159  void InsertBeforeE(int i); // insert ear before efirst
160  void RemoveV(int i); // remove vertex
161  int RemoveE(int i); // remove ear at i
162  void RemoveR(int i); // remove reflex vertex
163 
164  // The doubly linked list.
165  std::vector<Vertex> mVertices;
166  int mCFirst, mCLast; // linear list of convex vertices
167  int mRFirst, mRLast; // linear list of reflex vertices
168  int mEFirst, mELast; // cyclical list of ears
169 };
170 
171 
172 template <typename InputType, typename ComputeType>
174  :
175  mNumPoints(numPoints),
176  mPoints(points)
177 {
178  if (mNumPoints >= 3 && mPoints)
179  {
180  mComputePoints.resize(mNumPoints);
181  mIsConverted.resize(mNumPoints);
182  std::fill(mIsConverted.begin(), mIsConverted.end(), false);
184  }
185  else
186  {
187  LogError("Invalid input.");
188  mNumPoints = 0;
189  mPoints = nullptr;
190  // The operator() functions will triangulate only when mPoints is
191  // not null. The test mNumPoints >= 3 is redundant because of the
192  // logic in the constructor.
193  }
194 }
195 
196 template <typename InputType, typename ComputeType>
198  :
199  mNumPoints(static_cast<int>(points.size())),
200  mPoints(points.data())
201 {
202  if (mNumPoints >= 3 && mPoints)
203  {
204  mComputePoints.resize(mNumPoints);
205  mIsConverted.resize(mNumPoints);
206  std::fill(mIsConverted.begin(), mIsConverted.end(), false);
208  }
209  else
210  {
211  LogError("Invalid input.");
212  mNumPoints = 0;
213  mPoints = nullptr;
214  // The operator() functions will triangulate only when mPoints is
215  // not null. The test mNumPoints >= 3 is redundant because of the
216  // logic in the constructor.
217  }
218 }
219 
220 template <typename InputType, typename ComputeType> inline
221 std::vector<std::array<int, 3>> const& TriangulateEC<InputType, ComputeType>::GetTriangles() const
222 {
223  return mTriangles;
224 }
225 
226 template <typename InputType, typename ComputeType>
228 {
229  mTriangles.clear();
230  if (mPoints)
231  {
232  // Compute the points for the queries.
233  for (int i = 0; i < mNumPoints; ++i)
234  {
235  if (!mIsConverted[i])
236  {
237  mIsConverted[i] = true;
238  for (int j = 0; j < 2; ++j)
239  {
240  mComputePoints[i][j] = mPoints[i][j];
241  }
242  }
243  }
244 
245  // Triangulate the unindexed polygon.
246  InitializeVertices(mNumPoints, nullptr);
247  DoEarClipping(mNumPoints, nullptr);
248  return true;
249  }
250  else
251  {
252  return false;
253  }
254 }
255 
256 template <typename InputType, typename ComputeType>
258 {
259  mTriangles.clear();
260  if (mPoints)
261  {
262  // Compute the points for the queries.
263  int const numIndices = static_cast<int>(polygon.size());
264  int const* indices = polygon.data();
265  for (int i = 0; i < numIndices; ++i)
266  {
267  int index = indices[i];
268  if (!mIsConverted[index])
269  {
270  mIsConverted[index] = true;
271  for (int j = 0; j < 2; ++j)
272  {
273  mComputePoints[index][j] = mPoints[index][j];
274  }
275  }
276  }
277 
278  // Triangulate the indexed polygon.
279  InitializeVertices(numIndices, indices);
280  DoEarClipping(numIndices, indices);
281  return true;
282  }
283  else
284  {
285  return false;
286  }
287 }
288 
289 template <typename InputType, typename ComputeType>
291 {
292  mTriangles.clear();
293  if (mPoints)
294  {
295  // Two extra elements are needed to duplicate the endpoints of the
296  // edge introduced to combine outer and inner polygons.
297  int numPointsPlusExtras = mNumPoints + 2;
298  if (numPointsPlusExtras > static_cast<int>(mComputePoints.size()))
299  {
300  mComputePoints.resize(numPointsPlusExtras);
301  mIsConverted.resize(numPointsPlusExtras);
302  mIsConverted[mNumPoints] = false;
303  mIsConverted[mNumPoints + 1] = false;
304  mQuery.Set(numPointsPlusExtras, &mComputePoints[0]);
305  }
306 
307  // Convert any points that have not been encountered in other
308  // triangulation calls.
309  int const numOuterIndices = static_cast<int>(outer.size());
310  int const* outerIndices = outer.data();
311  for (int i = 0; i < numOuterIndices; ++i)
312  {
313  int index = outerIndices[i];
314  if (!mIsConverted[index])
315  {
316  mIsConverted[index] = true;
317  for (int j = 0; j < 2; ++j)
318  {
319  mComputePoints[index][j] = mPoints[index][j];
320  }
321  }
322  }
323 
324  int const numInnerIndices = static_cast<int>(inner.size());
325  int const* innerIndices = inner.data();
326  for (int i = 0; i < numInnerIndices; ++i)
327  {
328  int index = innerIndices[i];
329  if (!mIsConverted[index])
330  {
331  mIsConverted[index] = true;
332  for (int j = 0; j < 2; ++j)
333  {
334  mComputePoints[index][j] = mPoints[index][j];
335  }
336  }
337  }
338 
339  // Combine the outer polygon and the inner polygon into a simple
340  // polygon by inserting two edges connecting mutually visible
341  // vertices, one from the outer polygon and one from the inner
342  // polygon.
343  int nextElement = mNumPoints; // The next available element.
344  std::map<int, int> indexMap;
345  std::vector<int> combined;
346  if (!CombinePolygons(nextElement, outer, inner, indexMap, combined))
347  {
348  // An unexpected condition was encountered.
349  return false;
350  }
351 
352  // The combined polygon is now in the format of a simple polygon,
353  // albeit one with coincident edges.
354  int numVertices = static_cast<int>(combined.size());
355  int* const indices = &combined[0];
356  InitializeVertices(numVertices, indices);
357  DoEarClipping(numVertices, indices);
358 
359  // Map the duplicate indices back to the original indices.
360  RemapIndices(indexMap);
361  return true;
362  }
363  else
364  {
365  return false;
366  }
367 }
368 
369 template <typename InputType, typename ComputeType>
370 bool TriangulateEC<InputType, ComputeType>::operator()(Polygon const& outer, std::vector<Polygon> const& inners)
371 {
372  mTriangles.clear();
373  if (mPoints)
374  {
375  // Two extra elements per inner polygon are needed to duplicate the
376  // endpoints of the edges introduced to combine outer and inner
377  // polygons.
378  int numPointsPlusExtras = mNumPoints + 2 * (int)inners.size();
379  if (numPointsPlusExtras > static_cast<int>(mComputePoints.size()))
380  {
381  mComputePoints.resize(numPointsPlusExtras);
382  mIsConverted.resize(numPointsPlusExtras);
383  for (int i = mNumPoints; i < numPointsPlusExtras; ++i)
384  {
385  mIsConverted[i] = false;
386  }
387  mQuery.Set(numPointsPlusExtras, &mComputePoints[0]);
388  }
389 
390  // Convert any points that have not been encountered in other
391  // triangulation calls.
392  int const numOuterIndices = static_cast<int>(outer.size());
393  int const* outerIndices = outer.data();
394  for (int i = 0; i < numOuterIndices; ++i)
395  {
396  int index = outerIndices[i];
397  if (!mIsConverted[index])
398  {
399  mIsConverted[index] = true;
400  for (int j = 0; j < 2; ++j)
401  {
402  mComputePoints[index][j] = mPoints[index][j];
403  }
404  }
405  }
406 
407  for (auto const& inner : inners)
408  {
409  int const numInnerIndices = static_cast<int>(inner.size());
410  int const* innerIndices = inner.data();
411  for (int i = 0; i < numInnerIndices; ++i)
412  {
413  int index = innerIndices[i];
414  if (!mIsConverted[index])
415  {
416  mIsConverted[index] = true;
417  for (int j = 0; j < 2; ++j)
418  {
419  mComputePoints[index][j] = mPoints[index][j];
420  }
421  }
422  }
423  }
424 
425  // Combine the outer polygon and the inner polygons into a simple
426  // polygon by inserting two edges per inner polygon connecting
427  // mutually visible vertices.
428  int nextElement = mNumPoints; // The next available element.
429  std::map<int, int> indexMap;
430  std::vector<int> combined;
431  if (!ProcessOuterAndInners(nextElement, outer, inners, indexMap, combined))
432  {
433  // An unexpected condition was encountered.
434  return false;
435  }
436 
437  // The combined polygon is now in the format of a simple polygon, albeit
438  // with coincident edges.
439  int numVertices = static_cast<int>(combined.size());
440  int* const indices = &combined[0];
441  InitializeVertices(numVertices, indices);
442  DoEarClipping(numVertices, indices);
443 
444  // Map the duplicate indices back to the original indices.
445  RemapIndices(indexMap);
446  return true;
447  }
448  else
449  {
450  return false;
451  }
452 }
453 
454 template <typename InputType, typename ComputeType>
455 bool TriangulateEC<InputType, ComputeType>::operator()(std::shared_ptr<Tree> const& tree)
456 {
457  mTriangles.clear();
458  if (mPoints)
459  {
460  // Two extra elements per inner polygon are needed to duplicate the
461  // endpoints of the edges introduced to combine outer and inner
462  // polygons.
463  int numPointsPlusExtras = mNumPoints + InitializeFromTree(tree);
464  if (numPointsPlusExtras > static_cast<int>(mComputePoints.size()))
465  {
466  mComputePoints.resize(numPointsPlusExtras);
467  mIsConverted.resize(numPointsPlusExtras);
468  for (int i = mNumPoints; i < numPointsPlusExtras; ++i)
469  {
470  mIsConverted[i] = false;
471  }
472  mQuery.Set(numPointsPlusExtras, &mComputePoints[0]);
473  }
474 
475  int nextElement = mNumPoints;
476  std::map<int, int> indexMap;
477 
478  std::queue<std::shared_ptr<Tree>> treeQueue;
479  treeQueue.push(tree);
480  while (treeQueue.size() > 0)
481  {
482  std::shared_ptr<Tree> outer = treeQueue.front();
483  treeQueue.pop();
484 
485  int numChildren = static_cast<int>(outer->child.size());
486  int numVertices;
487  int const* indices;
488 
489  if (numChildren == 0)
490  {
491  // The outer polygon is a simple polygon (no nested inner
492  // polygons). Triangulate the simple polygon.
493  numVertices = static_cast<int>(outer->polygon.size());
494  indices = outer->polygon.data();
495  InitializeVertices(numVertices, indices);
496  DoEarClipping(numVertices, indices);
497  }
498  else
499  {
500  // Place the next level of outer polygon nodes on the queue for
501  // triangulation.
502  std::vector<Polygon> inners(numChildren);
503  for (int c = 0; c < numChildren; ++c)
504  {
505  std::shared_ptr<Tree> inner = outer->child[c];
506  inners[c] = inner->polygon;
507  int numGrandChildren = static_cast<int>(inner->child.size());
508  for (int g = 0; g < numGrandChildren; ++g)
509  {
510  treeQueue.push(inner->child[g]);
511  }
512  }
513 
514  // Combine the outer polygon and the inner polygons into a
515  // simple polygon by inserting two edges per inner polygon
516  // connecting mutually visible vertices.
517  std::vector<int> combined;
518  ProcessOuterAndInners(nextElement, outer->polygon, inners, indexMap, combined);
519 
520  // The combined polygon is now in the format of a simple
521  // polygon, albeit with coincident edges.
522  numVertices = static_cast<int>(combined.size());
523  indices = &combined[0];
524  InitializeVertices(numVertices, indices);
525  DoEarClipping(numVertices, indices);
526  }
527  }
528 
529  // Map the duplicate indices back to the original indices.
530  RemapIndices(indexMap);
531  return true;
532  }
533  else
534  {
535  return false;
536  }
537 }
538 
539 template <typename InputType, typename ComputeType>
541 {
542  mVertices.clear();
543  mVertices.resize(numVertices);
544  mCFirst = -1;
545  mCLast = -1;
546  mRFirst = -1;
547  mRLast = -1;
548  mEFirst = -1;
549  mELast = -1;
550 
551  // Create a circular list of the polygon vertices for dynamic removal of
552  // vertices.
553  int numVerticesM1 = numVertices - 1;
554  for (int i = 0; i <= numVerticesM1; ++i)
555  {
556  Vertex& vertex = V(i);
557  vertex.index = (indices ? indices[i] : i);
558  vertex.vPrev = (i > 0 ? i - 1 : numVerticesM1);
559  vertex.vNext = (i < numVerticesM1 ? i + 1 : 0);
560  }
561 
562  // Create a circular list of the polygon vertices for dynamic removal of
563  // vertices. Keep track of two linear sublists, one for the convex
564  // vertices and one for the reflex vertices. This is an O(N) process
565  // where N is the number of polygon vertices.
566  for (int i = 0; i <= numVerticesM1; ++i)
567  {
568  if (IsConvex(i))
569  {
570  InsertAfterC(i);
571  }
572  else
573  {
574  InsertAfterR(i);
575  }
576  }
577 }
578 
579 template <typename InputType, typename ComputeType>
581 {
582  // If the polygon is convex, just create a triangle fan.
583  if (mRFirst == -1)
584  {
585  int numVerticesM1 = numVertices - 1;
586  if (indices)
587  {
588  for (int i = 1; i < numVerticesM1; ++i)
589  {
590  mTriangles.push_back({ { indices[0], indices[i], indices[i + 1] } });
591  }
592  }
593  else
594  {
595  for (int i = 1; i < numVerticesM1; ++i)
596  {
597  mTriangles.push_back({ { 0, i, i + 1 } });
598  }
599  }
600  return;
601  }
602 
603  // Identify the ears and build a circular list of them. Let V0, V1, and
604  // V2 be consecutive vertices forming a triangle T. The vertex V1 is an
605  // ear if no other vertices of the polygon lie inside T. Although it is
606  // enough to show that V1 is not an ear by finding at least one other
607  // vertex inside T, it is sufficient to search only the reflex vertices.
608  // This is an O(C*R) process, where C is the number of convex vertices and
609  // R is the number of reflex vertices with N = C+R. The order is O(N^2),
610  // for example when C = R = N/2.
611  for (int i = mCFirst; i != -1; i = V(i).sNext)
612  {
613  if (IsEar(i))
614  {
615  InsertEndE(i);
616  }
617  }
618  V(mEFirst).ePrev = mELast;
619  V(mELast).eNext = mEFirst;
620 
621  // Remove the ears, one at a time.
622  bool bRemoveAnEar = true;
623  while (bRemoveAnEar)
624  {
625  // Add the triangle with the ear to the output list of triangles.
626  int iVPrev = V(mEFirst).vPrev;
627  int iVNext = V(mEFirst).vNext;
628  mTriangles.push_back({ { V(iVPrev).index, V(mEFirst).index, V(iVNext).index } });
629 
630  // Remove the vertex corresponding to the ear.
631  RemoveV(mEFirst);
632  if (--numVertices == 3)
633  {
634  // Only one triangle remains, just remove the ear and copy it.
636  iVPrev = V(mEFirst).vPrev;
637  iVNext = V(mEFirst).vNext;
638  mTriangles.push_back({ { V(iVPrev).index, V(mEFirst).index, V(iVNext).index } });
639  bRemoveAnEar = false;
640  continue;
641  }
642 
643  // Removal of the ear can cause an adjacent vertex to become an ear
644  // or to stop being an ear.
645  Vertex& vPrev = V(iVPrev);
646  if (vPrev.isEar)
647  {
648  if (!IsEar(iVPrev))
649  {
650  RemoveE(iVPrev);
651  }
652  }
653  else
654  {
655  bool wasReflex = !vPrev.isConvex;
656  if (IsConvex(iVPrev))
657  {
658  if (wasReflex)
659  {
660  RemoveR(iVPrev);
661  }
662 
663  if (IsEar(iVPrev))
664  {
665  InsertBeforeE(iVPrev);
666  }
667  }
668  }
669 
670  Vertex& vNext = V(iVNext);
671  if (vNext.isEar)
672  {
673  if (!IsEar(iVNext))
674  {
675  RemoveE(iVNext);
676  }
677  }
678  else
679  {
680  bool wasReflex = !vNext.isConvex;
681  if (IsConvex(iVNext))
682  {
683  if (wasReflex)
684  {
685  RemoveR(iVNext);
686  }
687 
688  if (IsEar(iVNext))
689  {
690  InsertAfterE(iVNext);
691  }
692  }
693  }
694 
695  // Remove the ear.
697  }
698 }
699 
700 template <typename InputType, typename ComputeType>
702  Polygon const& outer, Polygon const& inner, std::map<int, int>& indexMap,
703  std::vector<int>& combined)
704 {
705  int const numOuterIndices = static_cast<int>(outer.size());
706  int const* outerIndices = outer.data();
707  int const numInnerIndices = static_cast<int>(inner.size());
708  int const* innerIndices = inner.data();
709 
710  // Locate the inner-polygon vertex of maximum x-value, call this vertex M.
711  ComputeType xmax = mComputePoints[innerIndices[0]][0];
712  int xmaxIndex = 0;
713  for (int i = 1; i < numInnerIndices; ++i)
714  {
715  ComputeType x = mComputePoints[innerIndices[i]][0];
716  if (x > xmax)
717  {
718  xmax = x;
719  xmaxIndex = i;
720  }
721  }
722  Vector2<ComputeType> M = mComputePoints[innerIndices[xmaxIndex]];
723 
724  // Find the edge whose intersection Intr with the ray M+t*(1,0) minimizes
725  // the ray parameter t >= 0.
726  ComputeType const cmax = static_cast<ComputeType>(std::numeric_limits<InputType>::max());
727  ComputeType const zero = static_cast<ComputeType>(0);
728  Vector2<ComputeType> intr{ cmax, M[1] };
729  int v0min = -1, v1min = -1, endMin = -1;
730  int i0, i1;
731  ComputeType s = cmax;
732  ComputeType t = cmax;
733  for (i0 = numOuterIndices - 1, i1 = 0; i1 < numOuterIndices; i0 = i1++)
734  {
735  // Consider only edges for which the first vertex is below (or on) the
736  // ray and the second vertex is above (or on) the ray.
737  Vector2<ComputeType> diff0 = mComputePoints[outerIndices[i0]] - M;
738  if (diff0[1] > zero)
739  {
740  continue;
741  }
742  Vector2<ComputeType> diff1 = mComputePoints[outerIndices[i1]] - M;
743  if (diff1[1] < zero)
744  {
745  continue;
746  }
747 
748  // At this time, diff0.y <= 0 and diff1.y >= 0.
749  int currentEndMin = -1;
750  if (diff0[1] < zero)
751  {
752  if (diff1[1] > zero)
753  {
754  // The intersection of the edge and ray occurs at an interior
755  // edge point.
756  s = diff0[1] / (diff0[1] - diff1[1]);
757  t = diff0[0] + s * (diff1[0] - diff0[0]);
758  }
759  else // diff1.y == 0
760  {
761  // The vertex Outer[i1] is the intersection of the edge and
762  // the ray.
763  t = diff1[0];
764  currentEndMin = i1;
765  }
766  }
767  else // diff0.y == 0
768  {
769  if (diff1[1] > zero)
770  {
771  // The vertex Outer[i0] is the intersection of the edge and
772  // the ray;
773  t = diff0[0];
774  currentEndMin = i0;
775  }
776  else // diff1.y == 0
777  {
778  if (diff0[0] < diff1[0])
779  {
780  t = diff0[0];
781  currentEndMin = i0;
782  }
783  else
784  {
785  t = diff1[0];
786  currentEndMin = i1;
787  }
788  }
789  }
790 
791  if (zero <= t && t < intr[0])
792  {
793  intr[0] = t;
794  v0min = i0;
795  v1min = i1;
796  if (currentEndMin == -1)
797  {
798  // The current closest point is an edge-interior point.
799  endMin = -1;
800  }
801  else
802  {
803  // The current closest point is a vertex.
804  endMin = currentEndMin;
805  }
806  }
807  else if (t == intr[0])
808  {
809  // The current closest point is a vertex shared by multiple edges;
810  // thus, endMin and currentMin refer to the same point.
811  if (endMin == -1 || currentEndMin == -1)
812  {
813  LogError("Unexpected condition.");
814  return false;
815  }
816 
817  // We need to select the edge closest to M. The previous closest
818  // edge is <outer[v0min],outer[v1min]>. The current candidate is
819  // <outer[i0],outer[i1]>.
820  Vector2<ComputeType> shared = mComputePoints[outerIndices[i1]];
821 
822  // For the previous closest edge, endMin refers to a vertex of
823  // the edge. Get the index of the other vertex.
824  int other = (endMin == v0min ? v1min : v0min);
825 
826  // The new edge is closer if the other vertex of the old edge is
827  // left-of the new edge.
828  diff0 = mComputePoints[outerIndices[i0]] - shared;
829  diff1 = mComputePoints[outerIndices[other]] - shared;
830  ComputeType dotperp = DotPerp(diff0, diff1);
831  if (dotperp > zero)
832  {
833  // The new edge is closer to M.
834  v0min = i0;
835  v1min = i1;
836  endMin = currentEndMin;
837  }
838  }
839  }
840 
841  // The intersection intr[0] stored only the t-value of the ray. The
842  // actual point is (mx,my)+t*(1,0), so intr[0] must be adjusted.
843  intr[0] += M[0];
844 
845  int maxCosIndex;
846  if (endMin == -1)
847  {
848  // If you reach this assert, there is a good chance that you have two
849  // inner polygons that share a vertex or an edge.
850  if (v0min < 0 || v1min < 0)
851  {
852  LogError("Is this an invalid nested polygon?");
853  return false;
854  }
855 
856  // Select one of Outer[v0min] and Outer[v1min] that has an x-value
857  // larger than M.x, call this vertex P. The triangle <M,I,P> must
858  // contain an outer-polygon vertex that is visible to M, which is
859  // possibly P itself.
860  Vector2<ComputeType> sTriangle[3]; // <P,M,I> or <P,I,M>
861  int pIndex;
862  if (mComputePoints[outerIndices[v0min]][0] > mComputePoints[outerIndices[v1min]][0])
863  {
864  sTriangle[0] = mComputePoints[outerIndices[v0min]];
865  sTriangle[1] = intr;
866  sTriangle[2] = M;
867  pIndex = v0min;
868  }
869  else
870  {
871  sTriangle[0] = mComputePoints[outerIndices[v1min]];
872  sTriangle[1] = M;
873  sTriangle[2] = intr;
874  pIndex = v1min;
875  }
876 
877  // If any outer-polygon vertices other than P are inside the triangle
878  // <M,I,P>, then at least one of these vertices must be a reflex
879  // vertex. It is sufficient to locate the reflex vertex R (if any)
880  // in <M,I,P> that minimizes the angle between R-M and (1,0). The
881  // data member mQuery is used for the reflex query.
882  Vector2<ComputeType> diff = sTriangle[0] - M;
883  ComputeType maxSqrLen = Dot(diff, diff);
884  ComputeType maxCos = diff[0] * diff[0] / maxSqrLen;
885  PrimalQuery2<ComputeType> localQuery(3, sTriangle);
886  maxCosIndex = pIndex;
887  for (int i = 0; i < numOuterIndices; ++i)
888  {
889  if (i == pIndex)
890  {
891  continue;
892  }
893 
894  int curr = outerIndices[i];
895  int prev = outerIndices[(i + numOuterIndices - 1) % numOuterIndices];
896  int next = outerIndices[(i + 1) % numOuterIndices];
897  if (mQuery.ToLine(curr, prev, next) <= 0
898  && localQuery.ToTriangle(mComputePoints[curr], 0, 1, 2) <= 0)
899  {
900  // The vertex is reflex and inside the <M,I,P> triangle.
901  diff = mComputePoints[curr] - M;
902  ComputeType sqrLen = Dot(diff, diff);
903  ComputeType cs = diff[0] * diff[0] / sqrLen;
904  if (cs > maxCos)
905  {
906  // The reflex vertex forms a smaller angle with the
907  // positive x-axis, so it becomes the new visible
908  // candidate.
909  maxSqrLen = sqrLen;
910  maxCos = cs;
911  maxCosIndex = i;
912  }
913  else if (cs == maxCos && sqrLen < maxSqrLen)
914  {
915  // The reflex vertex has angle equal to the current
916  // minimum but the length is smaller, so it becomes the
917  // new visible candidate.
918  maxSqrLen = sqrLen;
919  maxCosIndex = i;
920  }
921  }
922  }
923  }
924  else
925  {
926  maxCosIndex = endMin;
927  }
928 
929  // The visible vertices are Position[Inner[xmaxIndex]] and
930  // Position[Outer[maxCosIndex]]. Two coincident edges with these
931  // endpoints are inserted to connect the outer and inner polygons into a
932  // simple polygon. Each of the two Position[] values must be duplicated,
933  // because the original might be convex (or reflex) and the duplicate is
934  // reflex (or convex). The ear-clipping algorithm needs to distinguish
935  // between them.
936  combined.resize(numOuterIndices + numInnerIndices + 2);
937  int cIndex = 0;
938  for (int i = 0; i <= maxCosIndex; ++i, ++cIndex)
939  {
940  combined[cIndex] = outerIndices[i];
941  }
942 
943  for (int i = 0; i < numInnerIndices; ++i, ++cIndex)
944  {
945  int j = (xmaxIndex + i) % numInnerIndices;
946  combined[cIndex] = innerIndices[j];
947  }
948 
949  int innerIndex = innerIndices[xmaxIndex];
950  mComputePoints[nextElement] = mComputePoints[innerIndex];
951  combined[cIndex] = nextElement;
952  auto iter = indexMap.find(innerIndex);
953  if (iter != indexMap.end())
954  {
955  innerIndex = iter->second;
956  }
957  indexMap[nextElement] = innerIndex;
958  ++cIndex;
959  ++nextElement;
960 
961  int outerIndex = outerIndices[maxCosIndex];
962  mComputePoints[nextElement] = mComputePoints[outerIndex];
963  combined[cIndex] = nextElement;
964  iter = indexMap.find(outerIndex);
965  if (iter != indexMap.end())
966  {
967  outerIndex = iter->second;
968  }
969  indexMap[nextElement] = outerIndex;
970  ++cIndex;
971  ++nextElement;
972 
973  for (int i = maxCosIndex + 1; i < numOuterIndices; ++i, ++cIndex)
974  {
975  combined[cIndex] = outerIndices[i];
976  }
977  return true;
978 }
979 
980 template <typename InputType, typename ComputeType>
982  Polygon const& outer, std::vector<Polygon> const& inners,
983  std::map<int, int>& indexMap, std::vector<int>& combined)
984 {
985  // Sort the inner polygons based on maximum x-values.
986  int numInners = static_cast<int>(inners.size());
987  std::vector<std::pair<ComputeType, int>> pairs(numInners);
988  for (int p = 0; p < numInners; ++p)
989  {
990  int numIndices = static_cast<int>(inners[p].size());
991  int const* indices = inners[p].data();
992  ComputeType xmax = mComputePoints[indices[0]][0];
993  for (int j = 1; j < numIndices; ++j)
994  {
995  ComputeType x = mComputePoints[indices[j]][0];
996  if (x > xmax)
997  {
998  xmax = x;
999  }
1000  }
1001  pairs[p].first = xmax;
1002  pairs[p].second = p;
1003  }
1004  std::sort(pairs.begin(), pairs.end());
1005 
1006  // Merge the inner polygons with the outer polygon.
1007  Polygon currentPolygon = outer;
1008  for (int p = numInners - 1; p >= 0; --p)
1009  {
1010  Polygon const& polygon = inners[pairs[p].second];
1011  Polygon currentCombined;
1012  if (!CombinePolygons(nextElement, currentPolygon, polygon, indexMap, currentCombined))
1013  {
1014  return false;
1015  }
1016  currentPolygon = std::move(currentCombined);
1017  nextElement += 2;
1018  }
1019 
1020  for (auto index : currentPolygon)
1021  {
1022  combined.push_back(index);
1023  }
1024  return true;
1025 }
1026 
1027 template <typename InputType, typename ComputeType>
1028 void TriangulateEC<InputType, ComputeType>::RemapIndices(std::map<int, int> const& indexMap)
1029 {
1030  // The triangulation includes indices to the duplicated outer and inner
1031  // vertices. These indices must be mapped back to the original ones.
1032  for (auto& tri : mTriangles)
1033  {
1034  for (int i = 0; i < 3; ++i)
1035  {
1036  auto iter = indexMap.find(tri[i]);
1037  if (iter != indexMap.end())
1038  {
1039  tri[i] = iter->second;
1040  }
1041  }
1042  }
1043 }
1044 
1045 template <typename InputType, typename ComputeType>
1047 {
1048  // Use a breadth-first search to process the outer-inners pairs of the
1049  // tree of nested polygons.
1050  int numExtraPoints = 0;
1051 
1052  std::queue<std::shared_ptr<Tree>> treeQueue;
1053  treeQueue.push(tree);
1054  while (treeQueue.size() > 0)
1055  {
1056  // The 'root' is an outer polygon.
1057  std::shared_ptr<Tree> outer = treeQueue.front();
1058  treeQueue.pop();
1059 
1060  // Count number of extra points for this outer-inners pair.
1061  int numChildren = static_cast<int>(outer->child.size());
1062  numExtraPoints += 2 * numChildren;
1063 
1064  // Convert outer points from InputType to ComputeType.
1065  int const numOuterIndices = static_cast<int>(outer->polygon.size());
1066  int const* outerIndices = outer->polygon.data();
1067  for (int i = 0; i < numOuterIndices; ++i)
1068  {
1069  int index = outerIndices[i];
1070  if (!mIsConverted[index])
1071  {
1072  mIsConverted[index] = true;
1073  for (int j = 0; j < 2; ++j)
1074  {
1075  mComputePoints[index][j] = mPoints[index][j];
1076  }
1077  }
1078  }
1079 
1080  // The grandchildren of the outer polygon are also outer polygons.
1081  // Insert them into the queue for processing.
1082  for (int c = 0; c < numChildren; ++c)
1083  {
1084  // The 'child' is an inner polygon.
1085  std::shared_ptr<Tree> inner = outer->child[c];
1086 
1087  // Convert inner points from InputType to ComputeType.
1088  int const numInnerIndices = static_cast<int>(inner->polygon.size());
1089  int const* innerIndices = inner->polygon.data();
1090  for (int i = 0; i < numInnerIndices; ++i)
1091  {
1092  int index = innerIndices[i];
1093  if (!mIsConverted[index])
1094  {
1095  mIsConverted[index] = true;
1096  for (int j = 0; j < 2; ++j)
1097  {
1098  mComputePoints[index][j] = mPoints[index][j];
1099  }
1100  }
1101  }
1102 
1103  int numGrandChildren = static_cast<int>(inner->child.size());
1104  for (int g = 0; g < numGrandChildren; ++g)
1105  {
1106  treeQueue.push(inner->child[g]);
1107  }
1108  }
1109  }
1110 
1111  return numExtraPoints;
1112 }
1113 
1114 template <typename InputType, typename ComputeType>
1116  :
1117  index(-1),
1118  isConvex(false),
1119  isEar(false),
1120  vPrev(-1),
1121  vNext(-1),
1122  sPrev(-1),
1123  sNext(-1),
1124  ePrev(-1),
1125  eNext(-1)
1126 {
1127 }
1128 
1129 template <typename InputType, typename ComputeType> inline
1131 {
1132  return mVertices[i];
1133 }
1134 
1135 template <typename InputType, typename ComputeType>
1137 {
1138  Vertex& vertex = V(i);
1139  int curr = vertex.index;
1140  int prev = V(vertex.vPrev).index;
1141  int next = V(vertex.vNext).index;
1142  vertex.isConvex = (mQuery.ToLine(curr, prev, next) > 0);
1143  return vertex.isConvex;
1144 }
1145 
1146 template <typename InputType, typename ComputeType>
1148 {
1149  Vertex& vertex = V(i);
1150 
1151  if (mRFirst == -1)
1152  {
1153  // The remaining polygon is convex.
1154  vertex.isEar = true;
1155  return true;
1156  }
1157 
1158  // Search the reflex vertices and test if any are in the triangle
1159  // <V[prev],V[curr],V[next]>.
1160  int prev = V(vertex.vPrev).index;
1161  int curr = vertex.index;
1162  int next = V(vertex.vNext).index;
1163  vertex.isEar = true;
1164  for (int j = mRFirst; j != -1; j = V(j).sNext)
1165  {
1166  // Check if the test vertex is already one of the triangle vertices.
1167  if (j == vertex.vPrev || j == i || j == vertex.vNext)
1168  {
1169  continue;
1170  }
1171 
1172  // V[j] has been ruled out as one of the original vertices of the
1173  // triangle <V[prev],V[curr],V[next]>. When triangulating polygons
1174  // with holes, V[j] might be a duplicated vertex, in which case it
1175  // does not affect the earness of V[curr].
1176  int test = V(j).index;
1177  if (mComputePoints[test] == mComputePoints[prev]
1178  || mComputePoints[test] == mComputePoints[curr]
1179  || mComputePoints[test] == mComputePoints[next])
1180  {
1181  continue;
1182  }
1183 
1184  // Test if the vertex is inside or on the triangle. When it is, it
1185  // causes V[curr] not to be an ear.
1186  if (mQuery.ToTriangle(test, prev, curr, next) <= 0)
1187  {
1188  vertex.isEar = false;
1189  break;
1190  }
1191  }
1192 
1193  return vertex.isEar;
1194 }
1195 
1196 template <typename InputType, typename ComputeType>
1198 {
1199  if (mCFirst == -1)
1200  {
1201  // Add the first convex vertex.
1202  mCFirst = i;
1203  }
1204  else
1205  {
1206  V(mCLast).sNext = i;
1207  V(i).sPrev = mCLast;
1208  }
1209  mCLast = i;
1210 }
1211 
1212 template <typename InputType, typename ComputeType>
1214 {
1215  if (mRFirst == -1)
1216  {
1217  // Add the first reflex vertex.
1218  mRFirst = i;
1219  }
1220  else
1221  {
1222  V(mRLast).sNext = i;
1223  V(i).sPrev = mRLast;
1224  }
1225  mRLast = i;
1226 }
1227 
1228 template <typename InputType, typename ComputeType>
1230 {
1231  if (mEFirst == -1)
1232  {
1233  // Add the first ear.
1234  mEFirst = i;
1235  mELast = i;
1236  }
1237  V(mELast).eNext = i;
1238  V(i).ePrev = mELast;
1239  mELast = i;
1240 }
1241 
1242 template <typename InputType, typename ComputeType>
1244 {
1245  Vertex& first = V(mEFirst);
1246  int currENext = first.eNext;
1247  Vertex& vertex = V(i);
1248  vertex.ePrev = mEFirst;
1249  vertex.eNext = currENext;
1250  first.eNext = i;
1251  V(currENext).ePrev = i;
1252 }
1253 
1254 template <typename InputType, typename ComputeType>
1256 {
1257  Vertex& first = V(mEFirst);
1258  int currEPrev = first.ePrev;
1259  Vertex& vertex = V(i);
1260  vertex.ePrev = currEPrev;
1261  vertex.eNext = mEFirst;
1262  first.ePrev = i;
1263  V(currEPrev).eNext = i;
1264 }
1265 
1266 template <typename InputType, typename ComputeType>
1268 {
1269  int currVPrev = V(i).vPrev;
1270  int currVNext = V(i).vNext;
1271  V(currVPrev).vNext = currVNext;
1272  V(currVNext).vPrev = currVPrev;
1273 }
1274 
1275 template <typename InputType, typename ComputeType>
1277 {
1278  int currEPrev = V(i).ePrev;
1279  int currENext = V(i).eNext;
1280  V(currEPrev).eNext = currENext;
1281  V(currENext).ePrev = currEPrev;
1282  return currENext;
1283 }
1284 
1285 template <typename InputType, typename ComputeType>
1287 {
1288  LogAssert(mRFirst != -1 && mRLast != -1, "Reflex vertices must exist.");
1289 
1290  if (i == mRFirst)
1291  {
1292  mRFirst = V(i).sNext;
1293  if (mRFirst != -1)
1294  {
1295  V(mRFirst).sPrev = -1;
1296  }
1297  V(i).sNext = -1;
1298  }
1299  else if (i == mRLast)
1300  {
1301  mRLast = V(i).sPrev;
1302  if (mRLast != -1)
1303  {
1304  V(mRLast).sNext = -1;
1305  }
1306  V(i).sPrev = -1;
1307  }
1308  else
1309  {
1310  int currSPrev = V(i).sPrev;
1311  int currSNext = V(i).sNext;
1312  V(currSPrev).sNext = currSNext;
1313  V(currSNext).sPrev = currSPrev;
1314  V(i).sNext = -1;
1315  V(i).sPrev = -1;
1316  }
1317 }
1318 
1319 }
PrimalQuery2< ComputeType > mQuery
void Set(int numVertices, Vector2< Real > const *vertices)
#define LogAssert(condition, message)
Definition: GteLogger.h:86
std::vector< int > Polygon
std::vector< std::array< int, 3 > > mTriangles
Vector2< InputType > const * mPoints
void DoEarClipping(int numVertices, int const *indices)
GLint GLenum GLint x
Definition: glcorearb.h:404
GLsizeiptr size
Definition: glcorearb.h:659
bool ProcessOuterAndInners(int &nextElement, Polygon const &outer, std::vector< Polygon > const &inners, std::map< int, int > &indexMap, std::vector< int > &combined)
GLboolean GLboolean g
Definition: glcorearb.h:1217
const GLubyte * c
Definition: glext.h:11671
GLfixed GLfixed GLint GLint GLfixed points
Definition: glext.h:4927
void RemapIndices(std::map< int, int > const &indexMap)
int ToLine(int i, int v0, int v1) const
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
GLint first
Definition: glcorearb.h:400
std::vector< std::shared_ptr< Tree > > child
Real DotPerp(Vector2< Real > const &v0, Vector2< Real > const &v1)
Definition: GteVector2.h:117
DualQuaternion< Real > Dot(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
GLdouble GLdouble t
Definition: glext.h:239
int ToTriangle(int i, int v0, int v1, int v2) const
std::vector< std::array< int, 3 > > const & GetTriangles() const
bool CombinePolygons(int nextElement, Polygon const &outer, Polygon const &inner, std::map< int, int > &indexMap, std::vector< int > &combined)
std::vector< Vector2< ComputeType > > mComputePoints
GLdouble s
Definition: glext.h:231
GLuint index
Definition: glcorearb.h:781
int InitializeFromTree(std::shared_ptr< Tree > const &tree)
std::vector< Vertex > mVertices
void InitializeVertices(int numVertices, int const *indices)
GLfloat GLfloat p
Definition: glext.h:11668
TriangulateEC(int numPoints, Vector2< InputType > const *points)
std::vector< bool > mIsConverted


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