xmsmesh  1.0
MePolyPaverToMeshPts.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
6 //------------------------------------------------------------------------------
7 
8 //----- Included files ---------------------------------------------------------
9 
10 // 1. Precompiled header
11 
12 // 2. My own header
14 
15 // 3. Standard library headers
16 #include <cfloat>
17 #include <list>
18 
19 // 4. External library headers
20 #include <boost/unordered_set.hpp>
21 
22 // 5. Shared code headers
23 #include <xmscore/points/pt.h>
30 #include <xmscore/misc/Progress.h>
31 #include <xmscore/misc/XmError.h>
32 #include <xmscore/misc/XmConst.h>
33 
34 // 6. Non-shared code headers
35 
36 //----- Forward declarations ---------------------------------------------------
37 
38 //----- External globals -------------------------------------------------------
39 
40 //----- Namespace declaration --------------------------------------------------
41 namespace xms
42 {
43 // function to access method on MePolyRedistributePtsImpl that we wanted
44 // removed from the public interface. This makes it so MePolyOffsetterOutput
45 // is not visible in the public interface and is only part of the "detail"
46 // implementation.
47 void mePolyPaverRedistribute(BSHP<MePolyRedistributePts> a_redist,
48  const MePolyOffsetterOutput& a_input,
49  MePolyOffsetterOutput& a_out,
50  int a_polyOffsetIter);
51 
52 //----- Constants / Enumerations -----------------------------------------------
53 
54 //----- Classes / Structs ------------------------------------------------------
55 
56 //----- Internal functions -----------------------------------------------------
57 
58 //----- Class / Function definitions -------------------------------------------
59 namespace
60 {
61 class Poly
62 {
63 public:
64  Poly()
65  : m_iter(0)
66  {
67  }
68  std::vector<Pt3d> m_outside;
69  std::vector<std::vector<Pt3d>> m_inside;
70  int m_iter;
71 };
72 
73 class MePolyPaverToMeshPtsImpl : public MePolyPaverToMeshPts
74 {
75 public:
76  MePolyPaverToMeshPtsImpl()
77  : m_meshPts(nullptr)
78  , m_xyTol(1e-9)
79  , m_bias(1)
80  , m_polyEnvelopeArea(0)
81  , m_polyOffsetIter(1)
82  {
83  }
84 
85  bool PolyToMeshPts(const std::vector<Pt3d>& a_outPoly,
86  const std::vector<std::vector<Pt3d>>& a_inPolys,
87  double a_bias,
88  double a_xyTol,
89  std::vector<Pt3d>& a_meshPts) override;
90  //------------------------------------------------------------------------------
92  //------------------------------------------------------------------------------
93  void SetRedistributor(BSHP<MePolyRedistributePts> a_) override { m_externalRedist = a_; }
94  void Setup();
95  void TearDown();
96  void ProcessStack();
97  void AddPolygonToMeshPoints(const Poly& a_poly, bool a_first);
98  void DoPave(const Poly& a_poly);
99  void CleanPave(const Poly& a_poly);
100  void RedistributePts();
101  void ClassifyPolys();
102  double AreaFromPolyStack();
103 
104  BSHP<VecPt3d> m_meshPts;
105  std::list<Poly> m_polyStack;
106  BSHP<MePolyOffsetter> m_offsetter;
107  BSHP<MePolyCleaner> m_cleaner;
108  BSHP<MePolyRedistributePts> m_redist;
109  BSHP<MePolyRedistributePts> m_externalRedist;
110  double m_xyTol;
111  double m_bias;
112  double m_polyEnvelopeArea;
113  int m_polyOffsetIter;
114  boost::unordered_set<std::pair<double, double>> m_ptHash;
115 
116  std::vector<MePolyOffsetterOutput> m_offsetOutputs;
117 };
118 
119 } // unnamed namespace
120 
121 //------------------------------------------------------------------------------
124 //------------------------------------------------------------------------------
125 BSHP<MePolyPaverToMeshPts> MePolyPaverToMeshPts::New()
126 {
127  BSHP<MePolyPaverToMeshPts> ret(new MePolyPaverToMeshPtsImpl);
128  return ret;
129 } // MePolyPaverToMeshPts::New
130 //------------------------------------------------------------------------------
132 //------------------------------------------------------------------------------
133 MePolyPaverToMeshPts::MePolyPaverToMeshPts()
134 {
135 }
136 //------------------------------------------------------------------------------
138 //------------------------------------------------------------------------------
139 MePolyPaverToMeshPts::~MePolyPaverToMeshPts()
140 {
141 }
142 
143 namespace
144 {
149 //------------------------------------------------------------------------------
160 //------------------------------------------------------------------------------
161 bool MePolyPaverToMeshPtsImpl::PolyToMeshPts(const std::vector<Pt3d>& a_outPoly,
162  const std::vector<std::vector<Pt3d>>& a_inPolys,
163  double a_bias,
164  double a_xyTol,
165  std::vector<Pt3d>& a_meshPts)
166 {
167  m_bias = a_bias;
168  m_xyTol = a_xyTol;
169  // Error checks
170  if (a_outPoly.empty())
171  return false;
172  for (size_t i = 0; i < a_inPolys.size(); ++i)
173  {
174  if (a_inPolys[i].empty())
175  return false;
176  }
177 
178  m_polyStack.push_back(Poly());
179  m_polyStack.back().m_outside = a_outPoly;
180  m_polyStack.back().m_inside = a_inPolys;
181  m_polyStack.back().m_iter = 1;
182 
183  Setup();
184  ProcessStack();
185  // fill the output variable
186  a_meshPts.swap(*m_meshPts);
187  TearDown();
188  return true;
189 } // MePolyPaverToMeshPtsImpl::PolyToMeshPts
190 //------------------------------------------------------------------------------
192 //------------------------------------------------------------------------------
193 void MePolyPaverToMeshPtsImpl::Setup()
194 {
195  // Calculate tolerance for point comparison
196  m_meshPts = BSHP<VecPt3d>(new VecPt3d());
197  m_offsetter = MePolyOffsetter::New();
198  m_cleaner = MePolyCleaner::New();
199  m_polyEnvelopeArea = AreaFromPolyStack();
200  if (!m_externalRedist)
201  {
202  m_redist = MePolyRedistributePts::New();
203  m_redist->SetSizeFuncFromPoly(m_polyStack.front().m_outside, m_polyStack.front().m_inside,
204  m_bias);
205  }
206  else
207  m_redist = m_externalRedist;
208 } // MePolyPaverToMeshPtsImpl::Setup
209 //------------------------------------------------------------------------------
211 //------------------------------------------------------------------------------
212 void MePolyPaverToMeshPtsImpl::TearDown()
213 {
214  m_meshPts.reset();
215  m_offsetter.reset();
216  m_cleaner.reset();
217  m_redist.reset();
218  m_ptHash.clear();
219 } // MePolyPaverToMeshPtsImpl::TearDown
220 //------------------------------------------------------------------------------
225 //------------------------------------------------------------------------------
226 void MePolyPaverToMeshPtsImpl::ProcessStack()
227 {
228  Progress prog("Paving Polygon");
229 
230  double area;
231  std::list<Poly>::iterator it(m_polyStack.begin());
232  bool first(true);
233  while (it != m_polyStack.end())
234  {
235  Poly& p(*it);
236 
237  m_polyOffsetIter = p.m_iter;
238  // Pave the polygon
239  DoPave(p);
240  // clean the results from the pave
241  CleanPave(p);
242  // redistribute points on the polygons
243  RedistributePts();
244  // clean again after redistributing the points
245  CleanPave(p);
246  // classify the newly created polys into polygons defined by the "Poly"
247  // class and put them on the stack
248  ClassifyPolys();
249  // add the points from this polygon to the mesh points
250  AddPolygonToMeshPoints(p, first);
251  first = false;
252 
253  // remove this poly from the stack and process the next one
254  m_polyStack.erase(it);
255  it = m_polyStack.begin();
256 
257  // do progress
258  area = AreaFromPolyStack();
259  prog.ProgressStatus(1.0 - (area / m_polyEnvelopeArea));
260  }
261 } // MePolyPaverToMeshPtsImpl::ProcessStack
262 //------------------------------------------------------------------------------
265 //------------------------------------------------------------------------------
266 void MePolyPaverToMeshPtsImpl::AddPolygonToMeshPoints(const Poly& a_poly, bool // a_first
267 )
268 {
269  auto itEnd = m_ptHash.end();
270  std::pair<double, double> pt;
271  for (size_t i = 0; i < a_poly.m_outside.size(); ++i)
272  {
273  pt.first = a_poly.m_outside[i].x;
274  pt.second = a_poly.m_outside[i].y;
275  if (m_ptHash.find(pt) == itEnd)
276  {
277  m_ptHash.insert(pt);
278  m_meshPts->push_back(a_poly.m_outside[i]);
279  }
280  }
281  for (size_t i = 0; i < a_poly.m_inside.size(); ++i)
282  {
283  for (size_t j = 0; j < a_poly.m_inside[i].size(); ++j)
284  {
285  pt.first = a_poly.m_inside[i][j].x;
286  pt.second = a_poly.m_inside[i][j].y;
287  if (m_ptHash.find(pt) == itEnd)
288  {
289  m_ptHash.insert(pt);
290  m_meshPts->push_back(a_poly.m_inside[i][j]);
291  }
292  }
293  }
294 
295  // if (a_first)
296  //{
297  // BSHP<GmPtSearch> ptSearch = GmPtSearch::New(true);
298  // ptSearch->VectorThatGrowsToSearch(m_meshPts);
299  // int idx;
300  // for (size_t i=0; i<a_poly.m_outside.size(); ++i)
301  // {
302  // if (!ptSearch->AddPtToVectorIfUnique(a_poly.m_outside[i], m_xyTol, idx))
303  // idx = -2;
304  // }
305  // for (size_t i=0; i<a_poly.m_inside.size(); ++i)
306  // {
307  // for (size_t j=0; j<a_poly.m_inside[i].size(); ++j)
308  // {
309  // if (!ptSearch->AddPtToVectorIfUnique(a_poly.m_inside[i][j], m_xyTol, idx))
310  // idx = -2;
311  // }
312  // }
313  //}
314  // else
315  //{
316  // m_meshPts->insert(m_meshPts->end(), a_poly.m_outside.begin(),
317  // a_poly.m_outside.end());
318  // for (size_t i=0; i<a_poly.m_inside.size(); ++i)
319  // {
320  // m_meshPts->insert(m_meshPts->end(), a_poly.m_inside[i].begin(),
321  // a_poly.m_inside[i].end());
322  // }
323  //}
324 
325 } // MePolyPaverToMeshPtsImpl::AddPolygonToMeshPoints
326 //------------------------------------------------------------------------------
328 //------------------------------------------------------------------------------
329 void MePolyPaverToMeshPtsImpl::DoPave(const Poly& a_poly)
330 {
331  m_offsetOutputs.clear();
332 
333  MePolyOffsetterOutput offsetOut;
334  MePolyOffsetter::polytype pIn(MePolyOffsetter::INSIDE_POLY), pOut(MePolyOffsetter::OUTSIDE_POLY);
335  std::vector<Pt3d> pts;
336  // pave in from the outer poly
337  m_offsetter->Offset(a_poly.m_outside, pOut, offsetOut, m_xyTol);
338  m_offsetOutputs.push_back(offsetOut);
339 
340  // pave out from the inner polys
341  for (size_t i = 0; i < a_poly.m_inside.size(); ++i)
342  {
343  m_offsetter->Offset(a_poly.m_inside[i], pIn, offsetOut, m_xyTol);
344  m_offsetOutputs.push_back(offsetOut);
345  }
346 } // MePolyPaverToMeshPtsImpl::DoPave
347 //------------------------------------------------------------------------------
350 //------------------------------------------------------------------------------
351 void MePolyPaverToMeshPtsImpl::CleanPave(const Poly& a_poly)
352 {
353  m_cleaner->SetOriginalOutsidePolygon(a_poly.m_outside);
354  // intersect the new inner polys with the other inner polys
355  MePolyOffsetterOutput out, out2;
356  m_cleaner->IntersectCleanInPolys(m_offsetOutputs, out, m_xyTol);
357 
358  // intersect the new inner polys with the outer polys
359  m_cleaner->IntersectCleanInOutPolys(out, out2, m_xyTol);
360  m_offsetOutputs.clear();
361  m_offsetOutputs.push_back(out2);
362 } // MePolyPaverToMeshPtsImpl::CleanPave
363 //------------------------------------------------------------------------------
366 //------------------------------------------------------------------------------
367 void MePolyPaverToMeshPtsImpl::RedistributePts()
368 {
369  XM_ASSERT(m_redist);
370  if (!m_redist)
371  return;
373  mePolyPaverRedistribute(m_redist, m_offsetOutputs[0], o, m_polyOffsetIter);
374  m_offsetOutputs[0] = o;
375 } // MePolyPaverToMeshPtsImpl::RedistributePts
376 //------------------------------------------------------------------------------
382 //------------------------------------------------------------------------------
383 void MePolyPaverToMeshPtsImpl::ClassifyPolys()
384 {
385  if (m_offsetOutputs[0].m_pts.empty())
386  return;
387 
388  std::vector<std::vector<size_t>> polys;
389  MeIntersectPolys ip;
390  ip.ClassifyPolys(m_offsetOutputs[0], polys);
391 
392  // put these on the stack
393  std::vector<Pt3d>& pts(m_offsetOutputs[0].m_pts);
394  Poly p;
395  p.m_iter = m_polyOffsetIter + 1;
396  for (size_t i = 0; i < polys.size(); ++i)
397  {
398  p.m_outside.resize(0);
399  p.m_inside.resize(0);
400  // get the outside loop
401  std::vector<size_t>& oLoop(m_offsetOutputs[0].m_loops[polys[i][0]]);
402  for (size_t j = 0; j < oLoop.size(); ++j)
403  {
404  p.m_outside.push_back(pts[oLoop[j]]);
405  }
406  // do inside loops
407  for (size_t j = 1; j < polys[i].size(); ++j)
408  {
409  std::vector<size_t>& iLoop(m_offsetOutputs[0].m_loops[polys[i][j]]);
410  p.m_inside.push_back(std::vector<Pt3d>());
411  for (size_t k = 0; k < iLoop.size(); ++k)
412  {
413  p.m_inside.back().push_back(pts[iLoop[k]]);
414  }
415  }
416 
417  m_polyStack.push_back(p);
418  }
419 
420 } // MePolyPaverToMeshPtsImpl::ClassifyPolys
421 //------------------------------------------------------------------------------
423 //------------------------------------------------------------------------------
424 static double iEnvelopeArea(const std::vector<Pt3d>& a_pts)
425 {
426  double area;
427  Pt3d pMin(XM_DBL_HIGHEST),
428  pMax(XM_DBL_LOWEST); // changed to XM_DBL_LOWEST because it is an arbitrarily low value
429  for (size_t i = 0; i < a_pts.size(); ++i)
430  {
431  gmAddToExtents(a_pts[i], pMin, pMax);
432  }
433  area = (pMax.x - pMin.x) * (pMax.y - pMin.y);
434  return area;
435 } // iEnvelopeArea
436 //------------------------------------------------------------------------------
438 //------------------------------------------------------------------------------
439 double MePolyPaverToMeshPtsImpl::AreaFromPolyStack()
440 {
441  double area(0);
442  // out polys are positive and in polys are negative
443  std::list<Poly>::iterator it(m_polyStack.begin()), itEnd(m_polyStack.end());
444  for (; it != itEnd; ++it)
445  {
446  Poly& p(*it);
447  area += iEnvelopeArea(p.m_outside);
448  }
449  return area;
450 } // MePolyPaverToMeshPtsImpl::AreaFromPolyStack
451 
452 } // unnamed namespace
453 
454 } // namespace xms
455 
456 #ifdef CXX_TEST
457 
460 
462 
463 // namespace xms {
464 using namespace xms;
465 
470 //------------------------------------------------------------------------------
472 //------------------------------------------------------------------------------
474 {
475  BSHP<MePolyPaverToMeshPts> p = MePolyPaverToMeshPts::New();
476  TS_ASSERT(p);
477 } // MeIntersectPolysTest::testCreateClass
478 //------------------------------------------------------------------------------
480 //------------------------------------------------------------------------------
482 {
483  // x = 0 2 4
484  //
485  // y=4 3--------4-------5-------6---------7
486  // | |
487  // | |
488  // 2 8
489  // | |
490  // | |
491  // y=2 1 9
492  // | |
493  // | |
494  // 0 10
495  // | |
496  // | |
497  // y=0 15--------14------13------12--------11
498  //
499  std::vector<Pt3d> outPoly = {{0, 1, 0}, {0, 2, 0}, {0, 3, 0}, {0, 4, 0}, {1, 4, 0}, {2, 4, 0},
500  {3, 4, 0}, {4, 4, 0}, {4, 3, 0}, {4, 2, 0}, {4, 1, 0}, {4, 0, 0},
501  {3, 0, 0}, {2, 0, 0}, {1, 0, 0}, {0, 0, 0}};
502  std::vector<std::vector<Pt3d>> inPoly;
503  MePolyPaverToMeshPtsImpl paver;
504  double bias(1), tol(1e-9);
505  std::vector<Pt3d> outPts;
506  paver.PolyToMeshPts(outPoly, inPoly, bias, tol, outPts);
507  std::vector<Pt3d> basePts = {
508  {0.0, 1.0, 0.0}, {0.0, 2.0, 0.0}, {0.0, 3.0, 0.0}, {0.0, 4.0, 0.0},
509  {1.0, 4.0, 0.0}, {2.0, 4.0, 0.0}, {3.0, 4.0, 0.0}, {4.0, 4.0, 0.0},
510  {4.0, 3.0, 0.0}, {4.0, 2.0, 0.0}, {4.0, 1.0, 0.0}, {4.0, 0.0, 0.0},
511  {3.0, 0.0, 0.0}, {2.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, 0.0, 0.0},
512  {0.8660, 0.8660, 0.0}, {0.8660, 1.8740, 0.0}, {0.8660, 2.8820, 0.0}, {1.6220, 3.1340, 0.0},
513  {2.6300, 3.1340, 0.0}, {3.1340, 2.6300, 0.0}, {3.1340, 1.6220, 0.0}, {2.8820, 0.8660, 0.0},
514  {1.8740, 0.8660, 0.0}, {2.3148, 1.7390, 0.0}, {1.7390, 2.0535, 0.0}, {2.3323, 2.3802, 0.0}};
515  TS_ASSERT_DELTA_VECPT3D(basePts, outPts, 1e-4);
516 } // MePolyPaverToMeshPtsUnitTests::testCase1
517 //------------------------------------------------------------------------------
519 //------------------------------------------------------------------------------
521 {
522  // x = 0 2 4
523  //
524  // y=4 3--------4-------5-------6---------7
525  // | |
526  // | |
527  // 2 8
528  // | 18--17 |
529  // | | | |
530  // y=2 1 19--16 9
531  // | |
532  // | |
533  // 0 10
534  // | |
535  // | |
536  // y=0 15--------14------13------12--------11
537  //
538  std::vector<Pt3d> outPoly = {{0, 1, 0}, {0, 2, 0}, {0, 3, 0}, {0, 4, 0}, {1, 4, 0}, {2, 4, 0},
539  {3, 4, 0}, {4, 4, 0}, {4, 3, 0}, {4, 2, 0}, {4, 1, 0}, {4, 0, 0},
540  {3, 0, 0}, {2, 0, 0}, {1, 0, 0}, {0, 0, 0}};
541  std::vector<std::vector<Pt3d>> inPoly;
542  std::vector<Pt3d> tmp = {{2.25, 2, 0}, {2.25, 2.25, 0}, {2, 2.25, 0}, {2, 2, 0}};
543  inPoly.push_back(tmp);
544  MePolyPaverToMeshPtsImpl paver;
545  double bias(1), tol(1e-9);
546  std::vector<Pt3d> outPts;
547  paver.PolyToMeshPts(outPoly, inPoly, bias, tol, outPts);
548  std::vector<Pt3d> basePts = {
549  {0.0, 1.0, 0.0}, {0.0, 2.0, 0.0}, {0.0, 3.0, 0.0}, {0.0, 4.0, 0.0},
550  {1.0, 4.0, 0.0}, {2.0, 4.0, 0.0}, {3.0, 4.0, 0.0}, {4.0, 4.0, 0.0},
551  {4.0, 3.0, 0.0}, {4.0, 2.0, 0.0}, {4.0, 1.0, 0.0}, {4.0, 0.0, 0.0},
552  {3.0, 0.0, 0.0}, {2.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, 0.0, 0.0},
553  {2.25, 2.0, 0.0}, {2.25, 2.25, 0.0}, {2.0, 2.25, 0.0}, {2.0, 2.0, 0.0},
554  {0.8660, 0.8660, 0.0}, {0.8660, 1.7951, 0.0}, {0.8660, 2.7070, 0.0}, {1.3659, 3.1340, 0.0},
555  {2.2505, 3.1340, 0.0}, {3.1340, 3.1224, 0.0}, {3.1340, 2.2316, 0.0}, {3.1340, 1.3448, 0.0},
556  {2.6848, 0.8660, 0.0}, {1.7732, 0.8660, 0.0}, {1.7835, 2.1250, 0.0}, {2.0069, 1.7912, 0.0},
557  {2.4260, 1.8985, 0.0}, {2.4335, 2.3440, 0.0}, {2.0093, 2.4589, 0.0}};
558  TS_ASSERT_DELTA_VECPT3D(basePts, outPts, 1e-4);
559 } // MePolyPaverToMeshPtsUnitTests::testCase1
560 
561 //} // namespace xms
562 #endif
void ClassifyPolys(const MePolyOffsetterOutput &a_input, std::vector< std::vector< size_t >> &a_output)
calls implementation
static BSHP< MePolyOffsetter > New()
Creates a BufferPoly class.
static BSHP< MePolyRedistributePts > New()
Creates an instance of this class.
#define TS_ASSERT_DELTA_VECPT3D(a, b, delta)
void mePolyPaverRedistribute(BSHP< MePolyRedistributePts > a_redist, const MePolyOffsetterOutput &a_input, MePolyOffsetterOutput &a_out, int a_polyOffsetIter)
Free function access an implement method that needs to be hidden from the public interface.
static BSHP< MePolyPaverToMeshPts > New()
Creates a new instance of this class.
void testCase2()
tests the figure below
convenience class for holding output data from the MePolyOffsetter
Intersect polygons that are a result of the paving process.
polytype
enum to identify types of polygons created by this class
void testCase1()
tests the figure below
static BSHP< MePolyCleaner > New()
Creates a new instance of this class.
#define XM_ASSERT(x)
void testCreateClass()
tests creating a class
Generates mesh node locations by paving a polygon.
void gmAddToExtents(const Pt3d &a_pt, Pt3d &a_min, Pt3d &a_max)
std::vector< Pt3d > VecPt3d