xmsmesh  1.0
MePolyRedistributePts.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 <sstream>
18 
19 // 4. External library headers
20 #include <boost/make_shared.hpp>
21 #include <boost/thread/mutex.hpp>
22 
23 // 5. Shared code headers
24 #include <xmscore/points/pt.h>
25 #include <xmscore/math/math.h>
27 #include <xmscore/stl/vector.h>
34 #include <xmscore/misc/xmstype.h>
35 #include <xmscore/misc/XmError.h>
36 #include <xmscore/misc/XmLog.h>
38 #include <xmscore/misc/XmConst.h>
39 
40 // 6. Non-shared code headers
41 
42 //----- Forward declarations ---------------------------------------------------
43 
44 //----- External globals -------------------------------------------------------
45 
46 //----- Namespace declaration --------------------------------------------------
47 namespace xms
48 {
49 //----- Constants / Enumerations -----------------------------------------------
50 
51 //----- Classes / Structs ------------------------------------------------------
52 
53 //----- Internal functions -----------------------------------------------------
54 
55 //----- Class / Function definitions -------------------------------------------
56 
58 {
59 public:
62  , m_minLength(XM_DBL_HIGHEST)
63  , m_maxLength(XM_DBL_LOWEST) // changed to be XM_DBL_LOWEST since it is an arbitrarily low value
64  , m_sizeBias(1.0)
65  , m_polyPts(new VecPt3d())
66  , m_intersectWithTris(false)
67  , m_distSqTol(0)
68  , m_biasConstSize(false)
69  , m_polyOffsetIter(0)
72  , m_minimumCurvature(0.001)
73  , m_smoothCurvature(false)
75  {
76  }
77 
78  virtual void SetSizeFunc(BSHP<InterpBase> a_interp) override;
79  virtual void SetSizeFuncFromPoly(const VecPt3d& a_outPoly,
80  const VecPt3d2d& a_inPolys,
81  double a_sizeBias) override;
82 
83  //------------------------------------------------------------------------------
86  //------------------------------------------------------------------------------
87  virtual void SetConstantSizeFunc(double a_size) override
88  {
89  m_constSize = a_size;
90  m_curvatureRedist.reset(); // remove curvature redistribution
91  } // SetConstantSizeFunc
92 
93  //------------------------------------------------------------------------------
96  //------------------------------------------------------------------------------
97  virtual void SetConstantSizeBias(double a_sizeBias) override
98  {
99  m_sizeBias = a_sizeBias;
100  m_biasConstSize = true;
101  m_curvatureRedist.reset(); // remove curvature redistribution
102  } // SetConstantSizeBias
103 
104  void SetUseCurvatureRedistribution(double a_featureSize,
105  double a_meanSpacing,
106  double a_minimumCurvature,
107  bool a_smooth) override;
108 
109  void Redistribute(const MePolyOffsetterOutput& a_input,
110  MePolyOffsetterOutput& a_out,
111  int a_polyOffsetIter);
112  virtual VecPt3d Redistribute(const VecPt3d& a_polyLine) override;
113  virtual double SizeFromLocation(const Pt3d& a_location) override;
114  virtual std::string ToPyRepr() const override;
115 
116  VecPt3d LoopToVecPt3d(const VecSizet& a_idx, const VecPt3d& a_pts);
117  void IntersectWithTris(VecPt3d& a_pts);
118  void InterpEdgeLengths(const VecPt3d& a_pts, VecDbl& lengths);
119  void InterpToPoint(size_t a_idx,
120  const VecPt3d& a_pts,
121  VecDbl& a_lengths,
122  VecDbl& a_wt,
123  VecDbl& a_d2,
124  double& a_bias);
125  void CalcInterpWeights(const Pt3d& a_pt, VecDbl& a_wt, VecDbl& a_d2, double& a_sumWt);
126  VecPt3d RedistPts(const VecPt3d& a_pts, const VecDbl& lengths);
127  VecPt3d RedistPts2(const VecPt3d& a_pts, const VecDbl& lengths);
128  void RedistPtsToOutput(const VecPt3d& a_pts, int a_polyType, MePolyOffsetterOutput& a_out);
129 
130  void TvaluesForSeg(size_t a_idx,
131  size_t a_nextIdx,
132  const VecDbl& a_segLengths,
133  const VecDbl& a_segTvalues,
134  const VecDbl& a_interpLengths,
135  double& a_pcntin,
136  VecDbl& a_tVals);
137  void SizeFromPolyCalcAveEdgeLengthAtPts(const VecPt3d& a_outPoly, const VecPt3d2d& a_inPolys);
138  void SizeFromPolyAddEdgeLengths(const VecPt3d& a_pts);
139  void CalcSegLengths(const VecPt3d& a_pts, VecDbl& a_segLength, VecDbl& _segTvalues);
140  void GetSegmentFromTval(const VecDbl& a_segTvalues,
141  double a_tVal,
142  size_t& a_segIdx,
143  double& a_segT0,
144  double& a_segT1);
145  void CreatePolyIntersector();
146 
147  double m_constSize,
148  m_minLength,
149  m_maxLength,
150  m_sizeBias;
151  BSHP<VecPt3d> m_polyPts;
153  BSHP<InterpBase> m_interp;
154  // BSHP<InterpIdw> m_idw; ///< interpolation class used with larger numbers of
155  // polygon points
156  BSHP<VecPt3d> m_sizePts;
157  BSHP<VecInt> m_sizeTris;
158  BSHP<GmMultiPolyIntersector> m_polyIntersector;
160  bool m_intersectWithTris;
162  double m_distSqTol;
165  double m_featureSizeCurvature;
178  BSHP<MePolyRedistributePtsCurvature> m_curvatureRedist;
179 };
180 
181 //------------------------------------------------------------------------------
184 //------------------------------------------------------------------------------
185 BSHP<MePolyRedistributePts> MePolyRedistributePts::New()
186 {
187  BSHP<MePolyRedistributePts> ret(new MePolyRedistributePtsImpl);
188  return ret;
189 } // MePolyRedistributePts::New
190 //------------------------------------------------------------------------------
192 //------------------------------------------------------------------------------
194 {
195 } // MePolyRedistributePts::~MePolyRedistributePts
196 //------------------------------------------------------------------------------
198 //------------------------------------------------------------------------------
200 {
201 } // MePolyRedistributePts::MePolyRedistributePts
202 
207 //------------------------------------------------------------------------------
210 //------------------------------------------------------------------------------
211 void MePolyRedistributePtsImpl::SetSizeFunc(BSHP<InterpBase> a_interp)
212 {
213  m_curvatureRedist.reset(); // remove curvature redistribution
214  m_interp = a_interp;
215  m_intersectWithTris = true;
216  // make sure we have triangles
217  m_sizePts = m_interp->GetPts();
218  m_sizeTris = m_interp->GetTris();
219  if (m_intersectWithTris && m_sizeTris->empty())
220  {
221  VecInt vTris;
222  TrTriangulatorPoints tri(*m_sizePts, vTris);
223  tri.Triangulate();
224  if (!vTris.empty())
225  {
226  m_sizeTris = BSHP<VecInt>(new VecInt());
227  m_sizeTris->reserve(vTris.size());
228  for (size_t i = 0; i < vTris.size(); ++i)
229  m_sizeTris->push_back((int)vTris[i]);
230  }
231  }
234 } // SetSizeFunc
235 //------------------------------------------------------------------------------
241 //------------------------------------------------------------------------------
243  const VecPt3d2d& a_inPolys,
244  double a_sizeBias)
245 {
246  m_curvatureRedist.reset(); // remove curvature redistribution
247  m_sizeBias = a_sizeBias;
248  // calculate the lengths of the segments
249  SizeFromPolyCalcAveEdgeLengthAtPts(a_outPoly, a_inPolys);
250  if (m_polyPts->empty())
251  return;
252  double diff = m_maxLength - m_minLength;
253  if (diff / m_minLength < .05)
254  {
256  }
257  // looking for a way to speed up interpolation of edge lengths
258  // doesn't work well
259  // else if (m_polyPts->size() > 100)
260  //{
261  // m_idw = InterpIdw::New();
262  // m_idw->SetPtsTris(m_polyPts, m_sizeTris);
263  // BSHP<VecFlt> s(new VecFlt(m_polyEdgeLengths.size()));
264  // for (size_t i=0; i<m_polyEdgeLengths.size(); ++i)
265  // (*s)[i] = (float)m_polyEdgeLengths[i];
266  // m_idw->SetScalars(s);
267  // m_idw->SetSearchOpts(32, false);
268  // m_idw->SetWeightCalcMethod(InterpIdw::CLASSIC);
269  //}
270  else
271  {
272  size_t nPts = m_polyPts->size();
273  Pt3d* p(&(*m_polyPts)[0]);
274  Pt3d pMin(p[0]), pMax(p[0]);
275  for (size_t i = 0; i < nPts; ++i)
276  {
277  if (p[i].x < pMin.x)
278  pMin.x = p[i].x;
279  if (p[i].y < pMin.y)
280  pMin.y = p[i].y;
281  if (p[i].x > pMax.x)
282  pMax.x = p[i].x;
283  if (p[i].y > pMax.y)
284  pMax.y = p[i].y;
285  }
286  // compute distance to avoid interpolating too much
287  double boundsDistSq = MdistSq(pMin.x, pMin.y, pMax.x, pMax.y);
288  m_distSqTol = 1e-4 * boundsDistSq;
289  }
290 } // MePolyRedistributePtsImpl::SetSizeFuncFromPoly
291 //------------------------------------------------------------------------------
300 //------------------------------------------------------------------------------
302  double a_meanSpacing,
303  double a_minimumCurvature,
304  bool a_smooth)
305 {
306  m_featureSizeCurvature = a_featureSize;
307  m_meanSpacingCurvature = a_meanSpacing;
308  m_minimumCurvature = a_minimumCurvature;
309  m_smoothCurvature = a_smooth;
311 } // MePolyRedistributePtsImpl::SetUseCurvatureRedistribution
312 //------------------------------------------------------------------------------
320 //------------------------------------------------------------------------------
322  MePolyOffsetterOutput& a_out,
323  int a_polyOffsetIter)
324 {
325  VecDbl lengths;
326  m_polyOffsetIter = a_polyOffsetIter;
327  a_out.m_loops.resize(0);
328  a_out.m_pts.resize(0);
329  a_out.m_loopTypes.resize(0);
330  for (size_t i = 0; i < a_input.m_loops.size(); ++i)
331  {
332  const VecSizet& loop(a_input.m_loops[i]);
333  const int& lType(a_input.m_loopTypes[i]);
334  VecPt3d pts = LoopToVecPt3d(loop, a_input.m_pts);
336  {
337  IntersectWithTris(pts);
338  }
339  pts.push_back(pts.front());
340  // interpolate edge lengths
341  InterpEdgeLengths(pts, lengths);
342  // redistribute the points
343  VecPt3d redistPts = RedistPts(pts, lengths);
344  if (!redistPts.empty())
345  redistPts.pop_back();
346  RedistPtsToOutput(redistPts, lType, a_out);
347  }
348  m_polyOffsetIter = 0;
349 } // MePolyPaverToMeshPtsImpl::Redistribute
350 //------------------------------------------------------------------------------
354 //------------------------------------------------------------------------------
356 {
357  if (m_curvatureRedist)
358  {
359  return m_curvatureRedist->Redistribute(a_polyLine, m_featureSizeCurvature,
362  }
363  VecPt3d pts(a_polyLine), ret;
364  VecDbl lengths;
366  {
367  IntersectWithTris(pts);
368  }
369  // interpolate edge lengths
370  InterpEdgeLengths(pts, lengths);
371  // redistribute the points
372  ret = RedistPts(pts, lengths);
373  return ret;
374 } // MePolyRedistributePtsImpl::Redistribute
375 //------------------------------------------------------------------------------
379 //------------------------------------------------------------------------------
381 {
382  if (m_curvatureRedist)
383  {
384  std::string msg = "MePolyRedistributePts set to use curvature redistribution; "
385  "MePolyRedistributePtsImpl::SizeFromLocation can not be call with these "
386  "settings. XM_NODATA will be returned.";
387  boost::mutex mtx;
388  mtx.lock();
389  XM_LOG(xmlog::error, msg);
390  mtx.unlock();
391  return XM_NODATA;
392  }
393  VecPt3d pts(1, a_location);
394  VecDbl lengths;
395  InterpEdgeLengths(pts, lengths);
396  return lengths.front();
397 } // MePolyRedistributePtsImpl::SizeFromLocation
398 //------------------------------------------------------------------------------
401 //------------------------------------------------------------------------------
403 {
404  std::stringstream ss;
405  ss << "size_bias: " << STRstd(m_sizeBias) << "\n";
406  if (m_constSize != XM_NONE)
407  ss << "constant_size_function: " << STRstd(m_constSize) << "\n";
408  if (m_interp)
409  ss << "size_func: <class: InterpBase>\n";
410  if (m_featureSizeCurvature != 0)
411  {
412  ss << "feature_size_curvature: " << STRstd(m_featureSizeCurvature) << "\n";
413  ss << "mean_spacing_curvature: " << STRstd(m_meanSpacingCurvature) << "\n";
414  ss << "minimum_curvature: " << STRstd(m_minimumCurvature) << "\n";
415  std::string offOn[2] = {"False", "True"};
416  ss << "smooth_curvature: " << offOn[(int)m_smoothCurvature] << "\n";
417  }
418  return ss.str();
419 } // MePolyRedistributePtsImpl::ToPyRepr
420 //------------------------------------------------------------------------------
426 //------------------------------------------------------------------------------
428 {
429  VecPt3d ret;
430  ret.reserve(a_idx.size());
431  for (size_t i = 0; i < a_idx.size(); ++i)
432  ret.push_back(a_pts[a_idx[i]]);
433  return ret;
434 } // MePolyRedistributePtsImpl::LoopToVecPt3d
435 //------------------------------------------------------------------------------
438 //------------------------------------------------------------------------------
440 {
441  VecPt3d newPts, pts;
442  VecInt polys;
443  for (size_t i = 0; i < a_pts.size(); ++i)
444  {
445  Pt3d p0(a_pts[i]), p1(a_pts[0]);
446  if (i < a_pts.size() - 1)
447  p1 = a_pts[i + 1];
448  m_polyIntersector->TraverseLineSegment(p0.x, p0.y, p1.x, p1.y, polys, pts);
449  auto start = pts.begin();
450  if (i > 0)
451  ++start;
452  newPts.insert(newPts.end(), start, pts.end());
453  }
454  a_pts.swap(newPts);
455  a_pts.pop_back();
456 } // MePolyRedistributePtsImpl::IntersectWithTris
457 //------------------------------------------------------------------------------
463 //------------------------------------------------------------------------------
465 {
466  a_lengths.assign(a_pts.size(), 0.0);
468  {
469  a_lengths.assign(a_pts.size(), m_constSize);
470  return;
471  }
472  double bias(XM_NONE);
474  {
475  bias = m_sizeBias;
476  if (bias > .99)
477  bias = .99;
478  else if (bias < .01)
479  bias = .01;
480  bias = 1 - bias;
481  bias = pow(bias, (double)m_polyOffsetIter);
482  }
483 
484  if (m_interp)
485  { // size function interpolation
486  VecFlt s;
487  m_interp->InterpToPts(a_pts, s);
488  for (size_t i = 0; i < s.size(); ++i)
489  a_lengths[i] = (double)s[i];
490  }
491  // tried to use to speed up but was not successful
492  // else if (m_idw)
493  //{
494  // VecFlt s;
495  // m_idw->InterpToPts(a_pts, s);
496  // for (size_t i=0; i<s.size(); ++i) a_lengths[i] = (double)s[i];
497  //}
498  else if (!m_polyEdgeLengths.empty())
499  {
500  double lastInterp(-1), distSq(0);
501  VecDbl wt, d2;
502  Pt3d aPt;
503  InterpToPoint(0, a_pts, a_lengths, wt, d2, bias);
504  lastInterp = a_lengths[0];
505  aPt = a_pts[0];
506 
507  // do the rest of the points
508  for (size_t i = 1; i < a_pts.size(); ++i)
509  {
510  distSq = MdistSq(aPt.x, aPt.y, a_pts[i].x, a_pts[i].y);
511  if (distSq < m_distSqTol)
512  {
513  a_lengths[i] = lastInterp;
514  continue;
515  }
516  InterpToPoint(i, a_pts, a_lengths, wt, d2, bias);
517  lastInterp = a_lengths[i];
518  aPt = a_pts[i];
519  }
520  }
521  else
522  {
523  boost::mutex mtx;
524  mtx.lock();
525  VecDbl lengths, tvals;
526  CalcSegLengths(a_pts, lengths, tvals);
527  double sum(0);
528  for (size_t i = 0; i < lengths.size(); ++i)
529  sum += lengths[i];
530  sum = sum / lengths.size();
531  m_constSize = sum;
532  std::stringstream ss;
533  ss << "Interpolator not defined in MePolyRedistributePts. Size function "
534  "set to constant value: "
535  << sum << ".";
536  XM_LOG(xmlog::debug, ss.str());
537  InterpEdgeLengths(a_pts, a_lengths);
538  mtx.unlock();
539  }
540 } // MePolyRedistributePtsImpl::InterpEdgeLengths
541 //------------------------------------------------------------------------------
552 //------------------------------------------------------------------------------
554  const VecPt3d& a_pts,
555  VecDbl& a_lengths,
556  VecDbl& a_wt,
557  VecDbl& a_d2,
558  double& a_bias)
559 {
560  double sumWt(0);
561  CalcInterpWeights(a_pts[a_idx], a_wt, a_d2, sumWt);
562  for (size_t j = 0; j < m_polyEdgeLengths.size(); ++j)
563  {
564  a_lengths[a_idx] += m_polyEdgeLengths[j] * (a_wt[j] / sumWt);
565  }
566  if (XM_NONE != a_bias)
567  {
568  double& d(a_lengths[a_idx]);
569  if (d > m_constSize)
570  {
571  d = d * a_bias;
572  if (d < m_constSize)
573  d = m_constSize;
574  }
575  else
576  {
577  d = d / a_bias;
578  if (d > m_constSize)
579  d = m_constSize;
580  }
581  }
582  else
583  {
584  if (a_lengths[a_idx] < m_minLength)
585  a_lengths[a_idx] = m_minLength;
586  if (a_lengths[a_idx] > m_maxLength)
587  a_lengths[a_idx] = m_maxLength;
588  }
589 } // MePolyRedistributePtsImpl::InterpToPoint
590 //------------------------------------------------------------------------------
597 //------------------------------------------------------------------------------
599  VecDbl& a_wt,
600  VecDbl& a_d2,
601  double& a_sumWt)
602 {
603  a_sumWt = 0;
604  double diff(0), factor(0);
605  size_t nPts = m_polyPts->size();
606  const Pt3d* p(&(*m_polyPts)[0]);
607  a_wt.resize(nPts);
608  a_d2.resize(nPts);
609  for (size_t i = 0; i < nPts; ++i)
610  {
611  a_d2[i] = MdistSq(a_pt.x, a_pt.y, p[i].x, p[i].y);
612  if (a_d2[i] < 10e-8)
613  a_wt[i] = 10e10;
614  else
615  a_wt[i] = 1 / a_d2[i];
616 
617  diff = m_polyEdgeLengths[i] - m_minLength;
618  factor = m_minLength + (m_sizeBias * diff);
619  a_wt[i] *= factor;
620 
621  a_sumWt += a_wt[i];
622  }
623 } // MePolyRedistributePtsImpl::CalcInterpWeights
624 //------------------------------------------------------------------------------
629 //------------------------------------------------------------------------------
630 VecPt3d MePolyRedistributePtsImpl::RedistPts(const VecPt3d& a_pts, const VecDbl& a_interpLengths)
631 {
632  static bool debug(false);
633  if (debug)
634  return RedistPts2(a_pts, a_interpLengths);
635 
636  // Get lengths of all segments and the total length
637  VecDbl segLength, segTvalues;
638  CalcSegLengths(a_pts, segLength, segTvalues);
639 
640  // create array of T values for locations of new points along this loop
641  double pcntin(0);
642  size_t nextIdx;
643  VecDbl tVals;
644  tVals.reserve(a_pts.size());
645  tVals.push_back(0.0); // this is the first and last point in our loop
646  for (size_t i = 0; i < a_pts.size() - 1; ++i)
647  {
648  nextIdx = 0;
649  if (i + 1 < a_pts.size() - 1)
650  nextIdx = i + 1;
651  TvaluesForSeg(i, nextIdx, segLength, segTvalues, a_interpLengths, pcntin, tVals);
652  }
653  double aveTincrement(0);
654  for (size_t i = 1; i < tVals.size(); ++i)
655  {
656  aveTincrement += tVals[i] - tVals[i - 1];
657  }
658  aveTincrement /= (tVals.size() - 1);
659 
660  VecPt3d ret;
661  // adjust the tvals based on what was left over when processing the last
662  // segment. If the left over tval is less than .5 of the last segment then
663  // we don't keep that last tval
664  double leftOverTval = 1 - tVals.back();
665  if (tVals.size() < 2)
666  return ret;
667  if (pcntin < .5)
668  {
669  tVals.pop_back();
670  if (leftOverTval >= 0)
671  leftOverTval = 1 - tVals.back();
672  }
673  if (tVals.size() > 2)
674  { // redistribute the leftover tvalue to all the tVals
675  double redistT = (leftOverTval - aveTincrement) / tVals.size();
676  for (size_t i = 1; i < tVals.size(); ++i)
677  tVals[i] += (i * redistT);
678  }
679  else if (segLength.size() > 3)
680  { // we initially had at least 3 points
681  tVals.assign(3, 0);
682  tVals[1] = 1 / 3.0;
683  tVals[2] = 2 / 3.0;
684  }
685 
686  if (tVals.size() > 2)
687  {
688  tVals.push_back(1.0);
689  ret.reserve(tVals.size());
690  // create the points
691  // put in the first point
692  ret.push_back(a_pts[0]);
693  // set the z to 0.0
694  ret[0].z = 0;
695  size_t segIdx(0);
696  for (size_t i = 1; i < tVals.size(); ++i)
697  { // get the segment that the tval is on
698  double segT0, segT1, tVal = tVals[i];
699  GetSegmentFromTval(segTvalues, tVals[i], segIdx, segT0, segT1);
700  // convert polyline tval to segment tval
701  tVal = (tVal - segT0) / (segT1 - segT0);
702  // calculate the point
703  size_t nextIdx = 0;
704  if (segIdx + 1 < a_pts.size())
705  nextIdx = segIdx + 1;
706  const Pt3d &p0(a_pts[segIdx]), &p1(a_pts[nextIdx]);
707  Pt3d pt;
708  pt.x = p0.x + tVal * (p1.x - p0.x);
709  pt.y = p0.y + tVal * (p1.y - p0.y);
710  ret.push_back(pt);
711  }
712  }
713  return ret;
714 } // MePolyRedistributePtsImpl::RedistPts
715 //------------------------------------------------------------------------------
720 //------------------------------------------------------------------------------
721 VecPt3d MePolyRedistributePtsImpl::RedistPts2(const VecPt3d& a_pts, const VecDbl& a_interpLengths)
722 {
723  VecPt4d finalpts;
724  finalpts.reserve(a_pts.size());
725  int numint((int)a_pts.size());
726  double pcntin(0), pcntleft(0);
727  int nextid(1);
728  Pt3d prevpt(a_pts[0]);
729  prevpt.z = a_interpLengths[0];
730  Pt3d nextpt(a_pts[1]);
731  nextpt.z = a_interpLengths[1];
732  double len_segs(0), len_arc(0), length(0);
733  len_arc = length = Mdist(prevpt.x, prevpt.y, nextpt.x, nextpt.y);
734  int numfinal(0);
735  double totdist(0), w1(0), w2(0);
736  bool done(false);
737  while (!done)
738  {
739  w1 = prevpt.z; // weight at first point
740  w2 = nextpt.z; // weight at second point
741  pcntleft = pcntin + 2 * length / (w1 + w2);
742  // check if we should add a point
743  if (pcntleft >= 1)
744  { // calc new pt location
745  double scale = 1.0 - pcntin;
746  double ptlength = 2 * scale * w1 * length / (2 * length + scale * (w1 - w2));
747  totdist += ptlength;
748  // weight at new point
749  double pcnt = ptlength / length;
750  double newweight = w1 * (1 - pcnt) + w2 * pcnt;
751  // add to final points
752  ++numfinal;
753  finalpts.push_back(Pt4d());
754  finalpts[numfinal - 1].x = prevpt.x + pcnt * (nextpt.x - prevpt.x);
755  finalpts[numfinal - 1].y = prevpt.y + pcnt * (nextpt.y - prevpt.y);
756  finalpts[numfinal - 1].z = newweight;
757  finalpts[numfinal - 1].w = totdist;
758  len_segs += totdist;
759  prevpt = finalpts[numfinal - 1];
760  totdist = 0.0;
761  // get length of segment left after inserting pt
762  length -= ptlength;
763  pcntin = 0.0;
764  }
765  else
766  { // go on to next segment
767  pcntin = pcntleft;
768  if (++nextid < numint)
769  {
770  prevpt = nextpt;
771 
772  nextpt = a_pts[nextid];
773  nextpt.z = a_interpLengths[nextid];
774  totdist += length;
775  length = Mdist(prevpt.x, prevpt.y, nextpt.x, nextpt.y);
776  len_arc += length;
777  }
778  else
779  done = true;
780  }
781  }
782 
783  // make sure we still have an arc
784  if (numfinal > 0)
785  {
786  double len_segs_to_adjust = 0.0;
787  // init length of the arc to adjust to remaining portion
788  double len_arc_to_adjust = len_arc - len_segs;
789  // init first point to move as the last in the list
790  int first_pt_to_move = numfinal - 1;
791  // eliminate last part_seg if less than half
792  if (pcntin < 0.5)
793  --numfinal;
794  // keep the length of the last seg if more than half
795  else
796  len_segs_to_adjust = (length + totdist) / pcntleft;
797  // find segs with length close to final length to find first pt to move
798  while (first_pt_to_move >= 0 && finalpts[first_pt_to_move].w < w1 * 2.0 &&
799  finalpts[first_pt_to_move].w > w1 * 0.5)
800  {
801  len_segs_to_adjust += finalpts[first_pt_to_move].w;
802  len_arc_to_adjust += finalpts[first_pt_to_move].w;
803  --first_pt_to_move;
804  }
805  ++first_pt_to_move;
806  // find error adjustment scale
807  double scale = len_arc_to_adjust / len_segs_to_adjust;
808  /* reset the locations using scaled distance */
809  nextid = 1;
810  prevpt = a_pts[0];
811  prevpt.z = a_interpLengths[0];
812  nextpt = a_pts[1];
813  nextpt.z = a_interpLengths[1];
814  length = Mdist(prevpt.x, prevpt.y, nextpt.x, nextpt.y);
815  for (int i = 0; i < numfinal; i++)
816  {
817  if (i < first_pt_to_move)
818  {
819  totdist = finalpts[i].w;
820  // move along int points until reach finalpt
821  while (totdist > length)
822  {
823  totdist -= length;
824  // go onto next segment
825  prevpt = nextpt;
826  ++nextid;
827  nextpt = a_pts[nextid];
828  nextpt.z = a_interpLengths[nextid];
829  length = Mdist(prevpt.x, prevpt.y, nextpt.x, nextpt.y);
830  }
831  }
832  else
833  {
834  totdist = finalpts[i].w * scale;
835  // move along int points until reach finalpt
836  while (totdist > length)
837  {
838  totdist -= length;
839  // go onto next segment
840  prevpt = nextpt;
841  ++nextid;
842  nextpt = a_pts[nextid];
843  nextpt.z = a_interpLengths[nextid];
844  length = Mdist(prevpt.x, prevpt.y, nextpt.x, nextpt.y);
845  }
846  // reached point to move
847  double pcnt = totdist / length;
848  finalpts[i].x = prevpt.x + pcnt * (nextpt.x - prevpt.x);
849  finalpts[i].y = prevpt.y + pcnt * (nextpt.y - prevpt.y);
850  }
851  prevpt = finalpts[i];
852  length -= totdist;
853  }
854  }
855 
856  VecPt3d ret;
857  // if arc closes, make sure there are at least 3 points on arc
858  if (a_pts.front() == a_pts.back() && numfinal < 2)
859  {
860  if (a_pts.size() < 3)
861  return ret;
862 
863  finalpts.resize(2);
864  finalpts[0] = a_pts[a_pts.size() / 3];
865  finalpts[1] = a_pts[a_pts.size() * 2 / 3];
866  }
867  ret.assign(finalpts.size() + 2, Pt3d());
868  ret.front() = a_pts.front();
869  ret.back() = a_pts.back();
870  for (size_t i = 1; i < finalpts.size(); ++i)
871  ret[i] = finalpts[i];
872  return ret;
873 } // MePolyRedistributePtsImpl::RedistPts2
874 //------------------------------------------------------------------------------
881 //------------------------------------------------------------------------------
883  int a_polyType,
884  MePolyOffsetterOutput& a_out)
885 {
886  if (a_pts.empty())
887  return;
888  a_out.m_loopTypes.push_back(a_polyType);
889  a_out.m_loops.push_back(VecSizet());
890  for (size_t i = 0; i < a_pts.size(); ++i)
891  {
892  a_out.m_loops.back().push_back(a_out.m_pts.size());
893  a_out.m_pts.push_back(a_pts[i]);
894  }
895 } // MePolyRedistributePtsImpl::RedistPtsToOutput
896 //------------------------------------------------------------------------------
910 //------------------------------------------------------------------------------
912  size_t a_nextIdx,
913  const VecDbl& a_segLengths,
914  const VecDbl& a_segTvalues,
915  const VecDbl& a_interpLengths,
916  double& a_pcntin,
917  VecDbl& a_tVals)
918 {
919  // current segment length
920  double length(a_segLengths[a_idx]);
921  // tvalues at the begin and end of current segment
922  double t1(a_segTvalues[a_idx]), t2(a_segTvalues[a_nextIdx]);
923  if (0 == a_nextIdx)
924  t2 = 1;
925  // target segment length at begin and end of segment
926  double w1(a_interpLengths[a_idx]), w2(a_interpLengths[a_nextIdx]);
927 
928  bool done(false);
929  while (!done)
930  {
931  double pcntleft = a_pcntin + (2 * length) / (w1 + w2);
932  if (pcntleft >= 1.0)
933  {
934  double scale = 1.0 - a_pcntin;
935  double ptlength = 2 * scale * w1 * length / (2 * length + scale * (w1 - w2));
936  double pcnt = ptlength / length;
937  double t = (pcnt * (t2 - t1)) + t1; // convert to polyline tval
938  a_tVals.push_back(t);
939 
940  w1 = w1 * (1 - pcnt) + w2 * pcnt;
941  t1 = t;
942  length -= ptlength;
943  a_pcntin = 0;
944  }
945  else
946  {
947  a_pcntin = pcntleft;
948  done = true;
949  }
950  }
951 } // MePolyRedistributePtsImpl::TvaluesForSeg
952 //------------------------------------------------------------------------------
957 //------------------------------------------------------------------------------
959  const VecPt3d2d& a_inPolys)
960 {
961  m_minLength = XM_DBL_HIGHEST;
962  m_maxLength = XM_DBL_LOWEST;
963  SizeFromPolyAddEdgeLengths(a_outPoly);
964  for (size_t i = 0; i < a_inPolys.size(); ++i)
965  SizeFromPolyAddEdgeLengths(a_inPolys[i]);
966 } // MePolyRedistributePtsImpl::SizeFromPolyCalcAveEdgeLengthAtPts
967 //------------------------------------------------------------------------------
971 //------------------------------------------------------------------------------
973 {
974  double l(0), dx, dy;
975  size_t start = m_polyEdgeLengths.size();
976  m_polyEdgeLengths.insert(m_polyEdgeLengths.end(), a_pts.size(), 0);
977  for (size_t i = 0; i < a_pts.size(); ++i)
978  {
979  size_t nextIdx(0);
980  Pt3d nextPt(a_pts[0]);
981  if (i + 1 < a_pts.size())
982  {
983  nextIdx = i + 1;
984  nextPt = a_pts[i + 1];
985  }
986  m_polyPts->push_back(a_pts[i]);
987 
988  dx = a_pts[i].x - nextPt.x;
989  dy = a_pts[i].y - nextPt.y;
990  l = sqrt(dx * dx + dy * dy);
991  if (l < m_minLength)
992  m_minLength = l;
993  if (l > m_maxLength)
994  m_maxLength = l;
995  l = l / 2;
996  m_polyEdgeLengths[i + start] += l;
997  m_polyEdgeLengths[nextIdx + start] += l;
998  }
999 } // MePolyRedistributePtsImpl::SizeFromPolyAddEdgeLengths
1000 //------------------------------------------------------------------------------
1007 //------------------------------------------------------------------------------
1009  VecDbl& a_segLength,
1010  VecDbl& a_segTvalues)
1011 {
1012  a_segLength.assign(a_pts.size() - 1, 0);
1013  a_segTvalues.assign(a_pts.size() - 1, 0);
1014  double totalLength(0);
1015  for (size_t i = 1; i < a_pts.size(); ++i)
1016  {
1017  const Pt3d &p0(a_pts[i - 1]), &p1(a_pts[i]);
1018  a_segLength[i - 1] = Mdist(p0.x, p0.y, p1.x, p1.y);
1019  totalLength += a_segLength[i - 1];
1020  }
1021  double sumLen(0);
1022  for (size_t i = 1; i < a_pts.size() - 1; ++i)
1023  {
1024  sumLen += a_segLength[i - 1];
1025  a_segTvalues[i] = sumLen / totalLength;
1026  }
1027 } // MePolyRedistributePtsImpl::CalcSegLengths
1028 //------------------------------------------------------------------------------
1037 //------------------------------------------------------------------------------
1039  double a_tVal,
1040  size_t& a_segIdx,
1041  double& a_segT0,
1042  double& a_segT1)
1043 {
1044  if (a_tVal > 1)
1045  {
1046  XM_ASSERT(0);
1047  a_tVal = 1;
1048  }
1049  if (a_segIdx >= a_segTvalues.size())
1050  a_segIdx = 0;
1051 
1052  a_segT0 = a_segTvalues[a_segIdx];
1053  a_segT1 = 1;
1054  if (a_segIdx + 1 < a_segTvalues.size())
1055  a_segT1 = a_segTvalues[a_segIdx + 1];
1056 
1057  bool done = false;
1058  while (!done)
1059  {
1060  if (a_tVal >= a_segT0 && a_tVal <= a_segT1)
1061  done = true;
1062  else
1063  {
1064  a_segIdx++;
1065  a_segT0 = a_segTvalues[a_segIdx];
1066  a_segT1 = 1;
1067  if (a_segIdx + 1 < a_segTvalues.size())
1068  a_segT1 = a_segTvalues[a_segIdx + 1];
1069  }
1070  }
1071 } // MePolyRedistributePtsImpl::GetSegmentFromTval
1072 //------------------------------------------------------------------------------
1074 //------------------------------------------------------------------------------
1076 {
1077  m_polys.assign(m_sizeTris->size() / 3, VecInt(3, 0));
1078  int* iPtr(&(*m_sizeTris)[0]);
1079  size_t idx;
1080  for (size_t i = 0; i < m_polys.size(); ++i)
1081  {
1082  idx = i * 3;
1083  m_polys[i][0] = iPtr[idx + 0];
1084  m_polys[i][1] = iPtr[idx + 1];
1085  m_polys[i][2] = iPtr[idx + 2];
1086  }
1087  BSHP<GmMultiPolyIntersectionSorterTerse> sorterTerse =
1088  boost::make_shared<GmMultiPolyIntersectionSorterTerse>();
1089  BSHP<GmMultiPolyIntersectionSorter> sorter = BDPC<GmMultiPolyIntersectionSorter>(sorterTerse);
1091 
1092 } // MePolyRedistributePtsImpl::CreatePolyIntersector
1093 //------------------------------------------------------------------------------
1100 //------------------------------------------------------------------------------
1101 void mePolyPaverRedistribute(BSHP<MePolyRedistributePts> a_redist,
1102  const MePolyOffsetterOutput& a_input,
1103  MePolyOffsetterOutput& a_out,
1104  int a_polyOffsetIter)
1105 {
1106  BSHP<MePolyRedistributePtsImpl> r = BDPC<MePolyRedistributePtsImpl>(a_redist);
1107  XM_ENSURE_TRUE(r);
1108  r->Redistribute(a_input, a_out, a_polyOffsetIter);
1109 } // mePolyPaverRedistribute
1110 
1111 } // namespace xms
1112 
1113 #ifdef CXX_TEST
1114 
1117 
1118 #include <xmscore/testing/TestTools.h>
1119 #include <xmsinterp/geometry/geoms.h>
1120 
1121 // namespace xms {
1122 using namespace xms;
1123 
1128 //------------------------------------------------------------------------------
1130 //------------------------------------------------------------------------------
1132 {
1133  BSHP<MePolyRedistributePts> b = MePolyRedistributePts::New();
1134  TS_ASSERT(b);
1135 } // MePolyRedistributePtsUnitTests::testCreateClass
1136 //------------------------------------------------------------------------------
1138 //------------------------------------------------------------------------------
1140 {
1142  // input polygon
1143  VecPt3d outPoly = {{0, 0, 0}, {0, 10, 0}, {10, 10, 0}, {10, 0, 0}};
1144  VecPt3d2d inPolys;
1145  r.SetSizeFuncFromPoly(outPoly, inPolys, 1);
1146  VecPt3d pts = {{1, 1, 0}, {1, 9, 0}, {9, 9, 0}, {9, 1, 0}};
1147  VecDbl lengths;
1148  r.InterpEdgeLengths(pts, lengths);
1149  VecDbl baseLengths = {10.0, 10.0, 10.0, 10.0};
1150  TS_ASSERT_EQUALS_VEC(baseLengths, lengths);
1151 } // MePolyRedistributePtsUnitTests::testInterpEdgeLengths
1152 //------------------------------------------------------------------------------
1154 //------------------------------------------------------------------------------
1156 {
1158  // input polygon
1159  VecPt3d outPoly = {{0, 0, 0}, {0, 2, 0}, {0, 4, 0}, {0, 6, 0},
1160  {0, 8, 0}, {0, 10, 0}, {10, 10, 0}, {10, 0, 0}};
1161  VecPt3d2d inPolys;
1162  r.SetSizeFuncFromPoly(outPoly, inPolys, 1);
1163  VecPt3d pts = {{1, 1, 0}, {1, 9, 0}, {9, 9, 0}, {9, 1, 0}};
1164  VecDbl lengths;
1165  r.InterpEdgeLengths(pts, lengths);
1166  VecDbl baseLengths = {5.00892, 5.00892, 9.79527, 9.79527};
1167  TS_ASSERT_DELTA_VEC(baseLengths, lengths, 1e-5);
1168 } // MePolyRedistributePtsUnitTests::testInterpEdgeLengths1
1169 //------------------------------------------------------------------------------
1171 //------------------------------------------------------------------------------
1173 {
1175  // input polygon
1176  VecPt3d outPoly = {{0, 0, 0}, {0, 2, 0}, {0, 4, 0}, {0, 6, 0},
1177  {0, 8, 0}, {0, 10, 0}, {10, 10, 0}, {10, 0, 0}};
1178  VecPt3d2d inPolys;
1179  VecPt3d in = {{4.9, 5, 0}, {4.95, 4.9, 0}, {5.05, 4.9, 0},
1180  {5.1, 5, 0}, {5.50, 5.1, 0}, {4.95, 5.1, 0}};
1181  inPolys.push_back(in);
1182 
1183  r.SetSizeFuncFromPoly(outPoly, inPolys, 1);
1184  VecPt3d pts = {{1, 1, 0}, {1, 9, 0}, {9, 9, 0}, {9, 1, 0}};
1185  VecDbl lengths;
1186  r.InterpEdgeLengths(pts, lengths);
1187  VecDbl baseLengths = {4.96661, 4.96586, 9.71356, 9.71552};
1188  TS_ASSERT_DELTA_VEC(baseLengths, lengths, 1e-5);
1189  r.m_sizeBias = 0;
1190  r.InterpEdgeLengths(pts, lengths);
1191  baseLengths = {3.36034, 3.36167, 7.02831, 7.03054};
1192  TS_ASSERT_DELTA_VEC(baseLengths, lengths, 1e-5);
1193 } // MePolyRedistributePtsUnitTests::testInterpEdgeLengths2
1194 //------------------------------------------------------------------------------
1196 //------------------------------------------------------------------------------
1198 {
1200  r.SetConstantSizeFunc(5.0);
1201  VecPt3d pts = {{0, 0, 0}, {0, 100, 0}, {100, 100, 0}, {100, 0, 0}};
1202  VecDbl lengths;
1203  r.InterpEdgeLengths(pts, lengths);
1204  VecDbl baseLengths(4, 5.0);
1205  TS_ASSERT_EQUALS_VEC(baseLengths, lengths);
1206 } // MePolyRedistributePtsUnitTests::testInterpEdgeLengths3
1207 //------------------------------------------------------------------------------
1209 //------------------------------------------------------------------------------
1211 {
1213  // r.SetConstantSizeFunc(5.0);
1214  VecPt3d pts = {{0, 0, 0}, {0, 100, 0}, {100, 100, 0}, {100, 0, 0}};
1215  VecDbl lengths;
1216  r.InterpEdgeLengths(pts, lengths);
1217  VecDbl baseLengths(4, 100.0);
1218  TS_ASSERT_EQUALS_VEC(baseLengths, lengths);
1219 } // MePolyRedistributePtsUnitTests::testInterpEdgeLengths4
1220 //------------------------------------------------------------------------------
1222 //------------------------------------------------------------------------------
1224 {
1225  VecPt3d pts = {{0, 0, 0}, {0, 10, 0}, {10, 10, 0}, {10, 0, 0}, {0, 0, 0}};
1226  VecDbl lengths = {5, 5, 5, 5, 5};
1227 
1229  VecPt3d outPts = r.RedistPts(pts, lengths);
1230  VecPt3d basePts = {{0, 0, 0}, {0, 5, 0}, {0, 10, 0}, {5, 10, 0}, {10, 10, 0},
1231  {10, 5, 0}, {10, 0, 0}, {5, 0, 0}, {0, 0, 0}};
1232  TS_ASSERT_EQUALS_VEC(basePts, outPts);
1233 } // MePolyRedistributePtsUnitTests::testRedistPts
1234 //------------------------------------------------------------------------------
1236 //------------------------------------------------------------------------------
1238 {
1239  VecPt3d pts = {{0, 0, 0}, {0, 10, 0}, {10, 10, 0}, {10, 0, 0}, {0, 0, 0}};
1240  VecDbl lengths = {4, 4, 4, 4, 4};
1241 
1243  VecPt3d outPts = r.RedistPts(pts, lengths);
1244  VecPt3d basePts = {{0, 0, 0}, {0, 4, 0}, {0, 8, 0}, {2, 10, 0}, {6, 10, 0}, {10, 10, 0},
1245  {10, 6, 0}, {10, 2, 0}, {8, 0, 0}, {4, 0, 0}, {0, 0, 0}};
1246  TS_ASSERT_DELTA_VECPT3D(basePts, outPts, 1e-9);
1247 } // MePolyRedistributePtsUnitTests::testRedistPts1
1248 //------------------------------------------------------------------------------
1250 //------------------------------------------------------------------------------
1252 {
1253  VecPt3d pts = {{0, 0, 0}, {0, 10, 0}, {10, 10, 0}, {10, 0, 0}, {0, 0, 0}};
1254  VecDbl lengths = {3, 3, 3, 3, 3};
1255 
1257  VecPt3d outPts = r.RedistPts(pts, lengths);
1258  VecPt3d basePts = {{0, 0, 0}, {0, 3.08, 0}, {0, 6.15, 0}, {0, 9.23, 0}, {2.31, 10, 0},
1259  {5.38, 10, 0}, {8.46, 10, 0}, {10, 8.46, 0}, {10, 5.38, 0}, {10, 2.31, 0},
1260  {9.23, 0, 0}, {6.15, 0, 0}, {3.08, 0, 0}, {0, 0, 0}};
1261  TS_ASSERT_DELTA_VECPT3D(basePts, outPts, 0.01);
1262 } // MePolyRedistributePtsUnitTests::testRedistPts2
1263 //------------------------------------------------------------------------------
1265 //------------------------------------------------------------------------------
1267 {
1268  VecPt3d pts = {{0, 0, 0}, {0, 10, 0}, {10, 10, 0}, {10, 0, 0}, {0, 0, 0}};
1269  VecDbl lengths = {3, 5, 3, 5, 3};
1270 
1272  VecPt3d outPts = r.RedistPts(pts, lengths);
1273  VecPt3d basePts = {{0, 0, 0}, {0, 3.34, 0}, {0, 7.43, 0}, {2.2, 10, 0},
1274  {6.36, 10, 0}, {9.76, 10, 0}, {10, 6.95, 0}, {10, 2.95, 0},
1275  {8.19, 0, 0}, {3.95, 0, 0}, {0, 0, 0}};
1276  TS_ASSERT_DELTA_VECPT3D(basePts, outPts, 0.01);
1277 } // MePolyRedistributePtsUnitTests::testRedistPts3
1278 //------------------------------------------------------------------------------
1280 //------------------------------------------------------------------------------
1282 {
1283  VecPt3d pts = {{0, 0, 0}, {0, 10, 0}, {10, 10, 0}, {10, 0, 0}, {0, 0, 0}};
1284  VecDbl lengths = {15, 15, 15, 15, 15};
1285 
1287  VecPt3d outPts = r.RedistPts(pts, lengths);
1288  VecPt3d basePts = {{0, 0, 0}, {3.33, 10, 0}, {10, 3.33, 0}, {0, 0, 0}};
1289  TS_ASSERT_DELTA_VECPT3D(basePts, outPts, 0.01);
1290 } // MePolyRedistributePtsUnitTests::testRedistPts4
1291 //------------------------------------------------------------------------------
1293 //------------------------------------------------------------------------------
1295 {
1296  VecPt3d pts = {{0, 0, 0}, {0, 10, 0}, {10, 10, 0}, {10, 0, 0}, {0, 0, 0}};
1297  VecDbl lengths = {20, 20, 20, 20, 20};
1298 
1300  VecPt3d outPts = r.RedistPts(pts, lengths);
1301  VecPt3d basePts = {{0, 0, 0}, {3.33, 10, 0}, {10, 3.33, 0}, {0, 0, 0}};
1302  TS_ASSERT_DELTA_VECPT3D(basePts, outPts, 0.01);
1303 } // MePolyRedistributePtsUnitTests::testRedistPts4
1304 //------------------------------------------------------------------------------
1307 //------------------------------------------------------------------------------
1309 {
1310  VecPt3d loop = {{0, 0, 0}, {0, 10, 0}, {10, 10, 0}, {10, 0, 0}};
1311  BSHP<VecPt3d> triPts(new VecPt3d());
1312  *triPts = {{5, 5, 0}, {-5, -5, 0}, {5, -5, 0}, {15, -5, 0}, {15, 5, 0},
1313  {15, 15, 0}, {5, 15, 0}, {-5, 15, 0}, {-5, 5, 0}};
1314  BSHP<VecInt> triTris(new VecInt());
1315  *triTris = {0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 7, 0, 7, 8, 0, 8, 1};
1316 
1318  r.m_sizePts = triPts;
1319  r.m_sizeTris = triTris;
1321  r.IntersectWithTris(loop);
1322  VecPt3d baseLoop = {{0, 0, 0}, {0, 5, 0}, {0, 10, 0}, {5, 10, 0},
1323  {10, 10, 0}, {10, 5, 0}, {10, 0, 0}, {5, 0, 0}};
1324  TS_ASSERT_DELTA_VECPT3D(baseLoop, loop, FLT_EPSILON);
1325 } // MePolyRedistributePtsUnitTests::testIntersectWithTris
1326 //------------------------------------------------------------------------------
1328 //------------------------------------------------------------------------------
1330 {
1331  VecPt3d pts = {{0, 0, 0}, {0, 10, 0}, {10, 10, 0}, {10, 0, 0}};
1332  VecDbl lengths = {5, 5, 5, 5};
1333 
1335  VecPt3d outPts = r.RedistPts(pts, lengths);
1336  VecPt3d basePts = {{0, 0, 0}, {0, 5, 0}, {0, 10, 0}, {5, 10, 0},
1337  {10, 10, 0}, {10, 5, 0}, {10, 0, 0}};
1338  TS_ASSERT_DELTA_VECPT3D(basePts, outPts, 0.01);
1339 } // MePolyRedistributePtsUnitTests::testRedistPolyLine
1340 //------------------------------------------------------------------------------
1342 //------------------------------------------------------------------------------
1344 {
1345  VecPt3d pts = {{0, 0, 0}, {0, 10, 0}, {10, 10, 0}, {10, 0, 0}};
1346  VecDbl lengths = {6, 6, 6, 6};
1347 
1349  VecPt3d outPts = r.RedistPts(pts, lengths);
1350  VecPt3d basePts = {{0, 0, 0}, {0, 6, 0}, {2, 10, 0}, {8, 10, 0}, {10, 6, 0}, {10, 0, 0}};
1351  TS_ASSERT_DELTA_VECPT3D(basePts, outPts, 0.01);
1352 } // MePolyRedistributePtsUnitTests::testRedistPolyLine1
1353 //------------------------------------------------------------------------------
1355 //------------------------------------------------------------------------------
1357 {
1358  VecPt3d pts = {{0, 0, 0}, {0, 10, 0}, {10, 10, 0}, {10, 0, 0}};
1359  VecDbl lengths = {3, 5, 3, 5};
1360 
1362  VecPt3d outPts = r.RedistPts(pts, lengths);
1363  VecPt3d basePts = {{0, 0, 0}, {0, 3.42, 0}, {0, 7.58, 0}, {2.43, 10, 0}, {6.66, 10, 0},
1364  {10, 9.85, 0}, {10, 6.76, 0}, {10, 3.68, 0}, {10, 0, 0}};
1365  TS_ASSERT_DELTA_VECPT3D(basePts, outPts, 0.01);
1366 } // MePolyRedistributePtsUnitTests::testRedistPolyLine2
1367 
1368 //} // namespace xms
1369 #endif
VecPt3d RedistPts(const VecPt3d &a_pts, const VecDbl &lengths)
Uses interpolated lengths to redistribute points on a polyline.
void testRedistPts1()
test redistributing the points on the polygon boundary
Redistributes the point locations on a polygon based on a size function.
#define XM_LOG(A, B)
void testInterpEdgeLengths1()
tests interpolating the edge length
std::vector< int > VecInt
double m_meanSpacingCurvature
Used by curvature redistribution. The mean spacing between the distributed points.
double m_constSize
constant size function
VecPt3d RedistPts2(const VecPt3d &a_pts, const VecDbl &lengths)
Uses interpolated lengths to redistribute points on a polyline.
static BSHP< MePolyRedistributePts > New()
Creates an instance of this class.
void SizeFromPolyAddEdgeLengths(const VecPt3d &a_pts)
Calculates average edge lengths at each point in a loop defining a polygon.
#define XM_NONE
bool m_intersectWithTris
flag to indicate that polygon should be intersected with the triangles
void testInterpEdgeLengths2()
tests interpolating the edge length
std::string STRstd(double a_value, int a_n, int width, int flags)
std::vector< double > VecDbl
#define TS_ASSERT_DELTA_VECPT3D(a, b, delta)
double m_distSqTol
tolerance used to speed up interpolation
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.
std::vector< float > VecFlt
double m_sizeBias
transition factor for size function
virtual void SetConstantSizeFunc(double a_size) override
Sets the size function to a constant value.
void SetUseCurvatureRedistribution(double a_featureSize, double a_meanSpacing, double a_minimumCurvature, bool a_smooth) override
Specifies that curvature redistribution will be used.
virtual ~MePolyRedistributePts()
destructor
BSHP< MePolyRedistributePtsCurvature > m_curvatureRedist
Point redistributor that uses curvature.
VecDbl m_polyEdgeLengths
edge lengths of the polygon
double m_minLength
min segment length in polygon
BSHP< VecPt3d > m_polyPts
polygon point locations
static boost::shared_ptr< GmMultiPolyIntersector > New(const std::vector< Pt3d > &a_points, const std::vector< std::vector< int > > &a_polys, boost::shared_ptr< GmMultiPolyIntersectionSorter > a_sorter, int a_startingId=1)
void IntersectWithTris(VecPt3d &a_pts)
Creates a vector of pts from indices into another vector of points.
void testRedistPts5()
test redistributing the points on the polygon boundary
convenience class for holding output data from the MePolyOffsetter
std::vector< Pt3d > m_pts
locations used by polygons
void testRedistPts4()
test redistributing the points on the polygon boundary
void testInterpEdgeLengths()
tests interpolating the edge length
void InterpToPoint(size_t a_idx, const VecPt3d &a_pts, VecDbl &a_lengths, VecDbl &a_wt, VecDbl &a_d2, double &a_bias)
Interpolates to a point from the boundary of the polygon.
void InterpEdgeLengths(const VecPt3d &a_pts, VecDbl &lengths)
Interpolates edge lengths to each of the points that make up a polyline.
void GetSegmentFromTval(const VecDbl &a_segTvalues, double a_tVal, size_t &a_segIdx, double &a_segT0, double &a_segT1)
Finds the segment that contains a_tVal.
void testInterpEdgeLengths4()
tests interpolating the edge length
std::vector< VecInt > VecInt2d
Redistributes points along polylines using a size function.
void testRedistPolyLine1()
test redistributing the points on a polyline
BSHP< GmMultiPolyIntersector > m_polyIntersector
used to intersect the polygon with m_sizeTris
BSHP< InterpBase > m_interp
interpolation class given to this class
void CreatePolyIntersector()
Creates the poly intersector class member variable.
std::vector< std::size_t > VecSizet
double MdistSq(_T x1, _U y1, _V x2, _W y2)
void SizeFromPolyCalcAveEdgeLengthAtPts(const VecPt3d &a_outPoly, const VecPt3d2d &a_inPolys)
Calculates average edge lengths at each point in a loop defining a polygon.
double m_maxLength
max segment length in polygon
#define XM_ENSURE_TRUE(...)
void testIntersectWithTris()
tests intersecting the polygon with the triangles from the interp size function
virtual void SetSizeFunc(BSHP< InterpBase > a_interp) override
Sets the size function interpolator.
void testCreateClass()
tests creating the class
void testRedistPts()
test redistributing the points on the polygon boundary
#define XM_NODATA
BSHP< VecPt3d > m_sizePts
points from the m_interp class
#define XM_ASSERT(x)
void testInterpEdgeLengths3()
tests interpolating the edge length
virtual std::string ToPyRepr() const override
returns a string for use in the python repr attribute
std::vector< VecPt3d > VecPt3d2d
VecPt3d LoopToVecPt3d(const VecSizet &a_idx, const VecPt3d &a_pts)
Creates a vector of pts from indices into another vector of points.
void Redistribute(const MePolyOffsetterOutput &a_input, MePolyOffsetterOutput &a_out, int a_polyOffsetIter)
Redistributes points on closed loop polylines. The length of edges in the redistribution comes from a...
std::vector< int > m_loopTypes
type of loop
static BSHP< MePolyRedistributePtsCurvature > New()
Creates an instance of this class.
virtual double SizeFromLocation(const Pt3d &a_location) override
returns a size based on the xy location
void CalcSegLengths(const VecPt3d &a_pts, VecDbl &a_segLength, VecDbl &_segTvalues)
Calculates the lengths of segments and parametric values of segment endpoints.
double Mdist(_T x1, _U y1, _V x2, _W y2)
std::vector< std::vector< size_t > > m_loops
indexes of points that define loops
virtual void SetConstantSizeBias(double a_sizeBias) override
Sets the bias for constant value size function.
void TvaluesForSeg(size_t a_idx, size_t a_nextIdx, const VecDbl &a_segLengths, const VecDbl &a_segTvalues, const VecDbl &a_interpLengths, double &a_pcntin, VecDbl &a_tVals)
A single segment of a polygon is analyzed to see where points are redistributed on that segment...
BSHP< VecInt > m_sizeTris
triangles from the m_interp class
virtual void SetSizeFuncFromPoly(const VecPt3d &a_outPoly, const VecPt3d2d &a_inPolys, double a_sizeBias) override
Creates an interpolator that uses the spacing on the input polygon as its scalar. ...
void CalcInterpWeights(const Pt3d &a_pt, VecDbl &a_wt, VecDbl &a_d2, double &a_sumWt)
Calculates the interpolation weights of the points used to do the interpolation.
void RedistPtsToOutput(const VecPt3d &a_pts, int a_polyType, MePolyOffsetterOutput &a_out)
Move the redistributed points to the output class.
#define TS_ASSERT_EQUALS_VEC(a, b)
void testRedistPolyLine2()
test redistributing the points on a polyline
std::vector< Pt4d > VecPt4d
void testRedistPts3()
test redistributing the points on the polygon boundary
void testRedistPolyLine()
test redistributing the points on a polyline
bool m_biasConstSize
flag to indicate transitioning to constant size function
#define TS_ASSERT_DELTA_VEC(a, b, delta)
std::vector< Pt3d > VecPt3d
void testRedistPts2()
test redistributing the points on the polygon boundary