56 enum RelaxTypeEnum { RELAXTYPE_AREA, RELAXTYPE_ANGLE, RELAXTYPE_SPRING };
67 const VecInt& a_fixedPoints,
68 BSHP<TrTin> a_tin)
override;
105 MeRelaxerImpl::MeRelaxerImpl()
108 , m_fixedPoints(nullptr)
112 , m_relaxType(RELAXTYPE_AREA)
121 MeRelaxerImpl::~MeRelaxerImpl()
135 const VecInt& a_fixedPoints,
149 for (
size_t i = 0; i < a_fixedPoints.size(); ++i)
161 int numiterations(3);
163 if (relaxtype == RELAXTYPE_SPRING)
168 "No size function specified with spring relaxation " 169 "method. Relaxation method has been set to AREA " 172 relaxtype = RELAXTYPE_AREA;
190 for (
int i = 0; i < numiterations; ++i)
197 m_tin->Triangles().clear();
198 m_tin->TrisAdjToPts().clear();
204 pts[idx] = pts.back();
206 szs[idx] = szs.back();
214 bool trianglesChanged(
false);
215 trianglesChanged =
m_tin->OptimizeTriangulation();
217 if (trianglesChanged && RELAXTYPE_SPRING == relaxtype)
234 if (type ==
"spring_relaxation")
246 size_t numTri =
m_tin->NumTriangles();
248 for (
size_t t = 0; t < numTri; ++t)
263 XM_ASSERT(a_iteration > 0 && a_numiterations > 0 && a_iteration <= a_numiterations);
267 size_t nPoints = points.size();
268 Pt3d origlocation, newlocation;
269 for (
size_t p = 0; p < nPoints; ++p)
273 origlocation = points[p];
280 case RELAXTYPE_ANGLE:
283 case RELAXTYPE_SPRING:
291 newlocation.
z = origlocation.
z;
296 points[p] = newlocation;
304 else if (RELAXTYPE_SPRING == a_relaxType)
321 double sumx(0.0), sumy(0.0), area, sumarea(0.0);
322 const VecInt& adjTris =
m_tin->TrisAdjToPts()[a_point];
323 for (
size_t i = 0; i < adjTris.size(); ++i)
325 area =
m_tin->TriangleArea(adjTris[i]);
331 a_newLocation.
x = sumx / sumarea;
332 a_newLocation.
y = sumy / sumarea;
343 double targetangle, mag, a, c, d;
344 double da, db, dx, dy, sx, sy, radius;
345 Pt2d sum, pt, p1, p2, p3, centroid;
349 const VecInt& adjTris =
m_tin->TrisAdjToPts()[a_point];
351 size_t num = adjTris.size();
354 targetangle = 2.0 *
XM_PI / (double)num;
359 for (
size_t i = 0; i < adjTris.size(); ++i)
361 int tri = adjTris[i];
362 id =
m_tin->LocalIndex(tri, a_point);
366 pt.
x = points[a_point].x;
367 pt.
y = points[a_point].y;
368 p1.
x = points[point1].x;
369 p1.
y = points[point1].y;
370 p2.
x = points[point2].x;
371 p2.
y = points[point2].y;
375 c = sqrt(
sqr(dx) +
sqr(dy));
376 sx = p1.
x + dx / 2.0;
377 sy = p1.
y + dy / 2.0;
379 a = (c / 2.0) / sin(targetangle / 2.0);
380 d = a * cos(targetangle / 2.0);
381 radius = (a * a) / (2.0 * d);
393 centroid.
x = sx + (d - radius) * dy;
394 centroid.
y = sy - (d - radius) * dx;
398 centroid.
x = sx - (d - radius) * dy;
399 centroid.
y = sy + (d - radius) * dx;
402 dx = pt.
x - centroid.
x;
403 dy = pt.
y - centroid.
y;
404 mag = sqrt(dx * dx + dy * dy);
408 p3.
x = centroid.
x + radius * dx;
409 p3.
y = centroid.
y + radius * dy;
414 a_newLocation.
x = (sum.
x / (double)num);
415 a_newLocation.
y = (sum.
y / (double)num);
428 double springStiffness(1.0);
431 double numPtsFactor(1.7 / (
double)neighbors.size());
432 Pt3d& p0(points[a_point]);
434 for (
size_t i = 0; i < neighbors.size(); ++i)
436 int neighborIdx = neighbors[i];
437 Pt3d& p1(points[neighborIdx]);
440 double dist =
Mdist(p0.x, p0.y, p1.
x, p1.
y);
441 double targetDist = 0.5 * (size0 + size1);
442 double force(springStiffness * (dist - targetDist));
443 double _fx = force * vec.
x / dist;
444 double _fy = force * vec.
y / dist;
450 a_newLocation.
x = p0.x + fx;
451 a_newLocation.
y = p0.y + fy;
461 size_t nPts(points.size());
464 m_flags.assign(nPts, RELAX_RELAX);
469 for (
size_t i = 0; i < points.size(); ++i)
475 const VecInt& adjTris = adjTris2d[i];
476 size_t numTri = adjTris.size();
478 std::set<int> setPoints;
479 for (
size_t j = 0; j < numTri; ++j)
481 int idx = adjTris[j] * 3;
482 for (
int t = 0; t < 3; ++t)
485 int ptIdx = tris[idx + t];
488 setPoints.insert(tris[idx + t]);
491 setPoints.erase(static_cast<int>(i));
503 size_t nPts(points.size());
505 for (
size_t i = 0; i < points.size(); ++i)
520 Pt3d originalLocation =
m_tin->Points()[a_idx];
521 m_tin->Points()[a_idx] = a_newLocation;
522 const VecInt& adjTris =
m_tin->TrisAdjToPts()[a_idx];
524 for (
size_t i = 0; rval && i < adjTris.size(); ++i)
527 if (!
GT_EPS(
m_tin->TriangleArea(adjTris[i]), 0.0, FLT_EPSILON))
532 m_tin->Points()[a_idx] = originalLocation;
542 for (
size_t i = 0; i < a_tin->NumTriangles(); ++i)
544 if (a_tin->TriangleArea(static_cast<int>(i)) < 0.0)
641 VecInt2d& trisAdjToPts = tin->TrisAdjToPts();
644 tin->Points().reserve(5 * 5);
645 for (
size_t i = 0; i < 5; ++i)
647 for (
size_t j = 0; j < 5; ++j)
649 tin->Points().push_back(
Pt3d(j * 10.0, i * 10.0, static_cast<double>(j)));
658 int outPolyA[] = {0, 1, 2, 3, 4, 9, 14, 19, 24, 23, 22, 21, 20, 15, 10, 5};
662 relaxer->Relax(outPoly, tin);
663 const double kDelta = 1e-2;
664 VecPt3d& tinPts = tin->Points();
666 {0.00, 0.00, 0.00}, {10.00, 0.00, 1.00}, {20.00, 0.00, 2.00}, {30.00, 0.00, 3.00},
667 {40.00, 0.00, 4.00}, {0.00, 10.00, 0.00}, {11.10, 8.88, 1.00}, {20.02, 10.20, 2.00},
668 {29.94, 9.92, 3.00}, {40.00, 10.00, 4.00}, {0.00, 20.00, 0.00}, {9.33, 19.09, 1.00},
669 {20.68, 20.86, 2.00}, {31.15, 18.86, 3.00}, {40.00, 20.00, 4.00}, {0.00, 30.00, 0.00},
670 {9.94, 29.75, 1.00}, {18.83, 31.19, 2.00}, {29.14, 29.13, 3.00}, {40.00, 30.00, 4.00},
671 {0.00, 40.00, 0.00}, {10.00, 40.00, 1.00}, {20.00, 40.00, 2.00}, {30.00, 40.00, 3.00},
672 {40.00, 40.00, 4.00}};
693 VecPt3d points = {{-10, -10, 0}, {0, -10, 0}, {10, -10, 0}, {-10, 0, 0}, {0, 0, 0},
694 {10, 0, 0}, {-10, 10, 0}, {0, 10, 0}, {10, 10, 0}, {-5, 10, 0}};
695 VecInt tris = {0, 4, 3, 0, 1, 4, 1, 2, 4, 2, 5, 4, 3, 7, 9, 4, 8, 7, 4, 5, 8, 3, 9, 6, 3, 4, 7};
698 tin->Points() = points;
699 tin->Triangles() = tris;
700 tin->BuildTrisAdjToPts();
703 sizer->SetConstantSizeFunc(3.0);
711 VecDbl expectedPointSizes(points.size(), 3);
714 {1, 3, 4}, {0, 2, 4}, {1, 4, 5}, {0, 4, 6, 7, 9}, {0, 1, 2, 3, 5, 7, 8},
715 {2, 4, 8}, {3, 9}, {3, 4, 8, 9}, {4, 5, 7}, {3, 6, 7}};
734 VecPt3d points = {{-10, -10, 0}, {0, -10, 0}, {10, -10, 0}, {-10, 0, 0}, {0, 0, 0},
735 {10, 0, 0}, {-10, 10, 0}, {0, 10, 0}, {10, 10, 0}, {-5, 10, 0}};
736 VecInt tris = {0, 4, 3, 0, 1, 4, 1, 2, 4, 2, 5, 4, 4, 8, 7, 4, 5, 8, 3, 9, 6};
739 tin->Points() = points;
740 tin->Triangles() = tris;
741 tin->BuildTrisAdjToPts();
744 sizer->SetConstantSizeFunc(3.0);
752 VecDbl expectedPointSizes(points.size(), 3);
755 {1, 3, 4}, {0, 2, 4}, {1, 4, 5}, {0, 4, 6, 9}, {0, 1, 2, 3, 5, 7, 8},
756 {2, 4, 8}, {3, 9}, {4, 8}, {4, 5, 7}, {3, 6}};
775 VecPt3d points = {{-10, -10, 1}, {0, -10, 2}, {10, -10, 3}, {-10, 0, 4}, {8, 7, 5},
776 {10, 0, 6}, {-10, 10, 7}, {0, 10, 8}, {10, 10, 9}};
777 VecInt tris = {0, 4, 3, 0, 1, 4, 1, 2, 4, 2, 5, 4, 3, 4, 6, 4, 7, 6, 4, 5, 8, 4, 8, 7};
780 tin->Points() = points;
781 tin->Triangles() = tris;
782 tin->BuildTrisAdjToPts();
785 sizer->SetConstantSizeFunc(10.0);
793 Pt3d newloc, startPt(8, 7, 0), ptZero;
794 double startDist(
Mdist(0.0, 0.0, startPt.x, startPt.y));
796 double newDist(
Mdist(0.0, 0.0, newloc.
x, newloc.
y));
797 TS_ASSERT(newDist < startDist);
800 Pt3d expectedNewLoc(0.905, 0.542, 0);
804 tin->Points()[4] = newloc;
807 newDist =
Mdist(0.0, 0.0, newloc.
x, newloc.
y);
808 TS_ASSERT(newDist < startDist);
809 expectedNewLoc =
Pt3d(0.023, 0.016, 0);
812 tin->Points()[4] = newloc;
815 newDist =
Mdist(0.0, 0.0, newloc.
x, newloc.
y);
816 TS_ASSERT(newDist < startDist);
817 expectedNewLoc =
Pt3d(0, 0, 0);
837 VecPt3d points = {{-10, -10, 0}, {0, -10, 0}, {10, -10, 0}, {-10, 0, 0}, {8, 7, 0},
838 {15, 0, 0}, {-10, 10, 0}, {0, 10, 0}, {10, 10, 0}};
839 VecInt tris = {0, 4, 3, 0, 1, 4, 1, 2, 4, 2, 5, 4, 3, 4, 6, 4, 7, 6, 4, 5, 8, 4, 8, 7};
842 tin->Points() = points;
843 tin->Triangles() = tris;
844 tin->BuildTrisAdjToPts();
847 sizer->SetConstantSizeFunc(10.0);
856 Pt3d newloc, startPt(8, 7, 0), ptZero;
857 double startDist(
Mdist(0.0, 0.0, startPt.x, startPt.y));
859 double newDist(
Mdist(0.0, 0.0, newloc.
x, newloc.
y));
860 TS_ASSERT(newDist < startDist);
863 Pt3d expectedNewLoc(0.673, 0.377, 0);
867 tin->Points()[4] = newloc;
870 newDist =
Mdist(0.0, 0.0, newloc.
x, newloc.
y);
871 TS_ASSERT(newDist < startDist);
872 expectedNewLoc =
Pt3d(0.547, -0.005, 0);
876 tin->Points()[4] = newloc;
879 newDist =
Mdist(0.0, 0.0, newloc.
x, newloc.
y);
880 TS_ASSERT(newDist < startDist);
881 expectedNewLoc =
Pt3d(0.545, 0, 0);
905 VecPt3d points = {{-10, -10, 0}, {0, -10, 0}, {10, -10, 0}, {-10, 0, 0}, {8, 7, 0},
906 {10, 0, 0}, {-10, 10, 0}, {0, 10, 0}, {10, 10, 0}};
907 VecInt tris = {0, 1, 3, 1, 4, 3, 1, 5, 4, 1, 2, 5, 3, 4, 6, 4, 7, 6, 4, 5, 8, 4, 8, 7};
910 tin->Points() = points;
911 tin->Triangles() = tris;
912 tin->BuildTrisAdjToPts();
915 sizer->SetConstantSizeFunc(100.0);
923 Pt3d newloc, startPt(8, 7, 0), ptZero;
944 VecPt3d points = {{-10, -10, 0}, {0, -10, 0}, {10, -10, 0}, {-10, 0, 0}, {0, 0, 0},
945 {5, 0, 0}, {-10, 10, 0}, {0, 10, 0}, {10, 10, 0}};
946 VecInt tris = {0, 4, 3, 0, 1, 4, 1, 2, 4, 2, 5, 4, 4, 5, 7, 5, 8, 7, 3, 4, 7, 3, 7, 6};
949 tin->Points() = points;
950 tin->Triangles() = tris;
951 tin->BuildTrisAdjToPts();
954 sizer->SetConstantSizeFunc(3.0);
962 Pt3d newloc(-2, -2, 0), ptZero;
965 tin->Points()[4] = ptZero;
966 newloc =
Pt3d(-2, 2, 0);
969 tin->Points()[4] = ptZero;
970 newloc =
Pt3d(-7, 7, 0);
973 tin->Points()[4] = ptZero;
974 newloc =
Pt3d(7, 0, 0);
977 tin->Points()[4] = ptZero;
978 newloc =
Pt3d(5, 5, 0);
981 tin->Points()[4] = ptZero;
982 newloc =
Pt3d(-10, 0, 0);
985 tin->Points()[4] = ptZero;
986 newloc =
Pt3d(-11, 0, 0);
989 tin->Points()[4] = ptZero;
990 newloc =
Pt3d(-2, -11, 0);
1010 VecPt3d points = {{-10, -10, 0}, {0, -10, 0}, {10, -10, 0}, {-10, 0, 0}, {8, 7, 0},
1011 {10, 0, 0}, {-10, 10, 0}, {0, 10, 0}, {10, 10, 0}};
1012 VecInt tris = {0, 4, 3, 0, 1, 4, 1, 2, 4, 2, 5, 4, 3, 4, 6, 4, 7, 6, 4, 5, 8, 4, 8, 7};
1015 tin->Points() = points;
1016 tin->Triangles() = tris;
1017 tin->BuildTrisAdjToPts();
1024 tin->Triangles() = tris;
void SetupPointSizes()
Set up point sizes to be used by the spring relax algorithm.
bool AllTrianglesHavePositiveArea(BSHP< TrTin > a_tin)
Checks if all triangles have a positive area.
void testSpringRelaxSinglePoint2()
Tests the spring relax of a point. Uses the TIN below.
std::vector< int > VecInt
void SpringRelaxSinglePoint(int a_point, Pt3d &a_newLocation)
Relax a point using spring method.
bool GT_EPS(_T A, _U B, _V epsilon)
static BSHP< MePolyRedistributePts > New()
Creates an instance of this class.
double m_slideangle
Used on boundary relaxation. Not sure how to document this one.
void testRelaxWhileMeshing()
Tests the relaxation code as if we were creating a mesh.
int trIncrementIndex(int i)
#define XM_ENSURE_TRUE_VOID(...)
std::vector< double > VecDbl
RelaxTypeEnum
Types of relaxation, or the relaxation algorithms.
std::string stToLowerCopy(const std::string &str)
void RelaxMarkedPoints(RelaxTypeEnum a_relaxType, int a_iteration, int a_numiterations)
Relaxes the points marked by m_flags. Compare to rlRelaxMarkedNodes.
void testAllTrianglesHavePositiveArea()
Tests the spring relax of a point. Uses the TIN below.
RelaxTypeEnum m_relaxType
the type of relaxation to perform. See RelaxTypeEnum
void testSpringRelaxSetup2()
Tests the spring relax setup. Uses the TIN below. This tin has missing triangles compared to the prev...
static BSHP< MeRelaxer > New()
Creates a new instance of the class.
const VecInt * m_fixedPoints
locations that may not be relaxed
void testSpringRelaxSinglePoint3()
Tests the spring relax of a point. Uses the TIN below. We are relaxing point 4 and it has 3 connectio...
VecPt3d m_centroids
The triangle centroids.
BSHP< MePolyRedistributePts > m_sizer
size function used by the spring relax method
void SetupNeighbors()
Set up neighbor point information to be used by the spring relax algorithm.
int trDecrementIndex(int i)
virtual bool SetRelaxationMethod(const std::string &a_relaxMethod) override
Sets the relaxation method.
std::vector< VecInt > VecInt2d
static BSHP< TrTin > New()
virtual ~MeRelaxer()
Destructor.
void ComputeCentroids()
Computes the centroids of each triangle.
#define XM_ENSURE_TRUE_VOID_NO_ASSERT(...)
VecDbl m_pointSizes
sizer size at each mesh point
#define XM_DISALLOW_COPY_AND_ASSIGN(TypeName)
virtual void Relax(const VecInt &a_fixedPoints, BSHP< TrTin > a_tin) override
Moves interior mesh points to create a better mesh.
bool NewLocationIsValid(size_t a_idx, Pt3d &a_newLocation)
Checks if a new relaxed location results in valid triangle (area is positive)
virtual void SetPointSizer(BSHP< MePolyRedistributePts > a_sizer) override
Sets size function used by the spring relaxation method.
RelaxFlagEnum
Point flags.
void AngleRelax(int a_point, Pt3d &a_newLocation)
Relax a point using angles. Moves point to equalize the angles between the edges touching the point...
Pt3d gmCreateVector(const Pt3d &a_p1, const Pt3d &a_p2)
#define XM_COUNTOF(array)
void testNewLocationIsValid()
Tests that a new location for a point is within one of the triangles adjacent to that point's current...
Relaxes mesh points. Moves them around to form a better mesh.
VecInt2d m_pointNeighbors
neighbor points for spring relaxation
double Mdist(_T x1, _U y1, _V x2, _W y2)
BSHP< TrTin > m_tin
triangles connecting points (mesh elements)
VecInt m_pointsToDelete
indexes of points that must be removed
void testSpringRelaxSinglePoint()
Tests the spring relax of a point. Uses the TIN below.
VecInt m_flags
Flags for points of type RelaxFlagEnum.
void AreaRelax(int a_point, Pt3d &a_newLocation)
Relax a point using area of surrounding triangles. Trys to move point to the center of the area...
std::vector< Pt3d > VecPt3d
void testSpringRelaxSetup()
Tests the spring relax setup. Uses the TIN below.