QUAOAR STUDIO // Mobius API
poly_Mesh.h
1 //-----------------------------------------------------------------------------
2 // Created on: 17 September 2018
3 //-----------------------------------------------------------------------------
4 // Copyright (c) 2013-present, Sergey Slyadnev
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 // * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // * Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
15 // * Neither the name of Sergey Slyadnev nor the
16 // names of all contributors may be used to endorse or promote products
17 // derived from this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 // DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
23 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //-----------------------------------------------------------------------------
30 
31 #ifndef poly_Mesh_HeaderFile
32 #define poly_Mesh_HeaderFile
33 
34 // Poly includes
35 #include <mobius/poly_Edge.h>
36 #include <mobius/poly_Jacobian.h>
37 #include <mobius/poly_Quad.h>
38 #include <mobius/poly_SurfAdapter.h>
39 #include <mobius/poly_Triangle.h>
40 #include <mobius/poly_Vertex.h>
41 
42 // Core includes
43 #include <mobius/core_IAlgorithm.h>
44 #include <mobius/core_Precision.h>
45 
46 // Geom includes
47 #include <mobius/geom_PlaneSurface.h>
48 
49 // Standard includes
50 #include <math.h>
51 #include <stack>
52 #include <unordered_map>
53 #include <unordered_set>
54 #include <map>
55 
56 namespace mobius {
57 
58 class geom_PlaneSurface;
59 
64 {
65 public:
66 
72  mobiusPoly_EXPORT static void
73  ComputeCenter(const t_xyz& v0,
74  const t_xyz& v1,
75  const t_xyz& v2,
76  t_xyz& center);
77 
85  mobiusPoly_EXPORT static bool
86  ComputeNormal(const t_xyz& v0,
87  const t_xyz& v1,
88  const t_xyz& v2,
89  t_xyz& norm);
90 
96  mobiusPoly_EXPORT static double
97  ComputeArea(const t_xyz& v0,
98  const t_xyz& v1,
99  const t_xyz& v2);
100 
103  mobiusPoly_EXPORT static bool
104  ComputePyramidProps(const t_xyz& v0,
105  const t_xyz& v1,
106  const t_xyz& v2,
107  const core_XYZ& apex,
108  double gProps[10],
109  const int nbPnts,
110  const double* pnts);
111 
112 private:
113 
114  poly_MeshUtils() = delete;
115  poly_MeshUtils(const poly_MeshUtils&) = delete;
116  void operator=(const poly_MeshUtils&) = delete;
117 
118 };
119 
125 template <typename ElemTraits = poly_Traits>
127 {
128 public:
129 
138  };
139 
141  typedef std::map< poly_TriangleHandle, std::unordered_set<poly_TriangleHandle> > t_adjacencyMx;
142 
143 // Construction & destruction:
144 public:
145 
147  poly_Mesh(core_ProgressEntry progress = nullptr,
148  core_PlotterEntry plotter = nullptr)
149  //
150  : core_IAlgorithm(progress, plotter)
151  {}
152 
153 public:
154 
157  t_ptr<poly_Mesh<>> DeepCopyWithoutTraits()
158  {
159  t_ptr<poly_Mesh<>> copy = new poly_Mesh<>;
160  //
161  copy->__vertices = this->__vertices;
162  copy->__edges = this->__edges;
163  copy->__quads = this->__quads;
164  copy->__links = this->__links;
165  copy->__surfAdt = this->__surfAdt;
166 
167  for ( const auto& tt : this->__triangles )
168  {
170 
171  copy->__triangles.push_back(t);
172  }
173 
174  return copy;
175  }
176 
179  t_ptr<poly_Mesh> DeepCopy() const
180  {
181  t_ptr<poly_Mesh> copy = new poly_Mesh;
182  //
183  copy->__vertices = this->__vertices;
184  copy->__edges = this->__edges;
185  copy->__triangles = this->__triangles;
186  copy->__quads = this->__quads;
187  copy->__links = this->__links;
188  copy->__surfAdt = this->__surfAdt;
189 
190  return copy;
191  }
192 
199  t_ptr< poly_Mesh<ElemTraits> >
200  ExtractRegion(const std::unordered_set<int>& tids) const
201  {
202  t_ptr< poly_Mesh<ElemTraits> > region = new poly_Mesh<ElemTraits>;
203 
204  // keep matching of original vertex handles and their copies
205  // to avoid vertex handles duplication in the region
206  std::unordered_map<poly_VertexHandle, poly_VertexHandle> ovh2rvh;
207 
208  for ( TriangleIterator tit(this); tit.More(); tit.Next() )
209  {
210  if ( tids.find(tit.Current().iIdx) == tids.end() )
211  continue;
212 
214  this->GetTriangle(tit.Current(), t);
215 
216  poly_VertexHandle hv0;
217  poly_VertexHandle hv1;
218  poly_VertexHandle hv2;
219  t.GetVertices(hv0, hv1, hv2);
220 
221  // Use the exisiting copy of the original vertex handle instead of coping it once again.
222  //
223  // First vertex handle
224  auto vhpair = ovh2rvh.find(hv0);
225  if ( vhpair != ovh2rvh.cend() )
226  {
227  // reuse the existing copy of the original vertex handle
228  hv0 = (*vhpair).second;
229  }
230  else
231  {
232  // add a new vertex as matching map does not contain it.
233  poly_Vertex v;
234  this->GetVertex(hv0, v);
235  poly_VertexHandle _hv = region->AddVertex(v);
236 
237  ovh2rvh[hv0] = _hv;
238  hv0 = _hv;
239  }
240 
241  // Second vertex handle
242  vhpair = ovh2rvh.find(hv1);
243  if ( vhpair != ovh2rvh.cend() )
244  {
245  // reuse the existing copy of the original vertex handle
246  hv1 = (*vhpair).second;
247  }
248  else
249  {
250  // add a new vertex as matching map does not contain it.
251  poly_Vertex v;
252  this->GetVertex(hv1, v);
253  poly_VertexHandle _hv = region->AddVertex(v);
254 
255  ovh2rvh[hv1] = _hv;
256  hv1 = _hv;
257  }
258 
259  // Third vertex handle
260  vhpair = ovh2rvh.find(hv2);
261  if ( vhpair != ovh2rvh.cend() )
262  {
263  // reuse the existing copy of the original vertex handle
264  hv2 = (*vhpair).second;
265  }
266  else
267  {
268  // add a new vertex if matching map does not contain it.
269  poly_Vertex v;
270  this->GetVertex(hv2, v);
271  poly_VertexHandle _hv = region->AddVertex(v);
272 
273  ovh2rvh[hv2] = _hv;
274  hv2 = _hv;
275  }
276 
277  poly_TriangleHandle newTh = region->AddTriangle( hv0, hv1, hv2, t.GetFaceRef() );
278 
279  // Copy traits.
280  region->ChangeTriangle(newTh).traits = t.traits;
281  }
282 
283  return region;
284  }
285 
288  void Merge(const t_ptr< poly_Mesh<ElemTraits> >& other)
289  {
290  for ( poly_Mesh<ElemTraits>::TriangleIterator tit(other); tit.More(); tit.Next() )
291  {
293  other->GetTriangle(tit.Current(), t);
294 
295  poly_VertexHandle hv0;
296  poly_VertexHandle hv1;
297  poly_VertexHandle hv2;
298  t.GetVertices(hv0, hv1, hv2);
299 
300  poly_Vertex v;
301  other->GetVertex(hv0, v);
302  hv0 = this->AddVertex(v);
303 
304  other->GetVertex(hv1, v);
305  hv1 = this->AddVertex(v);
306 
307  other->GetVertex(hv2, v);
308  hv2 = this->AddVertex(v);
309 
310  poly_TriangleHandle newTh = this->AddTriangle(hv0, hv1, hv2);
311 
312  // Copy traits.
313  this->ChangeTriangle(newTh).traits = t.traits;
314  }
315  }
316 
323  const t_adjacencyMx& mx,
324  std::unordered_set<poly_TriangleHandle>& region)
325  {
326  // Iterate over the adjacency matrix starting from the passed
327  // triangle `th` and add all visited triangle indices to the region.
328  // We use a pre-computed adjacency matrix as it is a little bit faster
329  // than querying triangle adjacency information as long as we go.
330  std::unordered_set<poly_TriangleHandle> processedRows;
331  std::stack<poly_TriangleHandle> stack;
332  stack.push(th);
333  //
334  while ( !stack.empty() )
335  {
336  const auto& next = stack.top();
337  stack.pop();
338 
339  processedRows.insert(next);
340 
341  const auto& row = mx.find(next);
342 
343  for ( const auto& curr : row->second )
344  {
345  region.insert(curr);
346 
347  if ( processedRows.find(curr) == processedRows.end() )
348  stack.push(curr);
349  }
350  }
351  }
352 
358  std::unordered_set<poly_TriangleHandle>& region)
359  {
360  // Fill adjacency matrix.
361  t_adjacencyMx adj;
362  //
363  for ( TriangleIterator tit(this); tit.More(); tit.Next() )
364  {
365  std::unordered_set<poly_TriangleHandle> adjacent;
366  this->FindAdjacentByVertices(tit.Current(), adjacent);
367 
368  adj.insert({tit.Current(), adjacent});
369  }
370 
371  GrowRegion(th, adj, region);
372  }
373 
377  void ComputeCComponents(std::vector< std::unordered_set<poly_TriangleHandle> >& ccomps)
378  {
379  // Fill adjacency matrix.
380  t_adjacencyMx adj;
381  //
382  for ( TriangleIterator tit(this); tit.More(); tit.Next() )
383  {
384  std::unordered_set<poly_TriangleHandle> adjacent;
385  this->FindAdjacentByVertices(tit.Current(), adjacent);
386 
387  adj.insert({tit.Current(), adjacent});
388  }
389 
390  // Grow regions.
391  std::unordered_set<poly_TriangleHandle> processed;
392  //
393  for ( const auto& tuple : adj )
394  {
395  const poly_TriangleHandle curr = tuple.first;
396 
397  // Check if already processed.
398  if ( processed.find(curr) != processed.end() )
399  continue;
400 
401  std::unordered_set<poly_TriangleHandle> nextRegion;
402  GrowRegion(curr, adj, nextRegion);
403 
404  // Add to processed.
405  processed.insert( nextRegion.begin(), nextRegion.end() );
406 
407  // Add to result.
408  ccomps.push_back(nextRegion);
409  }
410  }
411 
412 /* CAD link */
413 public:
414 
418  void
419  SetSurfAdapter(const t_ptr<poly_SurfAdapter>& adt)
420  {
421  __surfAdt = adt;
422  }
423 
424 public:
425 
432  mobiusPoly_EXPORT bool
433  AreSelfIntersecting(const int tag,
434  const poly_EdgeHandle eh0,
435  const poly_EdgeHandle eh1) const;
436 
443  mobiusPoly_EXPORT bool
444  AreSelfIntersecting(const int tag,
445  const std::vector<poly_EdgeHandle>& ehs0,
446  const std::vector<poly_EdgeHandle>& ehs1) const;
447 
451  mobiusPoly_EXPORT bool
452  AreSelfIntersecting(const std::unordered_set<int>& domain) const;
453 
454 public:
455 
463  void
464  GetBounds(double& xMin, double& xMax,
465  double& yMin, double& yMax,
466  double& zMin, double& zMax) const
467  {
468  double x_min = DBL_MAX, x_max = -DBL_MAX;
469  double y_min = DBL_MAX, y_max = -DBL_MAX;
470  double z_min = DBL_MAX, z_max = -DBL_MAX;
471 
472  for ( auto vit = __vertices.cbegin(); vit != __vertices.cend(); ++vit )
473  {
474  const poly_Vertex& V = *vit;
475  const double x = V.X(),
476  y = V.Y(),
477  z = V.Z();
478 
479  if ( x > x_max )
480  x_max = x;
481  if ( x < x_min )
482  x_min = x;
483  if ( y > y_max )
484  y_max = y;
485  if ( y < y_min )
486  y_min = y;
487  if ( z > z_max )
488  z_max = z;
489  if ( z < z_min )
490  z_min = z;
491  }
492 
493  // Set results.
494  xMin = x_min;
495  xMax = x_max;
496  yMin = y_min;
497  yMax = y_max;
498  zMin = z_min;
499  zMax = z_max;
500  }
501 
505  {
506  core_XYZ center;
507  t_xyz vertex;
508  int vNum = 0;
509  //
510  for ( VertexIterator vIt(this); vIt.More(); vIt.Next() )
511  {
512  this->GetVertex(vIt.Current(), vertex);
513  center += vertex;
514  ++vNum;
515  }
516 
517  if ( vNum > 1 )
518  {
519  center /= vNum;
520  }
521 
522  return center;
523  }
524 
530  double
532  const poly_VertexHandle hv1,
533  const poly_VertexHandle hv2) const
534  {
535  t_xyz tv[3];
536  this->GetVertex(hv0, tv[0]);
537  this->GetVertex(hv1, tv[1]);
538  this->GetVertex(hv2, tv[2]);
539 
540  // Compute area.
541  return poly_MeshUtils::ComputeArea(tv[0], tv[1], tv[2]);
542  }
543 
547  double ComputeArea(const poly_TriangleHandle ht) const
548  {
549  // Get triangle by its handle.
551  if ( !this->GetTriangle(ht, t) )
552  return false;
553 
554  // Get vertices on the triangle.
555  poly_VertexHandle htv[3];
556  //
557  t.GetVertices(htv[0], htv[1], htv[2]);
558  //
559  return ComputeArea(htv[0], htv[1], htv[2]);
560  }
561 
564  double ComputeArea()
565  {
566  double area = 0.;
567 
568  for ( TriangleIterator tit(this); tit.More(); tit.Next() )
569  {
570  area += ComputeArea(tit.Current());
571  }
572 
573  return area;
574  }
575 
584  void
586  double& volume,
587  core_XYZ& firstAxisOfInertia,
588  core_XYZ& secondAxisOfInertia,
589  core_XYZ& thirdAxisOfInertia) const
590  {
591  // Gauss points for barycentric coordinates
592  static double pntWg[] =
593  {
594  1. / 3., 1. / 3., 1. / 2., /* 1-point-based */
595  1. / 6., 1. / 6., 1. / 6., /* 3-points-based */
596  2. / 3., 1. / 6., 1. / 6.,
597  1. / 6., 2. / 3., 1. / 6.
598  };
599  //
600  int nbPoints = 1;
601  double* gaussPnts = &pntWg[0];
602  if ( density == PropsComputationDensity::ThreePoints )
603  {
604  nbPoints = 3;
605  gaussPnts = &pntWg[3];
606  }
607 
608  // Array to store global properties
609  double gProps[10] = { 0., 0., 0., 0., 0., 0., 0., 0., 0., 0 };
610 
611  core_XYZ polyCenter = this->ComputeCenter();
612 
613  for ( TriangleIterator trIt(this); trIt.More(); trIt.Next() )
614  {
615  poly_Triangle<ElemTraits> triangle;
616  this->GetTriangle(trIt.Current(), triangle);
617 
618  poly_VertexHandle hv0, hv1, hv2;
619  triangle.GetVertices(hv0, hv1, hv2);
620 
621  t_xyz tv[3];
622  this->GetVertex(hv0, tv[0]);
623  this->GetVertex(hv1, tv[1]);
624  this->GetVertex(hv2, tv[2]);
625 
626  poly_MeshUtils::ComputePyramidProps(tv[0], tv[1], tv[2], polyCenter, gProps, nbPoints, gaussPnts);
627  }
628 
629  // initialize output parameters
630  //
631  volume = gProps[0];
632  //
633  firstAxisOfInertia = core_XYZ(gProps[1], gProps[2], gProps[3]);
634  secondAxisOfInertia = core_XYZ(gProps[4], gProps[5], gProps[6]);
635  thirdAxisOfInertia = core_XYZ(gProps[7], gProps[8], gProps[9]);
636  }
637 
644  bool
646  poly_TriangleHandle& ht0,
647  poly_TriangleHandle& ht1,
648  poly_TriangleHandle& ht2)
649  {
650  // Get the triangle to split.
652  if ( !this->GetTriangle(ht, t) || t.IsDeleted() )
653  return false;
654 
655  // Get vertices on the triangle to split.
656  poly_VertexHandle htv[3];
657  t.GetVertices(htv[0], htv[1], htv[2]);
658  //
659  t_xyz midPt;
660  poly_Vertex tv[3];
661  for ( size_t k = 0; k < 3; ++k )
662  {
663  this->GetVertex(htv[k], tv[k]);
664 
665  midPt += tv[k];
666  }
667  //
668  midPt /= 3.0;
669 
670  // Add midpoint vertex.
671  poly_VertexHandle hmv = this->AddVertex(midPt);
672 
673  // Add new triangles.
674  ht0 = this->AddTriangle( htv[0], htv[1], hmv, t.GetFaceRef() );
675  ht1 = this->AddTriangle( hmv, htv[1], htv[2], t.GetFaceRef() );
676  ht2 = this->AddTriangle( htv[0], hmv, htv[2], t.GetFaceRef() );
677 
678  // Remove the refined triangle.
679  this->RemoveTriangle(ht);
680 
681  return true;
682  }
683 
688  {
689  poly_TriangleHandle hrt[3];
690  return this->RefineByMidpoint(ht, hrt[0], hrt[1], hrt[2]);
691  }
692 
697  bool
699  std::vector<poly_TriangleHandle>& hts)
700  {
701  // Get the triangle to refine.
703  if ( !this->GetTriangle(ht, t) )
704  return false;
705  //
706  if ( t.IsDeleted() )
707  return false;
708 
709  // Get vertices on the triangle.
710  poly_VertexHandle hv[3];
711  t.GetVertices(hv[0], hv[1], hv[2]);
712 
713  // Get the edges.
714  poly_Edge edges[3] = { poly_Edge(hv[0], hv[1]),
715  poly_Edge(hv[1], hv[2]),
716  poly_Edge(hv[2], hv[0]) };
717  //
718  poly_EdgeHandle hes[3] = { this->FindEdge(edges[0]),
719  this->FindEdge(edges[1]),
720  this->FindEdge(edges[2]) };
721  //
722  for ( int j = 0; j < 3; ++j )
723  {
724  if ( hes[j].iIdx == Mobius_InvalidHandleIndex )
725  return false;
726  }
727 
728  // Get corners.
729  t_xyz v[3];
730  this->GetVertex(hv[0], v[0]);
731  this->GetVertex(hv[1], v[1]);
732  this->GetVertex(hv[2], v[2]);
733 
734  // Build new vertices.
735  poly_VertexHandle hmv[3];
736  t_xyz mv[3];
737  //
738  hmv[0] = this->AddVertex( 0.5*(v[0] + v[1]) );
739  hmv[1] = this->AddVertex( 0.5*(v[1] + v[2]) );
740  hmv[2] = this->AddVertex( 0.5*(v[2] + v[0]) );
741 
742  std::unordered_map<poly_EdgeHandle, poly_VertexHandle> eSplits;
743  eSplits.insert({hes[0], hmv[0]});
744  eSplits.insert({hes[1], hmv[1]});
745  eSplits.insert({hes[2], hmv[2]});
746 
747  // Build new triangles.
748  hts.push_back( this->AddTriangle( hv [0], hmv[0], hmv[2], t.GetFaceRef() ) );
749  hts.push_back( this->AddTriangle( hmv[0], hv [1], hmv[1], t.GetFaceRef() ) );
750  hts.push_back( this->AddTriangle( hmv[1], hv [2], hmv[2], t.GetFaceRef() ) );
751  hts.push_back( this->AddTriangle( hmv[0], hmv[1], hmv[2], t.GetFaceRef() ) );
752 
753  // Add 9 newly created edges.
754  std::unordered_map<poly_Edge, std::pair<poly_TriangleHandle, poly_TriangleHandle>> newEdges;
755  //
756  newEdges.insert( { poly_Edge(hv [0], hmv[0]), { hts[0], poly_TriangleHandle() } } );
757  newEdges.insert( { poly_Edge(hmv[0], hmv[2]), { hts[0], hts[3] } } );
758  newEdges.insert( { poly_Edge(hmv[2], hv [0]), { hts[0], poly_TriangleHandle() } } );
759  //
760  newEdges.insert( { poly_Edge(hmv[0], hv [1]), { hts[1], poly_TriangleHandle() } } );
761  newEdges.insert( { poly_Edge(hv [1], hmv[1]), { hts[1], poly_TriangleHandle() } } );
762  newEdges.insert( { poly_Edge(hmv[1], hmv[0]), { hts[1], hts[3] } } );
763  //
764  newEdges.insert( { poly_Edge(hmv[1], hv [2]), { hts[2], poly_TriangleHandle() } } );
765  newEdges.insert( { poly_Edge(hv [2], hmv[2]), { hts[2], poly_TriangleHandle() } } );
766  newEdges.insert( { poly_Edge(hmv[2], hmv[1]), { hts[2], hts[3] } } );
767 
768  std::unordered_map<poly_TriangleHandle, poly_EdgeHandle> tris2Split;
769  for ( int j = 0; j < 3; ++j )
770  {
771  std::vector<poly_TriangleHandle> edgeTris;
772 
773  if ( !this->GetTriangles(hes[j], edgeTris) )
774  return false;
775 
776  for ( const auto& eth : edgeTris )
777  if ( eth != ht )
778  tris2Split.insert({eth, hes[j]});
779  }
780 
781  // Split neighbor triangles.
782  for ( const auto& toSplit : tris2Split )
783  {
784  // Get common edge.
785  poly_Edge cmnEdge;
786  if ( !this->GetEdge(toSplit.second, cmnEdge) )
787  continue;
788 
789  if ( cmnEdge.IsDeleted() )
790  continue;
791 
792  // Get triangle to split.
794  if ( !this->GetTriangle(toSplit.first, nextTri) )
795  continue;
796 
797  // Compute the reference normal to control the splitting validity.
798  t_xyz refNorm;
799  this->ComputeNormal(toSplit.first, refNorm);
800 
801  /* Find the opposite node. */
802 
804  oppVh = this->GetOppositeVertex(toSplit.first, toSplit.second);
805  //
806  if ( !oppVh.IsValid() )
807  continue; // Skip triangle if we are not able to find its opposite node.
808 
809  /* Split triangle */
810 
811  poly_VertexHandle a = oppVh;
812  poly_VertexHandle b = cmnEdge.hVertices[0];
813  poly_VertexHandle c = eSplits[toSplit.second];
814  poly_VertexHandle d = cmnEdge.hVertices[1];
815 
816  // Compute norms to preserve orientations.
817  t_xyz testN[2];
818  this->ComputeNormal(a, b, c, testN[0]);
819  this->ComputeNormal(a, c, d, testN[1]);
820 
821  // Add new triangles.
822  poly_TriangleHandle thLeft, thRight;
823  //
824  if ( testN[0].Dot(refNorm) > 0 )
825  {
826  thLeft = this->AddTriangle( a, b, c, nextTri.GetFaceRef() );
827  }
828  else
829  {
830  thLeft = this->AddTriangle( a, c, b, nextTri.GetFaceRef() );
831  }
832  //
833  if ( testN[1].Dot(refNorm) > 0 )
834  {
835  thRight = this->AddTriangle( a, c, d, nextTri.GetFaceRef() );
836  }
837  else
838  {
839  thRight = this->AddTriangle( a, d, c, nextTri.GetFaceRef() );
840  }
841 
842  // Update edges coming out of split.
843  newEdges[poly_Edge(b, c)].second = thLeft;
844  newEdges[poly_Edge(c, d)].second = thRight;
845  //
846  newEdges.insert( { poly_Edge(a, c), { thLeft, thRight } } );
847 
848  // Update edges sharing the opposite vertex.
849  this->updateLink( this->FindEdge( poly_Edge(a, b) ), toSplit.first, thLeft);
850  this->updateLink( this->FindEdge( poly_Edge(a, d) ), toSplit.first, thRight);
851 
852  /* Remove old triangle. */
853  this->RemoveTriangle(toSplit.first);
854  }
855 
856  // Remove old triangle.
857  this->RemoveTriangle(ht);
858 
859  // Erase old edges.
860  __links.erase(hes[0]);
861  __links.erase(hes[1]);
862  __links.erase(hes[2]);
863  //
864  this->RemoveEdge(hes[0]);
865  this->RemoveEdge(hes[1]);
866  this->RemoveEdge(hes[2]);
867  //
868  for ( const auto& edge2Insert : newEdges )
869  {
870  const poly_EdgeHandle newEh = this->AddEdge(edge2Insert.first);
871 
872  std::vector<poly_TriangleHandle> newTris;
873  //
874  if ( edge2Insert.second.first.IsValid() )
875  newTris.push_back(edge2Insert.second.first);
876  //
877  if ( edge2Insert.second.second.IsValid() )
878  newTris.push_back(edge2Insert.second.second);
879 
880  __links.insert({newEh, newTris});
881  }
882 
883  return true;
884  }
885 
890  {
891  std::vector<poly_TriangleHandle> hts;
892  return this->RefineByMidedges(ht, hts);
893  }
894 
902  const poly_EdgeHandle he) const
903  {
904  poly_Edge edge;
905  if ( !this->GetEdge(he, edge) )
906  return poly_VertexHandle();
907 
909  if ( !this->GetTriangle(ht, nbrTri) )
910  return poly_VertexHandle();
911 
912  poly_VertexHandle vhs[3];
913  nbrTri.GetVertices(vhs[0], vhs[1], vhs[2]);
914 
915  poly_VertexHandle oppVh;
916  for ( int vidx = 0; vidx < 3; ++vidx )
917  if ( (vhs[vidx] != edge.hVertices[0]) && (vhs[vidx] != edge.hVertices[1]) )
918  oppVh = vhs[vidx];
919 
920  if ( !oppVh.IsValid() )
921  return poly_VertexHandle();
922 
923  return oppVh;
924  }
925 
933  bool
935  const poly_VertexHandle hv1,
936  const poly_VertexHandle hv2,
937  t_xyz& norm) const
938  {
939  t_xyz tv[3];
940  //
941  this->GetVertex(hv0, tv[0]);
942  this->GetVertex(hv1, tv[1]);
943  this->GetVertex(hv2, tv[2]);
944 
945  return poly_MeshUtils::ComputeNormal(tv[0], tv[1], tv[2], norm);
946  }
947 
953  void
955  const poly_VertexHandle hv1,
956  const poly_VertexHandle hv2,
957  t_xyz& center) const
958  {
959  t_xyz tv[3];
960  //
961  this->GetVertex(hv0, tv[0]);
962  this->GetVertex(hv1, tv[1]);
963  this->GetVertex(hv2, tv[2]);
964 
965  poly_MeshUtils::ComputeCenter(tv[0], tv[1], tv[2], center);
966  }
967 
973  bool
975  t_xyz& norm) const
976  {
977  // Get triangle by its handle.
979  if ( !this->GetTriangle(ht, t) )
980  return false;
981 
982  // Get vertices on the triangle.
983  poly_VertexHandle htv[3];
984  t_xyz tv[3];
985  //
986  t.GetVertices(htv[0], htv[1], htv[2]);
987 
988  return this->ComputeNormal(htv[0], htv[1], htv[2], norm);
989  }
990 
994  double
996  {
997  // Get element.
999  this->GetTriangle(ht, elem);
1000 
1001  // Get nodes.
1002  poly_VertexHandle n0, n1, n2;
1003  elem.GetVertices(n0, n1, n2);
1004  //
1005  t_xyz v0, v1, v2;
1006  //
1007  this->GetVertex(n0, v0);
1008  this->GetVertex(n1, v1);
1009  this->GetVertex(n2, v2);
1010 
1011  double res = DBL_MAX;
1012  for ( int k = 0; k < 3; ++k )
1013  {
1014  t_uv uv[3];
1015  double J[2][2] = { {0, 0}, {0, 0} };
1016  double J_det = 0.;
1017  double J_det_n = 0.;
1018 
1019  // Compute for element.
1020  poly_Jacobian::Compute(v0, v1, v2, k, uv[0], uv[1], uv[2], J, J_det, J_det_n);
1021 
1022  res = std::min(res, J_det_n);
1023  }
1024 
1025  return res;
1026  }
1027 
1033  double
1035  const t_xyz& v1,
1036  const t_xyz& v2) const
1037  {
1038  double res = DBL_MAX;
1039  for ( int k = 0; k < 3; ++k )
1040  {
1041  t_uv uv[3];
1042  double J[2][2] = { {0, 0}, {0, 0} };
1043  double J_det = 0.;
1044  double J_det_n = 0.;
1045  //
1046  poly_Jacobian::Compute(v0, v1, v2, k, uv[0], uv[1], uv[2], J, J_det, J_det_n);
1047 
1048  res = std::min(res, J_det_n);
1049  }
1050 
1051  return res;
1052  }
1053 
1057  double
1059  {
1060  // Get triangle by its handle.
1062  if ( !this->GetTriangle(ht, t) )
1063  return false;
1064 
1065  // Get vertices on the triangle.
1066  poly_VertexHandle htv[3];
1067  t_xyz tv[3];
1068  //
1069  t.GetVertices(htv[0], htv[1], htv[2]);
1070  //
1071  for ( size_t k = 0; k < 3; ++k )
1072  this->GetVertex(htv[k], tv[k]);
1073 
1074  // Compute max length.
1075  const double maxLen = std::max( (tv[1] - tv[0]).Modulus(),
1076  std::max( (tv[2] - tv[1]).Modulus(),
1077  (tv[2] - tv[0]).Modulus() ) );
1078  return maxLen;
1079  }
1080 
1088  bool
1090  const t_xyz& v1,
1091  const t_xyz& v2,
1092  const double prec) const
1093  {
1094  t_xyz tv[3] = {v0, v1, v2};
1095 
1096  // Degenerated side.
1097  t_xyz vec01 = tv[1] - tv[0];
1098  const double sqNorm01 = vec01.SquaredModulus();
1099  if ( sqNorm01 <= prec )
1100  {
1101  return true;
1102  }
1103 
1104  // Degenerated side.
1105  t_xyz vec02 = tv[2] - tv[0];
1106  const double sqNorm02 = vec02.SquaredModulus();
1107  if ( sqNorm02 <= prec )
1108  {
1109  return true;
1110  }
1111 
1112  // Degenerated side.
1113  t_xyz vec12 = tv[2] - tv[1];
1114  const double sqNorm12 = vec12.SquaredModulus();
1115  if ( sqNorm12 <= prec )
1116  {
1117  return true;
1118  }
1119 
1120  /*const double a1 = vec01.Angle(vec02);
1121  const double a2 = vec12.Angle(vec01);
1122  const double a3 = vec02.Angle(vec12);*/
1123 
1124  const double SP0102 = vec01 * vec02;
1125  t_xyz vec = vec02 - (SP0102 / sqNorm01) * vec01;
1126  if ( vec.SquaredModulus() <= prec )
1127  {
1128  return true;
1129  }
1130 
1131  vec = vec01 - (SP0102 / sqNorm02) * vec02;
1132  if ( vec.SquaredModulus() <= prec )
1133  {
1134  return true;
1135  }
1136 
1137  vec = ((vec01 * vec12) / sqNorm12) * vec12 - vec01;
1138 
1139  return (vec.SquaredModulus() <= prec);
1140  }
1141 
1147  bool
1149  const double prec) const
1150  {
1151  // Get triangle by its handle.
1153  if ( !this->GetTriangle(ht, t) )
1154  return false;
1155 
1156  // Get vertices on the triangle.
1157  poly_VertexHandle htv[3];
1158  t_xyz tv[3];
1159  //
1160  t.GetVertices(htv[0], htv[1], htv[2]);
1161  //
1162  for ( size_t k = 0; k < 3; ++k )
1163  this->GetVertex(htv[k], tv[k]);
1164 
1165  return this->IsDegenerated(tv[0], tv[1], tv[2], prec);
1166  }
1167 
1173  bool
1175  {
1176  // Get triangle by its handle.
1178  if ( !this->GetTriangle(ht, t) )
1179  return false;
1180 
1181  // Get vertices on the triangle.
1182  poly_VertexHandle htv[3];
1183  t_xyz tv[3];
1184  //
1185  t.GetVertices(htv[0], htv[1], htv[2]);
1186  //
1187  for ( size_t k = 0; k < 3; ++k )
1188  this->GetVertex(htv[k], tv[k]);
1189 
1190  // Get triangle links.
1191  /*poly_Edge e[3] = { poly_Edge(htv[0], htv[1]),
1192  poly_Edge(htv[1], htv[2]),
1193  poly_Edge(htv[2], htv[0]) };*/
1194 
1195  // Prepare subdivision points.
1196  t_xyz mv[3] = { (tv[0] + tv[1])*0.5,
1197  (tv[1] + tv[2])*0.5,
1198  (tv[2] + tv[0])*0.5 };
1199  //
1200  poly_VertexHandle hmv[3] = { this->AddVertex(mv[0]),
1201  this->AddVertex(mv[1]),
1202  this->AddVertex(mv[2]) };
1203 
1204  // Add new triangles.
1205  this->AddTriangle( htv[0], hmv[0], hmv[2], t.GetFaceRef() );
1206  this->AddTriangle( hmv[0], htv[1], hmv[1], t.GetFaceRef() );
1207  this->AddTriangle( hmv[1], htv[2], hmv[2], t.GetFaceRef() );
1208  this->AddTriangle( hmv[0], hmv[1], hmv[2], t.GetFaceRef() );
1209 
1210  // Remove the subdivided triangle.
1211  this->RemoveTriangle(ht);
1212 
1213  return true;
1214  }
1215 
1219  {
1220  // Clean up any existing links.
1221  this->ClearEdges();
1222 
1223  // We keep the edge vertices sorted by their indices, so that we can
1224  // benefit from fast hashing. The idea is to hash twice using the
1225  // nested maps like
1226  //
1227  // <vertexHandle_0, <vertexHandle_1, edgeHandle_i>>
1228  // <vertexHandle_0, <vertexHandle_2, edgeHandle_j>>
1229  // ...
1230  typedef std::unordered_map<poly_VertexHandle, poly_EdgeHandle> t_vheh;
1231  std::unordered_map<poly_VertexHandle, t_vheh> visitedEdges;
1232 
1233  // Cache new links.
1234  for ( TriangleIterator tit(this); tit.More(); tit.Next() )
1235  {
1236  poly_TriangleHandle th = tit.Current();
1238 
1239  this->GetTriangle(th, t);
1240  //
1241  if ( t.IsDeleted() )
1242  continue;
1243 
1244  poly_VertexHandle vh[3];
1245  t.GetVertices(vh[0], vh[1], vh[2]);
1246 
1247  // Compose the edges to check for.
1248  poly_Edge edges[3];
1249 
1250  // Keep vertices sorted by index.
1251  edges[0] = (vh[0].iIdx < vh[1].iIdx ? poly_Edge(vh[0], vh[1]) : poly_Edge(vh[1], vh[0]));
1252  edges[1] = (vh[1].iIdx < vh[2].iIdx ? poly_Edge(vh[1], vh[2]) : poly_Edge(vh[2], vh[1]));
1253  edges[2] = (vh[2].iIdx < vh[0].iIdx ? poly_Edge(vh[2], vh[0]) : poly_Edge(vh[0], vh[2]));
1254 
1255  // Populate the map of links.
1256  for ( int eidx = 0; eidx < 3; ++eidx )
1257  {
1258  auto linkIt1 = visitedEdges.find(edges[eidx].hVertices[0]);
1259  //
1260  if ( linkIt1 == visitedEdges.end() )
1261  {
1262  poly_EdgeHandle eh( int( __links.size() ) );
1263 
1264  t_vheh rec; rec.insert({edges[eidx].hVertices[1], eh});
1265 
1266  visitedEdges.insert( {edges[eidx].hVertices[0], rec});
1267  __links .insert ( {eh, {th}} );
1268 
1269  // Add edge and keep a link in a triangle.
1270  __triangles[th.iIdx].hEdges[eidx] = this->AddEdge(edges[eidx]);
1271  }
1272  else
1273  {
1274  auto linkIt2 = linkIt1->second.find(edges[eidx].hVertices[1]);
1275  //
1276  if ( linkIt2 == linkIt1->second.end() )
1277  {
1278  poly_EdgeHandle eh( int( __links.size() ) );
1279 
1280  linkIt1->second.insert({edges[eidx].hVertices[1], eh});
1281 
1282  __links.insert( {eh, {th}} );
1283 
1284  // Add edge and keep a link in a triangle.
1285  __triangles[th.iIdx].hEdges[eidx] = this->AddEdge(edges[eidx]);
1286  }
1287  else
1288  {
1289  __links.find(linkIt2->second)->second.push_back(th);
1290 
1291  __triangles[th.iIdx].hEdges[eidx] = linkIt2->second;
1292  }
1293  }
1294  }
1295  }
1296  }
1297 
1299  void ClearEdges()
1300  {
1301  __links.clear();
1302  __edges.clear();
1303  }
1304 
1308  int CountTriangles(const poly_EdgeHandle he) const
1309  {
1310  auto linkIt = __links.find(he);
1311  if ( linkIt == __links.end() )
1312  return 0;
1313 
1314  return int( linkIt->second.size() );
1315  }
1316 
1322  bool
1324  std::vector<poly_TriangleHandle>& hts) const
1325  {
1326  auto linkIt = __links.find(he);
1327  if ( linkIt == __links.end() )
1328  return false;
1329 
1330  hts = linkIt->second;
1331  return true;
1332  }
1333 
1339  bool
1341  std::unordered_set<poly_TriangleHandle>& hts) const
1342  {
1343  auto linkIt = __links.find(he);
1344  if ( linkIt == __links.end() )
1345  return false;
1346 
1347  for ( const auto& ht : linkIt->second )
1348  hts.insert(ht);
1349 
1350  return true;
1351  }
1352 
1358  bool
1360  std::vector<poly_TriangleHandle>& hts) const
1361  {
1362  std::unordered_set<poly_TriangleHandle> tset;
1363  bool res = FindAdjacentByEdges(ht, tset);
1364  for (const auto& eth : tset)
1365  {
1366  hts.push_back(eth);
1367  }
1368 
1369  return res;
1370  }
1371 
1377  bool
1379  std::unordered_set<poly_TriangleHandle>& hts) const
1380  {
1381  // TODO: this method uses linear search for edges.
1382  // DO NOT USE THIS METHOD!!!
1383 
1385  this->GetTriangle(ht, t);
1386 
1387  poly_VertexHandle hv[3];
1388  t.GetVertices(hv[0], hv[1], hv[2]);
1389 
1390  poly_Edge edges[3] = { poly_Edge(hv[0], hv[1]),
1391  poly_Edge(hv[1], hv[2]),
1392  poly_Edge(hv[2], hv[0]) };
1393 
1394  poly_EdgeHandle hes[3] = { this->FindEdge(edges[0]),
1395  this->FindEdge(edges[1]),
1396  this->FindEdge(edges[2]) };
1397  //
1398  for ( int j = 0; j < 3; ++j )
1399  {
1400  if ( hes[j].iIdx == Mobius_InvalidHandleIndex )
1401  return false;
1402  }
1403 
1404  // Find triangles by edges.
1405  for ( int j = 0; j < 3; ++j )
1406  {
1407  std::unordered_set<poly_TriangleHandle> edgeTris;
1408 
1409  if ( !this->GetTriangles(hes[j], edgeTris) )
1410  return false;
1411 
1412  for ( const auto& eth : edgeTris )
1413  if ( eth != ht )
1414  hts.insert(eth);
1415  }
1416 
1417  return true;
1418  }
1419 
1425  void
1427  std::unordered_set<poly_TriangleHandle>& hts,
1428  const std::unordered_set<int>& domain = std::unordered_set<int>()) const
1429  {
1430  const std::unordered_set<poly_TriangleHandle>&
1431  vertexTris = __vertices[hv.iIdx].GetTriangleRefs();
1432 
1433  for ( const auto& vth : vertexTris )
1434  {
1435  if ( !domain.empty() && ( domain.find( __triangles[vth.iIdx].GetFaceRef() ) == domain.end() ) )
1436  continue; // Skip faces that are out of interest.
1437 
1438  hts.insert(vth);
1439  }
1440  }
1441 
1451  void
1453  std::unordered_set<poly_VertexHandle>& hvs,
1454  bool& isBoundary,
1455  std::unordered_set<int>& faceRefs,
1456  const std::unordered_set<int>& domain) const
1457  {
1458  isBoundary = false;
1459 
1460  // Take all triangles containing this vertex. Do not pass the domain here as we want
1461  // to take all triangles, including out-of-domain ones and then reason about the
1462  // feature boundaries (if we filter out the out-of-domain triangles here, we won't
1463  // be able to detect the boundary).
1464  std::unordered_set<poly_TriangleHandle> ths;
1465  this->FindAdjacent(hv, ths);
1466 
1467  // Vertices and their domains.
1468  std::unordered_map<poly_VertexHandle, int> vDomains;
1469 
1470  // Add the neighbor triangles' vertices to the result.
1471  for ( const auto& th : ths )
1472  {
1474  this->GetTriangle(th, t);
1475 
1476  if ( t.IsDeleted() )
1477  continue;
1478 
1479  faceRefs.insert( t.GetFaceRef() );
1480 
1481  for ( int k = 0; k < 3; ++k )
1482  {
1483  if ( t.hVertices[k] != hv )
1484  {
1485  vDomains.insert({t.hVertices[k], t.GetFaceRef()});
1486 
1487  // Check if that's a boundary vertex.
1488  if ( !isBoundary )
1489  {
1490  poly_EdgeHandle eh;
1491  for ( int j = 0; j < 3; ++j )
1492  {
1493  const poly_Edge& eCandidate = __edges[t.hEdges[j].iIdx];
1494 
1495  if ( ((eCandidate.hVertices[0] == hv) && (eCandidate.hVertices[1] == t.hVertices[k])) ||
1496  ((eCandidate.hVertices[1] == hv) && (eCandidate.hVertices[0] == t.hVertices[k])) )
1497  eh = t.hEdges[j];
1498  }
1499 
1500  if ( eh.IsValid() )
1501  {
1502  // Check if that's a boundary link.
1503  auto linkIt = __links.find(eh);
1504  //
1505  if ( ( linkIt != __links.end() ) && (linkIt->second.size() < 2) )
1506  isBoundary = true;
1507  }
1508  }
1509  }
1510  }
1511  }
1512 
1513  if ( !isBoundary && (faceRefs.size() > 1) )
1514  isBoundary = true;
1515 
1516  // Compose the result.
1517  for ( const auto& tuple : vDomains )
1518  {
1519  if ( domain.empty() || domain.count(tuple.second) )
1520  {
1521  hvs.insert(tuple.first);
1522  }
1523  }
1524  }
1525 
1531  bool
1533  std::vector<poly_TriangleHandle>& hts) const
1534  {
1535  if ( !he.IsValid() )
1536  return false;
1537 
1538  auto linkIt = __links.find(he);
1539  //
1540  if ( linkIt == __links.end() )
1541  return false;
1542 
1543  hts = linkIt->second;
1544  return true;
1545  }
1546 
1550  void
1552  std::unordered_set<poly_TriangleHandle>& hts) const
1553  {
1555  this->GetTriangle(ht, t);
1556 
1557  this->FindAdjacent(t.hVertices[0], hts);
1558  this->FindAdjacent(t.hVertices[1], hts);
1559  this->FindAdjacent(t.hVertices[2], hts);
1560  }
1561 
1584  bool
1586  const double normDevRad,
1587  const double planeDevRad,
1588  const bool checkJacobian,
1589  const bool checkWing,
1590  poly_TriangleHandle& ht0,
1591  poly_TriangleHandle& ht1,
1592  poly_VertexHandle& a,
1593  poly_VertexHandle& b,
1594  poly_VertexHandle& x,
1595  poly_VertexHandle& y,
1596  t_xyz& norm0,
1597  t_xyz& norm1) const
1598  {
1599  (void) planeDevRad;
1600 
1601  /* a
1602  o
1603  | \
1604  | \
1605  | \
1606  x o----o y
1607  \ |
1608  \ |
1609  \ |
1610  o
1611  b
1612  */
1613  a = b = x = y = poly_VertexHandle(Mobius_InvalidHandleIndex);
1614 
1615  std::vector<poly_TriangleHandle> hts;
1616  if ( !this->GetTriangles(he, hts) )
1617  return false;
1618 
1619  if ( hts.size() != 2 )
1620  return false;
1621 
1622  // Get scaled Jacobians to control the quality of the triangles
1623  // on edge flip (we do not want to make it worse).
1624  double J_before[2] = {0., 0.};
1625  //
1626  if ( checkJacobian )
1627  {
1628  J_before[0] = this->ComputeScaledJacobian(hts[0]);
1629  J_before[1] = this->ComputeScaledJacobian(hts[1]);
1630  }
1631 
1632  ht0 = hts[0];
1633  ht1 = hts[1];
1634 
1636  this->GetTriangle(ht0, t[0]);
1637  this->GetTriangle(ht1, t[1]);
1638  //
1639  if ( t[0].IsDeleted() || t[1].IsDeleted() )
1640  return false;
1641 
1642  /* Check normal criterion. */
1643 
1644  this->ComputeNormal(ht0, norm0);
1645  this->ComputeNormal(ht1, norm1);
1646  //
1647  if ( norm0.Angle(norm1) > normDevRad )
1648  return false;
1649 
1650  /* Check angle criterion. */
1651 
1652  // Get vertices of the edge.
1653  poly_Edge e;
1654  this->GetEdge(he, e);
1655  //
1656  x = e.hVertices[0];
1657  y = e.hVertices[1];
1658 
1659  poly_VertexHandle t0_v[3], t1_v[3];
1660  t[0].GetVertices(t0_v[0], t0_v[1], t0_v[2]);
1661  t[1].GetVertices(t1_v[0], t1_v[1], t1_v[2]);
1662 
1663  // Get opposite vertices `a` and `b`.
1664  for ( int j = 0; j < 3; ++j )
1665  {
1666  if ( t0_v[j] == x || t0_v[j] == y )
1667  continue;
1668 
1669  a = t0_v[j];
1670  break;
1671  }
1672  //
1673  for ( int j = 0; j < 3; ++j )
1674  {
1675  if ( t1_v[j] == x || t1_v[j] == y )
1676  continue;
1677 
1678  b = t1_v[j];
1679  break;
1680  }
1681  //
1682  if ( a.GetIdx() == Mobius_InvalidHandleIndex )
1683  return false;
1684  //
1685  if ( b.GetIdx() == Mobius_InvalidHandleIndex )
1686  return false;
1687 
1688  t_xyz a_coords, b_coords, x_coords, y_coords;
1689  this->GetVertex(a, a_coords);
1690  this->GetVertex(b, b_coords);
1691  this->GetVertex(x, x_coords);
1692  this->GetVertex(y, y_coords);
1693 
1694  // Check scaled Jacobians after edge flip.
1695  if ( checkJacobian )
1696  {
1697  const double J_after[2] = { this->ComputeScaledJacobian(a_coords, x_coords, b_coords),
1698  this->ComputeScaledJacobian(a_coords, y_coords, b_coords) };
1699  //
1700  if ( std::min(J_after[0], J_after[1]) < std::min(J_before[0], J_before[1]) )
1701  return false;
1702  }
1703 
1704  if ( checkWing )
1705  {
1706  // There's ambiguity how `x` and `y` are defined, so we
1707  // do all possible tests here.
1708  t_xyz bx = (b_coords - x_coords).Normalized();
1709  t_xyz ax = (a_coords - x_coords).Normalized();
1710  t_xyz xy = (y_coords - x_coords).Normalized();
1711  t_xyz by = (b_coords - y_coords).Normalized();
1712  t_xyz ay = (a_coords - y_coords).Normalized();
1713  t_xyz yx = (x_coords - y_coords).Normalized();
1714 
1715  const double adot1 = ax.Dot(xy);
1716  const double bdot1 = bx.Dot(xy);
1717  const double adot2 = ay.Dot(yx);
1718  const double bdot2 = by.Dot(yx);
1719 
1720  if ( adot1 < 0 || bdot1 < 0 || adot2 < 0 || bdot2 < 0 )
1721  return false;
1722  }
1723 
1724  return true;
1725  }
1726 
1740  bool
1742  const double normDevRad = 1./180.*M_PI,
1743  const double planeDevRad = 15./180.*M_PI,
1744  const bool checkJacobian = true,
1745  const bool checkWing = true) const
1746  {
1747  poly_TriangleHandle hts[2];
1748  poly_VertexHandle a, b, x, y;
1749  t_xyz norm0, norm1;
1750  //
1751  return this->CanFlip(he, normDevRad, planeDevRad, checkJacobian, checkWing,
1752  hts[0], hts[1], a, b, x, y, norm0, norm1);
1753  }
1754 
1767  bool
1769  const double normDevRad = 1./180.*M_PI,
1770  const double planeDevRad = 15./180.*M_PI,
1771  const bool checkJacobian = true,
1772  const bool checkWing = true)
1773  {
1774  poly_VertexHandle a, b, x, y;
1775  poly_TriangleHandle hts[2];
1776  t_xyz norm0, norm1;
1777  //
1778  if ( !this->CanFlip(he, normDevRad, planeDevRad, checkJacobian, checkWing,
1779  hts[0], hts[1], a, b, x, y, norm0, norm1) )
1780  return false;
1781 
1782  // Get triangles to rotate.
1784  this->GetTriangle(hts[0], ts[0]);
1785  this->GetTriangle(hts[1], ts[1]);
1786 
1787  // Compute norms to preserve orientations.
1788  t_xyz testN[2];
1789  this->ComputeNormal(a, x, b, testN[0]);
1790  this->ComputeNormal(b, y, a, testN[1]);
1791 
1792  // Add new (rotated) triangles.
1793  poly_TriangleHandle newHts[2];
1794  //
1795  if ( testN[0].Dot(norm0) > 0 )
1796  {
1797  newHts[0] = this->AddTriangle( a, x, b, ts[0].GetFaceRef() );
1798  }
1799  else
1800  {
1801  newHts[0] = this->AddTriangle( b, x, a, ts[0].GetFaceRef() );
1802  }
1803  //
1804  if ( testN[1].Dot(norm1) > 0 )
1805  {
1806  newHts[1] = this->AddTriangle( b, y, a, ts[1].GetFaceRef() );
1807  }
1808  else
1809  {
1810  newHts[1] = this->AddTriangle( a, y, b, ts[1].GetFaceRef() );
1811  }
1812 
1813  // Remove original triangles.
1814  this->RemoveTriangle(hts[0]);
1815  this->RemoveTriangle(hts[1]);
1816 
1817  // Update links.
1818  this->updateLink(he, hts[0], newHts[0]);
1819  this->updateLink(he, hts[1], newHts[1]);
1820 
1821  return true;
1822  }
1823 
1828  int
1829  FlipEdges(const double normDevRad = 1./180.*M_PI,
1830  const double planeDevRad = 15./180.*M_PI)
1831  {
1832  int nbFlips = 0;
1833 
1834  for ( poly_Mesh::EdgeIterator eit(this); eit.More(); eit.Next() )
1835  {
1836  const poly_EdgeHandle eh = eit.Current();
1837 
1838  if ( this->FlipEdge(eh, normDevRad, planeDevRad) )
1839  nbFlips++;
1840  }
1841 
1842  // Invalidate all existing links.
1843  this->ClearEdges();
1844 
1845  return nbFlips;
1846  }
1847 
1852  FindEdge(const poly_Edge& e) const
1853  {
1854  for ( size_t eidx = 0; eidx < __edges.size(); ++eidx )
1855  {
1856  if ( __edges[eidx] == e )
1857  return poly_EdgeHandle( int(eidx) );
1858  }
1859 
1860  return poly_EdgeHandle(Mobius_InvalidHandleIndex);
1861  }
1862 
1870  const poly_VertexHandle& hv1) const
1871  {
1872  return this->FindEdge( poly_Edge(hv0, hv1) );
1873  }
1874 
1882  const poly_TriangleHandle ht1) const
1883  {
1885  //
1886  if ( !this->GetTriangle(ht0, t0) )
1887  return poly_EdgeHandle();
1888  //
1889  if ( !this->GetTriangle(ht1, t1) )
1890  return poly_EdgeHandle();
1891 
1892  poly_VertexHandle a, b, c, d, e, f;
1893  t0.GetVertices(a, b, c);
1894  t1.GetVertices(d, e, f);
1895 
1896  // Get all edges.
1897  poly_Edge t0_edges[3] = { poly_Edge(a, b), poly_Edge(b, c), poly_Edge(c, a) };
1898  poly_Edge t1_edges[3] = { poly_Edge(d, e), poly_Edge(e, f), poly_Edge(f, d) };
1899 
1900  for ( int i = 0; i < 3; ++i )
1901  for ( int j = 0; j < 3; ++j )
1902  if ( t0_edges[i] == t1_edges[j] )
1903  return this->FindEdge(t0_edges[i]);
1904 
1905  return poly_EdgeHandle();
1906  }
1907 
1913  void
1914  FindBoundaryEdges(std::vector<poly_EdgeHandle>& bndEdges,
1915  std::vector<poly_TriangleHandle>& bndTris) const
1916  {
1917  // Extract edges from the computed links.
1918  for ( const auto& linkIt : __links )
1919  {
1920  const poly_EdgeHandle he = linkIt.first;
1921  const std::vector<poly_TriangleHandle>& hts = linkIt.second;
1922 
1923  // Keep alive triangles only.
1924  std::vector<poly_TriangleHandle> alive;
1925  //
1926  for ( const auto& ht : hts )
1927  {
1928  if ( !__triangles[ht.iIdx].IsDeleted() )
1929  alive.push_back(ht);
1930  }
1931 
1932  if ( (alive.size() != 2) || (__triangles[alive[0].iIdx].GetFaceRef() != __triangles[alive[1].iIdx].GetFaceRef()) )
1933  {
1934  bndEdges.push_back(he);
1935 
1936  // Add boundary triangles to the result.
1937  for ( const auto& ht : alive )
1938  bndTris.push_back(ht);
1939  }
1940  }
1941  }
1942 
1947  void
1948  FindDomainEdges(const int domainId,
1949  std::vector<poly_EdgeHandle>& innerEdges,
1950  std::vector<poly_EdgeHandle>& bndEdges) const
1951  {
1952  // Extract edges from the computed links.
1953  for ( const auto& linkIt : __links )
1954  {
1955  const poly_EdgeHandle he = linkIt.first;
1956  const std::vector<poly_TriangleHandle>& hts = linkIt.second;
1957 
1958  // Count the in-domain triangles.
1959  int numDomainTris = 0;
1960  //
1961  for ( const auto& ht : hts )
1962  {
1963  if ( __triangles[ht.iIdx].IsDeleted() )
1964  continue;
1965 
1966  if ( __triangles[ht.iIdx].GetFaceRef() == domainId )
1967  numDomainTris++;
1968  }
1969 
1970  if ( numDomainTris == 1 )
1971  bndEdges.push_back(he);
1972  else if ( numDomainTris == 2 )
1973  innerEdges.push_back(he);
1974  }
1975  }
1976 
1987  const poly_EdgeHandle he,
1988  int& vidx) const
1989  {
1991  //
1992  if ( !this->GetTriangle(ht, t) )
1993  return poly_VertexHandle();
1994 
1995  poly_Edge e;
1996  //
1997  if ( !this->GetEdge(he, e) )
1998  return poly_VertexHandle();
1999 
2000  for ( int i = 0; i < 3; ++i )
2001  for ( int j = 0; j < 2; ++j )
2002  if ( t.hVertices[i] == e.hVertices[j] )
2003  {
2004  vidx = i;
2005  return t.hVertices[i];
2006  }
2007 
2008  return poly_VertexHandle();
2009  }
2010 
2022  bool
2024  const bool checkBorderOn = true,
2025  const bool checkDegenOn = true,
2026  const double prec = core_Precision::Resolution3D(),
2027  const std::unordered_set<int>& domain = std::unordered_set<int>())
2028  {
2029  // Get triangles to remove.
2030  std::unordered_set<poly_TriangleHandle> hts2Remove;
2031  if ( !this->GetTriangles(he, hts2Remove) )
2032  return false;
2033 
2034  if ( checkBorderOn && (hts2Remove.size() < 2) )
2035  return false; // Collapsing a border edge distorts the mesh badly.
2036 
2037  // Get edge to collapse.
2038  poly_Edge e;
2039  if ( !this->GetEdge(he, e) )
2040  return false;
2041 
2042  // Get new vertex position.
2043  t_xyz V[2];
2044  this->GetVertex(e.hVertices[0], V[0]);
2045  this->GetVertex(e.hVertices[1], V[1]);
2046  //
2047  t_xyz Vm = (V[0] + V[1])*0.5;
2048 
2049  /* Check if edge collapse is not going to produce any degenerated triangles */
2050  if ( checkDegenOn )
2051  {
2052  for ( const auto& ht2Remove : hts2Remove )
2053  {
2054  std::unordered_set<poly_TriangleHandle> ths2Edit;
2055  this->FindAdjacentByVertices(ht2Remove, ths2Edit);
2056 
2057  // Get the vertex to survive (the one opposite to the collapsed edge).
2058  const poly_VertexHandle a = this->GetOppositeVertex(ht2Remove, he);
2059 
2060  t_xyz Va;
2061  this->GetVertex(a, Va);
2062 
2063  // Check neighbor triangles.
2064  for ( const auto& th2Check : ths2Edit )
2065  {
2066  // Skip the triangles that are supposed to be removed.
2067  if ( hts2Remove.find(th2Check) != hts2Remove.end() )
2068  continue;
2069 
2070  poly_Triangle<ElemTraits> t2Check;
2071  this->GetTriangle(th2Check, t2Check);
2072 
2073  if ( t2Check.IsDeleted() )
2074  continue;
2075 
2076  std::vector<t_xyz> t2CheckVerts;
2077  int ci = -1;
2078  const poly_VertexHandle c = this->FindVertex(th2Check, he, ci);
2079  //
2080  for ( int j = 0; j < 3; ++j )
2081  {
2082  if ( t2Check.hVertices[j] != c )
2083  {
2084  t_xyz Vj;
2085  this->GetVertex(t2Check.hVertices[j], Vj);
2086 
2087  t2CheckVerts.push_back(Vj);
2088  }
2089  }
2090 
2091  // Virtually move `c` to `Vm` for testing.
2092  t2CheckVerts.push_back(Vm);
2093 
2094  if ( t2CheckVerts.size() != 3 )
2095  continue;
2096 
2097  if ( this->IsDegenerated(t2CheckVerts[0], t2CheckVerts[1], t2CheckVerts[2], prec) )
2098  {
2099  return false;
2100  }
2101  }
2102  }
2103  }
2104 
2105  // If the border is restricted, we first check that edge collapse
2106  // is not going to affect any border triangles.
2107  //
2108  // TODO: we can cache the adjacent triangles to now find them twice
2109  // as we have exactly the same iteration below.
2110  if ( checkBorderOn )
2111  {
2112  // Adjacent face IDs.
2113  std::unordered_set<int> faceIDs;
2114 
2115  for ( const auto& ht2Remove : hts2Remove )
2116  {
2117  std::unordered_set<poly_TriangleHandle> ths2Check;
2118  this->FindAdjacentByVertices(ht2Remove, ths2Check);
2119 
2120  // Check neighbor triangles.
2121  for ( const auto& th2Check : ths2Check )
2122  {
2123  poly_Triangle<ElemTraits> t2Check;
2124  this->GetTriangle(th2Check, t2Check);
2125 
2126  if ( t2Check.IsDeleted() )
2127  continue;
2128 
2129  // Check domain.
2130  if ( !domain.empty() && ( domain.find( t2Check.GetFaceRef() ) == domain.end() ) )
2131  return false; // Do not allow collapsing an edge that would
2132  // affect out-of-domain elements.
2133 
2134  // Remember face ID to check that we're not going to affect multiple faces.
2135  faceIDs.insert( t2Check.GetFaceRef() );
2136 
2138  eh2Check[3] = { t2Check.hEdges[0], t2Check.hEdges[1], t2Check.hEdges[2] };
2139 
2140  for ( int i = 0; i < 3; ++i )
2141  {
2142  const int numEdgeTris = this->CountTriangles(eh2Check[i]);
2143  if ( numEdgeTris != 2 )
2144  return false;
2145  }
2146  }
2147  }
2148 
2149  if ( faceIDs.size() > 1 )
2150  return false; // Edge collapse is not a cross-patch operation.
2151  }
2152 
2153  /* When here, we're sure we can modify the mesh, so let's insert vertices,
2154  edit and remove triangles, etc.
2155  */
2156 
2157  // Add the new vertex.
2158  const poly_VertexHandle hVm = this->AddVertex(Vm);
2159 
2160  // Remove and modify triangles.
2161  for ( const auto& ht2Remove : hts2Remove )
2162  {
2163  std::unordered_set<poly_TriangleHandle> ths2Edit;
2164  this->FindAdjacentByVertices(ht2Remove, ths2Edit);
2165 
2166  // Current triangle to remove.
2167  poly_Triangle<ElemTraits> t2Remove;
2168  this->GetTriangle(ht2Remove, t2Remove);
2169 
2170  // Get the vertex to survive (the one opposite to the collapsed edge).
2171  const poly_VertexHandle a = this->GetOppositeVertex(ht2Remove, he);
2172 
2173  // Add new edge.
2174  const poly_EdgeHandle sharedEdgeHandle = this->AddEdge(a, hVm);
2175 
2176  // Edit neighbor triangles.
2177  for ( const auto& th2Edit : ths2Edit )
2178  {
2179  // Skip the triangles that are supposed to be removed.
2180  if ( hts2Remove.find(th2Edit) != hts2Remove.end() )
2181  continue;
2182 
2183  poly_Triangle<ElemTraits>& t2Edit = this->ChangeTriangle(th2Edit);
2184 
2185  // Find a vertex `c` shared by a triangle to edit and the edge
2186  // being collapsed. That is basically the vertex where the
2187  // dangling edge `he` is attached to the target triangle.
2188  int ci = -1;
2189  const poly_VertexHandle c = this->FindVertex(th2Edit, he, ci);
2190  //
2191  if ( !c.IsValid() )
2192  continue;
2193 
2194  // Move the vertex `c` using the non-const reference to the triangle.
2195  t2Edit.hVertices[ci] = hVm;
2196 
2197  // Edit the edges of the modified triangle.
2198  for ( int ei = 0; ei < 3; ++ei )
2199  {
2200  poly_Edge& e2Edit = __edges[t2Edit.hEdges[ei].iIdx];
2201 
2202  // Check if this edge is going to move.
2203  int vi = -1;
2204  int numVertAffected = 0;
2205  //
2206  for ( int k = 0; k < 3; ++k )
2207  {
2208  if ( e2Edit.hVertices[0] == t2Remove.hVertices[k] )
2209  {
2210  numVertAffected++;
2211  vi = 0;
2212  }
2213 
2214  if ( e2Edit.hVertices[1] == t2Remove.hVertices[k] )
2215  {
2216  numVertAffected++;
2217  vi = 1;
2218  }
2219  }
2220 
2221  // Edit edge.
2222  if ( numVertAffected == 1 )
2223  {
2224  e2Edit.hVertices[vi] = hVm;
2225  }
2226 
2227  // Substitute the edge with the shared one.
2228  if ( numVertAffected == 2 )
2229  {
2230  t2Edit.hEdges[ei] = sharedEdgeHandle;
2231  }
2232  }
2233 
2234  // Add back reference to keep consistent adjacency.
2235  this->ChangeVertex(hVm) .AddTriangleRef(th2Edit);
2236  this->ChangeVertex(e.hVertices[0]).SetDeleted();
2237  this->ChangeVertex(e.hVertices[1]).SetDeleted();
2238  }
2239 
2240  this->RemoveTriangle(ht2Remove);
2241  }
2242 
2243  // Remove edge.
2244  this->RemoveEdge(he);
2245 
2246  return true;
2247  }
2248 
2253  {
2254  // Get the edge to split.
2255  poly_Edge e;
2256  if ( !this->GetEdge(he, e) )
2257  return false;
2258 
2259  // Get the neighbor triangles.
2260  std::vector<poly_TriangleHandle> hts;
2261  if ( !this->FindAdjacent(he, hts) )
2262  return false;
2263 
2264  // Check that we're not touching corners (imagine a box and the
2265  // edges at corners) as edge split is not going to be valid there.
2266  for ( int k = 0; k < 2; ++k )
2267  {
2268  // Find neighbors.
2269  bool isBoundary = false;
2270  std::unordered_set<poly_VertexHandle> adjVerts;
2271  std::unordered_set<int> faceRefs;
2272  std::unordered_set<int> domain;
2273  //
2274  this->FindAdjacent(e.hVertices[0], adjVerts, isBoundary, faceRefs, domain);
2275 
2276  if ( faceRefs.size() > 2 )
2277  return false;
2278  }
2279 
2280  const poly_VertexHandle x = e.hVertices[0];
2281  const poly_VertexHandle y = e.hVertices[1];
2282 
2283  // Get new vertex position.
2284  t_xyz V[2];
2285  this->GetVertex(x, V[0]);
2286  this->GetVertex(y, V[1]);
2287  //
2288  t_xyz Vm = (V[0] + V[1])*0.5;
2289 
2290  // Add the new vertex.
2291  const poly_VertexHandle hVm = this->AddVertex(Vm);
2292 
2293  // Add edges.
2294  poly_EdgeHandle exm = this->AddEdge(x, hVm);
2295  poly_EdgeHandle eym = this->AddEdge(hVm, y);
2296 
2297  // New triangles sharing x, y.
2298  std::vector<poly_TriangleHandle> xths, yths;
2299 
2300  // Split the opposite triangles.
2301  for ( const auto& ht : hts )
2302  {
2303  const poly_VertexHandle hOppVert = this->GetOppositeVertex(ht, he);
2304  //
2305  if ( !hOppVert.IsValid() )
2306  continue;
2307 
2308  // Get triangle.
2310  //
2311  if ( !this->GetTriangle(ht, t) || t.IsDeleted() )
2312  continue;
2313 
2314  /* hOppVert
2315  o
2316  | \
2317  | \
2318  | \
2319  ex | \ ey
2320  | \
2321  | eh \
2322  x o---o---o y
2323  hVm
2324  */
2325 
2326  // Find the existing edges.
2327  poly_EdgeHandle ex, ey;
2328  //
2329  for ( int j = 0; j < 3; ++j )
2330  {
2331  const poly_Edge& te = __edges[t.hEdges[j].iIdx];
2332 
2333  if ( ((te.hVertices[0] == x) && (te.hVertices[1] == hOppVert)) ||
2334  ((te.hVertices[0] == hOppVert) && (te.hVertices[1] == x)) )
2335  {
2336  ex = t.hEdges[j];
2337  }
2338 
2339  if ( ((te.hVertices[0] == y) && (te.hVertices[1] == hOppVert)) ||
2340  ((te.hVertices[0] == hOppVert) && (te.hVertices[1] == y)) )
2341  {
2342  ey = t.hEdges[j];
2343  }
2344  }
2345 
2346  // Add split edge.
2347  poly_EdgeHandle vertEdgeHandle = this->AddEdge(hVm, hOppVert);
2348 
2349  // Compute the reference normal to control the split.
2350  t_xyz refNorm;
2351  this->ComputeNormal(x, y, hOppVert, refNorm);
2352 
2353  // Compute norms to preserve orientations.
2354  t_xyz testNorm[2];
2355  this->ComputeNormal(x, hVm, hOppVert, testNorm[0]);
2356  this->ComputeNormal(hVm, y, hOppVert, testNorm[1]);
2357 
2358  // Split triangle.
2359  poly_TriangleHandle splitHts[2];
2360  //
2361  if ( testNorm[0].Dot(refNorm) > 0 )
2362  {
2363  splitHts[0] = this->AddTriangle( x, hVm, hOppVert, t.GetFaceRef() );
2364  }
2365  else
2366  {
2367  splitHts[0] = this->AddTriangle( hVm, x, hOppVert, t.GetFaceRef() );
2368  }
2369  //
2370  if ( testNorm[1].Dot(refNorm) > 0 )
2371  {
2372  splitHts[1] = this->AddTriangle( hVm, y, hOppVert, t.GetFaceRef() );
2373  }
2374  else
2375  {
2376  splitHts[1] = this->AddTriangle( y, hVm, hOppVert, t.GetFaceRef() );
2377  }
2378 
2379  // Add back references to the edges.
2380  __triangles[splitHts[0].iIdx].hEdges[0] = ex;
2381  __triangles[splitHts[0].iIdx].hEdges[1] = exm;
2382  __triangles[splitHts[0].iIdx].hEdges[2] = vertEdgeHandle;
2383  //
2384  __triangles[splitHts[1].iIdx].hEdges[0] = ey;
2385  __triangles[splitHts[1].iIdx].hEdges[1] = eym;
2386  __triangles[splitHts[1].iIdx].hEdges[2] = vertEdgeHandle;
2387 
2388  xths.push_back(splitHts[0]);
2389  yths.push_back(splitHts[1]);
2390 
2391  // Remove the original triangle.
2392  this->RemoveTriangle(ht);
2393  }
2394 
2395  // Insert new links.
2396  __links.insert({exm, xths});
2397  __links.insert({eym, yths});
2398 
2399  // Remove edge.
2400  this->RemoveEdge(he);
2401 
2402  return true;
2403  }
2404 
2409  void Smooth(const int iter,
2410  const int tag,
2411  const bool checkInter)
2412  {
2413  std::unordered_set<int> domain = {tag};
2414 
2415  // Find adjacent vertices for each vertex.
2416  std::unordered_map< poly_VertexHandle, std::unordered_set<poly_VertexHandle> > adj;
2417  //
2418  for ( VertexIterator vit(this); vit.More(); vit.Next() )
2419  {
2420  const poly_VertexHandle vh = vit.Current();
2421 
2422  // Find neighbors.
2423  bool isBoundary = false;
2424  std::unordered_set<poly_VertexHandle> adjVerts;
2425  std::unordered_set<int> faceRefs;
2426  //
2427  this->FindAdjacent(vh, adjVerts, isBoundary, faceRefs, domain);
2428 
2429  if ( !isBoundary )
2430  adj.insert({vh, adjVerts});
2431  }
2432 
2433  int it = 0;
2434  std::unordered_map<poly_VertexHandle, t_xyz> origCoordsMap;
2435 
2436  // Move each vertex.
2437  while ( it++ < iter )
2438  {
2439  for ( const auto& vTuple : adj )
2440  {
2441  // Get the original coordinates.
2442  t_xyz origCoords;
2443  this->GetVertex(vTuple.first, origCoords);
2444  //
2445  if ( origCoordsMap.find(vTuple.first) == origCoordsMap.end() )
2446  origCoordsMap.insert({vTuple.first, origCoords});
2447 
2448  // Compute the new (average) position.
2449  t_xyz avrg;
2450  int num = 0;
2451  //
2452  for ( const auto& nvs : vTuple.second )
2453  {
2454  t_xyz coord;
2455  this->GetVertex(nvs, coord);
2456 
2457  avrg += coord;
2458  ++num;
2459  }
2460  //
2461  if ( !num )
2462  continue;
2463  //
2464  avrg /= num;
2465 
2466  // Move vertex.
2467  this->ChangeVertex(vTuple.first).ChangeCoords() = avrg;
2468  }
2469  }
2470 
2471  // Check for possible intersections.
2472  if ( checkInter )
2473  {
2474  // Get all edge handles for intersection test.
2475  std::vector<poly_EdgeHandle> innerEdges, bndEdges;
2476  this->FindDomainEdges(tag, innerEdges, bndEdges);
2477 
2478  if ( this->AreSelfIntersecting(tag, innerEdges, bndEdges) )
2479  {
2480  // Restore the original positions.
2481  for ( const auto& tuple : origCoordsMap )
2482  this->ChangeVertex(tuple.first).ChangeCoords() = tuple.second;
2483  }
2484  }
2485  }
2486 
2491  void
2492  Smooth(const int iter = 1,
2493  const std::unordered_set<int>& domain = std::unordered_set<int>(),
2494  const bool checkInter = false)
2495  {
2496  for ( auto tag : domain )
2497  this->Smooth(iter, tag, checkInter);
2498  }
2499 
2500 public:
2501 
2507  poly_Vertex& vertex) const
2508  {
2509  const int idx = h.GetIdx();
2510  if ( idx < 0 || idx > int( __vertices.size() ) ) return false;
2511  //
2512  vertex = __vertices[idx];
2513  return true;
2514  }
2515 
2521  t_xyz& vertex) const
2522  {
2523  const int idx = h.GetIdx();
2524  if ( idx < 0 || idx > int( __vertices.size() ) ) return false;
2525  //
2526  vertex = __vertices[idx];
2527  return true;
2528  }
2529 
2535  {
2536  return __vertices[h.iIdx];
2537  }
2538 
2543  bool GetEdge(const poly_EdgeHandle h,
2544  poly_Edge& edge) const
2545  {
2546  const int idx = h.GetIdx();
2547  if ( idx < 0 || idx > int( __edges.size() ) ) return false;
2548  //
2549  edge = __edges[idx];
2550  return true;
2551  }
2552 
2558  poly_Triangle<ElemTraits>& triangle) const
2559  {
2560  const int idx = h.GetIdx();
2561  if ( idx < 0 || idx > int( __triangles.size() ) ) return false;
2562  //
2563  triangle = __triangles[idx];
2564  return true;
2565  }
2566 
2572  {
2573  return __triangles[h.iIdx];
2574  }
2575 
2580  bool GetQuad(const poly_QuadHandle h,
2581  poly_Quad& quad) const
2582  {
2583  const int idx = h.GetIdx();
2584  if ( idx < 0 || idx > int( __quads.size() ) ) return false;
2585  //
2586  quad = __quads[idx];
2587  return true;
2588  }
2589 
2593  {
2594  return this->AddVertex( core_XYZ::O() );
2595  }
2596 
2603  const double y,
2604  const double z)
2605  {
2606  return this->AddVertex( core_XYZ(x, y, z) );
2607  }
2608 
2613  {
2614  __vertices.push_back( poly_Vertex(coords) );
2615  poly_VertexHandle hVertex( int( __vertices.size() ) - 1 );
2616  return hVertex;
2617  }
2618 
2622  {
2623  poly_VertexHandle inv;
2624  return this->AddEdge(inv, inv);
2625  }
2626 
2632  const poly_VertexHandle hFinishV)
2633  {
2634  __edges.push_back( poly_Edge(hStartV, hFinishV) );
2635  poly_EdgeHandle hEdge( int( __edges.size() ) - 1 );
2636  return hEdge;
2637  }
2638 
2642  {
2643  __edges.push_back(edge);
2644  poly_EdgeHandle hEdge( int( __edges.size() ) - 1 );
2645  return hEdge;
2646  }
2647 
2652  {
2653  const int idx = h.GetIdx();
2654  if ( idx < 0 || idx > int( __edges.size() ) ) return false;
2655 
2656  __edges[idx].SetDeleted();
2657  return true;
2658  }
2659 
2663  {
2664  poly_VertexHandle inv;
2665  return this->AddTriangle(inv, inv, inv);
2666  }
2667 
2674  const poly_VertexHandle hV1,
2675  const poly_VertexHandle hV2)
2676  {
2677  __triangles.push_back( poly_Triangle<ElemTraits>(hV0, hV1, hV2) );
2678  poly_TriangleHandle hTriangle( int( __triangles.size() ) - 1 );
2679 
2680  // Add back references to the vertices.
2681  __vertices[hV0.iIdx].AddTriangleRef(hTriangle);
2682  __vertices[hV1.iIdx].AddTriangleRef(hTriangle);
2683  __vertices[hV2.iIdx].AddTriangleRef(hTriangle);
2684 
2685  return hTriangle;
2686  }
2687 
2695  const poly_VertexHandle hV1,
2696  const poly_VertexHandle hV2,
2697  const int ref)
2698  {
2699  __triangles.push_back( poly_Triangle<ElemTraits>(hV0, hV1, hV2, ref) );
2700  poly_TriangleHandle hTriangle( int( __triangles.size() ) - 1 );
2701 
2702  // Add back references to the vertices.
2703  __vertices[hV0.iIdx].AddTriangleRef(hTriangle);
2704  __vertices[hV1.iIdx].AddTriangleRef(hTriangle);
2705  __vertices[hV2.iIdx].AddTriangleRef(hTriangle);
2706 
2707  return hTriangle;
2708  }
2709 
2714  {
2715  const int idx = h.GetIdx();
2716  if ( idx < 0 || idx > int( __triangles.size() ) ) return false;
2717 
2718  __triangles[idx].SetDeleted();
2719  return true;
2720  }
2721 
2725  {
2726  poly_VertexHandle inv;
2727  return this->AddQuad(inv, inv, inv, inv);
2728  }
2729 
2737  const poly_VertexHandle hV1,
2738  const poly_VertexHandle hV2,
2739  const poly_VertexHandle hV3)
2740  {
2741  __quads.push_back( poly_Quad(hV0, hV1, hV2, hV3) );
2742  poly_QuadHandle hQuad( int( __quads.size() ) - 1 );
2743  return hQuad;
2744  }
2745 
2747  int GetNumVertices() const
2748  {
2749  return int( __vertices.size() );
2750  }
2751 
2753  int GetNumEdges() const
2754  {
2755  return int( __edges.size() );
2756  }
2757 
2761  int GetNumTriangles(const bool includeDeads = false) const
2762  {
2763  if ( includeDeads )
2764  return int( __triangles.size() );
2765 
2766  int count = 0;
2767  for ( const auto& tri : __triangles )
2768  if ( !tri.IsDeleted() )
2769  count++;
2770 
2771  return count;
2772  }
2773 
2775  int GetNumQuads() const
2776  {
2777  return int( __quads.size() );
2778  }
2779 
2780 public:
2781 
2784  {
2785  public:
2786 
2788  VertexIterator(const t_ptr<poly_Mesh<ElemTraits>>& mesh) : m_mesh(mesh), m_pos(0) {}
2789 
2790  public:
2791 
2792  bool More() const { return m_pos < m_mesh->__vertices.size(); }
2793  void Next() { m_pos++; }
2794  poly_VertexHandle Current() const { return poly_VertexHandle( int(m_pos) ); }
2795 
2796  private:
2797 
2798  t_ptr<poly_Mesh<ElemTraits>> m_mesh;
2799  size_t m_pos;
2800  };
2801 
2804  {
2805  public:
2806 
2808  EdgeIterator(const t_ptr<poly_Mesh<ElemTraits>>& mesh) : m_mesh(mesh), m_pos(0) {}
2809 
2810  public:
2811 
2812  bool More() const { return m_pos < m_mesh->__edges.size(); }
2813  void Next() { m_pos++; }
2814  poly_EdgeHandle Current() const { return poly_EdgeHandle( int(m_pos) ); }
2815 
2816  private:
2817 
2818  t_ptr<poly_Mesh<ElemTraits>> m_mesh;
2819  size_t m_pos;
2820  };
2821 
2824  {
2825  public:
2826 
2828  TriangleIterator(const t_ptr<poly_Mesh<ElemTraits>>& mesh) : m_mesh(mesh), m_pos(0) {}
2829 
2830  public:
2831 
2832  bool More() const { return m_pos < m_mesh->__triangles.size(); }
2833  void Next() { m_pos++; }
2834  poly_TriangleHandle Current() const { return poly_TriangleHandle( int(m_pos) ); }
2835 
2836  private:
2837 
2838  t_ptr<poly_Mesh<ElemTraits>> m_mesh;
2839  size_t m_pos;
2840  };
2841 
2844  {
2845  public:
2846 
2848  QuadIterator(const t_ptr<poly_Mesh<ElemTraits>>& mesh) : m_mesh(mesh), m_pos(0) {}
2849 
2850  public:
2851 
2852  bool More() const { return m_pos < m_mesh->__quads.size(); }
2853  void Next() { m_pos++; }
2854  poly_QuadHandle Current() const { return poly_QuadHandle( int(m_pos) ); }
2855 
2856  private:
2857 
2858  t_ptr<poly_Mesh<ElemTraits>> m_mesh;
2859  size_t m_pos;
2860  };
2861 
2862 protected:
2863 
2865  void
2867  const poly_TriangleHandle htOld,
2868  const poly_TriangleHandle htNew)
2869  {
2870  auto link = __links.find(he);
2871  //
2872  if ( link == __links.end() )
2873  return; // No such link.
2874 
2875  std::vector<poly_TriangleHandle> newTuple;
2876  //
2877  for ( const auto& ht : link->second )
2878  {
2879  if ( ht == htOld )
2880  newTuple.push_back(htNew);
2881  else
2882  newTuple.push_back(ht);
2883  }
2884  //
2885  __links[he] = newTuple;
2886  }
2887 
2888 public:
2889 
2890  std::vector<poly_Vertex> __vertices;
2891  std::vector<poly_Edge> __edges;
2892  std::vector<poly_Triangle<ElemTraits>> __triangles;
2893  std::vector<poly_Quad> __quads;
2894 
2896  std::unordered_map< poly_EdgeHandle, std::vector<poly_TriangleHandle> > __links;
2897 
2899  t_ptr<poly_SurfAdapter> __surfAdt;
2900 
2901 };
2902 
2905 
2906 }
2907 
2908 #endif
mobius::poly_MeshUtils::ComputeArea
static mobiusPoly_EXPORT double ComputeArea(const t_xyz &v0, const t_xyz &v1, const t_xyz &v2)
mobius::poly_EdgeHandle
Definition: poly_Handles.h:129
mobius::poly_Mesh::ComputeNormal
bool ComputeNormal(const poly_VertexHandle hv0, const poly_VertexHandle hv1, const poly_VertexHandle hv2, t_xyz &norm) const
Definition: poly_Mesh.h:934
mobius::poly_Vertex
Definition: poly_Vertex.h:51
mobius::poly_Mesh::IsDegenerated
bool IsDegenerated(const t_xyz &v0, const t_xyz &v1, const t_xyz &v2, const double prec) const
Definition: poly_Mesh.h:1089
mobius::poly_Mesh::Subdivide
bool Subdivide(const poly_TriangleHandle ht)
Definition: poly_Mesh.h:1174
mobius
Defines an exception class C1 that inherits an exception class C2.
Definition: bspl_Decompose.h:41
mobius::poly_Triangle::hEdges
poly_EdgeHandle hEdges[3]
Handles to the edges.
Definition: poly_Triangle.h:173
mobius::poly_Mesh::IsDegenerated
bool IsDegenerated(const poly_TriangleHandle ht, const double prec) const
Definition: poly_Mesh.h:1148
mobius::core_XYZ
Definition: core_XYZ.h:45
mobius::core_IAlgorithm
Definition: core_IAlgorithm.h:43
mobius::poly_QuadHandle
Definition: poly_Handles.h:155
mobius::poly_Mesh::GetEdge
bool GetEdge(const poly_EdgeHandle h, poly_Edge &edge) const
Definition: poly_Mesh.h:2543
mobius::poly_Mesh::__surfAdt
t_ptr< poly_SurfAdapter > __surfAdt
CAD surface adapter.
Definition: poly_Mesh.h:2899
mobius::poly_Mesh::AddQuad
poly_QuadHandle AddQuad()
Definition: poly_Mesh.h:2724
mobius::poly_Mesh::AddQuad
poly_QuadHandle AddQuad(const poly_VertexHandle hV0, const poly_VertexHandle hV1, const poly_VertexHandle hV2, const poly_VertexHandle hV3)
Definition: poly_Mesh.h:2736
mobius::poly_Mesh::ExtractRegion
t_ptr< poly_Mesh< ElemTraits > > ExtractRegion(const std::unordered_set< int > &tids) const
Definition: poly_Mesh.h:200
mobius::poly_Mesh::FindAdjacentByEdges
bool FindAdjacentByEdges(const poly_TriangleHandle ht, std::vector< poly_TriangleHandle > &hts) const
Definition: poly_Mesh.h:1359
mobius::poly_Triangle::GetFaceRef
int GetFaceRef() const
Definition: poly_Triangle.h:141
mobius::poly_Mesh::CollapseEdge
bool CollapseEdge(const poly_EdgeHandle he, const bool checkBorderOn=true, const bool checkDegenOn=true, const double prec=core_Precision::Resolution3D(), const std::unordered_set< int > &domain=std::unordered_set< int >())
Definition: poly_Mesh.h:2023
mobius::poly_Mesh::ComputeCenter
core_XYZ ComputeCenter() const
Definition: poly_Mesh.h:504
mobius::poly_Mesh::AddEdge
poly_EdgeHandle AddEdge(const poly_VertexHandle hStartV, const poly_VertexHandle hFinishV)
Definition: poly_Mesh.h:2631
mobius::poly_Edge::hVertices
poly_VertexHandle hVertices[2]
Handles to the vertices.
Definition: poly_Edge.h:93
mobius::poly_Mesh::QuadIterator
Iterator for quads.
Definition: poly_Mesh.h:2843
mobius::core_PlotterEntry
Definition: core_IPlotter.h:252
mobius::poly_Mesh::Smooth
void Smooth(const int iter=1, const std::unordered_set< int > &domain=std::unordered_set< int >(), const bool checkInter=false)
Definition: poly_Mesh.h:2492
mobius::poly_Mesh::RemoveEdge
bool RemoveEdge(const poly_EdgeHandle h)
Definition: poly_Mesh.h:2651
mobius::poly_TriangleHandle
Definition: poly_Handles.h:142
mobius::poly_Mesh::QuadIterator::QuadIterator
QuadIterator(const t_ptr< poly_Mesh< ElemTraits >> &mesh)
Ctor accepting mesh.
Definition: poly_Mesh.h:2848
mobius::poly_Mesh::GetVertex
bool GetVertex(const poly_VertexHandle h, t_xyz &vertex) const
Definition: poly_Mesh.h:2520
mobius::poly_MeshUtils::ComputePyramidProps
static mobiusPoly_EXPORT bool ComputePyramidProps(const t_xyz &v0, const t_xyz &v1, const t_xyz &v2, const core_XYZ &apex, double gProps[10], const int nbPnts, const double *pnts)
mobius::poly_Mesh::OnePoint
@ OnePoint
Definition: poly_Mesh.h:134
mobius::poly_Mesh::GetTriangle
bool GetTriangle(const poly_TriangleHandle h, poly_Triangle< ElemTraits > &triangle) const
Definition: poly_Mesh.h:2557
mobius::poly_Triangle
Definition: poly_Triangle.h:48
mobius::poly_Mesh::ComputeNormal
bool ComputeNormal(const poly_TriangleHandle ht, t_xyz &norm) const
Definition: poly_Mesh.h:974
mobius::poly_Mesh::FindAdjacentByEdges
bool FindAdjacentByEdges(const poly_TriangleHandle ht, std::unordered_set< poly_TriangleHandle > &hts) const
Definition: poly_Mesh.h:1378
mobius::poly_Quad
Definition: poly_Quad.h:45
mobius::poly_BaseHandle::IsValid
bool IsValid() const
The handle is valid iff the index is not negative.
Definition: poly_Handles.h:63
mobius::poly_Mesh::__quads
std::vector< poly_Quad > __quads
List of quads.
Definition: poly_Mesh.h:2893
mobius::poly_Mesh::AddVertex
poly_VertexHandle AddVertex()
Definition: poly_Mesh.h:2592
mobius::core_ProgressEntry
Definition: core_IProgressNotifier.h:193
mobius::poly_Mesh::CanFlip
bool CanFlip(const poly_EdgeHandle he, const double normDevRad, const double planeDevRad, const bool checkJacobian, const bool checkWing, poly_TriangleHandle &ht0, poly_TriangleHandle &ht1, poly_VertexHandle &a, poly_VertexHandle &b, poly_VertexHandle &x, poly_VertexHandle &y, t_xyz &norm0, t_xyz &norm1) const
Definition: poly_Mesh.h:1585
mobius::poly_Mesh::GetTriangles
bool GetTriangles(const poly_EdgeHandle he, std::unordered_set< poly_TriangleHandle > &hts) const
Definition: poly_Mesh.h:1340
mobius::poly_Triangle::CopyWithoutTraits
poly_Triangle CopyWithoutTraits() const
Makes a copy of this triangle without traits.
Definition: poly_Triangle.h:105
mobius::poly_Mesh::DeepCopyWithoutTraits
t_ptr< poly_Mesh<> > DeepCopyWithoutTraits()
Definition: poly_Mesh.h:157
mobius::poly_Mesh::ClearEdges
void ClearEdges()
Cleans up the available edge info.
Definition: poly_Mesh.h:1299
mobius::poly_Mesh::GetQuad
bool GetQuad(const poly_QuadHandle h, poly_Quad &quad) const
Definition: poly_Mesh.h:2580
mobius::poly_Mesh::CountTriangles
int CountTriangles(const poly_EdgeHandle he) const
Definition: poly_Mesh.h:1308
mobius::poly_Mesh::FindAdjacent
void FindAdjacent(const poly_VertexHandle hv, std::unordered_set< poly_VertexHandle > &hvs, bool &isBoundary, std::unordered_set< int > &faceRefs, const std::unordered_set< int > &domain) const
Definition: poly_Mesh.h:1452
mobius::poly_Mesh::GetVertex
bool GetVertex(const poly_VertexHandle h, poly_Vertex &vertex) const
Definition: poly_Mesh.h:2506
mobius::poly_Mesh::ComputeArea
double ComputeArea()
Definition: poly_Mesh.h:564
mobius::poly_Mesh::GetNumEdges
int GetNumEdges() const
Definition: poly_Mesh.h:2753
mobius::poly_Mesh::ChangeVertex
poly_Vertex & ChangeVertex(const poly_VertexHandle h)
Definition: poly_Mesh.h:2534
mobius::poly_Mesh::__edges
std::vector< poly_Edge > __edges
List of edges.
Definition: poly_Mesh.h:2891
mobius::poly_Mesh::GetBounds
void GetBounds(double &xMin, double &xMax, double &yMin, double &yMax, double &zMin, double &zMax) const
Definition: poly_Mesh.h:464
mobius::poly_Mesh::VertexIterator::VertexIterator
VertexIterator(const t_ptr< poly_Mesh< ElemTraits >> &mesh)
Ctor accepting mesh.
Definition: poly_Mesh.h:2788
mobius::poly_Mesh::AreSelfIntersecting
mobiusPoly_EXPORT bool AreSelfIntersecting(const int tag, const poly_EdgeHandle eh0, const poly_EdgeHandle eh1) const
mobius::poly_Mesh::FindEdge
poly_EdgeHandle FindEdge(const poly_VertexHandle &hv0, const poly_VertexHandle &hv1) const
Definition: poly_Mesh.h:1869
mobius::poly_Mesh::FindAdjacent
void FindAdjacent(const poly_VertexHandle hv, std::unordered_set< poly_TriangleHandle > &hts, const std::unordered_set< int > &domain=std::unordered_set< int >()) const
Definition: poly_Mesh.h:1426
mobius::poly_Mesh::AddVertex
poly_VertexHandle AddVertex(const double x, const double y, const double z)
Definition: poly_Mesh.h:2602
mobius::poly_Mesh::ComputeCComponents
void ComputeCComponents(std::vector< std::unordered_set< poly_TriangleHandle > > &ccomps)
Definition: poly_Mesh.h:377
mobius::poly_Mesh::AddEdge
poly_EdgeHandle AddEdge()
Definition: poly_Mesh.h:2621
mobius::poly_Vertex::ChangeCoords
core_XYZ & ChangeCoords()
Definition: poly_Vertex.h:83
mobius::poly_Mesh::RefineByMidpoint
bool RefineByMidpoint(const poly_TriangleHandle ht)
Definition: poly_Mesh.h:687
mobius::poly_Mesh::TriangleIterator::TriangleIterator
TriangleIterator(const t_ptr< poly_Mesh< ElemTraits >> &mesh)
Ctor accepting mesh.
Definition: poly_Mesh.h:2828
mobius::poly_Triangle::hVertices
poly_VertexHandle hVertices[3]
Handles to the vertices.
Definition: poly_Triangle.h:172
mobius::poly_Mesh::Smooth
void Smooth(const int iter, const int tag, const bool checkInter)
Definition: poly_Mesh.h:2409
mobius::poly_Mesh::Merge
void Merge(const t_ptr< poly_Mesh< ElemTraits > > &other)
Definition: poly_Mesh.h:288
mobius::poly_Mesh::SetSurfAdapter
void SetSurfAdapter(const t_ptr< poly_SurfAdapter > &adt)
Definition: poly_Mesh.h:419
mobius::poly_Mesh::__links
std::unordered_map< poly_EdgeHandle, std::vector< poly_TriangleHandle > > __links
Edges-to-triangles map.
Definition: poly_Mesh.h:2896
mobius::poly_Mesh::ComputeMaxLen
double ComputeMaxLen(const poly_TriangleHandle ht) const
Definition: poly_Mesh.h:1058
mobius::poly_Triangle::GetVertices
void GetVertices(poly_VertexHandle &hv0, poly_VertexHandle &hv1, poly_VertexHandle &hv2) const
Definition: poly_Triangle.h:124
mobius::poly_Mesh::EdgeIterator::EdgeIterator
EdgeIterator(const t_ptr< poly_Mesh< ElemTraits >> &mesh)
Ctor accepting mesh.
Definition: poly_Mesh.h:2808
mobius::t_mesh
poly_Mesh t_mesh
Convenience shortcut for mesh with default traits.
Definition: poly_Mesh.h:2904
mobius::poly_Mesh::GrowRegion
void GrowRegion(const poly_TriangleHandle th, const t_adjacencyMx &mx, std::unordered_set< poly_TriangleHandle > &region)
Definition: poly_Mesh.h:322
mobius::poly_Mesh::FindAdjacent
bool FindAdjacent(const poly_EdgeHandle he, std::vector< poly_TriangleHandle > &hts) const
Definition: poly_Mesh.h:1532
mobius::poly_MeshUtils::ComputeCenter
static mobiusPoly_EXPORT void ComputeCenter(const t_xyz &v0, const t_xyz &v1, const t_xyz &v2, t_xyz &center)
mobius::poly_MeshUtils
Definition: poly_Mesh.h:63
mobius::poly_Edge::IsDeleted
bool IsDeleted() const
Definition: poly_Edge.h:79
mobius::poly_Vertex::AddTriangleRef
void AddTriangleRef(const poly_TriangleHandle ht)
Definition: poly_Vertex.h:108
mobius::poly_Mesh::t_adjacencyMx
std::map< poly_TriangleHandle, std::unordered_set< poly_TriangleHandle > > t_adjacencyMx
Adjacency matrix for triangles.
Definition: poly_Mesh.h:141
mobius::poly_Mesh::SplitEdge
bool SplitEdge(const poly_EdgeHandle he)
Definition: poly_Mesh.h:2252
mobius::poly_BaseHandle::iIdx
int iIdx
0-based index of the handle.
Definition: poly_Handles.h:107
mobius::poly_Mesh::RefineByMidedges
bool RefineByMidedges(const poly_TriangleHandle ht)
Definition: poly_Mesh.h:889
mobius::poly_Mesh::ComputeProps
void ComputeProps(const PropsComputationDensity density, double &volume, core_XYZ &firstAxisOfInertia, core_XYZ &secondAxisOfInertia, core_XYZ &thirdAxisOfInertia) const
Definition: poly_Mesh.h:585
mobius::poly_Mesh::GetNumVertices
int GetNumVertices() const
Definition: poly_Mesh.h:2747
mobius::poly_Mesh::ComputeScaledJacobian
double ComputeScaledJacobian(const poly_TriangleHandle ht) const
Definition: poly_Mesh.h:995
mobius::poly_Mesh::VertexIterator
Iterator for vertices.
Definition: poly_Mesh.h:2783
mobius::poly_Mesh::GetNumQuads
int GetNumQuads() const
Definition: poly_Mesh.h:2775
mobius::poly_Mesh::AddEdge
poly_EdgeHandle AddEdge(const poly_Edge &edge)
Definition: poly_Mesh.h:2641
mobius::poly_Mesh::RefineByMidedges
bool RefineByMidedges(const poly_TriangleHandle ht, std::vector< poly_TriangleHandle > &hts)
Definition: poly_Mesh.h:698
mobius::poly_Mesh::FindEdge
poly_EdgeHandle FindEdge(const poly_Edge &e) const
Definition: poly_Mesh.h:1852
mobius::poly_Mesh::ComputeScaledJacobian
double ComputeScaledJacobian(const t_xyz &v0, const t_xyz &v1, const t_xyz &v2) const
Definition: poly_Mesh.h:1034
mobius::poly_Mesh
Definition: poly_Mesh.h:126
mobius::poly_Mesh::DeepCopy
t_ptr< poly_Mesh > DeepCopy() const
Definition: poly_Mesh.h:179
mobius::poly_MeshUtils::ComputeNormal
static mobiusPoly_EXPORT bool ComputeNormal(const t_xyz &v0, const t_xyz &v1, const t_xyz &v2, t_xyz &norm)
mobius::poly_Mesh::RemoveTriangle
bool RemoveTriangle(const poly_TriangleHandle h)
Definition: poly_Mesh.h:2713
mobius::poly_Mesh::AddVertex
poly_VertexHandle AddVertex(const core_XYZ &coords)
Definition: poly_Mesh.h:2612
mobius::poly_Mesh::TriangleIterator
Iterator for triangles.
Definition: poly_Mesh.h:2823
mobius::poly_Mesh::PropsComputationDensity
PropsComputationDensity
Precision of Gauss cubature formulas.
Definition: poly_Mesh.h:131
mobius::poly_Mesh::AddTriangle
poly_TriangleHandle AddTriangle(const poly_VertexHandle hV0, const poly_VertexHandle hV1, const poly_VertexHandle hV2)
Definition: poly_Mesh.h:2673
mobius::poly_Mesh::poly_Mesh
poly_Mesh(core_ProgressEntry progress=nullptr, core_PlotterEntry plotter=nullptr)
Default ctor with optional diagnostic tools.
Definition: poly_Mesh.h:147
mobius::poly_Mesh::ThreePoints
@ ThreePoints
Definition: poly_Mesh.h:137
mobius::poly_Triangle::IsDeleted
bool IsDeleted() const
Definition: poly_Triangle.h:165
mobius::poly_Mesh::FindBoundaryEdges
void FindBoundaryEdges(std::vector< poly_EdgeHandle > &bndEdges, std::vector< poly_TriangleHandle > &bndTris) const
Definition: poly_Mesh.h:1914
mobius::poly_Mesh::ComputeCenter
void ComputeCenter(const poly_VertexHandle hv0, const poly_VertexHandle hv1, const poly_VertexHandle hv2, t_xyz &center) const
Definition: poly_Mesh.h:954
mobius::poly_Mesh::FindAdjacentByVertices
void FindAdjacentByVertices(const poly_TriangleHandle ht, std::unordered_set< poly_TriangleHandle > &hts) const
Definition: poly_Mesh.h:1551
mobius::poly_Mesh::__triangles
std::vector< poly_Triangle< ElemTraits > > __triangles
List of triangles.
Definition: poly_Mesh.h:2892
mobius::poly_Mesh::FindVertex
poly_VertexHandle FindVertex(const poly_TriangleHandle ht, const poly_EdgeHandle he, int &vidx) const
Definition: poly_Mesh.h:1986
mobius::poly_Mesh::GetTriangles
bool GetTriangles(const poly_EdgeHandle he, std::vector< poly_TriangleHandle > &hts) const
Definition: poly_Mesh.h:1323
mobius::poly_Mesh::CanFlip
bool CanFlip(const poly_EdgeHandle he, const double normDevRad=1./180.*M_PI, const double planeDevRad=15./180.*M_PI, const bool checkJacobian=true, const bool checkWing=true) const
Definition: poly_Mesh.h:1741
mobius::poly_Mesh::ChangeTriangle
poly_Triangle< ElemTraits > & ChangeTriangle(const poly_TriangleHandle h)
Definition: poly_Mesh.h:2571
mobius::poly_Mesh::GrowRegion
void GrowRegion(const poly_TriangleHandle th, std::unordered_set< poly_TriangleHandle > &region)
Definition: poly_Mesh.h:357
mobius::poly_Mesh::FindDomainEdges
void FindDomainEdges(const int domainId, std::vector< poly_EdgeHandle > &innerEdges, std::vector< poly_EdgeHandle > &bndEdges) const
Definition: poly_Mesh.h:1948
mobius::poly_Mesh::AddTriangle
poly_TriangleHandle AddTriangle()
Definition: poly_Mesh.h:2662
mobius::poly_Vertex::SetDeleted
void SetDeleted()
Flags this vertex as deleted.
Definition: poly_Vertex.h:141
mobius::poly_Mesh::__vertices
std::vector< poly_Vertex > __vertices
List of vertices.
Definition: poly_Mesh.h:2890
mobius::poly_Mesh::RefineByMidpoint
bool RefineByMidpoint(const poly_TriangleHandle ht, poly_TriangleHandle &ht0, poly_TriangleHandle &ht1, poly_TriangleHandle &ht2)
Definition: poly_Mesh.h:645
mobius::poly_Mesh::GetOppositeVertex
poly_VertexHandle GetOppositeVertex(const poly_TriangleHandle ht, const poly_EdgeHandle he) const
Definition: poly_Mesh.h:901
mobius::poly_Mesh::FlipEdges
int FlipEdges(const double normDevRad=1./180.*M_PI, const double planeDevRad=15./180.*M_PI)
Definition: poly_Mesh.h:1829
mobius::poly_Mesh::FlipEdge
bool FlipEdge(const poly_EdgeHandle he, const double normDevRad=1./180.*M_PI, const double planeDevRad=15./180.*M_PI, const bool checkJacobian=true, const bool checkWing=true)
Definition: poly_Mesh.h:1768
mobius::poly_Mesh::ComputeArea
double ComputeArea(const poly_TriangleHandle ht) const
Definition: poly_Mesh.h:547
mobius::poly_Edge
Definition: poly_Edge.h:43
mobius::core_UV
Definition: core_UV.h:42
mobius::poly_Mesh::ComputeEdges
void ComputeEdges()
Definition: poly_Mesh.h:1218
mobius::poly_Mesh::ComputeArea
double ComputeArea(const poly_VertexHandle hv0, const poly_VertexHandle hv1, const poly_VertexHandle hv2) const
Definition: poly_Mesh.h:531
mobius::poly_Mesh::GetNumTriangles
int GetNumTriangles(const bool includeDeads=false) const
Definition: poly_Mesh.h:2761
mobius::poly_Mesh::FindEdge
poly_EdgeHandle FindEdge(const poly_TriangleHandle ht0, const poly_TriangleHandle ht1) const
Definition: poly_Mesh.h:1881
mobius::poly_Mesh::AddTriangle
poly_TriangleHandle AddTriangle(const poly_VertexHandle hV0, const poly_VertexHandle hV1, const poly_VertexHandle hV2, const int ref)
Definition: poly_Mesh.h:2694
mobius::poly_Mesh::EdgeIterator
Iterator for edges.
Definition: poly_Mesh.h:2803
mobius::poly_Jacobian::Compute
static mobiusPoly_EXPORT bool Compute(const t_xyz &P0, const t_xyz &P1, const t_xyz &P2, const int zeroBasedNodeId, t_uv &p0, t_uv &p1, t_uv &p2, double J[][2], double &J_det, double &J_det_normalized)
mobius::poly_Mesh::updateLink
void updateLink(const poly_EdgeHandle he, const poly_TriangleHandle htOld, const poly_TriangleHandle htNew)
Updates the existing link by exchanging htOld with htNew.
Definition: poly_Mesh.h:2866
mobius::poly_VertexHandle
Definition: poly_Handles.h:116