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