xmsmesh  1.0
MeIntersectPolys.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 
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 #pragma warning(disable : 4267) // boost code: size_t to const int
23 #include <boost/geometry/geometry.hpp>
24 #pragma warning(pop)
25 #include <boost/unordered_set.hpp>
26 
27 // 5. Shared code headers
28 #include <xmsinterp/geometry/GmBoostTypes.h> // GmBstPoly3d, XmBstRing
30 #include <xmscore/misc/XmError.h>
31 #include <xmscore/stl/vector.h>
32 
33 // 6. Non-shared code headers
34 
35 //----- Forward declarations ---------------------------------------------------
36 
37 //----- External globals -------------------------------------------------------
38 
39 //----- Namespace declaration --------------------------------------------------
40 namespace xms
41 {
42 //----- Constants / Enumerations -----------------------------------------------
43 
44 //----- Classes / Structs ------------------------------------------------------
45 namespace
46 {
47 namespace bg = boost::geometry;
48 
49 #define T_TOL 1e-13
50 #define TOLERANCE 1e9
51 } // unnamed namespace
52 
54 {
55 public:
56  impl() {}
57 
58  void SetupInIn(const std::vector<MePolyOffsetterOutput>& a_offsets, double a_xyTol);
59  void SetupInOut(const MePolyOffsetterOutput& a_offsets, double a_xyTol);
60  void InInTrivialPolyCases();
61  void InInDoIntersection();
62  void InOutDoIntersection();
63  void FillOutput(MePolyOffsetterOutput& a_out);
64  void ClassifyPolys(const MePolyOffsetterOutput& a_input,
65  std::vector<std::vector<size_t>>& a_output);
66 
67  void OnSetup();
68  void ClassifyDisjointPolys(SetIdx& a_delPolys);
69  void ClassifyPolysInsideOfPolys(SetIdx& a_delPolys);
70  void UpdateInPolyLoopsFromHash(const std::vector<size_t>& a_idx);
72  std::vector<size_t> InOutFindIntersectingPolys(size_t a_poly);
73  void FillPolysInsideOfPolys(std::set<size_t>& a_oPoly,
74  std::set<size_t>& a_psetUsed,
75  std::vector<std::vector<size_t>>& a_output);
76 
77  GmBstPoly3d BoostPoly(size_t a_loopIdx);
78  bool BoostPolyUnion(size_t a_i, size_t a_j);
79  bool BoostPolySubtract(size_t a_i, size_t a_j);
80 
81  void DeleteBad_NEWOUT_POLY(MePolyOffsetterOutput& a_out, const VecPt3d& a_origOutsidePoly);
82 
84  std::vector<std::vector<size_t>> m_loops;
85  std::vector<int> m_loopTypes;
86  std::vector<GmBstBox3d> m_envelopes;
87  std::list<size_t> m_stack;
89 
90  std::vector<GmBstPoly3d> m_bPolys;
91  std::vector<GmBstPoly3d> m_bOutPolys;
92  std::vector<int> m_bOutPolyType;
93 
95 
96  // used by intersect IN wth IN
98  boost::unordered_set<std::pair<size_t, size_t>> m_polyInsideOfPoly;
99 };
100 //----- Internal functions -----------------------------------------------------
101 
102 //----- Class / Function definitions -------------------------------------------
103 //------------------------------------------------------------------------------
109 //------------------------------------------------------------------------------
110 static GmBstBox3d iCalcPolyEnvelope(const std::vector<size_t>& a_loop,
111  const std::vector<Pt3d>& a_pts)
112 {
113  GmBstBox3d b;
114  if (a_loop.empty() || a_pts.empty())
115  return b;
116 
117  b.min_corner() = b.max_corner() = a_pts[a_loop[0]];
118  b.min_corner().z = b.max_corner().z = 0;
119  for (size_t j = 1; j < a_loop.size(); ++j)
120  {
121  const Pt3d& p(a_pts[a_loop[j]]);
122  if (b.min_corner().x > p.x)
123  b.min_corner().x = p.x;
124  if (b.max_corner().x < p.x)
125  b.max_corner().x = p.x;
126  if (b.min_corner().y > p.y)
127  b.min_corner().y = p.y;
128  if (b.max_corner().y < p.y)
129  b.max_corner().y = p.y;
130  }
131  return b;
132 } // iCalcPolyEnvelope
133 //------------------------------------------------------------------------------
140 //------------------------------------------------------------------------------
141 static bool iEnvelopesOverlap(size_t a_i,
142  size_t a_j,
143  const std::vector<GmBstBox3d>& a_iEnv,
144  const std::vector<GmBstBox3d>& a_jEnv)
145 {
146  const Pt3d &iMin(a_iEnv[a_i].min_corner()), &iMax(a_iEnv[a_i].max_corner()),
147  &jMin(a_jEnv[a_j].min_corner()), &jMax(a_jEnv[a_j].max_corner());
148  if (iMax.x > jMin.x && iMin.x < jMax.x && iMax.y > jMin.y && iMin.y < jMax.y)
149  return true;
150  return false;
151 } // iEnvelopesOverlap
152 //------------------------------------------------------------------------------
158 //------------------------------------------------------------------------------
159 static bool iEnvelopeInsideOfEnvelope(size_t a_i,
160  size_t a_j,
161  const std::vector<GmBstBox3d>& a_envelopes)
162 {
163  const Pt3d &iMin(a_envelopes[a_i].min_corner()), &iMax(a_envelopes[a_i].max_corner()),
164  &jMin(a_envelopes[a_j].min_corner()), &jMax(a_envelopes[a_j].max_corner());
165  if (jMin.x >= iMin.x && jMin.y >= iMin.y && jMax.x <= iMax.x && jMax.y <= iMax.y)
166  return true;
167  return false;
168 } // iEnvelopeInsideOfEnvelope
169 
170 //------------------------------------------------------------------------------
172 //------------------------------------------------------------------------------
174 : m_p(new MeIntersectPolys::impl())
175 {
176 } // MpInsidePolys::MpInsidePolys
177 //------------------------------------------------------------------------------
179 //------------------------------------------------------------------------------
181 {
182  if (m_p)
183  delete (m_p);
184 } // MpInsidePolys::MpInsidePolys
185 //------------------------------------------------------------------------------
190 //------------------------------------------------------------------------------
191 void MeIntersectPolys::SetupInIn(const std::vector<MePolyOffsetterOutput>& a_offsets,
192  double a_xyTol)
193 {
194  m_p->SetupInIn(a_offsets, a_xyTol);
195 } // InsidePolys::SetupInIn
196 //------------------------------------------------------------------------------
200 //------------------------------------------------------------------------------
201 void MeIntersectPolys::SetupInOut(const MePolyOffsetterOutput& a_offsets, double a_xyTol)
202 {
203  m_p->SetupInOut(a_offsets, a_xyTol);
204 } // InsidePolys::SetupInOut
205 //------------------------------------------------------------------------------
207 //------------------------------------------------------------------------------
209 {
210  m_p->m_envelopes.resize(0);
211  for (size_t i = 0; i < m_p->m_loops.size(); ++i)
212  {
214  }
215 } // InsidePolys::CalcEnvelopes
216 //------------------------------------------------------------------------------
218 //------------------------------------------------------------------------------
220 {
222 } // InsidePolys::InInTrivialPolyCases
223 //------------------------------------------------------------------------------
225 //------------------------------------------------------------------------------
227 {
229 } // InsidePolys::InInDoIntersection
230 //------------------------------------------------------------------------------
232 //------------------------------------------------------------------------------
234 {
236 } // InsidePolys::InOutDoIntersection
237 //------------------------------------------------------------------------------
241 //------------------------------------------------------------------------------
243 {
244  m_p->FillOutput(a_out);
245 } // MpInsidePolys::FillOutput
246 //------------------------------------------------------------------------------
251 //------------------------------------------------------------------------------
253  std::vector<std::vector<size_t>>& a_output)
254 {
255  m_p->ClassifyPolys(a_input, a_output);
256 } // MpInsidePolys::ClassifyPolys
257 //------------------------------------------------------------------------------
262 //------------------------------------------------------------------------------
264  const VecPt3d& a_origOutsidePoly)
265 {
266  m_p->DeleteBad_NEWOUT_POLY(a_out, a_origOutsidePoly);
267 } // MpInsidePolys::DeleteBad_NEWOUT_POLY
268 
273 //------------------------------------------------------------------------------
278 //------------------------------------------------------------------------------
279 void MeIntersectPolys::impl::SetupInIn(const std::vector<MePolyOffsetterOutput>& a_offsets,
280  double a_xyTol)
281 {
282  m_polyPts.XyTol() = a_xyTol;
283  auto moveToOut = [this](const MePolyOffsetterOutput& o, size_t j, size_t start) {
284  m_out.m_loopTypes.push_back(o.m_loopTypes[j]);
285  m_out.m_loops.push_back(o.m_loops[j]);
286  for (size_t k = 0; start > 0 && k < m_out.m_loops.back().size(); ++k)
287  {
288  m_out.m_loops.back()[k] += start;
289  }
290  };
291 
292  // get all points of INSIDE_POLY polys and put into a single
293  // array and update indexes for segment definitions.
294  std::vector<Pt3d>& pts(m_polyPts.Pts());
295  for (size_t i = 0; i < a_offsets.size(); ++i)
296  {
297  const MePolyOffsetterOutput& o(a_offsets[i]);
298  std::vector<GmBstPoly3d> newOutPolys;
299  // add the points and INSIDE_POLY loops, but don' t add INSIDE_POLY that are in NEWOUT_POLY
300  size_t start = pts.size();
301  pts.insert(pts.end(), o.m_pts.begin(), o.m_pts.end());
302  for (size_t j = 0; j < o.m_loops.size(); ++j)
303  {
304  // move to output
305  if (MePolyOffsetter::OUTSIDE_POLY == o.m_loopTypes[j] ||
306  MePolyOffsetter::NEWOUT_POLY == o.m_loopTypes[j])
307  {
308  moveToOut(o, j, start);
309  if (MePolyOffsetter::NEWOUT_POLY == o.m_loopTypes[j])
310  {
311  // create a polygon to be used later when checking INSIDE_POLY polys
312  GmBstPoly3d bPoly;
313  const std::vector<size_t>& l(o.m_loops[j]);
314  std::vector<size_t>::const_iterator it(l.begin()), iend(l.end());
315  for (; it != iend; ++it)
316  {
317  bg::exterior_ring(bPoly).push_back(pts[*it]);
318  }
319  bg::exterior_ring(bPoly).push_back(pts[l[0]]);
320  newOutPolys.push_back(bPoly);
321  }
322  }
323  }
324 
325  for (size_t j = 0; j < o.m_loops.size(); ++j)
326  {
327  if (MePolyOffsetter::OUTSIDE_POLY == o.m_loopTypes[j] ||
328  MePolyOffsetter::NEWOUT_POLY == o.m_loopTypes[j])
329  {
330  continue;
331  }
332 
333  // make sure the INSIDE_POLY is not inside of a NEWOUT_POLY
334  bool moveToOutput(false);
335  Pt3d& p0(pts[o.m_loops[j][0]]);
336  for (size_t k = 0; !moveToOutput && k < newOutPolys.size(); ++k)
337  {
338  if (bg::within(p0, newOutPolys[k]))
339  moveToOutput = true;
340  }
341  if (moveToOutput)
342  {
343  moveToOut(o, j, start);
344  continue;
345  }
346 
347  m_loops.push_back(o.m_loops[j]);
348  for (size_t k = 0; start > 0 && k < m_loops.back().size(); ++k)
349  {
350  m_loops.back()[k] += start;
351  }
352  }
353  }
354  OnSetup();
355 } // InsidePolys::impl::SetupInIn
356 //------------------------------------------------------------------------------
358 //------------------------------------------------------------------------------
360 {
361  // hash the points and handle duplicates
362  std::vector<size_t> idx(m_polyPts.HashPts());
363  // update inside poly loops with indexes from hashing
364  UpdateInPolyLoopsFromHash(idx);
365  // create boost polygons
366  for (size_t i = 0; i < m_loops.size(); ++i)
367  {
368  m_bPolys.push_back(BoostPoly(i));
369  }
370 } // MeIntersectPolys::impl::OnSetup
371 //------------------------------------------------------------------------------
375 //------------------------------------------------------------------------------
376 void MeIntersectPolys::impl::SetupInOut(const MePolyOffsetterOutput& a_offsets, double a_xyTol)
377 {
378  m_polyPts.XyTol() = a_xyTol;
379  // get all points of OUTSIDE_POLY & INSIDE_POLY polys and put into a single
380  // array and update indexes for segment definitions.
381  std::vector<Pt3d>& pts(m_polyPts.Pts());
382  const MePolyOffsetterOutput& o(a_offsets);
383  pts.insert(pts.end(), o.m_pts.begin(), o.m_pts.end());
384  for (size_t j = 0; j < o.m_loops.size(); ++j)
385  {
386  if (MePolyOffsetter::NEWOUT_POLY == o.m_loopTypes[j])
387  {
388  m_out.m_loopTypes.push_back(o.m_loopTypes[j]);
389  m_out.m_loops.push_back(o.m_loops[j]);
390  continue;
391  }
392  m_loops.push_back(o.m_loops[j]);
393  m_loopTypes.push_back(o.m_loopTypes[j]);
394  }
395  OnSetup();
396 } // MeIntersectPolys::impl::SetupInOut
397 //------------------------------------------------------------------------------
403 //------------------------------------------------------------------------------
405 {
406  SetIdx delPolys;
407  ClassifyDisjointPolys(delPolys);
408  ClassifyPolysInsideOfPolys(delPolys);
409  ClassifyDisjointPolys(delPolys);
410 
411  // sort the remaining polys based on area of envelope and build a stack
412  // to process
413  std::multimap<double, size_t> areaMap;
414  std::vector<GmBstBox3d>& env(m_envelopes);
415  for (size_t i = 0; i < env.size(); ++i)
416  {
417  if (delPolys.find(i) == delPolys.end())
418  {
419  GmBstBox3d& b(env[i]);
420  double area = (b.max_corner().x - b.min_corner().x) * (b.max_corner().y - b.min_corner().y);
421  areaMap.insert(std::make_pair(area, i));
422  }
423  }
424  std::multimap<double, size_t>::reverse_iterator rit = areaMap.rbegin();
425  for (; rit != areaMap.rend(); ++rit)
426  {
427  m_stack.push_back(rit->second);
428  }
429 } // InsidePolys::impl::InInTrivialPolyCases
430 //------------------------------------------------------------------------------
439 //------------------------------------------------------------------------------
441 {
442  while (!m_stack.empty())
443  {
444  std::list<size_t>::iterator it = m_stack.begin();
445  size_t idx = *it, idx2;
446 
447  bool processed = false;
448  std::list<size_t>::iterator it2 = it;
449  ++it2;
450  while (!processed && it2 != m_stack.end())
451  {
452  idx2 = *it2;
453  // find potentially intersecting poly
454  if (iEnvelopesOverlap(idx, idx2, m_envelopes, m_envelopes))
455  { // process the 2 polygons. If they intersect a new poly is created and
456  // the original 2 are removed from the stack. A new OUTSIDE_POLY can
457  // also be created in this process; it is moved to the output
458  processed = BoostPolyUnion(idx, idx2);
459  }
460  if (processed)
461  {
462  m_stack.erase(it);
463  m_stack.erase(it2);
464  }
465  else
466  ++it2;
467  }
468 
469  if (!processed)
470  { // move this loop to the output
471  m_stack.pop_front();
472  m_bOutPolys.push_back(m_bPolys[idx]);
473  m_bOutPolyType.push_back(MePolyOffsetter::INSIDE_POLY);
474  }
475  }
476 } // InsidePolys::impl::InInDoIntersection
477 //------------------------------------------------------------------------------
486 //------------------------------------------------------------------------------
488 {
489  InOutCalcStartingStack();
490  while (!m_stack.empty())
491  {
492  std::list<size_t>::iterator it = m_stack.begin();
493  size_t idx = *it;
494  std::vector<size_t> polys(InOutFindIntersectingPolys(idx));
495 
496  bool processed(false);
497  for (size_t i = 0; i < polys.size(); ++i)
498  {
499  if (BoostPolySubtract(polys[i], idx))
500  {
501  processed = true;
502  }
503  }
504  m_stack.pop_front();
505  if (!processed)
506  { // move this loop to the output
507  m_bOutPolys.push_back(m_bPolys[idx]);
508  m_bOutPolyType.push_back(MePolyOffsetter::INSIDE_POLY);
509  }
510  }
511  // move the left over OUTSIDE_POLY to the output
512  SetIdx::iterator it(m_inOutOpolys.begin()), iend(m_inOutOpolys.end());
513  for (; it != iend; ++it)
514  {
515  m_bOutPolys.push_back(m_bPolys[*it]);
516  m_bOutPolyType.push_back(MePolyOffsetter::OUTSIDE_POLY);
517  }
518 } // MeIntersectPolys::impl::InOutDoIntersection
519 //------------------------------------------------------------------------------
523 //------------------------------------------------------------------------------
525 {
526  a_out = m_out;
527  // put the boost polys into the output
528  std::vector<size_t> loop;
529  for (size_t i = 0; i < m_bOutPolys.size(); ++i)
530  {
531  GmBstPoly3d& p(m_bOutPolys[i]);
532  loop.resize(0);
533  if (m_bOutPolyType[i] == MePolyOffsetter::INSIDE_POLY)
534  {
535  for (size_t j = 1; j < p.outer().size(); ++j)
536  {
537  Pt3d& pt(p.outer()[j]);
538  size_t idx = m_polyPts.IdxFromPt3d(pt);
539  loop.push_back(idx);
540  }
541  std::reverse(loop.begin(), loop.end());
542  // add inner rings as NEWOUT_POLY polygons
543  if (!p.inners().empty())
544  {
545  for (size_t j = 0; j < p.inners().size(); ++j)
546  {
547  std::vector<size_t> iPolyLoop;
548  VecPt3d& iPoly(p.inners()[j]);
549  for (size_t k = 0; k < iPoly.size() - 1; ++k)
550  {
551  size_t idx = m_polyPts.IdxFromPt3d(iPoly[k]);
552  iPolyLoop.push_back(idx);
553  }
554  std::reverse(iPolyLoop.begin(), iPolyLoop.end());
555  a_out.m_loops.push_back(iPolyLoop);
556  a_out.m_loopTypes.push_back(MePolyOffsetter::NEWOUT_POLY);
557  }
558  }
559  }
560  else
561  {
562  for (size_t j = 0; j < p.outer().size() - 1; ++j)
563  {
564  Pt3d& pt(p.outer()[j]);
565  size_t idx = m_polyPts.IdxFromPt3d(pt);
566  loop.push_back(idx);
567  }
568  }
569  a_out.m_loops.push_back(loop);
570  a_out.m_loopTypes.push_back(m_bOutPolyType[i]);
571  }
572  a_out.m_pts = m_polyPts.Pts();
573 } // MpInsidePolys::impl::FillOutput
574 //------------------------------------------------------------------------------
583 //------------------------------------------------------------------------------
584 void MeIntersectPolys::impl::FillPolysInsideOfPolys(std::set<size_t>& a_oPoly,
585  std::set<size_t>& a_psetUsed,
586  std::vector<std::vector<size_t>>& a_output)
587 {
588  std::vector<Pt3d>& pts(m_polyPts.Pts());
589  std::set<size_t>::iterator it(a_oPoly.begin()), itend(a_oPoly.end()), usedEnd(a_psetUsed.end());
590  for (; it != itend; ++it)
591  {
592  GmBstPoly3d poly = BoostPoly(*it);
593  a_output.push_back(std::vector<size_t>());
594  a_output.back().push_back(*it);
595  // for this method, no polygons should intersect so we just need to see
596  // if the first point of a polygon is inside of this polygon
597  for (size_t i = 0; i < m_loops.size(); ++i)
598  {
599  if (a_psetUsed.find(i) != usedEnd)
600  continue;
601 
602  Pt3d& p(pts[m_loops[i].front()]);
603  if (bg::within(p, poly))
604  {
605  a_output.back().push_back(i);
606  a_psetUsed.insert(i);
607  }
608  }
609  }
610 } // MeIntersectPolys::impl::FillPolysInsideOfPolys
611 //------------------------------------------------------------------------------
616 //------------------------------------------------------------------------------
618  std::vector<std::vector<size_t>>& a_output)
619 {
620  a_output.resize(0);
621  m_polyPts.Pts() = a_input.m_pts;
622  m_loops = a_input.m_loops;
623  m_loopTypes = a_input.m_loopTypes;
624 
625  std::set<size_t> psetNewOut, psetOut, psetUsed;
626  // first find all NEWOUT_POLY polygons
627  for (size_t i = 0; i < m_loopTypes.size(); ++i)
628  {
629  if (MePolyOffsetter::NEWOUT_POLY == m_loopTypes[i])
630  {
631  psetNewOut.insert(i);
632  psetUsed.insert(i);
633  }
634  else if (MePolyOffsetter::OUTSIDE_POLY == m_loopTypes[i])
635  {
636  psetOut.insert(i);
637  psetUsed.insert(i);
638  }
639  }
640  // find INSIDE_POLY that are inside of NEWOUT_POLY
641  FillPolysInsideOfPolys(psetNewOut, psetUsed, a_output);
642  // find INSIDE_POLY that are inside of OUTSIDE_POLY
643  FillPolysInsideOfPolys(psetOut, psetUsed, a_output);
644 } // MeIntersectPolys::impl::ClassifyPolys
645 //------------------------------------------------------------------------------
650 //------------------------------------------------------------------------------
652 {
653  std::vector<GmBstBox3d>& env(m_envelopes);
654  // find polys that are completely out of other poly envelopes
655  std::vector<int> overlaps(env.size(), 0);
656  for (size_t i = 0; i < env.size(); ++i)
657  {
658  if (a_delPolys.find(i) != a_delPolys.end())
659  continue;
660 
661  for (size_t j = 0; j < env.size(); j++)
662  {
663  if (i == j)
664  continue;
665  if (overlaps[j])
666  continue;
667  if (a_delPolys.find(j) != a_delPolys.end())
668  continue;
669 
670  if (iEnvelopesOverlap(i, j, env, env))
671  {
672  overlaps[i] = overlaps[j] = 1;
673  }
674  }
675  }
676  for (size_t i = 0; i < overlaps.size(); ++i)
677  { // anything that doesn't overlap move to the output and mark the poly
678  // as deleted
679  if (!overlaps[i] && a_delPolys.find(i) == a_delPolys.end())
680  {
681  m_out.m_loops.push_back(m_loops[i]);
682  m_out.m_loopTypes.push_back(MePolyOffsetter::INSIDE_POLY);
683  a_delPolys.insert(i);
684  }
685  }
686 } // InsidePolys::impl::ClassifyDisjointPolys
687 //------------------------------------------------------------------------------
692 //------------------------------------------------------------------------------
694 {
695  std::vector<GmBstBox3d>& env(m_envelopes);
696  for (size_t i = 0; i < env.size(); ++i)
697  {
698  if (a_delPolys.find(i) != a_delPolys.end())
699  continue;
700 
701  for (size_t j = 0; j < env.size(); j++)
702  {
703  if (i == j)
704  continue;
705  if (a_delPolys.find(j) != a_delPolys.end())
706  continue;
707 
708  if (iEnvelopeInsideOfEnvelope(i, j, env))
709  {
710  if (m_polyPts.PolyInsideOfPoly(m_loops[i], m_loops[j]))
711  {
712  m_polyInsideOfPoly.insert(std::make_pair(i, j));
713  // make sure the poly is not inside of an NEWOUT_POLY
714  bool inNewOut(false);
715  for (size_t k = 0; !inNewOut && k < m_out.m_loops.size(); ++k)
716  {
717  if (m_out.m_loopTypes[k] == MePolyOffsetter::NEWOUT_POLY)
718  {
719  std::vector<size_t> idx(m_out.m_loops[k]);
720  std::reverse(idx.begin(), idx.end());
721  if (m_polyPts.PolyInsideOfPoly(idx, m_loops[j]))
722  {
723  inNewOut = true;
724  }
725  }
726  }
727  if (!inNewOut)
728  a_delPolys.insert(j);
729  }
730  }
731  }
732  }
733 } // MeIntersectPolys::impl::ClassifyPolysInsideOfPolys
734 //------------------------------------------------------------------------------
740 //------------------------------------------------------------------------------
741 void MeIntersectPolys::impl::UpdateInPolyLoopsFromHash(const std::vector<size_t>& a_idx)
742 {
743  size_t idx;
744  std::vector<std::vector<size_t>>& loops(m_loops);
745  for (size_t i = 0; i < loops.size(); ++i)
746  {
747  for (size_t j = 0; j < loops[i].size(); ++j)
748  {
749  idx = loops[i][j];
750  loops[i][j] = a_idx[idx];
751  }
752  }
753 } // InsidePolys::impl::UpdateInPolyLoopsFromHash
754 //------------------------------------------------------------------------------
759 //------------------------------------------------------------------------------
761 {
762  std::vector<size_t> inPolys;
763  for (size_t i = 0; i < m_loopTypes.size(); ++i)
764  {
765  if (MePolyOffsetter::OUTSIDE_POLY == m_loopTypes[i])
766  m_inOutOpolys.insert(i);
767  else if (MePolyOffsetter::INSIDE_POLY == m_loopTypes[i])
768  inPolys.push_back(i);
769  }
770  // sort the polys by envelope size
771  std::multimap<double, size_t> areaMap;
772  for (size_t i = 0; i < inPolys.size(); ++i)
773  {
774  GmBstBox3d& b(m_envelopes[inPolys[i]]);
775  double area = (b.max_corner().x - b.min_corner().x) * (b.max_corner().y - b.min_corner().y);
776  areaMap.insert(std::make_pair(area, inPolys[i]));
777  }
778  std::multimap<double, size_t>::reverse_iterator rit = areaMap.rbegin();
779  for (; rit != areaMap.rend(); ++rit)
780  {
781  m_stack.push_back(rit->second);
782  }
783 } // MeIntersectPolys::impl::InOutCalcStartingStack
784 //------------------------------------------------------------------------------
789 //------------------------------------------------------------------------------
790 std::vector<size_t> MeIntersectPolys::impl::InOutFindIntersectingPolys(size_t a_poly)
791 {
792  std::vector<size_t> outPolys;
793  // find potentially intersecting OUTSIDE_POLY
794  std::vector<GmBstBox3d>& env(m_envelopes);
795  SetIdx::iterator it(m_inOutOpolys.begin()), iend(m_inOutOpolys.end());
796  for (; it != iend; ++it)
797  {
798  if (iEnvelopesOverlap(a_poly, *it, env, env))
799  {
800  if (!m_polyPts.PolyInsideOfPoly(m_bPolys[*it].outer(), m_loops[a_poly]))
801  {
802  outPolys.push_back(*it);
803  }
804  }
805  }
806  return outPolys;
807 } // MeIntersectPolys::impl::InOutFindIntersectingPolys
808 //------------------------------------------------------------------------------
814 //------------------------------------------------------------------------------
816 {
817  GmBstPoly3d poly;
818  std::vector<Pt3d>& pts(m_polyPts.Pts());
819  std::vector<size_t>& l(m_loops[a_loopIdx]);
820  if (m_loopTypes.empty() || m_loopTypes[a_loopIdx] == MePolyOffsetter::INSIDE_POLY)
821  {
822  std::vector<size_t>::reverse_iterator it(l.rbegin()), iend(l.rend());
823  bg::exterior_ring(poly).push_back(pts[l[0]]);
824  for (; it != iend; ++it)
825  {
826  bg::exterior_ring(poly).push_back(pts[*it]);
827  }
828  }
829  else
830  {
831  std::vector<size_t>::iterator it(l.begin()), iend(l.end());
832  for (; it != iend; ++it)
833  {
834  bg::exterior_ring(poly).push_back(pts[*it]);
835  }
836  bg::exterior_ring(poly).push_back(pts[l[0]]);
837  }
838  return poly;
839 } // MeIntersectPolys::impl::BoostPoly
840 //------------------------------------------------------------------------------
845 //------------------------------------------------------------------------------
846 bool MeIntersectPolys::impl::BoostPolyUnion(size_t a_i, size_t a_j)
847 {
848  std::vector<GmBstPoly3d> out;
849  GmBstPoly3d &iPoly(m_bPolys[a_i]), &jPoly(m_bPolys[a_j]);
850  std::pair<size_t, size_t> p1(a_i, a_j), p2(a_j, a_i);
851  if (m_polyInsideOfPoly.find(p1) != m_polyInsideOfPoly.end() ||
852  m_polyInsideOfPoly.find(p2) != m_polyInsideOfPoly.end())
853  return false;
854  bg::union_(iPoly, jPoly, out);
855  if (out.size() != 1)
856  return false;
857  m_stack.push_back(m_bPolys.size());
858  m_bPolys.push_back(out[0]);
859  // do not remove inner polygons
860  // m_bPolys.back().inners().clear();
861  std::vector<Pt3d>& pts(m_bPolys.back().outer());
862  std::vector<size_t> loop(pts.size());
863  for (size_t i = 0; i < loop.size(); ++i)
864  loop[i] = i;
865  m_envelopes.push_back(iCalcPolyEnvelope(loop, pts));
866 #if 0
867  // put any inner polygons into the output
868  for (size_t i = 0; i < out[0].inners().size(); ++i)
869  {
870  GmBstPoly3d innerPoly;
871  std::vector<Pt3d>& vi(out[0].inners()[i]);
872  std::vector<Pt3d>::reverse_iterator it(vi.rbegin()), iend(vi.rend());
873  for (; it != iend; ++it)
874  {
875  bg::exterior_ring(innerPoly).push_back(*it);
876  }
877  m_bOutPolys.push_back(innerPoly);
878  m_bOutPolyType.push_back(MePolyOffsetter::NEWOUT_POLY);
879  }
880 #endif
881  return true;
882 } // MeIntersectPolys::impl::BoostPolyUnion
883 //------------------------------------------------------------------------------
889 //------------------------------------------------------------------------------
890 bool MeIntersectPolys::impl::BoostPolySubtract(size_t a_i, size_t a_j)
891 {
892  std::vector<GmBstPoly3d> out;
893  GmBstPoly3d &iPoly(m_bPolys[a_i]), &jPoly(m_bPolys[a_j]);
894  if (!bg::intersects(iPoly, jPoly))
895  return false;
896  bg::difference(iPoly, jPoly, out);
897  m_inOutOpolys.erase(a_i);
898  for (size_t i = 0; i < out.size(); ++i)
899  {
900  m_inOutOpolys.insert(m_bPolys.size());
901  m_bPolys.push_back(out[i]);
902  m_bPolys.back().inners().clear();
903  std::vector<Pt3d>& pts(m_bPolys.back().outer());
904  std::vector<size_t> loop(pts.size());
905  for (size_t i = 0; i < loop.size(); ++i)
906  loop[i] = i;
907  m_envelopes.push_back(iCalcPolyEnvelope(loop, pts));
908  m_loopTypes.push_back(MePolyOffsetter::OUTSIDE_POLY);
909  }
910  return true;
911 } // MeIntersectPolys::impl::BoostPolyUnion
912 //------------------------------------------------------------------------------
918 //------------------------------------------------------------------------------
920  const VecPt3d& a_origOutsidePoly)
921 {
922  if (a_origOutsidePoly.empty())
923  return;
924 
925  // get the OUTSIDE_POLY polygons
926  std::set<size_t> newOutPolys, polysToDelete;
927  for (size_t i = 0; i < a_out.m_loopTypes.size(); ++i)
928  {
929  if (MePolyOffsetter::NEWOUT_POLY == a_out.m_loopTypes[i])
930  newOutPolys.insert(i);
931  }
932 
933  if (newOutPolys.empty())
934  return;
935 
936  // make a boost polygon from the outside polygon
937  GmBstPoly3d oPoly;
938  for (size_t i = 0; i < a_origOutsidePoly.size(); ++i)
939  {
940  bg::exterior_ring(oPoly).push_back(a_origOutsidePoly[i]);
941  }
942  bg::exterior_ring(oPoly).push_back(a_origOutsidePoly[0]);
943 
944  VecPt3d& pts(a_out.m_pts);
945  // now check the NEWOUT_POLY polygons to see if any points are outside the
946  // outside polygon
947  for (const auto& newOutPolyIdx : newOutPolys)
948  {
949  if (polysToDelete.find(newOutPolyIdx) != polysToDelete.end())
950  continue;
951 
952  bool pointOutside(false);
953  std::vector<size_t>& l1(a_out.m_loops[newOutPolyIdx]);
954  for (size_t i = 0; !pointOutside && i < l1.size(); ++i)
955  {
956  Pt3d& p(pts[l1[i]]);
957  if (!bg::covered_by(p, oPoly))
958  pointOutside = true;
959  }
960  if (pointOutside)
961  polysToDelete.insert(newOutPolyIdx);
962  }
963 
964  // delete polygons
965  auto rit = polysToDelete.rbegin(), rend = polysToDelete.rend();
966  for (; rit != rend; ++rit)
967  {
968  a_out.m_loops[*rit] = a_out.m_loops.back();
969  a_out.m_loops.pop_back();
970  a_out.m_loopTypes[*rit] = a_out.m_loopTypes.back();
971  a_out.m_loopTypes.pop_back();
972  }
973 } // MeIntersectPolys::impl::DeleteBad_NEWOUT_POLY
974 
975 } // namespace xms
976 
977 #ifdef CXX_TEST
978 
981 
983 
984 // namespace xms {
985 using namespace xms;
986 
991 //------------------------------------------------------------------------------
993 //------------------------------------------------------------------------------
995 {
996  // x = 0 4 8
997  //
998  // y=4 5----------------------------------6
999  // | |
1000  // | 15------14 |
1001  // | 1-----------2 | | |
1002  // | | | 12------13 |
1003  // | | 19---18 | |
1004  // y=2 | | | | | 8------11 |
1005  // | | 16---17 | | | |
1006  // | | | | | |
1007  // | 0-----------3 9------10 |
1008  // | |
1009  // y=0 4----------------------------------7
1010  //
1011  // Poly 0,1,2,3 is a NEWOUT_POLY, 4,5,6,7 is OUTSIDE_POLY
1012  // all the others are INSIDE_POLY
1013  //
1014  MePolyOffsetterOutput o, o1;
1015  o.m_pts = {{1, 1, 0}, {1, 3, 0}, {4, 3, 0}, {4, 1, 0}, {0, 0, 0},
1016  {0, 4, 0}, {8, 4, 0}, {8, 0, 0}, {5, 1, 0}, {7, 1, 0},
1017  {7, 2, 0}, {5, 2, 0}, {5, 3, 0}, {7, 3, 0}, {7, 3.5, 0},
1018  {5, 3.5, 0}, {1.5, 1.5, 0}, {3.5, 1.5, 0}, {3.5, 2.5, 0}, {1.5, 2.5, 0}};
1019  std::vector<size_t> v0 = {0, 1, 2, 3};
1020  o.m_loops.push_back(v0);
1021  std::vector<size_t> v1 = {4, 5, 6, 7};
1022  o.m_loops.push_back(v1);
1023  std::vector<size_t> v2 = {8, 9, 10, 11};
1024  o.m_loops.push_back(v2);
1025  std::vector<size_t> v3 = {12, 13, 14, 15};
1026  o.m_loops.push_back(v3);
1027  std::vector<size_t> v4 = {16, 17, 18, 19};
1028  o.m_loops.push_back(v4);
1029  o.m_loopTypes.assign(5, MePolyOffsetter::INSIDE_POLY);
1030  o.m_loopTypes[0] = MePolyOffsetter::NEWOUT_POLY;
1031  o.m_loopTypes[1] = MePolyOffsetter::OUTSIDE_POLY;
1032  std::vector<std::vector<size_t>> output;
1034  pc.ClassifyPolys(o, output);
1035  TS_ASSERT_EQUALS(2, output.size());
1036  if (2 != output.size())
1037  return;
1038  std::vector<size_t> baseIdx = {0, 4};
1039  TS_ASSERT_EQUALS_VEC(baseIdx, output[0]);
1040  baseIdx = {1, 2, 3};
1041  TS_ASSERT_EQUALS_VEC(baseIdx, output[1]);
1042 } // MeIntersectPolysUnitTests::testClassify
1043 
1044 //} // namespace xms
1045 #endif
std::vector< GmBstPoly3d > m_bOutPolys
boost::geometry::polygon
boost::geometry::model::box< Pt3d > GmBstBox3d
void ClassifyPolys(const MePolyOffsetterOutput &a_input, std::vector< std::vector< size_t >> &a_output)
calls implementation
void FillOutput(MePolyOffsetterOutput &a_out)
calls implementation
void SetupInOut(const MePolyOffsetterOutput &a_offsets, double a_xyTol)
Setup for InOutDoIntersection.
void SetupInOut(const MePolyOffsetterOutput &a_offsets, double a_xyTol)
calls implementation
void InInTrivialPolyCases()
calls implementation
void InOutDoIntersection()
calls implementation
Does polygon intersection for MePolyCleaner.
MeIntersectPolys()
Constructor.
bool BoostPolySubtract(size_t a_i, size_t a_j)
Performs a subtraction with 2 polygons. Used by InOutDoIntersection.
std::vector< size_t > InOutFindIntersectingPolys(size_t a_poly)
Finds OUTSIDE_POLY polygons that potentially intersect the INSIDE_POLY "a_poly". Used by InOutDoInter...
std::vector< GmBstBox3d > m_envelopes
extents of polygons
static GmBstBox3d iCalcPolyEnvelope(const std::vector< size_t > &a_loop, const std::vector< Pt3d > &a_pts)
Returns the envelop of a polygon.
void FillPolysInsideOfPolys(std::set< size_t > &a_oPoly, std::set< size_t > &a_psetUsed, std::vector< std::vector< size_t >> &a_output)
Finds INSIDE_POLY that are inside of NEWOUT_POLY or OUTSIDE_POLY. Used by MeIntersectPolys::impl::Cla...
void InOutDoIntersection()
A stack is created of INSIDE_POLY polygons. Each of these polygons is checked to see if it intersects...
void InInDoIntersection()
Uses a stack of INSIDE_POLY polygons to intersect the polygons with one another. The stack is sorted ...
void SetupInIn(const std::vector< MePolyOffsetterOutput > &a_offsets, double a_xyTol)
calls implementation
std::vector< int > m_loopTypes
type of polygon (OUTSIDE_POLY, INSIDE_POLY, NEWOUT_POLY)
void SetupInIn(const std::vector< MePolyOffsetterOutput > &a_offsets, double a_xyTol)
Setup for the InInDoIntersection.
void ClassifyDisjointPolys(SetIdx &a_delPolys)
Classifies polygons that are completely disjoint from other polygons based on the envelopes of the po...
std::vector< GmBstPoly3d > m_bPolys
boost::geometry::polygon
void UpdateInPolyLoopsFromHash(const std::vector< size_t > &a_idx)
Updates the indexes that define the polygons after the point locations have been hashed to find dupli...
convenience class for holding output data from the MePolyOffsetter
Intersect polygons that are a result of the paving process.
std::vector< Pt3d > m_pts
locations used by polygons
boost::geometry::model::polygon< Pt3d > GmBstPoly3d
impl * m_p
implementation class
MePolyOffsetterOutput m_out
newpolygons created by this class
std::vector< int > m_bOutPolyType
type of polygon (OUTSIDE_POLY, INSIDE_POLY, NEWOUT_POLY)
void InInTrivialPolyCases()
Looks for polygons that are completely disjoint based on their envelopes. Also finds polygons that ar...
std::list< size_t > m_stack
stack for processing the polygons
~MeIntersectPolys()
Destructor.
void ClassifyPolys(const MePolyOffsetterOutput &a_input, std::vector< std::vector< size_t >> &a_output)
Classifies the polygons. see PolyClassifierImpl::Classify.
MePolyPts m_polyPts
polygon points class
void DeleteBad_NEWOUT_POLY(MePolyOffsetterOutput &a_out, const VecPt3d &a_origOutsidePoly)
calls implementation
void DeleteBad_NEWOUT_POLY(MePolyOffsetterOutput &a_out, const VecPt3d &a_origOutsidePoly)
deletes NEWOUT_POLY polygons that have points outside of OUTSIDE_POLY polygon
GmBstPoly3d BoostPoly(size_t a_loopIdx)
Creates a boost polygon from a vector of point indexes.
void InOutCalcStartingStack()
Sets up the stack for the InOutDoIntersection method. A stack of INSIDE_POLY polygons is created and ...
std::set< size_t > SetIdx
typedef for shorter declaration
Definition: MePolyPts.h:22
boost::unordered_set< std::pair< size_t, size_t > > m_polyInsideOfPoly
index of polygon that is inside of another polygon
void CalcEnvelopes()
Calculates the envelope of all of the polygons.
static bool iEnvelopeInsideOfEnvelope(size_t a_i, size_t a_j, const std::vector< GmBstBox3d > &a_envelopes)
Returns true if envelope a_i is inside of envelope a_j.
SetIdx m_inOutOpolys
outside polygons
std::vector< int > m_loopTypes
type of loop
static bool iEnvelopesOverlap(size_t a_i, size_t a_j, const std::vector< GmBstBox3d > &a_iEnv, const std::vector< GmBstBox3d > &a_jEnv)
Returns true only if the envelopes overlap (not touch)
std::vector< std::vector< size_t > > m_loops
indexes of points that define loops
std::vector< Pt3d > & Pts()
Returns the vector of points.
Definition: MePolyPts.cpp:563
void InInDoIntersection()
calls implementation
void FillOutput(MePolyOffsetterOutput &a_out)
Fills the output class.
bool BoostPolyUnion(size_t a_i, size_t a_j)
Performs a union operation on 2 polygons. Used by InInDoIntersection.
#define TS_ASSERT_EQUALS_VEC(a, b)
double & XyTol()
Returns the tolerance.
Definition: MePolyPts.cpp:555
void ClassifyPolysInsideOfPolys(SetIdx &a_delPolys)
If an INSIDE_POLY is inside of another INSIDE_POLY then it will be deleted. But if it is inside of a ...
Utility class to work with polygon paving.
Definition: MePolyPts.h:28
void testClassify()
tests classifying polygons
void OnSetup()
Setup member variables. Called by SetupInIn and SetupInOut.
std::vector< std::vector< size_t > > m_loops
indexes to points that make polygons
std::vector< Pt3d > VecPt3d