24 #include <xmsgrid/ugrid/XmEdge.h> 53 bool operator==(
const Edge& a_rhs)
const 55 return m_p0 == a_rhs.m_p0 &&
m_p1 == a_rhs.m_p1 &&
m_fL == a_rhs.m_fL &&
m_fR == a_rhs.m_fR &&
56 m_pL == a_rhs.m_pL &&
m_pR == a_rhs.m_pR;
68 typedef std::vector<Edge>
VecEdge;
74 CellData(
int a_priorPt,
int a_nextPt,
int a_cell)
82 bool operator==(
const CellData& a_rhs)
const 93 typedef std::vector<CellData> VecCellData;
94 typedef std::vector<VecCellData> VecVecCellData;
95 typedef std::vector<VecVecCellData> VecVecVecCellData;
101 MeQuadBlossomImpl(
const VecPt3d& a_points,
const VecInt2d& a_triangles);
103 virtual int PreMakeQuads()
override;
104 virtual BSHP<XmUGrid> MakeQuads(
bool a_splitBoundaryPoints,
105 bool a_useAngle)
override;
107 virtual BSHP<XmUGrid> _MakeQuads(
bool a_splitBoundaryPoints =
true,
108 bool a_useAngle =
false,
110 const VecPt3d& GetLocations()
const;
112 void PrepareForMatch(
int a_cost,
114 VecInt MatchTriangles(
bool a_splitBoundaryPoints);
115 void GetEdges(
int a_cost);
116 void ProcessPointChains(
int a_p,
117 VecVecCellData& a_chains,
123 void ExtractCellsAdjacentToPoint(VecVecCellData& a_pointFaceChains,
124 VecVecVecCellData& a_sortedFaceChains);
125 int FindFaceThatStartsWith(
const VecCellData& facesData,
int a_p);
126 int FindChainThatStartsWith(
const VecVecCellData& a_chains,
int a_p);
127 VecVecCellData SortIntoPointChains(VecCellData& faces);
128 VecMeEdge CalculateEdgeCost(
bool a_useAngle);
130 VecEdge GetInteriorEdges(
int a_p,
const VecCellData& a_chain);
131 Edge GetBoundaryEdges(
int a_p,
132 const VecCellData& a_chain,
153 typedef std::pair<int, int> AdjPointMidpoint;
157 typedef std::vector<AdjPointMidpoint> VecAdjPointMidpoint;
160 typedef std::vector<VecAdjPointMidpoint> VecVecAdjPointMidpoint;
171 VecInt2d UGrid2dToVecInt2d(BSHP<XmUGrid> a_ugrid)
173 int numCells = a_ugrid->GetCellCount();
175 for (
int cellIdx = 0; cellIdx < numCells; ++cellIdx)
177 VecInt& cell = cells[cellIdx];
178 if (a_ugrid->GetCellDimension(cellIdx) == 2 && a_ugrid->GetCellEdgeCount(cellIdx) == 3)
180 VecInt cellPoints = a_ugrid->GetCellPoints(cellIdx);
181 for (
auto pointIdx : cellPoints)
183 cell.push_back(pointIdx);
197 BSHP<XmUGrid> BuildUGrid(
const VecPt3d& a_points,
const VecInt2d& a_faces)
200 for (
auto& face : a_faces)
202 if (face.size() == 4)
204 cells.push_back(XMU_QUAD);
206 cells.insert(cells.end(), face.begin(), face.end());
208 else if (face.size() == 3)
210 cells.push_back(XMU_TRIANGLE);
212 cells.insert(cells.end(), face.begin(), face.end());
229 double GetAngle(
const Pt3d& p0,
const Pt3d& pc,
const Pt3d& p1)
233 double angle_c0 = atan2(d0c[1], d0c[0]);
234 double angle_c1 = atan2(d1c[1], d1c[0]);
235 double angle_0c1 = angle_c0 - angle_c1;
240 else if (angle_0c1 > TWO_PI)
258 int GetEtaAngle(
const Pt3d& p0,
const Pt3d& p1,
const Pt3d& p2,
const Pt3d& p3)
260 double a0 = GetAngle(p1, p0, p2);
261 double a1 = GetAngle(p3, p1, p0);
262 double a2 = GetAngle(p0, p2, p3);
263 double a3 = GetAngle(p2, p3, p1);
280 double etaMax1 = std::max(fabs(PI_OVER_TWO - a0), fabs(PI_OVER_TWO - a1));
281 double etaMax2 = std::max(fabs(PI_OVER_TWO - a2), fabs(PI_OVER_TWO - a3));
282 double etaMax = 1.0 -
TWO_OVER_PI * std::max(etaMax1, etaMax2);
283 double eta = std::max(0.0, etaMax);
284 return int(1000.0 * eta + 0.5);
297 int GetEtaDistance(
const Pt3d& p0,
const Pt3d& p1,
const Pt3d& p2,
const Pt3d& p3)
309 double inveta1 = std::max((a + b) / e, e / (a + b));
310 double inveta2 = std::max((c + d) / e, e / (c + d));
311 double inveta3 = std::max((a + c) / f, f / (a + c));
312 double inveta4 = std::max((b + d) / f, f / (b + d));
313 double inveta = std::max(inveta1 + inveta2, inveta3 + inveta4);
315 return int(1000.0 * 2.0 / inveta + 0.5);
323 void GetPointIdxsAttachedByEdge(BSHP<XmUGrid> a_ugrid,
int a_pointIdx,
VecInt& a_edgePoints)
326 a_edgePoints.clear();
327 VecInt associatedCells = a_ugrid->GetPointAdjacentCells(a_pointIdx);
328 if (associatedCells.size() == 0)
332 for (
int i = 0; i < associatedCells.size(); ++i)
334 for (
int j = 0; j < a_ugrid->GetCellEdgeCount(associatedCells[i]); ++j)
336 XmEdge temp = a_ugrid->GetCellEdge(associatedCells[i], j);
339 a_edgePoints.push_back(temp.
GetSecond());
343 a_edgePoints.push_back(temp.
GetFirst());
347 std::sort(a_edgePoints.begin(), a_edgePoints.end());
348 auto it = std::unique(a_edgePoints.begin(), a_edgePoints.end());
349 a_edgePoints.erase(it, a_edgePoints.end());
363 int FindMidpoint(
const VecVecAdjPointMidpoint& a_edgeMidsides,
int a_idx0,
int a_idx1)
366 std::swap(a_idx0, a_idx1);
368 auto& adjPoints = a_edgeMidsides[a_idx0];
369 for (
auto& adjPoint : adjPoints)
371 if (adjPoint.first == a_idx1)
373 return adjPoint.second;
384 MeQuadBlossomImpl::MeQuadBlossomImpl(
const VecPt3d& a_points,
const VecInt2d& a_triangles)
397 int MeQuadBlossomImpl::PreMakeQuads()
401 GetEdges(DEFAULT_COST);
415 BSHP<XmUGrid> MeQuadBlossomImpl::MakeQuads(
bool a_splitBoundaryPoints,
418 return _MakeQuads(a_splitBoundaryPoints, a_useAngle);
431 BSHP<XmUGrid> MeQuadBlossomImpl::_MakeQuads(
bool a_splitBoundaryPoints ,
435 PrepareForMatch(a_cost, a_useAngle);
436 VecInt eliminate = MatchTriangles(a_splitBoundaryPoints);
437 EliminateEdges(eliminate);
454 void MeQuadBlossomImpl::PrepareForMatch(
int a_cost,
461 else if (a_cost != DEFAULT_COST)
465 edge.m_weight = a_cost;
468 m_costs = CalculateEdgeCost(a_useAngle);
482 VecInt MeQuadBlossomImpl::MatchTriangles(
bool a_splitBoundaryPoints)
484 bool maxCardinality = a_splitBoundaryPoints;
485 BSHP<MeWeightMatcher> matcher = MeWeightMatcher::New();
486 VecInt result = matcher->MatchWeights(
m_costs, maxCardinality);
490 for (
int i = 0; i < (int)result.size(); ++i)
500 for (
int k = 0; k <
m_costs.size(); ++k)
505 eliminate.push_back(k);
518 void MeQuadBlossomImpl::GetEdges(
int a_cost)
520 VecVecCellData dummy;
521 VecVecVecCellData sorted;
522 ExtractCellsAdjacentToPoint(dummy, sorted);
530 for (
auto& chains : sorted)
551 void MeQuadBlossomImpl::ProcessPointChains(
int a_p,
552 VecVecCellData& a_chains,
559 a_interiorEdges.clear();
560 a_boundaryEdges.clear();
562 if (a_chains.size() == 0)
567 if (a_chains.size() == 1)
569 auto& chain = a_chains[0];
570 auto& first = chain[0];
571 auto& last = chain.back();
572 if (last.m_nextPoint == first.m_priorPoint)
574 chain.push_back(first);
575 a_interiorEdges = GetInteriorEdges(a_p, chain);
578 a_interiorEdges = GetInteriorEdges(a_p, chain);
579 Edge boundaryEdge = GetBoundaryEdges(a_p, chain, extra_cost, a_extraEdges, a_extraPoints);
580 a_boundaryEdges.push_back(boundaryEdge);
584 for (
auto& chain : a_chains)
586 VecEdge edges = GetInteriorEdges(a_p, chain);
587 a_interiorEdges.insert(a_interiorEdges.begin(), edges.begin(), edges.end());
588 auto boundaryEdge = GetBoundaryEdges(a_p, chain, extra_cost, a_extraEdges, a_extraPoints);
589 a_boundaryEdges.push_back(boundaryEdge);
605 void MeQuadBlossomImpl::ExtractCellsAdjacentToPoint(VecVecCellData& a_pointFaceChains,
606 VecVecVecCellData& a_sortedFaceChains)
608 a_pointFaceChains.clear();
609 a_pointFaceChains.resize(
m_points.size(), VecCellData());
610 for (
int fi = 0; fi < (int)
m_faces.size(); ++fi)
617 a_pointFaceChains[p0].push_back(CellData(p2, p1, fi));
618 a_pointFaceChains[p1].push_back(CellData(p0, p2, fi));
619 a_pointFaceChains[p2].push_back(CellData(p1, p0, fi));
622 a_sortedFaceChains.clear();
623 for (
auto& pointFace : a_pointFaceChains)
625 VecVecCellData chains = SortIntoPointChains(pointFace);
626 a_sortedFaceChains.push_back(chains);
635 int MeQuadBlossomImpl::FindFaceThatStartsWith(
const VecCellData& facesData,
int a_p)
637 for (
size_t i = 0; i < facesData.size(); ++i)
656 int MeQuadBlossomImpl::FindChainThatStartsWith(
const VecVecCellData& a_chains,
int a_p)
658 for (
size_t i = 0; i < a_chains.size(); ++i)
677 VecVecCellData MeQuadBlossomImpl::SortIntoPointChains(VecCellData& facesData)
679 VecVecCellData chains;
680 VecCellData remaining = facesData;
683 while (remaining.size() > 0)
685 auto iter = remaining.begin() + face_i;
686 CellData face = remaining[face_i];
687 remaining.erase(iter);
688 int p = face.m_nextPoint;
689 chain.push_back(face);
690 face_i = FindFaceThatStartsWith(remaining, p);
691 if (face_i == XM_NONE)
695 int chain_i = FindChainThatStartsWith(chains, p);
696 if (chain_i != XM_NONE)
699 chains[chain_i].insert(chains[chain_i].begin(), chain.begin(), chain.end());
703 chains.push_back(chain);
717 VecMeEdge MeQuadBlossomImpl::CalculateEdgeCost(
bool a_useAngle)
719 auto& eta = a_useAngle ? GetEtaAngle : GetEtaDistance;
733 int cost = int(eta(p0, p1, p2, p3));
734 costs.push_back({edge.m_fL, edge.m_fR, cost});
753 VecInt2d MeQuadBlossomImpl::EliminateEdges(
const VecInt& eliminate)
758 std::iota(splitPointsRedir.begin(), splitPointsRedir.end(), 0);
759 for (
auto i : eliminate)
761 if (i >= nInteriorEdges)
775 int j = i - nInteriorEdges;
779 int firstVertexOut = extra[1];
780 int firstVertexIn = extra[2];
781 int lastVertexOut = extra[3];
782 int lastVertexIn = extra[4];
783 int first = edge.m_f0;
784 int last = edge.m_f1;
787 m_faces[first] = { firstVertexOut, firstVertexIn, p, px };
788 m_faces[last] = { p, lastVertexOut, lastVertexIn, px };
790 splitPointsRedir[p] = px;
794 for (
auto i : eliminate)
796 if (i < nInteriorEdges)
800 int p0 = splitPointsRedir[edge.m_p0];
801 int pR = splitPointsRedir[edge.m_pR];
802 int p1 = splitPointsRedir[edge.m_p1];
803 int pL = splitPointsRedir[edge.m_pL];
804 m_faces[edge.m_fL] = {p0, pR, p1, pL};
814 tempFaces.push_back(face);
829 VecEdge MeQuadBlossomImpl::GetInteriorEdges(
int a_p,
const VecCellData& chain)
833 for (
size_t i = 0; i < chain.size() - 1; ++i)
835 const CellData& last = chain[i];
836 const CellData& face = chain[i + 1];
837 int p1 = face.m_priorPoint;
848 edges.push_back({a_p, p1, last.m_cell, face.m_cell, last.m_priorPoint, face.m_nextPoint});
864 Edge MeQuadBlossomImpl::GetBoundaryEdges(
int a_p,
865 const VecCellData& chain,
871 const CellData& last = chain.back();
872 Edge edge = {a_p, last.m_nextPoint, last.m_cell,
XM_NONE, last.m_priorPoint,
XM_NONE};
874 if (chain.size() > 2)
876 const CellData& first = chain[0];
877 a_extraEdges.push_back({first.m_cell, last.m_cell, cost});
886 a_extraPoints.push_back(
887 {a_p, first.m_nextPoint, first.m_priorPoint, last.m_nextPoint, last.m_priorPoint});
890 int nTris = (int)chain.size();
891 const CellData& tri = chain[nTris >> 1];
899 px = (p0 + p1 + p2) / 3.0;
905 px = (p0 + p1) / 2.0;
925 BSHP<MeQuadBlossom> MeQuadBlossom::New(BSHP<XmUGrid> a_ugrid)
927 const VecPt3d& points = a_ugrid->GetLocations();
928 VecInt2d triangles = UGrid2dToVecInt2d(a_ugrid);
929 BSHP<MeQuadBlossom> wm(
new MeQuadBlossomImpl(points, triangles));
951 double minutes = 6.8E-11 * a_numPoints * a_numPoints * a_numPoints;
962 VecPt3d points = a_ugrid->GetLocations();
965 int numPoints = a_ugrid->GetPointCount();
966 VecVecAdjPointMidpoint edgeMidsides(numPoints);
967 for (
int pointIdx = 0; pointIdx < numPoints; ++pointIdx)
969 const Pt3d p0 = points[pointIdx];
971 GetPointIdxsAttachedByEdge(a_ugrid, pointIdx, adjPoints);
972 VecAdjPointMidpoint adjPoints2;
973 for (
auto otherIdx : adjPoints)
975 if (otherIdx > pointIdx)
977 const Pt3d& p1 = points[otherIdx];
978 Pt3d midPoint = (p0 + p1) * 0.5;
979 int midIdx = (int)points.size();
980 points.push_back(midPoint);
981 adjPoints2.push_back({ otherIdx, midIdx });
985 std::sort(adjPoints2.begin(), adjPoints2.end());
986 edgeMidsides[pointIdx] = adjPoints2;
991 int numCells = a_ugrid->GetCellCount();
992 for (
int cellIdx = 0; cellIdx < numCells; ++cellIdx)
995 VecInt cellPointIdxs = a_ugrid->GetCellPoints(cellIdx);
996 VecPt3d cellPoints = a_ugrid->GetPointsLocations(cellPointIdxs);
998 int centroidIdx = (int)points.size();
999 points.push_back(centroid);
1000 int numCellPoints = (int)cellPointIdxs.size();
1001 int lastIdx = cellPointIdxs.back();
1002 int midsideLast = FindMidpoint(edgeMidsides, cellPointIdxs.front(), lastIdx);
1003 for (
size_t i = 0; i < numCellPoints; ++i)
1005 int currentIdx = cellPointIdxs[i];
1006 int nextIdx = cellPointIdxs[(i + 1) % numCellPoints];
1007 int midside = FindMidpoint(edgeMidsides, currentIdx, nextIdx);
1013 cells.push_back(XMU_QUAD);
1015 cells.push_back(currentIdx);
1016 cells.push_back(midside);
1017 cells.push_back(centroidIdx);
1018 cells.push_back(midsideLast);
1020 midsideLast = midside;
1041 using namespace xms;
1055 MeQuadBlossomImpl blossom(points, triangles);
1058 VecCellData chain = {{3, 0, 0}, {0, 1, 1}, {1, 2, 2}, {2, 5, 3}, {5, 8, 6}, {8, 7, 5}, {7, 3, 7}};
1059 VecEdge edges = blossom.GetInteriorEdges(p, chain);
1061 VecEdge expect = {{4, 5, 3, 6, 2, 8}, {4, 8, 6, 5, 5, 7}, {4, 7, 5, 7, 8, 3}};
1063 TS_ASSERT_EQUALS(expect, edges);
1065 chain = {{3, 0, 0}, {0, 1, 1}, {1, 2, 2}, {2, 5, 3}, {5, 8, 6}, {8, 7, 5}, {7, 3, 7}, {3, 0, 0}};
1066 edges = blossom.GetInteriorEdges(p, chain);
1069 TS_ASSERT_EQUALS(expect, edges);
1071 chain = {{7, 3, 7}, {3, 0, 0}, {0, 1, 1}, {1, 2, 2}, {2, 5, 3}, {5, 8, 6}, {8, 7, 5}, {7, 3, 7}};
1072 edges = blossom.GetInteriorEdges(p, chain);
1074 expect = {{4, 5, 3, 6, 2, 8}, {4, 8, 6, 5, 5, 7}, {4, 7, 5, 7, 8, 3}};
1075 TS_ASSERT_EQUALS(expect, edges);
1077 chain = {{7, 3, 7}, {3, 0, 0}, {0, 1, 1}, {1, 2, 2}, {2, 5, 3}, {5, 8, 6}, {8, 7, 5}};
1078 edges = blossom.GetInteriorEdges(p, chain);
1080 expect = {{4, 5, 3, 6, 2, 8}, {4, 8, 6, 5, 5, 7}};
1081 TS_ASSERT_EQUALS(expect, edges);
1084 chain = {{8, 4, 6}, {4, 2, 3}};
1085 edges = blossom.GetInteriorEdges(p, chain);
1087 TS_ASSERT_EQUALS(expect, edges);
1090 chain = {{5, 4, 3}, {4, 1, 2}};
1091 expect = {{2, 4, 3, 2, 5, 1}};
1092 edges = blossom.GetInteriorEdges(p, chain);
1093 TS_ASSERT_EQUALS(expect, edges);
1102 MeQuadBlossomImpl blossom(points, triangles);
1105 VecCellData chain = {{1, 4, 1}, {4, 3, 0}};
1109 Edge result = blossom.GetBoundaryEdges(p, chain, cost, extraEdges, extraPoints);
1112 TS_ASSERT_EQUALS(expect, result);
1113 TS_ASSERT(extraEdges.empty());
1114 TS_ASSERT(extraPoints.empty());
1117 chain = {{0, 4, 0}, {4, 7, 7}, {7, 6, 4}};
1120 result = blossom.GetBoundaryEdges(p, chain, cost, extraEdges, extraPoints);
1123 VecInt2d expectExtraVertices = {{3, 4, 0, 6, 7}};
1125 TS_ASSERT_EQUALS(expect, result);
1126 TS_ASSERT_EQUALS(expectExtra, extraEdges);
1127 TS_ASSERT_EQUALS(expectExtraVertices, extraPoints);
1130 chain = {{3, 7, 4}};
1132 extraPoints.clear();
1134 result = blossom.GetBoundaryEdges(p, chain, cost, extraEdges, extraPoints);
1136 expectExtraVertices = {};
1138 TS_ASSERT_EQUALS(expect, result);
1139 TS_ASSERT(extraEdges.empty());
1140 TS_ASSERT(extraPoints.empty());
1143 chain = {{4, 8, 5}};
1145 result = blossom.GetBoundaryEdges(p, chain, cost, extraEdges, extraPoints);
1148 TS_ASSERT_EQUALS(expect, result);
1149 TS_ASSERT(extraEdges.empty());
1150 TS_ASSERT(extraPoints.empty());
1152 chain = {{6, 3, 4}};
1154 result = blossom.GetBoundaryEdges(p, chain, cost, extraEdges, extraPoints);
1157 TS_ASSERT_EQUALS(expect, result);
1158 TS_ASSERT(extraEdges.empty());
1159 TS_ASSERT(extraPoints.empty());
1168 MeQuadBlossomImpl blossom(points, triangles);
1171 VecVecCellData chains = {
1172 {{7, 3, 7}, {3, 0, 0}, {0, 1, 1}, {1, 2, 2}, {2, 5, 3}, {5, 8, 6}, {8, 7, 5}}};
1173 int extraCost = -1000;
1178 blossom.ProcessPointChains(p, chains, extraCost, interiorEdges, boundaryEdges, extraEdges,
1180 VecEdge expectInterior = {{4, 5, 3, 6, 2, 8}, {4, 8, 6, 5, 5, 7}, {4, 7, 5, 7, 8, 3}};
1185 TS_ASSERT_EQUALS(expectInterior, interiorEdges);
1186 TS_ASSERT_EQUALS(expectBoundary, boundaryEdges);
1187 TS_ASSERT_EQUALS(expectExtra, extraEdges);
1188 TS_ASSERT_EQUALS(expectExtraVertices, extraPoints);
1191 chains = {{{3, 7, 4}}};
1192 interiorEdges.clear();
1193 boundaryEdges.clear();
1195 extraPoints.clear();
1196 blossom.ProcessPointChains(p, chains, extraCost, interiorEdges, boundaryEdges, extraEdges,
1198 expectInterior = {};
1201 expectExtraVertices = {};
1203 TS_ASSERT_EQUALS(expectInterior, interiorEdges);
1204 TS_ASSERT_EQUALS(expectBoundary, boundaryEdges);
1205 TS_ASSERT_EQUALS(expectExtra, extraEdges);
1206 TS_ASSERT_EQUALS(expectExtraVertices, extraPoints);
1209 chains = {{{8, 4, 6}, {4, 2, 3}}};
1210 interiorEdges.clear();
1211 boundaryEdges.clear();
1213 extraPoints.clear();
1214 blossom.ProcessPointChains(p, chains, extraCost, interiorEdges, boundaryEdges, extraEdges,
1216 expectInterior = {};
1219 expectExtraVertices = {};
1221 TS_ASSERT_EQUALS(expectInterior, interiorEdges);
1222 TS_ASSERT_EQUALS(expectBoundary, boundaryEdges);
1223 TS_ASSERT_EQUALS(expectExtra, extraEdges);
1224 TS_ASSERT_EQUALS(expectExtraVertices, extraPoints);
1227 chains = {{{0, 4, 0}}, {{7, 13, 8}, {13, 6, 4}}};
1229 interiorEdges.clear();
1230 boundaryEdges.clear();
1232 extraPoints.clear();
1233 blossom.ProcessPointChains(p, chains, extraCost, interiorEdges, boundaryEdges, extraEdges,
1235 expectInterior = {{3, 13, 8, 4, 7, 6}};
1236 expectBoundary = {{3, 4, 0,
XM_NONE, 0,
XM_NONE}, {3, 6, 4,
XM_NONE, 13,
XM_NONE}};
1238 expectExtraVertices = {};
1240 TS_ASSERT_EQUALS(expectInterior, interiorEdges);
1241 TS_ASSERT_EQUALS(expectBoundary, boundaryEdges);
1242 TS_ASSERT_EQUALS(expectExtra, extraEdges);
1243 TS_ASSERT_EQUALS(expectExtraVertices, extraPoints);
1250 double h = 10.0 * sqrt(2.0);
1256 int angle_cost = GetEtaAngle(p0, p1, p2, p3);
1257 TS_ASSERT_EQUALS(1000, angle_cost);
1258 int distance_cost = GetEtaDistance(p0, p1, p2, p3);
1259 TS_ASSERT_EQUALS(1000, distance_cost);
1261 double a =
XM_PI / 3.0;
1262 double hy = 10.0 * sin(a);
1263 double hx = 10 * cos(a);
1264 double a_d = a * 180.0 /
XM_PI;
1270 angle_cost = GetEtaAngle(p0, p1, p2, p3);
1271 TS_ASSERT_EQUALS(667, angle_cost);
1272 distance_cost = GetEtaDistance(p0, p1, p2, p3);
1273 TS_ASSERT_EQUALS(500, distance_cost);
1275 angle_cost = GetEtaAngle(p1, p0, p3, p2);
1276 TS_ASSERT_EQUALS(667, angle_cost);
1277 distance_cost = GetEtaDistance(p1, p0, p3, p2);
1278 TS_ASSERT_EQUALS(500, distance_cost);
1283 a_d = a * 180.0 /
XM_PI;
1289 angle_cost = GetEtaAngle(p0, p1, p2, p3);
1290 TS_ASSERT_EQUALS(1000, angle_cost);
1291 distance_cost = GetEtaDistance(p0, p1, p2, p3);
1292 TS_ASSERT_EQUALS(1000, distance_cost);
1297 a_d = a * 180.0 /
XM_PI;
1303 angle_cost = GetEtaAngle(p0, p1, p2, p3);
1304 TS_ASSERT_EQUALS(667, angle_cost);
1305 distance_cost = GetEtaDistance(p0, p1, p2, p3);
1306 TS_ASSERT_EQUALS(500, distance_cost);
1311 a_d = a * 180.0 /
XM_PI;
1317 angle_cost = GetEtaAngle(p0, p1, p2, p3);
1318 TS_ASSERT_EQUALS(500, angle_cost);
1319 distance_cost = GetEtaDistance(p0, p1, p2, p3);
1320 TS_ASSERT_EQUALS(293, distance_cost);
1322 angle_cost = GetEtaAngle(p1, p0, p3, p2);
1323 TS_ASSERT_EQUALS(500, angle_cost);
1324 distance_cost = GetEtaDistance(p1, p0, p3, p2);
1325 TS_ASSERT_EQUALS(293, distance_cost);
1330 a_d = a * 180.0 /
XM_PI;
1336 angle_cost = GetEtaAngle(p0, p1, p2, p3);
1337 TS_ASSERT_EQUALS(333, angle_cost);
1338 distance_cost = GetEtaDistance(p0, p1, p2, p3);
1339 TS_ASSERT_EQUALS(134, distance_cost);
1341 angle_cost = GetEtaAngle(p1, p0, p3, p2);
1342 TS_ASSERT_EQUALS(333, angle_cost);
1343 distance_cost = GetEtaDistance(p1, p0, p3, p2);
1344 TS_ASSERT_EQUALS(134, distance_cost);
1347 p1 = {0, -hy * 100.0};
1348 p2 = {0, hy * 100.0};
1349 p0 = {-hx * 100.0, 0};
1350 p3 = {hx * 100.0, 0};
1352 angle_cost = GetEtaAngle(p0, p1, p2, p3);
1353 TS_ASSERT_EQUALS(333, angle_cost);
1354 distance_cost = GetEtaDistance(p0, p1, p2, p3);
1355 TS_ASSERT_EQUALS(134, distance_cost);
1357 angle_cost = GetEtaAngle(p1, p0, p3, p2);
1358 TS_ASSERT_EQUALS(333, angle_cost);
1359 distance_cost = GetEtaDistance(p1, p0, p3, p2);
1360 TS_ASSERT_EQUALS(134, distance_cost);
1363 p1 = {0, -hy / 100.0};
1364 p2 = {0, hy / 100.0};
1365 p0 = {-hx / 100.0, 0};
1366 p3 = {hx / 100.0, 0};
1368 angle_cost = GetEtaAngle(p0, p1, p2, p3);
1369 TS_ASSERT_EQUALS(333, angle_cost);
1370 distance_cost = GetEtaDistance(p0, p1, p2, p3);
1371 TS_ASSERT_EQUALS(134, distance_cost);
1373 angle_cost = GetEtaAngle(p1, p0, p3, p2);
1374 TS_ASSERT_EQUALS(333, angle_cost);
1375 distance_cost = GetEtaDistance(p1, p0, p3, p2);
1376 TS_ASSERT_EQUALS(134, distance_cost);
1383 Pt3d pc = {17, -31};
1384 Pt3d p0 = {17 + 8, -31};
1385 Pt3d p1 = {17 + 8, -31 + 0};
1386 double angle = GetAngle(p0, pc, p1);
1387 TS_ASSERT_DELTA(0.0, angle, 1.0e-5);
1388 angle = GetAngle(p1, pc, p0);
1389 TS_ASSERT_DELTA(0.0, angle, 1.0e-5);
1390 p1 = {17 + 8, -31 + 8};
1391 angle = GetAngle(p0, pc, p1);
1392 TS_ASSERT_DELTA(
XM_PI * 1.75, angle, 1.0e-5);
1393 angle = GetAngle(p1, pc, p0);
1394 TS_ASSERT_DELTA(
XM_PI * 0.25, angle, 1.0e-5);
1395 p1 = {17 + 0, -31 + 8};
1396 angle = GetAngle(p0, pc, p1);
1397 TS_ASSERT_DELTA(
XM_PI * 1.5, angle, 1.0e-5);
1398 angle = GetAngle(p1, pc, p0);
1399 TS_ASSERT_DELTA(
XM_PI * 0.5, angle, 1.0e-5);
1400 p1 = {17 - 8, -31 + 8};
1401 angle = GetAngle(p0, pc, p1);
1402 TS_ASSERT_DELTA(
XM_PI * 1.25, angle, 1.0e-5);
1403 angle = GetAngle(p1, pc, p0);
1404 TS_ASSERT_DELTA(
XM_PI * 0.75, angle, 1.0e-5);
1405 p1 = {17 - 8, -31 + 0};
1406 angle = GetAngle(p0, pc, p1);
1407 TS_ASSERT_DELTA(
XM_PI, angle, 1.0e-5);
1408 angle = GetAngle(p1, pc, p0);
1409 TS_ASSERT_DELTA(
XM_PI, angle, 1.0e-5);
1410 p1 = {17 - 8, -31 - 8};
1411 angle = GetAngle(p0, pc, p1);
1412 TS_ASSERT_DELTA(
XM_PI * 0.75, angle, 1.0e-5);
1413 angle = GetAngle(p1, pc, p0);
1414 TS_ASSERT_DELTA(
XM_PI * 1.25, angle, 1.0e-5);
1415 p1 = {17 - 0, -31 - 8};
1416 angle = GetAngle(p0, pc, p1);
1417 TS_ASSERT_DELTA(
XM_PI * 0.5, angle, 1.0e-5);
1418 angle = GetAngle(p1, pc, p0);
1419 TS_ASSERT_DELTA(
XM_PI * 1.5, angle, 1.0e-5);
1420 p1 = {17 + 8, -31 - 8};
1421 angle = GetAngle(p0, pc, p1);
1422 TS_ASSERT_DELTA(
XM_PI * 0.25, angle, 1.0e-5);
1423 angle = GetAngle(p1, pc, p0);
1424 TS_ASSERT_DELTA(
XM_PI * 1.75, angle, 1.0e-5);
1431 VecInt2d triangles = {{0, 3, 4}, {0, 4, 1}, {1, 4, 2}, {2, 4, 5},
1432 {3, 6, 7}, {4, 7, 8}, {4, 8, 5}, {3, 7, 4}};
1435 MeQuadBlossomImpl blossom(points, triangles);
1436 VecVecCellData vertexFaces;
1437 VecVecVecCellData sortedFacesChains;
1438 blossom.ExtractCellsAdjacentToPoint(vertexFaces, sortedFacesChains);
1440 VecVecCellData expected = {
1441 {{4, 3, 0}, {1, 4, 1}},
1442 {{4, 0, 1}, {2, 4, 2}},
1443 {{4, 1, 2}, {5, 4, 3}},
1444 {{0, 4, 0}, {7, 6, 4}, {4, 7, 7}},
1445 {{3, 0, 0}, {0, 1, 1}, {1, 2, 2}, {2, 5, 3}, {8, 7, 5}, {5, 8, 6}, {7, 3, 7}},
1446 {{4, 2, 3}, {8, 4, 6}},
1448 {{6, 3, 4}, {4, 8, 5}, {3, 4, 7}},
1449 {{7, 4, 5}, {4, 5, 6}}};
1451 VecVecVecCellData expectedSorted = {
1452 {{{1, 4, 1}, {4, 3, 0}}},
1453 {{{2, 4, 2}, {4, 0, 1}}},
1454 {{{5, 4, 3}, {4, 1, 2}}},
1455 {{{0, 4, 0}, {4, 7, 7}, {7, 6, 4}}},
1456 {{{3, 0, 0}, {0, 1, 1}, {1, 2, 2}, {2, 5, 3}, {5, 8, 6}, {8, 7, 5}, {7, 3, 7}}},
1457 {{{8, 4, 6}, {4, 2, 3}}},
1459 {{{6, 3, 4}, {3, 4, 7}, {4, 8, 5}}},
1460 {{{7, 4, 5}, {4, 5, 6}}}};
1462 TS_ASSERT_EQUALS(expected, vertexFaces);
1463 TS_ASSERT_EQUALS(expectedSorted, sortedFacesChains);
1465 triangles = {{0, 3, 4}, {0, 4, 1}, {1, 4, 2}, {2, 4, 5}, {3, 6, 7}, {4, 7, 8}, {4, 8, 5}};
1467 MeQuadBlossomImpl blossom2(points, triangles);
1468 blossom2.ExtractCellsAdjacentToPoint(vertexFaces, sortedFacesChains);
1470 expected = {{{4, 3, 0}, {1, 4, 1}},
1471 {{4, 0, 1}, {2, 4, 2}},
1472 {{4, 1, 2}, {5, 4, 3}},
1473 {{0, 4, 0}, {7, 6, 4}},
1474 {{3, 0, 0}, {0, 1, 1}, {1, 2, 2}, {2, 5, 3}, {8, 7, 5}, {5, 8, 6}},
1475 {{4, 2, 3}, {8, 4, 6}},
1477 {{6, 3, 4}, {4, 8, 5}},
1478 {{7, 4, 5}, {4, 5, 6}}};
1483 expectedSorted = {{{{1, 4, 1}, {4, 3, 0}}},
1484 {{{2, 4, 2}, {4, 0, 1}}},
1485 {{{5, 4, 3}, {4, 1, 2}}},
1486 {{{0, 4, 0}}, {{7, 6, 4}}},
1487 {{{3, 0, 0}, {0, 1, 1}, {1, 2, 2}, {2, 5, 3}, {5, 8, 6}, {8, 7, 5}}},
1488 {{{8, 4, 6}, {4, 2, 3}}},
1490 {{{6, 3, 4}}, {{4, 8, 5}}},
1491 {{{7, 4, 5}, {4, 5, 6}}}};
1493 TS_ASSERT_EQUALS(expected, vertexFaces);
1494 TS_ASSERT_EQUALS(expectedSorted, sortedFacesChains);
1506 MeQuadBlossomImpl blossom(points, triangles);
1507 blossom.GetEdges(17);
1517 TS_ASSERT_EQUALS(expect_interior, blossom.m_interiorEdges);
1518 TS_ASSERT_EQUALS(expect_boundary, blossom.m_boundaryEdges);
1519 TS_ASSERT_EQUALS(expect_extra, blossom.m_extraEdges);
1520 TS_ASSERT_EQUALS(expectExtraVertices, blossom.m_extraPoints);
1525 VecInt2d triangles = {{2, 9, 6}, {9, 4, 6}};
1528 MeQuadBlossomImpl blossom(points, triangles);
1529 blossom.GetEdges(17);
1531 VecEdge expect_interior = {{6, 9, 1, 0, 4, 2}};
1538 TS_ASSERT_EQUALS(expect_interior, blossom.m_interiorEdges);
1539 TS_ASSERT_EQUALS(expect_boundary, blossom.m_boundaryEdges);
1540 TS_ASSERT_EQUALS(expect_extra, blossom.m_extraEdges);
1541 TS_ASSERT_EQUALS(expectExtraVertices, blossom.m_extraPoints);
1546 VecInt2d triangles = {{2, 9, 6}, {9, 4, 6}, {9, 3, 4}};
1549 MeQuadBlossomImpl blossom(points, triangles);
1550 blossom.GetEdges(17);
1557 {9, 3, 2,
XM_NONE, 4,
XM_NONE}, {6, 2, 0,
XM_NONE, 9,
XM_NONE},
1558 {4, 6, 1,
XM_NONE, 9,
XM_NONE}, {3, 4, 2,
XM_NONE, 9,
XM_NONE},
1562 VecInt2d expectExtraVertices = {{9, 6, 2, 3, 4}};
1563 TS_ASSERT_EQUALS(expect_interior, blossom.m_interiorEdges);
1564 TS_ASSERT_EQUALS(expect_boundary, blossom.m_boundaryEdges);
1565 TS_ASSERT_EQUALS(expect_extra, blossom.m_extraEdges);
1566 TS_ASSERT_EQUALS(expectExtraVertices, blossom.m_extraPoints);
1571 VecInt2d triangles = {{4, 3, 0}, {1, 4, 0}, {2, 4, 1}, {5, 4, 2},
1572 {7, 6, 3}, {8, 7, 4}, {5, 8, 4}, {4, 7, 3}};
1575 MeQuadBlossomImpl blossom(points, triangles);
1576 blossom.GetEdges(17);
1597 VecMeEdge expect_extra = {{4, 0, 17}, {5, 4, 17}};
1598 VecInt2d expectExtraVertices = {{3, 7, 6, 0, 4}, {7, 4, 8, 6, 3}};
1599 TS_ASSERT_EQUALS(expect_interior, blossom.m_interiorEdges);
1600 TS_ASSERT_EQUALS(expect_boundary, blossom.m_boundaryEdges);
1601 TS_ASSERT_EQUALS(expect_extra, blossom.m_extraEdges);
1602 TS_ASSERT_EQUALS(expectExtraVertices, blossom.m_extraPoints);
1608 VecInt2d triangles = {{4, 3, 0}, {1, 4, 0}, {2, 4, 1}, {5, 4, 2},
1609 {3, 7, 9}, {8, 7, 4}, {5, 8, 4}, {3, 9, 6}};
1612 MeQuadBlossomImpl blossom(points, triangles);
1613 blossom.GetEdges(17);
1637 VecInt2d expectExtraVertices = {{4, 8, 7, 3, 0}};
1638 TS_ASSERT_EQUALS(expect_interior, blossom.m_interiorEdges);
1639 TS_ASSERT_EQUALS(expect_boundary, blossom.m_boundaryEdges);
1640 TS_ASSERT_EQUALS(expect_extra, blossom.m_extraEdges);
1641 TS_ASSERT_EQUALS(expectExtraVertices, blossom.m_extraPoints);
1650 VecInt2d triangles = {{4, 3, 0}, {1, 4, 0}, {2, 4, 1}, {5, 4, 2},
1651 {7, 6, 3}, {8, 7, 4}, {5, 8, 4}, {4, 7, 3}};
1654 MeQuadBlossomImpl blossom(points, triangles);
1655 blossom.GetEdges(17);
1656 VecInt2d quads = blossom.EliminateEdges({1, 3, 5, 7});
1657 VecInt2d expect = {{0, 1, 4, 3}, {2, 5, 4, 1}, {3, 4, 7, 6}, {4, 5, 8, 7}};
1658 TS_ASSERT_EQUALS(expect, quads);
1662 VecInt2d triangles = {{4, 3, 0}, {1, 4, 0}, {2, 4, 1}, {5, 4, 2},
1663 {3, 7, 9}, {8, 7, 4}, {5, 8, 4}, {3, 9, 6}};
1665 MeQuadBlossomImpl blossom(points, triangles);
1666 blossom.GetEdges(17);
1667 VecInt2d quads = blossom.EliminateEdges({2, 5, 3, 0});
1669 VecInt2d expect = {{0, 1, 4, 3}, {2, 5, 4, 1}, {4, 5, 8, 7}, {3, 7, 9, 6}};
1670 TS_ASSERT_EQUALS(expect, quads);
1679 VecPt3d points = {{0, 0, 0}, {10, 0, 0}, {20, 0, 0}, {30, 0, 0},
1680 {0, 10, 0}, {10, 10, 0}, {20, 10, 0},
1681 {0, 20, 0}, {10, 20, 0},
1684 VecInt2d triangles = {{0, 1, 4}, {1, 5, 4}, {1, 2, 5}, {2, 6, 5}, {2, 3, 6},
1685 {4, 5, 7}, {5, 8, 7}, {5, 6, 8}, {7, 8, 9}};
1692 MeQuadBlossomImpl blossom(points, triangles);
1694 bool splitBoundaryPoints =
false;
1695 bool useAngleCost =
true;
1696 BSHP<XmUGrid> ugrid = blossom._MakeQuads(splitBoundaryPoints, useAngleCost, cost);
1697 const VecInt& cells = ugrid->GetCellstream();
1699 XMU_QUAD, 4, 1, 5, 4, 0,
1700 XMU_QUAD, 4, 2, 6, 5, 1,
1701 XMU_TRIANGLE, 3, 2, 3, 6,
1702 XMU_QUAD, 4, 5, 8, 7, 4,
1703 XMU_TRIANGLE, 3, 5, 6, 8,
1704 XMU_TRIANGLE, 3, 7, 8, 9
1706 TS_ASSERT_EQUALS(expectedCells, cells);
1707 const VecPt3d& actualPoints = ugrid->GetLocations();
1712 MeQuadBlossomImpl blossom(points, triangles);
1714 bool splitBoundaryPoints =
true;
1715 bool useAngleCost =
true;
1716 BSHP<XmUGrid> ugrid = blossom._MakeQuads(splitBoundaryPoints, useAngleCost, cost);
1717 const VecInt& cells = ugrid->GetCellstream();
1719 XMU_QUAD, 4, 1, 5, 4, 0,
1720 XMU_QUAD, 4, 2, 10, 5, 1,
1721 XMU_QUAD, 4, 2, 3, 6, 10,
1722 XMU_QUAD, 4, 5, 8, 7, 4,
1723 XMU_QUAD, 4, 6, 8, 5, 10,
1724 XMU_TRIANGLE, 3, 7, 8, 9
1726 TS_ASSERT_EQUALS(expectedCells, cells);
1727 const VecPt3d& actualPoints = ugrid->GetLocations();
1728 VecPt3d expectedPoints = points;
1729 expectedPoints.push_back(
Pt3d(50.0/3.0, 20.0/3.0, 0.0));
1735 VecPt3d points = { {-10, 0, 0}, {0, 0, 0}, {10, 0, 0}, {-5, 7.07, 0}, {5, 7.07, 0}, {0, 14.14, 0} };
1737 VecInt2d triangles = { {0, 1, 3}, {1, 2, 4}, {1, 4, 3}, {3, 4, 5} };
1739 MeQuadBlossomImpl blossom(points, triangles);
1741 bool splitBoundaryPoints =
true;
1742 bool useAngleCost =
false;
1743 BSHP<XmUGrid> ugrid = blossom._MakeQuads(splitBoundaryPoints, useAngleCost, cost);
1744 const VecInt& cells = ugrid->GetCellstream();
1746 XMU_QUAD, 4, 3, 0, 1, 6,
1747 XMU_QUAD, 4, 1, 2, 4, 6,
1748 XMU_QUAD, 4, 3, 6, 4, 5
1750 TS_ASSERT_EQUALS(expectedCells, cells);
1751 const VecPt3d& actualPoints = ugrid->GetLocations();
1752 VecPt3d expectedPoints = points;
1753 expectedPoints.push_back(
Pt3d(0, 14.14 / 3, 0));
1764 {0, 0, 0}, {10, 0, 0}, {20, 0, 0}, {30, 0, 0},
1765 {0, 10, 0}, {10, 10, 0}, {20, 10, 0}, {30, 10, 0},
1766 {0, 20, 0}, {10, 20, 0}, {20, 20, 0}, {30, 20, 0},
1767 {0, 30, 0}, {10, 30, 0}, {20, 30, 0}, {30, 30, 0}};
1769 {0, 1, 4}, {1, 5, 4}, {1, 2, 5}, {2, 6, 5}, {2, 3, 6}, {3, 7, 6},
1770 {4, 9, 8}, {4, 5, 9}, {5, 10, 9}, {5, 6, 10}, {6, 7, 11}, {6, 11, 10},
1771 {8, 9, 12}, {9, 13, 12}, {9, 10, 13}, {10, 14, 13}, {10, 11, 14},
1775 MeQuadBlossomImpl blossom(points, triangles);
1777 bool splitBoundaryPoints =
false;
1778 bool useAngleCost =
true;
1779 BSHP<XmUGrid> ugrid = blossom._MakeQuads(splitBoundaryPoints, useAngleCost, cost);
1780 const VecInt& cells = ugrid->GetCellstream();
1782 XMU_QUAD, 4, 1, 5, 4, 0,
1783 XMU_QUAD, 4, 2, 6, 5, 1,
1784 XMU_QUAD, 4, 3, 7, 6, 2,
1785 XMU_QUAD, 4, 4, 5, 9, 8,
1786 XMU_QUAD, 4, 5, 6, 10, 9,
1787 XMU_QUAD, 4, 6, 7, 11, 10,
1788 XMU_QUAD, 4, 9, 13, 12, 8,
1789 XMU_QUAD, 4, 10, 14, 13, 9,
1790 XMU_QUAD, 4, 11, 15, 14, 10,
1792 TS_ASSERT_EQUALS(expectedCells, cells);
1793 const VecPt3d& actualPoints = ugrid->GetLocations();
1794 VecPt3d expectedPoints = points;
1799 MeQuadBlossomImpl blossom(points, triangles);
1801 bool splitBoundaryPoints =
true;
1802 bool useAngleCost =
true;
1803 BSHP<XmUGrid> ugrid = blossom._MakeQuads(splitBoundaryPoints, useAngleCost, cost);
1804 const VecInt& cells = ugrid->GetCellstream();
1806 XMU_QUAD, 4, 1, 5, 4, 0,
1807 XMU_QUAD, 4, 2, 6, 5, 1,
1808 XMU_QUAD, 4, 3, 7, 6, 2,
1809 XMU_QUAD, 4, 4, 5, 9, 8,
1810 XMU_QUAD, 4, 5, 6, 10, 9,
1811 XMU_QUAD, 4, 6, 7, 11, 10,
1812 XMU_QUAD, 4, 9, 13, 12, 8,
1813 XMU_QUAD, 4, 10, 14, 13, 9,
1814 XMU_QUAD, 4, 11, 15, 14, 10,
1816 TS_ASSERT_EQUALS(expectedCells, cells);
1817 const VecPt3d& actualPoints = ugrid->GetLocations();
1818 VecPt3d expectedPoints = points;
1830 {-10, 0, 0}, {0, 0, 0}, {10, 0,0},
1831 {-15, 10, 0}, {-5, 10, 0}, {5, 10, 0}, {15, 10, 0},
1832 {-20, 20, 0}, {-10, 20, 0}, {0, 20, 0}, {10, 20, 0}, {20, 20, 0},
1833 {-25, 30, 0}, {-15, 30, 0}, {-5, 30, 0}, {5, 30, 0}, {15, 30, 0}, {25, 30, 0},
1834 {-30, 40, 0}, {-20, 40, 0}, {-10, 40, 0}, {0, 40, 0}, {10, 40, 0}, {20, 40, 0}, {30, 40, 0}};
1836 {0, 4, 3}, {0, 1, 4}, {1, 5, 4}, {1, 2, 5}, {2, 6, 5},
1837 {3, 8, 7}, {3, 4, 8}, {4, 9, 8}, {4, 5, 9}, {5, 10, 9}, {5, 11, 10}, {5, 6, 11},
1838 {7, 13, 12}, {7, 8, 13}, {8, 14, 13}, {8, 9, 14}, {9, 15, 14}, {9, 10, 15}, {10, 16, 15}, {10, 11, 16}, {11, 17, 16},
1839 {12, 19, 18}, {12, 13, 19}, {13, 20, 19}, {13, 14, 20}, {14, 21, 20}, {14, 15, 21}, {15, 22, 21}, {15, 23, 22}, {15, 16, 23}, {16, 17, 23}, {17, 24, 23}};
1842 MeQuadBlossomImpl blossom(points, triangles);
1844 bool splitBoundaryPoints =
false;
1845 bool useAngleCost =
true;
1846 int numBoundaryEdges = blossom.PreMakeQuads();
1847 TS_ASSERT_EQUALS(16, numBoundaryEdges);
1848 BSHP<XmUGrid> ugrid = blossom._MakeQuads(splitBoundaryPoints, useAngleCost, cost);
1849 const VecInt& cells = ugrid->GetCellstream();
1851 XMU_TRIANGLE, 3, 0, 4, 3,
1852 XMU_QUAD, 4, 1, 5, 4, 0,
1853 XMU_QUAD, 4, 2, 6, 5, 1,
1854 XMU_TRIANGLE, 3, 3, 8, 7,
1855 XMU_QUAD, 4, 4, 9, 8, 3,
1856 XMU_QUAD, 4, 5, 10, 9, 4,
1857 XMU_QUAD, 4, 5, 6, 11, 10,
1858 XMU_TRIANGLE, 3, 7, 13, 12,
1859 XMU_QUAD, 4, 8, 14, 13, 7,
1860 XMU_QUAD, 4, 9, 15, 14, 8,
1861 XMU_QUAD, 4, 10, 16, 15, 9,
1862 XMU_QUAD, 4, 11, 17, 16, 10,
1863 XMU_TRIANGLE, 3, 12, 19, 18,
1864 XMU_QUAD, 4, 13, 20, 19, 12,
1865 XMU_QUAD, 4, 14, 21, 20, 13,
1866 XMU_QUAD, 4, 15, 22, 21, 14,
1867 XMU_QUAD, 4, 15, 16, 23, 22,
1868 XMU_QUAD, 4, 17, 24, 23, 16
1870 TS_ASSERT_EQUALS(expectedCells, cells);
1871 const VecPt3d& actualPoints = ugrid->GetLocations();
1872 VecPt3d expectedPoints = points;
1877 MeQuadBlossomImpl blossom(points, triangles);
1879 bool splitBoundaryPoints =
true;
1880 bool useAngleCost =
true;
1881 BSHP<XmUGrid> ugrid = blossom._MakeQuads(splitBoundaryPoints, useAngleCost, cost);
1882 const VecInt& cells = ugrid->GetCellstream();
1884 XMU_QUAD, 4, 3, 0, 4, 25,
1885 XMU_QUAD, 4, 1, 5, 4, 0,
1886 XMU_QUAD, 4, 2, 6, 5, 1,
1887 XMU_QUAD, 4, 8, 7, 3, 25,
1888 XMU_QUAD, 4, 4, 9, 8, 25,
1889 XMU_QUAD, 4, 5, 10, 9, 4,
1890 XMU_QUAD, 4, 5, 6, 11, 10,
1891 XMU_QUAD, 4, 12, 7, 13, 26,
1892 XMU_QUAD, 4, 8, 14, 13, 7,
1893 XMU_QUAD, 4, 9, 15, 14, 8,
1894 XMU_QUAD, 4, 10, 16, 15, 9,
1895 XMU_QUAD, 4, 11, 17, 16, 10,
1896 XMU_QUAD, 4, 19, 18, 12, 26,
1897 XMU_QUAD, 4, 13, 20, 19, 26,
1898 XMU_QUAD, 4, 14, 21, 20, 13,
1899 XMU_QUAD, 4, 15, 22, 21, 14,
1900 XMU_QUAD, 4, 15, 16, 23, 22,
1901 XMU_QUAD, 4, 17, 24, 23, 16,
1903 TS_ASSERT_EQUALS(expectedCells, cells);
1904 const VecPt3d& actualPoints = ugrid->GetLocations();
1905 VecPt3d expectedPoints = points;
1906 expectedPoints.push_back({-10, 13.3333, 0.0});
1907 expectedPoints.push_back({-20.0, 33.3333, 0.0});
1918 VecPt3d points = { { 0, 0, 0 }, { 10, 0, 0 }, { 20, 0, 0 }, { 30, 0, 0 },
1919 {0, 10, 0}, {10, 10, 0}, {20, 10, 0}, {30, 10, 0},
1920 {0, 20, 0}, {10, 20, 0}, {20, 20, 0}, {30, 20, 0}
1926 XMU_TRIANGLE, 3, 0, 5, 4,
1927 XMU_TRIANGLE, 3, 0, 1, 5,
1928 XMU_TRIANGLE, 3, 1, 2, 5,
1929 XMU_TRIANGLE, 3, 2, 6, 5,
1930 XMU_QUAD, 4, 2, 3, 7, 6,
1932 XMU_TRIANGLE, 3, 4, 5, 8,
1933 XMU_POLYGON, 3, 5, 9, 8,
1934 XMU_QUAD, 4, 5, 6, 10, 9,
1935 XMU_POLYGON, 4, 6, 7, 11, 10
1944 VecPt3d quadPoints = quadUGrid->GetLocations();
1946 VecPt3d expectedQuadPoints = {
1947 { 0, 0, 0 }, { 10, 0, 0 }, { 20, 0, 0 }, { 30, 0, 0 },
1948 {0, 10, 0}, {10, 10, 0}, {20, 10, 0}, {30, 10, 0},
1949 {0, 20, 0}, {10, 20, 0}, {20, 20, 0}, {30, 20, 0},
1951 {5, 0, 0}, {0, 5, 0}, {5, 5, 0}, {15, 0, 0}, {10, 5, 0},
1952 {25, 0, 0}, {15, 5, 0}, {20, 5, 0}, {30, 5, 0}, {5, 10, 0},
1953 {0, 15, 0}, {15, 10, 0}, {5, 15, 0}, {10, 15, 0}, {25, 10, 0},
1954 {20, 15, 0}, {30, 15, 0}, {5, 20, 0}, {15, 20, 0}, {25, 20, 0},
1956 {3.33333, 6.66667, 0}, {6.66667, 3.33333, 0},
1957 {13.33333, 3.33333, 0}, {16.66667, 6.66667, 0},
1958 {25, 5, 0}, {3.33333, 13.33333, 0}, {6.66667, 16.66667, 0},
1959 {15, 15, 0}, {25, 15, 0}
1963 VecInt expectedQuadCells = {
1964 XMU_QUAD, 4, 0, 14, 32, 13,
1965 XMU_QUAD, 4, 5, 21, 32, 14,
1966 XMU_QUAD, 4, 4, 13, 32, 21,
1967 XMU_QUAD, 4, 0, 12, 33, 14,
1968 XMU_QUAD, 4, 1, 16, 33, 12,
1969 XMU_QUAD, 4, 5, 14, 33, 16,
1970 XMU_QUAD, 4, 1, 15, 34, 16,
1971 XMU_QUAD, 4, 2, 18, 34, 15,
1972 XMU_QUAD, 4, 5, 16, 34, 18,
1973 XMU_QUAD, 4, 2, 19, 35, 18,
1974 XMU_QUAD, 4, 6, 23, 35, 19,
1975 XMU_QUAD, 4, 5, 18, 35, 23,
1976 XMU_QUAD, 4, 2, 17, 36, 19,
1977 XMU_QUAD, 4, 3, 20, 36, 17,
1978 XMU_QUAD, 4, 7, 26, 36, 20,
1979 XMU_QUAD, 4, 6, 19, 36, 26,
1980 XMU_QUAD, 4, 4, 21, 37, 22,
1981 XMU_QUAD, 4, 5, 24, 37, 21,
1982 XMU_QUAD, 4, 8, 22, 37, 24,
1983 XMU_QUAD, 4, 5, 25, 38, 24,
1984 XMU_QUAD, 4, 9, 29, 38, 25,
1985 XMU_QUAD, 4, 8, 24, 38, 29,
1986 XMU_QUAD, 4, 5, 23, 39, 25,
1987 XMU_QUAD, 4, 6, 27, 39, 23,
1988 XMU_QUAD, 4, 10, 30, 39, 27,
1989 XMU_QUAD, 4, 9, 25, 39, 30,
1990 XMU_QUAD, 4, 6, 26, 40, 27,
1991 XMU_QUAD, 4, 7, 28, 40, 26,
1992 XMU_QUAD, 4, 11, 31, 40, 28,
1993 XMU_QUAD, 4, 10, 27, 40, 31
1996 VecInt quadCells = quadUGrid->GetCellstream();
2024 VecPt3d points = {{0, 0, 0}, {10, 10, 0}, {0, 10, 0}};
2026 MeQuadBlossomImpl blossom(points, triangles);
2027 int numBoundaryEdges = blossom.PreMakeQuads();
2028 TS_ASSERT_EQUALS(3, numBoundaryEdges);
2038 TS_ASSERT_EQUALS(expect_interior, blossom.m_interiorEdges);
2039 TS_ASSERT_EQUALS(expect_boundary, blossom.m_boundaryEdges);
2040 TS_ASSERT_EQUALS(expect_extra, blossom.m_extraEdges);
2041 TS_ASSERT_EQUALS(expectExtraVertices, blossom.m_extraPoints);
2043 bool splitBoundaryPoints =
true;
2044 bool useAngle =
false;
2045 blossom.MakeQuads(splitBoundaryPoints, useAngle);
2048 TS_ASSERT_EQUALS(triangles, faces);
2059 VecInt2d triangles = {{2, 0, 3}, {3, 0, 1}};
2060 VecPt3d points = {{0, 0, 0}, {10, 0, 0}, {0, 10, 0}, {10, 10, 0}};
2062 MeQuadBlossomImpl blossom(points, triangles);
2063 int numBoundaryEdges = blossom.PreMakeQuads();
2064 TS_ASSERT_EQUALS(4, numBoundaryEdges);
2066 VecEdge expect_interior = {{0, 3, 0, 1, 2, 1}};
2074 TS_ASSERT_EQUALS(expect_interior, blossom.m_interiorEdges);
2075 TS_ASSERT_EQUALS(expect_boundary, blossom.m_boundaryEdges);
2076 TS_ASSERT_EQUALS(expect_extra, blossom.m_extraEdges);
2077 TS_ASSERT_EQUALS(expectExtraVertices, blossom.m_extraPoints);
2079 bool splitBoundaryPoints =
true;
2080 bool useAngle =
false;
2081 blossom.MakeQuads(splitBoundaryPoints, useAngle);
2084 VecInt2d expectedFaces = {{0, 1, 3, 2}};
2085 TS_ASSERT_EQUALS(expectedFaces, faces);
2090 VecInt2d triangles = {{2, 9, 6}, {9, 4, 6}, {9, 3, 4}};
2092 points[2] = {0, 0, 0};
2093 points[3] = {10, 20, 0};
2094 points[4] = {0, 20, 0};
2095 points[6] = {0, 10, 0};
2096 points[9] = {10, 10, 0};
2099 MeQuadBlossomImpl blossom(points, triangles);
2100 int numBoundaryEdges = blossom.PreMakeQuads();
2101 TS_ASSERT_EQUALS(5, numBoundaryEdges);
2108 {9, 3, 2,
XM_NONE, 4,
XM_NONE}, {6, 2, 0,
XM_NONE, 9,
XM_NONE},
2109 {4, 6, 1,
XM_NONE, 9,
XM_NONE}, {3, 4, 2,
XM_NONE, 9,
XM_NONE},
2112 VecMeEdge expect_extra = {{0, 2, -1000}};
2113 VecInt2d expectExtraVertices = {{9, 6, 2, 3, 4}};
2114 TS_ASSERT_EQUALS(expect_interior, blossom.m_interiorEdges);
2115 TS_ASSERT_EQUALS(expect_boundary, blossom.m_boundaryEdges);
2116 TS_ASSERT_EQUALS(expect_extra, blossom.m_extraEdges);
2117 TS_ASSERT_EQUALS(expectExtraVertices, blossom.m_extraPoints);
2119 bool splitBoundaryPoints =
true;
2120 bool useAngle =
false;
2121 blossom.MakeQuads(splitBoundaryPoints, useAngle);
2124 VecInt2d expectedFaces = {{2, 9, 6}, {4, 6, 9, 3}};
2125 TS_ASSERT_EQUALS(expectedFaces, faces);
VecEdge m_interiorEdges
The interior edges of the triangular mesh.
void testGetInteriorEdges()
Test GetInteriorEdges function.
std::vector< int > VecInt
void testExtractCellsAdjacentToPoint()
Test ExtractCellsAdjacentToPoint function.
int m_fL
Face on the left looking from m_p0 to m_p1.
void testProcessVertexChains()
Test ProcessVertexChains function.
void testEliminateEdges()
Test GetAngle function.
void testSimpleQuad()
Test simple quad with three divisions on each side.
VecInt2d m_faces
initially triangles becomes quads
void testEta()
Test GetEtaAngle and GetEtaDistance functions.
const double TWO_PI
2 times PI
double gmXyDistanceSquared(const Pt3d &pt1, const Pt3d &pt2)
static double EstimatedRunTimeInMinutes(int a_numPoints)
Get the estimated time to run the Quad Blossom algorithm in minutes.
virtual ~MeQuadBlossom()
Destructor.
static BSHP< XmUGrid > New()
Class to convert 2D grid of triangles to quads.
void testSplitToQuads()
Test MeQuadBlossom::SplitToQuads.
VecMeEdge m_extraEdges
The adjacent boundary triangles that can be split. { face0, face1, cost }.
void testEstimatedRunTime()
Test function to get estimated time to run Quad Blossom algorithm.
int m_pR
Point on the face (triangle) to the right opposite the edge.
int m_fR
Face on the right looking from m_p0 to m_p1.
std::vector< VecInt > VecInt2d
const double PI_OVER_TWO
PI divided by 2.
void testGetEdges()
Test GetAngle function.
MeQuadBlossom()
Constructor.
void testComplexQuad()
Test complex quad with three divisions on two opposite sides and.
Pt3d gmComputeCentroid(const VecPt3d &a_points)
std::vector< edgerecord > VecEdge
int m_nextPoint
Index of the point going out from point p.
Pt3d gmCreateVector(const Pt3d &a_p1, const Pt3d &a_p2)
const int DEFAULT_COST
The default weight for extra edges.
void testGetAngle()
Test GetAngle function.
int m_pL
Point on the face (triangle) to the left opposite the edge.
static BSHP< XmUGrid > SplitToQuads(BSHP< XmUGrid > a_ugrid)
Splits UGrid with 2D cells into quads by adding midpoints for each edge and creating a quad by attach...
VecPt3d m_splitPoints
The potential new points for split points.
const double TWO_OVER_PI
2 divided by PI
VecPt3d m_points
points of the triangular mesh
std::vector< MeEdge > VecMeEdge
Vector of MeEdge.
void testSimpleTriangle()
Test simple triangle with three divisions on each side.
int m_priorPoint
Index of the point coming into point p.
std::vector< Pt3d > VecPt3d
VecEdge m_boundaryEdges
The boundary edges of the triangular mesh.
void testGetBoundaryEdges()
Test GetBoundaryEdges function.
void testPreMakeQuads()
Test PreMakeQuads function.