xmsmesh  1.0
MeBadQuadRemover.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 <cmath>
17 #include <numeric>
18 
19 // 4. External library headers
20 #include <boost/utility.hpp>
21 
22 // 5. Shared code headers
23 #include <xmscore/misc/DynBitset.h>
24 #include <xmscore/misc/XmError.h>
25 #include <xmscore/misc/xmstype.h>
26 #include <xmsgrid/ugrid/XmEdge.h>
27 #include <xmsgrid/ugrid/XmUGrid.h>
29 
30 // 6. Non-shared code headers
31 
32 //----- Forward declarations ---------------------------------------------------
33 
34 //----- External globals -------------------------------------------------------
35 
36 //----- Namespace declaration --------------------------------------------------
37 
38 namespace xms
39 {
40 //----- Constants / Enumerations -----------------------------------------------
41 
42 //----- Classes / Structs ------------------------------------------------------
43 
44 namespace
45 {
48 struct CellData
49 {
54  explicit CellData(int a_num3EdgePoints = -999, int a_pointIdx = -1)
55  : m_num3EdgePoints(a_num3EdgePoints)
56  , m_pointIdx(a_pointIdx)
57  {
58  }
59 
61  int m_pointIdx;
64 };
67 
68 typedef std::vector<CellData> VecCellData;
69 
70 class MeBadQuadRemoverImpl : public MeBadQuadRemover
71 {
72 public:
73  MeBadQuadRemoverImpl(BSHP<XmUGrid> a_ugrid);
74 
75  virtual BSHP<XmUGrid> RemoveBadQuads(double a_maxAspect = 0.7) override;
76 
77  // implementation helpers
78  bool ReplacePoint(int a_ptIdx, int a_newPtIdx);
79  void MovePoint(int a_ptIdx, const Pt3d& a_newPoint);
80  void DeleteCell(int a_cellIdx);
81  BSHP<XmUGrid> BuildUGridFromReplacedPoints();
82  void CollapseFromPoint(int a_cellIdx, int a_pointIdx_w3, const VecInt& a_adjCells);
83  void ComputeCellData(int a_cellIdx, double max_aspect);
84  bool CanCollapse(int a_cellIdx, int pointIdx_w3, VecInt& a_adjCells);
85 
86 private:
87  typedef std::pair<int, Pt3d> MovedPoint;
88  typedef std::vector<MovedPoint> MovedPointVec;
89  BSHP<XmUGrid> m_ugrid;
92  MovedPointVec m_movedPoints;
93  VecCellData m_cellsData;
94 
98 };
99 
100 //----- Internal functions -----------------------------------------------------
101 
102 //----- Class / Function definitions -------------------------------------------
103 
104 //------------------------------------------------------------------------------
110 //------------------------------------------------------------------------------
111 BSHP<XmUGrid> BuildUGrid(const VecPt3d& a_points, const VecInt2d& a_faces)
112 {
113  VecInt cells;
114  for (auto& face : a_faces)
115  {
116  if (face.size() == 4)
117  {
118  cells.push_back(XMU_QUAD);
119  cells.push_back(4);
120  cells.insert(cells.end(), face.begin(), face.end());
121  }
122  else if (face.size() == 3)
123  {
124  cells.push_back(XMU_TRIANGLE);
125  cells.push_back(3);
126  cells.insert(cells.end(), face.begin(), face.end());
127  }
128  else
129  {
130  XM_ASSERT(0);
131  }
132  }
133 
134  return XmUGrid::New(a_points, cells);
135 } // BuildUGrid
136 //------------------------------------------------------------------------------
141 //------------------------------------------------------------------------------
142 void GetPointIdxsAttachedByEdge(BSHP<XmUGrid> a_ugrid, int a_pointIdx, VecInt& a_edgePoints)
143 {
144  // TODO: Use new UGrid code in xmsgrid
145  a_edgePoints.clear();
146  VecInt associatedCells = a_ugrid->GetPointAdjacentCells(a_pointIdx);
147  if (associatedCells.size() == 0)
148  {
149  return;
150  }
151  for (int i = 0; i < associatedCells.size(); ++i)
152  {
153  for (int j = 0; j < a_ugrid->GetCellEdgeCount(associatedCells[i]); ++j)
154  {
155  XmEdge temp = a_ugrid->GetCellEdge(associatedCells[i], j);
156  if (temp.GetFirst() == a_pointIdx)
157  {
158  a_edgePoints.push_back(temp.GetSecond());
159  }
160  else if (temp.GetSecond() == a_pointIdx)
161  {
162  a_edgePoints.push_back(temp.GetFirst());
163  }
164  }
165  }
166  std::sort(a_edgePoints.begin(), a_edgePoints.end());
167  auto it = std::unique(a_edgePoints.begin(), a_edgePoints.end());
168  a_edgePoints.erase(it, a_edgePoints.end());
169 } // GetPointIdxsAttachedByEdge
170 //------------------------------------------------------------------------------
177 //------------------------------------------------------------------------------
178 int GetAdjacentPointCount(BSHP<XmUGrid> a_ugrid, int a_pointIdx)
179 {
180  VecInt adjacentPoints;
181  GetPointIdxsAttachedByEdge(a_ugrid, a_pointIdx, adjacentPoints);
182  bool isBoundary = false;
183  VecInt adjacentCells;
184  for (auto adjacentPtIdx : adjacentPoints)
185  {
186  a_ugrid->GetPointsAdjacentCells(a_pointIdx, adjacentPtIdx, adjacentCells);
187  if (adjacentCells.size() == 1)
188  {
189  isBoundary = true;
190  break;
191  }
192  }
193 
194  int count = (int)adjacentPoints.size();
195  return isBoundary ? -count : count;
196 } // GetAdjacentPointCount
197 //------------------------------------------------------------------------------
202 //------------------------------------------------------------------------------
203 VecInt GetAdjacentPointCounts(BSHP<XmUGrid> a_ugrid)
204 {
205  VecInt counts(a_ugrid->GetPointCount());
206  int numPoints = a_ugrid->GetPointCount();
207  for (int pointIdx = 0; pointIdx < numPoints; ++pointIdx)
208  {
209  counts[pointIdx] = GetAdjacentPointCount(a_ugrid, pointIdx);
210  }
211  return counts;
212 } // GetAdjacentPointCounts
224 //------------------------------------------------------------------------------
227 //------------------------------------------------------------------------------
228 MeBadQuadRemoverImpl::MeBadQuadRemoverImpl(BSHP<XmUGrid> a_ugrid)
229 : m_ugrid(a_ugrid)
230 , m_pointIdxMap(a_ugrid->GetPointCount(), -1)
231 , m_adjPointCnts(GetAdjacentPointCounts(a_ugrid))
232 {
233  int cellCount = a_ugrid->GetCellCount();
234  m_cellsToDelete.resize(cellCount);
235  m_cellsData.resize(cellCount);
236 } // MeBadQuadRemoverImpl::MeBadQuadRemoverImpl
237 //------------------------------------------------------------------------------
241 //------------------------------------------------------------------------------
242 BSHP<XmUGrid> MeBadQuadRemoverImpl::RemoveBadQuads(double a_maxAspect)
243 {
244  if (a_maxAspect != 0.0)
245  {
246  a_maxAspect *= a_maxAspect;
247  }
248 
249  int cellCnt = m_ugrid->GetCellCount();
250 
251  for (int a_cellIdx = 0; a_cellIdx < cellCnt; ++a_cellIdx)
252  {
253  CellData& cellData = m_cellsData[a_cellIdx];
254  if (cellData.m_num3EdgePoints == -999)
255  {
256  ComputeCellData(a_cellIdx, a_maxAspect);
257  }
258  }
259 
260  while (true)
261  {
262  int collapseCnt = 0;
263  for (int a_cellIdx = 0; a_cellIdx < cellCnt; ++a_cellIdx)
264  {
265  if (!m_cellsToDelete[a_cellIdx])
266  {
267  CellData& data = m_cellsData[a_cellIdx];
268  if (data.m_num3EdgePoints == 1)
269  {
270  int collapsablePtIdx = data.m_pointIdx;
271  VecInt adjCells;
272  if (collapsablePtIdx != -1 && CanCollapse(a_cellIdx, collapsablePtIdx, adjCells))
273  {
274  ++collapseCnt;
275  CollapseFromPoint(a_cellIdx, collapsablePtIdx, adjCells);
276  }
277  // m_cellsData[a_cellIdx].m_num3EdgeVertices = -4;
278  }
279  }
280  }
281  if (collapseCnt == 0)
282  {
283  break;
284  }
285  }
286 
287  BSHP<XmUGrid> newUgrid = BuildUGridFromReplacedPoints();
288  return newUgrid;
289 } // MeBadQuadRemoverImpl::RemoveBadQuads
290 //------------------------------------------------------------------------------
296 //------------------------------------------------------------------------------
297 bool MeBadQuadRemoverImpl::ReplacePoint(int a_ptIdx, int a_newPtIdx)
298 {
299  int& oldIndex = m_pointIdxMap[a_ptIdx];
300  int& newIndex = m_pointIdxMap[a_newPtIdx];
301  if (oldIndex == -1 && newIndex == -1)
302  {
303  m_pointIdxMap[a_ptIdx] = a_newPtIdx;
304  return true;
305  }
306  return false;
307 } // ReplacePoint
308 //------------------------------------------------------------------------------
312 //------------------------------------------------------------------------------
313 void MeBadQuadRemoverImpl::MovePoint(int a_ptIdx, const Pt3d& a_newPoint)
314 {
315  m_movedPoints.push_back({a_ptIdx, a_newPoint});
316 } // MeBadQuadRemoverImpl::MovePoint
317 //------------------------------------------------------------------------------
321 //------------------------------------------------------------------------------
322 void MeBadQuadRemoverImpl::DeleteCell(int a_cellIdx)
323 {
324  m_cellsToDelete[a_cellIdx] = true;
325 } // MeBadQuadRemoverImpl::DeleteCell
326 //------------------------------------------------------------------------------
330 //------------------------------------------------------------------------------
331 BSHP<XmUGrid> MeBadQuadRemoverImpl::BuildUGridFromReplacedPoints()
332 {
333  VecPt3d oldPoints = m_ugrid->GetLocations();
334  for (auto& movedPoint : m_movedPoints)
335  {
336  oldPoints[movedPoint.first] = movedPoint.second;
337  }
338 
339  VecPt3d newPoints;
340  int numPoints = (int)m_ugrid->GetPointCount();
341  newPoints.reserve(numPoints);
342  int currPtIdx = 0;
343  VecInt newPointIdxLookupTable(numPoints, -1);
344  // - - - - - - - before mapping any
345  // 1 - 5 - - - 3 lookup after mapping 0 to 1; 2 to 5; 6 to 3
346  for (int pointIdx = 0; pointIdx < numPoints; ++pointIdx)
347  {
348  if (m_pointIdxMap[pointIdx] == -1)
349  {
350  newPoints.push_back(oldPoints[pointIdx]);
351  newPointIdxLookupTable[pointIdx] = currPtIdx;
352  ++currPtIdx;
353  }
354  }
355  // - 0 - 1 2 3 - newPointIdxLookupTable after the first pass
356 
357  for (int pointIdx = 0; pointIdx < numPoints; ++pointIdx)
358  {
359  int idx = m_pointIdxMap[pointIdx];
360  if (idx != -1)
361  {
362  newPointIdxLookupTable[pointIdx] = newPointIdxLookupTable[idx];
363  }
364  }
365  // 0 * 3 * * * 1 newPointIdxLookupTable after second pass (* means unchanged)
366  // 0 0 3 1 2 3 1 newPointIdxLookupTable after second pass
367  VecInt cells;
368  int numCells = m_ugrid->GetCellCount();
369  cells.reserve(6 * numCells);
370  for (int cellIdx = 0; cellIdx < numCells; ++cellIdx)
371  {
372  if (!m_cellsToDelete[cellIdx])
373  {
374  int cellType = m_ugrid->GetCellType(cellIdx);
375  XM_ASSERT(m_ugrid->GetCellDimension(cellIdx) == 2);
376  cells.push_back(cellType);
377  cells.push_back(m_ugrid->GetCellEdgeCount(cellIdx));
378  VecInt cellPoints = m_ugrid->GetCellPoints(cellIdx);
379  for (auto pointIdx : cellPoints)
380  {
381  cells.push_back(newPointIdxLookupTable[pointIdx]);
382  }
383  }
384  }
385  BSHP<XmUGrid> newUGrid = XmUGrid::New(newPoints, cells);
386  return newUGrid;
387 } // MeBadQuadRemoverImpl::BuildUGridFromReplacedPoints
388 //------------------------------------------------------------------------------
394 //------------------------------------------------------------------------------
395 void MeBadQuadRemoverImpl::CollapseFromPoint(int a_cellIdx,
396  int a_pointIdx_w3,
397  const VecInt& a_adjCells)
398 {
399  VecInt pointIdxs = m_ugrid->GetCellPoints(a_cellIdx);
400  auto it = std::find(pointIdxs.begin(), pointIdxs.end(), a_pointIdx_w3);
401  XM_ASSERT(it != pointIdxs.end());
402  int position = int(it - pointIdxs.begin());
403  int diagonalPtIdx = pointIdxs[(position + 2) % (int)pointIdxs.size()];
404  if (ReplacePoint(a_pointIdx_w3, diagonalPtIdx))
405  {
406  int diagonalCnt = m_adjPointCnts[diagonalPtIdx];
407  int vCnt = m_adjPointCnts[a_pointIdx_w3];
408  XM_ASSERT(vCnt == 3);
409  if (diagonalCnt > 0)
410  {
411  const VecPt3d& points = m_ugrid->GetLocations();
412  double sumWt = (double)(diagonalCnt + vCnt);
413  double ptWt = double(vCnt) / sumWt;
414  double diagonalPtWt = double(diagonalCnt) / sumWt;
415  Pt3d movedPos = diagonalPtWt * points[diagonalPtIdx] + ptWt * points[a_pointIdx_w3];
416  MovePoint(diagonalPtIdx, movedPos);
417  }
418  DeleteCell(a_cellIdx);
419  for (auto adjCell : a_adjCells)
420  {
421  m_cellsData[adjCell].m_num3EdgePoints = -4;
422  }
423  }
424 } // MeBadQuadRemoverImpl::CollapseFromPoint
425 //------------------------------------------------------------------------------
436 //------------------------------------------------------------------------------
437 void MeBadQuadRemoverImpl::ComputeCellData(int a_cellIdx, double max_aspect)
438 {
439  VecInt pointIdxs = m_ugrid->GetCellPoints(a_cellIdx);
440  VecPt3d points = m_ugrid->GetPointsLocations(pointIdxs);
441  int adjPointCnt = (int)points.size();
442 
443  if (adjPointCnt != 4)
444  {
445  CellData data(-adjPointCnt, -1);
446  m_cellsData[a_cellIdx] = data;
447  return;
448  }
449 
450  // Compute the aspect ratio of diagonals
451  VecBool aspectOk = {true, true, true, true};
452  VecDbl diagonals(2, 0.0);
453  if (max_aspect > 0.0)
454  {
455  double d0 = gmXyDistanceSquared(points[0], points[2]);
456  double d1 = gmXyDistanceSquared(points[1], points[3]);
457  diagonals[0] = d0;
458  diagonals[1] = d1;
459  bool even = d0 / d1 <= max_aspect;
460  bool odd = d1 / d0 <= max_aspect;
461  aspectOk = {even, odd, even, odd};
462  }
463 
464  int bits = 0;
465  int threes = 0;
466  int pointIdx_w3 = XM_NONE;
467  for (int i = 0; i < 4; ++i)
468  {
469  int pointIdx = pointIdxs[i];
470  int adjPointCnt = m_adjPointCnts[pointIdx];
471  bool on_boundary = adjPointCnt < 0;
472  adjPointCnt = abs(adjPointCnt);
473  if (adjPointCnt == 2 && !on_boundary)
474  {
475  int opposingIdx = pointIdxs[(i + 2) % 4];
476  Pt3d opposingPt = m_ugrid->GetPointLocation(opposingIdx);
477  int adjCellIdx = m_ugrid->GetCell2dEdgeAdjacentCell(a_cellIdx, i);
478  VecInt adjPointIdxs = m_ugrid->GetCellPoints(adjCellIdx);
479  if (adjPointIdxs.size() == 3)
480  {
481  // adjacent cell is a triangle
482  // +
483  // |\ \
484  // | \ \
485  // | + +
486  // | / /
487  // |/ /
488  // +
489  if (ReplacePoint(opposingIdx, pointIdxs[i]))
490  {
491  MovePoint(pointIdxs[i], opposingPt);
492  DeleteCell(a_cellIdx);
493  }
494  m_cellsData[a_cellIdx].m_num3EdgePoints = -4;
495  m_cellsData[adjCellIdx].m_num3EdgePoints = -4;
496  return;
497  }
498  else if (adjPointIdxs.size() == 4)
499  {
500  // Compute the other diagonal if the edges were deleted
501  // adjOpposingPt ---> +------+
502  // | /|
503  // | / |
504  // | + <--- at this point and cell to right
505  // | / |
506  // | / |
507  // +------+ <--- opposingPt
508 
509  auto it = std::find(adjPointIdxs.begin(), adjPointIdxs.end(), pointIdx);
510  int position = int(it - adjPointIdxs.begin());
511  int adjOpposingIdx = adjPointIdxs[(position + 2) % (int)adjPointIdxs.size()];
512  // int adjOpposingIdx = pointIdxs[(position + 2) % (int)adjPointIdxs.size()];
513  Pt3d adjOpposingPt = m_ugrid->GetPointLocation(adjOpposingIdx);
514  // Pt3d adjOpposingPt = m_ugrid->GetPoint(adjPointIdxs.at(adjOpposingIdx));
515  double d0 = gmXyDistanceSquared(adjOpposingPt, opposingPt);
516  double d1 = diagonals[(i + 1) & 0x1];
517  if (d0 / d1 < 1.0)
518  {
519  if (ReplacePoint(pointIdxs[i], opposingIdx))
520  {
521  DeleteCell(a_cellIdx);
522  m_cellsData[adjCellIdx].m_num3EdgePoints = -4;
523  m_cellsData[a_cellIdx].m_num3EdgePoints = -4;
524  }
525  return;
526  }
527  }
528  }
529 
530  if (adjPointCnt == 2 && on_boundary)
531  {
532  threes += 1;
533  if (aspectOk[i])
534  {
535  bits |= 0x1;
536  }
537  }
538 
539  if (adjPointCnt == 3 && !on_boundary)
540  {
541  threes += 1;
542  if (aspectOk[i])
543  {
544  bits |= 0x1;
545  pointIdx_w3 = pointIdx;
546  }
547  }
548 
549  bits <<= 1;
550  } // end for
551 
552  bits >>= 1;
553 
554  if (pointIdx_w3 != XM_NONE && threes == 2 &&
555  (bits == BOOST_BINARY(0101) || bits == BOOST_BINARY(1010)))
556  {
557  VecInt adjCells = m_ugrid->GetPointAdjacentCells(pointIdx_w3);
558  CollapseFromPoint(a_cellIdx, pointIdx_w3, adjCells);
559  return;
560  }
561 
562  m_cellsData[a_cellIdx] = CellData(threes, pointIdx_w3);
563 } // MeBadQuadRemoverImpl::Compute3VertexCellData
564 //------------------------------------------------------------------------------
569 //------------------------------------------------------------------------------
570 bool MeBadQuadRemoverImpl::CanCollapse(int a_cellIdx, int pointIdx_w3, VecInt& a_adjCells)
571 {
572  int adjPointCnt = m_adjPointCnts[pointIdx_w3];
573  bool on_boundary = adjPointCnt < 0;
574  if (on_boundary)
575  {
576  return false;
577  }
578 
579  adjPointCnt = std::abs(adjPointCnt);
580  XM_ASSERT(adjPointCnt == 3 && !on_boundary);
581 
582  a_adjCells = m_ugrid->GetPointAdjacentCells(pointIdx_w3);
583  for (auto adjCell : a_adjCells)
584  {
585  if (adjCell != a_cellIdx)
586  {
587  const CellData& fd = m_cellsData[adjCell];
588  int fd0 = fd.m_num3EdgePoints;
589  if (fd0 < 0 || fd0 > 1)
590  {
591  return false;
592  }
593  }
594  }
595 
596  return true;
597 } // MeBadQuadRemoverImpl::CanCollapse
598 
599 } // namespace
600 
605 //------------------------------------------------------------------------------
609 //------------------------------------------------------------------------------
610 BSHP<MeBadQuadRemover> MeBadQuadRemover::New(BSHP<XmUGrid> a_ugrid)
611 {
612  BSHP<MeBadQuadRemover> badQuadRemover(new MeBadQuadRemoverImpl(a_ugrid));
613  return badQuadRemover;
614 } // MeBadQuadRemover::New
615 //------------------------------------------------------------------------------
617 //------------------------------------------------------------------------------
619 {
620 } // MeBadQuadRemover::MeBadQuadRemover
621 //------------------------------------------------------------------------------
623 //------------------------------------------------------------------------------
625 {
626 } // MeBadQuadRemover::~MeBadQuadRemover
627 
628 } // namespace xms
629 
630 #if CXX_TEST
631 // UNIT TESTS
634 
636 
638 
639 //----- Namespace declaration --------------------------------------------------
640 
641 using namespace xms;
642 
647 //------------------------------------------------------------------------------
649 //------------------------------------------------------------------------------
651 {
652  // 0-----1-----2
653  // | 0 | 1 |
654  // 3-----4-----5
655  // | 2 | 3 |
656  // 6-----7-----8
657 
658  BSHP<xms::XmUGrid> grid = TEST_XmUGridSimpleQuad();
659  VecInt counts = GetAdjacentPointCounts(grid);
660  VecInt expectedCounts = {-2, -3, -2, -3, 4, -3, -2, -3, -2};
661  TS_ASSERT_EQUALS_VEC(expectedCounts, counts);
662 } // MeBadQuadRemoverUnitTests::testGetAdjacentPointCounts
663 //------------------------------------------------------------------------------
665 //------------------------------------------------------------------------------
667 {
668  {
669  // 10------11----12----4
670  // | | /\ |
671  // | | / \ |
672  // 5-------6--7 8--9
673  // | /| \ / |
674  // | /13 | \/ |
675  // 0 ------1-----2----3
676  VecPt3d points = {
677  {0, 0, 0}, {10, 0, 0}, {20, 0, 0}, {30, 0, 0}, {30, 20, 0}, {0, 10, 0}, {10, 10, 0},
678  {15, 10, 0}, {25, 10, 0}, {30, 10, 0}, {0, 20, 0}, {10, 20, 0}, {20, 20, 0}, {5, 3, 0},
679  };
680  VecInt cells = {XMU_QUAD, 4, 0, 1, 6, 13, XMU_QUAD, 4, 0, 13, 6, 5,
681  XMU_QUAD, 4, 1, 2, 7, 6, XMU_QUAD, 4, 2, 3, 9, 8,
682  XMU_QUAD, 4, 5, 6, 11, 10, XMU_QUAD, 4, 6, 7, 12, 11,
683  XMU_QUAD, 4, 2, 8, 12, 7, XMU_QUAD, 4, 8, 9, 4, 12};
684 
685  BSHP<XmUGrid> ugrid = XmUGrid::New(points, cells);
686  MeBadQuadRemoverImpl replacer(ugrid);
687 
688  replacer.MovePoint(8, {20, 10, 0});
689 
690  TS_ASSERT(replacer.ReplacePoint(7, 8));
691  replacer.DeleteCell(6);
692  TS_ASSERT(replacer.ReplacePoint(13, 1));
693  replacer.DeleteCell(0);
694 
695  VecPt3d expectPoints = {{0, 0, 0}, {10, 0, 0}, {20, 0, 0}, {30, 0, 0},
696  {30, 20, 0}, {0, 10, 0}, {10, 10, 0}, {20, 10, 0},
697  {30, 10, 0}, {0, 20, 0}, {10, 20, 0}, {20, 20, 0}};
698 
699  BSHP<XmUGrid> newUGrid = replacer.BuildUGridFromReplacedPoints();
700 
701  TS_ASSERT_DELTA_VECPT3D(expectPoints, newUGrid->GetLocations(), 1.0e-5);
702 
703  // 0 1 2 3 4 5 6 7 quad indices
704  // x x flagged to delete
705  VecInt expectCells = {// XMU_QUAD, 4, 0, 1, 6, 13,
706  XMU_QUAD, 4, 0, 1, 6, 5, XMU_QUAD, 4, 1, 2, 7, 6, XMU_QUAD, 4, 2, 3, 8, 7,
707  XMU_QUAD, 4, 5, 6, 10, 9, XMU_QUAD, 4, 6, 7, 11, 10,
708  // XMU_QUAD, 4, 2, 8, 12, 7,
709  XMU_QUAD, 4, 7, 8, 4, 11};
710  // 10------11----12----4
711  // | | /\ |
712  // | | / \ |
713  // 5-------6--7* 8--9
714  // | /| \ / |
715  // | /13* | \/ |
716  // 0 ------1-----2----3
717 
718  // 9------10----11----4
719  // | | | |
720  // | | | |
721  // 5-------6-----7----8
722  // | | | |
723  // | | | |
724  // 0 ------1-----2----3
725 
726  TS_ASSERT_EQUALS(expectCells, newUGrid->GetCellstream());
727  }
728 } // MeBadQuadRemoverUnitTests::testDeletePoints
729 //------------------------------------------------------------------------------
738 //------------------------------------------------------------------------------
740 {
741  /* The points below were generated in python in the following manner
742  points = []
743  for y in range(20, -10, -10):
744  for x in range(0, 100, 10):
745  points.append([x,y])
746 
747  points[10][0] -= 3
748  points[11][0] -= 3
749  points[12][0] -= 3
750  points[13][0] -= 3
751 
752  points[14][0] += 3
753  points[15][0] += 1.5
754 
755  points[17][0] -= 1.5
756  points[18][0] -= 3
757  points[19][0] += 5
758 
759  points.append([3, 10]) #30
760  points.append([33, 10]) #31
761  points.append([82, 10]) #32
762  points.append([90, 12]) #33
763  points.append([90, 8]) #34
764  points.append([15, 15]) #35
765  points.append([15, 5]) #36
766 
767  points.append([100, 10]) #37
768  points.append([70, -10]) #38
769  points.append([80, -10]) #39
770  points.append([73, -3]) #40
771  points.append([76, -4]) #41
772  points.append([77, -7]) #42
773  points.append([74, -6]) #43
774  */
775 
776  VecInt2d faces = {{10, 20, 30, 0}, {30, 11, 1, 0}, {35, 12, 2, 1}, {11, 12, 35, 1},
777  {12, 13, 3, 2}, {31, 14, 4, 3}, {14, 15, 5, 4}, {15, 16, 6, 5},
778  {16, 17, 7, 6}, {17, 18, 8, 7}, {32, 33, 9, 8}, {20, 21, 11, 30},
779  {36, 22, 12, 11}, {21, 22, 36, 11}, {22, 23, 13, 12}, {13, 23, 31, 3},
780  {23, 24, 14, 31}, {24, 25, 15, 14}, {25, 26, 16, 15}, {26, 27, 17, 16},
781  {27, 28, 18, 17}, {18, 28, 32, 8}, {28, 29, 34, 32}, {34, 19, 33, 32},
782  {33, 19, 37, 9}, {34, 29, 37, 19}, {40, 41, 28, 27}, {41, 42, 39, 28},
783  {42, 43, 38, 39}, {38, 43, 40, 27}, {43, 42, 41, 40}};
784 
785  VecPt3d points = {// row 1 (0-9)
786  {0, 20, 0},
787  {10, 20, 0},
788  {20, 20, 0},
789  {30, 20, 0},
790  {40, 20, 0},
791  {50, 20, 0},
792  {60, 20, 0},
793  {70, 20, 0},
794  {80, 20, 0},
795  {90, 20, 0},
796  // row 2 (10-19)
797  {-3, 10, 0},
798  {7, 10, 0},
799  {17, 10, 0},
800  {27, 10, 0},
801  {43, 10, 0},
802  {51.5, 10, 0},
803  {60, 10, 0},
804  {68.5, 10, 0},
805  {77, 10, 0},
806  {95, 10, 0},
807  // row 3 (20-29)
808  {0, 0, 0},
809  {10, 0, 0},
810  {20, 0, 0},
811  {30, 0, 0},
812  {40, 0, 0},
813  {50, 0, 0},
814  {60, 0, 0},
815  {70, 0, 0},
816  {80, 0, 0},
817  {90, 0, 0},
818  // additional (30-43)
819  {3, 10, 0},
820  {33, 10, 0},
821  {82, 10, 0},
822  {90, 12, 0},
823  {90, 8, 0},
824  {15, 15, 0},
825  {15, 5, 0},
826  {100, 10, 0},
827  {70, -10, 0},
828  {80, -10, 0},
829  {73, -3, 0},
830  {76, -4, 0},
831  {77, -7, 0},
832  {74, -6, 0}};
833 
834  BSHP<XmUGrid> ugridIn = BuildUGrid(points, faces);
835  BSHP<MeBadQuadRemover> remover = MeBadQuadRemover::New(ugridIn);
836  BSHP<XmUGrid> collapsedUGrid = remover->RemoveBadQuads(0.7);
837  VecPt3d expectedPoints = {// top row (0-9)
838  {0, 20, 0},
839  {10, 20, 0},
840  {20, 20, 0},
841  {30, 20, 0},
842  {40, 20, 0},
843  {50, 20, 0},
844  {60, 20, 0},
845  {70, 20, 0},
846  {80, 20, 0},
847  {90, 20, 0},
848  // row 2 (10-18)
849  {-3, 10, 0},
850  {7, 10, 0},
851  {17, 10, 0},
852  {30, 10, 0},
853  {43, 10, 0},
854  {51.5, 10, 0},
855  {60, 10, 0},
856  {68.5, 10, 0},
857  {95, 10, 0},
858  // bottom row (19-28)
859  {0, 0, 0},
860  {10, 0, 0},
861  {20, 0, 0},
862  {30, 0, 0},
863  {40, 0, 0},
864  {50, 0, 0},
865  {60, 0, 0},
866  {70, 0, 0},
867  {80, 0, 0},
868  {90, 0, 0},
869  // extra points in the middle row
870  {79.8571, 10, 0},
871  {90, 12, 0},
872  {90, 8, 0},
873  {15, 15, 0},
874  {100, 10, 0},
875  // extra points at the bottom
876  {70, -10, 0},
877  {80, -10, 0},
878  {73, -3, 0},
879  {76, -4, 0},
880  {77, -7, 0},
881  {74, -6, 0}};
882  VecPt3d actualPoints = collapsedUGrid->GetLocations();
883  TS_ASSERT_DELTA_VECPT3D(expectedPoints, actualPoints, 1.0e-4);
884 
885  VecInt expectedCells = {
886  9, 4, 10, 11, 1, 0, 9, 4, 32, 12, 2, 1, 9, 4, 11, 12, 32, 1, 9, 4, 12, 13, 3, 2,
887  9, 4, 13, 14, 4, 3, 9, 4, 14, 15, 5, 4, 9, 4, 15, 16, 6, 5, 9, 4, 16, 17, 7, 6,
888  9, 4, 17, 29, 8, 7, 9, 4, 29, 30, 9, 8, 9, 4, 19, 20, 11, 10, 9, 4, 20, 21, 12, 11,
889  9, 4, 21, 22, 13, 12, 9, 4, 22, 23, 14, 13, 9, 4, 23, 24, 15, 14, 9, 4, 24, 25, 16, 15,
890  9, 4, 25, 26, 17, 16, 9, 4, 26, 27, 29, 17, 9, 4, 27, 28, 31, 29, 9, 4, 31, 18, 30, 29,
891  9, 4, 30, 18, 33, 9, 9, 4, 31, 28, 33, 18, 9, 4, 36, 37, 27, 26, 9, 4, 37, 38, 35, 27,
892  9, 4, 38, 39, 34, 35, 9, 4, 34, 39, 36, 26, 9, 4, 39, 38, 37, 36};
893  VecInt actualCells = collapsedUGrid->GetCellstream();
894  TS_ASSERT_EQUALS(expectedCells, actualCells);
895 } // MeBadQuadRemoverUnitTests::testCollapse
896 //------------------------------------------------------------------------------
899 //------------------------------------------------------------------------------
901 {
902  VecInt2d faces = {{0, 2, 1, 3}, {0, 1, 2}};
903 
904  VecPt3d points = {
905  {-10, 0, 0},
906  {10, 0, 0}, // row 1
907  {0, 10, 0}, // row 2
908  {0, 20, 0} // row 3
909  };
910 
911  BSHP<XmUGrid> ugridIn = BuildUGrid(points, faces);
912  BSHP<MeBadQuadRemover> remover = MeBadQuadRemover::New(ugridIn);
913  BSHP<XmUGrid> collapsedUGrid = remover->RemoveBadQuads(0.7);
914  VecPt3d expectedPoints = {{-10, 0, 0}, {10, 0, 0}, {0, 20, 0}};
915 
916  VecPt3d actualPoints = collapsedUGrid->GetLocations();
917  TS_ASSERT_DELTA_VECPT3D(expectedPoints, actualPoints, 1.0e-4);
918 
919  VecInt expectedCells = {XMU_TRIANGLE, 3, 0, 1, 2};
920 
921  VecInt actualCells = collapsedUGrid->GetCellstream();
922  TS_ASSERT_EQUALS(expectedCells, actualCells);
923 } // MeBadQuadRemoverUnitTests::testCollapseQuadTri
924 
925 #endif // CXX_TEST
DynBitset m_cellsToDelete
True if a cell is to be deleted.
void testCollapseQuadTri()
Test simple mesh with one quad and one triangle that share two adjacent edges. Expected to result in ...
std::vector< int > VecInt
std::vector< bool > VecBool
#define XM_NONE
std::vector< double > VecDbl
#define TS_ASSERT_DELTA_VECPT3D(a, b, delta)
BSHP< XmUGrid > m_ugrid
The input UGrid containing the bad quads.
double gmXyDistanceSquared(const Pt3d &pt1, const Pt3d &pt2)
int GetSecond() const
VecCellData m_cellsData
Vector of potentially collapsable quads.
static BSHP< XmUGrid > New()
static BSHP< MeBadQuadRemover > New(BSHP< XmUGrid > a_ugrid)
Create new MeBadQuadRemover.
BSHP< XmUGrid > TEST_XmUGridSimpleQuad()
int m_pointIdx
boost::dynamic_bitset< size_t > DynBitset
std::vector< VecInt > VecInt2d
void testReplacePoints()
Test ReplacePoint and BuildUGridFromReplacedPoints.
const VecInt m_adjPointCnts
MeBadQuadRemover()
Constructor.
MovedPointVec m_movedPoints
List of points moved with new location.
int m_num3EdgePoints
#define XM_ASSERT(x)
VecInt m_pointIdxMap
A mapping of original index to new point index.
void testGetAdjacentPointCounts()
Test GetAdjacentPointCounts.
void testCollapse()
Testing quad removal on a more complex quad UGrid. The original mesh has two rows of quads with some ...
virtual ~MeBadQuadRemover()
Destructor.
#define TS_ASSERT_EQUALS_VEC(a, b)
int GetFirst() const
std::vector< Pt3d > VecPt3d