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