xmsgeom  1.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
TrBreaklineAdder.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
7 //------------------------------------------------------------------------------
8 
9 //----- Included files ---------------------------------------------------------
10 
11 // 1. Precompiled header
12 
13 // 2. My own header
15 
16 // 3. Standard library headers
17 #include <functional>
18 
19 // 4. External library headers
20 
21 // 5. Shared code headers
22 #include <xmscore/stl/set.h>
23 #include <xmscore/stl/vector.h>
24 #include <xmsgeom/geometry/geoms.h>
29 #include <xmscore/misc/Observer.h>
32 #include <xmscore/misc/XmError.h>
33 
34 // 6. Non-shared code headers
35 
36 //----- Namespace declaration --------------------------------------------------
37 
38 namespace xms
39 {
40 //----- Forward declarations ---------------------------------------------------
41 
42 //----- External globals -------------------------------------------------------
43 
44 //----- Constants / Enumerations -----------------------------------------------
45 
46 //----- Classes / Structs ------------------------------------------------------
47 
50 struct edgerecord
51 {
52  int pt1;
53  int pt2;
55 };
56 
57 typedef std::vector<edgerecord> VecEdge;
58 
61 {
62 public:
64  virtual ~TrBreaklineAdderImpl();
65 
68  virtual void SetObserver(BSHP<Observer> a_) override { m_observer = a_; }
69  virtual void SetTin(BSHP<TrTin> a_tin, double a_tol = -1) override;
70  virtual void AddBreakline(const VecInt& a_breakline) override;
71  virtual void AddBreaklines(const VecInt2d& a_breakline) override;
72  virtual std::string ErrorMessage(int) const override;
73 
74 private:
75  bool GetExtents();
76  void ComputeTolerance();
77  bool CrossesBoundary(int a_blpt1, int a_blpt2);
78  void ProcessSegmentBySwapping(int a_vtx1, int a_vtx2);
79  void GetIntersectingEdges(int a_blpt1, int a_blpt2, VecEdge& a_edges);
80  void FindIntersectingEdgeFromPoint(int a_blpt1,
81  int a_blpt2,
82  int* a_intpt1,
83  int* a_intpt2,
84  double* a_x,
85  double* a_y,
86  double* a_z1,
87  double* a_z2);
88  void FindIntersectingEdgeFromEdge(int a_ept1,
89  int a_ept2,
90  int a_blpt1,
91  int a_blpt2,
92  int* a_intpt1,
93  int* a_intpt2,
94  double* a_x,
95  double* a_y,
96  double* a_z1,
97  double* a_z2);
98 
99  BSHP<TrTin> m_tin;
100  BSHP<Observer> m_observer;
101  double m_xyTol;
102  size_t m_totNumSegs;
103  size_t m_segCount;
109  BSHP<GmMultiPolyIntersector>
111  BSHP<GmPtSearch> m_searcher;
112 }; // class TrBreaklineAdderImpl
113 
114 //----- Internal functions -----------------------------------------------------
115 
116 //----- Class / Function definitions -------------------------------------------
117 
122 //------------------------------------------------------------------------------
124 //------------------------------------------------------------------------------
125 TrBreaklineAdderImpl::TrBreaklineAdderImpl()
126 : m_tin()
127 , m_observer()
128 , m_xyTol(1e-9)
129 , m_totNumSegs(0)
130 , m_segCount(0)
131 , m_tris(nullptr)
132 , m_pts(nullptr)
133 , m_trisAdjToPts(nullptr)
134 , m_mn()
135 , m_mx()
136 , m_multiPolyIntersector()
137 , m_searcher()
138 {
139 }
140 //------------------------------------------------------------------------------
142 //------------------------------------------------------------------------------
143 TrBreaklineAdderImpl::~TrBreaklineAdderImpl()
144 {
145 }
146 //------------------------------------------------------------------------------
151 //------------------------------------------------------------------------------
152 void TrBreaklineAdderImpl::SetTin(BSHP<TrTin> a_tin, double a_tol /*-1*/)
153 {
154  m_tin = a_tin;
155 
156  // Check for an invalid tin
157  XM_ENSURE_TRUE_T_NO_ASSERT(m_tin, std::runtime_error("Tin is null."));
158  // XM_ENSURE_TRUE_T_NO_ASSERT(!m_tin->Triangles().empty(), std::runtime_error("Tin has no
159  // triangles.")); XM_ENSURE_TRUE_T_NO_ASSERT(!m_tin->Points().empty(), std::runtime_error("Tin
160  // has no points.")); XM_ENSURE_TRUE_T_NO_ASSERT(!m_tin->TrisAdjToPts().empty(),
161  // std::runtime_error("Tin has no adjacency info."));
162 
163  m_tris = &m_tin->Triangles();
164  m_pts = &m_tin->Points();
165  m_trisAdjToPts = &m_tin->TrisAdjToPts();
166  if (a_tol < 0)
167  {
169  }
170  else
171  {
172  m_xyTol = a_tol;
173  }
174 } // TrBreaklineAdderImpl::SetTin
175 //------------------------------------------------------------------------------
180 //------------------------------------------------------------------------------
182 {
183  XM_ENSURE_TRUE_T_NO_ASSERT(m_tin, std::runtime_error("No tin set in TrBreaklineAdder."));
184 
185  bool progressStarted = false;
186  if (m_observer)
187  {
188  if (m_totNumSegs < 1)
189  {
190  m_observer->BeginOperationString("Adding Breaklines");
191  progressStarted = true;
192  m_totNumSegs = a_breakline.size() - 1;
193  m_segCount = 0;
194  }
195  }
196 
197  for (size_t pt = 1; pt < a_breakline.size(); ++pt)
198  {
199  int pt1 = a_breakline[pt - 1];
200  int pt2 = a_breakline[pt];
201  if (!m_tin->VerticesAreAdjacent(pt1, pt2))
202  {
203  ProcessSegmentBySwapping(pt1, pt2);
204  }
205  if (m_observer)
206  {
207  m_observer->ProgressStatus(m_segCount / (double)m_totNumSegs);
208  m_segCount++;
209  }
210  }
211 
212  if (m_observer && progressStarted)
213  {
214  m_observer->EndOperation();
215  }
216 
217 } // TrBreaklineAdderImpl::AddBreakline
218 //------------------------------------------------------------------------------
223 //------------------------------------------------------------------------------
225 {
226  XM_ENSURE_TRUE_T_NO_ASSERT(m_tin, std::runtime_error("No tin set in TrBreaklineAdder."));
227 
228  if (m_observer)
229  {
230  m_observer->BeginOperationString("Adding Breaklines");
231  m_segCount = 0;
232  m_totNumSegs = 0;
233  for (size_t i = 0; i < a_breaklines.size(); ++i)
234  {
235  m_totNumSegs += a_breaklines[i].size() - 1;
236  }
237  }
238 
239  for (size_t i = 0; i < a_breaklines.size(); ++i)
240  {
241  AddBreakline(a_breaklines[i]);
242  }
243 
244  m_segCount = 0;
245  m_totNumSegs = 0;
246 
247  if (m_observer)
248  {
249  m_observer->EndOperation();
250  }
251 } // TrBreaklineAdderImpl::AddBreaklines
252 //------------------------------------------------------------------------------
256 //------------------------------------------------------------------------------
257 std::string TrBreaklineAdderImpl::ErrorMessage(int a_messageNumber) const
258 {
259  std::string message;
260  switch (a_messageNumber)
261  {
262  case 0:
263  message = "One or more breakline segments intersected a boundary and was ignored.";
264  break;
265  default:
266  XM_ASSERT(false);
267  break;
268  }
269  return message;
270 } // TrBreaklineAdderImpl::ErrorMessage
271 //------------------------------------------------------------------------------
277 //------------------------------------------------------------------------------
278 bool TrBreaklineAdderImpl::CrossesBoundary(int a_blpt1, int a_blpt2)
279 {
280  //#if 0
282  {
283  VecInt2d boundaryPolys;
284  m_tin->GetBoundaryPolys(boundaryPolys);
285 
286  BSHP<GmMultiPolyIntersectionSorter> sorter =
287  BSHP<GmMultiPolyIntersectionSorter>(new GmMultiPolyIntersectionSorterTerse());
288  m_multiPolyIntersector = GmMultiPolyIntersector::New(m_tin->Points(), boundaryPolys, sorter);
289  m_multiPolyIntersector->SetQuery(GMMPIQ_INTERSECTS);
290 
291  m_searcher = GmPtSearch::New(true);
292  m_searcher->PtsToSearch(m_tin->PointsPtr());
293  }
294 
295  VecInt intersectedPolys;
296  VecPt3d intersectionPts;
297  m_multiPolyIntersector->TraverseLineSegment(
298  m_tin->Points()[a_blpt1].x, m_tin->Points()[a_blpt1].y, m_tin->Points()[a_blpt2].x,
299  m_tin->Points()[a_blpt2].y, intersectedPolys, intersectionPts);
300  if (intersectedPolys.empty())
301  {
302  return false;
303  }
304  else
305  {
306  // See if the intersectionPts are at the boundary points. If so, we aren't
307  // crossing an edge.
308  for (size_t i = 0; i < intersectionPts.size(); ++i)
309  {
310  if (!m_searcher->PtInRTree(intersectionPts[i], m_xyTol))
311  {
312  return true;
313  }
314  }
315  }
316  //#endif
317  return false;
318 } // TrBreaklineAdderImpl::CrossesBoundary
319 //------------------------------------------------------------------------------
324 //------------------------------------------------------------------------------
326 {
327  if (CrossesBoundary(a_blpt1, a_blpt2))
328  {
330  "One or more breakline segments intersected a boundary and was ignored.");
331  return;
332  }
333 
334  VecEdge edges;
335  GetIntersectingEdges(a_blpt1, a_blpt2, edges);
336  VecEdge::iterator edge = edges.begin();
337 
338  bool good_tris = true;
339  bool trisSwappedThisPass = false;
340  double x, y, z1, z2;
341 
342  while (!edges.empty() && edge != edges.end())
343  {
344  int tri1 = m_tin->TriangleAdjacentToEdge(edge->pt1, edge->pt2);
345  int tri2 = m_tin->TriangleAdjacentToEdge(edge->pt2, edge->pt1);
346  if (!m_tin->SwapEdge(tri1, tri2, good_tris))
347  {
348  ++edge;
349  }
350  else
351  {
352  trisSwappedThisPass = true;
353  // See if new edge needs to be put on the list
354  int index = m_tin->CommonEdgeIndex(tri1, tri2);
355  // 'unsigned int', possible loss of data
356  int newpt1 = (*m_tris)[(tri1 * 3) + index];
357  index = trIncrementIndex(index);
358  int newpt2 = (*m_tris)[(tri1 * 3) + index];
359  if ((newpt1 != a_blpt1) && (newpt1 != a_blpt2) && (newpt2 != a_blpt1) &&
360  (newpt2 != a_blpt2) &&
361  gmIntersectLineSegmentsWithTol((*m_pts)[a_blpt1], (*m_pts)[a_blpt2], (*m_pts)[newpt1],
362  (*m_pts)[newpt2], &x, &y, &z1, &z2, m_xyTol))
363  {
364  // put edge on the list in place of swapped one
365  edge->pt1 = newpt1;
366  edge->pt2 = newpt2;
367  ++edge;
368  }
369  else
370  {
371  // Remove this edge from the list
372  edge = edges.erase(edge);
373  }
374  }
375  // if we are still not adjacent
376  if (edge == edges.end() && (tri1 != -1 && tri2 != -1))
377  {
378  // if we didn't do any swaps continue through list again
379  if (!trisSwappedThisPass)
380  {
381  if (good_tris)
382  {
383  good_tris = false;
384  }
385  else
386  {
387  break;
388  }
389  }
390  // There is a potential for infinite loop. This is where we could check for that
391  // We did some swapping or we removed triangle criterion - try starting over with the edge
392  // list
393  edge = edges.begin();
394  trisSwappedThisPass = false;
395  }
396  else if (m_tin->VerticesAreAdjacent(a_blpt1, a_blpt2))
397  break;
398  // if (xgCheckEscape()) {
399  // throw exceptions::Exception("User Escape");
400  //}
401  }
402 } // TrBreaklineAdderImpl::ProcessSegmentBySwapping
403 //------------------------------------------------------------------------------
409 //------------------------------------------------------------------------------
410 void TrBreaklineAdderImpl::GetIntersectingEdges(int a_blpt1, int a_blpt2, VecEdge& a_edges)
411 {
412  bool first = true;
413  bool done = false;
414  int intpt1, intpt2;
415  double x, y, z1, z2;
416  do
417  {
418  if (first)
419  {
420  FindIntersectingEdgeFromPoint(a_blpt1, a_blpt2, &intpt1, &intpt2, &x, &y, &z1, &z2);
421  first = false;
422  }
423  else
424  {
425  FindIntersectingEdgeFromEdge(intpt2, intpt1, a_blpt1, a_blpt2, &intpt1, &intpt2, &x, &y, &z1,
426  &z2);
427  }
428  if (intpt1 == -1 || intpt2 == -1)
429  done = true;
430  else if (intpt1 == a_blpt2 || intpt2 == a_blpt2)
431  done = true;
432  else
433  {
434  edgerecord edge;
435  edge.pt1 = intpt1;
436  edge.pt2 = intpt2;
437  edge.intersection.x = x;
438  edge.intersection.y = y;
439  edge.intersection.z = z2;
440  a_edges.push_back(edge);
441  }
442  } while (!done);
443 
444 } // TrBreaklineAdderImpl::GetIntersectingEdges
445 //------------------------------------------------------------------------------
456 //------------------------------------------------------------------------------
458  int a_blpt2,
459  int* a_intpt1,
460  int* a_intpt2,
461  double* a_x,
462  double* a_y,
463  double* a_z1,
464  double* a_z2)
465 {
466  // loop thru adjacent tris until found
467  bool found = false;
468  // 'unsigned int', possible loss of data
469  for (size_t adjTri = 0; adjTri < (*m_trisAdjToPts)[a_blpt1].size() && !found; ++adjTri)
470  {
471  int tri = (*m_trisAdjToPts)[a_blpt1][adjTri];
472  // Check opposite edge(s) for intersections
473  int localIdx1 = m_tin->LocalIndex(tri, a_blpt1);
474  localIdx1 = trIncrementIndex(localIdx1);
475  int localIdx2 = trIncrementIndex(localIdx1);
476  *a_intpt1 = m_tin->Triangles()[(tri * 3) + localIdx1];
477  *a_intpt2 = m_tin->Triangles()[(tri * 3) + localIdx2];
478  found =
479  gmIntersectLineSegmentsWithTol((*m_pts)[a_blpt1], (*m_pts)[a_blpt2], (*m_pts)[*a_intpt1],
480  (*m_pts)[*a_intpt2], a_x, a_y, a_z1, a_z2, m_xyTol);
481  }
482  if (!found)
483  {
484  *a_intpt1 = *a_intpt2 = -1;
485  }
486 
487 } // TrBreaklineAdderImpl::FindIntersectingEdgeFromPoint
488 //------------------------------------------------------------------------------
502 //------------------------------------------------------------------------------
504  int a_ept2,
505  int a_blpt1,
506  int a_blpt2,
507  int* a_intpt1,
508  int* a_intpt2,
509  double* a_x,
510  double* a_y,
511  double* a_z1,
512  double* a_z2)
513 {
514  bool found = false;
515  int tri = m_tin->TriangleAdjacentToEdge(a_ept2, a_ept1);
516  XM_ENSURE_TRUE_T_NO_ASSERT(tri != -1, std::runtime_error("Void in breakline"));
517 
518  int localIdx1 = m_tin->LocalIndex(tri, a_ept2);
519  const int kNumcorners = 3;
520  int crnrid;
521  int count;
522  for (crnrid = localIdx1, count = 1; !found && count <= kNumcorners - 1; count++)
523  {
524  int nextid = trIncrementIndex(crnrid);
525  int trisIdx = tri * 3;
526  *a_intpt1 = (*m_tris)[trisIdx + crnrid];
527  *a_intpt2 = (*m_tris)[trisIdx + nextid];
528  found =
529  gmIntersectLineSegmentsWithTol((*m_pts)[a_blpt1], (*m_pts)[a_blpt2], (*m_pts)[*a_intpt1],
530  (*m_pts)[*a_intpt2], a_x, a_y, a_z1, a_z2, m_xyTol);
531  if (found)
532  {
533  int adjTri = -1;
534  int id1, id2;
535  m_tin->TriangleFromEdge(*a_intpt1, *a_intpt2, adjTri, id1, id2);
536  if (adjTri == -1)
537  {
538  throw std::runtime_error("Void in breakline");
539  }
540  }
541  crnrid = nextid;
542  }
543 
544  if (!found)
545  {
546  *a_intpt1 = *a_intpt2 = -1;
547  }
548 
549 } // TrBreaklineAdderImpl::FindIntersectingEdgeFromEdge
550 //------------------------------------------------------------------------------
553 //------------------------------------------------------------------------------
555 {
556  if (m_tin)
557  {
558  return m_tin->GetExtents(m_mn, m_mx);
559  }
560  return false;
561 } // TrBreaklineAdderImpl::GetExtents
562 //------------------------------------------------------------------------------
564 //------------------------------------------------------------------------------
566 {
567  if (GetExtents())
568  {
569  m_xyTol = gmComputeXyTol(m_mn, m_mx);
570  }
571 } // TrBreaklineAdderImpl::ComputeTolerance
572 
580 //------------------------------------------------------------------------------
582 //------------------------------------------------------------------------------
583 TrBreaklineAdder::TrBreaklineAdder()
584 {
585 }
586 //------------------------------------------------------------------------------
588 //------------------------------------------------------------------------------
589 TrBreaklineAdder::~TrBreaklineAdder()
590 {
591 }
592 //------------------------------------------------------------------------------
595 //------------------------------------------------------------------------------
596 BSHP<TrBreaklineAdder> TrBreaklineAdder::New()
597 {
598  return BDPC<TrBreaklineAdder>(BSHP<TrBreaklineAdderImpl>(new TrBreaklineAdderImpl()));
599 } // TrBreaklineAdder::TrBreaklineAdder
600 
601 } // namespace xms
602 
604 // TESTS
606 #ifdef CXX_TEST
607 
609 
610 #include <boost/assign.hpp>
611 
613 #include <xmscore/misc/carray.h>
616 
617 //----- Namespace declaration --------------------------------------------------
618 
619 // namespace xms {
620 using namespace xms;
621 
626 //------------------------------------------------------------------------------
629 // Before
630 //
631 // 4- 3---------------4
632 // | / | \ / | \
633 // | / | \ 5 / | \
634 // | / | \ / | \
635 // 0- 0 0 | 1 1 2 | 4 2
636 // | \ | / \ | /
637 // | \ | / 3 \ | /
638 // | \ | / \ | /
639 // -4- 5-------------- 6
640 //
641 // |-------|-------|-------|-------|
642 // 0 5 10 15 20
643 //
644 // After
645 //
646 // 4- 3---------------4
647 // | / | \ / \
648 // | / | \ 5 / 2 \
649 // | / | \ / \
650 // 0- 0 0 | 1 1---------------2
651 // | \ | / \ /
652 // | \ | / 3 \ 4 /
653 // | \ | / \ /
654 // -4- 5-------------- 6
655 //
656 // |-------|-------|-------|-------|
657 // 0 5 10 15 20
659 //------------------------------------------------------------------------------
661 {
662  // Set up the tin
663  BSHP<TrTin> tin = TrTin::New();
664  tin->Points() = {{0, 0, 0}, {10, 0, 0}, {20, 0, 0}, {5, 4, 0},
665  {15, 4, 0}, {5, -4, 0}, {15, -4, 0}};
666  TrTriangulatorPoints triangulator(tin->Points(), tin->Triangles(), &tin->TrisAdjToPts());
667  triangulator.Triangulate();
668 
669  // Verify triangles before
670  int trisB[] = {0, 5, 3, 3, 5, 1, 1, 6, 4, 6, 1, 5, 2, 4, 6, 1, 4, 3};
671  TS_ASSERT_EQUALS(VecInt(&trisB[0], &trisB[18]), tin->Triangles());
672 
673  // Add breakline
674  BSHP<TrBreaklineAdder> adder = TrBreaklineAdder::New();
675  adder->SetTin(tin);
676  VecInt outPoly = {0, 5, 6, 1, 2, 4, 3};
677  adder->AddBreakline(outPoly);
678 
679  // Verify triangles after
680  int trisA[] = {0, 5, 3, 3, 5, 1, 1, 2, 4, 6, 1, 5, 2, 1, 6, 1, 4, 3};
681  TS_ASSERT_EQUALS(VecInt(&trisA[0], &trisA[XM_COUNTOF(trisA)]), tin->Triangles());
682 
683 } // TrBreaklineAdderUnitTests::test1
684 //------------------------------------------------------------------------------
689 // Before
690 //
691 // 10- 17-----18------19------20------21
692 // | |\ 8 /|\ 11 /|\ 22 / \ 26 /|
693 // | | \ / | \ / | \ / \ //|
694 // | | \ / | \ /30|23\ / 27 \ / /|
695 // 5- |6 13 12|9 14 | 15------16 /|
696 // | | / \ | /|\ | / \ 25 /|28/|
697 // | | / \ | / | \ | / \ / | / |
698 // | |/ 7 \|/ | \|/ 24 \ /29| / |
699 // 0- 9------10 10|3 11------12 | / |
700 // | |\ 13 / \ | / \ 15 / \ |/ |
701 // | | \ / \ | / \ / \ |/ |
702 // | | \ / 5 \|/ 16 \ / 21 \|/ |
703 // -5- | 0 5-------6-------7-------8 18|
704 // | | / \ 4 / \ 14 / \ 19 / \ |
705 // | | / \ / \ / \ / \ |
706 // | |/ 1 \ / 2 \ / 20 \ / 17 \|
707 // -10- 0-------1-------2-------3-------4
708 //
709 // |-------|-------|-------|-------|
710 // 0 10 20 30 40
711 //
712 // After swapping
713 //
714 // 10- 17-----18------19------20------21
715 // | |\ 8 / \ 11 /|\ 22 / \ 26 /|
716 // | | \ / \ / | \ / \ //|
717 // | | \ / 12 \ /30|23\ / 27 \ / /|
718 // 5- |6 13------14 | 15------16 /|
719 // | | /|\ 9 /|\ | /|\ 25 /|28/|
720 // | | / | \ / | \ | / | \ / | / |
721 // | |/ | \ / | \|/ |24\ /29| / |
722 // 0- 9 13|7 10 10|3 11 15| 12 | / |
723 // | |\ | / \ | / \ | / \ |/ |
724 // | | \ | / \ | / \ | / \ |/ |
725 // | | \|/ 5 \|/ 16 \|/ 21 \|/ |
726 // -5- | 0 5-------6-------7-------8 18|
727 // | | / \ 4 / \ 14 / \ 19 / \ |
728 // | | / \ / \ / \ / \ |
729 // | |/ 1 \ / 2 \ / 20 \ / 17 \|
730 // -10- 0-------1-------2-------3-------4
731 //
732 // |-------|-------|-------|-------|
733 // 0 10 20 30 40
734 //
735 // After removing triangles (*** means a hole)
736 //
737 // 10- 17-----18------19------20------21
738 // | |\ 7 / \ 9 /|\ 17 / \ 21 /
739 // | | \ / \ / | \ / \ /
740 // | | \ / 10 \ /24|18\ / 22 \ /
741 // 5- |6 13------14 | 15------16
742 // | | /|******/|\ | /|\ 20 /|
743 // | | / |*****/ | \ | /*| \ / |
744 // | |/ |****/ | \|/**|19\ /23|
745 // 0- 9 11|**10 8|3 11***| 12 |
746 // | |\ |**/ \ | /****| / \ |
747 // | | \ |*/ \ | /*****| / \ |
748 // | | \|/ 5 \|/******|/ 16 \|
749 // -5- | 0 5-------6-------7-------8
750 // | | / \ 4 / \ 12 / \ 14 / \
751 // | | / \ / \ / \ / \
752 // | |/ 1 \ / 2 \ / 15 \ / 13 \
753 // -10- 0-------1-------2-------3-------4
754 //
755 // |-------|-------|-------|-------|
756 // 0 10 20 30 40
758 //------------------------------------------------------------------------------
760 {
761  // Set up tin
762  BSHP<TrTin> tin = trBuildTestTin7();
763 
764  // Verify triangles before
765  int trisB[] = {0, 5, 9, 5, 0, 1, 1, 2, 6, 14, 6, 11, 1, 6, 5, 5, 6, 10, 9,
766  13, 17, 13, 9, 10, 17, 13, 18, 10, 14, 18, 14, 10, 6, 18, 14, 19, 10, 18,
767  13, 9, 5, 10, 6, 2, 7, 12, 11, 7, 7, 11, 6, 3, 4, 8, 8, 4, 21,
768  3, 8, 7, 7, 2, 3, 12, 7, 8, 19, 15, 20, 15, 19, 11, 12, 15, 11, 15,
769  12, 16, 20, 16, 21, 16, 20, 15, 21, 16, 8, 12, 8, 16, 11, 19, 14};
770  TS_ASSERT_EQUALS(VecInt(&trisB[0], &trisB[93]), tin->Triangles());
771 
772  // Set up polygons
773  int outPolyA[] = {0, 1, 2, 3, 4, 8, 16, 21, 20, 19, 18, 17, 9};
774  VecInt outPoly(&outPolyA[0], &outPolyA[13]);
775  int inPoly1[] = {10, 5, 13, 14};
776  int inPoly2[] = {6, 11, 15, 7};
777  VecInt2d inPolys;
778  inPolys.push_back(VecInt(&inPoly1[0], &inPoly1[4]));
779  inPolys.push_back(VecInt(&inPoly2[0], &inPoly2[4]));
780 
781  // Add breaklines
782  BSHP<TrBreaklineAdder> adder = TrBreaklineAdder::New();
783  adder->SetTin(tin);
784  adder->AddBreakline(outPoly);
785  adder->AddBreaklines(inPolys);
786 
787  // Verify triangles after
788  int trisA[] = {0, 5, 9, 5, 0, 1, 1, 2, 6, 14, 6, 11, 1, 6, 5, 5, 6, 10, 9,
789  13, 17, 13, 5, 10, 17, 13, 18, 10, 14, 13, 14, 10, 6, 18, 14, 19, 14, 18,
790  13, 9, 5, 13, 6, 2, 7, 15, 11, 7, 7, 11, 6, 3, 4, 8, 8, 4, 21,
791  3, 8, 7, 7, 2, 3, 12, 7, 8, 19, 15, 20, 15, 19, 11, 12, 15, 7, 15,
792  12, 16, 20, 16, 21, 16, 20, 15, 21, 16, 8, 12, 8, 16, 11, 19, 14};
793  VecInt trisAfter(&trisA[0], &trisA[XM_COUNTOF(trisA)]);
794  TS_ASSERT_EQUALS(trisAfter, tin->Triangles());
795 
796 } // TrBreaklineAdderUnitTests::test2
797 //------------------------------------------------------------------------------
800 //
817 //------------------------------------------------------------------------------
819 {
820  try
821  {
822  BSHP<TrTin> tin = trBuildTestTin8();
823 
824  // Add breakline
825  BSHP<TrBreaklineAdder> adder = TrBreaklineAdder::New();
826  adder->SetTin(tin);
827 
828  // Copy triangles before
829  VecInt tris = tin->Triangles();
830 
831  std::string errorMessage = adder->ErrorMessage(0);
832 
833  // Try to add a breakline that crosses the hole
834  VecInt breakline = {3, 8};
836  adder->AddBreakline(breakline);
837  TS_ASSERT(XmLog::Instance().ErrCount() == 1);
838  if (XmLog::Instance().ErrCount() > 0)
839  {
841  TS_ASSERT_EQUALS(messages[0].second, errorMessage);
842  }
843  TS_ASSERT_EQUALS(tris, tin->Triangles());
844 
845  // Try to add a breakline that crosses the concavity
846  breakline = {4, 11};
848  adder->AddBreakline(breakline);
849  TS_ASSERT(XmLog::Instance().ErrCount() == 1);
850  if (XmLog::Instance().ErrCount() > 0)
851  {
853  TS_ASSERT_EQUALS(messages[0].second, errorMessage);
854  }
855  TS_ASSERT_EQUALS(tris, tin->Triangles());
856 
857  // Try to add a breakline that crosses both inside and inner boundary
858  breakline = {10, 7, 2, 8};
860  adder->AddBreakline(breakline);
861  TS_ASSERT(XmLog::Instance().ErrCount() == 1);
862  if (XmLog::Instance().ErrCount() > 0)
863  {
865  TS_ASSERT_EQUALS(messages[0].second, errorMessage);
866  }
867  {
868  int trisA[] = {0, 3, 2, 0, 1, 3, 1, 4, 3, 1, 5, 4, 2, 7, 6, 3, 7, 2,
869  4, 8, 7, 4, 5, 8, 6, 7, 9, 7, 10, 9, 8, 10, 7, 8, 11, 10};
870  TS_ASSERT_EQUALS(VecInt(&trisA[0], &trisA[XM_COUNTOF(trisA)]), tin->Triangles());
871  }
872 
873  // Try to add a breakline that crosses both inside and outer boundary
874  breakline = {0, 4, 11};
876  adder->AddBreakline(breakline);
877  TS_ASSERT(XmLog::Instance().ErrCount() == 1);
878  if (XmLog::Instance().ErrCount() > 0)
879  {
881  TS_ASSERT_EQUALS(messages[0].second, errorMessage);
882  }
883  {
884  int trisA[] = {0, 3, 2, 0, 4, 3, 1, 4, 0, 1, 5, 4, 2, 7, 6, 3, 7, 2,
885  4, 8, 7, 4, 5, 8, 6, 7, 9, 7, 10, 9, 8, 10, 7, 8, 11, 10};
886  TS_ASSERT_EQUALS(VecInt(&trisA[0], &trisA[XM_COUNTOF(trisA)]), tin->Triangles());
887  }
888 
889  // Go around inner border
890  breakline = {3, 4, 7, 8, 4, 3, 7};
892  adder->AddBreakline(breakline);
893  TS_ASSERT(XmLog::Instance().ErrCount() == 0);
894  {
895  int trisA[] = {0, 3, 2, 0, 4, 3, 1, 4, 0, 1, 5, 4, 2, 7, 6, 3, 7, 2,
896  4, 8, 7, 4, 5, 8, 6, 7, 9, 7, 10, 9, 8, 10, 7, 8, 11, 10};
897  TS_ASSERT_EQUALS(VecInt(&trisA[0], &trisA[XM_COUNTOF(trisA)]), tin->Triangles());
898  }
899 
901  }
902  catch (std::exception&)
903  {
904  TS_FAIL("exception");
905  }
906 
907 } // TrBreaklineAdderUnitTests::testCrossingBoundary
908 
909  //} // namespace xms
910 
911 #endif
static boost::shared_ptr< TrBreaklineAdder > New()
Create a TrBreaklineAdderImpl object.
BSHP< Observer > m_observer
The observer.
#define XM_LOG(A, B)
virtual void AddBreakline(const VecInt &a_breakline) override
Add a breakline by swapping. Compare to bkProcessScatBySwapping.
BSHP< TrTin > trBuildTestTin8()
Builds a simple TIN with a hole in the middle and a concavity.
Definition: TrTin.cpp:1499
void test2()
Test a more complex case involving two inner polygons and removal of outer triangles. This doesn't remove the triangles - that would be the next step.
void test1()
Test a simple case involving a swap and removal of outer triangle.
Functions dealing with triangles.
size_t m_totNumSegs
Total num segments. For progress.
std::vector< std::pair< xmlog::MessageTypeEnum, std::string > > MessageStack
void FindIntersectingEdgeFromPoint(int a_blpt1, int a_blpt2, int *a_intpt1, int *a_intpt2, double *a_x, double *a_y, double *a_z1, double *a_z2)
Finds edge opposite of a_blpt1 intersected by breakline segment a_blpt1, a_blpt2. Compare to bkiFindI...
void ProcessSegmentBySwapping(int a_vtx1, int a_vtx2)
Insert breakline segment into triangulation by swapping triangle edges. Compare to bkiProcessScatSegm...
int pt1
Index of point defining the edge.
boost::geometry types
void ComputeTolerance()
Computes a tolerance to use based on point extents.
static boost::shared_ptr< GmMultiPolyIntersector > New(const std::vector< Pt3d > &a_points, const std::vector< std::vector< int > > &a_polys, boost::shared_ptr< GmMultiPolyIntersectionSorter > a_sorter, int a_startingId=1)
Creates a new GmMultiPolyIntersectorImpl object.
Adds breaklines to a triangulation.
MessageStack GetAndClearStack()
std::vector< int > VecInt
virtual void SetObserver(BSHP< Observer > a_) override
Set the observer to use for feedback while processing.
VecPt3d * m_pts
Pointer to m_tin points for convenience.
Pt3d m_mx
Maximum extent of all points.
Functions dealing with geometry.
static BSHP< TrTin > New()
Create a TrTinImpl object.
Definition: TrTin.cpp:1247
bool Triangulate()
Triangulate the points into a tin.
std::string GetAndClearStackStr()
Adds breaklines to a tin.
Pt3d intersection
Point of intersection.
std::vector< Pt3d > VecPt3d
virtual std::string ErrorMessage(int) const override
Returns the error message associated with the given number.
void FindIntersectingEdgeFromEdge(int a_ept1, int a_ept2, int a_blpt1, int a_blpt2, int *a_intpt1, int *a_intpt2, double *a_x, double *a_y, double *a_z1, double *a_z2)
Finds edge of triangle intersected by breakline and returns next edge in a_intpt1 and a_intpt2...
Pt3d m_mn
Minimum extent of all points.
#define XM_ASSERT(x)
void GetIntersectingEdges(int a_blpt1, int a_blpt2, VecEdge &a_edges)
Find triangle edges which intersect the breakline. Compare to bkiGetListOfIntersectingScatEdges.
#define XM_ENSURE_TRUE_T_NO_ASSERT(...)
void testCrossingBoundary()
Test a case involving crossing a hole and the outer boundary.
virtual void SetTin(BSHP< TrTin > a_tin, double a_tol=-1) override
Sets the tin that will have breaklines added to it.
#define XM_COUNTOF(array)
BSHP< GmMultiPolyIntersector > m_multiPolyIntersector
Used to check if breakline crosses boundary.
BSHP< TrTin > trBuildTestTin7()
Builds a simple TIN for testing.
Definition: TrTin.cpp:1465
static BSHP< GmPtSearch > New(bool a_2dSearch)
Creates an PtSearch class.
Definition: GmPtSearch.cpp:236
static XmLog & Instance(bool a_delete=false, XmLog *a_new=NULL)
int pt2
Index of point defining the edge.
std::vector< VecInt > VecInt2d
virtual void AddBreaklines(const VecInt2d &a_breakline) override
Add breaklines by swapping. Compare to bkProcessScatBySwapping.
BSHP< GmPtSearch > m_searcher
Used to check if breakline crosses boundary.
Class for sorting intersections from GmMultiPolyIntersector in a terse way (with no duplicate info)...
VecInt * m_tris
Pointer to m_tin triangles for convenience.
Defines an edge that intersects a breakline.
double m_xyTol
Xy tolerance used with geom functions.
size_t m_segCount
Current segment. For progress.
bool GetExtents()
Computes the extents (min, max) of the polygon.
bool CrossesBoundary(int a_blpt1, int a_blpt2)
Returns true if the line connecting the two points crosses the tin boundary.
BSHP< TrTin > m_tin
The tin.
Class to triangulate simple points.
VecInt2d * m_trisAdjToPts
Pointer to m_tin trisAdjToPts for convenience.