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