xmsgrid  1.0
TrTin.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
6 //------------------------------------------------------------------------------
7 
8 //----- Included files ---------------------------------------------------------
9 
10 // 1. Precompiled header
11 
12 // 2. My own header
14 
15 // 3. Standard library headers
16 #include <cfloat>
17 #include <numeric>
18 #include <ostream>
19 #include <sstream>
20 
21 // 4. External library headers
22 #include <boost/bind.hpp>
23 #include <boost/archive/text_iarchive.hpp>
24 #include <boost/archive/text_oarchive.hpp>
25 #include <boost/serialization/export.hpp>
26 #include <boost/serialization/vector.hpp>
27 #include <boost/unordered_set.hpp>
28 
29 // 5. Shared code headers
31 #include <xmscore/stl/set.h>
32 #include <xmscore/stl/vector.h>
33 #include <xmsgrid/geometry/geoms.h>
36 #include <xmscore/misc/XmError.h>
37 #include <xmscore/misc/xmstype.h>
38 #include <xmscore/misc/XmConst.h>
39 
40 // 6. Non-shared code headers
41 
42 //----- Namespace declaration --------------------------------------------------
43 
44 namespace xms
45 {
46 //----- Forward declarations ---------------------------------------------------
47 
48 //----- External globals -------------------------------------------------------
49 
50 //----- Constants / Enumerations -----------------------------------------------
51 
52 //----- Classes / Structs ------------------------------------------------------
53 
55 class TrTinImpl : public TrTin
56 {
58  friend class boost::serialization::access;
60 public:
61  TrTinImpl();
62  virtual ~TrTinImpl();
63 
64  // Setters
65  virtual void SetPoints(BSHP<VecPt3d> a_pts) override;
66  virtual void SetTriangles(BSHP<VecInt> a_tris) override;
67  virtual void SetTrianglesAdjacentToPoints(BSHP<VecInt2d> a_trisAdjToPts) override;
68  virtual void SetGeometry(BSHP<VecPt3d> a_pts,
69  BSHP<VecInt> a_tris,
70  BSHP<VecInt2d> a_trisAdjToPts) override;
71 
72  // Getters
73  virtual VecPt3d& Points() override;
74  virtual VecInt& Triangles() override;
75  virtual VecInt2d& TrisAdjToPts() override;
76 
77  virtual const VecPt3d& Points() const override;
78  virtual const VecInt& Triangles() const override;
79  virtual const VecInt2d& TrisAdjToPts() const override;
80 
81  virtual BSHP<VecPt3d> PointsPtr() override;
82  virtual BSHP<VecInt> TrianglesPtr() override;
83 
84  virtual int NumPoints() const override;
85  virtual int NumTriangles() const override;
86 
87  // "tr" equivalent functions (trTriangleFromEdge, trIndex etc)
88 
89  // Non modifiers
90  virtual bool TriangleFromEdge(int a_pt1,
91  int a_pt2,
92  int& a_tri,
93  int& a_idx1,
94  int& a_idx2) const override;
95  virtual int TriangleAdjacentToEdge(int a_pt1, int a_pt2) const override;
96  virtual int LocalIndex(int a_tri, int a_pt) const override;
97  virtual int GlobalIndex(int a_triIdx, int a_localVtxIdx) const override;
98  virtual bool VerticesAreAdjacent(int a_pt1, int a_pt2) const override;
99  virtual int CommonEdgeIndex(int a_tri, int a_adjTri) const override;
100  virtual int AdjacentTriangle(int a_triIdx, int a_edgeIdx) const override;
101  virtual Pt3d TriangleCentroid(int a_tri) const override;
102  virtual double TriangleArea(int a_tri) const override;
103  // virtual int FirstBoundaryPoint () const;
104  virtual int NextBoundaryPoint(int a_point) const override;
105  virtual int PreviousBoundaryPoint(int a_point) const override;
106  virtual void GetBoundaryPoints(VecInt& a_boundaryPoints) const override;
107  virtual void GetBoundaryPolys(VecInt2d& a_polys) const override;
108  virtual bool GetExtents(Pt3d& a_mn, Pt3d& a_mx) const override;
109  virtual void ExportTinFile(std::ostream& a_os) const override;
110 
111  // Modifiers
112  virtual bool SwapEdge(int a_triA, int a_triB, bool a_checkAngle = true) override;
113  virtual void DeleteTriangles(const SetInt& a_trisToDelete) override;
114  virtual void DeletePoints(const SetInt& a_points) override;
115  virtual bool OptimizeTriangulation() override;
116  virtual bool RemoveLongThinTrianglesOnPerimeter(const double a_ratio) override;
117  virtual void Clear() override;
118  virtual void BuildTrisAdjToPts() override;
119 
120  virtual std::string ToString() const override;
121  virtual void FromString(const std::string&) override;
122  template <typename Archive>
123  void serialize(Archive& archive, const unsigned int version);
124 
125 private:
126  void InsertAdjacentTriangle(int a_pt, int a_tri);
127  void DeleteAdjacentTriangle(int a_pt, int a_tri);
128  bool TriIndexFound(const int& a_triPt) const;
129  bool PointIndexFound(const Pt3d& a_point) const;
130  bool AdjacentIndexFound(const VecInt& a_point) const;
131  bool CheckAndSwap(int a_triA, int a_triB, bool a_propagate, const VecInt& a_flags);
132  bool PointIsInCircumcircle(int a_tri1, int a_tri2, int id);
133  void BuildTrisAdjToPtsConst() const;
134  void CheckTriangle(const int a_tri, const int a_index, const double a_ratio,
135  VecInt &a_flags, SetInt &a_trisToDelete) const;
136  int AdjacentTriangleIndex(const int a_currTri, const int a_adjTri) const;
137 
138  BSHP<VecPt3d> m_pts;
139  BSHP<VecInt> m_tris;
140  BSHP<VecInt2d> m_trisAdjToPts;
141  boost::unordered_set<int> m_toDelete;
142 
143 }; // class TrTinImpl
144 } // namespace xms
145 
147 // BOOST_CLASS_VERSION(xms::TrTinImpl, 1) // only if using version
148 
149 namespace xms
150 {
151 //----- Internal functions -----------------------------------------------------
152 
153 //----- Class / Function definitions -------------------------------------------
154 
160 //------------------------------------------------------------------------------
162 //------------------------------------------------------------------------------
164 : m_pts(new VecPt3d())
165 , m_tris(new VecInt())
166 , m_trisAdjToPts(new VecInt2d())
167 , m_toDelete()
168 {
169 }
170 //------------------------------------------------------------------------------
172 //------------------------------------------------------------------------------
174 {
175 }
176 //------------------------------------------------------------------------------
179 //------------------------------------------------------------------------------
180 void TrTinImpl::SetPoints(BSHP<VecPt3d> a_pts)
181 {
182  m_pts = a_pts;
183 }
184 //------------------------------------------------------------------------------
187 //------------------------------------------------------------------------------
188 void TrTinImpl::SetTriangles(BSHP<VecInt> a_tris)
189 {
190  m_tris = a_tris;
191 }
192 //------------------------------------------------------------------------------
195 //------------------------------------------------------------------------------
196 void TrTinImpl::SetTrianglesAdjacentToPoints(BSHP<VecInt2d> a_trisAdjToPts)
197 {
198  m_trisAdjToPts = a_trisAdjToPts;
199 }
200 //------------------------------------------------------------------------------
205 //------------------------------------------------------------------------------
206 void TrTinImpl::SetGeometry(BSHP<VecPt3d> a_pts, BSHP<VecInt> a_tris, BSHP<VecInt2d> a_trisAdjToPts)
207 {
208  m_pts = a_pts;
209  m_tris = a_tris;
210  m_trisAdjToPts = a_trisAdjToPts;
211 } // TrTinImpl::SetGeometry
212 //------------------------------------------------------------------------------
215 //------------------------------------------------------------------------------
217 {
218  return *m_pts.get();
219 }
220 //------------------------------------------------------------------------------
223 //------------------------------------------------------------------------------
225 {
226  return *m_tris.get();
227 }
228 //------------------------------------------------------------------------------
231 //------------------------------------------------------------------------------
233 {
234  return *m_trisAdjToPts.get();
235 }
236 //------------------------------------------------------------------------------
239 //------------------------------------------------------------------------------
241 {
242  return *m_pts.get();
243 }
244 //------------------------------------------------------------------------------
247 //------------------------------------------------------------------------------
249 {
250  return *m_tris.get();
251 }
252 //------------------------------------------------------------------------------
255 //------------------------------------------------------------------------------
257 {
258  return *m_trisAdjToPts.get();
259 }
260 //------------------------------------------------------------------------------
263 //------------------------------------------------------------------------------
264 BSHP<VecPt3d> TrTinImpl::PointsPtr()
265 {
266  return m_pts;
267 }
268 //------------------------------------------------------------------------------
271 //------------------------------------------------------------------------------
273 {
274  return m_tris;
275 }
276 //------------------------------------------------------------------------------
279 //------------------------------------------------------------------------------
281 {
282  return (int)(*m_pts).size();
283 }
284 //------------------------------------------------------------------------------
287 //------------------------------------------------------------------------------
289 {
290  return (int)(*m_tris).size() / 3;
291 }
292 //------------------------------------------------------------------------------
301 //------------------------------------------------------------------------------
303  int a_pt2,
304  int& a_tri,
305  int& a_localPt1,
306  int& a_localPt2) const
307 {
308  a_localPt1 = a_localPt2 = 0;
309 
310  // For each triangle adjacent to a_pt1
311  VecInt::const_iterator adj = (*m_trisAdjToPts)[a_pt1].begin();
312  for (; adj != (*m_trisAdjToPts)[a_pt1].end(); ++adj)
313  {
314  a_localPt1 = LocalIndex(*adj, a_pt1);
315  a_localPt2 = trIncrementIndex(a_localPt1);
316  if ((*m_tris)[(*adj * 3) + a_localPt2] == a_pt2)
317  {
318  a_tri = *adj;
319  return true;
320  }
321  }
322  a_tri = XM_NONE;
323  return false;
324 } // TrTinImpl::TriangleFromEdge
325 //------------------------------------------------------------------------------
333 //------------------------------------------------------------------------------
334 int TrTinImpl::TriangleAdjacentToEdge(int a_pt1, int a_pt2) const
335 {
336  int localIdx1, localIdx2;
337 
338  // For each triangle adjacent to a_pt1
339  VecInt::const_iterator adj = (*m_trisAdjToPts)[a_pt1].begin();
340  bool found = false;
341  for (; adj != (*m_trisAdjToPts)[a_pt1].end(); ++adj)
342  {
343  localIdx1 = LocalIndex(*adj, a_pt1);
344  localIdx2 = trDecrementIndex(localIdx1);
345  if ((*m_tris)[(*adj * 3) + localIdx2] == a_pt2)
346  {
347  found = true;
348  break;
349  }
350  }
351  return (found ? *adj : XM_NONE);
352 } // TrTinImpl::TriangleAdjacentToEdge
353 //------------------------------------------------------------------------------
360 //------------------------------------------------------------------------------
361 int TrTinImpl::LocalIndex(int a_tri, int a_pt) const
362 {
363  int t = a_tri * 3;
364  for (int i = 0; i < 3; ++i)
365  {
366  if ((*m_tris)[t + i] == a_pt)
367  return i;
368  }
369  return XM_NONE;
370 } // TrTinImpl::LocalIndex
371 //------------------------------------------------------------------------------
377 //------------------------------------------------------------------------------
378 bool TrTinImpl::VerticesAreAdjacent(int a_pt1, int a_pt2) const
379 {
380  // Look through the triangles adjacent to a_pt1
381  for (size_t i = 0; i < (*m_trisAdjToPts)[a_pt1].size(); ++i)
382  {
383  int trisIdx = (*m_trisAdjToPts)[a_pt1][i] * 3; // Index in m_tris
384  // See if a_pt2 is part of this triangle by checking all three points.
385  // vrVerticesAreAdjacent would call trIndex then trIncrementIndex and
386  // trDecrementIndex but I think this is simpler and maybe faster.
387  for (int j = 0; j < 3; ++j)
388  {
389  if ((*m_tris)[trisIdx + j] == a_pt2)
390  {
391  return true;
392  }
393  }
394  }
395  return false;
396 } // TrTinImpl::VerticesAreAdjacent
397 //------------------------------------------------------------------------------
418 //------------------------------------------------------------------------------
419 bool TrTinImpl::SwapEdge(int a_triA, int a_triB, bool a_checkAngle /*true*/)
420 {
421  XM_ENSURE_TRUE_NO_ASSERT(a_triA >= 0 && a_triB >= 0, false);
422 
423  int a1, a2, a3, b1, b2, b3;
424  int top, btm, lft, rgt;
425  Pt3d toppt, btmpt, lftpt, rgtpt;
426 
427  b3 = CommonEdgeIndex(a_triB, a_triA);
428  b2 = trDecrementIndex(b3);
429  b1 = trIncrementIndex(b3);
430  a3 = LocalIndex(a_triA, GlobalIndex(a_triB, b1));
431  a1 = trIncrementIndex(a3);
432  a2 = trIncrementIndex(a1);
433  top = GlobalIndex(a_triB, b2);
434  lft = GlobalIndex(a_triB, b3);
435  rgt = GlobalIndex(a_triB, b1);
436  btm = GlobalIndex(a_triA, a2);
437  toppt = (*m_pts)[top];
438  lftpt = (*m_pts)[lft];
439  rgtpt = (*m_pts)[rgt];
440  btmpt = (*m_pts)[btm];
441 
442  // make sure triangles are good
443  double area1 = trArea(toppt, lftpt, btmpt);
444  double area2 = trArea(btmpt, rgtpt, toppt);
445 
446  if (area1 > 0.0 && area2 > 0.0)
447  {
448  bool swap = true;
449  if (a_checkAngle)
450  {
451  double ang1 = gmAngleBetweenEdges(rgtpt, btmpt, toppt);
452  double ang2 = gmAngleBetweenEdges(btmpt, toppt, rgtpt);
453  double ang3 = gmAngleBetweenEdges(toppt, btmpt, lftpt);
454  double ang4 = gmAngleBetweenEdges(lftpt, toppt, btmpt);
455  const static double min_ang = 0.01 * (XM_PI / 180.0);
456  const static double max_ang = 179.99 * (XM_PI / 180.0);
457  if (ang1 < min_ang || ang1 > max_ang || ang2 < min_ang || ang2 > max_ang || ang3 < min_ang ||
458  ang3 > max_ang || ang4 < min_ang || ang4 > max_ang)
459  {
460  swap = false;
461  }
462  }
463  if (swap)
464  {
465  // update the adjacent tin ptrs
466  DeleteAdjacentTriangle(lft, a_triB);
467  DeleteAdjacentTriangle(rgt, a_triA);
468  InsertAdjacentTriangle(top, a_triA /*, a3*/);
469  InsertAdjacentTriangle(btm, a_triB /*, b3*/);
470 
471  // update the verts
472  (*m_tris)[(a_triA * 3) + a3] = top;
473  (*m_tris)[(a_triB * 3) + b3] = btm;
474 
475  // See if we created a bad triangle
476  if (!gmCounterClockwiseTri((*m_pts)[(*m_tris)[a_triA * 3]],
477  (*m_pts)[(*m_tris)[(a_triA * 3) + 1]],
478  (*m_pts)[(*m_tris)[(a_triA * 3) + 2]]) ||
479  !gmCounterClockwiseTri((*m_pts)[(*m_tris)[a_triB * 3]],
480  (*m_pts)[(*m_tris)[(a_triB * 3) + 1]],
481  (*m_pts)[(*m_tris)[(a_triB * 3) + 2]]))
482  {
483  std::stringstream msg;
484  msg << "Swapping triangles: " << a_triA << " and " << a_triB
485  << " created invalid triangles (ordered cw instead of ccw).";
486  XM_LOG(xmlog::error, msg.str());
487  }
488  return true;
489  }
490  }
491  return false;
492 } // TrTinImpl::SwapEdge
493 //------------------------------------------------------------------------------
516 //------------------------------------------------------------------------------
517 bool TrTinImpl::CheckAndSwap(int a_triA, int a_triB, bool a_propagate, const VecInt& a_flags)
518 {
519  XM_ENSURE_TRUE_NO_ASSERT(a_triA >= 0 && a_triB >= 0, false);
520 
521  bool change = false;
522  int tri1id2 = 0;
523  int tri2id0 = 0, tri2id1 = 0, tri2id2 = 0;
524 
525  if (a_triB != XM_NONE)
526  {
527  tri2id2 = CommonEdgeIndex(a_triB, a_triA);
528  tri2id1 = trDecrementIndex(tri2id2);
529  change = PointIsInCircumcircle(a_triA, a_triB, tri2id1);
530  }
531 
532  if (change)
533  {
534  tri2id0 = trIncrementIndex(tri2id2);
535  tri1id2 = LocalIndex(a_triA, GlobalIndex(a_triB, tri2id0));
536 
537  SwapEdge(a_triA, a_triB, false);
538  int adjTri = AdjacentTriangle(a_triA, tri1id2);
539  if (a_propagate || (!a_propagate && adjTri != XM_NONE && a_flags[adjTri]))
540  {
541  CheckAndSwap(a_triA, adjTri, a_propagate, a_flags);
542  }
543  adjTri = AdjacentTriangle(a_triA, tri2id0);
544  if (a_propagate || (!a_propagate && adjTri != XM_NONE && a_flags[adjTri]))
545  {
546  CheckAndSwap(a_triB, adjTri, a_propagate, a_flags);
547  }
548  }
549 
550  return false;
551 } // TrTinImpl::CheckAndSwap
552 //------------------------------------------------------------------------------
581 //------------------------------------------------------------------------------
582 bool TrTinImpl::PointIsInCircumcircle(int a_tri1, int a_tri2, int a_localPt)
583 {
584  int t = a_tri1 * 3;
585  return (gmPtInCircumcircle((*m_pts)[GlobalIndex(a_tri2, a_localPt)], &(*m_pts)[t]) == PT_IN);
586 } // TrTinImpl::PointIsInCircumcircle
587 //------------------------------------------------------------------------------
597 //------------------------------------------------------------------------------
598 int TrTinImpl::CommonEdgeIndex(int a_tri, int a_adjTri) const
599 {
600  bool found = false;
601  int edge = 0;
602  while (!found)
603  {
604  int adjtri = AdjacentTriangle(a_tri, edge);
605  if (adjtri == a_adjTri)
606  found = true;
607  else
608  edge = trIncrementIndex(edge);
609  if (edge == 0)
610  break;
611  }
612  if (!found)
613  edge = XM_NONE;
614  return edge;
615 } // TrTinImpl::CommonEdgeIndex
616 //------------------------------------------------------------------------------
632 //------------------------------------------------------------------------------
633 int TrTinImpl::AdjacentTriangle(int a_triIdx, int a_edgeIdx) const
634 {
635  int t = a_triIdx * 3;
636  int edgePt1 = (*m_tris)[t + a_edgeIdx];
637  int edgePt2 = (*m_tris)[t + trIncrementIndex(a_edgeIdx)];
638 
639  int adjTri;
640  int idx1, idx2;
641  if (TriangleFromEdge(edgePt2, edgePt1, adjTri, idx1, idx2))
642  {
643  return adjTri;
644  }
645  return XM_NONE;
646 } // TrTinImpl::AdjacentTriangle
647 //------------------------------------------------------------------------------
651 //------------------------------------------------------------------------------
652 xms::Pt3d TrTinImpl::TriangleCentroid(int a_tri) const
653 {
654  int t = a_tri * 3;
655  Pt3d centroid((*m_pts)[(*m_tris)[t]]);
656  centroid += (*m_pts)[(*m_tris)[t + 1]];
657  centroid += (*m_pts)[(*m_tris)[t + 2]];
658  return (centroid / (double)3);
659 } // TrTinImpl::TriangleCentroid
660 //------------------------------------------------------------------------------
664 //------------------------------------------------------------------------------
665 double TrTinImpl::TriangleArea(int a_tri) const
666 {
667  int t = a_tri * 3;
668  return trArea((*m_pts)[(*m_tris)[t]], (*m_pts)[(*m_tris)[t + 1]], (*m_pts)[(*m_tris)[t + 2]]);
669 
670 } // TrTinImpl::TriangleArea
671 #if 0 // FirstBoundaryPoint has been commented out because it wasn't used
672  // Also, what if you have holes? Consider using GetBoundaryPoints and
673  // GetBoundaryPolys. The code has been left here in case we reconsider.
674 //------------------------------------------------------------------------------
679 //------------------------------------------------------------------------------
680 int TrTinImpl::FirstBoundaryPoint () const
681 {
682  XM_ENSURE_TRUE_NO_ASSERT(!(*m_trisAdjToPts).empty(), XM_NONE);
683 
684  int nPoints = NumPoints();
685  int firstTri, tri, localIndex, prevtri(XM_NONE);
686  for (int p = 0; p < nPoints; ++p)
687  {
688  firstTri = tri = (*m_trisAdjToPts)[p][0];
689  do {
690  localIndex = LocalIndex(tri, p);
691  prevtri = tri;
692  tri = AdjacentTriangle(tri, localIndex);
693  } while (tri != firstTri && tri != XM_NONE);
694  if (tri == XM_NONE) {
695  return p;
696  }
697  }
698  return XM_NONE;
699 } // TrTinImpl::FirstBoundaryPoint
700 #endif
701 //------------------------------------------------------------------------------
709 //------------------------------------------------------------------------------
710 int TrTinImpl::NextBoundaryPoint(int a_point) const
711 {
712  XM_ENSURE_TRUE_NO_ASSERT(a_point >= 0 && a_point <= (int)(*m_pts).size(), XM_NONE);
713  XM_ENSURE_TRUE_NO_ASSERT(!(*m_trisAdjToPts)[a_point].empty(), XM_NONE);
714 
715  // Get a starting tri
716  int firstTri, tri, prevtri(XM_NONE), bpoint(XM_NONE);
717  int localIndex;
718  firstTri = tri = (*m_trisAdjToPts)[a_point][0];
719 
720  // use a "do" loop not a "while" loop here
721  do
722  {
723  localIndex = trDecrementIndex(LocalIndex(tri, a_point));
724  prevtri = tri;
725  tri = AdjacentTriangle(tri, localIndex);
726  } while (tri != firstTri && tri != XM_NONE);
727 
728  // if tri is null, there is a boundary vertex
729  if (tri == XM_NONE)
730  {
731  bpoint = GlobalIndex(prevtri, localIndex);
732  }
733  return bpoint;
734 
735 } // TrTinImpl::NextBoundaryPoint
736 //------------------------------------------------------------------------------
744 //------------------------------------------------------------------------------
745 int TrTinImpl::PreviousBoundaryPoint(int a_point) const
746 {
747  XM_ENSURE_TRUE_NO_ASSERT(a_point >= 0 && a_point <= (int)(*m_pts).size(), XM_NONE);
748  XM_ENSURE_TRUE_NO_ASSERT(!(*m_trisAdjToPts)[a_point].empty(), XM_NONE);
749 
750  // Get a starting tri
751  int firstTri, tri, prevtri(XM_NONE), bpoint(XM_NONE);
752  int localIndex;
753  firstTri = tri = (*m_trisAdjToPts)[a_point][0];
754 
755  // use a "do" loop not a "while" loop here
756  do
757  {
758  localIndex = LocalIndex(tri, a_point);
759  prevtri = tri;
760  tri = AdjacentTriangle(tri, localIndex);
761  } while (tri != firstTri && tri != XM_NONE);
762 
763  // if tri is null, there is a boundary vertex
764  if (tri == XM_NONE)
765  {
766  bpoint = GlobalIndex(prevtri, trIncrementIndex(localIndex));
767  }
768  return bpoint;
769 } // TrTinImpl::PreviousBoundaryPoint
770 //------------------------------------------------------------------------------
775 //------------------------------------------------------------------------------
776 void TrTinImpl::GetBoundaryPoints(VecInt& a_boundaryPoints) const
777 {
778  // Make sure adjacencies exist first
779  if (TrisAdjToPts().empty())
780  {
782  }
783 
784  VecInt& tris = *m_tris;
785  SetInt setPoints;
786  size_t numTri = m_tris->size() / 3;
787  int t = 0;
788  for (size_t tri = 0; tri < numTri; ++tri, t += 3)
789  {
790  for (int i = 0; i < 3; ++i)
791  {
792  if (AdjacentTriangle((int)tri, i) == XM_NONE)
793  {
794  setPoints.insert(tris[t + i]);
795  setPoints.insert(tris[t + trIncrementIndex(i)]);
796  }
797  }
798  }
799 
800  a_boundaryPoints.clear();
801  std::copy(setPoints.begin(), setPoints.end(), std::back_inserter(a_boundaryPoints));
802 
803 } // TrTinImpl::GetBoundaryPoints
804 //------------------------------------------------------------------------------
809 //------------------------------------------------------------------------------
811 {
812  // Get all the points on any boundary
813  VecInt points;
814  GetBoundaryPoints(points);
815 
816  // Convert to a set
817  boost::unordered_set<int> pointSet(points.begin(), points.end());
818 
819  // Put points into polygons
820  a_polys.clear();
821  while (!pointSet.empty())
822  {
823  // Get the new first point
824  // using minimum element so result is consistent for different architectures
825  auto it = std::min_element(pointSet.begin(), pointSet.end());
826 
827  // Find adjacent points on the border until we return to the first point,
828  // removing the points from the set of boundary points
829  int first = *it;
830  a_polys.push_back(VecInt());
831  a_polys.back().push_back(first);
832  pointSet.erase(it);
833  int next = NextBoundaryPoint(first);
834  while (next != first)
835  {
836  a_polys.back().push_back(next);
837  it = pointSet.find(next);
838  if (it == pointSet.end())
839  {
841  "Unable to get boundary polygon from meshed points. Check the input polygon.");
842  a_polys.clear();
843  return;
844  }
845  pointSet.erase(it);
846  next = NextBoundaryPoint(next);
847  }
848  a_polys.back().push_back(a_polys.back().front()); // Repeat first point as the last point
849  }
850 } // TrTinImpl::GetBoundaryPolys
851 //------------------------------------------------------------------------------
856 //------------------------------------------------------------------------------
857 bool TrTinImpl::GetExtents(Pt3d& a_mn, Pt3d& a_mx) const
858 {
859  if (!(*m_pts).empty())
860  {
861  const VecPt3d& pts = (*m_pts);
862  a_mn = XM_DBL_HIGHEST;
863  a_mx = XM_DBL_LOWEST;
864  for (size_t i = 0; i < pts.size(); ++i)
865  {
866  gmAddToExtents(pts[i], a_mn, a_mx);
867  }
868  return true;
869  }
870  return false;
871 } // TrTinImpl::GetExtents
872 //------------------------------------------------------------------------------
875 //------------------------------------------------------------------------------
876 void TrTinImpl::ExportTinFile(std::ostream& a_os) const
877 {
878  a_os << "TIN\n";
879  a_os << "BEGT\n";
880 
881  // Points
882  VecPt3d& pts = (*m_pts);
883  a_os << "VERT " << pts.size() << "\n";
884  for (size_t i = 0; i < pts.size(); ++i)
885  {
886  a_os << STRstd(pts[i].x) << "\t" << STRstd(pts[i].y) << "\t" << STRstd(pts[i].z) << "\n";
887  }
888 
889  // Triangles
890  VecInt& tris = (*m_tris);
891  a_os << "TRI " << NumTriangles() << "\n";
892  for (size_t i = 0; i < tris.size(); i += 3)
893  {
894  a_os << (tris[i] + 1) << "\t" << (tris[i + 1] + 1) << "\t" << (tris[i + 2] + 1) << "\n";
895  }
896 
897  a_os << "ENDT\n";
898 } // TrTinImpl::ExportTinFile
899 //------------------------------------------------------------------------------
904 //------------------------------------------------------------------------------
905 void TrTinImpl::InsertAdjacentTriangle(int a_pt, int a_tri)
906 {
907  XM_ENSURE_TRUE_VOID(a_pt >= 0 && a_tri >= 0);
908 
909  (*m_trisAdjToPts)[a_pt].push_back(a_tri);
910 } // TrTinImpl::InsertAdjacentTriangle
911 //------------------------------------------------------------------------------
916 //------------------------------------------------------------------------------
917 void TrTinImpl::DeleteAdjacentTriangle(int a_pt, int a_tri)
918 {
919  VecInt::iterator adjTri = (*m_trisAdjToPts)[a_pt].begin();
920  for (; adjTri != (*m_trisAdjToPts)[a_pt].end(); ++adjTri)
921  {
922  if (*adjTri == a_tri)
923  {
924  (*m_trisAdjToPts)[a_pt].erase(adjTri);
925  break;
926  }
927  }
928 } // TrTinImpl::DeleteAdjacentTriangle
929 //------------------------------------------------------------------------------
934 //------------------------------------------------------------------------------
935 int TrTinImpl::GlobalIndex(int a_triIdx, int a_localPt) const
936 {
937  XM_ENSURE_TRUE((a_triIdx * 3) + a_localPt < static_cast<int>((*m_tris).size()), XM_NONE);
938  return (*m_tris)[(a_triIdx * 3) + a_localPt];
939 } // TrTinImpl::GlobalIndex
940 //------------------------------------------------------------------------------
949 //------------------------------------------------------------------------------
950 bool TrTinImpl::TriIndexFound(const int& a_triPt) const
951 {
952  int index = (int)(&a_triPt - &*(*m_tris).begin());
953  return m_toDelete.find(index) != m_toDelete.end();
954 } // TrTinImpl::TriIndexFound
955 //------------------------------------------------------------------------------
964 //------------------------------------------------------------------------------
965 bool TrTinImpl::PointIndexFound(const Pt3d& a_point) const
966 {
967  int index = (int)(&a_point - &*(*m_pts).begin());
968  return m_toDelete.find(index) != m_toDelete.end();
969 } // TrTinImpl::PointIndexFound
970 //------------------------------------------------------------------------------
979 //------------------------------------------------------------------------------
980 bool TrTinImpl::AdjacentIndexFound(const VecInt& a_adj) const
981 {
982  int index = (int)(&a_adj - &*(*m_trisAdjToPts).begin());
983  return m_toDelete.find(index) != m_toDelete.end();
984 } // TrTinImpl::AdjacentIndexFound
985 //------------------------------------------------------------------------------
989 //------------------------------------------------------------------------------
990 void TrTinImpl::DeleteTriangles(const SetInt& a_trisToDelete)
991 {
992  int oldNumTris = NumTriangles();
993 
994  // Add indices of triangles in m_tris to a hash table
995  for (SetInt::iterator it = a_trisToDelete.begin(); it != a_trisToDelete.end(); ++it)
996  {
997  XM_ENSURE_TRUE_VOID_NO_ASSERT((*it * 3) + 2 < static_cast<int>((*m_tris).size()));
998  m_toDelete.insert((*it * 3));
999  m_toDelete.insert((*it * 3) + 1);
1000  m_toDelete.insert((*it * 3) + 2);
1001  }
1002 
1003  // Erase triangles from the m_tris vector using m_toDelete set.
1004  // This would be better as a lamda but I couldn't get it to work.
1005  (*m_tris).erase(std::remove_if((*m_tris).begin(), (*m_tris).end(),
1006  boost::bind(&TrTinImpl::TriIndexFound, this, _1)),
1007  (*m_tris).end());
1008  m_toDelete.clear();
1009 
1010  // Remove adjacent triangles from m_trisAdjToPts
1011  for (VecInt2d::iterator itPoint = (*m_trisAdjToPts).begin(); itPoint != (*m_trisAdjToPts).end();
1012  ++itPoint)
1013  {
1014  for (VecInt::iterator itTri = itPoint->begin(); itTri != itPoint->end();)
1015  {
1016  if (a_trisToDelete.find(*itTri) != a_trisToDelete.end())
1017  {
1018  itTri = itPoint->erase(itTri);
1019  }
1020  else
1021  {
1022  ++itTri;
1023  }
1024  }
1025  }
1026 
1027  // Renumber triangles in m_trisAdjToPts
1028  // Create a oldToNewIdxs
1029  VecInt oldToNewIdxs(oldNumTris); // Size of old, will have new idxs
1030  std::iota(oldToNewIdxs.begin(), oldToNewIdxs.end(), 0); // Init 0 to old size
1031  SetInt::iterator it = a_trisToDelete.begin();
1032  int offset = 0;
1033  for (int i = 0; i < oldNumTris; ++i)
1034  {
1035  if (it != a_trisToDelete.end() && i >= *it)
1036  {
1037  offset++;
1038  ++it;
1039  }
1040  else
1041  {
1042  oldToNewIdxs[i] -= offset;
1043  }
1044  }
1045  for (VecInt2d::iterator itPoint = (*m_trisAdjToPts).begin(); itPoint != (*m_trisAdjToPts).end();
1046  ++itPoint)
1047  {
1048  for (VecInt::iterator itAdj = itPoint->begin(); itAdj != itPoint->end(); ++itAdj)
1049  {
1050  *itAdj = oldToNewIdxs[*itAdj];
1051  }
1052  }
1053 
1054 } // TrTinImpl::DeleteTriangles
1055 //------------------------------------------------------------------------------
1059 //------------------------------------------------------------------------------
1060 void TrTinImpl::DeletePoints(const SetInt& a_points)
1061 {
1062  // Add a_points to a hash table which is used by the predicate
1063  m_toDelete.clear();
1064  m_toDelete.insert(a_points.begin(), a_points.end());
1065 
1066  // Erase points from the m_pts vector using m_toDelete set.
1067  // This would be better as a lamda but I couldn't get it to work.
1068  (*m_pts).erase(std::remove_if((*m_pts).begin(), (*m_pts).end(),
1069  boost::bind(&TrTinImpl::PointIndexFound, this, _1)),
1070  (*m_pts).end());
1071 
1072  // Create a set of all triangles adjacent to all points to be deleted
1073  SetInt trianglesToDelete;
1074  if (!(*m_trisAdjToPts).empty() && !(*m_tris).empty())
1075  {
1076  SetInt::const_iterator it = a_points.begin();
1077  for (; it != a_points.end(); ++it)
1078  {
1079  trianglesToDelete.insert((*m_trisAdjToPts)[*it].begin(), (*m_trisAdjToPts)[*it].end());
1080  }
1081  }
1082 
1083  if (!(*m_trisAdjToPts).empty())
1084  {
1085  // Erase points from the m_trisAdjToPts vector using m_toDelete set.
1086  // This would be better as a lamda but I couldn't get it to work.
1087  (*m_trisAdjToPts)
1088  .erase(std::remove_if((*m_trisAdjToPts).begin(), (*m_trisAdjToPts).end(),
1089  boost::bind(&TrTinImpl::AdjacentIndexFound, this, _1)),
1090  (*m_trisAdjToPts).end());
1091  }
1092  m_toDelete.clear();
1093 
1094  // Remove all triangles attached to the deleted points
1095  if (!(*m_trisAdjToPts).empty() && !(*m_tris).empty())
1096  {
1097  DeleteTriangles(trianglesToDelete);
1098  trRenumberOnDelete(a_points, (*m_tris));
1099  }
1100 
1101 } // TrTinImpl::DeletePoints
1102 //------------------------------------------------------------------------------
1105 //------------------------------------------------------------------------------
1107 {
1108  bool modified = false;
1109  int nTri = NumTriangles();
1110  VecInt flags(nTri, false);
1111 
1112  bool meshaltered;
1113  int id;
1114  int adjtri;
1115 
1116  do
1117  {
1118  meshaltered = false;
1119  for (int tri = 0; tri < nTri; ++tri)
1120  {
1121  if (flags[tri])
1122  {
1123  id = 0;
1124  for (int i = 0; i <= 2; i++)
1125  {
1126  // get neighboring element
1127  adjtri = AdjacentTriangle(tri, id);
1128  if (adjtri != XM_NONE && flags[adjtri])
1129  {
1130  // swap if needed and propagate
1131  if (CheckAndSwap(tri, adjtri, false, flags))
1132  {
1133  meshaltered = true;
1134  }
1135  }
1136  id = trIncrementIndex(id);
1137  }
1138  }
1139  }
1140  if (meshaltered)
1141  modified = true;
1142  } while (meshaltered);
1143 
1144  return true;
1145 } // TrTinImpl::OptimizeTriangulation
1146 //------------------------------------------------------------------------------
1153 //------------------------------------------------------------------------------
1154 int TrTinImpl::AdjacentTriangleIndex(const int a_currTri, const int a_adjTri) const
1155 {
1156  if (a_currTri == XM_NONE || a_adjTri == XM_NONE)
1157  return XM_NONE; // hold onto your butts
1158  int index = 0;
1159  while (index < 3)
1160  {
1161  if (AdjacentTriangle(a_adjTri, index) == a_currTri)
1162  return index;
1163  else
1164  ++index;
1165  }
1166  return XM_NONE; // hold onto your butts
1167 } // TrTinImpl::AdjacentTriangleIndex
1168 //------------------------------------------------------------------------------
1180 //------------------------------------------------------------------------------
1181 void TrTinImpl::CheckTriangle(const int a_tri, const int a_index,
1182  const double a_ratio, VecInt &a_flags, SetInt &a_trisToDelete) const
1183 {
1184  if (a_tri != XM_NONE)
1185  {
1186  a_flags[a_tri] |= a_index;
1187  const int indexPlus1 = trIncrementIndex(a_index);
1188  const int indexPlus2 = trIncrementIndex(indexPlus1);
1189  int t = a_tri * 3;
1190  Pt3d p1((*m_pts)[(*m_tris)[t + a_index]]);
1191  Pt3d p2((*m_pts)[(*m_tris)[t + indexPlus1]]);
1192  Pt3d p3((*m_pts)[(*m_tris)[t + indexPlus2]]);
1193  double l12 = gmXyDistance(p1, p2);
1194  double l23 = gmXyDistance(p2, p3);
1195  double l31 = gmXyDistance(p3, p1);
1196  double lengthRatio = l12 / (l23 + l31);
1197  if (lengthRatio >= a_ratio)
1198  {
1199  a_trisToDelete.insert(a_tri);
1200  // check the two adjacent triangles
1201  int adjTri = AdjacentTriangle(a_tri, indexPlus1);
1202  if (adjTri != XM_NONE && !(a_flags[adjTri] & AdjacentTriangleIndex(a_tri, adjTri)))
1203  CheckTriangle(adjTri, AdjacentTriangleIndex(a_tri, adjTri), a_ratio,
1204  a_flags, a_trisToDelete);
1205  adjTri = AdjacentTriangle(a_tri, indexPlus2);
1206  if (adjTri != XM_NONE && !(a_flags[adjTri] & AdjacentTriangleIndex(a_tri, adjTri)))
1207  CheckTriangle(adjTri, AdjacentTriangleIndex(a_tri, adjTri), a_ratio,
1208  a_flags, a_trisToDelete);
1209  }
1210  }
1211 } // TrTinImpl::CheckTriangle
1212 //------------------------------------------------------------------------------
1218 //------------------------------------------------------------------------------
1220 {
1221  // set flags so that a triangle does not get checked more than once
1222  int nTri = NumTriangles();
1223  VecInt flags(nTri, 4);
1224  SetInt trisToDelete;
1225  for (int tri = 0; tri < nTri; ++tri)
1226  {
1227  int i = 0;
1228  while (i <= 2)
1229  {
1230  if (AdjacentTriangle(tri, i) == XM_NONE)
1231  {
1232  // No adjacent triangle on edge i. currtriangle is on outside edge
1233  CheckTriangle(tri, i, a_ratio, flags, trisToDelete);
1234  // Don't stop. Must check all edges as 2 may be on boundary and
1235  // the first one might not have met the criteria but the 2nd might.
1236  }
1237  ++i;
1238  }
1239  }
1240  DeleteTriangles(trisToDelete);
1241  return true;
1242 } // TrTinImpl::RemoveLongThinTrianglesOnPerimeter
1243 //------------------------------------------------------------------------------
1245 //------------------------------------------------------------------------------
1247 {
1248  if (m_pts)
1249  m_pts->clear();
1250  if (m_tris)
1251  m_tris->clear();
1252  if (m_trisAdjToPts)
1253  m_trisAdjToPts->clear();
1254 } // TrTinImpl::Clear
1255 //------------------------------------------------------------------------------
1257 //------------------------------------------------------------------------------
1259 {
1260  BuildTrisAdjToPtsConst(); // code moved to const version
1261 } // TrTinImpl::BuildTrisAdjToPts
1262 //------------------------------------------------------------------------------
1265 //------------------------------------------------------------------------------
1266 std::string TrTinImpl::ToString() const
1267 {
1268  std::stringstream ss;
1269  {
1270  boost::archive::text_oarchive oa(ss);
1271  oa << *this;
1272  }
1273  return ss.str();
1274 } // TrTinImpl::ToString
1275 //------------------------------------------------------------------------------
1278 //------------------------------------------------------------------------------
1279 void TrTinImpl::FromString(const std::string& a_text)
1280 {
1281  std::stringstream ss(a_text);
1282  {
1283  boost::archive::text_iarchive ia(ss);
1284  ia >> *this;
1285  }
1286 } // TrTinImpl::FromString
1287 //------------------------------------------------------------------------------
1291 //------------------------------------------------------------------------------
1292 template <typename Archive>
1293 void TrTinImpl::serialize(Archive& archive, const unsigned int version)
1294 {
1295  (void)version; // Because Doxygen complained when commented out above.
1296  archive& boost::serialization::base_object<TrTin>(*this); // does nothing
1297 
1298  VecPt3d& p(*m_pts);
1299  VecInt& t(*m_tris);
1300  VecInt2d& t2(*m_trisAdjToPts);
1301 
1302  archive& p;
1303  archive& t;
1304  archive& t2;
1305 } // TrTinImpl::serialize
1306 //------------------------------------------------------------------------------
1309 //------------------------------------------------------------------------------
1311 {
1312  // You would think m_trisAdjToPts would need to be mutable, but it doesn't
1313  VecInt2d& trisAdjToPts = *m_trisAdjToPts;
1314  const VecInt& tris = *m_tris;
1315  trisAdjToPts.assign(m_pts->size(), VecInt());
1316  size_t numTri = tris.size() / 3;
1317  int t = 0;
1318  for (size_t tri = 0; tri < numTri; ++tri)
1319  {
1320  trisAdjToPts[tris[t++]].push_back((int)tri);
1321  trisAdjToPts[tris[t++]].push_back((int)tri);
1322  trisAdjToPts[tris[t++]].push_back((int)tri);
1323  }
1324  stShrinkCapacity(trisAdjToPts);
1325 } // TrTinImpl::BuildTrisAdjToPtsConst
1326 
1331 //------------------------------------------------------------------------------
1333 //------------------------------------------------------------------------------
1335 {
1336 }
1337 //------------------------------------------------------------------------------
1339 //------------------------------------------------------------------------------
1341 {
1342 }
1343 //------------------------------------------------------------------------------
1346 //------------------------------------------------------------------------------
1347 BSHP<TrTin> TrTin::New()
1348 {
1349  return BDPC<TrTin>(BSHP<TrTinImpl>(new TrTinImpl()));
1350 } // TrTin::TrTin
1351 //------------------------------------------------------------------------------
1353 //------------------------------------------------------------------------------
1354 // template<typename Archive>
1355 // void TrTin::serialize(Archive& archive, const unsigned int version)
1356 //{
1357 // TrTinImpl *t = dynamic_cast<TrTinImp*>(this);
1358 // if (t)
1359 // {
1360 // t->serialize(archive, version);
1361 // }
1362 //} // TrTinImpl::serialize
1363 
1364 //----- Global functions -------------------------------------------------------
1365 
1366 //------------------------------------------------------------------------------
1375 //------------------------------------------------------------------------------
1376 void trRenumberOnDelete(const SetInt& a_deleting, VecInt& a_vec)
1377 {
1378  for (SetInt::reverse_iterator itDeleting = a_deleting.rbegin(); itDeleting != a_deleting.rend();
1379  ++itDeleting)
1380  {
1381  int pt = *itDeleting;
1382  for (VecInt::iterator itTriPt = a_vec.begin(); itTriPt != a_vec.end(); ++itTriPt)
1383  {
1384  if (*itTriPt >= pt)
1385  {
1386  --(*itTriPt);
1387  }
1388  }
1389  }
1390 } // trRenumberOnDelete
1391 
1392 } // namespace xms
1393 
1394 #if CXX_TEST
1395 // UNIT TESTS
1398 
1400 
1401 #include <xmscore/testing/TestTools.h>
1402 #include <xmscore/misc/carray.h>
1404 
1405 //----- Namespace declaration --------------------------------------------------
1406 
1407 // namespace xms {
1408 using namespace xms;
1409 
1410 namespace
1411 {
1412 //------------------------------------------------------------------------------
1414 //------------------------------------------------------------------------------
1415 static VecPt3d iArrayToVecPt3d(double* a_array, int a_size)
1416 {
1417  VecPt3d v(a_size / 2);
1418  for (int i = 0; i < a_size; i += 2)
1419  {
1420  v[i / 2].x = a_array[i];
1421  v[i / 2].y = a_array[i + 1];
1422  }
1423  return v;
1424 } // iArrayToVecPt3d
1425 
1426 } // namespace unnamed
1427 
1428 //------------------------------------------------------------------------------
1450 //------------------------------------------------------------------------------
1451 BSHP<TrTin> trBuildTestTin()
1452 {
1453  BSHP<TrTin> tin = TrTin::New();
1454 
1455  tin->Points() = {{5, 0, 0}, {10, 0, 0}, {0, 5, 0}, {5, 5, 0}, {10, 5, 0},
1456  {15, 5, 0}, {0, 10, 0}, {5, 10, 0}, {10, 10, 0}, {5, 15, 0}};
1457  tin->Triangles() = {0, 3, 2, 0, 1, 3, 1, 4, 3, 1, 5, 4, 2, 3, 6,
1458  3, 7, 6, 4, 8, 7, 4, 5, 8, 6, 7, 9, 7, 8, 9};
1459  tin->BuildTrisAdjToPts();
1460  return tin;
1461 } // trBuildTestTin
1462 //------------------------------------------------------------------------------
1486 //------------------------------------------------------------------------------
1487 BSHP<TrTin> trBuildTestTin2()
1488 {
1489  BSHP<TrTin> tin = TrTin::New();
1490 
1491  tin->Points() = {{0, 0, 0}, {5, 0, 0}, {10, 0, 0}, {2.5, 2.5, 0},
1492  {0, 5, 0}, {5, 5, 0}, {0, 10, 0}};
1493  int tris[] = {0, 1, 3, 1, 2, 5, 0, 3, 4, 1, 5, 3, 4, 3, 5, 4, 5, 6};
1494  tin->Triangles().assign(&tris[0], &tris[XM_COUNTOF(tris)]);
1495  tin->BuildTrisAdjToPts();
1496  return tin;
1497 } // trBuildTestTin2
1498 //------------------------------------------------------------------------------
1520 //------------------------------------------------------------------------------
1521 BSHP<TrTin> trBuildTestTin6()
1522 {
1523  BSHP<TrTin> tin = TrTin::New();
1524  const double kYMax = 40;
1525  const double kXMax = 80;
1526  for (int y = 0; y <= kYMax; y += 10)
1527  {
1528  for (int x = 0; x <= kXMax; x += 10)
1529  {
1530  tin->Points().push_back(Pt3d(x, y, 0.0));
1531  }
1532  }
1533 
1534  TrTriangulatorPoints triangulator(tin->Points(), tin->Triangles(), &tin->TrisAdjToPts());
1535  triangulator.Triangulate();
1536  return tin;
1537 } // trBuildTestTin6
1538 //------------------------------------------------------------------------------
1542 // 10- 17-----18------19------20------21
1543 // | |\ 8 /|\ 11 /|\ 22 / \ 26 /|
1544 // | | \ / | \ / | \ / \ //|
1545 // | | \ / | \ /30|23\ / 27 \ / /|
1546 // 5- |6 13 12|9 14 | 15------16 /|
1547 // | | / \ | /|\ | / \ 25 /|28/|
1548 // | | / \ | / | \ | / \ / | / |
1549 // | |/ 7 \|/ | \|/ 24 \ /29| / |
1550 // 0- 9------10 10|3 11------12 | / |
1551 // | |\ 13 / \ | / \ 15 / \ |/ |
1552 // | | \ / \ | / \ / \ |/ |
1553 // | | \ / 5 \|/ 16 \ / 21 \|/ |
1554 // -5- | 0 5-------6-------7-------8 18|
1555 // | | / \ 4 / \ 14 / \ 19 / \ |
1556 // | | / \ / \ / \ / \ |
1557 // | |/ 1 \ / 2 \ / 20 \ / 17 \|
1558 // -10- 0-------1-------2-------3-------4
1559 //
1560 // |-------|-------|-------|-------|
1561 // 0 10 20 30 40
1564 //------------------------------------------------------------------------------
1565 BSHP<TrTin> trBuildTestTin7()
1566 {
1567  double meshPtsA[] = {0, -10, 10, -10, 20, -10, 30, -10, 40, -10, 5, -5, 15, -5, 25,
1568  -5, 35, -5, 0, 0, 10, 0, 20, 0, 30, 0, 5, 5, 15, 5,
1569  25, 5, 35, 5, 0, 10, 10, 10, 20, 10, 30, 10, 40, 10};
1570  BSHP<TrTin> tin = TrTin::New();
1571  tin->Points() = iArrayToVecPt3d(meshPtsA, XM_COUNTOF(meshPtsA));
1572  TrTriangulatorPoints triangulator(tin->Points(), tin->Triangles(), &tin->TrisAdjToPts());
1573  triangulator.Triangulate();
1574  return tin;
1575 } // trBuildTestTin7
1576 //------------------------------------------------------------------------------
1598 //------------------------------------------------------------------------------
1599 BSHP<TrTin> trBuildTestTin8()
1600 {
1601  BSHP<TrTin> tin = TrTin::New();
1602 
1603  tin->Points() = {{5, 0, 0}, {10, 0, 0}, {0, 5, 0}, {5, 5, 0}, {10, 5, 0}, {15, 5, 0},
1604  {0, 10, 0}, {5, 10, 0}, {10, 10, 0}, {5, 15, 0}, {10, 15, 0}, {15, 15, 0}};
1605  tin->Triangles() = {0, 3, 2, 0, 1, 3, 1, 4, 3, 1, 5, 4, 2, 3, 6, 3, 7, 6,
1606  4, 8, 7, 4, 5, 8, 6, 7, 9, 7, 8, 9, 8, 10, 9, 8, 11, 10};
1607  tin->BuildTrisAdjToPts();
1608  return tin;
1609 } // trBuildTestTin8
1610 //------------------------------------------------------------------------------
1634 //------------------------------------------------------------------------------
1635 BSHP<TrTin> trBuildTestTin9()
1636 {
1637  BSHP<TrTin> tin = TrTin::New();
1638 
1639  tin->Points() = {{0, 0, 0}, {5, 0, 0}, {10, 0, 0}, {2.5, 2.5, 0},
1640  {0, 5, 0}, {5, 5, 0}, {6, 5, 0}, {0, 10, 0}};
1641  int tris[] = {0, 1, 3, 1, 2, 5, 0, 3, 4, 1, 5, 3, 4, 3, 5, 5, 2, 6, 4, 5, 7, 5, 6, 7};
1642  tin->Triangles().assign(&tris[0], &tris[XM_COUNTOF(tris)]);
1643  tin->BuildTrisAdjToPts();
1644  return tin;
1645 } // trBuildTestTin9
1646 
1651 //------------------------------------------------------------------------------
1654 
1655 // 10- 3-----------4
1656 // | /0\2 1/2\
1657 // | / \ 2 / \
1658 // | / \ / \
1659 // | / 0 \ / 1 \
1660 // | /1 2\0/0 1\
1661 // 0- 0-----------1-----------2
1662 //
1663 // |-----|-----|-----|-----|
1664 // 0 5 10 15 20
1665 //
1666 // m_tris = 3,0,1, 1,2,4, 1,4,3
1667 // m_trisAdjToPts = [0][0,1,2][1][0,2][1,2]
1668 
1670 //------------------------------------------------------------------------------
1672 {
1673  // Create memory
1674  BSHP<VecPt3d> pts(new VecPt3d());
1675  BSHP<VecInt> tris(new VecInt());
1676  BSHP<VecInt2d> trisAdjToPts(new VecInt2d());
1677 
1678  // Set up to our example tin
1679  *pts = {{0, 0, 0}, {10, 0, 0}, {20, 0, 0}, {5, 10, 0}, {15, 10, 0}};
1680  *tris = {3, 0, 1, 1, 2, 4, 1, 4, 3};
1681  *trisAdjToPts = {{0}, {0, 1, 2}, {1}, {0, 2}, {1, 2}};
1682 
1683  BSHP<TrTin> tin = TrTin::New();
1684  tin->SetGeometry(pts, tris, trisAdjToPts);
1685 
1686  // TriangleFromEdge
1687 
1688  int tri;
1689  int idx1, idx2;
1690  bool rv;
1691  rv = tin->TriangleFromEdge(1, 3, tri, idx1, idx2);
1692  TS_ASSERT_EQUALS(rv, true);
1693  TS_ASSERT_EQUALS(tri, 0);
1694  TS_ASSERT_EQUALS(idx1, 2);
1695  TS_ASSERT_EQUALS(idx2, 0);
1696  rv = tin->TriangleFromEdge(3, 1, tri, idx1, idx2);
1697  TS_ASSERT_EQUALS(rv, true);
1698  TS_ASSERT_EQUALS(tri, 2);
1699  TS_ASSERT_EQUALS(idx1, 2);
1700  TS_ASSERT_EQUALS(idx2, 0);
1701  rv = tin->TriangleFromEdge(1, 0, tri, idx1, idx2);
1702  TS_ASSERT_EQUALS(rv, false);
1703 
1704  // TriangleAdjacentToEdge
1705 
1706  tri = tin->TriangleAdjacentToEdge(1, 3);
1707  TS_ASSERT_EQUALS(tri, 2);
1708  tri = tin->TriangleAdjacentToEdge(3, 1);
1709  TS_ASSERT_EQUALS(tri, 0);
1710  tri = tin->TriangleAdjacentToEdge(1, 0);
1711  TS_ASSERT_EQUALS(tri, 0);
1712 
1713  // LocalIndex
1714 
1715  TS_ASSERT_EQUALS(tin->LocalIndex(0, 0), 1);
1716  TS_ASSERT_EQUALS(tin->LocalIndex(0, 1), 2);
1717  TS_ASSERT_EQUALS(tin->LocalIndex(0, 3), 0);
1718  TS_ASSERT_EQUALS(tin->LocalIndex(0, 4), XM_NONE);
1719 
1720  // GlobalIndex
1721 
1722  TS_ASSERT_EQUALS(tin->GlobalIndex(0, 0), 3);
1723  TS_ASSERT_EQUALS(tin->GlobalIndex(0, 1), 0);
1724  TS_ASSERT_EQUALS(tin->GlobalIndex(0, 2), 1);
1725  TS_ASSERT_EQUALS(tin->GlobalIndex(1, 0), 1);
1726  TS_ASSERT_EQUALS(tin->GlobalIndex(1, 1), 2);
1727  TS_ASSERT_EQUALS(tin->GlobalIndex(1, 2), 4);
1728  TS_ASSERT_EQUALS(tin->GlobalIndex(2, 0), 1);
1729  TS_ASSERT_EQUALS(tin->GlobalIndex(2, 1), 4);
1730  TS_ASSERT_EQUALS(tin->GlobalIndex(2, 2), 3);
1731  bool asserting = xmAsserting();
1732  xmAsserting() = false;
1733  TS_ASSERT_EQUALS(tin->GlobalIndex(3, 2), XM_NONE);
1734  TS_ASSERT_EQUALS(tin->GlobalIndex(2, 3), XM_NONE);
1735  xmAsserting() = asserting;
1736 
1737  // VerticesAreAdjacent
1738 
1739  TS_ASSERT_EQUALS(tin->VerticesAreAdjacent(0, 1), true);
1740  TS_ASSERT_EQUALS(tin->VerticesAreAdjacent(1, 0), true);
1741  TS_ASSERT_EQUALS(tin->VerticesAreAdjacent(0, 2), false);
1742 
1743  // CommonEdgeIndex
1744 
1745  TS_ASSERT_EQUALS(tin->CommonEdgeIndex(0, 2), 2);
1746  TS_ASSERT_EQUALS(tin->CommonEdgeIndex(2, 0), 2);
1747  TS_ASSERT_EQUALS(tin->CommonEdgeIndex(1, 2), 2);
1748  TS_ASSERT_EQUALS(tin->CommonEdgeIndex(2, 1), 0);
1749  TS_ASSERT_EQUALS(tin->CommonEdgeIndex(0, 1), XM_NONE);
1750 
1751  // AdjacentTriangle
1752 
1753  TS_ASSERT_EQUALS(tin->AdjacentTriangle(0, 0), XM_NONE);
1754  TS_ASSERT_EQUALS(tin->AdjacentTriangle(0, 1), XM_NONE);
1755  TS_ASSERT_EQUALS(tin->AdjacentTriangle(0, 2), 2);
1756  TS_ASSERT_EQUALS(tin->AdjacentTriangle(1, 0), XM_NONE);
1757  TS_ASSERT_EQUALS(tin->AdjacentTriangle(1, 1), XM_NONE);
1758  TS_ASSERT_EQUALS(tin->AdjacentTriangle(1, 2), 2);
1759  TS_ASSERT_EQUALS(tin->AdjacentTriangle(2, 0), 1);
1760  TS_ASSERT_EQUALS(tin->AdjacentTriangle(2, 1), XM_NONE);
1761  TS_ASSERT_EQUALS(tin->AdjacentTriangle(2, 2), 0);
1762 
1763  // TriangleCentroid
1764 
1765  const double kDelta = 1e-5;
1766  TS_ASSERT_DELTA_PT3D(tin->TriangleCentroid(0), Pt3d(5, 3.333333333, 0), kDelta);
1767  TS_ASSERT_DELTA_PT3D(tin->TriangleCentroid(1), Pt3d(15, 3.333333333, 0), kDelta);
1768  TS_ASSERT_DELTA_PT3D(tin->TriangleCentroid(2), Pt3d(10, 6.66666667, 0), kDelta);
1769 
1770  // TriangleArea
1771 
1772  TS_ASSERT_DELTA(tin->TriangleArea(0), 50.0, kDelta);
1773  TS_ASSERT_DELTA(tin->TriangleArea(1), 50.0, kDelta);
1774  TS_ASSERT_DELTA(tin->TriangleArea(2), 50.0, kDelta);
1775 
1776  // NextBoundaryPoint
1777 
1778  TS_ASSERT_EQUALS(tin->NextBoundaryPoint(0), 3);
1779  TS_ASSERT_EQUALS(tin->NextBoundaryPoint(3), 4);
1780  TS_ASSERT_EQUALS(tin->NextBoundaryPoint(4), 2);
1781  TS_ASSERT_EQUALS(tin->NextBoundaryPoint(2), 1);
1782  TS_ASSERT_EQUALS(tin->NextBoundaryPoint(1), 0);
1783 
1784  // PreviousBoundaryPoint
1785 
1786  TS_ASSERT_EQUALS(tin->PreviousBoundaryPoint(0), 1);
1787  TS_ASSERT_EQUALS(tin->PreviousBoundaryPoint(1), 2);
1788  TS_ASSERT_EQUALS(tin->PreviousBoundaryPoint(2), 4);
1789  TS_ASSERT_EQUALS(tin->PreviousBoundaryPoint(4), 3);
1790  TS_ASSERT_EQUALS(tin->PreviousBoundaryPoint(3), 0);
1791 
1792  // GetBoundaryPoints is tested elsewhere
1793  // GetBoundaryPolys is tested elsewhere
1794 
1795  // GetExtents
1796 
1797  Pt3d mn, mx;
1798  TS_ASSERT_EQUALS(tin->GetExtents(mn, mx), true);
1799  TS_ASSERT_DELTA_PT3D(mn, Pt3d(0, 0, 0), kDelta);
1800  TS_ASSERT_DELTA_PT3D(mx, Pt3d(20, 10, 0), kDelta);
1801 
1802  // Below here we've modified the tin -----------------------------------------
1803 
1804  // SwapEdge
1805 
1806  rv = tin->SwapEdge(0, 2);
1807  TS_ASSERT_EQUALS(rv, true);
1808  TS_ASSERT_EQUALS(tin->Triangles()[0], 3);
1809  TS_ASSERT_EQUALS(tin->Triangles()[1], 0);
1810  TS_ASSERT_EQUALS(tin->Triangles()[2], 4);
1811  TS_ASSERT_EQUALS(tin->Triangles()[3], 1);
1812  TS_ASSERT_EQUALS(tin->Triangles()[4], 2);
1813  TS_ASSERT_EQUALS(tin->Triangles()[5], 4);
1814  TS_ASSERT_EQUALS(tin->Triangles()[6], 1);
1815  TS_ASSERT_EQUALS(tin->Triangles()[7], 4);
1816  TS_ASSERT_EQUALS(tin->Triangles()[8], 0);
1817  const VecInt2d& trisAdjToPtsRef = tin->TrisAdjToPts();
1818  TS_ASSERT_EQUALS((VecInt{0, 2}), trisAdjToPtsRef[0]);
1819  TS_ASSERT_EQUALS((VecInt{1, 2}), trisAdjToPtsRef[1]);
1820  TS_ASSERT_EQUALS((VecInt{1}), trisAdjToPtsRef[2]);
1821  TS_ASSERT_EQUALS((VecInt{0}), trisAdjToPtsRef[3]);
1822  TS_ASSERT_EQUALS((VecInt{1, 2, 0}), trisAdjToPtsRef[4]);
1823 
1824  // DeleteTriangles is tested elsewhere
1825  // DeletePoints is tested elsewhere
1826  // OptimizeTriangulation is tested elsewhere
1827  // Clear is tested below
1828 
1829  // BuildTrisAdjToPts
1830 
1831  tin->TrisAdjToPts().clear();
1832  tin->BuildTrisAdjToPts();
1833  TS_ASSERT_EQUALS(*trisAdjToPts, tin->TrisAdjToPts());
1834 
1835  // Clear
1836 
1837  tin->Clear();
1838  TS_ASSERT_EQUALS(tin->Points().empty(), true);
1839  TS_ASSERT_EQUALS(tin->Triangles().empty(), true);
1840  TS_ASSERT_EQUALS(tin->TrisAdjToPts().empty(), true);
1841 
1842 } // TrTinUnitTests::test1
1843 //------------------------------------------------------------------------------
1846 // Before
1847 //
1848 // 20- 6------7------8
1849 // | |\ |\ |
1850 // | |\\ 3 |\\ 7 |
1851 // | |\ \ |\ \ |
1852 // | | \ \ | \ \ |
1853 // | | \ \ | \ \ |
1854 // | | \ \| \ \|
1855 // 10- 3 1 \2 4 5 \6 5
1856 // | |\ \ |\ \ |
1857 // | | \ \ | \ \ |
1858 // | | \ \ | \ \ |
1859 // | | \ \| \ \|
1860 // | | 0 \\| 4 \\|
1861 // | | \| \|0
1862 // 0 - 0------1------2
1863 //
1864 // |------|------|
1865 // 0 10 20
1866 
1867 // After
1868 // 20- 6------7------8
1869 // | |\ |\ |
1870 // | | \ 3 | \ 7 |
1871 // | | \ | \ |
1872 // | | \ | \ |
1873 // | | 2 \ | 6 \ |
1874 // | | \| \|
1875 // 10- 3------4------5
1876 // | |\ |\ |
1877 // | | \ 1 | \ 5 |
1878 // | | \ | \ |
1879 // | | \ | \ |
1880 // | | 0 \ | 4 \ |
1881 // | | \| \|
1882 // 0 - 0------1------2
1883 //
1884 // |------|------|
1885 // 0 10 20
1887 //------------------------------------------------------------------------------
1889 {
1890  // Create memory
1891  BSHP<VecPt3d> pts(new VecPt3d());
1892  BSHP<VecInt> tris(new VecInt());
1893  BSHP<VecInt2d> trisAdjToPts(new VecInt2d());
1894 
1895  // Set up to our example tin
1896  *pts = {{0, 0, 0}, {10, 0, 0}, {20, 0, 0}, {0, 10, 0}, {10, 10, 0},
1897  {20, 10, 0}, {0, 20, 0}, {10, 20, 0}, {20, 20, 0}};
1898  *tris = {0, 1, 3, 1, 6, 3, 1, 4, 6, 4, 7, 6, 1, 2, 4, 2, 7, 4, 2, 5, 7, 5, 8, 7};
1899  *trisAdjToPts = {{0}, {0, 1, 2, 4}, {4, 5, 6}, {0, 1}, {2, 4, 5, 3},
1900  {6, 7}, {1, 2, 3}, {3, 5, 6, 7}, {7}};
1901 
1902  BSHP<TrTin> tin = TrTin::New();
1903  tin->SetGeometry(pts, tris, trisAdjToPts);
1904 
1905  // Test GetBoundaryPoints
1906  VecInt boundaryPoints;
1907  tin->GetBoundaryPoints(boundaryPoints);
1908  TS_ASSERT_EQUALS((VecInt{0, 1, 2, 3, 5, 6, 7, 8}), boundaryPoints);
1909 
1910  // Optimize
1911  TS_ASSERT(tin->OptimizeTriangulation());
1912  VecInt trisAfter = {0, 1, 3, 1, 6, 3, 1, 4, 6, 4, 7, 6, 1, 2, 4, 2, 7, 4, 2, 5, 7, 5, 8, 7};
1913  TS_ASSERT_EQUALS_VEC(trisAfter, tin->Triangles());
1914 
1915  // Test GetBoundaryPoints
1916  tin->GetBoundaryPoints(boundaryPoints);
1917  TS_ASSERT_EQUALS((VecInt{0, 1, 2, 3, 5, 6, 7, 8}), boundaryPoints);
1918 
1919 } // TrTinUnitTests::testOptimizeTriangulation
1920 //------------------------------------------------------------------------------
1923 // 20- 5-----------6-----------7 20- 5-----------6-----------7
1924 // | |\ / \ /| | |\ /|\ /|
1925 // | | \ 1 / \ 6 / | | | \ 1 / | \ 6 / |
1926 // | | \ / \ / | | | \ / | \ / |
1927 // | | \ / 7 \ / | | | \ / | \ / |
1928 // | | \ / \ / | | | \ / | \ / |
1929 // 10- | 2 3-----------4 4 | 10- | 2 3 3 | 7 4 4 |
1930 // | | / \ / \ | | | / \ | / \ |
1931 // | | / \ 3 / \ | | | / \ | / \ |
1932 // | | / \ / \ | | | / \ | / \ |
1933 // | | / 0 \ / 5 \ | | | / 0 \ | / 5 \ |
1934 // | |/ \ / \| | |/ \|/ \|
1935 // 0- 0-----------1-----------2 0- 0-----------1-----------2
1936 //
1937 // |-----|-----|-----|-----| |-----|-----|-----|-----|
1938 // 0 5 10 15 20 0 5 10 15 20
1940 //------------------------------------------------------------------------------
1942 {
1943  // Create tin and get some convenience variables
1944  BSHP<TrTin> tin = TrTin::New();
1945  VecInt& tris = tin->Triangles();
1946  VecInt2d& trisAdjToPts = tin->TrisAdjToPts();
1947 
1948  // Set up to our example tin points
1949  tin->Points() = {{0, 0, 0}, {10, 0, 0}, {20, 0, 0}, {5, 10, 0},
1950  {15, 10, 0}, {0, 20, 0}, {10, 20, 0}, {20, 20, 0}};
1951 
1952  // Triangulate the points
1953  TrTriangulatorPoints client(tin->Points(), tin->Triangles(), &trisAdjToPts);
1954  client.Triangulate();
1955 
1956  // See that things are as expected before the swap
1957  int trisB[] = {0, 1, 3, 5, 3, 6, 3, 5, 0, 1, 4, 3, 4, 2, 7, 2, 4, 1, 7, 6, 4, 4, 6, 3};
1958  VecInt trisBefore(&trisB[0], &trisB[24]);
1959  TS_ASSERT_EQUALS(trisBefore, tris);
1960 
1961  VecInt2d trisAdjToPtsBefore = {{0, 2}, {0, 3, 5}, {4, 5}, {0, 1, 2, 3, 7},
1962  {3, 4, 5, 6, 7}, {1, 2}, {1, 6, 7}, {4, 6}};
1963 
1964  TS_ASSERT_EQUALS(trisAdjToPtsBefore, trisAdjToPts);
1965 
1966  // Swap
1967  bool rv = tin->SwapEdge(3, 7);
1968  TS_ASSERT_EQUALS(rv, true);
1969 
1970  // See that things are as expected after the swap
1971  int trisA[] = {0, 1, 3, 5, 3, 6, 3, 5, 0, 1, 6, 3, 4, 2, 7, 2, 4, 1, 7, 6, 4, 4, 6, 1};
1972  VecInt trisAfter(&trisA[0], &trisA[24]);
1973  TS_ASSERT_EQUALS(trisAfter, tris);
1974 
1975  VecInt2d trisAdjToPtsAfter = {{0, 2}, {0, 3, 5, 7}, {4, 5}, {0, 1, 2, 3},
1976  {4, 5, 6, 7}, {1, 2}, {1, 6, 7, 3}, {4, 6}};
1977  TS_ASSERT_EQUALS(trisAdjToPtsAfter, trisAdjToPts);
1978 
1979  // Test GetBoundaryPoints
1980  VecInt boundaryPoints;
1981  tin->GetBoundaryPoints(boundaryPoints);
1982  TS_ASSERT_EQUALS((VecInt{0, 1, 2, 5, 6, 7}), boundaryPoints);
1983 
1984 } // TrTinUnitTests::testSwap
1985 #if 0 // FirstBoundaryPoint has been commented out because it wasn't used
1986 //------------------------------------------------------------------------------
1988 //------------------------------------------------------------------------------
1989 void TrTinTests::testFirstBoundaryPoint ()
1990 {
1991 
1992 
1993  // Example 1
1994  {
1995  BSHP<TrTin> tin = trBuildTestTin();
1996  TS_ASSERT_EQUALS(tin->FirstBoundaryPoint(), 0);
1997  }
1998 
1999  // Example 2
2000 // 20- 5-----------6-----------7
2001 // | |\ / \ /|
2002 // | | \ 1 / \ 6 / |
2003 // | | \ / \ / |
2004 // | | \ / 7 \ / |
2005 // | | \ / \ / |
2006 // 10- | 2 0-----------1 4 |
2007 // | | / \ / \ |
2008 // | | / \ 3 / \ |
2009 // | | / \ / \ |
2010 // | | / 0 \ / 5 \ |
2011 // | |/ \ / \|
2012 // 0- 2-----------3-----------4
2013 //
2014 // |-----|-----|-----|-----|
2015 // 0 5 10 15 20
2016 
2017  {
2018  BSHP<TrTin> tin = TrTin::New();
2019  tin->Points() = {{5,10,0},{15,10,0},{0,0,0},{10,0,0},
2020  {20,0,0},{0,20,0},{10,20,0},{20,20,0}};
2021  TrTriangulatorPoints client(tin->Points(), tin->Triangles(),
2022  &tin->TrisAdjToPts());
2023  client.Triangulate();
2024  TS_ASSERT_EQUALS(tin->FirstBoundaryPoint(), 2);
2025  }
2026 
2027 } // TrTinTests::testFirstBoundaryPoint
2028 #endif
2029 //------------------------------------------------------------------------------
2032 
2033 // 40 34-35--36--37--38--39--40--41--42
2034 // |\15|\23|\19|\44|41/|42/|\51|\49|
2035 // |16\|17\|20\|21\|/37|/40|43\|50\|
2036 // 30 25-26--27--28--29--30--31--32--33
2037 // |\13| \18|\52|38/|39/ \48|\47|
2038 // |14\| \|22\|/29|/ \|45\|
2039 // 20 18-19 20--21--22 23--24
2040 // |\ 3| /|\24|\26|\ |46/|
2041 // |1 \| / 9|12\|27\|28\ |/36|
2042 // 10 9--10--11--12--13--14--15--16--17
2043 // |2 /|\11|7 /|8 /|\31|\30|\32|35/|
2044 // |/ 0|4 \|/ 5|/ 6|10\|25\|33\|/34|
2045 // 0 0---1---2---3---4---5---6---7---8
2046 // 0 10 20 30 40 50 60 70 80
2047 
2049 //------------------------------------------------------------------------------
2051 {
2052  BSHP<TrTin> tin = trBuildTestTin6();
2053  SetInt toDelete = {20, 24};
2054  tin->DeletePoints(toDelete);
2055  VecInt2d boundaries;
2056 
2057  // GetBoundaryPoints
2058 
2059  VecInt pts;
2060  tin->GetBoundaryPoints(pts);
2061  int ptsA[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20,
2062  22, 23, 24, 25, 26, 27, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42};
2063  VecInt expectedPts(&ptsA[0], &ptsA[XM_COUNTOF(ptsA)]);
2064  TS_ASSERT_EQUALS(expectedPts, pts);
2065 
2066  // GetBoundaryPolys
2067 
2068  tin->GetBoundaryPolys(boundaries);
2069 
2070  VecInt2d expected = {
2071  {0, 9, 18, 25, 34, 35, 36, 37, 38, 39, 40, 41, 42, 33, 24, 17, 8, 7, 6, 5, 4, 3, 2, 1, 0},
2072  {10, 11, 20, 27, 26, 19, 10},
2073  {15, 16, 23, 31, 22, 15}};
2074  TS_ASSERT_EQUALS_VEC2D(expected, boundaries);
2075 } // TrTinUnitTests::testBoundaries
2076 //------------------------------------------------------------------------------
2078 //------------------------------------------------------------------------------
2080 {
2081  BSHP<TrTin> tin = trBuildTestTin6();
2082  TS_ASSERT_EQUALS(tin->NumTriangles(), 64);
2083  TS_ASSERT_EQUALS(tin->NumPoints(), 45);
2084 
2085  const VecInt2d& trisAdjToPts = tin->TrisAdjToPts();
2086 
2087  // Verify adjacency
2088  TS_ASSERT_EQUALS((VecInt{7, 19, 20, 21, 23, 29}), trisAdjToPts[20]);
2089  TS_ASSERT_EQUALS((VecInt{0, 1, 2, 3, 4, 7, 12, 29}), trisAdjToPts[10]);
2090  TS_ASSERT_EQUALS((VecInt{7, 8, 10, 12, 21}), trisAdjToPts[11]);
2091  TS_ASSERT_EQUALS((VecInt{10, 13, 20, 21, 22, 27, 30}), trisAdjToPts[21]);
2092  TS_ASSERT_EQUALS((VecInt{18, 20, 22, 23, 25, 28}), trisAdjToPts[29]);
2093  TS_ASSERT_EQUALS((VecInt{14, 16, 17, 18, 19, 23}), trisAdjToPts[28]);
2094  TS_ASSERT_EQUALS((VecInt{3, 14, 15, 19, 29}), trisAdjToPts[19]);
2095 
2096  // Delete the triangles around point 20
2097  SetInt toDelete = {7, 19, 20, 21, 23, 29};
2098  tin->DeleteTriangles(toDelete);
2099 
2100  TS_ASSERT_EQUALS(tin->NumTriangles(), 58); // 64 - 6
2101  TS_ASSERT_EQUALS(tin->NumPoints(), 45);
2102 
2103  // Make sure we renumbered the adjacency array properly
2104  int mx = -1;
2105  for (size_t i = 0; i < trisAdjToPts.size(); ++i)
2106  {
2107  for (size_t j = 0; j < trisAdjToPts[i].size(); ++j)
2108  {
2109  if (trisAdjToPts[i][j] > mx)
2110  mx = trisAdjToPts[i][j];
2111  }
2112  }
2113  TS_ASSERT_EQUALS(mx, 57); // 58 - 1
2114 
2129  // Verify adjacency
2130  TS_ASSERT(tin->TrisAdjToPts()[20].empty());
2131  TS_ASSERT_EQUALS((VecInt{0, 1, 2, 3, 4, 11}), trisAdjToPts[10]);
2132  TS_ASSERT_EQUALS((VecInt{7, 9, 11}), trisAdjToPts[11]);
2133  TS_ASSERT_EQUALS((VecInt{9, 12, 18, 22, 24}), trisAdjToPts[21]);
2134  TS_ASSERT_EQUALS((VecInt{17, 18, 20, 23}), trisAdjToPts[29]);
2135  TS_ASSERT_EQUALS((VecInt{13, 15, 16, 17}), trisAdjToPts[28]);
2136  TS_ASSERT_EQUALS((VecInt{3, 13, 14}), trisAdjToPts[19]);
2137 } // TrTinUnitTests::testDeleteTriangles
2138 //------------------------------------------------------------------------------
2140 //------------------------------------------------------------------------------
2142 {
2143  BSHP<TrTin> tin = trBuildTestTin6();
2144  TS_ASSERT_EQUALS(tin->NumTriangles(), 64);
2145  TS_ASSERT_EQUALS(tin->NumPoints(), 45);
2146 
2147  SetInt toDelete = {20, 24};
2148  tin->DeletePoints(toDelete);
2149 
2150  TS_ASSERT_EQUALS(tin->NumTriangles(), 53);
2151  TS_ASSERT_EQUALS(tin->NumPoints(), 43);
2152 
2167 
2168  // Verify adjacency
2169  const VecInt2d& trisAdjToPts = tin->TrisAdjToPts();
2170 
2171  TS_ASSERT_EQUALS((VecInt{0, 1, 2, 3, 4, 11}), trisAdjToPts[10]);
2172  TS_ASSERT_EQUALS((VecInt{7, 9, 11}), trisAdjToPts[11]);
2173  TS_ASSERT_EQUALS((VecInt{9, 12, 18, 22, 24}), trisAdjToPts[20]);
2174  TS_ASSERT_EQUALS((VecInt{17, 18, 20, 23}), trisAdjToPts[27]);
2175  TS_ASSERT_EQUALS((VecInt{13, 15, 16, 17}), trisAdjToPts[26]);
2176  TS_ASSERT_EQUALS((VecInt{3, 13, 14}), trisAdjToPts[19]);
2177 
2178  TS_ASSERT_EQUALS((VecInt{28, 30, 32, 33}), trisAdjToPts[15]);
2179  TS_ASSERT_EQUALS((VecInt{32, 35, 36, 46}), trisAdjToPts[16]);
2180  TS_ASSERT_EQUALS((VecInt{45, 46, 48}), trisAdjToPts[23]);
2181  TS_ASSERT_EQUALS((VecInt{39, 40, 43, 48}), trisAdjToPts[31]);
2182  TS_ASSERT_EQUALS((VecInt{26, 28, 29, 39}), trisAdjToPts[22]);
2183 } // TrTinUnitTests::testDeletePoints
2184 //------------------------------------------------------------------------------
2186 //------------------------------------------------------------------------------
2188 {
2189  BSHP<TrTin> tin = trBuildTestTin9();
2190  TS_ASSERT_EQUALS(tin->NumTriangles(), 8);
2191  TS_ASSERT_EQUALS(tin->NumPoints(), 8);
2192 
2193  tin->RemoveLongThinTrianglesOnPerimeter(0.75);
2194 
2195  TS_ASSERT_EQUALS(tin->NumTriangles(), 6);
2196  TS_ASSERT_EQUALS(tin->NumPoints(), 8);
2197 } // TrTinUnitTests::testRemoveLongThinTrianglesOnPerimeter
2198 
2199  //} // namespace xms
2200 
2201 #endif // CXX_TEST
int trDecrementIndex(int i)
Faster than a % operation and we do this a lot.
Definition: triangles.h:54
bool CheckAndSwap(int a_triA, int a_triB, bool a_propagate, const VecInt &a_flags)
Swap edges if triangles combine to form convex quad. Compare to trCheckAndSwap.
Definition: TrTin.cpp:517
#define TS_ASSERT_DELTA_PT3D(a, b, delta)
#define XM_LOG(A, B)
virtual int AdjacentTriangle(int a_triIdx, int a_edgeIdx) const override
Returns the triangle adjacent to a_triIdx across a_edgeIdx (0-2). Compare to trAdjacentTriangle. Example: a_edgeIdx 2 returns triangle adjacent to edge c.
Definition: TrTin.cpp:633
void testBoundaries()
Tests TrTin::GetBoundaryPoints and TrTin::GetBoundaryPolys.
Definition: TrTin.cpp:2050
virtual bool TriangleFromEdge(int a_pt1, int a_pt2, int &a_tri, int &a_idx1, int &a_idx2) const override
Finds the triangle with the edge defined by a_pt1 and a_pt2 and the local index of those points...
Definition: TrTin.cpp:302
std::vector< int > VecInt
virtual ~TrTinImpl()
destructor
Definition: TrTin.cpp:173
BSHP< TrTin > trBuildTestTin8()
Builds a simple TIN with a hole in the middle and a concavity.
Definition: TrTin.cpp:1599
virtual ~TrTin()
destructor
Definition: TrTin.cpp:1340
virtual int NextBoundaryPoint(int a_point) const override
Returns the next point CW from point on the boundary. CCW if in an inside hole. Compare to trNextBoun...
Definition: TrTin.cpp:710
double gmXyDistance(double x1, double y1, double x2, double y2)
Compute the 2d distance between 2 points.
Definition: geoms.cpp:832
#define XM_NONE
BOOST_CLASS_EXPORT(xms::TrTinImpl)
Cause boost.
#define XM_ENSURE_TRUE_VOID(...)
std::string STRstd(double a_value, int a_n, int width, int flags)
BSHP< VecPt3d > m_pts
tin points
Definition: TrTin.cpp:138
Functions dealing with triangles.
virtual int LocalIndex(int a_tri, int a_pt) const override
Returns index (0-2) of point within triangle given global index. Compare to trIndex.
Definition: TrTin.cpp:361
void InsertAdjacentTriangle(int a_pt, int a_tri)
Adds a_tri as an adjacent triangle to a_pt and updates m_trisAdjToPts.
Definition: TrTin.cpp:905
virtual std::string ToString() const override
Use boost archive to get the TrTin as text.
Definition: TrTin.cpp:1266
bool TriIndexFound(const int &a_triPt) const
Predicate used in remove_if to get the index of the current item in the vector.
Definition: TrTin.cpp:950
PtInOutOrOn_enum gmPtInCircumcircle(const Pt3d &pt, Pt3d circumcirclePts[3])
Is a given point inside a circumcircle defined by three points?
Definition: geoms.cpp:172
virtual void SetTriangles(BSHP< VecInt > a_tris) override
Sets the tin triangles.
Definition: TrTin.cpp:188
virtual bool GetExtents(Pt3d &a_mn, Pt3d &a_mx) const override
Computes the extents (min, max) of the tin.
Definition: TrTin.cpp:857
bool & xmAsserting()
BSHP< TrTin > trBuildTestTin()
Builds a simple TIN with a hole in the middle.
Definition: TrTin.cpp:1451
#define XM_ENSURE_TRUE_NO_ASSERT(...)
bool AdjacentIndexFound(const VecInt &a_point) const
Predicate used in remove_if to get the index of the current item in the vector.
Definition: TrTin.cpp:980
virtual int GlobalIndex(int a_triIdx, int a_localVtxIdx) const override
Returns index into m_pts of a_localPt which is 0-2.
Definition: TrTin.cpp:935
bool PointIndexFound(const Pt3d &a_point) const
Predicate used in remove_if to get the index of the current item in the vector.
Definition: TrTin.cpp:965
virtual void SetTrianglesAdjacentToPoints(BSHP< VecInt2d > a_trisAdjToPts) override
Sets the adjacency info of triangles adjacent to points.
Definition: TrTin.cpp:196
BSHP< VecInt > m_tris
triangles, 0-based indices to m_pts, grouped by 3s
Definition: TrTin.cpp:139
virtual void Clear() override
Delete the memory.
Definition: TrTin.cpp:1246
double gmAngleBetweenEdges(const Pt3d &p1, const Pt3d &p2, const Pt3d &p3)
Returns the ccw angle (0-2pi) between p2-p1 and p2-p3.
Definition: geoms.cpp:655
virtual void BuildTrisAdjToPts() override
Build array of triangles adjacent to points.
Definition: TrTin.cpp:1258
void testRemoveLongThinTrianglesOnPerimeter()
Tests TrTin::RemoveLongThinTrianglesOnPerimeter.
Definition: TrTin.cpp:2187
BSHP< TrTin > trBuildTestTin6()
Builds a simple TIN for testing.
Definition: TrTin.cpp:1521
std::vector< VecInt > VecInt2d
void testSwap()
Definition: TrTin.cpp:1941
virtual void GetBoundaryPolys(VecInt2d &a_polys) const override
Gets exterior boundary and all interior voids as polygons of 0-based point indices. First point is not repeated as the last point.
Definition: TrTin.cpp:810
Functions dealing with geometry.
static BSHP< TrTin > New()
Create a TrTinImpl object.
Definition: TrTin.cpp:1347
virtual BSHP< VecPt3d > PointsPtr() override
Return the pointer to tin points.
Definition: TrTin.cpp:264
bool Triangulate()
Triangulate the points into a tin.
Class to encapsulate a tin made simply of arrays of points, triangles and adjacency information...
Definition: TrTin.cpp:55
virtual bool RemoveLongThinTrianglesOnPerimeter(const double a_ratio) override
Removes long thin triangles on the boundary of the TIN.
Definition: TrTin.cpp:1219
double trArea(const Pt3d &a_pt1, const Pt3d &a_pt2, const Pt3d &a_pt3)
Return the signed planar area of the triangle (CCW Positive).
Definition: triangles.cpp:46
void DeleteAdjacentTriangle(int a_pt, int a_tri)
Removes a_tri from a_pt&#39;s adjacent triangles. Compare to vrDeleteAdjacentTrianglePtr.
Definition: TrTin.cpp:917
virtual VecInt2d & TrisAdjToPts() override
Returns triangles adjacent to points (0-based).
Definition: TrTin.cpp:232
#define XM_ENSURE_TRUE(...)
virtual int NumPoints() const override
Return the number of points.
Definition: TrTin.cpp:280
virtual void DeleteTriangles(const SetInt &a_trisToDelete) override
Deletes the triangles specified in a_trisToDelete and updates and renumbers triangle adjacency info...
Definition: TrTin.cpp:990
virtual double TriangleArea(int a_tri) const override
Calculate and return the area of a triangle.
Definition: TrTin.cpp:665
#define XM_ENSURE_TRUE_VOID_NO_ASSERT(...)
int AdjacentTriangleIndex(const int a_currTri, const int a_adjTri) const
finds the index of adjacent triangle that points to the current triangle
Definition: TrTin.cpp:1154
std::set< int > SetInt
virtual void FromString(const std::string &) override
Use boost archive to turn the text into a TrTin.
Definition: TrTin.cpp:1279
virtual void GetBoundaryPoints(VecInt &a_boundaryPoints) const override
Gives the 0-based indices of all points on any boundary, in no particular order.
Definition: TrTin.cpp:776
XMS Namespace.
Definition: geoms.cpp:34
void trRenumberOnDelete(const SetInt &a_deleting, VecInt &a_vec)
Boost serialize function.
Definition: TrTin.cpp:1376
void CheckTriangle(const int a_tri, const int a_index, const double a_ratio, VecInt &a_flags, SetInt &a_trisToDelete) const
If triangle is long and thin (index edge is long compared to sum of other two edges) the triangle is ...
Definition: TrTin.cpp:1181
virtual void DeletePoints(const SetInt &a_points) override
Deletes the points and any attached triangles, updates adjacency and renumbers things.
Definition: TrTin.cpp:1060
virtual bool SwapEdge(int a_triA, int a_triB, bool a_checkAngle=true) override
Swap edges if triangles combine to form convex quad. Compare to trSwapEdge.
Definition: TrTin.cpp:419
virtual int PreviousBoundaryPoint(int a_point) const override
Returns the previous point CCW from point on the boundary. CW if in an inside hole. Compare to trPreviousBoundaryVertex (or trNextBoundaryVertex since order here is CW, not CCW).
Definition: TrTin.cpp:745
boost::unordered_set< int > m_toDelete
Used only when deleting stuff.
Definition: TrTin.cpp:141
virtual VecInt & Triangles() override
Return 0-based indices of triangle points (grouped by 3s).
Definition: TrTin.cpp:224
virtual VecPt3d & Points() override
Return the tin points.
Definition: TrTin.cpp:216
#define XM_PI
#define XM_COUNTOF(array)
virtual Pt3d TriangleCentroid(int a_tri) const override
Calculate and return the centroid of a triangle.
Definition: TrTin.cpp:652
BSHP< TrTin > trBuildTestTin7()
Builds a simple TIN for testing.
Definition: TrTin.cpp:1565
void testDeletePoints()
Tests TrTin::DeletePoints.
Definition: TrTin.cpp:2141
TrTinImpl()
constructor
Definition: TrTin.cpp:163
virtual void SetPoints(BSHP< VecPt3d > a_pts) override
Sets the tin points.
Definition: TrTin.cpp:180
void serialize(Archive &archive, const unsigned int version)
Boost serialize function.
Definition: TrTin.cpp:1293
void stShrinkCapacity(std::vector< T > &v)
TrTin()
constructor
Definition: TrTin.cpp:1334
void gmAddToExtents(const Pt3d &a_pt, Pt3d &a_min, Pt3d &a_max)
Compares a_pt to a_min and a_max. If a_pt is less than a_min or greater than a_max, a_min and a_max are updated.
Definition: geoms.cpp:787
virtual int CommonEdgeIndex(int a_tri, int a_adjTri) const override
Return index of common edge between triangle and neighbor. Edge index is 0-2 based on a_tri...
Definition: TrTin.cpp:598
bool gmCounterClockwiseTri(const Pt3d &vtx0, const Pt3d &vtx1, const Pt3d &vtx2)
Returns true if the triangle is wrapped counter clockwise.
Definition: geoms.cpp:564
bool PointIsInCircumcircle(int a_tri1, int a_tri2, int id)
Returns true if a_localPt of a_tri2 is inside a_tri1&#39;s circumcircle.
Definition: TrTin.cpp:582
virtual bool VerticesAreAdjacent(int a_pt1, int a_pt2) const override
Return true if vertices form the edge of a triangle. Compare to vrVerticesAreAdjacent.
Definition: TrTin.cpp:378
BSHP< VecInt2d > m_trisAdjToPts
triangles adjacent to points. 1st dim = size of m_pts
Definition: TrTin.cpp:140
virtual bool OptimizeTriangulation() override
Swaps triangle edges until they are a Delauney triangulation.
Definition: TrTin.cpp:1106
virtual BSHP< VecInt > TrianglesPtr() override
Return the pointer to tin triangles.
Definition: TrTin.cpp:272
BSHP< TrTin > trBuildTestTin2()
Builds a simple TIN for testing.
Definition: TrTin.cpp:1487
void test1()
Tests a bunch of the TrTin methods.
Definition: TrTin.cpp:1671
#define TS_ASSERT_EQUALS_VEC(a, b)
virtual void SetGeometry(BSHP< VecPt3d > a_pts, BSHP< VecInt > a_tris, BSHP< VecInt2d > a_trisAdjToPts) override
Set all the tin geometry at once (points, triangles, adjacency).
Definition: TrTin.cpp:206
void BuildTrisAdjToPtsConst() const
A const function used only internally and needed to modify m_trisAdjToPts which is mutable...
Definition: TrTin.cpp:1310
virtual void ExportTinFile(std::ostream &a_os) const override
Export in the .tin file format. Useful for debugging.
Definition: TrTin.cpp:876
virtual int TriangleAdjacentToEdge(int a_pt1, int a_pt2) const override
Returns the triangle adjacent to the edge defined by a_pt1 and a_pt2. Compare to trTriangleAdjacentTo...
Definition: TrTin.cpp:334
void testOptimizeTriangulation()
Definition: TrTin.cpp:1888
virtual int NumTriangles() const override
Return the number of triangles.
Definition: TrTin.cpp:288
int trIncrementIndex(int i)
Faster than a % operation and we do this a lot.
Definition: triangles.h:44
in
Definition: geoms.h:38
void testDeleteTriangles()
Tests TrTin::DeleteTriangles.
Definition: TrTin.cpp:2079
BSHP< TrTin > trBuildTestTin9()
Builds a TIN with long thin triangles for testing.
Definition: TrTin.cpp:1635
Class to triangulate simple points.
#define TS_ASSERT_EQUALS_VEC2D(expected, actual)
std::vector< Pt3d > VecPt3d