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