triSurfaceTools.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2016-2022 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "triSurfaceTools.H"
30 #include "triSurface.H"
31 #include "MeshedSurface.H"
32 #include "OFstream.H"
33 #include "mergePoints.H"
34 #include "polyMesh.H"
35 #include "plane.H"
36 #include "geompack.H"
37 
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 
40 const Foam::label Foam::triSurfaceTools::ANYEDGE = -1;
41 const Foam::label Foam::triSurfaceTools::NOEDGE = -2;
42 const Foam::label Foam::triSurfaceTools::COLLAPSED = -3;
43 
44 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
45 
46 /*
47  Refine by splitting all three edges of triangle ('red' refinement).
48  Neighbouring triangles (which are not marked for refinement get split
49  in half ('green') refinement. (R. Verfuerth, "A review of a posteriori
50  error estimation and adaptive mesh refinement techniques",
51  Wiley-Teubner, 1996)
52 */
53 
54 // Facei gets refined ('red'). Propagate edge refinement.
55 void Foam::triSurfaceTools::calcRefineStatus
56 (
57  const triSurface& surf,
58  const label facei,
59  List<refineType>& refine
60 )
61 {
62  if (refine[facei] == RED)
63  {
64  // Already marked for refinement. Do nothing.
65  }
66  else
67  {
68  // Not marked or marked for 'green' refinement. Refine.
69  refine[facei] = RED;
70 
71  const labelList& myNeighbours = surf.faceFaces()[facei];
72 
73  for (const label neighbourFacei : myNeighbours)
74  {
75  if (refine[neighbourFacei] == GREEN)
76  {
77  // Change to red refinement and propagate
78  calcRefineStatus(surf, neighbourFacei, refine);
79  }
80  else if (refine[neighbourFacei] == NONE)
81  {
82  refine[neighbourFacei] = GREEN;
83  }
84  }
85  }
86 }
87 
88 
89 // Split facei along edgeI at position newPointi
90 void Foam::triSurfaceTools::greenRefine
91 (
92  const triSurface& surf,
93  const label facei,
94  const label edgeI,
95  const label newPointi,
96  DynamicList<labelledTri>& newFaces
97 )
98 {
99  const labelledTri& f = surf.localFaces()[facei];
100  const edge& e = surf.edges()[edgeI];
101 
102  // Find index of edge in face.
103 
104  label fp0 = f.find(e[0]);
105  label fp1 = f.fcIndex(fp0);
106  label fp2 = f.fcIndex(fp1);
107 
108  if (f[fp1] == e[1])
109  {
110  // Edge oriented like face
111  newFaces.append
112  (
113  labelledTri
114  (
115  f[fp0],
116  newPointi,
117  f[fp2],
118  f.region()
119  )
120  );
121  newFaces.append
122  (
123  labelledTri
124  (
125  newPointi,
126  f[fp1],
127  f[fp2],
128  f.region()
129  )
130  );
131  }
132  else
133  {
134  newFaces.append
135  (
136  labelledTri
137  (
138  f[fp2],
139  newPointi,
140  f[fp1],
141  f.region()
142  )
143  );
144  newFaces.append
145  (
146  labelledTri
147  (
148  newPointi,
149  f[fp0],
150  f[fp1],
151  f.region()
152  )
153  );
154  }
155 }
156 
157 
158 // Refine all triangles marked for refinement.
159 Foam::triSurface Foam::triSurfaceTools::doRefine
160 (
161  const triSurface& surf,
162  const List<refineType>& refineStatus
163 )
164 {
165  // Storage for new points. (start after old points)
166  label newVertI = surf.nPoints();
167 
168  DynamicList<point> newPoints(newVertI);
169  newPoints.append(surf.localPoints());
170 
171  // Storage for new faces
172  DynamicList<labelledTri> newFaces(surf.size());
173 
174 
175  // Point index for midpoint on edge
176  labelList edgeMid(surf.nEdges(), -1);
177 
178  forAll(refineStatus, facei)
179  {
180  if (refineStatus[facei] == RED)
181  {
182  // Create new vertices on all edges to be refined.
183  const labelList& fEdges = surf.faceEdges()[facei];
184 
185  for (const label edgei : fEdges)
186  {
187  if (edgeMid[edgei] == -1)
188  {
189  const edge& e = surf.edges()[edgei];
190 
191  // Create new point on mid of edge
192  newPoints.append(e.centre(surf.localPoints()));
193  edgeMid[edgei] = newVertI++;
194  }
195  }
196 
197  // Now we have new mid edge vertices for all edges on face
198  // so create triangles for RED refinement.
199 
200  const edgeList& edges = surf.edges();
201 
202  // Corner triangles
203  newFaces.append
204  (
205  labelledTri
206  (
207  edgeMid[fEdges[0]],
208  edges[fEdges[0]].commonVertex(edges[fEdges[1]]),
209  edgeMid[fEdges[1]],
210  surf[facei].region()
211  )
212  );
213 
214  newFaces.append
215  (
216  labelledTri
217  (
218  edgeMid[fEdges[1]],
219  edges[fEdges[1]].commonVertex(edges[fEdges[2]]),
220  edgeMid[fEdges[2]],
221  surf[facei].region()
222  )
223  );
224 
225  newFaces.append
226  (
227  labelledTri
228  (
229  edgeMid[fEdges[2]],
230  edges[fEdges[2]].commonVertex(edges[fEdges[0]]),
231  edgeMid[fEdges[0]],
232  surf[facei].region()
233  )
234  );
235 
236  // Inner triangle
237  newFaces.append
238  (
239  labelledTri
240  (
241  edgeMid[fEdges[0]],
242  edgeMid[fEdges[1]],
243  edgeMid[fEdges[2]],
244  surf[facei].region()
245  )
246  );
247 
248 
249  // Create triangles for GREEN refinement.
250  for (const label edgei : fEdges)
251  {
252  label otherFacei = otherFace(surf, facei, edgei);
253 
254  if ((otherFacei != -1) && (refineStatus[otherFacei] == GREEN))
255  {
256  greenRefine
257  (
258  surf,
259  otherFacei,
260  edgei,
261  edgeMid[edgei],
262  newFaces
263  );
264  }
265  }
266  }
267  }
268 
269  // Copy unmarked triangles since keep original vertex numbering.
270  forAll(refineStatus, facei)
271  {
272  if (refineStatus[facei] == NONE)
273  {
274  newFaces.append(surf.localFaces()[facei]);
275  }
276  }
277 
278  newFaces.shrink();
279  newPoints.shrink();
280 
281 
282  // Transfer DynamicLists to straight ones.
284  allPoints.transfer(newPoints);
285  newPoints.clear();
286 
287  return triSurface(newFaces, surf.patches(), allPoints, true);
288 }
289 
290 
291 // Angle between two neighbouring triangles,
292 // angle between shared-edge end points and left and right face end points
293 Foam::scalar Foam::triSurfaceTools::faceCosAngle
294 (
295  const point& pStart,
296  const point& pEnd,
297  const point& pLeft,
298  const point& pRight
299 )
300 {
301  const vector common(pEnd - pStart);
302  const vector base0(pLeft - pStart);
303  const vector base1(pRight - pStart);
304 
305  const vector n0 = normalised(common ^ base0);
306  const vector n1 = normalised(base1 ^ common);
307 
308  return n0 & n1;
309 }
310 
311 
312 // Protect edges around vertex from collapsing.
313 // Moving vertI to a different position
314 // - affects obviously the cost of the faces using it
315 // - but also their neighbours since the edge between the faces changes
316 void Foam::triSurfaceTools::protectNeighbours
317 (
318  const triSurface& surf,
319  const label vertI,
320  labelList& faceStatus
321 )
322 {
323 // for (const label facei : surf.pointFaces()[vertI])
324 // {
325 // if ((faceStatus[facei] == ANYEDGE) || (faceStatus[facei] >= 0))
326 // {
327 // faceStatus[facei] = NOEDGE;
328 // }
329 // }
330 
331  for (const label edgei : surf.pointEdges()[vertI])
332  {
333  for (const label facei : surf.edgeFaces()[edgei])
334  {
335  if ((faceStatus[facei] == ANYEDGE) || (faceStatus[facei] >= 0))
336  {
337  faceStatus[facei] = NOEDGE;
338  }
339  }
340  }
341 }
342 
343 
344 //
345 // Edge collapse helper functions
346 //
347 
348 // Get all faces that will get collapsed if edgeI collapses.
349 Foam::labelHashSet Foam::triSurfaceTools::getCollapsedFaces
350 (
351  const triSurface& surf,
352  label edgeI
353 )
354 {
355  const edge& e = surf.edges()[edgeI];
356  const label v1 = e.start();
357  const label v2 = e.end();
358 
359  // Faces using edge will certainly get collapsed.
360  const labelList& myFaces = surf.edgeFaces()[edgeI];
361 
362  labelHashSet facesToBeCollapsed(2*myFaces.size());
363  facesToBeCollapsed.insert(myFaces);
364 
365  // From faces using v1 check if they share an edge with faces
366  // using v2.
367  // - share edge: are part of 'splay' tree and will collapse if edge
368  // collapses
369  const labelList& v1Faces = surf.pointFaces()[v1];
370 
371  for (const label face1I : v1Faces)
372  {
373  label otherEdgeI = oppositeEdge(surf, face1I, v1);
374 
375  // Step across edge to other face
376  label face2I = otherFace(surf, face1I, otherEdgeI);
377 
378  if (face2I != -1)
379  {
380  // found face on other side of edge. Now check if uses v2.
381  if (oppositeVertex(surf, face2I, otherEdgeI) == v2)
382  {
383  // triangles face1I and face2I form splay tree and will
384  // collapse.
385  facesToBeCollapsed.insert(face1I);
386  facesToBeCollapsed.insert(face2I);
387  }
388  }
389  }
390 
391  return facesToBeCollapsed;
392 }
393 
394 
395 // Return value of faceUsed for faces using vertI
396 Foam::label Foam::triSurfaceTools::vertexUsesFace
397 (
398  const triSurface& surf,
399  const labelHashSet& faceUsed,
400  const label vertI
401 )
402 {
403  for (const label face1I : surf.pointFaces()[vertI])
404  {
405  if (faceUsed.found(face1I))
406  {
407  return face1I;
408  }
409  }
410  return -1;
411 }
412 
413 
414 // Calculate new edge-face addressing resulting from edge collapse
415 void Foam::triSurfaceTools::getMergedEdges
416 (
417  const triSurface& surf,
418  const label edgeI,
419  const labelHashSet& collapsedFaces,
420  Map<label>& edgeToEdge,
421  Map<label>& edgeToFace
422 )
423 {
424  const edge& e = surf.edges()[edgeI];
425  const label v1 = e.start();
426  const label v2 = e.end();
427 
428  const labelList& v1Faces = surf.pointFaces()[v1];
429  const labelList& v2Faces = surf.pointFaces()[v2];
430 
431  // Mark all (non collapsed) faces using v2
432  labelHashSet v2FacesHash(v2Faces.size());
433 
434  for (const label facei : v2Faces)
435  {
436  if (!collapsedFaces.found(facei))
437  {
438  v2FacesHash.insert(facei);
439  }
440  }
441 
442 
443  for (const label face1I: v1Faces)
444  {
445  if (collapsedFaces.found(face1I))
446  {
447  continue;
448  }
449 
450  //
451  // Check if face1I uses a vertex connected to a face using v2
452  //
453 
454  label vert1I = -1;
455  label vert2I = -1;
456  otherVertices
457  (
458  surf,
459  face1I,
460  v1,
461  vert1I,
462  vert2I
463  );
464  //Pout<< "Face:" << surf.localFaces()[face1I] << " other vertices:"
465  // << vert1I << ' ' << vert2I << endl;
466 
467  // Check vert1, vert2 for usage by v2Face.
468 
469  label commonVert = vert1I;
470  label face2I = vertexUsesFace(surf, v2FacesHash, commonVert);
471  if (face2I == -1)
472  {
473  commonVert = vert2I;
474  face2I = vertexUsesFace(surf, v2FacesHash, commonVert);
475  }
476 
477  if (face2I != -1)
478  {
479  // Found one: commonVert is used by both face1I and face2I
480  label edge1I = getEdge(surf, v1, commonVert);
481  label edge2I = getEdge(surf, v2, commonVert);
482 
483  edgeToEdge.insert(edge1I, edge2I);
484  edgeToEdge.insert(edge2I, edge1I);
485 
486  edgeToFace.insert(edge1I, face2I);
487  edgeToFace.insert(edge2I, face1I);
488  }
489  }
490 }
491 
492 
493 // Calculates (cos of) angle across edgeI of facei,
494 // taking into account updated addressing (resulting from edge collapse)
495 Foam::scalar Foam::triSurfaceTools::edgeCosAngle
496 (
497  const triSurface& surf,
498  const label v1,
499  const point& pt,
500  const labelHashSet& collapsedFaces,
501  const Map<label>& edgeToEdge,
502  const Map<label>& edgeToFace,
503  const label facei,
504  const label edgeI
505 )
506 {
507  const pointField& localPoints = surf.localPoints();
508 
509  label A = surf.edges()[edgeI].start();
510  label B = surf.edges()[edgeI].end();
511  label C = oppositeVertex(surf, facei, edgeI);
512 
513  label D = -1;
514 
515  label face2I = -1;
516 
517  if (edgeToEdge.found(edgeI))
518  {
519  // Use merged addressing
520  label edge2I = edgeToEdge[edgeI];
521  face2I = edgeToFace[edgeI];
522 
523  D = oppositeVertex(surf, face2I, edge2I);
524  }
525  else
526  {
527  // Use normal edge-face addressing
528  face2I = otherFace(surf, facei, edgeI);
529 
530  if ((face2I != -1) && !collapsedFaces.found(face2I))
531  {
532  D = oppositeVertex(surf, face2I, edgeI);
533  }
534  }
535 
536  scalar cosAngle = 1;
537 
538  if (D != -1)
539  {
540  if (A == v1)
541  {
542  cosAngle = faceCosAngle
543  (
544  pt,
545  localPoints[B],
546  localPoints[C],
547  localPoints[D]
548  );
549  }
550  else if (B == v1)
551  {
552  cosAngle = faceCosAngle
553  (
554  localPoints[A],
555  pt,
556  localPoints[C],
557  localPoints[D]
558  );
559  }
560  else if (C == v1)
561  {
562  cosAngle = faceCosAngle
563  (
564  localPoints[A],
565  localPoints[B],
566  pt,
567  localPoints[D]
568  );
569  }
570  else if (D == v1)
571  {
572  cosAngle = faceCosAngle
573  (
574  localPoints[A],
575  localPoints[B],
576  localPoints[C],
577  pt
578  );
579  }
580  else
581  {
583  << "face " << facei << " does not use vertex "
584  << v1 << " of collapsed edge" << abort(FatalError);
585  }
586  }
587  return cosAngle;
588 }
589 
590 
591 Foam::scalar Foam::triSurfaceTools::collapseMinCosAngle
592 (
593  const triSurface& surf,
594  const label v1,
595  const point& pt,
596  const labelHashSet& collapsedFaces,
597  const Map<label>& edgeToEdge,
598  const Map<label>& edgeToFace
599 )
600 {
601  const labelList& v1Faces = surf.pointFaces()[v1];
602 
603  scalar minCos = 1;
604 
605  for (const label facei : v1Faces)
606  {
607  if (collapsedFaces.found(facei))
608  {
609  continue;
610  }
611 
612  for (const label edgeI : surf.faceEdges()[facei])
613  {
614  minCos =
615  min
616  (
617  minCos,
618  edgeCosAngle
619  (
620  surf,
621  v1,
622  pt,
623  collapsedFaces,
624  edgeToEdge,
625  edgeToFace,
626  facei,
627  edgeI
628  )
629  );
630  }
631  }
632 
633  return minCos;
634 }
635 
636 
637 // Calculate max dihedral angle after collapsing edge to v1 (at pt).
638 // Note that all edges of all faces using v1 are affected.
639 bool Foam::triSurfaceTools::collapseCreatesFold
640 (
641  const triSurface& surf,
642  const label v1,
643  const point& pt,
644  const labelHashSet& collapsedFaces,
645  const Map<label>& edgeToEdge,
646  const Map<label>& edgeToFace,
647  const scalar minCos
648 )
649 {
650  const labelList& v1Faces = surf.pointFaces()[v1];
651 
652  for (const label facei : v1Faces)
653  {
654  if (collapsedFaces.found(facei))
655  {
656  continue;
657  }
658 
659  const labelList& myEdges = surf.faceEdges()[facei];
660 
661  for (const label edgeI : myEdges)
662  {
663  if
664  (
665  edgeCosAngle
666  (
667  surf,
668  v1,
669  pt,
670  collapsedFaces,
671  edgeToEdge,
672  edgeToFace,
673  facei,
674  edgeI
675  )
676  < minCos
677  )
678  {
679  return true;
680  }
681  }
682  }
683 
684  return false;
685 }
686 
687 
690 // a vertex.
691 //bool Foam::triSurfaceTools::collapseCreatesDuplicates
692 //(
693 // const triSurface& surf,
694 // const label edgeI,
695 // const labelHashSet& collapsedFaces
696 //)
697 //{
698 //Pout<< "duplicate : edgeI:" << edgeI << surf.edges()[edgeI]
699 // << " collapsedFaces:" << collapsedFaces.toc() << endl;
700 //
701 // // Mark neighbours of faces to be collapsed, i.e. get the first layer
702 // // of triangles outside collapsedFaces.
703 // // neighbours actually contains the
704 // // edge with which triangle connects to collapsedFaces.
705 //
706 // Map<label> neighbours;
707 //
708 // labelList collapsed = collapsedFaces.toc();
709 //
710 // for (const label facei : collapsed)
711 // {
712 // const labelList& myEdges = surf.faceEdges()[facei];
713 //
714 // Pout<< "collapsing facei:" << facei << " uses edges:" << myEdges
715 // << endl;
716 //
717 // forAll(myEdges, myEdgeI)
718 // {
719 // const labelList& myFaces = surf.edgeFaces()[myEdges[myEdgeI]];
720 //
721 // Pout<< "Edge " << myEdges[myEdgeI] << " is used by faces "
722 // << myFaces << endl;
723 //
724 // if ((myEdges[myEdgeI] != edgeI) && (myFaces.size() == 2))
725 // {
726 // // Get the other face
727 // label neighbourFacei = myFaces[0];
728 //
729 // if (neighbourFacei == facei)
730 // {
731 // neighbourFacei = myFaces[1];
732 // }
733 //
734 // // Is 'outside' face if not in collapsedFaces itself
735 // if (!collapsedFaces.found(neighbourFacei))
736 // {
737 // neighbours.insert(neighbourFacei, myEdges[myEdgeI]);
738 // }
739 // }
740 // }
741 // }
742 //
743 // // Now neighbours contains first layer of triangles outside of
744 // // collapseFaces
745 // // There should be
746 // // -two if edgeI is a boundary edge
747 // // since the outside 'edge' of collapseFaces should
748 // // form a triangle and the face connected to edgeI is not inserted.
749 // // -four if edgeI is not a boundary edge since then the outside edge forms
750 // // a diamond.
751 //
752 // // Check if any of the faces in neighbours share an edge. (n^2)
753 //
754 // labelList neighbourList = neighbours.toc();
755 //
756 //Pout<< "edgeI:" << edgeI << " neighbourList:" << neighbourList << endl;
757 //
758 //
759 // forAll(neighbourList, i)
760 // {
761 // const labelList& faceIEdges = surf.faceEdges()[neighbourList[i]];
762 //
763 // for (label j = i+1; j < neighbourList.size(); i++)
764 // {
765 // const labelList& faceJEdges = surf.faceEdges()[neighbourList[j]];
766 //
767 // // Check if facei and faceJ share an edge
768 // forAll(faceIEdges, fI)
769 // {
770 // forAll(faceJEdges, fJ)
771 // {
772 // Pout<< " comparing " << faceIEdges[fI] << " to "
773 // << faceJEdges[fJ] << endl;
774 //
775 // if (faceIEdges[fI] == faceJEdges[fJ])
776 // {
777 // return true;
778 // }
779 // }
780 // }
781 // }
782 // }
783 // Pout<< "Found no match. Returning false" << endl;
784 // return false;
785 //}
786 
787 
788 // Finds the triangle edge cut by the plane between a point inside / on edge
789 // of a triangle and a point outside. Returns:
790 // - cut through edge/point
791 // - miss()
792 Foam::surfaceLocation Foam::triSurfaceTools::cutEdge
793 (
794  const triSurface& s,
795  const label triI,
796  const label excludeEdgeI,
797  const label excludePointi,
798 
799  const point& triPoint,
800  const plane& cutPlane,
801  const point& toPoint
802 )
803 {
804  const pointField& points = s.points();
805  const labelledTri& f = s[triI];
806  const labelList& fEdges = s.faceEdges()[triI];
807 
808  // Get normal distance to planeN
809  FixedList<scalar, 3> d;
810 
811  scalar norm = 0;
812  forAll(d, fp)
813  {
814  d[fp] = cutPlane.signedDistance(points[f[fp]]);
815  norm += mag(d[fp]);
816  }
817 
818  // Normalise and truncate
819  forAll(d, i)
820  {
821  d[i] /= norm;
822 
823  if (mag(d[i]) < 1e-6)
824  {
825  d[i] = 0.0;
826  }
827  }
828 
829  // Return information
830  surfaceLocation cut;
831 
832  if (excludePointi != -1)
833  {
834  // Excluded point. Test only opposite edge.
835 
836  label fp0 = s.localFaces()[triI].find(excludePointi);
837 
838  if (fp0 == -1)
839  {
841  << " localF:" << s.localFaces()[triI] << abort(FatalError);
842  }
843 
844  label fp1 = f.fcIndex(fp0);
845  label fp2 = f.fcIndex(fp1);
846 
847 
848  if (d[fp1] == 0.0)
849  {
850  cut.hitPoint(points[f[fp1]]);
851  cut.elementType() = triPointRef::POINT;
852  cut.setIndex(s.localFaces()[triI][fp1]);
853  }
854  else if (d[fp2] == 0.0)
855  {
856  cut.hitPoint(points[f[fp2]]);
857  cut.elementType() = triPointRef::POINT;
858  cut.setIndex(s.localFaces()[triI][fp2]);
859  }
860  else if
861  (
862  (d[fp1] < 0 && d[fp2] < 0)
863  || (d[fp1] > 0 && d[fp2] > 0)
864  )
865  {
866  // Both same sign. Not crossing edge at all.
867  // cut already set to miss().
868  }
869  else
870  {
871  cut.hitPoint
872  (
873  (d[fp2]*points[f[fp1]] - d[fp1]*points[f[fp2]])
874  / (d[fp2] - d[fp1])
875  );
876  cut.elementType() = triPointRef::EDGE;
877  cut.setIndex(fEdges[fp1]);
878  }
879  }
880  else
881  {
882  // Find the two intersections
883  FixedList<surfaceLocation, 2> inters;
884  label interI = 0;
885 
886  forAll(f, fp0)
887  {
888  label fp1 = f.fcIndex(fp0);
889 
890  if (d[fp0] == 0)
891  {
892  if (interI >= 2)
893  {
895  << "problem : triangle has three intersections." << nl
896  << "triangle:" << f.tri(points)
897  << " d:" << d << abort(FatalError);
898  }
899  inters[interI].hitPoint(points[f[fp0]]);
900  inters[interI].elementType() = triPointRef::POINT;
901  inters[interI].setIndex(s.localFaces()[triI][fp0]);
902  interI++;
903  }
904  else if
905  (
906  (d[fp0] < 0 && d[fp1] > 0)
907  || (d[fp0] > 0 && d[fp1] < 0)
908  )
909  {
910  if (interI >= 2)
911  {
913  << "problem : triangle has three intersections." << nl
914  << "triangle:" << f.tri(points)
915  << " d:" << d << abort(FatalError);
916  }
917  inters[interI].hitPoint
918  (
919  (d[fp0]*points[f[fp1]] - d[fp1]*points[f[fp0]])
920  / (d[fp0] - d[fp1])
921  );
922  inters[interI].elementType() = triPointRef::EDGE;
923  inters[interI].setIndex(fEdges[fp0]);
924  interI++;
925  }
926  }
927 
928 
929  if (interI == 0)
930  {
931  // Return miss
932  }
933  else if (interI == 1)
934  {
935  // Only one intersection. Should not happen!
936  cut = inters[0];
937  }
938  else if (interI == 2)
939  {
940  // Handle excludeEdgeI
941  if
942  (
943  inters[0].elementType() == triPointRef::EDGE
944  && inters[0].index() == excludeEdgeI
945  )
946  {
947  cut = inters[1];
948  }
949  else if
950  (
951  inters[1].elementType() == triPointRef::EDGE
952  && inters[1].index() == excludeEdgeI
953  )
954  {
955  cut = inters[0];
956  }
957  else
958  {
959  // Two cuts. Find nearest.
960  if
961  (
962  inters[0].point().distSqr(toPoint)
963  < inters[1].point().distSqr(toPoint)
964  )
965  {
966  cut = inters[0];
967  }
968  else
969  {
970  cut = inters[1];
971  }
972  }
973  }
974  }
975  return cut;
976 }
977 
978 
979 // 'Snap' point on to endPoint.
980 void Foam::triSurfaceTools::snapToEnd
981 (
982  const triSurface& s,
983  const surfaceLocation& end,
984  surfaceLocation& current
985 )
986 {
987  if (end.elementType() == triPointRef::NONE)
988  {
989  if (current.elementType() == triPointRef::NONE)
990  {
991  // endpoint on triangle; current on triangle
992  if (current.index() == end.index())
993  {
994  //if (debug)
995  //{
996  // Pout<< "snapToEnd : snapping:" << current << " onto:"
997  // << end << endl;
998  //}
999  current = end;
1000  current.setHit();
1001  }
1002  }
1003  // No need to handle current on edge/point since tracking handles this.
1004  }
1005  else if (end.elementType() == triPointRef::EDGE)
1006  {
1007  if (current.elementType() == triPointRef::NONE)
1008  {
1009  // endpoint on edge; current on triangle
1010  const labelList& fEdges = s.faceEdges()[current.index()];
1011 
1012  if (fEdges.found(end.index()))
1013  {
1014  //if (debug)
1015  //{
1016  // Pout<< "snapToEnd : snapping:" << current << " onto:"
1017  // << end << endl;
1018  //}
1019  current = end;
1020  current.setHit();
1021  }
1022  }
1023  else if (current.elementType() == triPointRef::EDGE)
1024  {
1025  // endpoint on edge; current on edge
1026  if (current.index() == end.index())
1027  {
1028  //if (debug)
1029  //{
1030  // Pout<< "snapToEnd : snapping:" << current << " onto:"
1031  // << end << endl;
1032  //}
1033  current = end;
1034  current.setHit();
1035  }
1036  }
1037  else
1038  {
1039  // endpoint on edge; current on point
1040  const edge& e = s.edges()[end.index()];
1041 
1042  if (current.index() == e[0] || current.index() == e[1])
1043  {
1044  //if (debug)
1045  //{
1046  // Pout<< "snapToEnd : snapping:" << current << " onto:"
1047  // << end << endl;
1048  //}
1049  current = end;
1050  current.setHit();
1051  }
1052  }
1053  }
1054  else // end.elementType() == POINT
1055  {
1056  if (current.elementType() == triPointRef::NONE)
1057  {
1058  // endpoint on point; current on triangle
1059  const triSurface::face_type& f = s.localFaces()[current.index()];
1060 
1061  if (f.found(end.index()))
1062  {
1063  //if (debug)
1064  //{
1065  // Pout<< "snapToEnd : snapping:" << current << " onto:"
1066  // << end << endl;
1067  //}
1068  current = end;
1069  current.setHit();
1070  }
1071  }
1072  else if (current.elementType() == triPointRef::EDGE)
1073  {
1074  // endpoint on point; current on edge
1075  const edge& e = s.edges()[current.index()];
1076 
1077  if (end.index() == e[0] || end.index() == e[1])
1078  {
1079  //if (debug)
1080  //{
1081  // Pout<< "snapToEnd : snapping:" << current << " onto:"
1082  // << end << endl;
1083  //}
1084  current = end;
1085  current.setHit();
1086  }
1087  }
1088  else
1089  {
1090  // endpoint on point; current on point
1091  if (current.index() == end.index())
1092  {
1093  //if (debug)
1094  //{
1095  // Pout<< "snapToEnd : snapping:" << current << " onto:"
1096  // << end << endl;
1097  //}
1098  current = end;
1099  current.setHit();
1100  }
1101  }
1102  }
1103 }
1104 
1105 
1106 // Start:
1107 // - location
1108 // - element type (triangle/edge/point) and index
1109 // - triangle to exclude
1110 Foam::surfaceLocation Foam::triSurfaceTools::visitFaces
1111 (
1112  const triSurface& s,
1113  const labelList& eFaces,
1114  const surfaceLocation& start,
1115  const label excludeEdgeI,
1116  const label excludePointi,
1117  const surfaceLocation& end,
1118  const plane& cutPlane
1119 )
1120 {
1121  surfaceLocation nearest;
1122 
1123  scalar minDistSqr = Foam::sqr(GREAT);
1124 
1125  for (const label triI : eFaces)
1126  {
1127  // Make sure we don't revisit previous face
1128  if (triI != start.triangle())
1129  {
1130  if (end.elementType() == triPointRef::NONE && end.index() == triI)
1131  {
1132  // Endpoint is in this triangle. Jump there.
1133  nearest = end;
1134  nearest.setHit();
1135  nearest.triangle() = triI;
1136  break;
1137  }
1138  else
1139  {
1140  // Which edge is cut.
1141 
1142  surfaceLocation cutInfo = cutEdge
1143  (
1144  s,
1145  triI,
1146  excludeEdgeI, // excludeEdgeI
1147  excludePointi, // excludePointi
1148  start.point(),
1149  cutPlane,
1150  end.point()
1151  );
1152 
1153  // If crossing an edge we expect next edge to be cut.
1154  if (excludeEdgeI != -1 && !cutInfo.hit())
1155  {
1157  << "Triangle:" << triI
1158  << " excludeEdge:" << excludeEdgeI
1159  << " point:" << start.point()
1160  << " plane:" << cutPlane
1161  << " . No intersection!" << abort(FatalError);
1162  }
1163 
1164  if (cutInfo.hit())
1165  {
1166  scalar distSqr = cutInfo.point().distSqr(end.point());
1167 
1168  if (distSqr < minDistSqr)
1169  {
1170  minDistSqr = distSqr;
1171  nearest = cutInfo;
1172  nearest.triangle() = triI;
1173  nearest.setMiss();
1174  }
1175  }
1176  }
1177  }
1178  }
1179 
1180  if (nearest.triangle() == -1)
1181  {
1182  // Did not move from edge. Give warning? Return something special?
1183  // For now responsibility of caller to make sure that nothing has
1184  // moved.
1185  }
1186 
1187  return nearest;
1188 }
1190 
1191 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1192 
1193 
1194 // Write pointField to file
1196 (
1197  const fileName& fName,
1198  const pointField& pts
1199 )
1200 {
1201  OFstream outFile(fName);
1202 
1203  for (const point& pt : pts)
1204  {
1205  outFile<< "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl;
1206  }
1207  Pout<< "Written " << pts.size() << " vertices to file " << fName << endl;
1208 }
1209 
1210 
1211 // Write vertex subset to OBJ format file
1213 (
1214  const triSurface& surf,
1215  const fileName& fName,
1216  const boolList& markedVerts
1217 )
1218 {
1219  OFstream outFile(fName);
1220 
1221  label nVerts = 0;
1222  forAll(markedVerts, vertI)
1223  {
1224  if (markedVerts[vertI])
1225  {
1226  const point& pt = surf.localPoints()[vertI];
1227 
1228  outFile<< "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl;
1229 
1230  nVerts++;
1231  }
1232  }
1233  Pout<< "Written " << nVerts << " vertices to file " << fName << endl;
1234 }
1235 
1237 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1238 // Addressing helper functions:
1239 
1240 
1241 // Get all triangles using vertices of edge
1243 (
1244  const triSurface& surf,
1245  const label edgeI,
1246  labelList& edgeTris
1247 )
1248 {
1249  const edge& e = surf.edges()[edgeI];
1250  const labelList& myFaces = surf.edgeFaces()[edgeI];
1251 
1252  label face1I = myFaces[0];
1253  label face2I = -1;
1254  if (myFaces.size() == 2)
1255  {
1256  face2I = myFaces[1];
1257  }
1258 
1259  const labelList& startFaces = surf.pointFaces()[e.start()];
1260  const labelList& endFaces = surf.pointFaces()[e.end()];
1261 
1262  // Number of triangles is sum of pointfaces - common faces
1263  // (= faces using edge)
1264  edgeTris.setSize(startFaces.size() + endFaces.size() - myFaces.size());
1265 
1266  label nTris = 0;
1267  for (const label facei : startFaces)
1268  {
1269  edgeTris[nTris++] = facei;
1270  }
1271 
1272  for (const label facei : endFaces)
1273  {
1274  if ((facei != face1I) && (facei != face2I))
1275  {
1276  edgeTris[nTris++] = facei;
1277  }
1278  }
1279 }
1280 
1281 
1282 // Get all vertices connected to vertices of edge
1284 (
1285  const triSurface& surf,
1286  const edge& e
1287 )
1288 {
1289  const edgeList& edges = surf.edges();
1290  const label v1 = e.start();
1291  const label v2 = e.end();
1292 
1293  // Get all vertices connected to v1 or v2 through an edge
1294  labelHashSet vertexNeighbours;
1295 
1296  const labelList& v1Edges = surf.pointEdges()[v1];
1297 
1298  for (const label edgei : v1Edges)
1299  {
1300  vertexNeighbours.insert(edges[edgei].otherVertex(v1));
1301  }
1302 
1303  const labelList& v2Edges = surf.pointEdges()[v2];
1304 
1305  for (const label edgei : v2Edges)
1306  {
1307  vertexNeighbours.insert(edges[edgei].otherVertex(v2));
1308  }
1309  return vertexNeighbours.toc();
1310 }
1311 
1312 
1313 // Get the other face using edgeI
1315 (
1316  const triSurface& surf,
1317  const label facei,
1318  const label edgeI
1319 )
1320 {
1321  const labelList& myFaces = surf.edgeFaces()[edgeI];
1322 
1323  if (myFaces.size() != 2)
1324  {
1325  return -1;
1326  }
1327  else if (facei == myFaces[0])
1328  {
1329  return myFaces[1];
1330  }
1331  else
1332  {
1333  return myFaces[0];
1334  }
1335 }
1336 
1337 
1338 // Get the two edges on facei counterclockwise after edgeI
1340 (
1341  const triSurface& surf,
1342  const label facei,
1343  const label edgeI,
1344  label& e1,
1345  label& e2
1346 )
1347 {
1348  const labelList& eFaces = surf.faceEdges()[facei];
1349 
1350  label i0 = eFaces.find(edgeI);
1351 
1352  if (i0 == -1)
1353  {
1355  << "Edge " << surf.edges()[edgeI] << " not in face "
1356  << surf.localFaces()[facei] << abort(FatalError);
1357  }
1358 
1359  label i1 = eFaces.fcIndex(i0);
1360  label i2 = eFaces.fcIndex(i1);
1361 
1362  e1 = eFaces[i1];
1363  e2 = eFaces[i2];
1364 }
1365 
1366 
1367 // Get the two vertices on facei counterclockwise vertI
1369 (
1370  const triSurface& surf,
1371  const label facei,
1372  const label vertI,
1373  label& vert1I,
1374  label& vert2I
1375 )
1376 {
1377  const labelledTri& f = surf.localFaces()[facei];
1378 
1379  if (vertI == f[0])
1380  {
1381  vert1I = f[1];
1382  vert2I = f[2];
1383  }
1384  else if (vertI == f[1])
1385  {
1386  vert1I = f[2];
1387  vert2I = f[0];
1388  }
1389  else if (vertI == f[2])
1390  {
1391  vert1I = f[0];
1392  vert2I = f[1];
1393  }
1394  else
1395  {
1397  << "Vertex " << vertI << " not in face " << f << nl
1399  }
1400 }
1401 
1402 
1403 // Get edge opposite vertex
1405 (
1406  const triSurface& surf,
1407  const label facei,
1408  const label vertI
1409 )
1410 {
1411  const labelList& myEdges = surf.faceEdges()[facei];
1412 
1413  for (const label edgei : myEdges)
1414  {
1415  const edge& e = surf.edges()[edgei];
1416 
1417  if (!e.found(vertI))
1418  {
1419  return edgei;
1420  }
1421  }
1422 
1424  << "Cannot find vertex " << vertI << " in edges of face " << facei
1425  << nl
1426  << abort(FatalError);
1428  return -1;
1429 }
1430 
1431 
1432 // Get vertex opposite edge
1434 (
1435  const triSurface& surf,
1436  const label facei,
1437  const label edgeI
1438 )
1439 {
1440  const triSurface::face_type& f = surf.localFaces()[facei];
1441  const edge& e = surf.edges()[edgeI];
1442 
1443  for (const label pointi : f)
1444  {
1445  if (!e.found(pointi))
1446  {
1447  return pointi;
1448  }
1449  }
1450 
1452  << "Cannot find vertex opposite edge " << edgeI << " vertices " << e
1453  << " in face " << facei << " vertices " << f << abort(FatalError);
1455  return -1;
1456 }
1457 
1458 
1459 // Returns edge label connecting v1, v2
1461 (
1462  const triSurface& surf,
1463  const label v1,
1464  const label v2
1465 )
1466 {
1467  const labelList& v1Edges = surf.pointEdges()[v1];
1468 
1469  for (const label edgei : v1Edges)
1470  {
1471  const edge& e = surf.edges()[edgei];
1472 
1473  if (e.found(v2))
1474  {
1475  return edgei;
1476  }
1477  }
1478  return -1;
1479 }
1480 
1481 
1482 // Return index of triangle (or -1) using all three edges
1484 (
1485  const triSurface& surf,
1486  const label e0I,
1487  const label e1I,
1488  const label e2I
1489 )
1490 {
1491  if ((e0I == e1I) || (e0I == e2I) || (e1I == e2I))
1492  {
1494  << "Duplicate edge labels : e0:" << e0I << " e1:" << e1I
1495  << " e2:" << e2I
1496  << abort(FatalError);
1497  }
1498 
1499  const labelList& eFaces = surf.edgeFaces()[e0I];
1500 
1501  for (const label facei : eFaces)
1502  {
1503  const labelList& myEdges = surf.faceEdges()[facei];
1504 
1505  if
1506  (
1507  (myEdges[0] == e1I)
1508  || (myEdges[1] == e1I)
1509  || (myEdges[2] == e1I)
1510  )
1511  {
1512  if
1513  (
1514  (myEdges[0] == e2I)
1515  || (myEdges[1] == e2I)
1516  || (myEdges[2] == e2I)
1517  )
1518  {
1519  return facei;
1520  }
1521  }
1522  }
1523  return -1;
1524 }
1525 
1526 
1527 // Collapse indicated edges. Return new tri surface.
1529 (
1530  const triSurface& surf,
1531  const labelList& collapsableEdges
1532 )
1533 {
1534  pointField edgeMids(surf.nEdges());
1535 
1536  forAll(edgeMids, edgeI)
1537  {
1538  const edge& e = surf.edges()[edgeI];
1539  edgeMids[edgeI] = e.centre(surf.localPoints());
1540  }
1541 
1542 
1543  labelList faceStatus(surf.size(), ANYEDGE);
1544 
1546  //forAll(edges, edgeI)
1547  //{
1548  // const labelList& neighbours = edgeFaces[edgeI];
1549  //
1550  // if ((neighbours.size() != 2) && (neighbours.size() != 1))
1551  // {
1552  // FatalErrorInFunction
1553  // << abort(FatalError);
1554  // }
1555  //
1556  // if (neighbours.size() == 2)
1557  // {
1558  // if (surf[neighbours[0]].region() != surf[neighbours[1]].region())
1559  // {
1560  // // Neighbours on different regions. For now, do not allow
1561  // // any collapse.
1562  // //Pout<< "protecting face " << neighbours[0]
1563  // // << ' ' << neighbours[1] << endl;
1564  // faceStatus[neighbours[0]] = NOEDGE;
1565  // faceStatus[neighbours[1]] = NOEDGE;
1566  // }
1567  // }
1568  //}
1570  return collapseEdges(surf, collapsableEdges, edgeMids, faceStatus);
1571 }
1572 
1573 
1574 // Collapse indicated edges. Return new tri surface.
1576 (
1577  const triSurface& surf,
1578  const labelList& collapseEdgeLabels,
1579  const pointField& edgeMids,
1580  labelList& faceStatus
1581 )
1582 {
1583  const labelListList& edgeFaces = surf.edgeFaces();
1584  const pointField& localPoints = surf.localPoints();
1585  const edgeList& edges = surf.edges();
1586 
1587  // Storage for new points
1588  pointField newPoints(localPoints);
1589 
1590  // Map for old to new points
1591  labelList pointMap(identity(localPoints.size()));
1592 
1593  // Do actual 'collapsing' of edges
1594 
1595  for (const label edgei : collapseEdgeLabels)
1596  {
1597  if (edgei < 0 || edgei >= surf.nEdges())
1598  {
1600  << "Edge label outside valid range." << endl
1601  << "edge label:" << edgei << endl
1602  << "total number of edges:" << surf.nEdges() << endl
1603  << abort(FatalError);
1604  }
1605 
1606  const labelList& neighbours = edgeFaces[edgei];
1607 
1608  if (neighbours.size() == 2)
1609  {
1610  const label stat0 = faceStatus[neighbours[0]];
1611  const label stat1 = faceStatus[neighbours[1]];
1612 
1613  // Check faceStatus to make sure this one can be collapsed
1614  if
1615  (
1616  ((stat0 == ANYEDGE) || (stat0 == edgei))
1617  && ((stat1 == ANYEDGE) || (stat1 == edgei))
1618  )
1619  {
1620  const edge& e = edges[edgei];
1621 
1622  // Set up mapping to 'collapse' points of edge
1623  if
1624  (
1625  (pointMap[e.start()] != e.start())
1626  || (pointMap[e.end()] != e.end())
1627  )
1628  {
1630  << "points already mapped. Double collapse." << endl
1631  << "edgei:" << edgei
1632  << " start:" << e.start()
1633  << " end:" << e.end()
1634  << " pointMap[start]:" << pointMap[e.start()]
1635  << " pointMap[end]:" << pointMap[e.end()]
1636  << abort(FatalError);
1637  }
1638 
1639  const label minVert = min(e.start(), e.end());
1640  pointMap[e.start()] = minVert;
1641  pointMap[e.end()] = minVert;
1642 
1643  // Move shared vertex to mid of edge
1644  newPoints[minVert] = edgeMids[edgei];
1645 
1646  // Protect neighbouring faces
1647  protectNeighbours(surf, e.start(), faceStatus);
1648  protectNeighbours(surf, e.end(), faceStatus);
1649  protectNeighbours
1650  (
1651  surf,
1652  oppositeVertex(surf, neighbours[0], edgei),
1653  faceStatus
1654  );
1655  protectNeighbours
1656  (
1657  surf,
1658  oppositeVertex(surf, neighbours[1], edgei),
1659  faceStatus
1660  );
1661 
1662  // Mark all collapsing faces
1663  labelList collapseFaces =
1664  getCollapsedFaces
1665  (
1666  surf,
1667  edgei
1668  ).toc();
1669 
1670  forAll(collapseFaces, collapseI)
1671  {
1672  faceStatus[collapseFaces[collapseI]] = COLLAPSED;
1673  }
1674  }
1675  }
1676  }
1677 
1678 
1679  // Storage for new triangles
1680  List<labelledTri> newTriangles(surf.size());
1681  label nNewTris = 0;
1682 
1683  const List<labelledTri>& localFaces = surf.localFaces();
1684 
1685  // Get only non-collapsed triangles and renumber vertex labels.
1686  forAll(localFaces, facei)
1687  {
1688  if (faceStatus[facei] != COLLAPSED)
1689  {
1690  // Uncollapsed triangle
1691  labelledTri f(localFaces[facei]);
1692 
1693  // inplace renumber
1694  f[0] = pointMap[f[0]];
1695  f[1] = pointMap[f[1]];
1696  f[2] = pointMap[f[2]];
1697 
1698  if (f.good())
1699  {
1700  newTriangles[nNewTris++] = f;
1701  }
1702  }
1703  }
1704  newTriangles.resize(nNewTris);
1705 
1706 
1707  // Pack faces
1708 
1709  triSurface tempSurf(newTriangles, surf.patches(), newPoints);
1710 
1711  return
1712  triSurface
1713  (
1714  tempSurf.localFaces(),
1715  tempSurf.patches(),
1716  tempSurf.localPoints()
1717  );
1718 }
1719 
1720 
1721 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1722 
1724 (
1725  const triSurface& surf,
1726  const labelList& refineFaces
1727 )
1728 {
1729  List<refineType> refineStatus(surf.size(), NONE);
1730 
1731  // Mark & propagate refinement
1732  forAll(refineFaces, refineFacei)
1733  {
1734  calcRefineStatus(surf, refineFaces[refineFacei], refineStatus);
1735  }
1737  // Do actual refinement
1738  return doRefine(surf, refineStatus);
1739 }
1740 
1741 
1742 Foam::triSurface Foam::triSurfaceTools::greenRefine
1743 (
1744  const triSurface& surf,
1745  const labelList& refineEdges
1746 )
1747 {
1748  // Storage for marking faces
1749  List<refineType> refineStatus(surf.size(), NONE);
1750 
1751  // Storage for new faces
1752  DynamicList<labelledTri> newFaces(0);
1753 
1754  pointField newPoints(surf.localPoints());
1755  newPoints.setSize(surf.nPoints() + surf.nEdges());
1756  label newPointi = surf.nPoints();
1757 
1758 
1759  // Refine edges
1760  for (const label edgei : refineEdges)
1761  {
1762  const labelList& myFaces = surf.edgeFaces()[edgei];
1763 
1764  bool neighbourIsRefined= false;
1765 
1766  for (const label facei : myFaces)
1767  {
1768  if (refineStatus[facei] != NONE)
1769  {
1770  neighbourIsRefined = true;
1771  }
1772  }
1773 
1774  // Only refine if none of the faces is refined
1775  if (!neighbourIsRefined)
1776  {
1777  // Refine edge
1778  const edge& e = surf.edges()[edgei];
1779 
1780  newPoints[newPointi] = e.centre(surf.localPoints());
1781 
1782  // Refine faces using edge
1783  for (const label facei : myFaces)
1784  {
1785  // Add faces to newFaces
1786  greenRefine
1787  (
1788  surf,
1789  facei,
1790  edgei,
1791  newPointi,
1792  newFaces
1793  );
1794 
1795  // Mark as refined
1796  refineStatus[facei] = GREEN;
1797  }
1798 
1799  ++newPointi;
1800  }
1801  }
1802 
1803  // Add unrefined faces
1804  forAll(surf.localFaces(), facei)
1805  {
1806  if (refineStatus[facei] == NONE)
1807  {
1808  newFaces.append(surf.localFaces()[facei]);
1809  }
1810  }
1811 
1812  newFaces.shrink();
1813  newPoints.setSize(newPointi);
1814 
1815  return triSurface(newFaces, surf.patches(), newPoints, true);
1816 }
1817 
1818 
1820 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1821 // Geometric helper functions:
1822 
1823 
1824 // Returns element in edgeIndices with minimum length
1826 (
1827  const triSurface& surf,
1828  const labelList& edgeIndices
1829 )
1830 {
1831  scalar minLen = GREAT;
1832  label minEdge = -1;
1833 
1834  for (const label edgei : edgeIndices)
1835  {
1836  const edge& e = surf.edges()[edgei];
1837 
1838  const scalar length = e.mag(surf.localPoints());
1839 
1840  if (length < minLen)
1841  {
1842  minLen = length;
1843  minEdge = edgei;
1844  }
1845  }
1847  return minEdge;
1848 }
1849 
1850 
1851 // Returns element in edgeIndices with maximum length
1853 (
1854  const triSurface& surf,
1855  const labelList& edgeIndices
1856 )
1857 {
1858  scalar maxLen = -GREAT;
1859  label maxEdge = -1;
1860 
1861  for (const label edgei : edgeIndices)
1862  {
1863  const edge& e = surf.edges()[edgei];
1864 
1865  const scalar length = e.mag(surf.localPoints());
1866 
1867  if (length > maxLen)
1868  {
1869  maxLen = length;
1870  maxEdge = edgei;
1871  }
1872  }
1874  return maxEdge;
1875 }
1876 
1877 
1878 // Merge points and reconstruct surface
1880 (
1881  const triSurface& surf,
1882  const scalar mergeTol
1883 )
1884 {
1885  labelList pointMap;
1886  labelList uniquePoints;
1887 
1888  label nChanged = Foam::mergePoints
1889  (
1890  surf.localPoints(),
1891  pointMap,
1892  uniquePoints,
1893  mergeTol,
1894  false
1895  );
1896 
1897  if (nChanged)
1898  {
1899  // Pack the triangles
1900 
1901  // Storage for new triangles
1902  List<labelledTri> newTriangles(surf.size());
1903  label nNewTris = 0;
1904 
1905  // Iterate and work on a copy
1906  for (labelledTri f : surf.localFaces())
1907  {
1908  // inplace renumber
1909  f[0] = pointMap[f[0]];
1910  f[1] = pointMap[f[1]];
1911  f[2] = pointMap[f[2]];
1912 
1913  if (f.good())
1914  {
1915  newTriangles[nNewTris++] = f;
1916  }
1917  }
1918  newTriangles.resize(nNewTris);
1919 
1920  pointField newPoints(surf.localPoints(), uniquePoints);
1921 
1922  return triSurface
1923  (
1924  newTriangles,
1925  surf.patches(),
1926  newPoints,
1927  true //reuse storage
1928  );
1929  }
1931  return surf;
1932 }
1933 
1934 
1935 // Calculate normal on triangle
1937 (
1938  const triSurface& surf,
1939  const label nearestFacei,
1940  const point& nearestPt
1941 )
1942 {
1943  const triSurface::face_type& f = surf[nearestFacei];
1944  const pointField& points = surf.points();
1945 
1946  label nearType, nearLabel;
1947 
1948  f.nearestPointClassify(nearestPt, points, nearType, nearLabel);
1949 
1950  if (nearType == triPointRef::NONE)
1951  {
1952  // Nearest to face
1953  return surf.faceNormals()[nearestFacei];
1954  }
1955  else if (nearType == triPointRef::EDGE)
1956  {
1957  // Nearest to edge. Assume order of faceEdges same as face vertices.
1958  label edgeI = surf.faceEdges()[nearestFacei][nearLabel];
1959 
1960  // Calculate edge normal by averaging face normals
1961  const labelList& eFaces = surf.edgeFaces()[edgeI];
1962 
1963  vector edgeNormal(Zero);
1964 
1965  for (const label facei : eFaces)
1966  {
1967  edgeNormal += surf.faceNormals()[facei];
1968  }
1969  return normalised(edgeNormal);
1970  }
1971  else
1972  {
1973  // Nearest to point
1974  const triSurface::face_type& localF = surf.localFaces()[nearestFacei];
1975  return surf.pointNormals()[localF[nearLabel]];
1976  }
1977 }
1978 
1979 
1981 (
1982  const triSurface& surf,
1983  const point& sample,
1984  const point& nearestPoint,
1985  const label edgeI
1986 )
1987 {
1988  const labelList& eFaces = surf.edgeFaces()[edgeI];
1989 
1990  if (eFaces.size() != 2)
1991  {
1992  // Surface not closed.
1993  return UNKNOWN;
1994  }
1995  else
1996  {
1997  const vectorField& faceNormals = surf.faceNormals();
1998 
1999  // Compare to bisector. This is actually correct since edge is
2000  // nearest so there is a knife-edge.
2001 
2002  vector n = 0.5*(faceNormals[eFaces[0]] + faceNormals[eFaces[1]]);
2003 
2004  if (((sample - nearestPoint) & n) > 0)
2005  {
2006  return OUTSIDE;
2007  }
2008  else
2009  {
2010  return INSIDE;
2011  }
2012  }
2013 }
2014 
2015 
2016 // Calculate normal on triangle
2018 (
2019  const triSurface& surf,
2020  const point& sample,
2021  const label nearestFacei
2022 )
2023 {
2024  const triSurface::face_type& f = surf[nearestFacei];
2025  const pointField& points = surf.points();
2026 
2027  // Find where point is on face
2028  label nearType, nearLabel;
2029 
2030  pointHit pHit = f.nearestPointClassify(sample, points, nearType, nearLabel);
2031 
2032  const point& nearestPoint = pHit.point();
2033 
2034  if (nearType == triPointRef::NONE)
2035  {
2036  vector sampleNearestVec = (sample - nearestPoint);
2037 
2038  // Nearest to face interior. Use faceNormal to determine side
2039  scalar c = sampleNearestVec & surf.faceNormals()[nearestFacei];
2040 
2041  // // If the sample is essentially on the face, do not check for
2042  // // it being perpendicular.
2043 
2044  // scalar magSampleNearestVec = mag(sampleNearestVec);
2045 
2046  // if (magSampleNearestVec > SMALL)
2047  // {
2048  // c /= magSampleNearestVec*mag(surf.faceNormals()[nearestFacei]);
2049 
2050  // if (mag(c) < 0.99)
2051  // {
2052  // FatalErrorInFunction
2053  // << "nearestPoint identified as being on triangle face "
2054  // << "but vector from nearestPoint to sample is not "
2055  // << "perpendicular to the normal." << nl
2056  // << "sample: " << sample << nl
2057  // << "nearestPoint: " << nearestPoint << nl
2058  // << "sample - nearestPoint: "
2059  // << sample - nearestPoint << nl
2060  // << "normal: " << surf.faceNormals()[nearestFacei] << nl
2061  // << "mag(sample - nearestPoint): "
2062  // << mag(sample - nearestPoint) << nl
2063  // << "normalised dot product: " << c << nl
2064  // << "triangle vertices: " << nl
2065  // << " " << points[f[0]] << nl
2066  // << " " << points[f[1]] << nl
2067  // << " " << points[f[2]] << nl
2068  // << abort(FatalError);
2069  // }
2070  // }
2071 
2072  if (c > 0)
2073  {
2074  return OUTSIDE;
2075  }
2076  else
2077  {
2078  return INSIDE;
2079  }
2080  }
2081  else if (nearType == triPointRef::EDGE)
2082  {
2083  // Nearest to edge nearLabel. Note that this can only be a knife-edge
2084  // situation since otherwise the nearest point could never be the edge.
2085 
2086  // Get the edge. Assume order of faceEdges same as face vertices.
2087  label edgeI = surf.faceEdges()[nearestFacei][nearLabel];
2088 
2089  // if (debug)
2090  // {
2091  // // Check order of faceEdges same as face vertices.
2092  // const edge& e = surf.edges()[edgeI];
2093  // const labelList& meshPoints = surf.meshPoints();
2094  // const edge meshEdge(meshPoints[e[0]], meshPoints[e[1]]);
2095 
2096  // if
2097  // (
2098  // meshEdge
2099  // != edge(f[nearLabel], f[f.fcIndex(nearLabel)])
2100  // )
2101  // {
2102  // FatalErrorInFunction
2103  // << "Edge:" << edgeI << " local vertices:" << e
2104  // << " mesh vertices:" << meshEdge
2105  // << " not at position " << nearLabel
2106  // << " in face " << f
2107  // << abort(FatalError);
2108  // }
2109  // }
2110 
2111  return edgeSide(surf, sample, nearestPoint, edgeI);
2112  }
2113  else
2114  {
2115  // Nearest to point. Could use pointNormal here but is not correct.
2116  // Instead determine which edge using point is nearest and use test
2117  // above (nearType == triPointRef::EDGE).
2118 
2119 
2120  const triSurface::face_type& localF = surf.localFaces()[nearestFacei];
2121  label nearPointi = localF[nearLabel];
2122 
2123  const edgeList& edges = surf.edges();
2124  const pointField& localPoints = surf.localPoints();
2125  const point& base = localPoints[nearPointi];
2126 
2127  const labelList& pEdges = surf.pointEdges()[nearPointi];
2128 
2129  scalar minDistSqr = Foam::sqr(GREAT);
2130  label minEdgeI = -1;
2131 
2132  forAll(pEdges, i)
2133  {
2134  label edgeI = pEdges[i];
2135 
2136  const edge& e = edges[edgeI];
2137 
2138  label otherPointi = e.otherVertex(nearPointi);
2139 
2140  // Get edge normal.
2141  vector eVec(localPoints[otherPointi] - base);
2142  scalar magEVec = mag(eVec);
2143 
2144  if (magEVec > VSMALL)
2145  {
2146  eVec /= magEVec;
2147 
2148  // Get point along vector and determine closest.
2149  const point perturbPoint = base + eVec;
2150 
2151  scalar distSqr = Foam::magSqr(sample - perturbPoint);
2152 
2153  if (distSqr < minDistSqr)
2154  {
2155  minDistSqr = distSqr;
2156  minEdgeI = edgeI;
2157  }
2158  }
2159  }
2160 
2161  if (minEdgeI == -1)
2162  {
2164  << "Problem: did not find edge closer than " << minDistSqr
2165  << abort(FatalError);
2166  }
2168  return edgeSide(surf, sample, nearestPoint, minEdgeI);
2169  }
2170 }
2171 
2172 
2174 (
2175  const polyBoundaryMesh& bMesh,
2176  const labelHashSet& includePatches,
2177  labelList& faceMap,
2178  const bool verbose
2179 )
2180 {
2181  const polyMesh& mesh = bMesh.mesh();
2182 
2183  // Storage for surfaceMesh. Size estimate.
2184  List<labelledTri> triangles;
2185 
2186  // Calculate number of triangles
2187  label nTris = 0;
2188 
2189  for (const label patchi : includePatches)
2190  {
2191  const polyPatch& patch = bMesh[patchi];
2192  const pointField& points = patch.points();
2193  for (const face& f : patch)
2194  {
2195  nTris += f.nTriangles(points);
2196  }
2197  }
2198 
2199  triangles.setSize(nTris);
2200  faceMap.setSize(nTris);
2201  label newPatchi = 0;
2202 
2203  nTris = 0;
2204  for (const label patchi : includePatches)
2205  {
2206  const polyPatch& patch = bMesh[patchi];
2207  const pointField& points = patch.points();
2208 
2209  label nTriTotal = 0;
2210 
2211  label faceI = 0;
2212  for (const face& f : patch)
2213  {
2214  faceList triFaces(f.nTriangles(points));
2215 
2216  label nTri = 0;
2217 
2218  f.triangles(points, nTri, triFaces);
2219 
2220  for (const face& f : triFaces)
2221  {
2222  faceMap[nTris] = patch.start() + faceI;
2223  triangles[nTris++] = labelledTri(f[0], f[1], f[2], newPatchi);
2224 
2225  ++nTriTotal;
2226  }
2227 
2228  faceI++;
2229  }
2230 
2231  if (verbose)
2232  {
2233  Pout<< patch.name() << " : generated " << nTriTotal
2234  << " triangles from " << patch.size() << " faces with"
2235  << " new patchid " << newPatchi << endl;
2236  }
2237 
2238  newPatchi++;
2239  }
2240  //triangles.shrink();
2241 
2242  // Create globally numbered tri surface
2243  triSurface rawSurface(triangles, mesh.points());
2244 
2245  // Create locally numbered tri surface
2246  triSurface surface
2247  (
2248  rawSurface.localFaces(),
2249  rawSurface.localPoints()
2250  );
2251 
2252  // Add patch names to surface
2253  surface.patches().setSize(newPatchi);
2254 
2255  newPatchi = 0;
2256 
2257  for (const label patchi : includePatches)
2258  {
2259  const polyPatch& patch = bMesh[patchi];
2260 
2261  surface.patches()[newPatchi].name() = patch.name();
2262  surface.patches()[newPatchi].geometricType() = patch.type();
2263 
2264  newPatchi++;
2265  }
2266 
2267  return surface;
2268 }
2269 
2270 
2272 (
2273  const polyBoundaryMesh& bMesh,
2274  const labelHashSet& includePatches,
2275  const boundBox& bBox,
2276  const bool verbose
2277 )
2278 {
2279  const polyMesh& mesh = bMesh.mesh();
2280 
2281  // Storage for surfaceMesh. Size estimate.
2282  DynamicList<labelledTri> triangles(mesh.nBoundaryFaces());
2283 
2284  label newPatchi = 0;
2285 
2286  for (const label patchi : includePatches)
2287  {
2288  const polyPatch& patch = bMesh[patchi];
2289  const pointField& points = patch.points();
2290 
2291  label nTriTotal = 0;
2292 
2293  forAll(patch, patchFacei)
2294  {
2295  const face& f = patch[patchFacei];
2296 
2297  if (bBox.containsAny(points, f))
2298  {
2299  faceList triFaces(f.nTriangles(points));
2300 
2301  label nTri = 0;
2302 
2303  f.triangles(points, nTri, triFaces);
2304 
2305  forAll(triFaces, triFacei)
2306  {
2307  const face& f = triFaces[triFacei];
2308 
2309  triangles.append(labelledTri(f[0], f[1], f[2], newPatchi));
2310 
2311  nTriTotal++;
2312  }
2313  }
2314  }
2315 
2316  if (verbose)
2317  {
2318  Pout<< patch.name() << " : generated " << nTriTotal
2319  << " triangles from " << patch.size() << " faces with"
2320  << " new patchid " << newPatchi << endl;
2321  }
2322 
2323  newPatchi++;
2324  }
2325  triangles.shrink();
2326 
2327  // Create globally numbered tri surface
2328  triSurface rawSurface(triangles, mesh.points());
2329 
2330  // Create locally numbered tri surface
2331  triSurface surface
2332  (
2333  rawSurface.localFaces(),
2334  rawSurface.localPoints()
2335  );
2336 
2337  // Add patch names to surface
2338  surface.patches().setSize(newPatchi);
2339 
2340  newPatchi = 0;
2341 
2342  for (const label patchi : includePatches)
2343  {
2344  const polyPatch& patch = bMesh[patchi];
2345 
2346  surface.patches()[newPatchi].name() = patch.name();
2347  surface.patches()[newPatchi].geometricType() = patch.type();
2348 
2349  ++newPatchi;
2350  }
2352  return surface;
2353 }
2354 
2355 
2356 // triangulation of boundaryMesh
2358 (
2359  const polyBoundaryMesh& bMesh,
2360  const labelHashSet& includePatches,
2361  const bool verbose
2362 )
2363 {
2364  const polyMesh& mesh = bMesh.mesh();
2365 
2366  // Storage for new points = meshpoints + face centres.
2367  const pointField& points = mesh.points();
2368  const pointField& faceCentres = mesh.faceCentres();
2369 
2370  pointField newPoints(points.size() + faceCentres.size());
2371 
2372  label newPointi = 0;
2373 
2374  forAll(points, pointi)
2375  {
2376  newPoints[newPointi++] = points[pointi];
2377  }
2378  forAll(faceCentres, facei)
2379  {
2380  newPoints[newPointi++] = faceCentres[facei];
2381  }
2382 
2383 
2384  // Count number of faces.
2385  DynamicList<labelledTri> triangles(mesh.nBoundaryFaces());
2386 
2387  label newPatchi = 0;
2388 
2389  for (const label patchi : includePatches)
2390  {
2391  const polyPatch& patch = bMesh[patchi];
2392 
2393  label nTriTotal = 0;
2394 
2395  forAll(patch, patchFacei)
2396  {
2397  // Face in global coords.
2398  const face& f = patch[patchFacei];
2399 
2400  // Index in newPointi of face centre.
2401  label fc = points.size() + patchFacei + patch.start();
2402 
2403  forAll(f, fp)
2404  {
2405  label fp1 = f.fcIndex(fp);
2406 
2407  triangles.append(labelledTri(f[fp], f[fp1], fc, newPatchi));
2408 
2409  nTriTotal++;
2410  }
2411  }
2412 
2413  if (verbose)
2414  {
2415  Pout<< patch.name() << " : generated " << nTriTotal
2416  << " triangles from " << patch.size() << " faces with"
2417  << " new patchid " << newPatchi << endl;
2418  }
2419 
2420  newPatchi++;
2421  }
2422  triangles.shrink();
2423 
2424 
2425  // Create globally numbered tri surface
2426  triSurface rawSurface(triangles, newPoints);
2427 
2428  // Create locally numbered tri surface
2429  triSurface surface
2430  (
2431  rawSurface.localFaces(),
2432  rawSurface.localPoints()
2433  );
2434 
2435  // Add patch names to surface
2436  surface.patches().setSize(newPatchi);
2437 
2438  newPatchi = 0;
2439 
2440  for (const label patchi : includePatches)
2441  {
2442  const polyPatch& patch = bMesh[patchi];
2443 
2444  surface.patches()[newPatchi].name() = patch.name();
2445  surface.patches()[newPatchi].geometricType() = patch.type();
2446 
2447  newPatchi++;
2448  }
2449 
2450  return surface;
2451 }
2452 
2453 
2455 {
2456  // Vertices in geompack notation. Note that could probably just use
2457  // pts.begin() if double precision.
2458  List<double> geompackVertices(2*pts.size());
2459  label doubleI = 0;
2460  for (const vector2D& pt : pts)
2461  {
2462  geompackVertices[doubleI++] = pt[0];
2463  geompackVertices[doubleI++] = pt[1];
2464  }
2465 
2466  // Storage for triangles
2467  int m2 = 3;
2468  List<int> triangle_node(m2*3*pts.size());
2469  List<int> triangle_neighbor(m2*3*pts.size());
2470 
2471  // Triangulate
2472  int nTris = 0;
2473  int err = dtris2
2474  (
2475  pts.size(),
2476  geompackVertices.begin(),
2477  &nTris,
2478  triangle_node.begin(),
2479  triangle_neighbor.begin()
2480  );
2481 
2482  if (err != 0)
2483  {
2485  << "Failed dtris2 with vertices:" << pts.size()
2486  << abort(FatalError);
2487  }
2488 
2489  // Trim
2490  triangle_node.setSize(3*nTris);
2491  triangle_neighbor.setSize(3*nTris);
2492 
2493  // Convert to triSurface.
2494  List<labelledTri> faces(nTris);
2495 
2496  forAll(faces, i)
2497  {
2498  faces[i] = labelledTri
2499  (
2500  triangle_node[3*i]-1,
2501  triangle_node[3*i+1]-1,
2502  triangle_node[3*i+2]-1,
2503  0
2504  );
2505  }
2506 
2508  forAll(pts, i)
2509  {
2510  points[i][0] = pts[i][0];
2511  points[i][1] = pts[i][1];
2512  points[i][2] = 0.0;
2513  }
2514 
2515  return triSurface(faces, points);
2516 }
2517 
2518 
2520 (
2521  const triPointRef& tri,
2522  const point& p,
2523  FixedList<scalar, 3>& weights
2524 )
2525 {
2526  // calculate triangle edge vectors and triangle face normal
2527  // the 'i':th edge is opposite node i
2528  FixedList<vector, 3> edge;
2529  edge[0] = tri.c()-tri.b();
2530  edge[1] = tri.a()-tri.c();
2531  edge[2] = tri.b()-tri.a();
2532 
2533  const vector triangleFaceNormal = edge[1] ^ edge[2];
2534 
2535  // calculate edge normal (pointing inwards)
2536  FixedList<vector, 3> normal;
2537  for (label i=0; i<3; i++)
2538  {
2539  normal[i] = normalised(triangleFaceNormal ^ edge[i]);
2540  }
2541 
2542  weights[0] = ((p-tri.b()) & normal[0]) / max(VSMALL, normal[0] & edge[1]);
2543  weights[1] = ((p-tri.c()) & normal[1]) / max(VSMALL, normal[1] & edge[2]);
2544  weights[2] = ((p-tri.a()) & normal[2]) / max(VSMALL, normal[2] & edge[0]);
2545 }
2546 
2547 
2548 // Calculate weighting factors from samplePts to triangle it is in.
2549 // Uses linear search.
2551 (
2552  const triSurface& s,
2553  const pointField& samplePts,
2554  List<FixedList<label, 3>>& allVerts,
2555  List<FixedList<scalar, 3>>& allWeights
2556 )
2557 {
2558  allVerts.setSize(samplePts.size());
2559  allWeights.setSize(samplePts.size());
2560 
2561  const pointField& points = s.points();
2562 
2563  forAll(samplePts, i)
2564  {
2565  const point& samplePt = samplePts[i];
2566 
2567  FixedList<label, 3>& verts = allVerts[i];
2568  FixedList<scalar, 3>& weights = allWeights[i];
2569 
2570  scalar minDistance = GREAT;
2571 
2572  for (const labelledTri& f : s)
2573  {
2574  triPointRef tri(f.tri(points));
2575 
2576  label nearType, nearLabel;
2577 
2578  pointHit nearest = tri.nearestPointClassify
2579  (
2580  samplePt,
2581  nearType,
2582  nearLabel
2583  );
2584 
2585  if (nearest.hit())
2586  {
2587  // samplePt inside triangle
2588  verts[0] = f[0];
2589  verts[1] = f[1];
2590  verts[2] = f[2];
2591 
2592  calcInterpolationWeights(tri, nearest.point(), weights);
2593 
2594  //Pout<< "calcScalingFactors : samplePt:" << samplePt
2595  // << " inside triangle:" << facei
2596  // << " verts:" << verts
2597  // << " weights:" << weights
2598  // << endl;
2599 
2600  break;
2601  }
2602  else if (nearest.distance() < minDistance)
2603  {
2604  minDistance = nearest.distance();
2605 
2606  // Outside triangle. Store nearest.
2607 
2608  if (nearType == triPointRef::POINT)
2609  {
2610  verts[0] = f[nearLabel];
2611  weights[0] = 1;
2612  verts[1] = -1;
2613  weights[1] = -GREAT;
2614  verts[2] = -1;
2615  weights[2] = -GREAT;
2616 
2617  //Pout<< "calcScalingFactors : samplePt:" << samplePt
2618  // << " distance:" << nearest.distance()
2619  // << " from point:" << points[f[nearLabel]]
2620  // << endl;
2621  }
2622  else if (nearType == triPointRef::EDGE)
2623  {
2624  verts[0] = f[nearLabel];
2625  verts[1] = f[f.fcIndex(nearLabel)];
2626  verts[2] = -1;
2627 
2628  const point& p0 = points[verts[0]];
2629  const point& p1 = points[verts[1]];
2630 
2631  scalar s = min
2632  (
2633  1,
2634  nearest.point().dist(p0)/p1.dist(p0)
2635  );
2636 
2637  // Interpolate
2638  weights[0] = 1 - s;
2639  weights[1] = s;
2640  weights[2] = -GREAT;
2641 
2642  //Pout<< "calcScalingFactors : samplePt:" << samplePt
2643  // << " distance:" << nearest.distance()
2644  // << " from edge:" << p0 << p1 << " s:" << s
2645  // << endl;
2646  }
2647  else
2648  {
2649  // triangle. Can only happen because of truncation errors.
2650  verts[0] = f[0];
2651  verts[1] = f[1];
2652  verts[2] = f[2];
2653 
2654  calcInterpolationWeights(tri, nearest.point(), weights);
2655 
2656  //Pout<< "calcScalingFactors : samplePt:" << samplePt
2657  // << " distance:" << nearest.distance()
2658  // << " to verts:" << verts
2659  // << " weights:" << weights
2660  // << endl;
2661 
2662  break;
2663  }
2664  }
2665  }
2666  }
2668 
2669 
2670 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2671 // Checking:
2672 
2674 (
2675  const triSurface& surf,
2676  const label facei,
2677  const bool verbose
2678 )
2679 {
2680  typedef labelledTri FaceType;
2681  const FaceType& f = surf[facei];
2682 
2683  // Simple check on indices ok.
2684  for (const label pointi : f)
2685  {
2686  if (pointi < 0 || pointi >= surf.points().size())
2687  {
2688  if (verbose)
2689  {
2691  << "triangle " << facei << " vertices " << f
2692  << " uses point indices outside point range 0.."
2693  << surf.points().size()-1 << endl;
2694  }
2695  return false;
2696  }
2697  }
2698 
2699  if (f[0] == f[1] || f[0] == f[2] || f[1] == f[2])
2700  {
2701  if (verbose)
2702  {
2704  << "triangle " << facei
2705  << " uses non-unique vertices " << f
2706  << " coords:" << f.points(surf.points()) << endl;
2707  }
2708  return false;
2709  }
2710 
2711  // duplicate triangle check
2712 
2713  const labelList& fFaces = surf.faceFaces()[facei];
2714 
2715  // Check if faceNeighbours use same points as this face.
2716  // Note: discards normal information - sides of baffle are merged.
2717  for (const label nbrFacei : fFaces)
2718  {
2719  if (nbrFacei <= facei)
2720  {
2721  // lower numbered faces already checked
2722  continue;
2723  }
2724 
2725  const FaceType& nbrF = surf[nbrFacei];
2726 
2727  // Same as calling triFace::compare(f, nbrF) == 1 only
2728  if
2729  (
2730  (f[0] == nbrF[0] || f[0] == nbrF[1] || f[0] == nbrF[2])
2731  && (f[1] == nbrF[0] || f[1] == nbrF[1] || f[1] == nbrF[2])
2732  && (f[2] == nbrF[0] || f[2] == nbrF[1] || f[2] == nbrF[2])
2733  )
2734  {
2735  if (verbose)
2736  {
2738  << "triangle " << facei << " vertices " << f
2739  << " has the same vertices as triangle " << nbrFacei
2740  << " vertices " << nbrF
2741  << " coords:" << f.points(surf.points()) << endl;
2742  }
2743 
2744  return false;
2745  }
2746  }
2747 
2748  return true;
2749 }
2750 
2751 
2753 (
2754  const MeshedSurface<face>& surf,
2755  const label facei,
2756  const bool verbose
2757 )
2758 {
2759  typedef face FaceType;
2760  const FaceType& f = surf[facei];
2761 
2762  if (f.size() != 3)
2763  {
2764  if (verbose)
2765  {
2767  << "face " << facei
2768  << " is not a triangle, it has " << f.size()
2769  << " indices" << endl;
2770  }
2771  return false;
2772  }
2773 
2774  // Simple check on indices ok.
2775  for (const label pointi : f)
2776  {
2777  if (pointi < 0 || pointi >= surf.points().size())
2778  {
2779  if (verbose)
2780  {
2782  << "triangle " << facei << " vertices " << f
2783  << " uses point indices outside point range 0.."
2784  << surf.points().size()-1 << endl;
2785  }
2786  return false;
2787  }
2788  }
2789 
2790  if (f[0] == f[1] || f[0] == f[2] || f[1] == f[2])
2791  {
2792  if (verbose)
2793  {
2795  << "triangle " << facei
2796  << " uses non-unique vertices " << f
2797  << " coords:" << f.points(surf.points()) << endl;
2798  }
2799  return false;
2800  }
2801 
2802  // duplicate triangle check
2803 
2804  const labelList& fFaces = surf.faceFaces()[facei];
2805 
2806  // Check if faceNeighbours use same points as this face.
2807  // Note: discards normal information - sides of baffle are merged.
2808  for (const label nbrFacei : fFaces)
2809  {
2810  if (nbrFacei <= facei)
2811  {
2812  // lower numbered faces already checked
2813  continue;
2814  }
2815 
2816  const FaceType& nbrF = surf[nbrFacei];
2817 
2818  // Same as calling triFace::compare(f, nbrF) == 1 only
2819  if
2820  (
2821  (f[0] == nbrF[0] || f[0] == nbrF[1] || f[0] == nbrF[2])
2822  && (f[1] == nbrF[0] || f[1] == nbrF[1] || f[1] == nbrF[2])
2823  && (f[2] == nbrF[0] || f[2] == nbrF[1] || f[2] == nbrF[2])
2824  )
2825  {
2826  if (verbose)
2827  {
2829  << "triangle " << facei << " vertices " << f
2830  << " has the same vertices as triangle " << nbrFacei
2831  << " vertices " << nbrF
2832  << " coords:" << f.points(surf.points()) << endl;
2833  }
2834  return false;
2835  }
2836  }
2837 
2838  return true;
2839 }
2841 
2842 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2843 // Tracking:
2844 
2845 // Test point on surface to see if is on face,edge or point.
2847 (
2848  const triSurface& s,
2849  const label triI,
2850  const point& trianglePoint
2851 )
2852 {
2853  surfaceLocation nearest;
2854 
2855  // Nearest point could be on point or edge. Retest.
2856  label index, elemType;
2857  //bool inside =
2858  triPointRef(s[triI].tri(s.points())).classify
2859  (
2860  trianglePoint,
2861  elemType,
2862  index
2863  );
2864 
2865  nearest.setPoint(trianglePoint);
2866 
2867  if (elemType == triPointRef::NONE)
2868  {
2869  nearest.setHit();
2870  nearest.setIndex(triI);
2871  nearest.elementType() = triPointRef::NONE;
2872  }
2873  else if (elemType == triPointRef::EDGE)
2874  {
2875  nearest.setMiss();
2876  nearest.setIndex(s.faceEdges()[triI][index]);
2877  nearest.elementType() = triPointRef::EDGE;
2878  }
2879  else //if (elemType == triPointRef::POINT)
2880  {
2881  nearest.setMiss();
2882  nearest.setIndex(s.localFaces()[triI][index]);
2883  nearest.elementType() = triPointRef::POINT;
2884  }
2885 
2886  return nearest;
2887 }
2888 
2889 
2891 (
2892  const triSurface& s,
2893  const surfaceLocation& start,
2894  const surfaceLocation& end,
2895  const plane& cutPlane
2896 )
2897 {
2898  // Start off from starting point
2899  surfaceLocation nearest = start;
2900  nearest.setMiss();
2901 
2902  // See if in same triangle as endpoint. If so snap.
2903  snapToEnd(s, end, nearest);
2904 
2905  if (!nearest.hit())
2906  {
2907  // Not yet at end point
2908 
2909  if (start.elementType() == triPointRef::NONE)
2910  {
2911  // Start point is inside triangle. Trivial cases already handled
2912  // above.
2913 
2914  // end point is on edge or point so cross current triangle to
2915  // see which edge is cut.
2916 
2917  nearest = cutEdge
2918  (
2919  s,
2920  start.index(), // triangle
2921  -1, // excludeEdge
2922  -1, // excludePoint
2923  start.point(),
2924  cutPlane,
2925  end.point()
2926  );
2927  nearest.elementType() = triPointRef::EDGE;
2928  nearest.triangle() = start.index();
2929  nearest.setMiss();
2930  }
2931  else if (start.elementType() == triPointRef::EDGE)
2932  {
2933  // Pick connected triangle that is most in direction.
2934  const labelList& eFaces = s.edgeFaces()[start.index()];
2935 
2936  nearest = visitFaces
2937  (
2938  s,
2939  eFaces,
2940  start,
2941  start.index(), // excludeEdgeI
2942  -1, // excludePointi
2943  end,
2944  cutPlane
2945  );
2946  }
2947  else // start.elementType() == triPointRef::POINT
2948  {
2949  const labelList& pFaces = s.pointFaces()[start.index()];
2950 
2951  nearest = visitFaces
2952  (
2953  s,
2954  pFaces,
2955  start,
2956  -1, // excludeEdgeI
2957  start.index(), // excludePointi
2958  end,
2959  cutPlane
2960  );
2961  }
2962  snapToEnd(s, end, nearest);
2963  }
2964  return nearest;
2965 }
2966 
2967 
2969 (
2970  const triSurface& s,
2971  const surfaceLocation& endInfo,
2972  const plane& cutPlane,
2973  surfaceLocation& hitInfo
2974 )
2975 {
2976  //OFstream str("track.obj");
2977  //label vertI = 0;
2978  //meshTools::writeOBJ(str, hitInfo.point());
2979  //vertI++;
2980 
2981  // Track across surface.
2982  while (true)
2983  {
2984  //Pout<< "Tracking from:" << nl
2985  // << " " << hitInfo.info()
2986  // << endl;
2987 
2988  hitInfo = trackToEdge
2989  (
2990  s,
2991  hitInfo,
2992  endInfo,
2993  cutPlane
2994  );
2995 
2996  //meshTools::writeOBJ(str, hitInfo.point());
2997  //vertI++;
2998  //str<< "l " << vertI-1 << ' ' << vertI << nl;
2999 
3000  //Pout<< "Tracked to:" << nl
3001  // << " " << hitInfo.info() << endl;
3002 
3003  if (hitInfo.hit() || hitInfo.triangle() == -1)
3004  {
3005  break;
3006  }
3007  }
3008 }
3009 
3010 
3011 // ************************************************************************* //
const labelListList & pointEdges() const
Return point-edge addressing.
static labelList getVertexVertices(const triSurface &surf, const edge &e)
Get all vertices (local numbering) connected to vertices of edge.
void setMiss() noexcept
Set the hit status off.
label nPoints() const
Number of points supporting patch faces.
triPointRef::proxType & elementType() noexcept
const List< face_type > & localFaces() const
Return patch faces addressing into local point list.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
A triangle primitive used to calculate face normals and swept volumes. Uses referred points...
Definition: triangle.H:217
A class for handling file names.
Definition: fileName.H:72
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
const Field< point_type > & localPoints() const
Return pointField of points in patch.
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:160
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
Unknown proximity.
Definition: triangle.H:239
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:517
List< edge > edgeList
List of edge.
Definition: edgeList.H:32
static triSurface triangulate(const polyBoundaryMesh &mBesh, const labelHashSet &includePatches, labelList &faceMap, const bool verbose=false)
Simple triangulation of (selected patches of) boundaryMesh. Needs.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Output to file stream, using an OSstream.
Definition: OFstream.H:49
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Vector2D< scalar > vector2D
A 2D vector of scalars obtained from the generic Vector2D.
Definition: vector2D.H:56
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
bool found(const T &val, label pos=0) const
Same as contains()
Definition: UList.H:879
void setHit() noexcept
Set the hit status on.
std::vector< Triangle > triangles
static void track(const triSurface &, const surfaceLocation &endInfo, const plane &cutPlane, surfaceLocation &hitInfo)
Track from edge to edge across surface. Uses trackToEdge.
static triSurface redGreenRefine(const triSurface &surf, const labelList &refineFaces)
Refine face by splitting all edges. Neighbouring face is.
label otherFace(const primitiveMesh &mesh, const label celli, const label facei, const label edgeI)
Return face on cell using edgeI but not facei. Throws error.
Definition: meshTools.C:548
static label maxEdge(const triSurface &surf, const labelList &edgeIndices)
Returns element in edgeIndices with minimum length.
quaternion normalised(const quaternion &q)
Return the normalised (unit) quaternion of the given quaternion.
Definition: quaternionI.H:674
static vector surfaceNormal(const triSurface &surf, const label nearestFacei, const point &nearestPt)
Triangle (unit) normal. If nearest point to triangle on edge use.
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:232
static const label NOEDGE
static triSurface delaunay2D(const List< vector2D > &)
Do unconstrained Delaunay of points. Returns triSurface with 3D.
static triSurface collapseEdges(const triSurface &surf, const labelList &collapsableEdges)
Create new triSurface by collapsing edges to edge mids.
static label otherFace(const triSurface &surf, const label facei, const label edgeI)
Get face connected to edge not facei.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
triSurface triangulateFaceCentre(const polyBoundaryMesh &mBesh, const labelHashSet &includePatches, const bool verbose=false)
Face-centre triangulation of (selected patches of) boundaryMesh.
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1078
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
static void calcInterpolationWeights(const triPointRef &tri, const point &p, FixedList< scalar, 3 > &weights)
Calculate linear interpolation weights for point (guaranteed to be.
Close to point.
Definition: triangle.H:240
label fcIndex(const label i) const noexcept
The forward circular index. The next index in the list which returns to the first at the end of the l...
Definition: UListI.H:97
static label oppositeVertex(const triSurface &surf, const label facei, const label edgeI)
Get vertex (local numbering) opposite edge.
label mergePoints(const PointList &points, labelList &pointToUnique, labelList &uniquePoints, const scalar mergeTol=SMALL, const bool verbose=false)
Calculate merge mapping, preserving the original point order. All points closer/equal mergeTol are to...
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
bool hit() const noexcept
Is there a hit.
Definition: pointHit.H:145
const Field< point_type > & faceNormals() const
Return face unit normals for patch.
List< face > faceList
List of faces.
Definition: faceListFwd.H:39
static label getEdge(List< DynamicList< label >> &pe, DynamicList< edge > &es, const label pointi, const label nextPointi)
A list of faces which address into the list of points.
const labelListList & faceFaces() const
Return face-face addressing.
const geometricSurfacePatchList & patches() const noexcept
Definition: triSurface.H:509
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
static triSurface mergePoints(const triSurface &surf, const scalar mergeTol)
Merge points within distance.
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
void setSize(const label n)
Alias for resize()
Definition: List.H:316
dynamicFvMesh & mesh
Close to edge.
Definition: triangle.H:241
const pointField & points
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:51
An edge is a list of two vertex labels. This can correspond to a directed graph edge or an edge on a ...
Definition: edge.H:59
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
Definition: labelLists.C:44
static sideType edgeSide(const triSurface &surf, const point &sample, const point &nearestPoint, const label edgeI)
If nearest point is on edgeI, determine on which side of surface.
void setPoint(const point_type &p)
Set the point.
static label minEdge(const triSurface &surf, const labelList &edgeIndices)
Returns element in edgeIndices with minimum length.
labelledTri face_type
The face type (same as the underlying PrimitivePatch)
Definition: triSurface.H:256
static void otherVertices(const triSurface &surf, const label facei, const label vertI, label &vert1I, label &vert2I)
Get the two vertices (local numbering) on facei counterclockwise.
const labelListList & edgeFaces() const
Return edge-face addressing.
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
PointFrompoint toPoint(const Foam::point &p)
static const label COLLAPSED
A triFace with additional (region) index.
Definition: labelledTri.H:53
Vector< scalar > vector
Definition: vector.H:57
Describes the interaction of a object and a (templated) point. It carries the info of a successful hi...
Definition: pointHit.H:43
const Field< point_type > & points() const noexcept
Return reference to global points.
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
errorManip< error > abort(error &err)
Definition: errorManip.H:139
static surfaceLocation trackToEdge(const triSurface &, const surfaceLocation &start, const surfaceLocation &end, const plane &cutPlane)
Track on surface to get closer to point.
label find(const T &val) const
Find index of the first occurrence of the value.
Definition: UList.C:173
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
const wordList surface
Standard surface field types (scalar, vector, tensor, etc)
const labelListList & pointFaces() const
Return point-face addressing.
void setMiss(const bool eligible) noexcept
Set the hit status off and set the eligible miss status.
Definition: pointHit.H:226
label nEdges() const
Number of edges in patch.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
sideType
On which side of surface.
const Field< point_type > & pointNormals() const
Return point normals for patch.
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:201
volScalarField & C
Geometric merging of points. See below.
labelList f(nPoints)
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::HEX);labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells].reset(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
void setIndex(const label index) noexcept
Set the index.
static label getTriangle(const triSurface &surf, const label e0I, const label e1I, const label e2I)
Return index of triangle (or -1) using all three edges.
const vectorField & faceCentres() const
static bool validTri(const triSurface &, const label facei, const bool verbose=true)
Check single triangle for (topological) validity.
int dtris2(int point_num, double point_xy[], int *tri_num, int tri_vert[], int tri_nabe[])
Definition: geompack.C:953
static sideType surfaceSide(const triSurface &surf, const point &sample, const label nearestFacei)
Given nearest point (to sample) on surface determines which side.
vector point
Point is a vector.
Definition: point.H:37
#define WarningInFunction
Report a warning using Foam::Warning.
label newPointi
Definition: readKivaGrid.H:496
static void otherEdges(const triSurface &surf, const label facei, const label edgeI, label &e1, label &e2)
Get the two edges on facei counterclockwise after edgeI.
const dimensionedScalar c
Speed of light in a vacuum.
scalar distance() const noexcept
Return distance to hit.
Definition: pointHit.H:169
const std::string patch
OpenFOAM patch number as a std::string.
triangle< point, const point & > triPointRef
A triangle using referred points.
Definition: triangleFwd.H:39
const point_type & point() const noexcept
Return the point, no checks.
Definition: pointHit.H:161
const labelListList & faceEdges() const
Return face-edge addressing.
label n
tmp< pointField > allPoints(const Triangulation &t)
Extract all points in vertex-index order.
Field< vector > vectorField
Specialisation of Field<T> for vector.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
Contains information about location on a triSurface.
const dimensionedScalar & D
static void writeOBJ(const fileName &fName, const pointField &pts)
Write pointField to OBJ format file.
List< label > labelList
A List of labels.
Definition: List.H:62
volScalarField & p
Triangulated surface description with patch information.
Definition: triSurface.H:71
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
static const label ANYEDGE
Face collapse status.
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces)
static const Foam::dimensionedScalar A("", Foam::dimPressure, 611.21)
static label getEdge(const triSurface &surf, const label vert1I, const label vert2I)
Returns edge label connecting v1, v2 (local numbering)
static void getVertexTriangles(const triSurface &surf, const label edgeI, labelList &edgeTris)
Get all triangles using edge endpoint.
PrimitivePatch< List< face >, const pointField > bMesh
Holder of faceList and points. (v.s. e.g. primitivePatch which references points) ...
Definition: bMesh.H:39
List< bool > boolList
A List of bools.
Definition: List.H:60
static surfaceLocation classify(const triSurface &, const label triI, const point &trianglePoint)
Test point on plane of triangle to see if on edge or point or inside.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
static const Foam::dimensionedScalar B("", Foam::dimless, 18.678)
const volScalarField & p0
Definition: EEqn.H:36
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
static label oppositeEdge(const triSurface &surf, const label facei, const label vertI)
Get edge opposite vertex (local numbering)
PointHit< point > pointHit
A PointHit with a 3D point.
Definition: pointHit.H:43
const pointField & pts
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127