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.