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