xmsmesh  1.0
MePolyPatcher.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 <set>
17 
18 // 4. External library headers
19 
20 // 5. Shared code headers
21 #include <xmscore/math/math.h>
22 #include <xmscore/misc/DynBitset.h>
23 #include <xmscore/misc/XmError.h>
24 #include <xmscore/misc/XmLog.h>
25 #include <xmscore/misc/xmstype.h>
29 
30 // 6. Non-shared code headers
31 
32 //----- Forward declarations ---------------------------------------------------
34 
35 //----- External globals -------------------------------------------------------
36 
37 //----- Namespace declaration --------------------------------------------------
38 namespace xms
39 {
40 //----- Constants / Enumerations -----------------------------------------------
41 
42 //----- Classes / Structs ------------------------------------------------------
43 
44 //----- Internal functions -----------------------------------------------------
45 
46 //----- Class / Function definitions -------------------------------------------
52 {
54 public:
56  : m_n0(0)
57  , m_n1(0)
58  , m_dn(0)
59  , m_np_end(0)
60  , m_m0(0)
61  , m_m1(0)
62  , m_dm(0)
63  , m_np_side(0)
64  , m_ptSearch(GmPtSearch::New(true))
65  , m_meshPts(new VecPt3d())
66  , m_polyId(-1)
67  {
68  m_ptSearch->VectorThatGrowsToSearch(m_meshPts);
69  }
70 
71  virtual bool MeshIt(int a_polyId,
72  const VecPt3d& a_outPoly,
73  const VecInt& a_polyCorners,
74  double a_xytol,
75  VecPt3d& a_points,
76  VecInt& a_cells) override;
77 
78  size_t PolyCornerClosestToTopLeft(const VecPt3d& a_oPoly,
79  const VecInt& a_idx,
80  const Pt3d& a_topLeft);
81  void PolyPtsToSides(const VecPt3d& a_outPoly, const VecInt& a_polyCorners);
82  void OrderPoints();
83  bool QuadPatchErrors(const VecPt3d& a_outPoly, const VecInt& a_polyCorners);
84  void QuadPatch(const VecPt3d& a_outPoly, const VecInt& a_polyCorners);
85  bool SetupSideInfo();
86  bool AdjustNodesInCol3a(VecInt& a_nodesincol, int flag);
87  void GetPercentages(int a_np, const VecPt3d& a_pts, VecDbl& pcnts);
88  void PointsFromPercentages(const VecPt3d& a_pts,
89  const VecDbl& a_pcnts,
90  int a_np_new,
91  VecPt3d& a_ptsNew);
92  void InterpolatePercentages(const VecDbl& a_pcnt_in, VecDbl& a_pcnt_out);
93  void CalcPointPercentages();
94  void GenerateMeshPts();
95  void SetUpColumnForRectPatch3a(int a_j, VecPt3d& a_newcol);
96  void GenerateMeshCells();
97  void ValidateMeshCells();
98  bool CellOverlapsAdj(int a_cellIdx, DynBitset& a_cellFlags);
99 
101  void GetCellPtInfo(int a_cellIdx, VecInt& a_ptIdxs, VecInt& a_adjCellIdx, VecInt2d& a_adjPts);
102 
104  m_side1pts,
105  m_side2pts,
106  m_end1pts,
107  m_end2pts;
108  int m_n0,
109  m_n1,
110  m_dn,
111  m_np_end,
112  m_m0,
113  m_m1,
114  m_dm,
115  m_np_side;
117  m_nodesincol;
119  m_side2pcnt,
120  m_end1pcnt,
121  m_end2pcnt;
124  m_newend1pcnt,
125  m_newend2pcnt;
126 
127  BSHP<GmPtSearch> m_ptSearch;
128  BSHP<VecPt3d> m_meshPts;
132  double m_xytol;
134  m_ptCellIdx,
135  m_ptAdjCells,
136  m_cellIdx;
137  int m_polyId;
138 };
139 
140 //------------------------------------------------------------------------------
143 //------------------------------------------------------------------------------
144 BSHP<MePolyPatcher> MePolyPatcher::New()
145 {
146  BSHP<MePolyPatcher> ret(new MePolyPatcherImpl());
147  return ret;
148 } // MePolyPaverToMeshPts::New
149 //------------------------------------------------------------------------------
159 //------------------------------------------------------------------------------
160 bool MePolyPatcherImpl::MeshIt(int a_polyId,
161  const VecPt3d& a_outPoly,
162  const VecInt& a_polyCorners,
163  double a_xytol,
164  VecPt3d& a_points,
165  VecInt& a_cells)
166 {
167  m_polyId = a_polyId;
168  m_xytol = a_xytol;
169  size_t nCorner = a_polyCorners.size();
170  // if all corner indices are the same we have a problem
171  bool same(true);
172  for (size_t i = 1; same && i < a_polyCorners.size(); ++i)
173  {
174  if (a_polyCorners[i] != a_polyCorners[0])
175  same = false;
176  }
177  if (same)
178  nCorner = 1;
179 
180  if (2 == nCorner || 3 == nCorner)
181  QuadPatch(a_outPoly, a_polyCorners);
182  else
183  {
184  std::string msg = "Polygon corners incorrectly specified. Aborting patch mesh generation.";
186  XM_LOG(xmlog::error, msg);
187  return false;
188  }
189 
190  a_points.swap(*m_meshPts);
191  a_cells.swap(m_meshCells);
192  return true;
193 } // MePolyPatcherImpl::MeshIt
194 //------------------------------------------------------------------------------
200 //------------------------------------------------------------------------------
202  const VecInt& a_idx,
203  const Pt3d& a_topLeft)
204 {
205  int polyCornerIdx(0);
206  double dist = MdistSq(a_oPoly[0].x, a_oPoly[0].y, a_topLeft.x, a_topLeft.y);
207  for (size_t i = 0; i < a_idx.size(); ++i)
208  {
209  int q = a_idx[i];
210  double d1 = MdistSq(a_oPoly[q].x, a_oPoly[q].y, a_topLeft.x, a_topLeft.y);
211  if (d1 < dist)
212  {
213  dist = d1;
214  polyCornerIdx = (int)i;
215  }
216  }
217  return polyCornerIdx;
218 } // MePolyPatcherImpl::PolyCornerClosestToTopLeft
219 //------------------------------------------------------------------------------
223 //------------------------------------------------------------------------------
224 void MePolyPatcherImpl::PolyPtsToSides(const VecPt3d& a_outPoly, const VecInt& a_polyCorners)
225 {
226  XM_ENSURE_TRUE(!a_outPoly.empty());
227  // create pt vectors (like the figure) from a_outPoly
228  // pts[3]
229  // | -----------------> |
230  // | |
231  // | |
232  // | |
233  // | |
234  // pts[0] | | pts[2]
235  // | |
236  // | |
237  // | |
238  // | |
239  // | |
240  // v -----------------> v
241  // pts[1]
242 
243  Pt3d pMin, pMax;
244  gmEnvelopeOfPts(a_outPoly, pMin, pMax);
245  // find corner that is closest to the upper left of the poly envelope
246  VecInt idx(1, 0);
247  idx.insert(idx.end(), a_polyCorners.begin(), a_polyCorners.end());
248  Pt3d topLeft(pMin);
249  topLeft.y = pMax.y;
250  size_t polyCornerIdx = PolyCornerClosestToTopLeft(a_outPoly, idx, topLeft);
251 
252  // fill in the arrays of points from a_outPoly
253  VecPt3d pts(a_outPoly);
254  idx.push_back((int)pts.size());
255  pts.push_back(pts.front());
256  VecPt3d2d tmpPts;
257  tmpPts.assign(idx.size() - 1, VecPt3d());
258  for (size_t i = 1; i < idx.size(); ++i)
259  {
260  for (int j = idx[i - 1]; j <= idx[i]; ++j)
261  {
262  tmpPts[i - 1].push_back(pts[j]);
263  }
264  }
265  // this array tells the order of tmpPts to m_pts shown in the figure above
266  int ix[4][4] = {{3, 2, 1, 0}, {0, 3, 2, 1}, {1, 0, 3, 2}, {2, 1, 0, 3}};
267  m_pts.assign(4, VecPt3d());
268  m_pts[0].swap(tmpPts[ix[polyCornerIdx][0]]);
269  m_pts[1].swap(tmpPts[ix[polyCornerIdx][1]]);
270  m_pts[2].swap(tmpPts[ix[polyCornerIdx][2]]);
271  m_pts[3].swap(tmpPts[ix[polyCornerIdx][3]]);
272  std::reverse(m_pts[0].begin(), m_pts[0].end());
273  std::reverse(m_pts[1].begin(), m_pts[1].end());
274 } // MePolyPatcherImpl::PolyPtsToSides
275 //------------------------------------------------------------------------------
302 //------------------------------------------------------------------------------
304 {
305  VecInt np(m_pts.size(), 0);
306  for (size_t i = 0; i < m_pts.size(); ++i)
307  np[i] = (int)m_pts[i].size();
308 
309  int tmpnp;
310  // see if we need to switch ends and sides
311  if ((np[2] - np[0] == 0) && (np[3] - np[1] != 0))
312  { // swap end 1 with side 1
313  tmpnp = np[0];
314  np[0] = np[3];
315  np[3] = tmpnp;
316  m_pts[0].swap(m_pts[3]);
317  // swap end 2 with side 2
318  tmpnp = np[1];
319  np[1] = np[2];
320  np[2] = tmpnp;
321  m_pts[1].swap(m_pts[2]);
322  }
323  // make the end with less nodes the right end
324  if (np[0] > np[2])
325  { // swap two ends
326  tmpnp = np[0];
327  np[0] = np[2];
328  np[2] = tmpnp;
329  m_pts[0].swap(m_pts[2]);
330  // reorder two sides
331  std::reverse(m_pts[1].begin(), m_pts[1].end());
332  std::reverse(m_pts[3].begin(), m_pts[3].end());
333  }
334  // make side with less nodes the top side
335  if (np[3] > np[1])
336  { // swap two sides
337  tmpnp = np[1];
338  np[1] = np[3];
339  np[3] = tmpnp;
340  m_pts[1].swap(m_pts[3]);
341  // reorder two ends
342  std::reverse(m_pts[0].begin(), m_pts[0].end());
343  std::reverse(m_pts[2].begin(), m_pts[2].end());
344  }
345  // make difference between columns more than that between rows
346  if ((np[1] - np[3]) > (np[2] - np[0]))
347  { // swap end 1 with side 1
348  tmpnp = np[0];
349  np[0] = np[3];
350  np[3] = tmpnp;
351  m_pts[0].swap(m_pts[3]);
352  // swap end 2 with side 2
353  tmpnp = np[1];
354  np[1] = np[2];
355  np[2] = tmpnp;
356  m_pts[1].swap(m_pts[2]);
357  }
358 } // MePolyPatcherImpl::OrderPoints
359 //------------------------------------------------------------------------------
365 //------------------------------------------------------------------------------
366 bool MePolyPatcherImpl::QuadPatchErrors(const VecPt3d& a_outPoly, const VecInt& a_polyCorners)
367 {
368  bool err(false);
369  XM_ENSURE_TRUE(a_outPoly.size() > 1, true);
370 
371  // the angles at the corners must be convex
372  VecInt c;
373  c.reserve(a_polyCorners.size() + 1);
374  c.push_back(0);
375  for (size_t i = 0; i < a_polyCorners.size(); ++i)
376  c.push_back(a_polyCorners[i]);
377 
378  Pt3d p0, p1, p2;
379  p0 = a_outPoly.back();
380  p1 = a_outPoly.front();
381  p2 = a_outPoly[1];
382  double angle = gmAngleBetweenEdges(p0, p1, p2);
383  if (angle >= XM_PI)
384  err = true;
385  for (size_t i = 1; i < c.size() && !err; ++i)
386  {
387  if (c[i] == c[i - 1])
388  continue; // skip when we have a merged node
389  if (c[i] - 1 < 0)
390  {
391  std::string msg = "Invalid corner detected in polygon. Aborting patch.";
393  XM_LOG(xmlog::error, msg);
394  return true;
395  }
396  p0 = a_outPoly[c[i] - 1];
397  p1 = a_outPoly[c[i]];
398  if (c[i] + 1 < (int)a_outPoly.size())
399  p2 = a_outPoly[c[i] + 1];
400  else
401  p2 = a_outPoly[0];
402  angle = gmAngleBetweenEdges(p0, p1, p2);
403  if (angle >= XM_PI)
404  err = true;
405  }
406 
407  if (err)
408  {
409  std::string msg = "Non-convex corner detected in polygon. Aborting patch.";
411  XM_LOG(xmlog::error, msg);
412  return true;
413  }
414  // Check number of sides. There should be 3 or 4. If there are 3 we treat
415  // the corner with the smallest angle as the "merged node."
416  return false;
417 } // MePolyPatcherImpl::QuadPatchErrors
418 //------------------------------------------------------------------------------
422 //------------------------------------------------------------------------------
423 void MePolyPatcherImpl::QuadPatch(const VecPt3d& a_outPoly, const VecInt& a_polyCorners)
424 {
425  if (QuadPatchErrors(a_outPoly, a_polyCorners))
426  return;
427  PolyPtsToSides(a_outPoly, a_polyCorners);
428  OrderPoints();
429  if (!SetupSideInfo())
430  return;
431  GenerateMeshPts();
434 } // MePolyPatcherImpl::QuadPatch
435 //------------------------------------------------------------------------------
438 //------------------------------------------------------------------------------
440 {
441  // get info about sides 0, 2
442  m_n0 = (int)m_pts[0].size();
443  m_n1 = (int)m_pts[2].size();
444  m_dn = m_n1 - m_n0;
445  m_np_end = Mmax(m_n0, m_n1);
446  // get info about sides
447  m_m0 = (int)m_pts[3].size();
448  m_m1 = (int)m_pts[1].size();
449  m_np_side = Mmax(m_m0, m_m1);
450  m_dm = m_m1 - m_m0;
451  // set up these arrays
452  // nodes = (noderec***)malloc(np_end * sizeof(noderec**));
453  m_nodesinrow.assign(m_np_end, 0);
454  m_nodesincol.assign(m_np_side, 0);
455  // determine number of nodes in each column
456  double tmpd;
457  for (int i = 0; i < m_np_side; i++)
458  {
459  tmpd = ((double)i / (double)(m_np_side - 1) * m_dn);
460  if (m_dn < 0)
461  m_nodesincol[i] = m_n0 + (int)(tmpd - .5);
462  else
463  m_nodesincol[i] = m_n0 + (int)(tmpd + .5);
464  }
465  // determine number of nodes in each row
466  for (int i = 0; i < m_np_end; i++)
467  {
468  tmpd = ((double)i / (double)(m_np_end - 1) * m_dm);
469  if (m_dm < 0)
470  m_nodesinrow[i] = m_m0 + (int)(tmpd - .5);
471  else
472  m_nodesinrow[i] = m_m0 + (int)(tmpd + .5);
473  }
474 
476  return false;
478  return false;
479  return true;
480 } // MePolyPatcherImpl::SetupSideInfo
481 //------------------------------------------------------------------------------
488 //------------------------------------------------------------------------------
489 bool MePolyPatcherImpl::AdjustNodesInCol3a(VecInt& a_nodesincol, int a_flag)
490 {
491  XM_ENSURE_TRUE(!a_nodesincol.empty(), false);
492 
493  int changes = a_nodesincol.back() - a_nodesincol[0];
494 
495  if (a_flag)
496  {
497  if (changes > 1)
498  {
499  for (size_t i = 1; i < a_nodesincol.size() - 1; ++i)
500  {
501  if (a_nodesincol[i] > a_nodesincol[i - 1])
502  {
503  if (a_nodesincol[i] & 1)
504  {
505  if (!(a_nodesincol[i - 1] & 1))
506  {
507  (a_nodesincol[i])--;
508  }
509  }
510  }
511  }
512  // if both boundaries odd, make all columns odd */
513  if (a_nodesincol[0] % 2 && a_nodesincol.back() % 2)
514  {
515  for (size_t i = 1; i < a_nodesincol.size() - 1; ++i)
516  {
517  if (a_nodesincol[i] < a_nodesincol.back() && a_nodesincol[i] % 2 == 0)
518  (a_nodesincol[i])++;
519  }
520  }
521  }
522  else if (changes < -1)
523  {
524  std::string msg = "Error in polygon to patch algorithm.";
526  XM_LOG(xmlog::debug, msg);
527  return false;
528  }
529  }
530  // handle degenerate case
531  for (size_t i = 1; i < a_nodesincol.size() - 1; ++i)
532  a_nodesincol[i] = Mmax(a_nodesincol[i], 2);
533  return true;
534 } // MePolyPatcherImpl::AdjustNodesInCol3a
535 //------------------------------------------------------------------------------
540 //------------------------------------------------------------------------------
541 void MePolyPatcherImpl::GetPercentages(int a_np, const VecPt3d& a_pts, VecDbl& a_pcnts)
542 {
543  XM_ENSURE_TRUE(a_np > 0);
544  XM_ENSURE_TRUE(a_np <= (int)a_pts.size() && a_np <= (int)a_pcnts.size());
545  double len(0), delta(0);
546 
547  // get total length of points
548  for (int i = 1; i < a_np; ++i)
549  len += Mdist(a_pts[i].x, a_pts[i].y, a_pts[i - 1].x, a_pts[i - 1].y);
550  a_pcnts[0] = 0;
551  a_pcnts[a_np - 1] = 1.0;
552  // loop through middle points
553  for (int i = 1; i < a_np - 1; ++i)
554  {
555  delta += Mdist(a_pts[i].x, a_pts[i].y, a_pts[i - 1].x, a_pts[i - 1].y);
556  // AKZ
557  if (len < 0.00001)
558  a_pcnts[i] = (double)i / (double)(a_pts.size() - 1);
559  else
560  a_pcnts[i] = delta / len;
561  }
562 } // MePolyPatcherImpl::GetPercentages
563 //------------------------------------------------------------------------------
571 //------------------------------------------------------------------------------
573  const VecDbl& a_pcnt,
574  int a_np_new,
575  VecPt3d& a_ptsNew)
576 {
577  // get percentages for new column/row
578  VecDbl pcnt_new(a_np_new, 0);
579  // degenerate case
580  if (1 == a_pts.size())
581  {
582  for (size_t i = 0; i < pcnt_new.size() && i < a_ptsNew.size(); ++i)
583  {
584  a_ptsNew[i] = a_pts[0];
585  pcnt_new[i] = 1.0;
586  }
587  }
588  else
589  {
590  InterpolatePercentages(a_pcnt, pcnt_new);
591  for (size_t i = 0, j = 0; i < pcnt_new.size(); i++)
592  { // get the index before or on current percentage
593  while (j < (a_pts.size() - 1) && a_pcnt[j + 1] <= pcnt_new[i])
594  j++;
595 
596  if (j == (a_pts.size() - 1))
597  a_ptsNew[i] = a_pts[j];
598  else
599  { // get values of current percentage
600  a_ptsNew[i].x = a_pts[j].x + (pcnt_new[i] - a_pcnt[j]) * (a_pts[j + 1].x - a_pts[j].x) /
601  (a_pcnt[j + 1] - a_pcnt[j]);
602  a_ptsNew[i].y = a_pts[j].y + (pcnt_new[i] - a_pcnt[j]) * (a_pts[j + 1].y - a_pts[j].y) /
603  (a_pcnt[j + 1] - a_pcnt[j]);
604  a_ptsNew[i].z = a_pts[j].z + (pcnt_new[i] - a_pcnt[j]) * (a_pts[j + 1].z - a_pts[j].z) /
605  (a_pcnt[j + 1] - a_pcnt[j]);
606  }
607  }
608  }
609 } // MePolyPatcherImpl::PointsFromPercentages
610 //------------------------------------------------------------------------------
631 //------------------------------------------------------------------------------
632 void MePolyPatcherImpl::InterpolatePercentages(const VecDbl& a_pcnt_in, VecDbl& a_pcnt_out)
633 {
634  // fill in the x-axis arrays
635  VecDbl x_in(a_pcnt_in.size(), 0);
636  for (size_t i = 1; i < x_in.size() - 1; ++i)
637  {
638  x_in[i] = (double)i / (x_in.size() - 1);
639  }
640  x_in.back() = 1.0;
641 
642  VecDbl x_out(a_pcnt_out.size(), 0);
643  for (size_t i = 1; i < x_out.size() - 1; ++i)
644  {
645  x_out[i] = (double)i / (x_out.size() - 1);
646  }
647  x_out.back() = 1.0;
648  // find the y-axis array to fill in
649  // DSG: reset end percentages to be whatever is passed in
650  // DSG pcnt_out[0] = 0.0;
651  // DSG pcnt_out[np_out-1] = 1.0;
652  a_pcnt_out.front() = x_out.front();
653  a_pcnt_out.back() = x_out.back();
654 
655  for (size_t i = 1, j = 0; i < a_pcnt_out.size() - 1; ++i)
656  { // get the index before or on current x-loc
657  while (j < a_pcnt_in.size() - 1 && x_in[j + 1] <= x_out[i])
658  j++;
659  // get percentage of current x-loc
660  a_pcnt_out[i] = a_pcnt_in[j] + (x_out[i] - x_in[j]) * (a_pcnt_in[j + 1] - a_pcnt_in[j]) /
661  (x_in[j + 1] - x_in[j]);
662  }
663 } // MePolyPatcherImpl::InterpolatePercentages
664 //------------------------------------------------------------------------------
667 //------------------------------------------------------------------------------
669 {
670  m_side1pcnt.assign(m_m0, 0);
671  m_side2pcnt.assign(m_m1, 0);
672  m_end1pcnt.assign(m_n0, 0);
673  m_end2pcnt.assign(m_n1, 0);
678 
679  VecDbl vd(m_np_side, 0);
680  VecPt3d tmp(m_np_side, Pt3d());
681  m_side1pts.assign(m_np_end, tmp);
682  m_side2pts.assign(m_np_end, tmp);
683  m_newside1pcnt.assign(m_np_end, vd);
684  m_newside2pcnt.assign(m_np_end, vd);
685 
686  vd.resize(m_np_end, 0);
687  tmp.resize(m_np_end, Pt3d());
688  m_end1pts.assign(m_np_side, tmp);
689  m_end2pts.assign(m_np_side, tmp);
690  m_newend1pcnt.assign(m_np_side, vd);
691  m_newend2pcnt.assign(m_np_side, vd);
692 
693  // get points for each column percentages
694  for (int i = 0; i < m_np_end; ++i)
695  {
700  }
701  // get points for each row percentages
702  for (int j = 0; j < m_np_side; ++j)
703  {
708  }
709 } // MePolyPatcherImpl::CalcPointPercentages
710 //------------------------------------------------------------------------------
712 //------------------------------------------------------------------------------
714 {
716  // init m_nodeIdx to -1
717  VecInt vn(m_np_side, -1);
718  m_nodeIdx.assign(m_np_end, vn);
719  // create the first column
720  int idx;
721  for (int i = 0, j = 0; i < m_nodesincol[j]; ++i)
722  {
723  m_ptSearch->AddPtToVectorIfUnique(m_pts[0][i], XM_ZERO_TOL, idx);
724  m_nodeIdx[i][j] = (int)idx;
725  }
726  // create the last column
727  for (int i = 0, j = (int)m_nodesincol.size() - 1; i < m_nodesincol[j]; ++i)
728  {
729  m_ptSearch->AddPtToVectorIfUnique(m_pts[2][i], XM_ZERO_TOL, idx);
730  m_nodeIdx[i][j] = (int)idx;
731  }
732  // loop through columns and create mesh points
733  size_t m0(m_pts[3].size());
734  VecPt3d newcol(m_np_end, Pt3d());
735  for (int j = 1; j < m_np_side - 1; ++j)
736  {
737  SetUpColumnForRectPatch3a(j, newcol);
738  // top node
739  newcol[0] = m_pts[3][(int)((double)j / (m_np_side - 1) * (m0 - 1) + 0.5)];
740  // bottom node
741  newcol[m_nodesincol[j] - 1] = m_pts[1][j];
742  // create the nodes
743  for (int i = 0; i < m_nodesincol[j]; i++)
744  {
745  Pt3d pt1, pt2;
746  int idx1 = m_nodeIdx[i][j - 1];
747  if (idx1 > 0 && idx1 < (int)m_meshPts->size())
748  pt1 = (*m_meshPts)[idx1];
749  int idx2 = m_nodeIdx[m_nodesincol[j - 1] - 1][j - 1];
750  if (idx2 > 0 && idx2 < (int)m_meshPts->size())
751  pt2 = (*m_meshPts)[idx2];
752 
753  if (fabs(newcol[i].x + 1234.5) < XM_ZERO_TOL && fabs(newcol[i].y + 1234.5) < XM_ZERO_TOL &&
754  fabs(newcol[i].z + 1234.5) < XM_ZERO_TOL)
755  {
756  m_nodeIdx[i][j] = m_nodeIdx[0][0];
757  }
758  else if (i > 0 &&
759  Mdist(newcol[i].x, newcol[i].y, newcol[i - 1].x, newcol[i - 1].y) < XM_ZERO_TOL)
760  {
761  m_nodeIdx[i][j] = m_nodeIdx[i - 1][j];
762  }
763  else if (i == 0 && Mdist(newcol[i].x, newcol[i].y, pt1.x, pt1.y) < XM_ZERO_TOL)
764  {
765  m_nodeIdx[i][j] = m_nodeIdx[i][j - 1];
766  }
767  else if (i == m_nodesincol[j] && Mdist(newcol[i].x, newcol[i].y, pt2.x, pt2.y) < XM_ZERO_TOL)
768  {
769  m_nodeIdx[i][j] = m_nodeIdx[m_nodesincol[j - 1] - 1][j - 1];
770  }
771  else
772  {
773  m_ptSearch->AddPtToVectorIfUnique(newcol[i], XM_ZERO_TOL, idx);
774  m_nodeIdx[i][j] = (int)idx;
775  }
776  }
777  }
778 } // MePolyPatcherImpl::GenerateMeshPts
779 //------------------------------------------------------------------------------
783 //------------------------------------------------------------------------------
785 {
786  a_newcol.resize(m_np_end, Pt3d());
787  int np = m_nodesincol[a_j];
788  int np_side = m_nodesinrow.back();
789  // get corners
790  Pt3d c[4];
791  c[0] = m_end1pts[a_j][0];
792  c[1] = m_end1pts[a_j][np - 1];
793  c[2] = m_end2pts[a_j][0];
794  c[3] = m_end2pts[a_j][np - 1];
795  // find points on new column
796  for (int i = 1; i < np - 1; ++i)
797  {
798  double u_pcnt = (double)a_j / (np_side - 1);
799  int row = (int)((double)i / (np - 1) * (m_np_end - 1) + 0.5);
800  int col = (int)(u_pcnt * (m_nodesinrow[row] - 1) + 0.5);
801  // avoid messing up the mesh, find least row that gives same row
802  for (int i_test = i; row > 0 && i_test == i;)
803  {
804  i_test = (int)((double)(row - 1) / (m_np_end - 1) * (np - 1) + 0.5);
805  if (i_test == i)
806  {
807  row--;
808  col = (int)(u_pcnt * (m_nodesinrow[row] - 1) + 0.5);
809  }
810  }
811  // don't create extra nodes on boundary
812  if (col == m_nodesinrow[row] - 1 && col == 1)
813  {
814  a_newcol[i].x = a_newcol[i].y = a_newcol[i].z = -1234.5;
815  }
816  else
817  {
818  // don't create extra nodes on boundary
819  if (col == 0)
820  col++;
821  else if (col == m_nodesinrow[row] - 1)
822  col--;
823  a_newcol[0] = m_side1pts[row][col];
824  a_newcol[np - 1] = m_side2pts[row][col];
825  // avoid messing up the mesh, find least j that gives same column
826  int j_test, col_test;
827  for (j_test = a_j, col_test = col; j_test > 1 && col_test == col;)
828  {
829  col_test =
830  (int)((double)(j_test - 1) / (m_nodesinrow[m_np_end - 1] - 1) * (m_nodesinrow[row] - 1) +
831  0.5);
832  if (col_test == 0)
833  col_test++;
834  else if (col_test == m_nodesinrow[row] - 1)
835  col_test--;
836  if (col_test == col)
837  j_test--;
838  }
839  // find correct i value
840  int i_test = (int)((double)i / (m_nodesincol[a_j] - 1) * (m_nodesincol[j_test] - 1) + 0.5);
841  // handle degenerate case with this if statement
842  if (m_nodesincol[j_test] > 2)
843  {
844  if (i_test == 0)
845  i_test++;
846  else if (i_test == m_nodesincol[j_test] - 1)
847  i_test--;
848  }
849  // compute these
850  int j_min = Mmin(j_test, m_nodesinrow[i_test] - 1);
851  u_pcnt = (double)j_min / (double)(m_nodesinrow[i_test] - 1); // j_min
852  double v_pcnt = (double)i_test / (double)(m_nodesincol[j_test] - 1); // j_test
853  // now get the correct percentages
854  double u1 =
855  m_newside1pcnt[i_test][j_min] * (1.0 - v_pcnt) + m_newside2pcnt[i_test][j_min] * v_pcnt;
856  double u2 = 1.0 - u1;
857  double v1 =
858  m_newend1pcnt[j_test][i_test] * (1.0 - u_pcnt) + m_newend2pcnt[j_test][i_test] * u_pcnt;
859  double v2 = 1.0 - v1;
860  // finally, compute the x, y, z components from the Coons equation
861  a_newcol[i].x = u2 * m_end1pts[j_test][i_test].x + u1 * m_end2pts[j_test][i_test].x +
862  v2 * a_newcol[0].x + v1 * a_newcol[np - 1].x -
863  u2 * (v2 * c[0].x + v1 * c[1].x) - u1 * (v2 * c[2].x + v1 * c[3].x);
864  a_newcol[i].y = u2 * m_end1pts[j_test][i_test].y + u1 * m_end2pts[j_test][i_test].y +
865  v2 * a_newcol[0].y + v1 * a_newcol[np - 1].y -
866  u2 * (v2 * c[0].y + v1 * c[1].y) - u1 * (v2 * c[2].y + v1 * c[3].y);
867  a_newcol[i].z = u2 * m_end1pts[j_test][i_test].z + u1 * m_end2pts[j_test][i_test].z +
868  v2 * a_newcol[0].z + v1 * a_newcol[np - 1].z -
869  u2 * (v2 * c[0].z + v1 * c[1].z) - u1 * (v2 * c[2].z + v1 * c[3].z);
870  }
871  }
872 } // MePolyPatcherImpl::SetUpColumnForRectPatch3a
873 //------------------------------------------------------------------------------
875 //------------------------------------------------------------------------------
877 {
878  // These correspond to defines in vtkCellType. There are classes downstream from
879  // meshing that convert a cell stream into a vtkUnstructured grid that use these
880  // magic numbers.
881  const int VTK_QUAD(9);
882  const int VTK_TRI(5);
883 
884  // loop through columns
885  for (int j = 1; j < m_np_side; ++j)
886  {
887  // find nodes for next element as follows
888  //------------------------------------------------------------------------------
889  // node1a node2a
890  // *-------*
891  // | |
892  // | |
893  // | |
894  // *-------*
895  // node1b node2b
896  //------------------------------------------------------------------------------
897  int i(0), index1(0), index2(0);
898  for (i = 1, index1 = 0; i < m_nodesincol[j]; ++i)
899  { // find index2
900  if (m_nodesincol[j] == m_nodesincol[j - 1])
901  index2 = i;
902  else
903  {
904  double fval = (double)i / (m_nodesincol[j] - 1);
905  if (fval >= 0.50)
906  index2 = (int)(fval * (m_nodesincol[j - 1] - 1) + 0.51);
907  else
908  index2 = (int)(fval * (m_nodesincol[j - 1] - 1) + 0.49);
909  // make sure index2 is okay
910  index2 = Mmin(index2, index1 + 1);
911  }
912  // get nodes for new cell
913  int node1a(m_nodeIdx[index1][j - 1]), node1b(m_nodeIdx[index2][j - 1]),
914  node2a(m_nodeIdx[i - 1][j]), node2b(m_nodeIdx[i][j]);
915  index1 = index2;
916  // see if the element got pinched to a line
917  if ((node1a == node1b && node2a == node2b) || (node1a == node2a && node1b == node2b) ||
918  (node1a == node1b && node1a == node2a) || (node1b == node1a && node1b == node2b) ||
919  (node2b == node1b && node2b == node2a) || (node2a == node1a && node2a == node2b))
920  { // do not create element in this case
921  }
922  else
923  { // make sure nodes are ccw
924  int x[4] = {node1a, node1b, node2b, node2a};
925  VecInt n_ccw(&x[0], &x[4]);
926  VecInt idxs(4);
927  VecPt3d pts(4, Pt3d());
928  for (int i = 0; i < 4; ++i)
929  {
930  idxs[i] = i;
931  pts[i] = (*m_meshPts)[n_ccw[i]];
932  }
934  node1a = n_ccw[idxs[0]];
935  node1b = n_ccw[idxs[1]];
936  node2b = n_ccw[idxs[2]];
937  node2a = n_ccw[idxs[3]];
938  // see if new quad will be built
939  if (node1a != node1b && node2a != node2b && node1a != node2a && node1b != node2b)
940  {
941  m_meshCells.push_back(VTK_QUAD); // cell type
942  m_meshCells.push_back(4); // number of points
943  m_meshCells.push_back(node1a); // the points that make up the
944  m_meshCells.push_back(node1b); // cell
945  m_meshCells.push_back(node2b);
946  m_meshCells.push_back(node2a);
947  }
948  else
949  { // triangle will be built -- find which one
950  int ix[3];
951  ix[0] = node1a;
952  if (node1a == node1b)
953  {
954  ix[1] = node2b;
955  ix[2] = node2a;
956  }
957  else if (node2a == node2b)
958  {
959  ix[1] = node1b;
960  ix[2] = node2a;
961  }
962  else if (node1a == node2a)
963  {
964  ix[1] = node1b;
965  ix[2] = node2b;
966  }
967  else
968  {
969  ix[1] = node1b;
970  ix[2] = node2a;
971  }
972  m_meshCells.push_back(VTK_TRI);
973  m_meshCells.push_back(3);
974  for (int i = 0; i < 3; ++i)
975  m_meshCells.push_back(ix[i]);
976  }
977  }
978  }
979  }
980 } // MePolyPatcherImpl::GenerateMeshCells
981 //------------------------------------------------------------------------------
983 //------------------------------------------------------------------------------
985 {
986  if (m_meshCells.size() < 7)
987  return;
988 
990  bool err(false);
991  int nCell(0);
992  size_t i = 0;
993  while (i < m_meshCells.size())
994  {
995  ++i; // celltype
996  int numPts = m_meshCells[i++];
997  i += numPts;
998  ++nCell;
999  }
1000 
1001  DynBitset cellFlags;
1002  cellFlags.resize(nCell, false);
1003  // loop through cells
1004  for (int i = 0; !err && i < nCell; ++i)
1005  {
1006  err = CellOverlapsAdj(i, cellFlags);
1007  }
1008  if (err)
1009  {
1010  m_meshCells.clear();
1011  m_meshPts->clear();
1012  }
1013 } // MePolyPatcherImpl::ValidateMeshCells
1014 //------------------------------------------------------------------------------
1019 //------------------------------------------------------------------------------
1020 bool MePolyPatcherImpl::CellOverlapsAdj(int a_cellIdx, DynBitset& a_cellFlags)
1021 {
1022  const VecPt3d& mp(*m_meshPts);
1023  VecInt cellPtIdx, adjCellIdx;
1024  VecInt2d adjPtIdx;
1025  GetCellPtInfo(a_cellIdx, cellPtIdx, adjCellIdx, adjPtIdx);
1026  VecPt3d cellPoints;
1027  Pt3d cellCenter;
1028  for (size_t i = 0; i < cellPtIdx.size(); ++i)
1029  {
1030  cellPoints.push_back(mp[cellPtIdx[i]]);
1031  cellCenter += cellPoints.back();
1032  }
1033  cellCenter /= cellPoints.size();
1034 
1035  // add the first idx to the end of the vector so that we can test the edge defined by
1036  // the last point to the first point
1037  cellPtIdx.push_back(cellPtIdx.front());
1038  // check each edge to see if it overlaps the edges of any neighbor cell
1039  for (size_t i = 1; i < cellPtIdx.size(); ++i)
1040  {
1041  int i0(cellPtIdx[i - 1]), i1(cellPtIdx[i]);
1042  const Pt3d &p0(mp[i0]), &p1(mp[i1]);
1043  int cnt(-1);
1044  for (auto v : adjPtIdx)
1045  {
1046  cnt++;
1047  if (a_cellFlags[adjCellIdx[cnt]])
1048  continue;
1049  Pt3d adjCellCenter;
1050  VecPt3d adjacentPoints;
1051  for (size_t j = 0; j < v.size(); ++j)
1052  {
1053  adjacentPoints.push_back(mp[v[j]]);
1054  adjCellCenter += adjacentPoints.back();
1055  }
1056  adjCellCenter /= adjacentPoints.size();
1057 
1058  bool overlap(false);
1059  // see if centroid of a_cellIdx is inside of neigh
1060  if (gmPointInPolygon2D(&adjacentPoints[0], adjacentPoints.size(), cellCenter) > -1)
1061  {
1062  std::string msg = "Invalid patch. Centroid of base cell inside of adjacent cell.";
1064  XM_LOG(xmlog::error, msg);
1065  return true;
1066  }
1067 
1068  // see if centroid of neigh is inside of a_cellIdx
1069  if (gmPointInPolygon2D(&cellPoints[0], cellPoints.size(), adjCellCenter) > -1)
1070  {
1071  std::string msg = "Invalid patch. Centroid of adjacent cell inside of base cell.";
1073  XM_LOG(xmlog::error, msg);
1074  return true;
1075  }
1076 
1077  // add the first idx to the end of the vector so that we can test the edge defined by
1078  // the last point to the first point
1079  v.push_back(v.front());
1080  for (size_t j = 1; !overlap && j < v.size(); ++j)
1081  {
1082  int j0(v[j - 1]), j1(v[j]);
1083  // edges share a point in the grid so don't check if they intersect
1084  if (i0 == j0 || i0 == j1 || i1 == j0 || i1 == j1)
1085  continue;
1086 
1087  const Pt3d &p2(mp[j0]), &p3(mp[j1]);
1088  if (gmLinesIntersect(p0, p1, p2, p3))
1089  {
1090  std::string msg = "Invalid patch. Edges of adjacent cells overlap.";
1092  XM_LOG(xmlog::error, msg);
1093  return true;
1094  }
1095  }
1096  }
1097  }
1098  a_cellFlags[a_cellIdx] = true;
1099  return false;
1100 } // MePolyPatcherImpl::CellOverlapsAdj
1101 //------------------------------------------------------------------------------
1103 //------------------------------------------------------------------------------
1105 {
1106  m_ptCellCnt.assign(m_meshPts->size(), 0);
1107  m_cellIdx.reserve(m_meshCells.size() / 3);
1108  // for each point count the number of attached cells
1109  for (size_t i = 0; i < m_meshCells.size(); ++i)
1110  {
1111  m_cellIdx.push_back(static_cast<int>(i));
1112  for (int j = 0; j < m_meshCells[i + 1]; ++j)
1113  {
1114  m_ptCellCnt[m_meshCells[i + 2 + j]]++;
1115  }
1116  i += (m_meshCells[i + 1] + 1);
1117  }
1118  // for each point create an index into an array with adjacent cells listed
1119  m_ptCellIdx.assign(m_ptCellCnt.size(), 0);
1120  int last(0);
1121  for (size_t i = 0; i < m_ptCellCnt.size(); ++i)
1122  {
1123  m_ptCellIdx[i] = last;
1124  last += m_ptCellCnt[i];
1125  }
1126  // fill an array with point/cell adjacency info
1127  m_ptAdjCells.assign(last, -1);
1128  for (size_t i = 0, c = 0; i < m_meshCells.size(); ++i, ++c)
1129  {
1130  for (int j = 0; j < m_meshCells[i + 1]; ++j)
1131  {
1132  int ptIdx = m_meshCells[i + 2 + j];
1133  int ix = m_ptCellIdx[ptIdx];
1134  while (m_ptAdjCells[ix] != -1)
1135  ix++;
1136  m_ptAdjCells[ix] = (int)c;
1137  }
1138  i += (m_meshCells[i + 1] + 1);
1139  }
1140 } // MePolyPatcherImpl::CreateCellAdjacencyInfo
1141 //------------------------------------------------------------------------------
1147 //------------------------------------------------------------------------------
1149  VecInt& a_ptIdxs,
1150  VecInt& a_adjCellIdx,
1151  VecInt2d& a_adjPts)
1152 {
1153  // get points for this cell
1154  a_ptIdxs.resize(0);
1155  int ix = m_cellIdx[a_cellIdx];
1156  for (int i = 0; i < m_meshCells[ix + 1]; ++i)
1157  {
1158  a_ptIdxs.push_back(m_meshCells[ix + 2 + i]);
1159  }
1160  // get adjacent cell points
1161  std::set<int> adjCells;
1162  adjCells.insert(a_cellIdx);
1163  a_adjPts.resize(0);
1164  a_adjCellIdx.resize(0);
1165  for (size_t i = 0; i < a_ptIdxs.size(); ++i)
1166  {
1167  const int& px = a_ptIdxs[i];
1168  ix = m_ptCellIdx[px];
1169  // adjacent cells
1170  for (int j = 0; j < m_ptCellCnt[px]; ++j)
1171  {
1172  const int& cx1 = m_ptAdjCells[ix + j]; // adjacent cell
1173  if (adjCells.find(cx1) != adjCells.end())
1174  continue;
1175  adjCells.insert(cx1);
1176  a_adjPts.push_back(VecInt());
1177  a_adjCellIdx.push_back(cx1);
1178  const int& cx = m_cellIdx[cx1];
1179  for (int k = 0; k < m_meshCells[cx + 1]; ++k)
1180  { // points on this cell
1181  const int& pt(m_meshCells[cx + 2 + k]);
1182  a_adjPts.back().push_back(pt);
1183  }
1184  }
1185  }
1186 } // MePolyPatcherImpl::GetCellPtInfo
1187 
1188 } // namespace xms
1189 
1190 #ifdef CXX_TEST
1191 
1194 
1195 #include <xmscore/testing/TestTools.h>
1196 
1201 //------------------------------------------------------------------------------
1203 //------------------------------------------------------------------------------
1205 {
1206  BSHP<xms::MePolyPatcher> p = xms::MePolyPatcher::New();
1207  TS_ASSERT(p);
1208 } // MeIntersectPolysTest::testCreateClass
1209 //------------------------------------------------------------------------------
1211 //------------------------------------------------------------------------------
1213 {
1214  xms::VecPt3d pts;
1215  {
1216  using namespace xms;
1217  pts = {{0, 0, 0}, {0, 10, 0}, {0, 20, 0}, {0, 30, 0}, {10, 30, 0}, {20, 30, 0},
1218  {30, 30, 0}, {30, 20, 0}, {30, 10, 0}, {30, 0, 0}, {20, 0, 0}, {10, 0, 0}};
1219  }
1220  xms::VecInt corner = {3, 6, 9};
1222  p.PolyPtsToSides(pts, corner);
1223  TS_ASSERT_EQUALS(4, p.m_pts.size());
1224  if (4 != p.m_pts.size())
1225  return;
1226  xms::VecPt3d2d basePts(4);
1227  {
1228  using namespace xms;
1229  basePts[0] = {{0, 30, 0}, {0, 20, 0}, {0, 10, 0}, {0, 0, 0}};
1230  basePts[1] = {{0, 0, 0}, {10, 0, 0}, {20, 0, 0}, {30, 0, 0}};
1231  basePts[2] = {{30, 30, 0}, {30, 20, 0}, {30, 10, 0}, {30, 0, 0}};
1232  basePts[3] = {{0, 30, 0}, {10, 30, 0}, {20, 30, 0}, {30, 30, 0}};
1233  }
1234  TS_ASSERT_DELTA_VECPT3D(basePts[0], p.m_pts[0], 1e-9);
1235  TS_ASSERT_DELTA_VECPT3D(basePts[1], p.m_pts[1], 1e-9);
1236  TS_ASSERT_DELTA_VECPT3D(basePts[2], p.m_pts[2], 1e-9);
1237  TS_ASSERT_DELTA_VECPT3D(basePts[3], p.m_pts[3], 1e-9);
1238 
1239  // change the starting point "[0]" of input polygon
1240  {
1241  using namespace xms;
1242  pts = {{0, 30, 0}, {10, 30, 0}, {20, 30, 0}, {30, 30, 0}, {30, 20, 0}, {30, 10, 0},
1243  {30, 0, 0}, {20, 0, 0}, {10, 0, 0}, {0, 0, 0}, {0, 10, 0}, {0, 20, 0}};
1244  }
1245  p.PolyPtsToSides(pts, corner);
1246  TS_ASSERT_EQUALS(4, p.m_pts.size());
1247  if (4 != p.m_pts.size())
1248  return;
1249  {
1250  using namespace xms;
1251  basePts[0] = {{0, 30, 0}, {0, 20, 0}, {0, 10, 0}, {0, 0, 0}};
1252  basePts[1] = {{0, 0, 0}, {10, 0, 0}, {20, 0, 0}, {30, 0, 0}};
1253  basePts[2] = {{30, 30, 0}, {30, 20, 0}, {30, 10, 0}, {30, 00, 0}};
1254  basePts[3] = {{0, 30, 0}, {10, 30, 0}, {20, 30, 0}, {30, 30, 0}};
1255  }
1256  TS_ASSERT_DELTA_VECPT3D(basePts[0], p.m_pts[0], 1e-9);
1257  TS_ASSERT_DELTA_VECPT3D(basePts[1], p.m_pts[1], 1e-9);
1258  TS_ASSERT_DELTA_VECPT3D(basePts[2], p.m_pts[2], 1e-9);
1259  TS_ASSERT_DELTA_VECPT3D(basePts[3], p.m_pts[3], 1e-9);
1260 } // MePolyPatcherUnitTests::testPolyPtsToSides
1261 //------------------------------------------------------------------------------
1263 //------------------------------------------------------------------------------
1265 {
1266  xms::VecPt3d pts;
1267  {
1268  using namespace xms;
1269  pts = {{0, 0, 0}, {0, 70, 0}, {0, 100, 0}, {35, 100, 0}, {100, 100, 0},
1270  {100, 70, 0}, {100, 35, 0}, {100, 0, 0}, {70, 0, 0}, {35, 0, 0}};
1271  }
1272  xms::VecInt corner = {2, 4, 7};
1274  p.PolyPtsToSides(pts, corner);
1275  TS_ASSERT_EQUALS(4, p.m_pts.size());
1276  if (4 != p.m_pts.size())
1277  return;
1278  xms::VecPt3d2d basePts(4);
1279  {
1280  using namespace xms;
1281  basePts[0] = {{0, 100, 0}, {0, 70, 0}, {0, 0, 0}};
1282  basePts[1] = {{0, 0, 0}, {35, 0, 0}, {70, 0, 0}, {100, 0, 0}};
1283  basePts[2] = {{100, 100, 0}, {100, 70, 0}, {100, 35, 0}, {100, 0, 0}};
1284  basePts[3] = {{0, 100, 0}, {35, 100, 0}, {100, 100, 0}};
1285  }
1286  TS_ASSERT_DELTA_VECPT3D(basePts[0], p.m_pts[0], 1e-9);
1287  TS_ASSERT_DELTA_VECPT3D(basePts[1], p.m_pts[1], 1e-9);
1288  TS_ASSERT_DELTA_VECPT3D(basePts[2], p.m_pts[2], 1e-9);
1289  TS_ASSERT_DELTA_VECPT3D(basePts[3], p.m_pts[3], 1e-9);
1290 } // MePolyPatcherUnitTests::testPolyPtsToSides1
1291 //------------------------------------------------------------------------------
1293 //------------------------------------------------------------------------------
1295 {
1296  xms::VecPt3d pts;
1297  {
1298  using namespace xms;
1299  pts = {{0, 0, 0}, {0, 10, 0}, {0, 20, 0}, {0, 30, 0}, {10, 30, 0}, {20, 30, 0},
1300  {30, 30, 0}, {30, 20, 0}, {30, 10, 0}, {30, 0, 0}, {20, 0, 0}, {10, 0, 0}};
1301  }
1302  xms::VecInt corner = {3, 6, 9};
1304  xms::VecPt3d mPts;
1305  xms::VecInt mCells;
1306  p.MeshIt(-1, pts, corner, 1e-9, mPts, mCells);
1307 } // MePolyPatcherUnitTests::testPatch00
1308 //------------------------------------------------------------------------------
1310 //------------------------------------------------------------------------------
1312 {
1313  xms::VecPt3d pts;
1314  {
1315  using namespace xms;
1316  pts = {{1, 1, 0}, {0, 1, 0}, {0, 10, 0}, {0, 20, 0}, {0, 30, 0}, {10, 30, 0}, {20, 30, 0},
1317  {30, 30, 0}, {30, 20, 0}, {30, 10, 0}, {30, 0, 0}, {20, 0, 0}, {10, 0, 0}, {1, 0, 0}};
1318  }
1319  xms::VecInt corner = {4, 7, 10};
1321  TS_ASSERT_EQUALS(true, p.QuadPatchErrors(pts, corner));
1322  {
1323  TS_ASSERT_STACKED_ERRORS("---Non-convex corner detected in polygon. Aborting patch.\n\n");
1324  }
1325 
1326  {
1327  using namespace xms;
1328  pts = {{0, 0, 0}, {0, 10, 0}, {0, 20, 0}, {0, 29, 0}, {0, 30, 0}, {10, 30, 0}, {20, 30, 0},
1329  {30, 30, 0}, {30, 20, 0}, {30, 10, 0}, {30, 0, 0}, {20, 0, 0}, {10, 0, 0}};
1330  }
1331  corner = {3, 7, 10};
1332  TS_ASSERT_EQUALS(true, p.QuadPatchErrors(pts, corner));
1333  {
1334  TS_ASSERT_STACKED_ERRORS("---Non-convex corner detected in polygon. Aborting patch.\n\n");
1335  }
1336 } // MePolyPatcherUnitTests::testQuadPatchErrors
1337 //------------------------------------------------------------------------------
1339 //------------------------------------------------------------------------------
1341 {
1342  xms::VecPt3d pts = {{-15, 38}, {17, 47}, {52, 50}, {95, 40},
1343  {92, 27}, {51, 35}, {18, 33}, {-12, 26}};
1344  xms::VecInt corner = {3, 4, 7};
1346  xms::VecPt3d mpts;
1347  xms::VecInt mcells;
1348  TS_ASSERT_EQUALS(true, p.MeshIt(-1, pts, corner, 1e-9, mpts, mcells));
1349  xms::VecPt3d basePts = {{-15, 38}, {-12, 26}, {95, 40}, {92, 27},
1350  {17, 47}, {18, 33}, {52, 50}, {51, 35}};
1351  TS_ASSERT_EQUALS_VEC(basePts, mpts);
1352  xms::VecInt baseCells = {9, 4, 0, 1, 5, 4, 9, 4, 4, 5, 7, 6, 9, 4, 6, 7, 3, 2};
1353  TS_ASSERT_EQUALS_VEC(baseCells, mcells);
1354 } // MePolyPatcherUnitTests::testBug9226
1355 
1356 #endif
int m_polyId
id of the polygon
int m_np_side
variable refactored out of patch code
tests MePolyPatcher
void GenerateMeshCells()
Creates the mesh cells and puts the mesh pts into 1 vector.
#define XM_LOG(A, B)
std::vector< int > VecInt
VecInt m_nodesincol
number of nodes in a column
void gmEnvelopeOfPts(const VecPt3d &a_pts, Pt3d &a_min, Pt3d &a_max)
int m_m1
variable refactored out of patch code
VecInt m_meshCells
generated mesh cells
Utilities related to a VTK unstructured grid (from shared1\UGridUtils.cpp)
virtual bool MeshIt(int a_polyId, const VecPt3d &a_outPoly, const VecInt &a_polyCorners, double a_xytol, VecPt3d &a_points, VecInt &a_cells) override
Perform MESH_PATCH meshing on a polygon. Return the mesh points through a_points and a_cells (mix of ...
friend MePolyPatcherUnitTests
tests the class
bool QuadPatchErrors(const VecPt3d &a_outPoly, const VecInt &a_polyCorners)
Checks the polygon to make sure that each side of the polygon has the same number of segments...
static BSHP< MePolyPatcher > New()
Creates a new instance of this class.
std::vector< double > VecDbl
#define TS_ASSERT_DELTA_VECPT3D(a, b, delta)
int m_dm
variable refactored out of patch code
double gmAngleBetweenEdges(const Pt3d &p1, const Pt3d &p2, const Pt3d &p3)
VecInt m_nodesinrow
number of nodes in a row
bool AdjustNodesInCol3a(VecInt &a_nodesincol, int flag)
performs adjustments to the nodes to make the correct desired transitions from column to column...
VecPt3d2d m_end2pts
1 side of polygon points
VecDbl2d m_newend1pcnt
percentage of node location along side
VecPt3d2d m_side1pts
1 side of polygon points
BSHP< VecPt3d > m_meshPts
generated mesh nodes
void testQuadPatchErrors()
tests error detection in polygon for quad patch
VecDbl m_side1pcnt
percentage of node location along side
void testCreateClass()
test creating the class
VecDbl2d m_newside1pcnt
percentage of node location along side
void testPolyPtsToSides1()
tests converting the polygon definition into the "side" definition
void testPatch00()
test patch generation of a square with equal side spacing
int gmPointInPolygon2D(const T *a_verts, const size_t a_num, const double a_x, const double a_y, const double a_tol)
#define XM_ZERO_TOL
VecPt3d2d m_pts
polygon points divided into 4 sides
VecInt2d m_nodeIdx
index to m_meshPts identifying mesh nodes
double m_xytol
tolerance for geometry comparison
VecDbl m_end1pcnt
percentage of node location along side
VecDbl m_end2pcnt
percentage of node location along side
boost::dynamic_bitset< size_t > DynBitset
std::vector< VecInt > VecInt2d
void QuadPatch(const VecPt3d &a_outPoly, const VecInt &a_polyCorners)
Creates mesh cells using the patch algorithm for triangles.
void meModifyMessageWithPolygonId(int a_polyId, std::string &a_msg)
Prepends the polygon id as part of an error messge.
bool gmLinesIntersect(const Pt3d &one1, const Pt3d &one2, const Pt3d &two1, const Pt3d &two2)
bool SetupSideInfo()
Set up some variables based on the points being setup.
VecInt m_ptCellCnt
number of cells connected to each point
void CalcPointPercentages()
Calculates percentages that are used to determine the locations of the mesh points.
void ValidateMeshCells()
Ensures that the generated mesh cells are valid (no ill formed cells)
void PolyPtsToSides(const VecPt3d &a_outPoly, const VecInt &a_polyCorners)
puts the polygon points in the
VecPt3d2d m_side2pts
1 side of polygon points
int m_np_end
variable refactored out of patch code
double MdistSq(_T x1, _U y1, _V x2, _W y2)
int m_n0
variable refactored out of patch code
VecInt m_ptCellIdx
index into cell adjacency array for each point
#define XM_ENSURE_TRUE(...)
int m_n1
variable refactored out of patch code
_T Mmax(_T a, _U b)
void InterpolatePercentages(const VecDbl &a_pcnt_in, VecDbl &a_pcnt_out)
gets the new percentages, interpolated from old percentages
VecDbl2d m_newend2pcnt
percentage of node location along side
BSHP< GmPtSearch > m_ptSearch
spatial index for searching points
void testPolyPtsToSides()
tests converting the polygon definition into the "side" definition
#define TS_ASSERT_STACKED_ERRORS(expected)
void CreateCellAdjacencyInfo()
Creates arrays with cell adjacency information.
std::vector< VecPt3d > VecPt3d2d
Generates a mesh with triangle/quad cells using the patch method.
Definition: MePolyPatcher.h:26
#define XM_PI
VecDbl m_side2pcnt
percentage of node location along side
void gmOrderPointsCounterclockwise(const VecPt3d &a_pts, VecInt &a_ccwOrder, int a_startindex)
std::vector< VecDbl > VecDbl2d
VecInt m_cellIdx
location of each cell in m_meshCells
void OrderPoints()
checks that the points are ordered in the expected order
double Mdist(_T x1, _U y1, _V x2, _W y2)
VecInt m_ptAdjCells
adjacent cells for each point
void testBug9226()
tests for bug report 9226
VecDbl2d m_newside2pcnt
percentage of node location along side
_T Mmin(_T a, _U b)
Generates an adaptive patch mesh from a polygon.
int m_m0
variable refactored out of patch code
#define TS_ASSERT_EQUALS_VEC(a, b)
int m_dn
variable refactored out of patch code
void GetCellPtInfo(int a_cellIdx, VecInt &a_ptIdxs, VecInt &a_adjCellIdx, VecInt2d &a_adjPts)
Gets the points that make up the cell and points from adjacent cells.
VecPt3d2d m_end1pts
1 side of polygon points
void PointsFromPercentages(const VecPt3d &a_pts, const VecDbl &a_pcnts, int a_np_new, VecPt3d &a_ptsNew)
reinterpolates the array of points a_pts to a new array of points a_ptsNew. The interpolation is perf...
void SetUpColumnForRectPatch3a(int a_j, VecPt3d &a_newcol)
initialize an array of nodes for a column of patch nodes
void GetPercentages(int a_np, const VecPt3d &a_pts, VecDbl &pcnts)
returns the real percentage for each point across the line.
void GenerateMeshPts()
Creates the mesh pts.
VecInt m_ptIdxToRemove
mesh nodes that will be removed
bool CellOverlapsAdj(int a_cellIdx, DynBitset &a_cellFlags)
Checks to see if the cells overlaps with any adjacent cells.
std::vector< Pt3d > VecPt3d
size_t PolyCornerClosestToTopLeft(const VecPt3d &a_oPoly, const VecInt &a_idx, const Pt3d &a_topLeft)
puts the polygon points in the