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-2021 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 triangles
2205  label nTris = 0;
2206 
2207  for (const label patchi : includePatches)
2208  {
2209  const polyPatch& patch = bMesh[patchi];
2210  const pointField& points = patch.points();
2211  for (const face& f : patch)
2212  {
2213  nTris += f.nTriangles(points);
2214  }
2215  }
2216 
2217  triangles.setSize(nTris);
2218  faceMap.setSize(nTris);
2219  label newPatchi = 0;
2220 
2221  nTris = 0;
2222  for (const label patchi : includePatches)
2223  {
2224  const polyPatch& patch = bMesh[patchi];
2225  const pointField& points = patch.points();
2226 
2227  label nTriTotal = 0;
2228 
2229  label faceI = 0;
2230  for (const face& f : patch)
2231  {
2232  faceList triFaces(f.nTriangles(points));
2233 
2234  label nTri = 0;
2235 
2236  f.triangles(points, nTri, triFaces);
2237 
2238  for (const face& f : triFaces)
2239  {
2240  faceMap[nTris] = patch.start() + faceI;
2241  triangles[nTris++] = labelledTri(f[0], f[1], f[2], newPatchi);
2242 
2243  ++nTriTotal;
2244  }
2245 
2246  faceI++;
2247  }
2248 
2249  if (verbose)
2250  {
2251  Pout<< patch.name() << " : generated " << nTriTotal
2252  << " triangles from " << patch.size() << " faces with"
2253  << " new patchid " << newPatchi << endl;
2254  }
2255 
2256  newPatchi++;
2257  }
2258  //triangles.shrink();
2259 
2260  // Create globally numbered tri surface
2261  triSurface rawSurface(triangles, mesh.points());
2262 
2263  // Create locally numbered tri surface
2264  triSurface surface
2265  (
2266  rawSurface.localFaces(),
2267  rawSurface.localPoints()
2268  );
2269 
2270  // Add patch names to surface
2271  surface.patches().setSize(newPatchi);
2272 
2273  newPatchi = 0;
2274 
2275  for (const label patchi : includePatches)
2276  {
2277  const polyPatch& patch = bMesh[patchi];
2278 
2279  surface.patches()[newPatchi].name() = patch.name();
2280  surface.patches()[newPatchi].geometricType() = patch.type();
2281 
2282  newPatchi++;
2283  }
2284 
2285  return surface;
2286 }
2287 
2288 
2291  const polyBoundaryMesh& bMesh,
2292  const labelHashSet& includePatches,
2293  const boundBox& bBox,
2294  const bool verbose
2295 )
2296 {
2297  const polyMesh& mesh = bMesh.mesh();
2298 
2299  // Storage for surfaceMesh. Size estimate.
2301 
2302  label newPatchi = 0;
2303 
2304  for (const label patchi : includePatches)
2305  {
2306  const polyPatch& patch = bMesh[patchi];
2307  const pointField& points = patch.points();
2308 
2309  label nTriTotal = 0;
2310 
2311  forAll(patch, patchFacei)
2312  {
2313  const face& f = patch[patchFacei];
2314 
2315  if (bBox.containsAny(points, f))
2316  {
2317  faceList triFaces(f.nTriangles(points));
2318 
2319  label nTri = 0;
2320 
2321  f.triangles(points, nTri, triFaces);
2322 
2323  forAll(triFaces, triFacei)
2324  {
2325  const face& f = triFaces[triFacei];
2326 
2327  triangles.append(labelledTri(f[0], f[1], f[2], newPatchi));
2328 
2329  nTriTotal++;
2330  }
2331  }
2332  }
2333 
2334  if (verbose)
2335  {
2336  Pout<< patch.name() << " : generated " << nTriTotal
2337  << " triangles from " << patch.size() << " faces with"
2338  << " new patchid " << newPatchi << endl;
2339  }
2340 
2341  newPatchi++;
2342  }
2343  triangles.shrink();
2344 
2345  // Create globally numbered tri surface
2346  triSurface rawSurface(triangles, mesh.points());
2347 
2348  // Create locally numbered tri surface
2349  triSurface surface
2350  (
2351  rawSurface.localFaces(),
2352  rawSurface.localPoints()
2353  );
2354 
2355  // Add patch names to surface
2356  surface.patches().setSize(newPatchi);
2357 
2358  newPatchi = 0;
2359 
2360  for (const label patchi : includePatches)
2361  {
2362  const polyPatch& patch = bMesh[patchi];
2363 
2364  surface.patches()[newPatchi].name() = patch.name();
2365  surface.patches()[newPatchi].geometricType() = patch.type();
2366 
2367  ++newPatchi;
2368  }
2369 
2370  return surface;
2371 }
2372 
2373 
2374 // triangulation of boundaryMesh
2377  const polyBoundaryMesh& bMesh,
2378  const labelHashSet& includePatches,
2379  const bool verbose
2380 )
2381 {
2382  const polyMesh& mesh = bMesh.mesh();
2383 
2384  // Storage for new points = meshpoints + face centres.
2385  const pointField& points = mesh.points();
2386  const pointField& faceCentres = mesh.faceCentres();
2387 
2388  pointField newPoints(points.size() + faceCentres.size());
2389 
2390  label newPointi = 0;
2391 
2392  forAll(points, pointi)
2393  {
2394  newPoints[newPointi++] = points[pointi];
2395  }
2396  forAll(faceCentres, facei)
2397  {
2398  newPoints[newPointi++] = faceCentres[facei];
2399  }
2400 
2401 
2402  // Count number of faces.
2404 
2405  label newPatchi = 0;
2406 
2407  for (const label patchi : includePatches)
2408  {
2409  const polyPatch& patch = bMesh[patchi];
2410 
2411  label nTriTotal = 0;
2412 
2413  forAll(patch, patchFacei)
2414  {
2415  // Face in global coords.
2416  const face& f = patch[patchFacei];
2417 
2418  // Index in newPointi of face centre.
2419  label fc = points.size() + patchFacei + patch.start();
2420 
2421  forAll(f, fp)
2422  {
2423  label fp1 = f.fcIndex(fp);
2424 
2425  triangles.append(labelledTri(f[fp], f[fp1], fc, newPatchi));
2426 
2427  nTriTotal++;
2428  }
2429  }
2430 
2431  if (verbose)
2432  {
2433  Pout<< patch.name() << " : generated " << nTriTotal
2434  << " triangles from " << patch.size() << " faces with"
2435  << " new patchid " << newPatchi << endl;
2436  }
2437 
2438  newPatchi++;
2439  }
2440  triangles.shrink();
2441 
2442 
2443  // Create globally numbered tri surface
2444  triSurface rawSurface(triangles, newPoints);
2445 
2446  // Create locally numbered tri surface
2447  triSurface surface
2448  (
2449  rawSurface.localFaces(),
2450  rawSurface.localPoints()
2451  );
2452 
2453  // Add patch names to surface
2454  surface.patches().setSize(newPatchi);
2455 
2456  newPatchi = 0;
2457 
2458  for (const label patchi : includePatches)
2459  {
2460  const polyPatch& patch = bMesh[patchi];
2461 
2462  surface.patches()[newPatchi].name() = patch.name();
2463  surface.patches()[newPatchi].geometricType() = patch.type();
2464 
2465  newPatchi++;
2466  }
2467 
2468  return surface;
2469 }
2470 
2471 
2473 {
2474  // Vertices in geompack notation. Note that could probably just use
2475  // pts.begin() if double precision.
2476  List<doubleScalar> geompackVertices(2*pts.size());
2477  label doubleI = 0;
2478  for (const vector2D& pt : pts)
2479  {
2480  geompackVertices[doubleI++] = pt[0];
2481  geompackVertices[doubleI++] = pt[1];
2482  }
2483 
2484  // Storage for triangles
2485  int m2 = 3;
2486  List<int> triangle_node(m2*3*pts.size());
2487  List<int> triangle_neighbor(m2*3*pts.size());
2488 
2489  // Triangulate
2490  int nTris = 0;
2491  int err = dtris2
2492  (
2493  pts.size(),
2494  geompackVertices.begin(),
2495  &nTris,
2496  triangle_node.begin(),
2497  triangle_neighbor.begin()
2498  );
2499 
2500  if (err != 0)
2501  {
2503  << "Failed dtris2 with vertices:" << pts.size()
2504  << abort(FatalError);
2505  }
2506 
2507  // Trim
2508  triangle_node.setSize(3*nTris);
2509  triangle_neighbor.setSize(3*nTris);
2510 
2511  // Convert to triSurface.
2512  List<labelledTri> faces(nTris);
2513 
2514  forAll(faces, i)
2515  {
2516  faces[i] = labelledTri
2517  (
2518  triangle_node[3*i]-1,
2519  triangle_node[3*i+1]-1,
2520  triangle_node[3*i+2]-1,
2521  0
2522  );
2523  }
2524 
2525  pointField points(pts.size());
2526  forAll(pts, i)
2527  {
2528  points[i][0] = pts[i][0];
2529  points[i][1] = pts[i][1];
2530  points[i][2] = 0.0;
2531  }
2532 
2533  return triSurface(faces, points);
2534 }
2535 
2536 
2539  const triPointRef& tri,
2540  const point& p,
2541  FixedList<scalar, 3>& weights
2542 )
2543 {
2544  // calculate triangle edge vectors and triangle face normal
2545  // the 'i':th edge is opposite node i
2547  edge[0] = tri.c()-tri.b();
2548  edge[1] = tri.a()-tri.c();
2549  edge[2] = tri.b()-tri.a();
2550 
2551  const vector triangleFaceNormal = edge[1] ^ edge[2];
2552 
2553  // calculate edge normal (pointing inwards)
2554  FixedList<vector, 3> normal;
2555  for (label i=0; i<3; i++)
2556  {
2557  normal[i] = normalised(triangleFaceNormal ^ edge[i]);
2558  }
2559 
2560  weights[0] = ((p-tri.b()) & normal[0]) / max(VSMALL, normal[0] & edge[1]);
2561  weights[1] = ((p-tri.c()) & normal[1]) / max(VSMALL, normal[1] & edge[2]);
2562  weights[2] = ((p-tri.a()) & normal[2]) / max(VSMALL, normal[2] & edge[0]);
2563 }
2564 
2565 
2566 // Calculate weighting factors from samplePts to triangle it is in.
2567 // Uses linear search.
2570  const triSurface& s,
2571  const pointField& samplePts,
2572  List<FixedList<label, 3>>& allVerts,
2573  List<FixedList<scalar, 3>>& allWeights
2574 )
2575 {
2576  allVerts.setSize(samplePts.size());
2577  allWeights.setSize(samplePts.size());
2578 
2579  const pointField& points = s.points();
2580 
2581  forAll(samplePts, i)
2582  {
2583  const point& samplePt = samplePts[i];
2584 
2585  FixedList<label, 3>& verts = allVerts[i];
2586  FixedList<scalar, 3>& weights = allWeights[i];
2587 
2588  scalar minDistance = GREAT;
2589 
2590  for (const labelledTri& f : s)
2591  {
2592  triPointRef tri(f.tri(points));
2593 
2594  label nearType, nearLabel;
2595 
2596  pointHit nearest = tri.nearestPointClassify
2597  (
2598  samplePt,
2599  nearType,
2600  nearLabel
2601  );
2602 
2603  if (nearest.hit())
2604  {
2605  // samplePt inside triangle
2606  verts[0] = f[0];
2607  verts[1] = f[1];
2608  verts[2] = f[2];
2609 
2610  calcInterpolationWeights(tri, nearest.rawPoint(), weights);
2611 
2612  //Pout<< "calcScalingFactors : samplePt:" << samplePt
2613  // << " inside triangle:" << facei
2614  // << " verts:" << verts
2615  // << " weights:" << weights
2616  // << endl;
2617 
2618  break;
2619  }
2620  else if (nearest.distance() < minDistance)
2621  {
2622  minDistance = nearest.distance();
2623 
2624  // Outside triangle. Store nearest.
2625 
2626  if (nearType == triPointRef::POINT)
2627  {
2628  verts[0] = f[nearLabel];
2629  weights[0] = 1;
2630  verts[1] = -1;
2631  weights[1] = -GREAT;
2632  verts[2] = -1;
2633  weights[2] = -GREAT;
2634 
2635  //Pout<< "calcScalingFactors : samplePt:" << samplePt
2636  // << " distance:" << nearest.distance()
2637  // << " from point:" << points[f[nearLabel]]
2638  // << endl;
2639  }
2640  else if (nearType == triPointRef::EDGE)
2641  {
2642  verts[0] = f[nearLabel];
2643  verts[1] = f[f.fcIndex(nearLabel)];
2644  verts[2] = -1;
2645 
2646  const point& p0 = points[verts[0]];
2647  const point& p1 = points[verts[1]];
2648 
2649  scalar s = min
2650  (
2651  1,
2652  max
2653  (
2654  0,
2655  mag(nearest.rawPoint() - p0)/mag(p1 - p0)
2656  )
2657  );
2658 
2659  // Interpolate
2660  weights[0] = 1 - s;
2661  weights[1] = s;
2662  weights[2] = -GREAT;
2663 
2664  //Pout<< "calcScalingFactors : samplePt:" << samplePt
2665  // << " distance:" << nearest.distance()
2666  // << " from edge:" << p0 << p1 << " s:" << s
2667  // << endl;
2668  }
2669  else
2670  {
2671  // triangle. Can only happen because of truncation errors.
2672  verts[0] = f[0];
2673  verts[1] = f[1];
2674  verts[2] = f[2];
2675 
2676  calcInterpolationWeights(tri, nearest.rawPoint(), weights);
2677 
2678  //Pout<< "calcScalingFactors : samplePt:" << samplePt
2679  // << " distance:" << nearest.distance()
2680  // << " to verts:" << verts
2681  // << " weights:" << weights
2682  // << endl;
2683 
2684  break;
2685  }
2686  }
2687  }
2688  }
2689 }
2690 
2691 
2692 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2693 // Checking:
2694 
2697  const triSurface& surf,
2698  const label facei,
2699  const bool verbose
2700 )
2701 {
2702  typedef labelledTri FaceType;
2703  const FaceType& f = surf[facei];
2704 
2705  // Simple check on indices ok.
2706  for (const label pointi : f)
2707  {
2708  if (pointi < 0 || pointi >= surf.points().size())
2709  {
2710  if (verbose)
2711  {
2713  << "triangle " << facei << " vertices " << f
2714  << " uses point indices outside point range 0.."
2715  << surf.points().size()-1 << endl;
2716  }
2717  return false;
2718  }
2719  }
2720 
2721  if (f[0] == f[1] || f[0] == f[2] || f[1] == f[2])
2722  {
2723  if (verbose)
2724  {
2726  << "triangle " << facei
2727  << " uses non-unique vertices " << f
2728  << " coords:" << f.points(surf.points()) << endl;
2729  }
2730  return false;
2731  }
2732 
2733  // duplicate triangle check
2734 
2735  const labelList& fFaces = surf.faceFaces()[facei];
2736 
2737  // Check if faceNeighbours use same points as this face.
2738  // Note: discards normal information - sides of baffle are merged.
2739  for (const label nbrFacei : fFaces)
2740  {
2741  if (nbrFacei <= facei)
2742  {
2743  // lower numbered faces already checked
2744  continue;
2745  }
2746 
2747  const FaceType& nbrF = surf[nbrFacei];
2748 
2749  // Same as calling triFace::compare(f, nbrF) == 1 only
2750  if
2751  (
2752  (f[0] == nbrF[0] || f[0] == nbrF[1] || f[0] == nbrF[2])
2753  && (f[1] == nbrF[0] || f[1] == nbrF[1] || f[1] == nbrF[2])
2754  && (f[2] == nbrF[0] || f[2] == nbrF[1] || f[2] == nbrF[2])
2755  )
2756  {
2757  if (verbose)
2758  {
2760  << "triangle " << facei << " vertices " << f
2761  << " has the same vertices as triangle " << nbrFacei
2762  << " vertices " << nbrF
2763  << " coords:" << f.points(surf.points()) << endl;
2764  }
2765 
2766  return false;
2767  }
2768  }
2769 
2770  return true;
2771 }
2772 
2773 
2776  const MeshedSurface<face>& surf,
2777  const label facei,
2778  const bool verbose
2779 )
2780 {
2781  typedef face FaceType;
2782  const FaceType& f = surf[facei];
2783 
2784  if (f.size() != 3)
2785  {
2786  if (verbose)
2787  {
2789  << "face " << facei
2790  << " is not a triangle, it has " << f.size()
2791  << " indices" << endl;
2792  }
2793  return false;
2794  }
2795 
2796  // Simple check on indices ok.
2797  for (const label pointi : f)
2798  {
2799  if (pointi < 0 || pointi >= surf.points().size())
2800  {
2801  if (verbose)
2802  {
2804  << "triangle " << facei << " vertices " << f
2805  << " uses point indices outside point range 0.."
2806  << surf.points().size()-1 << endl;
2807  }
2808  return false;
2809  }
2810  }
2811 
2812  if (f[0] == f[1] || f[0] == f[2] || f[1] == f[2])
2813  {
2814  if (verbose)
2815  {
2817  << "triangle " << facei
2818  << " uses non-unique vertices " << f
2819  << " coords:" << f.points(surf.points()) << endl;
2820  }
2821  return false;
2822  }
2823 
2824  // duplicate triangle check
2825 
2826  const labelList& fFaces = surf.faceFaces()[facei];
2827 
2828  // Check if faceNeighbours use same points as this face.
2829  // Note: discards normal information - sides of baffle are merged.
2830  for (const label nbrFacei : fFaces)
2831  {
2832  if (nbrFacei <= facei)
2833  {
2834  // lower numbered faces already checked
2835  continue;
2836  }
2837 
2838  const FaceType& nbrF = surf[nbrFacei];
2839 
2840  // Same as calling triFace::compare(f, nbrF) == 1 only
2841  if
2842  (
2843  (f[0] == nbrF[0] || f[0] == nbrF[1] || f[0] == nbrF[2])
2844  && (f[1] == nbrF[0] || f[1] == nbrF[1] || f[1] == nbrF[2])
2845  && (f[2] == nbrF[0] || f[2] == nbrF[1] || f[2] == nbrF[2])
2846  )
2847  {
2848  if (verbose)
2849  {
2851  << "triangle " << facei << " vertices " << f
2852  << " has the same vertices as triangle " << nbrFacei
2853  << " vertices " << nbrF
2854  << " coords:" << f.points(surf.points()) << endl;
2855  }
2856  return false;
2857  }
2858  }
2859 
2860  return true;
2861 }
2862 
2863 
2864 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2865 // Tracking:
2866 
2867 // Test point on surface to see if is on face,edge or point.
2870  const triSurface& s,
2871  const label triI,
2872  const point& trianglePoint
2873 )
2874 {
2875  surfaceLocation nearest;
2876 
2877  // Nearest point could be on point or edge. Retest.
2878  label index, elemType;
2879  //bool inside =
2880  triPointRef(s[triI].tri(s.points())).classify
2881  (
2882  trianglePoint,
2883  elemType,
2884  index
2885  );
2886 
2887  nearest.setPoint(trianglePoint);
2888 
2889  if (elemType == triPointRef::NONE)
2890  {
2891  nearest.setHit();
2892  nearest.setIndex(triI);
2893  nearest.elementType() = triPointRef::NONE;
2894  }
2895  else if (elemType == triPointRef::EDGE)
2896  {
2897  nearest.setMiss();
2898  nearest.setIndex(s.faceEdges()[triI][index]);
2899  nearest.elementType() = triPointRef::EDGE;
2900  }
2901  else //if (elemType == triPointRef::POINT)
2902  {
2903  nearest.setMiss();
2904  nearest.setIndex(s.localFaces()[triI][index]);
2905  nearest.elementType() = triPointRef::POINT;
2906  }
2907 
2908  return nearest;
2909 }
2910 
2911 
2914  const triSurface& s,
2915  const surfaceLocation& start,
2916  const surfaceLocation& end,
2917  const plane& cutPlane
2918 )
2919 {
2920  // Start off from starting point
2921  surfaceLocation nearest = start;
2922  nearest.setMiss();
2923 
2924  // See if in same triangle as endpoint. If so snap.
2925  snapToEnd(s, end, nearest);
2926 
2927  if (!nearest.hit())
2928  {
2929  // Not yet at end point
2930 
2931  if (start.elementType() == triPointRef::NONE)
2932  {
2933  // Start point is inside triangle. Trivial cases already handled
2934  // above.
2935 
2936  // end point is on edge or point so cross current triangle to
2937  // see which edge is cut.
2938 
2939  nearest = cutEdge
2940  (
2941  s,
2942  start.index(), // triangle
2943  -1, // excludeEdge
2944  -1, // excludePoint
2945  start.rawPoint(),
2946  cutPlane,
2947  end.rawPoint()
2948  );
2949  nearest.elementType() = triPointRef::EDGE;
2950  nearest.triangle() = start.index();
2951  nearest.setMiss();
2952  }
2953  else if (start.elementType() == triPointRef::EDGE)
2954  {
2955  // Pick connected triangle that is most in direction.
2956  const labelList& eFaces = s.edgeFaces()[start.index()];
2957 
2958  nearest = visitFaces
2959  (
2960  s,
2961  eFaces,
2962  start,
2963  start.index(), // excludeEdgeI
2964  -1, // excludePointi
2965  end,
2966  cutPlane
2967  );
2968  }
2969  else // start.elementType() == triPointRef::POINT
2970  {
2971  const labelList& pFaces = s.pointFaces()[start.index()];
2972 
2973  nearest = visitFaces
2974  (
2975  s,
2976  pFaces,
2977  start,
2978  -1, // excludeEdgeI
2979  start.index(), // excludePointi
2980  end,
2981  cutPlane
2982  );
2983  }
2984  snapToEnd(s, end, nearest);
2985  }
2986  return nearest;
2987 }
2988 
2989 
2992  const triSurface& s,
2993  const surfaceLocation& endInfo,
2994  const plane& cutPlane,
2995  surfaceLocation& hitInfo
2996 )
2997 {
2998  //OFstream str("track.obj");
2999  //label vertI = 0;
3000  //meshTools::writeOBJ(str, hitInfo.rawPoint());
3001  //vertI++;
3002 
3003  // Track across surface.
3004  while (true)
3005  {
3006  //Pout<< "Tracking from:" << nl
3007  // << " " << hitInfo.info()
3008  // << endl;
3009 
3010  hitInfo = trackToEdge
3011  (
3012  s,
3013  hitInfo,
3014  endInfo,
3015  cutPlane
3016  );
3017 
3018  //meshTools::writeOBJ(str, hitInfo.rawPoint());
3019  //vertI++;
3020  //str<< "l " << vertI-1 << ' ' << vertI << nl;
3021 
3022  //Pout<< "Tracked to:" << nl
3023  // << " " << hitInfo.info() << endl;
3024 
3025  if (hitInfo.hit() || hitInfo.triangle() == -1)
3026  {
3027  break;
3028  }
3029  }
3030 }
3031 
3032 
3033 // ************************************************************************* //
Foam::PrimitivePatch::points
const Field< point_type > & points() const noexcept
Return reference to global points.
Definition: PrimitivePatch.H:299
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
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:301
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:262
Foam::edgeList
List< edge > edgeList
A List of edges.
Definition: edgeList.H:63
Foam::fileName
A class for handling file names.
Definition: fileName.H:73
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:63
Foam::PrimitivePatch::edges
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
Definition: PrimitivePatch.C:183
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::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:2376
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:2472
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:461
Foam::PrimitivePatch::nEdges
label nEdges() const
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:175
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
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:275
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::HashSet< label, Hash< label > >
Foam::DynamicList::shrink
DynamicList< T, SizeMin > & shrink()
Shrink the allocated space to the number of elements used.
Definition: DynamicListI.H:434
Foam::triSurface::patches
const geometricSurfacePatchList & patches() const noexcept
Definition: triSurface.H:399
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:59
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
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::List::setSize
void setSize(const label n)
Alias for resize()
Definition: List.H:222
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:288
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:95
Foam::primitiveMesh::nBoundaryFaces
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces)
Definition: primitiveMeshI.H:84
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:2538
newPointi
label newPointi
Definition: readKivaGrid.H:496
Foam::PrimitivePatch::nPoints
label nPoints() const
Number of points supporting patch faces.
Definition: PrimitivePatch.H:316
Foam::FatalError
error FatalError
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
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:317
Foam::FixedList::setSize
void setSize(const label n)
Dummy function, to make FixedList consistent with List.
Definition: FixedList.H:304
Foam::triangle::POINT
Close to point.
Definition: triangle.H:96
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:359
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:487
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:2913
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:2869
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:453
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
Foam::triangle::EDGE
Close to edge.
Definition: triangle.H:97
Foam::nl
constexpr char nl
Definition: Ostream.H:404
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:191
D
const dimensionedScalar & D
Definition: solveBulkSurfactant.H:4
Foam::labelledTri
A triFace with additional (region) index.
Definition: labelledTri.H:57
Foam::PrimitivePatch::faceNormals
const Field< point_type > & faceNormals() const
Return face unit normals for patch.
Definition: PrimitivePatch.C:445
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:249
Foam::triSurfaceTools::validTri
static bool validTri(const triSurface &, const label facei, const bool verbose=true)
Check single triangle for (topological) validity.
Definition: triSurfaceTools.C:2696
Foam::labelHashSet
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
Foam::MeshedSurface< face >
Foam::MeshedSurface::size
label size() const
The surface size is the number of faces.
Definition: MeshedSurface.H:407
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:328
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].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
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:2991
Foam::triPointRef
triangle< point, const point & > triPointRef
A triangle using referred points.
Definition: triangle.H:71
MeshedSurface.H
Foam::PrimitivePatch
A list of faces which address into the list of points.
Definition: PrimitivePatch.H:79
sample
Minimal example by using system/controlDict.functions: