xmsmesh  1.0
MeRelaxer.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
6 //------------------------------------------------------------------------------
7 
8 //----- Included files ---------------------------------------------------------
9 
10 // 1. Precompiled header
11 
12 // 2. My own header
14 
15 // 3. Standard library headers
16 #include <cfloat>
17 
18 // 4. External library headers
19 
20 // 5. Shared code headers
21 #include <xmscore/math/math.h>
23 #include <xmscore/misc/XmConst.h>
24 #include <xmscore/misc/XmError.h>
25 #include <xmscore/misc/carray.h>
26 #include <xmscore/misc/xmstype.h> // for XM_PI
27 #include <xmscore/points/pt.h>
28 #include <xmscore/stl/vector.h>
34 
35 // 6. Non-shared code headers
36 
37 //----- Forward declarations ---------------------------------------------------
38 
39 //----- External globals -------------------------------------------------------
40 
41 //----- Namespace declaration --------------------------------------------------
42 
43 namespace xms
44 {
45 //----- Constants / Enumerations -----------------------------------------------
46 
47 //----- Classes / Structs ------------------------------------------------------
48 
50 class MeRelaxerImpl : public MeRelaxer
51 {
52 public:
54  enum RelaxFlagEnum { RELAX_RELAX = 1 };
56  enum RelaxTypeEnum { RELAXTYPE_AREA, RELAXTYPE_ANGLE, RELAXTYPE_SPRING };
57 
58  MeRelaxerImpl();
59  virtual ~MeRelaxerImpl();
60 
61  // protected:
62  // MeRelaxerImpl(const MeRelaxerImpl&);
63 
65 
66  virtual void Relax(/*MeshPolyEnum a_meshPolyEnum,*/
67  const VecInt& a_fixedPoints,
68  BSHP<TrTin> a_tin) override;
69  virtual bool SetRelaxationMethod(const std::string& a_relaxMethod) override;
70  //------------------------------------------------------------------------------
73  //------------------------------------------------------------------------------
74  virtual void SetPointSizer(BSHP<MePolyRedistributePts> a_sizer) override { m_sizer = a_sizer; }
75 
76  void ComputeCentroids();
77  void RelaxMarkedPoints(RelaxTypeEnum a_relaxType, int a_iteration, int a_numiterations);
78  void AreaRelax(int a_point, Pt3d& a_newLocation);
79  void AngleRelax(int a_point, Pt3d& a_newLocation);
80  void SpringRelaxSinglePoint(int a_point, Pt3d& a_newLocation);
81  void SetupNeighbors();
82  void SetupPointSizes();
83  bool NewLocationIsValid(size_t a_idx, Pt3d& a_newLocation);
84  bool AllTrianglesHavePositiveArea(BSHP<TrTin> a_tin);
85 
86  BSHP<TrTin> m_tin;
89  double m_slideangle;
92  BSHP<MePolyRedistributePts> m_sizer;
96 }; // class MeRelaxerImpl
97 
102 //------------------------------------------------------------------------------
104 //------------------------------------------------------------------------------
105 MeRelaxerImpl::MeRelaxerImpl()
106 : m_tin()
107 /*, m_meshPolyEnum*/
108 , m_fixedPoints(nullptr)
109 , m_centroids()
110 , m_slideangle(5.0)
111 , m_flags()
112 , m_relaxType(RELAXTYPE_AREA)
113 , m_sizer()
114 , m_pointSizes()
115 , m_pointsToDelete()
116 {
117 } // MeRelaxerImpl::MeRelaxerImpl
118 //------------------------------------------------------------------------------
120 //------------------------------------------------------------------------------
121 MeRelaxerImpl::~MeRelaxerImpl()
122 {
123 } // MeRelaxerImpl::~MeRelaxerImpl
124 //------------------------------------------------------------------------------
133 //------------------------------------------------------------------------------
134 void MeRelaxerImpl::Relax(/*MeshPolyEnum a_meshPolyEnum,*/
135  const VecInt& a_fixedPoints,
136  BSHP<TrTin> a_tin)
137 {
139  XM_ENSURE_TRUE_VOID(!a_tin->TrisAdjToPts().empty());
141  // Set up member variables
143  // m_meshPolyEnum = a_meshPolyEnum;
144  m_tin = a_tin;
145  m_fixedPoints = &a_fixedPoints;
146 
147  // Mark fixed points to not be relaxed (breaklines)
148  m_flags.assign(m_tin->Points().size(), RELAX_RELAX);
149  for (size_t i = 0; i < a_fixedPoints.size(); ++i)
150  {
151  XM_ASSERT(a_fixedPoints[i] >= 0 && a_fixedPoints[i] < (int)m_flags.size());
152  m_flags[a_fixedPoints[i]] = 0;
153  }
154 
156 
157  // Set up iterations
158 #ifdef _DEBUG
159  VecPt3d& pts(m_tin->Points());
160 #endif
161  int numiterations(3); // default to 3 for area relaxation
162  RelaxTypeEnum relaxtype(m_relaxType);
163  if (relaxtype == RELAXTYPE_SPRING)
164  {
165  if (!m_sizer)
166  {
167  std::string msg =
168  "No size function specified with spring relaxation "
169  "method. Relaxation method has been set to AREA "
170  "relaxation.";
171  XM_LOG(xmlog::warning, msg);
172  relaxtype = RELAXTYPE_AREA;
173  }
174  else
175  {
176  if (m_pointSizes.empty())
177  {
178  SetupPointSizes();
179  }
180  SetupNeighbors();
181  XM_ASSERT(pts.size() == m_pointNeighbors.size());
182  XM_ASSERT(pts.size() == m_pointSizes.size());
183  }
184  }
185  XM_ASSERT(pts.size() == m_flags.size());
186 
187  int iteration = 0;
188 
189  // Perform relaxation and swap
190  for (int i = 0; i < numiterations; ++i)
191  {
192  ++iteration;
193  RelaxMarkedPoints(relaxtype, iteration, numiterations);
194  // delete points and triangles
195  if (!m_pointsToDelete.empty())
196  {
197  m_tin->Triangles().clear();
198  m_tin->TrisAdjToPts().clear();
199  VecPt3d& pts(m_tin->Points());
200  VecDbl& szs(m_pointSizes);
201  for (auto it = m_pointsToDelete.rbegin(); it != m_pointsToDelete.rend(); ++it)
202  {
203  int idx = *it;
204  pts[idx] = pts.back();
205  pts.pop_back();
206  szs[idx] = szs.back();
207  szs.pop_back();
208  m_flags[idx] = m_flags.back();
209  m_flags.pop_back();
210  }
211  m_pointsToDelete.clear();
212  break;
213  }
214  bool trianglesChanged(false);
215  trianglesChanged = m_tin->OptimizeTriangulation();
216 
217  if (trianglesChanged && RELAXTYPE_SPRING == relaxtype)
218  { // set up spring relax if the triangles have changed
219  SetupNeighbors();
220  }
221  }
222 
223 } // MeRelaxerImpl::Relax
224 //------------------------------------------------------------------------------
229 //------------------------------------------------------------------------------
230 bool MeRelaxerImpl::SetRelaxationMethod(const std::string& a_relaxType)
231 {
232  bool rval(false);
233  std::string type = stToLowerCopy(a_relaxType);
234  if (type == "spring_relaxation")
235  {
236  m_relaxType = RELAXTYPE_SPRING;
237  rval = true;
238  }
239  return rval;
240 } // MeRelaxerImpl::SetRelaxationMethod
241 //------------------------------------------------------------------------------
243 //------------------------------------------------------------------------------
245 {
246  size_t numTri = m_tin->NumTriangles();
247  m_centroids.assign(numTri, Pt3d());
248  for (size_t t = 0; t < numTri; ++t)
249  {
250  m_centroids[t] = m_tin->TriangleCentroid((int)t);
251  }
252 } // MeRelaxerImpl::ComputeCentroids
253 //------------------------------------------------------------------------------
258 //------------------------------------------------------------------------------
260  int a_iteration,
261  int a_numiterations)
262 {
263  XM_ASSERT(a_iteration > 0 && a_numiterations > 0 && a_iteration <= a_numiterations);
264 
265  // Relax the marked nodes
266  VecPt3d& points = m_tin->Points(); // for convenience
267  size_t nPoints = points.size();
268  Pt3d origlocation, newlocation;
269  for (size_t p = 0; p < nPoints; ++p)
270  {
271  if (m_flags[p])
272  {
273  origlocation = points[p];
274  // do general point relax
275  switch (a_relaxType)
276  {
277  case RELAXTYPE_AREA:
278  AreaRelax((int)p, newlocation);
279  break;
280  case RELAXTYPE_ANGLE:
281  AngleRelax((int)p, newlocation);
282  break;
283  case RELAXTYPE_SPRING:
284  SpringRelaxSinglePoint((int)p, newlocation);
285  break;
286  default:
287  XM_ASSERT(false);
288  break;
289  }
290  // preserve the elevation
291  newlocation.z = origlocation.z;
292 
293  // Change the points location and check for bad triangles
294  if (NewLocationIsValid(p, newlocation))
295  {
296  points[p] = newlocation;
297  if (m_sizer)
298  {
299  // point moved and we must update its target size when doing
300  // spring_relax
301  m_pointSizes[p] = m_sizer->SizeFromLocation(points[p]);
302  }
303  }
304  else if (RELAXTYPE_SPRING == a_relaxType)
305  { // mark point for deletion
306  m_pointsToDelete.push_back(static_cast<int>(p));
307  }
308 
309  } // if (m_flags[p])
310 
311  } // for (int p = 0; p < nPoints; ++p)
312 } // MeRelaxerImpl::RelaxMarkedPoints
313 //------------------------------------------------------------------------------
318 //------------------------------------------------------------------------------
319 void MeRelaxerImpl::AreaRelax(int a_point, Pt3d& a_newLocation)
320 {
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)
324  {
325  area = m_tin->TriangleArea(adjTris[i]);
326  sumx += area * m_centroids[adjTris[i]].x;
327  sumy += area * m_centroids[adjTris[i]].y;
328  sumarea += area;
329  }
330 
331  a_newLocation.x = sumx / sumarea;
332  a_newLocation.y = sumy / sumarea;
333 } // MeRelaxerImpl::AreaRelax
334 //------------------------------------------------------------------------------
339 //------------------------------------------------------------------------------
340 void MeRelaxerImpl::AngleRelax(int a_point, Pt3d& a_newLocation)
341 {
342  int id;
343  double targetangle, mag, a, c, d;
344  double da, db, dx, dy, sx, sy, radius;
345  Pt2d sum, pt, p1, p2, p3, centroid;
346  int point1, point2;
347 
348  // get the target angle
349  const VecInt& adjTris = m_tin->TrisAdjToPts()[a_point];
350  VecPt3d& points = m_tin->Points();
351  size_t num = adjTris.size();
352  XM_ASSERT(num > 0);
353 
354  targetangle = 2.0 * XM_PI / (double)num;
355  // loop through adjacent elems and find the
356  // circle with the two adjacent points and
357  // the new point
358  sum.x = sum.y = 0.0;
359  for (size_t i = 0; i < adjTris.size(); ++i)
360  {
361  int tri = adjTris[i];
362  id = m_tin->LocalIndex(tri, a_point);
363  point1 = m_tin->GlobalIndex(tri, trIncrementIndex(id));
364  point2 = m_tin->GlobalIndex(tri, trDecrementIndex(id));
365  // set up points
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;
372  // find length of line bisecting p1 and p2
373  dx = p1.x - p2.x;
374  dy = p1.y - p2.y;
375  c = sqrt(sqr(dx) + sqr(dy));
376  sx = p1.x + dx / 2.0;
377  sy = p1.y + dy / 2.0;
378  // compute length of triangle sides
379  a = (c / 2.0) / sin(targetangle / 2.0);
380  d = a * cos(targetangle / 2.0);
381  radius = (a * a) / (2.0 * d);
382  // find candidate point p3 and circle centroid
383  dx /= c;
384  dy /= c;
385  p3.x = sx + d * dy;
386  p3.y = sy - d * dx;
387  da = sqr(p3.x - pt.x) + sqr(p3.y - pt.y);
388  p3.x = sx - d * dy;
389  p3.y = sy + d * dx;
390  db = sqr(p3.x - pt.x) + sqr(p3.y - pt.y);
391  if (da < db)
392  {
393  centroid.x = sx + (d - radius) * dy;
394  centroid.y = sy - (d - radius) * dx;
395  }
396  else
397  {
398  centroid.x = sx - (d - radius) * dy;
399  centroid.y = sy + (d - radius) * dx;
400  }
401  // find p3 along circle, radius away from centroid
402  dx = pt.x - centroid.x;
403  dy = pt.y - centroid.y;
404  mag = sqrt(dx * dx + dy * dy);
405  dx /= mag;
406  dy /= mag;
407  // find new point
408  p3.x = centroid.x + radius * dx;
409  p3.y = centroid.y + radius * dy;
410  // sum new point's x and y
411  sum.x += p3.x;
412  sum.y += p3.y;
413  }
414  a_newLocation.x = (sum.x / (double)num);
415  a_newLocation.y = (sum.y / (double)num);
416 } // MeRelaxerImpl::AngleRelax
417 //------------------------------------------------------------------------------
422 //------------------------------------------------------------------------------
423 void MeRelaxerImpl::SpringRelaxSinglePoint(int a_point, Pt3d& a_newLocation)
424 {
425  double fx(0.0);
426  double fy(0.0);
427 
428  double springStiffness(1.0);
429  VecPt3d& points = m_tin->Points();
430  VecInt& neighbors(m_pointNeighbors[a_point]);
431  double numPtsFactor(1.7 / (double)neighbors.size());
432  Pt3d& p0(points[a_point]);
433  double size0(m_pointSizes[a_point]);
434  for (size_t i = 0; i < neighbors.size(); ++i)
435  {
436  int neighborIdx = neighbors[i];
437  Pt3d& p1(points[neighborIdx]);
438  double size1(m_pointSizes[neighborIdx]);
439  Pt3d vec = gmCreateVector(p0, p1);
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;
445  fx += _fx;
446  fy += _fy;
447  }
448  fx *= numPtsFactor;
449  fy *= numPtsFactor;
450  a_newLocation.x = p0.x + fx;
451  a_newLocation.y = p0.y + fy;
452 } // MeRelaxerImpl::SpringRelax
453 //------------------------------------------------------------------------------
456 //------------------------------------------------------------------------------
458 {
459  m_pointNeighbors.clear();
460  VecPt3d& points = m_tin->Points();
461  size_t nPts(points.size());
462  if (m_flags.empty())
463  {
464  m_flags.assign(nPts, RELAX_RELAX);
465  }
466  m_pointNeighbors.assign(nPts, VecInt());
467  VecInt& tris = m_tin->Triangles();
468  VecInt2d& adjTris2d = m_tin->TrisAdjToPts();
469  for (size_t i = 0; i < points.size(); ++i)
470  {
471  if (m_flags[i] == 0) // We don't relax fixed points, so we don't need its neighbors.
472  {
473  continue;
474  }
475  const VecInt& adjTris = adjTris2d[i];
476  size_t numTri = adjTris.size();
477  // find the other points that make up the edges that a_point is connected to
478  std::set<int> setPoints;
479  for (size_t j = 0; j < numTri; ++j)
480  {
481  int idx = adjTris[j] * 3;
482  for (int t = 0; t < 3; ++t)
483  {
484 #ifdef _DEBUG
485  int ptIdx = tris[idx + t];
486 #endif
487  XM_ASSERT(ptIdx < nPts);
488  setPoints.insert(tris[idx + t]);
489  }
490  }
491  setPoints.erase(static_cast<int>(i));
492  m_pointNeighbors[i] = VecInt(setPoints.begin(), setPoints.end());
493  }
494 } // MeRelaxerImpl::SetupNeighbors()
495 //------------------------------------------------------------------------------
498 //------------------------------------------------------------------------------
500 {
501  m_pointSizes.clear();
502  VecPt3d& points = m_tin->Points();
503  size_t nPts(points.size());
504  m_pointSizes.reserve(nPts);
505  for (size_t i = 0; i < points.size(); ++i)
506  {
507  // compute point sizes prior to relaxing below
508  Pt3d& p(m_tin->Points()[i]);
509  m_pointSizes.push_back(m_sizer->SizeFromLocation(p));
510  }
511 } // MeRelaxerImpl::SetupPointSizes
512 //------------------------------------------------------------------------------
517 //------------------------------------------------------------------------------
518 bool MeRelaxerImpl::NewLocationIsValid(size_t a_idx, Pt3d& a_newLocation)
519 {
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];
523  bool rval(true);
524  for (size_t i = 0; rval && i < adjTris.size(); ++i)
525  {
526  // Is triangle ill-formed? See that it has some area
527  if (!GT_EPS(m_tin->TriangleArea(adjTris[i]), 0.0, FLT_EPSILON))
528  {
529  rval = false;
530  }
531  }
532  m_tin->Points()[a_idx] = originalLocation;
533  return rval;
534 } // MeRelaxerImpl::NewLocationIsValid
535 //------------------------------------------------------------------------------
539 //------------------------------------------------------------------------------
541 {
542  for (size_t i = 0; i < a_tin->NumTriangles(); ++i)
543  {
544  if (a_tin->TriangleArea(static_cast<int>(i)) < 0.0)
545  return false;
546  }
547  return true;
548 } // MeRelaxerImpl::AllTrianglesHavePositiveArea
549 
555 //------------------------------------------------------------------------------
558 //------------------------------------------------------------------------------
559 BSHP<MeRelaxer> MeRelaxer::New()
560 {
561  BSHP<MeRelaxer> polyMesher(new MeRelaxerImpl);
562  // MeRelaxerImpl->SetBSHP(polyMesher); // If MeRelaxerImpl needs ptr to
563  // MeRelaxer
564  return polyMesher;
565 } // MeRelaxer::New
566 //------------------------------------------------------------------------------
568 //------------------------------------------------------------------------------
570 {
571 } // MeRelaxer::MeRelaxer
572 //------------------------------------------------------------------------------
574 //------------------------------------------------------------------------------
576 {
577 } // MeRelaxer::~MeRelaxer
578 
579 } // namespace xms
580 
581 #if CXX_TEST
582 // UNIT TESTS
585 
587 
590 
591 //----- Namespace declaration --------------------------------------------------
592 
593 // namespace xms {
594 using namespace xms;
595 
600 //------------------------------------------------------------------------------
603 // 40- 20-----21-----22-----23-----24
604 // | |\2 1|\2 1|\0 2|\1 0|
605 // | |0\ 12 |1\ 26 |2\ 25 |1\ 28 |
606 // | | \ | \ | \ | \ |
607 // | | 8 \ | \ | \ | \ |
608 // | | \0| 11 \0| 23 \1| 27 \2|
609 // | |1 2\|2 0\|0 1\|2 0\|
610 // 30- 15-----16-----17-----18-----19
611 // | |\2 1|\2 1|0 2/|\1 0|
612 // | |0\ |1\ 31 | 24 /2|2\ 29 |
613 // | | \ 9 | \ | / | \ |
614 // | | 7 \ | \ | / | \ |
615 // | | \0| 10 \0|1/ 22 | 30 \2|
616 // | |1 2\|2 0\|/0 1|0 1\|
617 // 20- 10-----11-----12-----13-----14
618 // | |0 2/|\1 0|\0 2|\0 2|
619 // | | 13 /2|2\ 14 |2\ 18 |2\ 21 |
620 // | | / | \ | \ | \ |
621 // | | / 6 | 5 \ | \ | \ |
622 // | |1/ | \2| 15 \1| 19 \1|
623 // | |/0 1|0 1\|0 1\|0 1\|
624 // 10- 5------6------7------8------9
625 // | |\0 2|\0 2|\1 0|\1 0|
626 // | |2\ |1\ |0\ 16 |0\ 20 |
627 // | | \ 1 | \ 2 | \ | \ |
628 // | | 0 \ | 3 \ | 4 \ | \ |
629 // | | \1| \1| \2| 17 \2|
630 // | |0 1\|2 0\|1 2\|1 2\|
631 // 0 - 0------1------2------3------4
632 //
633 // |------|------|------|------|
634 // 0 10 20 30 40
636 //------------------------------------------------------------------------------
638 {
639  // Create tin and get some convenience variables
640  BSHP<TrTin> tin = TrTin::New();
641  VecInt2d& trisAdjToPts = tin->TrisAdjToPts();
642 
643  // Set up to our example tin points
644  tin->Points().reserve(5 * 5);
645  for (size_t i = 0; i < 5; ++i)
646  {
647  for (size_t j = 0; j < 5; ++j)
648  {
649  tin->Points().push_back(Pt3d(j * 10.0, i * 10.0, static_cast<double>(j)));
650  }
651  }
652 
653  // Triangulate the points
654  TrTriangulatorPoints client(tin->Points(), tin->Triangles(), &trisAdjToPts);
655  client.Triangulate();
656 
657  // Set up fixed points (outer boundary)
658  int outPolyA[] = {0, 1, 2, 3, 4, 9, 14, 19, 24, 23, 22, 21, 20, 15, 10, 5};
659  VecInt outPoly(&outPolyA[0], &outPolyA[XM_COUNTOF(outPolyA)]);
660 
661  BSHP<MeRelaxer> relaxer = MeRelaxer::New();
662  relaxer->Relax(outPoly, tin);
663  const double kDelta = 1e-2;
664  VecPt3d& tinPts = tin->Points();
665  VecPt3d expectedPts{
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}};
673 
674  TS_ASSERT_DELTA_VECPT3D(expectedPts, tinPts, kDelta);
675 
676 } // MeRelaxerUnitTests::testRelaxWhileMeshing
677 //------------------------------------------------------------------------------
690 //------------------------------------------------------------------------------
692 {
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};
696  // create a test tin
697  BSHP<TrTin> tin = TrTin::New();
698  tin->Points() = points;
699  tin->Triangles() = tris;
700  tin->BuildTrisAdjToPts();
701  // create a sizer that returns a constant value
702  BSHP<MePolyRedistributePts> sizer = MePolyRedistributePts::New();
703  sizer->SetConstantSizeFunc(3.0);
704 
705  MeRelaxerImpl r;
706  r.m_tin = tin;
707  r.m_sizer = sizer;
708  r.SetupPointSizes();
709  r.SetupNeighbors();
710 
711  VecDbl expectedPointSizes(points.size(), 3);
712  TS_ASSERT_EQUALS_VEC(expectedPointSizes, r.m_pointSizes);
713  VecInt2d expectedPointNeighbors = {
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}};
716  TS_ASSERT_EQUALS_VEC2D(expectedPointNeighbors, r.m_pointNeighbors);
717 } // MeRelaxerUnitTests::testSpringRelaxSetup
718 //------------------------------------------------------------------------------
731 //------------------------------------------------------------------------------
733 {
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};
737  // create a test tin
738  BSHP<TrTin> tin = TrTin::New();
739  tin->Points() = points;
740  tin->Triangles() = tris;
741  tin->BuildTrisAdjToPts();
742  // create a sizer that returns a constant value
743  BSHP<MePolyRedistributePts> sizer = MePolyRedistributePts::New();
744  sizer->SetConstantSizeFunc(3.0);
745 
746  MeRelaxerImpl r;
747  r.m_tin = tin;
748  r.m_sizer = sizer;
749  r.SetupPointSizes();
750  r.SetupNeighbors();
751 
752  VecDbl expectedPointSizes(points.size(), 3);
753  TS_ASSERT_EQUALS_VEC(expectedPointSizes, r.m_pointSizes);
754  VecInt2d expectedPointNeighbors = {
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}};
757  TS_ASSERT_EQUALS_VEC2D(expectedPointNeighbors, r.m_pointNeighbors);
758 } // MeRelaxerUnitTests::testSpringRelaxSetup
759 //------------------------------------------------------------------------------
772 //------------------------------------------------------------------------------
774 {
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};
778  // create a test tin
779  BSHP<TrTin> tin = TrTin::New();
780  tin->Points() = points;
781  tin->Triangles() = tris;
782  tin->BuildTrisAdjToPts();
783  // create a sizer that returns a constant value
784  BSHP<MePolyRedistributePts> sizer = MePolyRedistributePts::New();
785  sizer->SetConstantSizeFunc(10.0);
786 
787  MeRelaxerImpl r;
788  r.m_tin = tin;
789  r.m_sizer = sizer;
790  r.SetupPointSizes();
791  r.SetupNeighbors();
792 
793  Pt3d newloc, startPt(8, 7, 0), ptZero;
794  double startDist(Mdist(0.0, 0.0, startPt.x, startPt.y));
795  r.SpringRelaxSinglePoint(4, newloc);
796  double newDist(Mdist(0.0, 0.0, newloc.x, newloc.y));
797  TS_ASSERT(newDist < startDist);
798  TS_ASSERT(r.NewLocationIsValid(4, newloc));
799 
800  Pt3d expectedNewLoc(0.905, 0.542, 0);
801  TS_ASSERT_DELTA_PT3D(expectedNewLoc, newloc, 1e-2);
802  TS_ASSERT(r.NewLocationIsValid(4, newloc));
803 
804  tin->Points()[4] = newloc;
805  startDist = newDist;
806  r.SpringRelaxSinglePoint(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);
810  TS_ASSERT_DELTA_PT3D(expectedNewLoc, newloc, 1e-2);
811 
812  tin->Points()[4] = newloc;
813  startDist = newDist;
814  r.SpringRelaxSinglePoint(4, newloc);
815  newDist = Mdist(0.0, 0.0, newloc.x, newloc.y);
816  TS_ASSERT(newDist < startDist);
817  expectedNewLoc = Pt3d(0, 0, 0);
818  TS_ASSERT_DELTA_PT3D(expectedNewLoc, newloc, 1e-2);
819  TS_ASSERT(r.NewLocationIsValid(4, newloc));
820 } // MeRelaxerUnitTests::testSpringRelaxSinglePoint
821 //------------------------------------------------------------------------------
834 //------------------------------------------------------------------------------
836 {
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};
840  // create a test tin
841  BSHP<TrTin> tin = TrTin::New();
842  tin->Points() = points;
843  tin->Triangles() = tris;
844  tin->BuildTrisAdjToPts();
845  // create a sizer that returns a constant value
846  BSHP<MePolyRedistributePts> sizer = MePolyRedistributePts::New();
847  sizer->SetConstantSizeFunc(10.0);
848 
849  MeRelaxerImpl r;
850  r.m_tin = tin;
851  r.m_sizer = sizer;
852  r.SetupPointSizes();
853  r.SetupNeighbors();
854  r.m_pointSizes[5] = 15;
855 
856  Pt3d newloc, startPt(8, 7, 0), ptZero;
857  double startDist(Mdist(0.0, 0.0, startPt.x, startPt.y));
858  r.SpringRelaxSinglePoint(4, newloc);
859  double newDist(Mdist(0.0, 0.0, newloc.x, newloc.y));
860  TS_ASSERT(newDist < startDist);
861  TS_ASSERT(r.NewLocationIsValid(4, newloc));
862 
863  Pt3d expectedNewLoc(0.673, 0.377, 0);
864  TS_ASSERT_DELTA_PT3D(expectedNewLoc, newloc, 1e-2);
865  TS_ASSERT(r.NewLocationIsValid(4, newloc));
866 
867  tin->Points()[4] = newloc;
868  startDist = newDist;
869  r.SpringRelaxSinglePoint(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);
873  TS_ASSERT_DELTA_PT3D(expectedNewLoc, newloc, 1e-2);
874  TS_ASSERT(r.NewLocationIsValid(4, newloc));
875 
876  tin->Points()[4] = newloc;
877  startDist = newDist;
878  r.SpringRelaxSinglePoint(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);
882  TS_ASSERT_DELTA_PT3D(expectedNewLoc, newloc, 1e-2);
883  TS_ASSERT(r.NewLocationIsValid(4, newloc));
884 
885 } // MeRelaxerUnitTests::testSpringRelaxSinglePoint2
886 //------------------------------------------------------------------------------
902 //------------------------------------------------------------------------------
904 {
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};
908  // create a test tin
909  BSHP<TrTin> tin = TrTin::New();
910  tin->Points() = points;
911  tin->Triangles() = tris;
912  tin->BuildTrisAdjToPts();
913  // create a sizer that returns a constant value
914  BSHP<MePolyRedistributePts> sizer = MePolyRedistributePts::New();
915  sizer->SetConstantSizeFunc(100.0);
916 
917  MeRelaxerImpl r;
918  r.m_tin = tin;
919  r.m_sizer = sizer;
920  r.SetupPointSizes();
921  r.SetupNeighbors();
922 
923  Pt3d newloc, startPt(8, 7, 0), ptZero;
924  r.SpringRelaxSinglePoint(4, newloc);
925  TS_ASSERT(!r.NewLocationIsValid(4, newloc));
926 } // MeRelaxerUnitTests::testSpringRelaxSinglePoint3
927 //------------------------------------------------------------------------------
941 //------------------------------------------------------------------------------
943 {
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};
947  // create a test tin
948  BSHP<TrTin> tin = TrTin::New();
949  tin->Points() = points;
950  tin->Triangles() = tris;
951  tin->BuildTrisAdjToPts();
952  // create a sizer that returns a constant value
953  BSHP<MePolyRedistributePts> sizer = MePolyRedistributePts::New();
954  sizer->SetConstantSizeFunc(3.0);
955 
956  MeRelaxerImpl r;
957  r.m_tin = tin;
958  r.m_sizer = sizer;
959  r.SetupPointSizes();
960  r.SetupNeighbors();
961 
962  Pt3d newloc(-2, -2, 0), ptZero;
963  TS_ASSERT(r.NewLocationIsValid(4, newloc));
964 
965  tin->Points()[4] = ptZero;
966  newloc = Pt3d(-2, 2, 0);
967  TS_ASSERT(r.NewLocationIsValid(4, newloc));
968 
969  tin->Points()[4] = ptZero;
970  newloc = Pt3d(-7, 7, 0);
971  TS_ASSERT(!r.NewLocationIsValid(4, newloc));
972 
973  tin->Points()[4] = ptZero;
974  newloc = Pt3d(7, 0, 0);
975  TS_ASSERT(!r.NewLocationIsValid(4, newloc));
976 
977  tin->Points()[4] = ptZero;
978  newloc = Pt3d(5, 5, 0);
979  TS_ASSERT(!r.NewLocationIsValid(4, newloc));
980 
981  tin->Points()[4] = ptZero;
982  newloc = Pt3d(-10, 0, 0);
983  TS_ASSERT(!r.NewLocationIsValid(4, newloc));
984 
985  tin->Points()[4] = ptZero;
986  newloc = Pt3d(-11, 0, 0);
987  TS_ASSERT(!r.NewLocationIsValid(4, newloc));
988 
989  tin->Points()[4] = ptZero;
990  newloc = Pt3d(-2, -11, 0);
991  TS_ASSERT(!r.NewLocationIsValid(4, newloc));
992 
993 } // MeRelaxerUnitTests::testNewLocationIsValid
994 //------------------------------------------------------------------------------
1007 //------------------------------------------------------------------------------
1009 {
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};
1013  // create a test tin
1014  BSHP<TrTin> tin = TrTin::New();
1015  tin->Points() = points;
1016  tin->Triangles() = tris;
1017  tin->BuildTrisAdjToPts();
1018 
1019  MeRelaxerImpl r;
1020  TS_ASSERT(r.AllTrianglesHavePositiveArea(tin));
1021  // create an invalid triangle
1022  tris[1] = 3;
1023  tris[2] = 4;
1024  tin->Triangles() = tris;
1025  TS_ASSERT(!r.AllTrianglesHavePositiveArea(tin));
1026 } // MeRelaxerUnitTests::testAllTrianglesHavePositiveArea
1027 
1028 //} // namespace xms
1029 #endif // CXX_TEST
void SetupPointSizes()
Set up point sizes to be used by the spring relax algorithm.
Definition: MeRelaxer.cpp:499
#define TS_ASSERT_DELTA_PT3D(a, b, delta)
#define XM_LOG(A, B)
bool AllTrianglesHavePositiveArea(BSHP< TrTin > a_tin)
Checks if all triangles have a positive area.
Definition: MeRelaxer.cpp:540
void testSpringRelaxSinglePoint2()
Tests the spring relax of a point. Uses the TIN below.
Definition: MeRelaxer.cpp:835
std::vector< int > VecInt
void SpringRelaxSinglePoint(int a_point, Pt3d &a_newLocation)
Relax a point using spring method.
Definition: MeRelaxer.cpp:423
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.
Definition: MeRelaxer.cpp:89
void testRelaxWhileMeshing()
Tests the relaxation code as if we were creating a mesh.
Definition: MeRelaxer.cpp:637
int trIncrementIndex(int i)
#define XM_ENSURE_TRUE_VOID(...)
std::vector< double > VecDbl
#define TS_ASSERT_DELTA_VECPT3D(a, b, delta)
RelaxTypeEnum
Types of relaxation, or the relaxation algorithms.
Definition: MeRelaxer.cpp:56
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.
Definition: MeRelaxer.cpp:259
void testAllTrianglesHavePositiveArea()
Tests the spring relax of a point. Uses the TIN below.
Definition: MeRelaxer.cpp:1008
RelaxTypeEnum m_relaxType
the type of relaxation to perform. See RelaxTypeEnum
Definition: MeRelaxer.cpp:91
void testSpringRelaxSetup2()
Tests the spring relax setup. Uses the TIN below. This tin has missing triangles compared to the prev...
Definition: MeRelaxer.cpp:732
static BSHP< MeRelaxer > New()
Creates a new instance of the class.
Definition: MeRelaxer.cpp:559
const VecInt * m_fixedPoints
locations that may not be relaxed
Definition: MeRelaxer.cpp:87
void testSpringRelaxSinglePoint3()
Tests the spring relax of a point. Uses the TIN below. We are relaxing point 4 and it has 3 connectio...
Definition: MeRelaxer.cpp:903
VecPt3d m_centroids
The triangle centroids.
Definition: MeRelaxer.cpp:88
MeRelaxer()
Constructor.
Definition: MeRelaxer.cpp:569
BSHP< MePolyRedistributePts > m_sizer
size function used by the spring relax method
Definition: MeRelaxer.cpp:92
void SetupNeighbors()
Set up neighbor point information to be used by the spring relax algorithm.
Definition: MeRelaxer.cpp:457
int trDecrementIndex(int i)
virtual bool SetRelaxationMethod(const std::string &a_relaxMethod) override
Sets the relaxation method.
Definition: MeRelaxer.cpp:230
std::vector< VecInt > VecInt2d
static BSHP< TrTin > New()
virtual ~MeRelaxer()
Destructor.
Definition: MeRelaxer.cpp:575
void ComputeCentroids()
Computes the centroids of each triangle.
Definition: MeRelaxer.cpp:244
#define XM_ENSURE_TRUE_VOID_NO_ASSERT(...)
_T sqr(const _T x)
VecDbl m_pointSizes
sizer size at each mesh point
Definition: MeRelaxer.cpp:93
#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.
Definition: MeRelaxer.cpp:134
#define XM_ASSERT(x)
bool NewLocationIsValid(size_t a_idx, Pt3d &a_newLocation)
Checks if a new relaxed location results in valid triangle (area is positive)
Definition: MeRelaxer.cpp:518
virtual void SetPointSizer(BSHP< MePolyRedistributePts > a_sizer) override
Sets size function used by the spring relaxation method.
Definition: MeRelaxer.cpp:74
RelaxFlagEnum
Point flags.
Definition: MeRelaxer.cpp:54
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...
Definition: MeRelaxer.cpp:340
Pt3d gmCreateVector(const Pt3d &a_p1, const Pt3d &a_p2)
#define XM_PI
#define XM_COUNTOF(array)
void testNewLocationIsValid()
Tests that a new location for a point is within one of the triangles adjacent to that point&#39;s current...
Definition: MeRelaxer.cpp:942
Relaxes mesh points. Moves them around to form a better mesh.
Definition: MeRelaxer.cpp:50
VecInt2d m_pointNeighbors
neighbor points for spring relaxation
Definition: MeRelaxer.cpp:94
double Mdist(_T x1, _U y1, _V x2, _W y2)
BSHP< TrTin > m_tin
triangles connecting points (mesh elements)
Definition: MeRelaxer.cpp:86
VecInt m_pointsToDelete
indexes of points that must be removed
Definition: MeRelaxer.cpp:95
void testSpringRelaxSinglePoint()
Tests the spring relax of a point. Uses the TIN below.
Definition: MeRelaxer.cpp:773
VecInt m_flags
Flags for points of type RelaxFlagEnum.
Definition: MeRelaxer.cpp:90
#define TS_ASSERT_EQUALS_VEC(a, b)
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...
Definition: MeRelaxer.cpp:319
Relaxes mesh points.
Definition: MeRelaxer.h:31
#define TS_ASSERT_EQUALS_VEC2D(expected, actual)
std::vector< Pt3d > VecPt3d
void testSpringRelaxSetup()
Tests the spring relax setup. Uses the TIN below.
Definition: MeRelaxer.cpp:691