xmsgrid  1.0
TrBreaklineAdder.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 <functional>
17 
18 // 4. External library headers
19 
20 // 5. Shared code headers
21 #include <xmscore/misc/Progress.h>
22 #include <xmscore/stl/set.h>
23 #include <xmscore/stl/vector.h>
24 #include <xmsgrid/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;
107  BSHP<GmMultiPolyIntersector>
109  BSHP<GmPtSearch> m_searcher;
110 }; // class TrBreaklineAdderImpl
111 
112 //----- Internal functions -----------------------------------------------------
113 
114 //----- Class / Function definitions -------------------------------------------
115 
120 //------------------------------------------------------------------------------
122 //------------------------------------------------------------------------------
123 TrBreaklineAdderImpl::TrBreaklineAdderImpl()
124 : m_tin()
125 , m_observer()
126 , m_xyTol(1e-9)
127 , m_tris(nullptr)
128 , m_pts(nullptr)
129 , m_trisAdjToPts(nullptr)
130 , m_mn()
131 , m_mx()
132 , m_multiPolyIntersector()
133 , m_searcher()
134 {
135 }
136 //------------------------------------------------------------------------------
138 //------------------------------------------------------------------------------
139 TrBreaklineAdderImpl::~TrBreaklineAdderImpl()
140 {
141 }
142 //------------------------------------------------------------------------------
147 //------------------------------------------------------------------------------
148 void TrBreaklineAdderImpl::SetTin(BSHP<TrTin> a_tin, double a_tol /*-1*/)
149 {
150  m_tin = a_tin;
151 
152  // Check for an invalid tin
153  XM_ENSURE_TRUE_T_NO_ASSERT(m_tin, std::runtime_error("Tin is null."));
154  // XM_ENSURE_TRUE_T_NO_ASSERT(!m_tin->Triangles().empty(), std::runtime_error("Tin has no
155  // triangles.")); XM_ENSURE_TRUE_T_NO_ASSERT(!m_tin->Points().empty(), std::runtime_error("Tin
156  // has no points.")); XM_ENSURE_TRUE_T_NO_ASSERT(!m_tin->TrisAdjToPts().empty(),
157  // std::runtime_error("Tin has no adjacency info."));
158 
159  m_tris = &m_tin->Triangles();
160  m_pts = &m_tin->Points();
161  m_trisAdjToPts = &m_tin->TrisAdjToPts();
162  if (a_tol < 0)
163  {
165  }
166  else
167  {
168  m_xyTol = a_tol;
169  }
170 } // TrBreaklineAdderImpl::SetTin
171 //------------------------------------------------------------------------------
176 //------------------------------------------------------------------------------
178 {
179  XM_ENSURE_TRUE_T_NO_ASSERT(m_tin, std::runtime_error("No tin set in TrBreaklineAdder."));
180  Progress prog("Adding Breaklines");
181  double totNumSegs = static_cast<double>(a_breakline.size() - 1);
182  double segCount(0.0);
183 
184  for (size_t pt = 1; pt < a_breakline.size(); ++pt)
185  {
186  int pt1 = a_breakline[pt - 1];
187  int pt2 = a_breakline[pt];
188  if (!m_tin->VerticesAreAdjacent(pt1, pt2))
189  {
190  ProcessSegmentBySwapping(pt1, pt2);
191  }
192  segCount += 1.0;
193  prog.ProgressStatus(std::min(1.0, segCount / totNumSegs));
194  }
195 } // TrBreaklineAdderImpl::AddBreakline
196 //------------------------------------------------------------------------------
201 //------------------------------------------------------------------------------
203 {
204  XM_ENSURE_TRUE_T_NO_ASSERT(m_tin, std::runtime_error("No tin set in TrBreaklineAdder."));
205  Progress prog("Adding Breaklines");
206  size_t segCount(0);
207  size_t totNumSegs(0);
208  for (size_t i = 0; i < a_breaklines.size(); ++i)
209  {
210  totNumSegs += a_breaklines[i].size() - 1;
211  }
212  double total = static_cast<double>(totNumSegs);
213  for (size_t i = 0; i < a_breaklines.size(); ++i)
214  {
215  segCount += a_breaklines[i].size() - 1;
216  AddBreakline(a_breaklines[i]);
217  prog.ProgressStatus(static_cast<double>(segCount) / total);
218  }
219 } // TrBreaklineAdderImpl::AddBreaklines
220 //------------------------------------------------------------------------------
224 //------------------------------------------------------------------------------
225 std::string TrBreaklineAdderImpl::ErrorMessage(int a_messageNumber) const
226 {
227  std::string message;
228  switch (a_messageNumber)
229  {
230  case 0:
231  message = "One or more breakline segments intersected a boundary and was ignored.";
232  break;
233  default:
234  XM_ASSERT(false);
235  break;
236  }
237  return message;
238 } // TrBreaklineAdderImpl::ErrorMessage
239 //------------------------------------------------------------------------------
245 //------------------------------------------------------------------------------
246 bool TrBreaklineAdderImpl::CrossesBoundary(int a_blpt1, int a_blpt2)
247 {
248  //#if 0
250  {
251  VecInt2d boundaryPolys;
252  m_tin->GetBoundaryPolys(boundaryPolys);
253 
254  BSHP<GmMultiPolyIntersectionSorter> sorter =
255  BSHP<GmMultiPolyIntersectionSorter>(new GmMultiPolyIntersectionSorterTerse());
256  m_multiPolyIntersector = GmMultiPolyIntersector::New(m_tin->Points(), boundaryPolys, sorter);
257  m_multiPolyIntersector->SetQuery(GMMPIQ_INTERSECTS);
258 
259  m_searcher = GmPtSearch::New(true);
260  m_searcher->PtsToSearch(m_tin->PointsPtr());
261  }
262 
263  VecInt intersectedPolys;
264  VecPt3d intersectionPts;
265  m_multiPolyIntersector->TraverseLineSegment(
266  m_tin->Points()[a_blpt1].x, m_tin->Points()[a_blpt1].y, m_tin->Points()[a_blpt2].x,
267  m_tin->Points()[a_blpt2].y, intersectedPolys, intersectionPts);
268  if (intersectedPolys.empty())
269  {
270  return false;
271  }
272  else
273  {
274  // See if the intersectionPts are at the boundary points. If so, we aren't
275  // crossing an edge.
276  for (size_t i = 0; i < intersectionPts.size(); ++i)
277  {
278  if (!m_searcher->PtInRTree(intersectionPts[i], m_xyTol))
279  {
280  return true;
281  }
282  }
283  }
284  //#endif
285  return false;
286 } // TrBreaklineAdderImpl::CrossesBoundary
287 //------------------------------------------------------------------------------
292 //------------------------------------------------------------------------------
294 {
295  if (CrossesBoundary(a_blpt1, a_blpt2))
296  {
298  "One or more breakline segments intersected a boundary and was ignored.");
299  return;
300  }
301 
302  VecEdge edges;
303  GetIntersectingEdges(a_blpt1, a_blpt2, edges);
304  VecEdge::iterator edge = edges.begin();
305 
306  bool good_tris = true;
307  bool trisSwappedThisPass = false;
308  double x, y, z1, z2;
309 
310  while (!edges.empty() && edge != edges.end())
311  {
312  int tri1 = m_tin->TriangleAdjacentToEdge(edge->pt1, edge->pt2);
313  int tri2 = m_tin->TriangleAdjacentToEdge(edge->pt2, edge->pt1);
314  if (!m_tin->SwapEdge(tri1, tri2, good_tris))
315  {
316  ++edge;
317  }
318  else
319  {
320  trisSwappedThisPass = true;
321  // See if new edge needs to be put on the list
322  int index = m_tin->CommonEdgeIndex(tri1, tri2);
323  // 'unsigned int', possible loss of data
324  int newpt1 = (*m_tris)[(tri1 * 3) + index];
325  index = trIncrementIndex(index);
326  int newpt2 = (*m_tris)[(tri1 * 3) + index];
327  if ((newpt1 != a_blpt1) && (newpt1 != a_blpt2) && (newpt2 != a_blpt1) &&
328  (newpt2 != a_blpt2) &&
329  gmIntersectLineSegmentsWithTol((*m_pts)[a_blpt1], (*m_pts)[a_blpt2], (*m_pts)[newpt1],
330  (*m_pts)[newpt2], &x, &y, &z1, &z2, m_xyTol))
331  {
332  // put edge on the list in place of swapped one
333  edge->pt1 = newpt1;
334  edge->pt2 = newpt2;
335  ++edge;
336  }
337  else
338  {
339  // Remove this edge from the list
340  edge = edges.erase(edge);
341  }
342  }
343  // if we are still not adjacent
344  if (edge == edges.end() && (tri1 != -1 && tri2 != -1))
345  {
346  // if we didn't do any swaps continue through list again
347  if (!trisSwappedThisPass)
348  {
349  if (good_tris)
350  {
351  good_tris = false;
352  }
353  else
354  {
355  break;
356  }
357  }
358  // There is a potential for infinite loop. This is where we could check for that
359  // We did some swapping or we removed triangle criterion - try starting over with the edge
360  // list
361  edge = edges.begin();
362  trisSwappedThisPass = false;
363  }
364  else if (m_tin->VerticesAreAdjacent(a_blpt1, a_blpt2))
365  break;
366  // if (xgCheckEscape()) {
367  // throw exceptions::Exception("User Escape");
368  //}
369  }
370 } // TrBreaklineAdderImpl::ProcessSegmentBySwapping
371 //------------------------------------------------------------------------------
377 //------------------------------------------------------------------------------
378 void TrBreaklineAdderImpl::GetIntersectingEdges(int a_blpt1, int a_blpt2, VecEdge& a_edges)
379 {
380  bool first = true;
381  bool done = false;
382  int intpt1, intpt2;
383  double x, y, z1, z2;
384  do
385  {
386  if (first)
387  {
388  FindIntersectingEdgeFromPoint(a_blpt1, a_blpt2, &intpt1, &intpt2, &x, &y, &z1, &z2);
389  first = false;
390  }
391  else
392  {
393  FindIntersectingEdgeFromEdge(intpt2, intpt1, a_blpt1, a_blpt2, &intpt1, &intpt2, &x, &y, &z1,
394  &z2);
395  }
396  if (intpt1 == -1 || intpt2 == -1)
397  done = true;
398  else if (intpt1 == a_blpt2 || intpt2 == a_blpt2)
399  done = true;
400  else
401  {
402  edgerecord edge;
403  edge.pt1 = intpt1;
404  edge.pt2 = intpt2;
405  edge.intersection.x = x;
406  edge.intersection.y = y;
407  edge.intersection.z = z2;
408  a_edges.push_back(edge);
409  }
410  } while (!done);
411 
412 } // TrBreaklineAdderImpl::GetIntersectingEdges
413 //------------------------------------------------------------------------------
424 //------------------------------------------------------------------------------
426  int a_blpt2,
427  int* a_intpt1,
428  int* a_intpt2,
429  double* a_x,
430  double* a_y,
431  double* a_z1,
432  double* a_z2)
433 {
434  // loop thru adjacent tris until found
435  bool found = false;
436  // 'unsigned int', possible loss of data
437  for (size_t adjTri = 0; adjTri < (*m_trisAdjToPts)[a_blpt1].size() && !found; ++adjTri)
438  {
439  int tri = (*m_trisAdjToPts)[a_blpt1][adjTri];
440  // Check opposite edge(s) for intersections
441  int localIdx1 = m_tin->LocalIndex(tri, a_blpt1);
442  localIdx1 = trIncrementIndex(localIdx1);
443  int localIdx2 = trIncrementIndex(localIdx1);
444  *a_intpt1 = m_tin->Triangles()[(tri * 3) + localIdx1];
445  *a_intpt2 = m_tin->Triangles()[(tri * 3) + localIdx2];
446  found =
447  gmIntersectLineSegmentsWithTol((*m_pts)[a_blpt1], (*m_pts)[a_blpt2], (*m_pts)[*a_intpt1],
448  (*m_pts)[*a_intpt2], a_x, a_y, a_z1, a_z2, m_xyTol);
449  }
450  if (!found)
451  {
452  *a_intpt1 = *a_intpt2 = -1;
453  }
454 
455 } // TrBreaklineAdderImpl::FindIntersectingEdgeFromPoint
456 //------------------------------------------------------------------------------
470 //------------------------------------------------------------------------------
472  int a_ept2,
473  int a_blpt1,
474  int a_blpt2,
475  int* a_intpt1,
476  int* a_intpt2,
477  double* a_x,
478  double* a_y,
479  double* a_z1,
480  double* a_z2)
481 {
482  bool found = false;
483  int tri = m_tin->TriangleAdjacentToEdge(a_ept2, a_ept1);
484  XM_ENSURE_TRUE_T_NO_ASSERT(tri != -1, std::runtime_error("Void in breakline"));
485 
486  int localIdx1 = m_tin->LocalIndex(tri, a_ept2);
487  const int kNumcorners = 3;
488  int crnrid;
489  int count;
490  for (crnrid = localIdx1, count = 1; !found && count <= kNumcorners - 1; count++)
491  {
492  int nextid = trIncrementIndex(crnrid);
493  int trisIdx = tri * 3;
494  *a_intpt1 = (*m_tris)[trisIdx + crnrid];
495  *a_intpt2 = (*m_tris)[trisIdx + nextid];
496  found =
497  gmIntersectLineSegmentsWithTol((*m_pts)[a_blpt1], (*m_pts)[a_blpt2], (*m_pts)[*a_intpt1],
498  (*m_pts)[*a_intpt2], a_x, a_y, a_z1, a_z2, m_xyTol);
499  if (found)
500  {
501  int adjTri = -1;
502  int id1, id2;
503  m_tin->TriangleFromEdge(*a_intpt1, *a_intpt2, adjTri, id1, id2);
504  if (adjTri == -1)
505  {
506  throw std::runtime_error("Void in breakline");
507  }
508  }
509  crnrid = nextid;
510  }
511 
512  if (!found)
513  {
514  *a_intpt1 = *a_intpt2 = -1;
515  }
516 
517 } // TrBreaklineAdderImpl::FindIntersectingEdgeFromEdge
518 //------------------------------------------------------------------------------
521 //------------------------------------------------------------------------------
523 {
524  if (m_tin)
525  {
526  return m_tin->GetExtents(m_mn, m_mx);
527  }
528  return false;
529 } // TrBreaklineAdderImpl::GetExtents
530 //------------------------------------------------------------------------------
532 //------------------------------------------------------------------------------
534 {
535  if (GetExtents())
536  {
538  }
539 } // TrBreaklineAdderImpl::ComputeTolerance
540 
548 //------------------------------------------------------------------------------
550 //------------------------------------------------------------------------------
551 TrBreaklineAdder::TrBreaklineAdder()
552 {
553 }
554 //------------------------------------------------------------------------------
556 //------------------------------------------------------------------------------
557 TrBreaklineAdder::~TrBreaklineAdder()
558 {
559 }
560 //------------------------------------------------------------------------------
563 //------------------------------------------------------------------------------
564 BSHP<TrBreaklineAdder> TrBreaklineAdder::New()
565 {
566  return BDPC<TrBreaklineAdder>(BSHP<TrBreaklineAdderImpl>(new TrBreaklineAdderImpl()));
567 } // TrBreaklineAdder::TrBreaklineAdder
568 
569 } // namespace xms
570 
572 // TESTS
574 #ifdef CXX_TEST
575 
577 
578 #include <boost/assign.hpp>
579 
581 #include <xmscore/misc/carray.h>
584 
585 //----- Namespace declaration --------------------------------------------------
586 
587 // namespace xms {
588 using namespace xms;
589 
594 //------------------------------------------------------------------------------
597 // Before
598 //
599 // 4- 3---------------4
600 // | / | \ / | \
601 // | / | \ 5 / | \
602 // | / | \ / | \
603 // 0- 0 0 | 1 1 2 | 4 2
604 // | \ | / \ | /
605 // | \ | / 3 \ | /
606 // | \ | / \ | /
607 // -4- 5-------------- 6
608 //
609 // |-------|-------|-------|-------|
610 // 0 5 10 15 20
611 //
612 // After
613 //
614 // 4- 3---------------4
615 // | / | \ / \
616 // | / | \ 5 / 2 \
617 // | / | \ / \
618 // 0- 0 0 | 1 1---------------2
619 // | \ | / \ /
620 // | \ | / 3 \ 4 /
621 // | \ | / \ /
622 // -4- 5-------------- 6
623 //
624 // |-------|-------|-------|-------|
625 // 0 5 10 15 20
627 //------------------------------------------------------------------------------
629 {
630  // Set up the tin
631  BSHP<TrTin> tin = TrTin::New();
632  tin->Points() = {{0, 0, 0}, {10, 0, 0}, {20, 0, 0}, {5, 4, 0},
633  {15, 4, 0}, {5, -4, 0}, {15, -4, 0}};
634  TrTriangulatorPoints triangulator(tin->Points(), tin->Triangles(), &tin->TrisAdjToPts());
635  triangulator.Triangulate();
636 
637  // Verify triangles before
638  int trisB[] = {0, 5, 3, 3, 5, 1, 1, 6, 4, 6, 1, 5, 2, 4, 6, 1, 4, 3};
639  TS_ASSERT_EQUALS(VecInt(&trisB[0], &trisB[18]), tin->Triangles());
640 
641  // Add breakline
642  BSHP<TrBreaklineAdder> adder = TrBreaklineAdder::New();
643  adder->SetTin(tin);
644  VecInt outPoly = {0, 5, 6, 1, 2, 4, 3};
645  adder->AddBreakline(outPoly);
646 
647  // Verify triangles after
648  int trisA[] = {0, 5, 3, 3, 5, 1, 1, 2, 4, 6, 1, 5, 2, 1, 6, 1, 4, 3};
649  TS_ASSERT_EQUALS(VecInt(&trisA[0], &trisA[XM_COUNTOF(trisA)]), tin->Triangles());
650 
651 } // TrBreaklineAdderUnitTests::test1
652 //------------------------------------------------------------------------------
657 // Before
658 //
659 // 10- 17-----18------19------20------21
660 // | |\ 8 /|\ 11 /|\ 22 / \ 26 /|
661 // | | \ / | \ / | \ / \ //|
662 // | | \ / | \ /30|23\ / 27 \ / /|
663 // 5- |6 13 12|9 14 | 15------16 /|
664 // | | / \ | /|\ | / \ 25 /|28/|
665 // | | / \ | / | \ | / \ / | / |
666 // | |/ 7 \|/ | \|/ 24 \ /29| / |
667 // 0- 9------10 10|3 11------12 | / |
668 // | |\ 13 / \ | / \ 15 / \ |/ |
669 // | | \ / \ | / \ / \ |/ |
670 // | | \ / 5 \|/ 16 \ / 21 \|/ |
671 // -5- | 0 5-------6-------7-------8 18|
672 // | | / \ 4 / \ 14 / \ 19 / \ |
673 // | | / \ / \ / \ / \ |
674 // | |/ 1 \ / 2 \ / 20 \ / 17 \|
675 // -10- 0-------1-------2-------3-------4
676 //
677 // |-------|-------|-------|-------|
678 // 0 10 20 30 40
679 //
680 // After swapping
681 //
682 // 10- 17-----18------19------20------21
683 // | |\ 8 / \ 11 /|\ 22 / \ 26 /|
684 // | | \ / \ / | \ / \ //|
685 // | | \ / 12 \ /30|23\ / 27 \ / /|
686 // 5- |6 13------14 | 15------16 /|
687 // | | /|\ 9 /|\ | /|\ 25 /|28/|
688 // | | / | \ / | \ | / | \ / | / |
689 // | |/ | \ / | \|/ |24\ /29| / |
690 // 0- 9 13|7 10 10|3 11 15| 12 | / |
691 // | |\ | / \ | / \ | / \ |/ |
692 // | | \ | / \ | / \ | / \ |/ |
693 // | | \|/ 5 \|/ 16 \|/ 21 \|/ |
694 // -5- | 0 5-------6-------7-------8 18|
695 // | | / \ 4 / \ 14 / \ 19 / \ |
696 // | | / \ / \ / \ / \ |
697 // | |/ 1 \ / 2 \ / 20 \ / 17 \|
698 // -10- 0-------1-------2-------3-------4
699 //
700 // |-------|-------|-------|-------|
701 // 0 10 20 30 40
702 //
703 // After removing triangles (*** means a hole)
704 //
705 // 10- 17-----18------19------20------21
706 // | |\ 7 / \ 9 /|\ 17 / \ 21 /
707 // | | \ / \ / | \ / \ /
708 // | | \ / 10 \ /24|18\ / 22 \ /
709 // 5- |6 13------14 | 15------16
710 // | | /|******/|\ | /|\ 20 /|
711 // | | / |*****/ | \ | /*| \ / |
712 // | |/ |****/ | \|/**|19\ /23|
713 // 0- 9 11|**10 8|3 11***| 12 |
714 // | |\ |**/ \ | /****| / \ |
715 // | | \ |*/ \ | /*****| / \ |
716 // | | \|/ 5 \|/******|/ 16 \|
717 // -5- | 0 5-------6-------7-------8
718 // | | / \ 4 / \ 12 / \ 14 / \
719 // | | / \ / \ / \ / \
720 // | |/ 1 \ / 2 \ / 15 \ / 13 \
721 // -10- 0-------1-------2-------3-------4
722 //
723 // |-------|-------|-------|-------|
724 // 0 10 20 30 40
726 //------------------------------------------------------------------------------
728 {
729  // Set up tin
730  BSHP<TrTin> tin = trBuildTestTin7();
731 
732  // Verify triangles before
733  int trisB[] = {0, 5, 9, 5, 0, 1, 1, 2, 6, 14, 6, 11, 1, 6, 5, 5, 6, 10, 9,
734  13, 17, 13, 9, 10, 17, 13, 18, 10, 14, 18, 14, 10, 6, 18, 14, 19, 10, 18,
735  13, 9, 5, 10, 6, 2, 7, 12, 11, 7, 7, 11, 6, 3, 4, 8, 8, 4, 21,
736  3, 8, 7, 7, 2, 3, 12, 7, 8, 19, 15, 20, 15, 19, 11, 12, 15, 11, 15,
737  12, 16, 20, 16, 21, 16, 20, 15, 21, 16, 8, 12, 8, 16, 11, 19, 14};
738  TS_ASSERT_EQUALS(VecInt(&trisB[0], &trisB[93]), tin->Triangles());
739 
740  // Set up polygons
741  int outPolyA[] = {0, 1, 2, 3, 4, 8, 16, 21, 20, 19, 18, 17, 9};
742  VecInt outPoly(&outPolyA[0], &outPolyA[13]);
743  int inPoly1[] = {10, 5, 13, 14};
744  int inPoly2[] = {6, 11, 15, 7};
745  VecInt2d inPolys;
746  inPolys.push_back(VecInt(&inPoly1[0], &inPoly1[4]));
747  inPolys.push_back(VecInt(&inPoly2[0], &inPoly2[4]));
748 
749  // Add breaklines
750  BSHP<TrBreaklineAdder> adder = TrBreaklineAdder::New();
751  adder->SetTin(tin);
752  adder->AddBreakline(outPoly);
753  adder->AddBreaklines(inPolys);
754 
755  // Verify triangles after
756  int trisA[] = {0, 5, 9, 5, 0, 1, 1, 2, 6, 14, 6, 11, 1, 6, 5, 5, 6, 10, 9,
757  13, 17, 13, 5, 10, 17, 13, 18, 10, 14, 13, 14, 10, 6, 18, 14, 19, 14, 18,
758  13, 9, 5, 13, 6, 2, 7, 15, 11, 7, 7, 11, 6, 3, 4, 8, 8, 4, 21,
759  3, 8, 7, 7, 2, 3, 12, 7, 8, 19, 15, 20, 15, 19, 11, 12, 15, 7, 15,
760  12, 16, 20, 16, 21, 16, 20, 15, 21, 16, 8, 12, 8, 16, 11, 19, 14};
761  VecInt trisAfter(&trisA[0], &trisA[XM_COUNTOF(trisA)]);
762  TS_ASSERT_EQUALS(trisAfter, tin->Triangles());
763 
764 } // TrBreaklineAdderUnitTests::test2
765 //------------------------------------------------------------------------------
768 //
785 //------------------------------------------------------------------------------
787 {
788  try
789  {
790  BSHP<TrTin> tin = trBuildTestTin8();
791 
792  // Add breakline
793  BSHP<TrBreaklineAdder> adder = TrBreaklineAdder::New();
794  adder->SetTin(tin);
795 
796  // Copy triangles before
797  VecInt tris = tin->Triangles();
798 
799  std::string errorMessage = adder->ErrorMessage(0);
800 
801  // Try to add a breakline that crosses the hole
802  VecInt breakline = {3, 8};
804  adder->AddBreakline(breakline);
805  TS_ASSERT(XmLog::Instance().ErrCount() == 1);
806  if (XmLog::Instance().ErrCount() > 0)
807  {
809  TS_ASSERT_EQUALS(messages[0].second, errorMessage);
810  }
811  TS_ASSERT_EQUALS(tris, tin->Triangles());
812 
813  // Try to add a breakline that crosses the concavity
814  breakline = {4, 11};
816  adder->AddBreakline(breakline);
817  TS_ASSERT(XmLog::Instance().ErrCount() == 1);
818  if (XmLog::Instance().ErrCount() > 0)
819  {
821  TS_ASSERT_EQUALS(messages[0].second, errorMessage);
822  }
823  TS_ASSERT_EQUALS(tris, tin->Triangles());
824 
825  // Try to add a breakline that crosses both inside and inner boundary
826  breakline = {10, 7, 2, 8};
828  adder->AddBreakline(breakline);
829  TS_ASSERT(XmLog::Instance().ErrCount() == 1);
830  if (XmLog::Instance().ErrCount() > 0)
831  {
833  TS_ASSERT_EQUALS(messages[0].second, errorMessage);
834  }
835  {
836  int trisA[] = {0, 3, 2, 0, 1, 3, 1, 4, 3, 1, 5, 4, 2, 7, 6, 3, 7, 2,
837  4, 8, 7, 4, 5, 8, 6, 7, 9, 7, 10, 9, 8, 10, 7, 8, 11, 10};
838  TS_ASSERT_EQUALS(VecInt(&trisA[0], &trisA[XM_COUNTOF(trisA)]), tin->Triangles());
839  }
840 
841  // Try to add a breakline that crosses both inside and outer boundary
842  breakline = {0, 4, 11};
844  adder->AddBreakline(breakline);
845  TS_ASSERT(XmLog::Instance().ErrCount() == 1);
846  if (XmLog::Instance().ErrCount() > 0)
847  {
849  TS_ASSERT_EQUALS(messages[0].second, errorMessage);
850  }
851  {
852  int trisA[] = {0, 3, 2, 0, 4, 3, 1, 4, 0, 1, 5, 4, 2, 7, 6, 3, 7, 2,
853  4, 8, 7, 4, 5, 8, 6, 7, 9, 7, 10, 9, 8, 10, 7, 8, 11, 10};
854  TS_ASSERT_EQUALS(VecInt(&trisA[0], &trisA[XM_COUNTOF(trisA)]), tin->Triangles());
855  }
856 
857  // Go around inner border
858  breakline = {3, 4, 7, 8, 4, 3, 7};
860  adder->AddBreakline(breakline);
861  TS_ASSERT(XmLog::Instance().ErrCount() == 0);
862  {
863  int trisA[] = {0, 3, 2, 0, 4, 3, 1, 4, 0, 1, 5, 4, 2, 7, 6, 3, 7, 2,
864  4, 8, 7, 4, 5, 8, 6, 7, 9, 7, 10, 9, 8, 10, 7, 8, 11, 10};
865  TS_ASSERT_EQUALS(VecInt(&trisA[0], &trisA[XM_COUNTOF(trisA)]), tin->Triangles());
866  }
867 
869  }
870  catch (std::exception&)
871  {
872  TS_FAIL("exception");
873  }
874 
875 } // TrBreaklineAdderUnitTests::testCrossingBoundary
876 
877  //} // namespace xms
878 
879 #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.
std::vector< std::pair< xmlog::MessageTypeEnum, std::string > > MessageStack
std::vector< int > VecInt
BSHP< TrTin > trBuildTestTin8()
Builds a simple TIN with a hole in the middle and a concavity.
Definition: TrTin.cpp:1599
void test2()
Test a more complex case involving two inner polygons and removal of outer triangles. This doesn&#39;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.
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
bool gmIntersectLineSegmentsWithTol(const Pt3d &one1, const Pt3d &one2, const Pt3d &two1, const Pt3d &two2, double *xi, double *yi, double *zi1, double *zi2, double tol)
Intersects the plan projection of two line segments.
Definition: geoms.cpp:420
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()
virtual void SetObserver(BSHP< Observer > a_) override
Set the observer to use for feedback while processing.
std::vector< VecInt > VecInt2d
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:1347
bool Triangulate()
Triangulate the points into a tin.
std::string GetAndClearStackStr()
Adds breaklines to a tin.
Pt3d intersection
Point of intersection.
double gmComputeXyTol(const Pt3d &a_mn, const Pt3d &a_mx)
Given extents (min, max), compute a tolerance for the xy plane to be used with geometric functions...
Definition: geoms.cpp:1262
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...
void ProgressStatus(double a_percentComplete)
Pt3d m_mn
Minimum extent of all points.
#define XM_ASSERT(x)
XMS Namespace.
Definition: geoms.cpp:34
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:1565
static BSHP< GmPtSearch > New(bool a_2dSearch)
Creates an PtSearch class.
Definition: GmPtSearch.cpp:235
static XmLog & Instance(bool a_delete=false, XmLog *a_new=NULL)
int pt2
Index of point defining the edge.
virtual void AddBreaklines(const VecInt2d &a_breakline) override
Add breaklines by swapping. Compare to bkProcessScatBySwapping.
std::vector< edgerecord > VecEdge
Vector of edgerecord.
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.
bool GetExtents()
Computes the extents (min, max) of the polygon.
int trIncrementIndex(int i)
Faster than a % operation and we do this a lot.
Definition: triangles.h:44
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.
std::vector< Pt3d > VecPt3d
VecInt2d * m_trisAdjToPts
Pointer to m_tin trisAdjToPts for convenience.