collapseBase.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2022 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "collapseBase.H"
30 #include "triSurfaceTools.H"
31 #include "argList.H"
32 #include "OFstream.H"
33 #include "SubList.H"
34 #include "labelPair.H"
35 #include "meshTools.H"
36 #include "OSspecific.H"
37 
38 using namespace Foam;
39 
40 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
41 
43 //static void writeRegionOBJ
44 //(
45 // const triSurface& surf,
46 // const label regionI,
47 // const labelList& collapseRegion,
48 // const labelList& outsideVerts
49 //)
50 //{
51 // fileName dir("regions");
52 //
53 // mkDir(dir);
54 // fileName regionName(dir / "region_" + name(regionI) + ".obj");
55 //
56 // Pout<< "Dumping region " << regionI << " to file " << regionName << endl;
57 //
58 // boolList include(surf.size(), false);
59 //
60 // forAll(collapseRegion, facei)
61 // {
62 // if (collapseRegion[facei] == regionI)
63 // {
64 // include[facei] = true;
65 // }
66 // }
67 //
68 // triSurface regionSurf(surf.subsetMesh(include));
69 //
70 // Pout<< "Region " << regionI << " surface:" << nl;
71 // regionSurf.writeStats(Pout);
72 //
73 // regionSurf.write(regionName);
74 //
75 //
76 // // Dump corresponding outside vertices.
77 // fileName pointsName(dir / "regionPoints_" + name(regionI) + ".obj");
78 //
79 // Pout<< "Dumping region " << regionI << " points to file " << pointsName
80 // << endl;
81 //
82 // OFstream str(pointsName);
83 //
84 // forAll(outsideVerts, i)
85 // {
86 // meshTools::writeOBJ(str, surf.localPoints()[outsideVerts[i]]);
87 // }
88 //}
89 
90 
91 // Split triangle into multiple triangles because edge e being split
92 // into multiple edges.
93 static void splitTri
94 (
95  const labelledTri& f,
96  const edge& e,
97  const labelList& splitPoints,
99 )
100 {
101  //label oldNTris = tris.size();
102 
103  label fp = f.find(e[0]);
104  label fp1 = f.fcIndex(fp);
105  label fp2 = f.fcIndex(fp1);
106 
107  if (f[fp1] == e[1])
108  {
109  // Split triangle along fp to fp1
110  tris.append(labelledTri(f[fp2], f[fp], splitPoints[0], f.region()));
111 
112  for (label i = 1; i < splitPoints.size(); i++)
113  {
114  tris.append
115  (
117  (
118  f[fp2],
119  splitPoints[i-1],
120  splitPoints[i],
121  f.region()
122  )
123  );
124  }
125 
126  tris.append
127  (
129  (
130  f[fp2],
131  splitPoints.last(),
132  f[fp1],
133  f.region()
134  )
135  );
136  }
137  else if (f[fp2] == e[1])
138  {
139  // Split triangle along fp2 to fp. (Reverse order of splitPoints)
140 
141  tris.append
142  (
144  (
145  f[fp1],
146  f[fp2],
147  splitPoints.last(),
148  f.region()
149  )
150  );
151 
152  for (label i = splitPoints.size()-1; i > 0; --i)
153  {
154  tris.append
155  (
157  (
158  f[fp1],
159  splitPoints[i],
160  splitPoints[i-1],
161  f.region()
162  )
163  );
164  }
165 
166  tris.append
167  (
169  (
170  f[fp1],
171  splitPoints[0],
172  f[fp],
173  f.region()
174  )
175  );
176  }
177  else
178  {
180  << "Edge " << e << " not part of triangle " << f
181  << " fp:" << fp
182  << " fp1:" << fp1
183  << " fp2:" << fp2
184  << abort(FatalError);
185  }
186 
187  //Pout<< "Split face " << f << " along edge " << e
188  // << " into triangles:" << endl;
189  //
190  //for (label i = oldNTris; i < tris.size(); i++)
191  //{
192  // Pout<< " " << tris[i] << nl;
193  //}
194 }
195 
196 
197 // Insert scalar into sortedVerts/sortedWeights so the weights are in
198 // incrementing order.
199 static bool insertSorted
200 (
201  const label vertI,
202  const scalar weight,
203 
204  labelList& sortedVerts,
205  scalarField& sortedWeights
206 )
207 {
208  if (sortedVerts.found(vertI))
209  {
211  << " which is already in list of sorted vertices "
212  << sortedVerts << abort(FatalError);
213  }
214 
215  if (weight <= 0 || weight >= 1)
216  {
218  << " with illegal weight " << weight
219  << " into list of sorted vertices "
220  << sortedVerts << abort(FatalError);
221  }
222 
223 
224  label insertI = sortedVerts.size();
225 
226  forAll(sortedVerts, sortedI)
227  {
228  scalar w = sortedWeights[sortedI];
229 
230  if (mag(w - weight) < SMALL)
231  {
233  << "Trying to insert weight " << weight << " which is close to"
234  << " existing weight " << w << " in " << sortedWeights
235  << endl;
236  }
237 
238  if (w > weight)
239  {
240  // Start inserting before sortedI.
241  insertI = sortedI;
242  break;
243  }
244  }
245 
246 
247  label sz = sortedWeights.size();
248 
249  sortedWeights.setSize(sz + 1);
250  sortedVerts.setSize(sz + 1);
251 
252  // Leave everything up to (not including) insertI intact.
253 
254  // Make space by copying from insertI up.
255  for (label i = sz-1; i >= insertI; --i)
256  {
257  sortedWeights[i+1] = sortedWeights[i];
258  sortedVerts[i+1] = sortedVerts[i];
259  }
260  sortedWeights[insertI] = weight;
261  sortedVerts[insertI] = vertI;
262 
263  return true;
264 }
265 
266 
267 // Is triangle candidate for collapse? Small height or small quality
268 bool isSliver
269 (
270  const triSurface& surf,
271  const scalar minLen,
272  const scalar minQuality,
273  const label facei,
274  const label edgeI
275 )
276 {
277  const pointField& localPoints = surf.localPoints();
278 
279  // Check
280  // - opposite vertex projects onto base edge
281  // - normal distance is small
282  // - or triangle quality is small
283 
284  label opposite0 =
286  (
287  surf,
288  facei,
289  edgeI
290  );
291 
292  const edge& e = surf.edges()[edgeI];
293  const labelledTri& f = surf[facei];
294 
295  pointHit pHit =
296  e.line(localPoints).nearestDist
297  (
298  localPoints[opposite0]
299  );
300 
301  if
302  (
303  pHit.hit()
304  && (
305  pHit.distance() < minLen
306  || f.tri(surf.points()).quality() < minQuality
307  )
308  )
309  {
310  // Remove facei and split all other faces using this
311  // edge. This is done by 'replacing' the edgeI with the
312  // opposite0 vertex
313  //Pout<< "Splitting face " << facei << " since distance "
314  // << pHit.distance()
315  // << " from vertex " << opposite0
316  // << " to edge " << edgeI
317  // << " points "
318  // << localPoints[e[0]]
319  // << localPoints[e[1]]
320  // << " is too small or triangle quality "
321  // << f.tri(surf.points()).quality()
322  // << " too small." << endl;
323 
324  return true;
325  }
326 
327  return false;
328 }
329 
330 
331 // Mark all faces that are going to be collapsed.
332 // faceToEdge: per face -1 or the base edge of the face.
333 static void markCollapsedFaces
334 (
335  const triSurface& surf,
336  const scalar minLen,
337  const scalar minQuality,
338  labelList& faceToEdge
339 )
340 {
341  faceToEdge.setSize(surf.size());
342  faceToEdge = -1;
343 
344  const labelListList& edgeFaces = surf.edgeFaces();
345 
346  forAll(edgeFaces, edgeI)
347  {
348  const labelList& eFaces = surf.edgeFaces()[edgeI];
349 
350  forAll(eFaces, i)
351  {
352  label facei = eFaces[i];
353 
354  bool isCandidate = isSliver(surf, minLen, minQuality, facei, edgeI);
355 
356  if (isCandidate)
357  {
358  // Mark face as being collapsed
359  if (faceToEdge[facei] != -1)
360  {
362  << "Cannot collapse face " << facei << " since "
363  << " is marked to be collapsed both to edge "
364  << faceToEdge[facei] << " and " << edgeI
365  << abort(FatalError);
366  }
367 
368  faceToEdge[facei] = edgeI;
369  }
370  }
371  }
372 }
373 
374 
375 // Recurse through collapsed faces marking all of them with regionI (in
376 // collapseRegion)
377 static void markRegion
378 (
379  const triSurface& surf,
380  const labelList& faceToEdge,
381  const label regionI,
382  const label facei,
383  labelList& collapseRegion
384 )
385 {
386  if (faceToEdge[facei] == -1 || collapseRegion[facei] != -1)
387  {
389  << "Problem : crossed into uncollapsed/regionized face"
390  << abort(FatalError);
391  }
392 
393  collapseRegion[facei] = regionI;
394 
395  // Recurse across edges to collapsed neighbours
396 
397  const labelList& fEdges = surf.faceEdges()[facei];
398 
399  forAll(fEdges, fEdgeI)
400  {
401  label edgeI = fEdges[fEdgeI];
402 
403  const labelList& eFaces = surf.edgeFaces()[edgeI];
404 
405  forAll(eFaces, i)
406  {
407  label nbrFacei = eFaces[i];
408 
409  if (faceToEdge[nbrFacei] != -1)
410  {
411  if (collapseRegion[nbrFacei] == -1)
412  {
413  markRegion
414  (
415  surf,
416  faceToEdge,
417  regionI,
418  nbrFacei,
419  collapseRegion
420  );
421  }
422  else if (collapseRegion[nbrFacei] != regionI)
423  {
425  << "Edge:" << edgeI << " between face " << facei
426  << " with region " << regionI
427  << " and face " << nbrFacei
428  << " with region " << collapseRegion[nbrFacei]
429  << endl;
430  }
431  }
432  }
433  }
434 }
435 
436 
437 // Mark every face with region (in collapseRegion) (or -1).
438 // Return number of regions.
439 static label markRegions
440 (
441  const triSurface& surf,
442  const labelList& faceToEdge,
443  labelList& collapseRegion
444 )
445 {
446  label regionI = 0;
447 
448  forAll(faceToEdge, facei)
449  {
450  if (collapseRegion[facei] == -1 && faceToEdge[facei] != -1)
451  {
452  //Pout<< "markRegions : Marking region:" << regionI
453  // << " starting from face " << facei << endl;
454 
455  // Collapsed face. Mark connected region with current region number
456  markRegion(surf, faceToEdge, regionI++, facei, collapseRegion);
457  }
458  }
459  return regionI;
460 }
461 
462 
463 // Type of region.
464 // -1 : edge inbetween uncollapsed faces.
465 // -2 : edge inbetween collapsed faces
466 // >=0 : edge inbetween uncollapsed and collapsed region. Returns region.
467 static label edgeType
468 (
469  const triSurface& surf,
470  const labelList& collapseRegion,
471  const label edgeI
472 )
473 {
474  const labelList& eFaces = surf.edgeFaces()[edgeI];
475 
476  // Detect if edge is inbetween collapseRegion and non-collapse face
477  bool usesUncollapsed = false;
478  label usesRegion = -1;
479 
480  forAll(eFaces, i)
481  {
482  label facei = eFaces[i];
483 
484  label region = collapseRegion[facei];
485 
486  if (region == -1)
487  {
488  usesUncollapsed = true;
489  }
490  else if (usesRegion == -1)
491  {
492  usesRegion = region;
493  }
494  else if (usesRegion != region)
495  {
497  }
498  else
499  {
500  // Equal regions.
501  }
502  }
503 
504  if (usesUncollapsed)
505  {
506  if (usesRegion == -1)
507  {
508  // uncollapsed faces only.
509  return -1;
510  }
511  else
512  {
513  // between uncollapsed and collapsed.
514  return usesRegion;
515  }
516  }
517  else
518  {
519  if (usesRegion == -1)
520  {
522  return -2;
523  }
524  else
525  {
526  return -2;
527  }
528  }
529 }
530 
531 
532 // Get points on outside edge of region (= outside points)
533 static labelListList getOutsideVerts
534 (
535  const triSurface& surf,
536  const labelList& collapseRegion,
537  const label nRegions
538 )
539 {
540  const labelListList& edgeFaces = surf.edgeFaces();
541 
542  // Per region all the outside vertices.
543  labelListList outsideVerts(nRegions);
544 
545  forAll(edgeFaces, edgeI)
546  {
547  // Detect if edge is inbetween collapseRegion and non-collapse face
548  label regionI = edgeType(surf, collapseRegion, edgeI);
549 
550  if (regionI >= 0)
551  {
552  // Edge borders both uncollapsed face and collapsed face on region
553  // usesRegion.
554 
555  const edge& e = surf.edges()[edgeI];
556 
557  labelList& regionVerts = outsideVerts[regionI];
558 
559  // Add both edge points to regionVerts.
560  forAll(e, eI)
561  {
562  label v = e[eI];
563 
564  if (!regionVerts.found(v))
565  {
566  label sz = regionVerts.size();
567  regionVerts.setSize(sz+1);
568  regionVerts[sz] = v;
569  }
570  }
571  }
572  }
573 
574  return outsideVerts;
575 }
576 
577 
578 // n^2 search for furthest removed point pair.
579 static labelPair getSpanPoints
580 (
581  const triSurface& surf,
582  const labelList& outsideVerts
583 )
584 {
585  const pointField& localPoints = surf.localPoints();
586 
587  scalar maxDist = -GREAT;
588  labelPair maxPair;
589 
590  forAll(outsideVerts, i)
591  {
592  label v0 = outsideVerts[i];
593 
594  for (label j = i+1; j < outsideVerts.size(); j++)
595  {
596  label v1 = outsideVerts[j];
597 
598  scalar d = mag(localPoints[v0] - localPoints[v1]);
599 
600  if (d > maxDist)
601  {
602  maxDist = d;
603  maxPair[0] = v0;
604  maxPair[1] = v1;
605  }
606  }
607  }
608 
609  return maxPair;
610 }
611 
612 
613 // Project all non-span points onto the span edge.
614 static void projectNonSpanPoints
615 (
616  const triSurface& surf,
617  const labelList& outsideVerts,
618  const labelPair& spanPair,
619  labelList& sortedVertices,
620  scalarField& sortedWeights
621 )
622 {
623  const point& p0 = surf.localPoints()[spanPair[0]];
624  const point& p1 = surf.localPoints()[spanPair[1]];
625 
626  forAll(outsideVerts, i)
627  {
628  label v = outsideVerts[i];
629 
630  if (v != spanPair[0] && v != spanPair[1])
631  {
632  // Is a non-span point. Project onto spanning edge.
633 
634  pointHit pHit =
635  linePointRef(p0, p1).nearestDist
636  (
637  surf.localPoints()[v]
638  );
639 
640  if (!pHit.hit())
641  {
643  << abort(FatalError);
644  }
645 
646  scalar w = pHit.point().dist(p0) / p1.dist(p0);
647 
648  insertSorted(v, w, sortedVertices, sortedWeights);
649  }
650  }
651 }
652 
653 
654 // Slice part of the orderVertices (and optionally reverse) for this edge.
655 static void getSplitVerts
656 (
657  const triSurface& surf,
658  const label regionI,
659  const labelPair& spanPoints,
660  const labelList& orderedVerts,
661  const scalarField& orderedWeights,
662  const label edgeI,
663 
664  labelList& splitVerts,
665  scalarField& splitWeights
666 )
667 {
668  const edge& e = surf.edges()[edgeI];
669  const label sz = orderedVerts.size();
670 
671  if (e[0] == spanPoints[0])
672  {
673  // Edge in same order as spanPoints&orderedVerts. Keep order.
674 
675  if (e[1] == spanPoints[1])
676  {
677  // Copy all.
678  splitVerts = orderedVerts;
679  splitWeights = orderedWeights;
680  }
681  else
682  {
683  // Copy upto (but not including) e[1]
684  label i1 = orderedVerts.find(e[1]);
685  splitVerts = SubList<label>(orderedVerts, i1, 0);
686  splitWeights = SubList<scalar>(orderedWeights, i1, 0);
687  }
688  }
689  else if (e[0] == spanPoints[1])
690  {
691  // Reverse.
692 
693  if (e[1] == spanPoints[0])
694  {
695  // Copy all.
696  splitVerts = orderedVerts;
697  reverse(splitVerts);
698  splitWeights = orderedWeights;
699  reverse(splitWeights);
700  }
701  else
702  {
703  // Copy downto (but not including) e[1]
704 
705  label i1 = orderedVerts.find(e[1]);
706  splitVerts = SubList<label>(orderedVerts, sz-(i1+1), i1+1);
707  reverse(splitVerts);
708  splitWeights = SubList<scalar>(orderedWeights, sz-(i1+1), i1+1);
709  reverse(splitWeights);
710  }
711  }
712  else if (e[1] == spanPoints[0])
713  {
714  // Reverse.
715 
716  // Copy upto (but not including) e[0]
717 
718  label i0 = orderedVerts.find(e[0]);
719  splitVerts = SubList<label>(orderedVerts, i0, 0);
720  reverse(splitVerts);
721  splitWeights = SubList<scalar>(orderedWeights, i0, 0);
722  reverse(splitWeights);
723  }
724  else if (e[1] == spanPoints[1])
725  {
726  // Copy from (but not including) e[0] to end
727 
728  label i0 = orderedVerts.find(e[0]);
729  splitVerts = SubList<label>(orderedVerts, sz-(i0+1), i0+1);
730  splitWeights = SubList<scalar>(orderedWeights, sz-(i0+1), i0+1);
731  }
732  else
733  {
734  label i0 = orderedVerts.find(e[0]);
735  label i1 = orderedVerts.find(e[1]);
736 
737  if (i0 == -1 || i1 == -1)
738  {
740  << "Did not find edge in projected vertices." << nl
741  << "region:" << regionI << nl
742  << "spanPoints:" << spanPoints
743  << " coords:" << surf.localPoints()[spanPoints[0]]
744  << surf.localPoints()[spanPoints[1]] << nl
745  << "edge:" << edgeI
746  << " verts:" << e
747  << " coords:" << surf.localPoints()[e[0]]
748  << surf.localPoints()[e[1]] << nl
749  << "orderedVerts:" << orderedVerts << nl
750  << abort(FatalError);
751  }
752 
753  if (i0 < i1)
754  {
755  splitVerts = SubList<label>(orderedVerts, i1-i0-1, i0+1);
756  splitWeights = SubList<scalar>(orderedWeights, i1-i0-1, i0+1);
757  }
758  else
759  {
760  splitVerts = SubList<label>(orderedVerts, i0-i1-1, i1+1);
761  reverse(splitVerts);
762  splitWeights = SubList<scalar>(orderedWeights, i0-i1-1, i1+1);
763  reverse(splitWeights);
764  }
765  }
766 }
767 
768 
769 label collapseBase
770 (
771  triSurface& surf,
772  const scalar minLen,
773  const scalar minQuality
774 )
775 {
776  label nTotalSplit = 0;
777 
778  // label iter = 0;
779 
780  while (true)
781  {
782  // Detect faces to collapse
783  // ~~~~~~~~~~~~~~~~~~~~~~~~
784 
785  // -1 or edge the face is collapsed onto.
786  labelList faceToEdge(surf.size(), -1);
787 
788  // Calculate faceToEdge (face collapses)
789  markCollapsedFaces(surf, minLen, minQuality, faceToEdge);
790 
791 
792  // Find regions of connected collapsed faces
793  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
794 
795  // per face -1 or region
796  labelList collapseRegion(surf.size(), -1);
797 
798  label nRegions = markRegions(surf, faceToEdge, collapseRegion);
799 
800  //Pout<< "Detected " << nRegions << " regions of faces to be collapsed"
801  // << nl << endl;
802 
803  // Pick up all vertices on outside of region
804  labelListList outsideVerts
805  (
806  getOutsideVerts(surf, collapseRegion, nRegions)
807  );
808 
809  // For all regions determine maximum distance between points
810  List<labelPair> spanPoints(nRegions);
811  labelListList orderedVertices(nRegions);
812  List<scalarField> orderedWeights(nRegions);
813 
814  forAll(spanPoints, regionI)
815  {
816  spanPoints[regionI] = getSpanPoints(surf, outsideVerts[regionI]);
817 
818  //Pout<< "For region " << regionI << " found extrema at points "
819  // << surf.localPoints()[spanPoints[regionI][0]]
820  // << surf.localPoints()[spanPoints[regionI][1]]
821  // << endl;
822 
823  // Project all non-span points onto the span edge.
824  projectNonSpanPoints
825  (
826  surf,
827  outsideVerts[regionI],
828  spanPoints[regionI],
829  orderedVertices[regionI],
830  orderedWeights[regionI]
831  );
832 
833  //Pout<< "For region:" << regionI
834  // << " span:" << spanPoints[regionI]
835  // << " orderedVerts:" << orderedVertices[regionI]
836  // << " orderedWeights:" << orderedWeights[regionI]
837  // << endl;
838 
839  //writeRegionOBJ
840  //(
841  // surf,
842  // regionI,
843  // collapseRegion,
844  // outsideVerts[regionI]
845  //);
846 
847  //Pout<< endl;
848  }
849 
850 
851 
852  // Actually split the edges
853  // ~~~~~~~~~~~~~~~~~~~~~~~~
854 
855 
856  const List<labelledTri>& localFaces = surf.localFaces();
857  const edgeList& edges = surf.edges();
858 
859  label nSplit = 0;
860 
861  // Storage for new triangles.
862  DynamicList<labelledTri> newTris(surf.size());
863 
864  // Whether face has been dealt with (either copied/split or deleted)
865  boolList faceHandled(surf.size(), false);
866 
867 
868  forAll(edges, edgeI)
869  {
870  const edge& e = edges[edgeI];
871 
872  // Detect if edge is inbetween collapseRegion and non-collapse face
873  label regionI = edgeType(surf, collapseRegion, edgeI);
874 
875  if (regionI == -2)
876  {
877  // inbetween collapsed faces. nothing needs to be done.
878  }
879  else if (regionI == -1)
880  {
881  // edge inbetween uncollapsed faces. Handle these later on.
882  }
883  else
884  {
885  // some faces around edge are collapsed.
886 
887  // Find additional set of points on edge to be used to split
888  // the remaining faces.
889 
890  labelList splitVerts;
891  scalarField splitWeights;
892  getSplitVerts
893  (
894  surf,
895  regionI,
896  spanPoints[regionI],
897  orderedVertices[regionI],
898  orderedWeights[regionI],
899  edgeI,
900 
901  splitVerts,
902  splitWeights
903  );
904 
905  if (splitVerts.size())
906  {
907  // Split edge using splitVerts. All non-collapsed triangles
908  // using edge will get split.
909 
910  //{
911  // const pointField& localPoints = surf.localPoints();
912  // Pout<< "edge " << edgeI << ' ' << e
913  // << " points "
914  // << localPoints[e[0]] << ' ' << localPoints[e[1]]
915  // << " split into edges with extra points:"
916  // << endl;
917  // forAll(splitVerts, i)
918  // {
919  // Pout<< " " << splitVerts[i] << " weight "
920  // << splitWeights[i] << nl;
921  // }
922  //}
923 
924  const labelList& eFaces = surf.edgeFaces()[edgeI];
925 
926  forAll(eFaces, i)
927  {
928  label facei = eFaces[i];
929 
930  if (!faceHandled[facei] && faceToEdge[facei] == -1)
931  {
932  // Split face to use vertices.
933  splitTri
934  (
935  localFaces[facei],
936  e,
937  splitVerts,
938  newTris
939  );
940 
941  faceHandled[facei] = true;
942 
943  nSplit++;
944  }
945  }
946  }
947  }
948  }
949 
950  // Copy all unsplit faces
951  forAll(faceHandled, facei)
952  {
953  if (!faceHandled[facei] && faceToEdge[facei] == -1)
954  {
955  newTris.append(localFaces[facei]);
956  }
957  }
958 
959  Info<< "collapseBase : collapsing " << nSplit
960  << " triangles by splitting their base edge."
961  << endl;
962 
963  nTotalSplit += nSplit;
964 
965  if (nSplit == 0)
966  {
967  break;
968  }
969 
970  // Pack the triangles
971  newTris.shrink();
972 
973  //Pout<< "Resetting surface from " << surf.size() << " to "
974  // << newTris.size() << " triangles" << endl;
975  surf = triSurface(newTris, surf.patches(), surf.localPoints());
976 
977  //{
978  // fileName fName("bla" + name(iter) + ".obj");
979  // Pout<< "Writing surf to " << fName << endl;
980  // surf.write(fName);
981  //}
982 
983  // ++iter;
984  }
985 
986  // Remove any unused vertices
987  surf = triSurface(surf.localFaces(), surf.patches(), surf.localPoints());
988 
989  return nTotalSplit;
990 }
991 
992 
993 // ************************************************************************* //
const List< face_type > & localFaces() const
Return patch faces addressing into local point list.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
label collapseBase(triSurface &surf, const scalar minLen, const scalar minQuality)
Keep collapsing all triangles whose height is < minLen or quality < minQ.
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
const Field< point_type > & localPoints() const
Return pointField of points in patch.
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:578
label find(const T &val, label pos=0) const
Find index of the first occurrence of the value.
Definition: UList.C:204
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
bool found(const T &val, label pos=0) const
Same as contains()
Definition: UList.H:840
Routines collapse sliver triangles by splitting the base edge.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:414
label fcIndex(const label i) const noexcept
The forward circular index. The next index in the list which returns to the first at the end of the l...
Definition: UListI.H:52
static label oppositeVertex(const triSurface &surf, const label facei, const label edgeI)
Get vertex (local numbering) opposite edge.
bool hit() const noexcept
Is there a hit.
Definition: pointHit.H:145
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
A List obtained as a section of another List.
Definition: SubList.H:50
const geometricSurfacePatchList & patches() const noexcept
Definition: triSurface.H:509
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
void setSize(const label n)
Alias for resize()
Definition: List.H:289
line< point, const point & > linePointRef
A line using referred points.
Definition: line.H:66
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:51
An edge is a list of two vertex labels. This can correspond to a directed graph edge or an edge on a ...
Definition: edge.H:59
const labelListList & edgeFaces() const
Return edge-face addressing.
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
void reverse(UList< T > &list, const label n)
Reverse the first n elements of the list.
Definition: UListI.H:450
A triFace with additional (region) index.
Definition: labelledTri.H:53
Describes the interaction of a object and a (templated) point. It carries the info of a successful hi...
Definition: pointHit.H:43
const Field< point_type > & points() const noexcept
Return reference to global points.
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicList.H:570
errorManip< error > abort(error &err)
Definition: errorManip.H:139
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
labelList f(nPoints)
T & last()
Access last element of the list, position [size()-1].
Definition: UList.H:828
#define WarningInFunction
Report a warning using Foam::Warning.
scalar distance() const noexcept
Return distance to hit.
Definition: pointHit.H:169
const point_type & point() const noexcept
Return the point, no checks.
Definition: pointHit.H:161
messageStream Info
Information stream (stdout output on master, null elsewhere)
const labelListList & faceEdges() const
Return face-edge addressing.
Triangulated surface description with patch information.
Definition: triSurface.H:71
const volScalarField & p0
Definition: EEqn.H:36
Namespace for OpenFOAM.