xmsgeom  1.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
GmPolygon.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
7 //------------------------------------------------------------------------------
8 //----- Included files ---------------------------------------------------------
9 
10 // 1. Precompiled header
11 
12 // 2. My own header
14 
15 // 3. Standard library headers
16 
17 // 4. External library headers
18 #pragma warning(push)
19 #pragma warning(disable : 4512) // boost code: no assignment operator
20 #pragma warning(disable : 4244) // boost code: possible loss of data
21 #pragma warning(disable : 4127) // boost code: conditional expression is constant
22 #include <boost/geometry/geometry.hpp>
23 #pragma warning(pop)
24 
25 // 5. Shared code headers
26 #include <xmscore/misc/XmError.h>
27 #include <xmsgeom/geometry/GmBoostTypes.h> // GmBstPoly3d, GmBstRing3d
29 
30 // 6. Non-shared code headers
31 
32 //----- Forward declarations ---------------------------------------------------
33 
34 //----- External globals -------------------------------------------------------
35 
36 //----- Namespace declaration --------------------------------------------------
37 
38 namespace xms
39 {
40 //----- Constants / Enumerations -----------------------------------------------
41 
42 //----- Classes / Structs ------------------------------------------------------
43 
45 class GmPolygonImpl : public GmPolygon
46 {
47 public:
48  GmPolygonImpl();
49  ~GmPolygonImpl() {}
50 
51  virtual void Setup(const VecPt3d& a_poly, const VecPt3d2d& a_inPolys) override;
52  virtual void GetPoints(VecPt3d& a_poly, VecPt3d2d& a_inPolys) const override;
53 
54  virtual bool CoveredBy(Pt3d a_point) const override;
55  virtual bool Within(Pt3d a_point) const override;
56  virtual double MinDistanceToBoundary(Pt3d a_pt) const override;
57  virtual void Intersection(const GmPolygon& a_,
58  std::vector<BSHP<GmPolygon>>& a_out) const override;
59  virtual void Union(const GmPolygon& a_, std::vector<BSHP<GmPolygon>>& a_out) const override;
60 
61 private:
62  GmBstPoly3d m_poly;
63 }; // GmPolygonImpl
64 
65 //----- Internal functions -----------------------------------------------------
66 
67 static double iDistanceToRing(const GmBstRing3d& a_ring, const Pt3d& a_pt);
68 //----- Class / Function definitions -------------------------------------------
69 
70 //------------------------------------------------------------------------------
75 //------------------------------------------------------------------------------
76 static double iDistanceToRing(const GmBstRing3d& a_ring, const Pt3d& a_pt)
77 {
78  GmBstLine3d line;
79  // make each ring a linestring and get minimum distance
80  for (size_t i = 0; i < a_ring.size(); ++i)
81  {
82  line.push_back(a_ring[i]);
83  }
84  double d = boost::geometry::distance(line, a_pt);
85  return d;
86 } // iDistanceToRing
87 
101 //------------------------------------------------------------------------------
103 //------------------------------------------------------------------------------
105 : m_poly()
106 {
107 } // GmPolygonImpl::GmPolygonImpl
108 //------------------------------------------------------------------------------
116 //------------------------------------------------------------------------------
117 void GmPolygonImpl::Setup(const VecPt3d& a_outPoly, const VecPt3d2d& a_inPolys)
118 {
119  namespace bg = boost::geometry;
120 
121  m_poly.clear();
122 
123  // See http://www.boost.org/doc/libs/1_55_0/libs/geometry/doc/src/examples/core/rings.cpp
124  // Outer poly
125  for (size_t i = 0; i < a_outPoly.size(); ++i)
126  {
127  bg::exterior_ring(m_poly).push_back(a_outPoly[i]);
128  }
129 
130  // Inner polys
131  for (size_t i = 0; i < a_inPolys.size(); ++i)
132  {
133  GmBstRing3d inner;
134  for (size_t j = 0; j < a_inPolys[i].size(); ++j)
135  {
136  inner.push_back(a_inPolys[i][j]);
137  }
138  bg::interior_rings(m_poly).push_back(inner);
139  }
140 
141  // Fix the orientation and closure of the polygon.
142  bg::correct(m_poly);
143 
144 } // GmPolygonImpl::Setup
145 //------------------------------------------------------------------------------
149 //------------------------------------------------------------------------------
150 void GmPolygonImpl::GetPoints(VecPt3d& a_outPoly, VecPt3d2d& a_inPolys) const
151 {
152  a_outPoly.clear();
153  a_inPolys.clear();
154  a_outPoly = m_poly.outer();
155  for (auto& p : m_poly.inners())
156  {
157  a_inPolys.push_back(p);
158  }
159 } // GmPolygonImpl::GetPoints
160 //------------------------------------------------------------------------------
168 //------------------------------------------------------------------------------
169 bool GmPolygonImpl::CoveredBy(Pt3d a_point) const
170 {
171  namespace bg = boost::geometry;
172 
173  if (bg::covered_by(a_point, m_poly))
174  {
175  return true;
176  }
177  return false;
178 } // GmPolygonImpl::CoveredBy
179 //------------------------------------------------------------------------------
187 //------------------------------------------------------------------------------
188 bool GmPolygonImpl::Within(Pt3d a_point) const
189 {
190  namespace bg = boost::geometry;
191 
192  if (bg::within(a_point, m_poly))
193  {
194  return true;
195  }
196  return false;
197 } // GmPolygonImpl::Within
198 //------------------------------------------------------------------------------
202 //------------------------------------------------------------------------------
204 {
205  namespace bg = boost::geometry;
206  double d = iDistanceToRing(m_poly.outer(), a_pt);
207  for (size_t i = 0; i < m_poly.inners().size(); ++i)
208  {
209  double d1 = iDistanceToRing(m_poly.inners()[i], a_pt);
210  if (d1 < d)
211  d = d1;
212  }
213  return d;
214 } // GmPolygonImpl::Within
215 //------------------------------------------------------------------------------
219 //------------------------------------------------------------------------------
220 void GmPolygonImpl::Intersection(const GmPolygon& a_, std::vector<BSHP<GmPolygon>>& a_out) const
221 {
222  a_out.clear();
223  namespace bg = boost::geometry;
224  const GmPolygonImpl* p = dynamic_cast<const GmPolygonImpl*>(&a_);
225  XM_ENSURE_TRUE(p);
226  std::vector<GmBstPoly3d> output;
227  bg::intersection(m_poly, p->m_poly, output);
228 
229  for (auto& o : output)
230  {
231  VecPt3d outPoly = o.outer();
232  VecPt3d2d inPoly;
233  for (auto& i : o.inners())
234  {
235  inPoly.push_back(i);
236  }
237  BSHP<GmPolygon> gp = GmPolygon::New();
238  gp->Setup(outPoly, inPoly);
239  a_out.push_back(gp);
240  }
241 } // GmPolygonImpl::Intersection
242 //------------------------------------------------------------------------------
246 //------------------------------------------------------------------------------
247 void GmPolygonImpl::Union(const GmPolygon& a_, std::vector<BSHP<GmPolygon>>& a_out) const
248 {
249  a_out.clear();
250  namespace bg = boost::geometry;
251  const GmPolygonImpl* p = dynamic_cast<const GmPolygonImpl*>(&a_);
252  XM_ENSURE_TRUE(p);
253  std::vector<GmBstPoly3d> output;
254  bg::union_(m_poly, p->m_poly, output);
255 
256  for (auto& o : output)
257  {
258  VecPt3d outPoly = o.outer();
259  VecPt3d2d inPoly;
260  for (auto& i : o.inners())
261  {
262  inPoly.push_back(i);
263  }
264  BSHP<GmPolygon> gp = GmPolygon::New();
265  gp->Setup(outPoly, inPoly);
266  a_out.push_back(gp);
267  }
268 } // GmPolygonImpl::Union
269 
274 //------------------------------------------------------------------------------
276 //------------------------------------------------------------------------------
278 {
279 } // GmPolygon::GmPolygon
280 //------------------------------------------------------------------------------
282 //------------------------------------------------------------------------------
284 {
285 } // GmPolygon::~GmPolygon
286 //------------------------------------------------------------------------------
289 //------------------------------------------------------------------------------
290 BSHP<GmPolygon> GmPolygon::New()
291 {
292  BSHP<GmPolygon> ret(new GmPolygonImpl);
293  return ret;
294 } // GmPolygon::New
295 
296 } // namespace xms
297 
298 #if CXX_TEST
299 // UNIT TESTS
302 
304 
305 #include <boost/assign.hpp>
306 #include <boost/timer/timer.hpp>
307 
309 #include <xmsgeom/geometry/geoms.h>
311 #include <xmscore/misc/carray.h>
312 
313 //----- Namespace declaration --------------------------------------------------
314 
315 // namespace xms {
316 
321 {
322 public:
323  //----------------------------------------------------------------------------
325  //----------------------------------------------------------------------------
328  , m_poly()
329  {
330  }
331 
332 private:
333  //----------------------------------------------------------------------------
335  //----------------------------------------------------------------------------
336  virtual void Setup() override
337  {
338  GmPointInPolyUnitTests::Setup(); // Call the base class
339 
341  xms::VecPt3d2d inPolys(1, m_inPoly);
342  m_poly->Setup(m_outPoly, inPolys);
343  }
344  //----------------------------------------------------------------------------
347  //----------------------------------------------------------------------------
348  virtual void CheckPoint(const xms::Pt3d& a_pt) override
349  {
350  // We'll just do covered by. If we want to see if it's on an edge we'd
351  // have to do Within.
352  m_status = m_poly->CoveredBy(a_pt);
353  } // CheckPoint
354  //----------------------------------------------------------------------------
357  //----------------------------------------------------------------------------
358  virtual double MaxTime() override
359  {
360  // It takes .51 - .65 seconds on my machine in release.
361  return 1.2;
362  // Hopefully big enough for the tests to pass on all machines but give us
363  // an error if it starts going a lot slower for some reason.
364  } // MaxTime
365 
366 private:
367  BSHP<xms::GmPolygon> m_poly;
368 
371 }; // GmPointInPolyTester_GmPolygon
372 
373 //} // namespace xms
374 
379 //------------------------------------------------------------------------------
383 // 15 - 0 1 2 3 4
384 // |
385 // 10 - 5 6---7---8 9
386 // | | |
387 // 5 - 10 11 12 13 14
388 // | | |
389 // 0 - 15 16--17--18 19
390 // |
391 // -5 - 20 21 22 23 24
392 //
393 // |---|---|---|---|
394 // -5 0 5 10 15
396 //------------------------------------------------------------------------------
398 {
399  using xms::Pt3d;
400 
401  // Counter clockwise outer poly (wrong, but will be fixed automatically).
402  // First point not repeated (wrong, but will be fixed automatically).
403  xms::VecPt3d poly{{0, 0, 0}, {5, 0, 0}, {10, 0, 0}, {10, 5, 0}, {10, 10, 0}, {0, 10, 0}};
404  BSHP<xms::GmPolygon> m = xms::GmPolygon::New();
405  m->Setup(poly, xms::VecPt3d2d());
406  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(-5, 15, 0)), false); // 0
407  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(0, 15, 0)), false); // 1
408  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(5, 15, 0)), false); // 2
409  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(10, 15, 0)), false); // 3
410  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(15, 15, 0)), false); // 4
411  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(-5, 10, 0)), false); // 5
412  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(0, 10, 0)), true); // 6
413  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(5, 10, 0)), true); // 7
414  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(10, 10, 0)), true); // 8
415  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(15, 10, 0)), false); // 9
416  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(-5, 5, 0)), false); // 10
417  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(0, 5, 0)), true); // 11
418  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(5, 5, 0)), true); // 12
419  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(10, 5, 0)), true); // 13
420  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(15, 5, 0)), false); // 14
421  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(-5, 0, 0)), false); // 15
422  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(0, 0, 0)), true); // 16
423  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(5, 0, 0)), true); // 17
424  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(10, 0, 0)), true); // 18
425  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(15, 0, 0)), false); // 19
426  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(-5, -5, 0)), false); // 20
427  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(0, -5, 0)), false); // 21
428  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(5, -5, 0)), false); // 22
429  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(10, -5, 0)), false); // 23
430  TS_ASSERT_EQUALS(m->CoveredBy(Pt3d(15, -5, 0)), false); // 24
431 
432  TS_ASSERT_EQUALS(m->Within(Pt3d(-5, 15, 0)), false); // 0
433  TS_ASSERT_EQUALS(m->Within(Pt3d(0, 15, 0)), false); // 1
434  TS_ASSERT_EQUALS(m->Within(Pt3d(5, 15, 0)), false); // 2
435  TS_ASSERT_EQUALS(m->Within(Pt3d(10, 15, 0)), false); // 3
436  TS_ASSERT_EQUALS(m->Within(Pt3d(15, 15, 0)), false); // 4
437  TS_ASSERT_EQUALS(m->Within(Pt3d(-5, 10, 0)), false); // 5
438  TS_ASSERT_EQUALS(m->Within(Pt3d(0, 10, 0)), false); // 6
439  TS_ASSERT_EQUALS(m->Within(Pt3d(5, 10, 0)), false); // 7
440  TS_ASSERT_EQUALS(m->Within(Pt3d(10, 10, 0)), false); // 8
441  TS_ASSERT_EQUALS(m->Within(Pt3d(15, 10, 0)), false); // 9
442  TS_ASSERT_EQUALS(m->Within(Pt3d(-5, 5, 0)), false); // 10
443  TS_ASSERT_EQUALS(m->Within(Pt3d(0, 5, 0)), false); // 11
444  TS_ASSERT_EQUALS(m->Within(Pt3d(5, 5, 0)), true); // 12
445  TS_ASSERT_EQUALS(m->Within(Pt3d(10, 5, 0)), false); // 13
446  TS_ASSERT_EQUALS(m->Within(Pt3d(15, 5, 0)), false); // 14
447  TS_ASSERT_EQUALS(m->Within(Pt3d(-5, 0, 0)), false); // 15
448  TS_ASSERT_EQUALS(m->Within(Pt3d(0, 0, 0)), false); // 16
449  TS_ASSERT_EQUALS(m->Within(Pt3d(5, 0, 0)), false); // 17
450  TS_ASSERT_EQUALS(m->Within(Pt3d(10, 0, 0)), false); // 18
451  TS_ASSERT_EQUALS(m->Within(Pt3d(15, 0, 0)), false); // 19
452  TS_ASSERT_EQUALS(m->Within(Pt3d(-5, -5, 0)), false); // 20
453  TS_ASSERT_EQUALS(m->Within(Pt3d(0, -5, 0)), false); // 21
454  TS_ASSERT_EQUALS(m->Within(Pt3d(5, -5, 0)), false); // 22
455  TS_ASSERT_EQUALS(m->Within(Pt3d(10, -5, 0)), false); // 23
456  TS_ASSERT_EQUALS(m->Within(Pt3d(15, -5, 0)), false); // 24
457 
458 } // GmPolygonUnitTests::testNoHoles
459 //------------------------------------------------------------------------------
463 // 35 - * * * * * * * * * * * * *
464 // |
465 // 30 - * 5---*---*---*---*---*---*---*---*---*---4 *
466 // | | |
467 // 25 - * * * * * * * * * * * * *
468 // | | |
469 // 20 - * * * 1---*---2 * 1---*---2 * * *
470 // | | | | | | |
471 // 15 - * * * * * 3 * * * 3 * 3 *
472 // | | | | | | |
473 // 10 - * * * 0---5---4 * 0---5---4 * * *
474 // | | |
475 // 5 - * * * * * * * * * * * * *
476 // | | |
477 // 0 - * 0---*---*---*---*---1---*---*---*---*---2 *
478 // |
479 // -5 - * * * * * * * * * * * * *
480 //
481 // |---|---|---|---|---|---|---|---|---|---|---|---|
482 // -5 0 5 10 15 20 25 30 35 40 45 50 55
484 //------------------------------------------------------------------------------
486 {
487  using xms::Pt3d;
488 
489  xms::VecPt3d outPoly;
490  xms::VecPt3d2d inPolys;
491  xms::VecPt3d pts;
492  SetUpPolyWithHoles1(outPoly, inPolys, pts);
493 
494  // Don't repeat the first point on the inner poly to test we can handle that
495  inPolys[1].erase(inPolys[1].begin() + inPolys[1].size() - 1);
496  // Make an inner poly CW to test that we can handle that
497  std::reverse(inPolys[1].begin(), inPolys[1].end());
498 
499  // Set up GmPolygon class
500  BSHP<xms::GmPolygon> m = xms::GmPolygon::New();
501  m->Setup(outPoly, inPolys);
502 
503  // CoveredBy
504  {
505  std::vector<int> actual(pts.size(), 0);
506  for (size_t i = 0; i < pts.size(); ++i)
507  {
508  actual[i] = (m->CoveredBy(pts[i]) != 0);
509  }
510 
511  std::vector<int> expected{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 12
512  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 25
513  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 38
514  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 51
515  0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, // 64
516  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 77
517  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 90
518  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 103
519  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // 116
520  TS_ASSERT_EQUALS_VEC(expected, actual);
521  }
522 
523  // Within
524  {
525  std::vector<int> actual(pts.size(), 0);
526  for (size_t i = 0; i < pts.size(); ++i)
527  {
528  actual[i] = (m->Within(pts[i]) != 0);
529  }
530 
531  std::vector<int> expected{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 12
532  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 25
533  0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 38
534  0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, // 51
535  0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, // 64
536  0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, // 77
537  0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 90
538  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 103
539  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // 116
540  TS_ASSERT_EQUALS_VEC(expected, actual);
541  }
542 
543 } // GmPolygonUnitTests::testWithHoles
544 //------------------------------------------------------------------------------
551 // 30 - 1---------------------------------------2
552 // | | |
553 // 25 - | |
554 // | | |
555 // 20 - | 5-------4 5-------4 |
556 // | | | | | | |
557 // 15 - | | 3 | 3 3
558 // | | | | | | |
559 // 10 - | 0---1---2 0---1---2 |
560 // | | |
561 // 5 - | |
562 // | | |
563 // 0 - 0-------------------5-------------------4
564 //
565 // |---|---|---|---|---|---|---|---|---|---|
566 // 0 5 10 15 20 25 30 35 40 45 50 55
568 //------------------------------------------------------------------------------
570  xms::VecPt3d2d& a_inPolys,
571  xms::VecPt3d& a_ptsToTest)
572 {
573  using xms::Pt3d;
574 
575  a_outPoly.clear();
576  a_inPolys.clear();
577 
578  // Set up inner and outer polygons
579  // Clockwise outer poly. First point repeated.
580  a_outPoly = {{0, 0, 0}, {0, 30, 0}, {50, 30, 0}, {50, 15, 0}, {50, 0, 0}, {25, 0, 0}, {0, 0, 0}};
581 
582  // Counter clockwise inner polys. First point repeated.
583  xms::VecPt3d inPoly1{{10, 10, 0}, {15, 10, 0}, {20, 10, 0}, {20, 15, 0},
584  {20, 20, 0}, {10, 20, 0}, {10, 10, 0}};
585  xms::VecPt3d inPoly2{{30, 10, 0}, {35, 10, 0}, {40, 10, 0}, {40, 15, 0},
586  {40, 20, 0}, {30, 20, 0}, {30, 10, 0}};
587  a_inPolys.push_back(inPoly1);
588  a_inPolys.push_back(inPoly2);
589 
590  // Set up points to test
591  a_ptsToTest.clear();
592  for (int y = 35; y >= -5; y -= 5)
593  {
594  for (int x = -5; x <= 55; x += 5)
595  {
596  a_ptsToTest.push_back(Pt3d(x, y, 0));
597  }
598  }
599 
600 } // GmPolygonUnitTests::SetUpPolyWithHoles1
601 //------------------------------------------------------------------------------
607 // 30 - 8---9 12--13 16--17 20--21 24------25
608 // | | | | | | | | | | |
609 // 25 - 7 10--11 14--15 18--19 22--23 27--26
610 // | | |
611 // 20 - 6---5 2---3---4---5---6---7---8 28--29
612 // | | | | |
613 // 15 - 3---4 1 18---17 14---13 10---9 31--30
614 // | | | | | | | | |
615 // 10 - 2 0---19 16---15 12---11 32--33
616 // | | |
617 // 5 - 1 51-50 47-46 43-42 39-38 35-34
618 // | | | | | | | | | | |
619 // 0 - 0--52 49-48 45--44 41-40 37-36
620 //
621 // |---|---|---|---|---|---|---|---|---|---|
622 // 0 5 10 15 20 25 30 35 40 45 50 55
624 //------------------------------------------------------------------------------
626 {
627  using xms::Pt3d;
628 
629  a_outPoly.clear();
630  a_inPoly.clear();
631 
632  // Set up inner and outer polygons
633  // Clockwise outer poly. First point repeated.
634  double outPoly[] = {
635  0, 0, 0, 5, 0, 10, 0, 15, 5, 15, 5, 20, 0, 20, 0, 25, 0, 30, 5, 30, // 9
636  5, 25, 10, 25, 10, 30, 15, 30, 15, 25, 20, 25, 20, 30, 25, 30, 25, 25, 30, 25, // 19
637  30, 30, 35, 30, 35, 25, 40, 25, 40, 30, 50, 30, 50, 25, 45, 25, 45, 20, 50, 20, // 29
638  50, 15, 45, 15, 45, 10, 50, 10, 50, 5, 45, 5, 45, 0, 40, 0, 40, 5, 35, 5, // 39
639  35, 0, 30, 0, 30, 5, 25, 5, 25, 0, 20, 0, 20, 5, 15, 5, 15, 0, 10, 0, // 49
640  10, 5, 5, 5, 5, 0, 0, 0}; // 52
641  a_outPoly = xms::gmArrayToVecPt3d(outPoly, XM_COUNTOF(outPoly));
642 
643  // double outPolyBA[] =
644  //{ 0,0, 5,0, 5,5, 10,5, 10,0, 15,0, 15,5, 20,5, 20,0, 25,0, // 9
645  // 25,5, 30,5, 30,0, 35,0, 35,5, 40,5, 40,0, 45,0, 45,5, 50,5, // 19
646  // 50,10, 45,10, 45,15, 50,15, 50,20, 45,20, 45,25, 50,25, 50,30, 40,30, // 29
647  // 40,25, 35,25, 35,30, 30,30, 30,25, 25,25, 25,30, 20,30, 20,25, 15,25, // 39
648  // 15,30, 10,30, 10,25, 5,25, 5,30, 0,30, 0,25, 0,20, 5,20, 5,15, // 49
649  // 0,15, 0,10, 0,5, 0,0}; // 52
650  // xms::VecPt3d outPolyB = xms::gmArrayToVecPt3d(outPolyBA, XM_COUNTOF(outPolyBA));
651  // std::reverse(outPolyB.begin(), outPolyB.end());
652  // TS_ASSERT_EQUALS(outPolyB, a_outPoly);
653 
654  // Counter clockwise inner poly. First point repeated.
655  double inPoly1[] = {
656  10, 10, 15, 10, 15, 15, 20, 15, 20, 10, 25, 10, 25, 15, 30, 15, 30, 10, 35, 10, // 9
657  35, 15, 40, 15, 40, 20, 35, 20, 30, 20, 25, 20, 20, 20, 15, 20, 10, 20, 10, 15, // 19
658  10, 10};
659  a_inPoly = xms::gmArrayToVecPt3d(inPoly1, XM_COUNTOF(inPoly1));
660 
661  // double inPoly1BA[] =
662  //{10,10, 10,15, 10,20, 15,20, 20,20, 25,20, 30,20, 35,20, 40,20, 40,15, // 9
663  // 35,15, 35,10, 30,10, 30,15, 25,15, 25,10, 20,10, 20,15, 15,15, 15,10}; // 19
664  // xms::VecPt3d inPoly1B = xms::gmArrayToVecPt3d(inPoly1BA, XM_COUNTOF(inPoly1BA));
665  // std::reverse(inPoly1B.begin(), inPoly1B.end());
666  // TS_ASSERT_EQUALS(inPoly1B, a_inPoly);
667 
668 } // GmPolygonUnitTests::SetUpPolyWithHole
669 //------------------------------------------------------------------------------
671 //------------------------------------------------------------------------------
673 {
674  using namespace xms;
675  std::vector<Pt3d> pts{{0, 0, 0}, {0, 10, 0}, {10, 10, 0}, {10, 0, 0}};
676  std::vector<std::vector<Pt3d>> v2d;
677  GmPolygonImpl i;
678  i.Setup(pts, v2d);
679  Pt3d pt(0, 20, 0);
680  TS_ASSERT_EQUALS(10, i.MinDistanceToBoundary(pt));
681  pt.x = 20;
682  pt.y = 0;
683  TS_ASSERT_EQUALS(10, i.MinDistanceToBoundary(pt));
684  pt.y = 20;
685  double d(200);
686  d = sqrt(d);
687  TS_ASSERT_EQUALS(d, i.MinDistanceToBoundary(pt));
688  pt.x = 5;
689  pt.y = 1;
690  TS_ASSERT_EQUALS(1, i.MinDistanceToBoundary(pt));
691  std::vector<Pt3d> in{{1, 1, 0}, {2, 1, 0}, {2, 2, 0}, {1, 2, 0}};
692  v2d.push_back(in);
693  in = {{8, 8, 0}, {9, 8, 0}, {9, 9, 0}, {8, 9, 0}};
694  v2d.push_back(in);
695  i.Setup(pts, v2d);
696  pt.x = 3;
697  pt.y = 2;
698  TS_ASSERT_EQUALS(1, i.MinDistanceToBoundary(pt));
699  pt.x = 7;
700  pt.y = 8;
701  TS_ASSERT_EQUALS(1, i.MinDistanceToBoundary(pt));
702 } // GmPolygonUnitTests::testMinDistanceToBoundary
703 //------------------------------------------------------------------------------
705 //------------------------------------------------------------------------------
707 {
708  BSHP<xms::GmPolygon> p1 = xms::GmPolygon::New();
709  BSHP<xms::GmPolygon> p2 = xms::GmPolygon::New();
710 
711  xms::VecPt3d out1 = {{0.0, 0.0}, {0.0, 1.0}, {1.0, 1.0}, {1.0, 0.0}, {0.0, 0.0}};
712  xms::VecPt3d2d in;
713  p1->Setup(out1, in);
714  xms::VecPt3d out2 = {{-1.0, -1.0}, {-1.0, 2.0}, {2.0, 2.0}, {2.0, -1.0}, {-1.0, -1.0}};
715  p2->Setup(out2, in);
716  std::vector<BSHP<xms::GmPolygon>> output;
717  p1->Intersection(*p2, output);
718  TS_ASSERT(output.size() == 1);
719  if (output.size() != 1)
720  return;
721  xms::VecPt3d base = out1;
722  xms::VecPt3d outputPts;
723  xms::VecPt3d2d outputPtsInPoly;
724  output[0]->GetPoints(outputPts, outputPtsInPoly);
725  double tol(1e-12);
726  TS_ASSERT_DELTA_VECPT3D(base, outputPts, tol);
727 
728  out2 = {{0.5, -1.0}, {0.5, 2.0}, {2.0, 2.0}, {2.0, -1.0}, {0.5, -1.0}};
729  p2->Setup(out2, in);
730  p1->Intersection(*p2, output);
731  TS_ASSERT(output.size() == 1);
732  if (output.size() != 1)
733  return;
734  base = {{0.5, 1.0}, {1.0, 1.0}, {1.0, 0.0}, {0.5, 0.0}, {0.5, 1.0}};
735  output[0]->GetPoints(outputPts, outputPtsInPoly);
736  tol = 1e-6;
737  TS_ASSERT_DELTA_VECPT3D(base, outputPts, tol);
738 
739 } // GmPolygonUnitTests::testIntersection
740 //------------------------------------------------------------------------------
742 //------------------------------------------------------------------------------
744 {
745  BSHP<xms::GmPolygon> p1 = xms::GmPolygon::New();
746  BSHP<xms::GmPolygon> p2 = xms::GmPolygon::New();
747 
748  xms::VecPt3d out1 = {{0.0, 0.0}, {0.0, 1.0}, {1.0, 1.0}, {1.0, 0.0}, {0.0, 0.0}};
749  xms::VecPt3d2d in;
750  p1->Setup(out1, in);
751  xms::VecPt3d out2 = {{-1.0, -1.0}, {-1.0, 2.0}, {2.0, 2.0}, {2.0, -1.0}, {-1.0, -1.0}};
752  p2->Setup(out2, in);
753  std::vector<BSHP<xms::GmPolygon>> output;
754  p1->Union(*p2, output);
755  TS_ASSERT(output.size() == 1);
756  if (output.size() != 1)
757  return;
758  xms::VecPt3d base = out2;
759  xms::VecPt3d outputPts;
760  xms::VecPt3d2d outputPtsInPoly;
761  output[0]->GetPoints(outputPts, outputPtsInPoly);
762  double tol(1e-12);
763  TS_ASSERT_DELTA_VECPT3D(base, outputPts, tol);
764 
765  out2 = {{0.5, -1.0}, {0.5, 2.0}, {2.0, 2.0}, {2.0, -1.0}, {0.5, -1.0}};
766  p2->Setup(out2, in);
767  p1->Union(*p2, output);
768  TS_ASSERT(output.size() == 1);
769  if (output.size() != 1)
770  return;
771  base = {{0.5, 1.0}, {0.5, 2.0}, {2.0, 2.0}, {2.0, -1.0}, {0.5, -1.0},
772  {0.5, 0.0}, {0.0, 0.0}, {0.0, 1.0}, {0.5, 1.0}};
773  output[0]->GetPoints(outputPts, outputPtsInPoly);
774  tol = 1e-6;
775  TS_ASSERT_DELTA_VECPT3D(base, outputPts, tol);
776 
777  out2 = {{2.0, 0.0}, {2.0, 1.0}, {3.0, 1.0}, {3.0, 0.0}, {2.0, 0.0}};
778  p2->Setup(out2, in);
779  p1->Union(*p2, output);
780  TS_ASSERT(output.size() == 2);
781  output[0]->GetPoints(outputPts, outputPtsInPoly);
782  base = out1;
783  tol = 1e-12;
784  TS_ASSERT_DELTA_VECPT3D(base, outputPts, tol);
785  output[1]->GetPoints(outputPts, outputPtsInPoly);
786  base = out2;
787  TS_ASSERT_DELTA_VECPT3D(base, outputPts, tol);
788 } // GmPolygonUnitTests::testUnion
792 //------------------------------------------------------------------------------
795 //------------------------------------------------------------------------------
796 // virtual
797 #ifndef CXXTEST4
798 const CxxTest::TestGroup& GmPolygonIntermediateTests::group()
799 {
800  return *CxxTest::TestGroup::GetGroup(CxxTest::TG_INTERMEDIATE);
801 } // GmPolygonIntermediateTests::group
802 #endif
803 //------------------------------------------------------------------------------
807 // 30 - 45--44 41--40 37--36 33--32 29------28
808 // | | | | | | | | | | |
809 // 25 - 46 43--42 39--38 35--34 31--30 26--27
810 // | | |
811 // 20 - 47---48 2---3---4---5---6---7---8 25--24
812 // | | | | |
813 // 15 - 50---49 1 18---17 14---13 10---9 22--23
814 // | | | | | | | | |
815 // 10 - 51 0---19 16---15 12---11 21--20
816 // | | |
817 // 5 - 52 2---3 6---7 10--11 14--15 18--19
818 // | | | | | | | | | | |
819 // 0 - 0---1 4---5 8---9 12--13 16--17
820 //
821 // |---|---|---|---|---|---|---|---|---|---|
822 // 0 5 10 15 20 25 30 35 40 45 50 55
824 //------------------------------------------------------------------------------
826 {
827 #if BOOST_OS_WINDOWS
828 #ifndef _DEBUG
830  tester.DoTest();
831 #endif
832 #endif
833 } // GmPolygonIntermediateTests::testSpeed
834 
835 #endif // CXX_TEST
virtual void Setup()
Setup the polygons.
Definition: geoms.cpp:2190
virtual void Setup(const VecPt3d &a_poly, const VecPt3d2d &a_inPolys) override
Create a boost geometry polygon to use in point in polygon.
Definition: GmPolygon.cpp:117
Pt3< double > Pt3d
GmBstPoly3d m_poly
The boost geom polygon.
Definition: GmPolygon.cpp:62
void testNoHoles()
Test a simple polygon with some points outside, some inside, some on, and some coincident with polygo...
Definition: GmPolygon.cpp:397
virtual void GetPoints(VecPt3d &a_poly, VecPt3d2d &a_inPolys) const override
Get the points from a boost polygon as vectors of Pt3d.
Definition: GmPolygon.cpp:150
#define TS_ASSERT_DELTA_VECPT3D(a, b, delta)
Wraps a boost polygon for point in poly, min distance from point to poly etc.
Definition: GmPolygon.cpp:45
virtual void Setup() override
Sets things up.
Definition: GmPolygon.cpp:336
virtual const CxxTest::TestGroup & group()
Returns the test group.
Definition: GmPolygon.cpp:798
virtual bool Within(Pt3d a_point) const override
Tests if a_point is inside the polygon and not in a hole.
Definition: GmPolygon.cpp:188
GmPolygon()
Constructor.
Definition: GmPolygon.cpp:277
Interface to a boost::geometry::polygon class.
Definition: GmPolygon.h:34
boost::geometry types
static BSHP< GmPolygon > New()
Creates a class.
Definition: GmPolygon.cpp:290
void testSpeed()
Test lots of points for timing purposes. Only in release, not debug.
Definition: GmPolygon.cpp:825
static void SetUpPolyWithHole(xms::VecPt3d &a_outPoly, xms::VecPt3d &a_inPolys)
Used in tests to create a polygon with lots of segments and 2 holes.
Definition: GmPolygon.cpp:625
virtual void CheckPoint(const xms::Pt3d &a_pt) override
Checks if point is covered by the poly and updates status.
Definition: GmPolygon.cpp:348
virtual double MaxTime() override
Return the max time this test should ever take.
Definition: GmPolygon.cpp:358
void testIntersection()
tests intersection of polygons
Definition: GmPolygon.cpp:706
virtual bool CoveredBy(Pt3d a_point) const override
Tests if a_point is inside or on the polygon and not in a hole.
Definition: GmPolygon.cpp:169
std::vector< VecPt3d > VecPt3d2d
int m_status
Status (in, out, on) of at least one pt.
Definition: geoms.t.h:67
XM_DISALLOW_COPY_AND_ASSIGN(GmPointInPolyTester_GmPolygon)
Hide compiler generated copy and assign.
static void SetUpPolyWithHoles1(xms::VecPt3d &a_outPoly, xms::VecPt3d2d &a_inPolys, xms::VecPt3d &a_ptsToTest)
Used in tests to create a polygon with two holes.
Definition: GmPolygon.cpp:569
void DoTest()
Run the test. This is the main function to call.
Definition: geoms.cpp:2181
virtual ~GmPolygon()
Destructor.
Definition: GmPolygon.cpp:283
GmPointInPolyTester_GmPolygon()
Constructor.
Definition: GmPolygon.cpp:326
Functions dealing with geometry.
void testUnion()
tests union of polygons
Definition: GmPolygon.cpp:743
#define XM_ENSURE_TRUE(...)
std::vector< Pt3d > VecPt3d
BSHP< xms::GmPolygon > m_poly
Polygon to test.
Definition: GmPolygon.cpp:367
std::vector< xms::Pt3d > m_inPoly
Input polygon.
Definition: geoms.t.h:64
Used for speed tests of various point in poly functions / classes.
Definition: geoms.t.h:42
#define XM_COUNTOF(array)
GmPolygonImpl()
Constructor.
Definition: GmPolygon.cpp:104
virtual void Intersection(const GmPolygon &a_, std::vector< BSHP< GmPolygon >> &a_out) const override
Performs a polygon intersection.
Definition: GmPolygon.cpp:220
void testWithHoles()
Test a polygon with holes.
Definition: GmPolygon.cpp:485
#define TS_ASSERT_EQUALS_VEC(a, b)
std::vector< xms::Pt3d > m_outPoly
Output polygon.
Definition: geoms.t.h:63
void testMinDistanceToBoundary()
tests calculating the minimum distance to the boundary of a polygon.
Definition: GmPolygon.cpp:672
virtual double MinDistanceToBoundary(Pt3d a_pt) const override
Computes the min distance from a point to a polygon.
Definition: GmPolygon.cpp:203
Helper class for testing GmPolygon.
Definition: GmPolygon.cpp:320
virtual void Union(const GmPolygon &a_, std::vector< BSHP< GmPolygon >> &a_out) const override
Performs a polygon union.
Definition: GmPolygon.cpp:247