20 #include <boost/utility.hpp> 26 #include <xmsgrid/ugrid/XmEdge.h> 54 explicit CellData(
int a_num3EdgePoints = -999,
int a_pointIdx = -1)
68 typedef std::vector<CellData> VecCellData;
73 MeBadQuadRemoverImpl(BSHP<XmUGrid> a_ugrid);
75 virtual BSHP<XmUGrid> RemoveBadQuads(
double a_maxAspect = 0.7)
override;
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);
87 typedef std::pair<int, Pt3d> MovedPoint;
88 typedef std::vector<MovedPoint> MovedPointVec;
111 BSHP<XmUGrid> BuildUGrid(
const VecPt3d& a_points,
const VecInt2d& a_faces)
114 for (
auto& face : a_faces)
116 if (face.size() == 4)
118 cells.push_back(XMU_QUAD);
120 cells.insert(cells.end(), face.begin(), face.end());
122 else if (face.size() == 3)
124 cells.push_back(XMU_TRIANGLE);
126 cells.insert(cells.end(), face.begin(), face.end());
142 void GetPointIdxsAttachedByEdge(BSHP<XmUGrid> a_ugrid,
int a_pointIdx,
VecInt& a_edgePoints)
145 a_edgePoints.clear();
146 VecInt associatedCells = a_ugrid->GetPointAdjacentCells(a_pointIdx);
147 if (associatedCells.size() == 0)
151 for (
int i = 0; i < associatedCells.size(); ++i)
153 for (
int j = 0; j < a_ugrid->GetCellEdgeCount(associatedCells[i]); ++j)
155 XmEdge temp = a_ugrid->GetCellEdge(associatedCells[i], j);
158 a_edgePoints.push_back(temp.
GetSecond());
162 a_edgePoints.push_back(temp.
GetFirst());
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());
178 int GetAdjacentPointCount(BSHP<XmUGrid> a_ugrid,
int a_pointIdx)
181 GetPointIdxsAttachedByEdge(a_ugrid, a_pointIdx, adjacentPoints);
182 bool isBoundary =
false;
184 for (
auto adjacentPtIdx : adjacentPoints)
186 a_ugrid->GetPointsAdjacentCells(a_pointIdx, adjacentPtIdx, adjacentCells);
187 if (adjacentCells.size() == 1)
194 int count = (int)adjacentPoints.size();
195 return isBoundary ? -count : count;
203 VecInt GetAdjacentPointCounts(BSHP<XmUGrid> a_ugrid)
205 VecInt counts(a_ugrid->GetPointCount());
206 int numPoints = a_ugrid->GetPointCount();
207 for (
int pointIdx = 0; pointIdx < numPoints; ++pointIdx)
209 counts[pointIdx] = GetAdjacentPointCount(a_ugrid, pointIdx);
228 MeBadQuadRemoverImpl::MeBadQuadRemoverImpl(BSHP<XmUGrid> a_ugrid)
233 int cellCount = a_ugrid->GetCellCount();
242 BSHP<XmUGrid> MeBadQuadRemoverImpl::RemoveBadQuads(
double a_maxAspect)
244 if (a_maxAspect != 0.0)
246 a_maxAspect *= a_maxAspect;
249 int cellCnt =
m_ugrid->GetCellCount();
251 for (
int a_cellIdx = 0; a_cellIdx < cellCnt; ++a_cellIdx)
254 if (cellData.m_num3EdgePoints == -999)
256 ComputeCellData(a_cellIdx, a_maxAspect);
263 for (
int a_cellIdx = 0; a_cellIdx < cellCnt; ++a_cellIdx)
268 if (data.m_num3EdgePoints == 1)
270 int collapsablePtIdx = data.m_pointIdx;
272 if (collapsablePtIdx != -1 && CanCollapse(a_cellIdx, collapsablePtIdx, adjCells))
275 CollapseFromPoint(a_cellIdx, collapsablePtIdx, adjCells);
281 if (collapseCnt == 0)
287 BSHP<XmUGrid> newUgrid = BuildUGridFromReplacedPoints();
297 bool MeBadQuadRemoverImpl::ReplacePoint(
int a_ptIdx,
int a_newPtIdx)
301 if (oldIndex == -1 && newIndex == -1)
313 void MeBadQuadRemoverImpl::MovePoint(
int a_ptIdx,
const Pt3d& a_newPoint)
322 void MeBadQuadRemoverImpl::DeleteCell(
int a_cellIdx)
331 BSHP<XmUGrid> MeBadQuadRemoverImpl::BuildUGridFromReplacedPoints()
336 oldPoints[movedPoint.first] = movedPoint.second;
340 int numPoints = (int)
m_ugrid->GetPointCount();
341 newPoints.reserve(numPoints);
343 VecInt newPointIdxLookupTable(numPoints, -1);
346 for (
int pointIdx = 0; pointIdx < numPoints; ++pointIdx)
350 newPoints.push_back(oldPoints[pointIdx]);
351 newPointIdxLookupTable[pointIdx] = currPtIdx;
357 for (
int pointIdx = 0; pointIdx < numPoints; ++pointIdx)
362 newPointIdxLookupTable[pointIdx] = newPointIdxLookupTable[idx];
368 int numCells =
m_ugrid->GetCellCount();
369 cells.reserve(6 * numCells);
370 for (
int cellIdx = 0; cellIdx < numCells; ++cellIdx)
374 int cellType =
m_ugrid->GetCellType(cellIdx);
376 cells.push_back(cellType);
377 cells.push_back(
m_ugrid->GetCellEdgeCount(cellIdx));
379 for (
auto pointIdx : cellPoints)
381 cells.push_back(newPointIdxLookupTable[pointIdx]);
385 BSHP<XmUGrid> newUGrid = XmUGrid::New(newPoints, cells);
395 void MeBadQuadRemoverImpl::CollapseFromPoint(
int a_cellIdx,
400 auto it = std::find(pointIdxs.begin(), pointIdxs.end(), a_pointIdx_w3);
402 int position = int(it - pointIdxs.begin());
403 int diagonalPtIdx = pointIdxs[(position + 2) % (
int)pointIdxs.size()];
404 if (ReplacePoint(a_pointIdx_w3, diagonalPtIdx))
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);
418 DeleteCell(a_cellIdx);
419 for (
auto adjCell : a_adjCells)
437 void MeBadQuadRemoverImpl::ComputeCellData(
int a_cellIdx,
double max_aspect)
441 int adjPointCnt = (int)points.size();
443 if (adjPointCnt != 4)
445 CellData data(-adjPointCnt, -1);
451 VecBool aspectOk = {
true,
true,
true,
true};
453 if (max_aspect > 0.0)
459 bool even = d0 / d1 <= max_aspect;
460 bool odd = d1 / d0 <= max_aspect;
461 aspectOk = {even, odd, even, odd};
467 for (
int i = 0; i < 4; ++i)
469 int pointIdx = pointIdxs[i];
471 bool on_boundary = adjPointCnt < 0;
472 adjPointCnt = abs(adjPointCnt);
473 if (adjPointCnt == 2 && !on_boundary)
475 int opposingIdx = pointIdxs[(i + 2) % 4];
476 Pt3d opposingPt =
m_ugrid->GetPointLocation(opposingIdx);
477 int adjCellIdx =
m_ugrid->GetCell2dEdgeAdjacentCell(a_cellIdx, i);
479 if (adjPointIdxs.size() == 3)
489 if (ReplacePoint(opposingIdx, pointIdxs[i]))
491 MovePoint(pointIdxs[i], opposingPt);
492 DeleteCell(a_cellIdx);
498 else if (adjPointIdxs.size() == 4)
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()];
513 Pt3d adjOpposingPt =
m_ugrid->GetPointLocation(adjOpposingIdx);
516 double d1 = diagonals[(i + 1) & 0x1];
519 if (ReplacePoint(pointIdxs[i], opposingIdx))
521 DeleteCell(a_cellIdx);
530 if (adjPointCnt == 2 && on_boundary)
539 if (adjPointCnt == 3 && !on_boundary)
545 pointIdx_w3 = pointIdx;
554 if (pointIdx_w3 != XM_NONE && threes == 2 &&
555 (bits == BOOST_BINARY(0101) || bits == BOOST_BINARY(1010)))
557 VecInt adjCells =
m_ugrid->GetPointAdjacentCells(pointIdx_w3);
558 CollapseFromPoint(a_cellIdx, pointIdx_w3, adjCells);
562 m_cellsData[a_cellIdx] = CellData(threes, pointIdx_w3);
570 bool MeBadQuadRemoverImpl::CanCollapse(
int a_cellIdx,
int pointIdx_w3,
VecInt& a_adjCells)
573 bool on_boundary = adjPointCnt < 0;
579 adjPointCnt = std::abs(adjPointCnt);
580 XM_ASSERT(adjPointCnt == 3 && !on_boundary);
582 a_adjCells =
m_ugrid->GetPointAdjacentCells(pointIdx_w3);
583 for (
auto adjCell : a_adjCells)
585 if (adjCell != a_cellIdx)
588 int fd0 = fd.m_num3EdgePoints;
589 if (fd0 < 0 || fd0 > 1)
610 BSHP<MeBadQuadRemover> MeBadQuadRemover::New(BSHP<XmUGrid> a_ugrid)
612 BSHP<MeBadQuadRemover> badQuadRemover(
new MeBadQuadRemoverImpl(a_ugrid));
613 return badQuadRemover;
659 VecInt counts = GetAdjacentPointCounts(grid);
660 VecInt expectedCounts = {-2, -3, -2, -3, 4, -3, -2, -3, -2};
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},
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};
686 MeBadQuadRemoverImpl replacer(ugrid);
688 replacer.MovePoint(8, {20, 10, 0});
690 TS_ASSERT(replacer.ReplacePoint(7, 8));
691 replacer.DeleteCell(6);
692 TS_ASSERT(replacer.ReplacePoint(13, 1));
693 replacer.DeleteCell(0);
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}};
699 BSHP<XmUGrid> newUGrid = replacer.BuildUGridFromReplacedPoints();
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,
709 XMU_QUAD, 4, 7, 8, 4, 11};
726 TS_ASSERT_EQUALS(expectCells, newUGrid->GetCellstream());
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}};
834 BSHP<XmUGrid> ugridIn = BuildUGrid(points, faces);
836 BSHP<XmUGrid> collapsedUGrid = remover->RemoveBadQuads(0.7);
882 VecPt3d actualPoints = collapsedUGrid->GetLocations();
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);
902 VecInt2d faces = {{0, 2, 1, 3}, {0, 1, 2}};
911 BSHP<XmUGrid> ugridIn = BuildUGrid(points, faces);
913 BSHP<XmUGrid> collapsedUGrid = remover->RemoveBadQuads(0.7);
914 VecPt3d expectedPoints = {{-10, 0, 0}, {10, 0, 0}, {0, 20, 0}};
916 VecPt3d actualPoints = collapsedUGrid->GetLocations();
919 VecInt expectedCells = {XMU_TRIANGLE, 3, 0, 1, 2};
921 VecInt actualCells = collapsedUGrid->GetCellstream();
922 TS_ASSERT_EQUALS(expectedCells, actualCells);
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
std::vector< double > VecDbl
BSHP< XmUGrid > m_ugrid
The input UGrid containing the bad quads.
double gmXyDistanceSquared(const Pt3d &pt1, const Pt3d &pt2)
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()
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.
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.
std::vector< Pt3d > VecPt3d