1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "collapseBase.H"
28 #include "triSurfaceTools.H"
32 #include "labelPair.H"
33 #include "meshTools.H"
34 #include "OSspecific.H"
38 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
40 // Dump collapse region to .obj file
41 static void writeRegionOBJ
43 const triSurface& surf,
45 const labelList& collapseRegion,
46 const labelList& outsideVerts
49 fileName dir("regions");
52 fileName regionName(dir / "region_" + name(regionI) + ".obj");
54 Pout<< "Dumping region " << regionI << " to file " << regionName << endl;
56 boolList include(surf.size(), false);
58 forAll(collapseRegion, faceI)
60 if (collapseRegion[faceI] == regionI)
62 include[faceI] = true;
66 labelList pointMap, faceMap;
68 triSurface regionSurf(surf.subsetMesh(include, pointMap, faceMap));
70 //Pout<< "Region " << regionI << " surface:" << nl;
71 //regionSurf.writeStats(Pout);
73 regionSurf.write(regionName);
76 // Dump corresponding outside vertices.
77 fileName pointsName(dir / "regionPoints_" + name(regionI) + ".obj");
79 Pout<< "Dumping region " << regionI << " points to file " << pointsName
82 OFstream str(pointsName);
84 forAll(outsideVerts, i)
86 meshTools::writeOBJ(str, surf.localPoints()[outsideVerts[i]]);
91 // Split triangle into multiple triangles because edge e being split
92 // into multiple edges.
97 const labelList& splitPoints,
98 DynamicList<labelledTri>& tris
101 label oldNTris = tris.size();
103 label fp = findIndex(f, e[0]);
104 label fp1 = (fp+1)%3;
105 label fp2 = (fp1+1)%3;
109 // Split triangle along fp to fp1
110 tris.append(labelledTri(f[fp2], f[fp], splitPoints[0], f.region()));
112 for (label i = 1; i < splitPoints.size(); i++)
131 splitPoints[splitPoints.size()-1],
137 else if (f[fp2] == e[1])
139 // Split triangle along fp2 to fp. (Reverse order of splitPoints)
147 splitPoints[splitPoints.size()-1],
152 for (label i = splitPoints.size()-1; i > 0; --i)
179 FatalErrorIn("splitTri")
180 << "Edge " << e << " not part of triangle " << f
184 << abort(FatalError);
187 Pout<< "Split face " << f << " along edge " << e
188 << " into triangles:" << endl;
190 for (label i = oldNTris; i < tris.size(); i++)
192 Pout<< " " << tris[i] << nl;
197 // Insert scalar into sortedVerts/sortedWeights so the weights are in
198 // incrementing order.
199 static bool insertSorted
204 labelList& sortedVerts,
205 scalarField& sortedWeights
208 if (findIndex(sortedVerts, vertI) != -1)
210 FatalErrorIn("insertSorted") << "Trying to insert vertex " << vertI
211 << " which is already in list of sorted vertices "
212 << sortedVerts << abort(FatalError);
215 if (weight <= 0 || weight >= 1)
217 FatalErrorIn("insertSorted") << "Trying to insert vertex " << vertI
218 << " with illegal weight " << weight
219 << " into list of sorted vertices "
220 << sortedVerts << abort(FatalError);
224 label insertI = sortedVerts.size();
226 forAll(sortedVerts, sortedI)
228 scalar w = sortedWeights[sortedI];
230 if (mag(w - weight) < SMALL)
232 WarningIn("insertSorted")
233 << "Trying to insert weight " << weight << " which is close to"
234 << " existing weight " << w << " in " << sortedWeights
240 // Start inserting before sortedI.
247 label sz = sortedWeights.size();
249 sortedWeights.setSize(sz + 1);
250 sortedVerts.setSize(sz + 1);
252 // Leave everything up to (not including) insertI intact.
254 // Make space by copying from insertI up.
255 for (label i = sz-1; i >= insertI; --i)
257 sortedWeights[i+1] = sortedWeights[i];
258 sortedVerts[i+1] = sortedVerts[i];
260 sortedWeights[insertI] = weight;
261 sortedVerts[insertI] = vertI;
267 // Mark all faces that are going to be collapsed.
268 // faceToEdge: per face -1 or the base edge of the face.
269 static void markCollapsedFaces
271 const triSurface& surf,
273 labelList& faceToEdge
276 faceToEdge.setSize(surf.size());
279 const pointField& localPoints = surf.localPoints();
280 const labelListList& edgeFaces = surf.edgeFaces();
282 forAll(edgeFaces, edgeI)
284 const edge& e = surf.edges()[edgeI];
286 const labelList& eFaces = surf.edgeFaces()[edgeI];
290 label faceI = eFaces[i];
292 // Check distance of vertex to edge.
294 triSurfaceTools::oppositeVertex
302 e.line(localPoints).nearestDist
304 localPoints[opposite0]
307 if (pHit.hit() && pHit.distance() < minLen)
309 // Remove faceI and split all other faces using this
310 // edge. This is done by 'replacing' the edgeI with the
312 Pout<< "Splitting face " << faceI << " since distance "
314 << " from vertex " << opposite0
315 << " to edge " << edgeI
319 << " is too small" << endl;
321 // Mark face as being collapsed
322 if (faceToEdge[faceI] != -1)
324 FatalErrorIn("markCollapsedFaces")
325 << "Cannot collapse face " << faceI << " since "
326 << " is marked to be collapsed both to edge "
327 << faceToEdge[faceI] << " and " << edgeI
328 << abort(FatalError);
331 faceToEdge[faceI] = edgeI;
338 // Recurse through collapsed faces marking all of them with regionI (in
340 static void markRegion
342 const triSurface& surf,
343 const labelList& faceToEdge,
346 labelList& collapseRegion
349 if (faceToEdge[faceI] == -1 || collapseRegion[faceI] != -1)
351 FatalErrorIn("markRegion")
352 << "Problem : crossed into uncollapsed/regionized face"
353 << abort(FatalError);
356 collapseRegion[faceI] = regionI;
358 // Recurse across edges to collapsed neighbours
360 const labelList& fEdges = surf.faceEdges()[faceI];
362 forAll(fEdges, fEdgeI)
364 label edgeI = fEdges[fEdgeI];
366 const labelList& eFaces = surf.edgeFaces()[edgeI];
370 label nbrFaceI = eFaces[i];
372 if (faceToEdge[nbrFaceI] != -1)
374 if (collapseRegion[nbrFaceI] == -1)
385 else if (collapseRegion[nbrFaceI] != regionI)
387 FatalErrorIn("markRegion")
388 << "Edge:" << edgeI << " between face " << faceI
389 << " with region " << regionI
390 << " and face " << nbrFaceI
391 << " with region " << collapseRegion[nbrFaceI]
400 // Mark every face with region (in collapseRegion) (or -1).
401 // Return number of regions.
402 static label markRegions
404 const triSurface& surf,
405 const labelList& faceToEdge,
406 labelList& collapseRegion
411 forAll(faceToEdge, faceI)
413 if (collapseRegion[faceI] == -1 && faceToEdge[faceI] != -1)
415 Pout<< "markRegions : Marking region:" << regionI
416 << " starting from face " << faceI << endl;
418 // Collapsed face. Mark connected region with current region number
419 markRegion(surf, faceToEdge, regionI++, faceI, collapseRegion);
427 // -1 : edge inbetween uncollapsed faces.
428 // -2 : edge inbetween collapsed faces
429 // >=0 : edge inbetween uncollapsed and collapsed region. Returns region.
430 static label edgeType
432 const triSurface& surf,
433 const labelList& collapseRegion,
437 const labelList& eFaces = surf.edgeFaces()[edgeI];
439 // Detect if edge is inbetween collapseRegion and non-collapse face
440 bool usesUncollapsed = false;
441 label usesRegion = -1;
445 label faceI = eFaces[i];
447 label region = collapseRegion[faceI];
451 usesUncollapsed = true;
453 else if (usesRegion == -1)
457 else if (usesRegion != region)
459 FatalErrorIn("edgeRegion") << abort(FatalError);
469 if (usesRegion == -1)
471 // uncollapsed faces only.
476 // between uncollapsed and collapsed.
482 if (usesRegion == -1)
484 FatalErrorIn("edgeRegion") << abort(FatalError);
495 // Get points on outside edge of region (= outside points)
496 static labelListList getOutsideVerts
498 const triSurface& surf,
499 const labelList& collapseRegion,
503 const labelListList& edgeFaces = surf.edgeFaces();
505 // Per region all the outside vertices.
506 labelListList outsideVerts(nRegions);
508 forAll(edgeFaces, edgeI)
510 // Detect if edge is inbetween collapseRegion and non-collapse face
511 label regionI = edgeType(surf, collapseRegion, edgeI);
515 // Edge borders both uncollapsed face and collapsed face on region
518 const edge& e = surf.edges()[edgeI];
520 labelList& regionVerts = outsideVerts[regionI];
522 // Add both edge points to regionVerts.
527 if (findIndex(regionVerts, v) == -1)
529 label sz = regionVerts.size();
530 regionVerts.setSize(sz+1);
541 // n^2 search for furthest removed point pair.
542 static labelPair getSpanPoints
544 const triSurface& surf,
545 const labelList& outsideVerts
548 const pointField& localPoints = surf.localPoints();
550 scalar maxDist = -GREAT;
553 forAll(outsideVerts, i)
555 label v0 = outsideVerts[i];
557 for (label j = i+1; j < outsideVerts.size(); j++)
559 label v1 = outsideVerts[j];
561 scalar d = mag(localPoints[v0] - localPoints[v1]);
576 // Project all non-span points onto the span edge.
577 static void projectNonSpanPoints
579 const triSurface& surf,
580 const labelList& outsideVerts,
581 const labelPair& spanPair,
582 labelList& sortedVertices,
583 scalarField& sortedWeights
586 const point& p0 = surf.localPoints()[spanPair[0]];
587 const point& p1 = surf.localPoints()[spanPair[1]];
589 forAll(outsideVerts, i)
591 label v = outsideVerts[i];
593 if (v != spanPair[0] && v != spanPair[1])
595 // Is a non-span point. Project onto spanning edge.
598 linePointRef(p0, p1).nearestDist
600 surf.localPoints()[v]
605 FatalErrorIn("projectNonSpanPoints")
606 << abort(FatalError);
609 scalar w = mag(pHit.hitPoint() - p0) / mag(p1 - p0);
611 insertSorted(v, w, sortedVertices, sortedWeights);
617 // Slice part of the orderVertices (and optionally reverse) for this edge.
618 static void getSplitVerts
620 const triSurface& surf,
622 const labelPair& spanPoints,
623 const labelList& orderedVerts,
624 const scalarField& orderedWeights,
627 labelList& splitVerts,
628 scalarField& splitWeights
631 const edge& e = surf.edges()[edgeI];
632 const label sz = orderedVerts.size();
634 if (e[0] == spanPoints[0])
636 // Edge in same order as spanPoints&orderedVerts. Keep order.
638 if (e[1] == spanPoints[1])
641 splitVerts = orderedVerts;
642 splitWeights = orderedWeights;
646 // Copy upto (but not including) e[1]
647 label i1 = findIndex(orderedVerts, e[1]);
648 splitVerts = SubList<label>(orderedVerts, i1, 0);
649 splitWeights = SubList<scalar>(orderedWeights, i1, 0);
652 else if (e[0] == spanPoints[1])
656 if (e[1] == spanPoints[0])
659 splitVerts = orderedVerts;
661 splitWeights = orderedWeights;
662 reverse(splitWeights);
666 // Copy downto (but not including) e[1]
668 label i1 = findIndex(orderedVerts, e[1]);
669 splitVerts = SubList<label>(orderedVerts, sz-(i1+1), i1+1);
671 splitWeights = SubList<scalar>(orderedWeights, sz-(i1+1), i1+1);
672 reverse(splitWeights);
675 else if (e[1] == spanPoints[0])
679 // Copy upto (but not including) e[0]
681 label i0 = findIndex(orderedVerts, e[0]);
682 splitVerts = SubList<label>(orderedVerts, i0, 0);
684 splitWeights = SubList<scalar>(orderedWeights, i0, 0);
685 reverse(splitWeights);
687 else if (e[1] == spanPoints[1])
689 // Copy from (but not including) e[0] to end
691 label i0 = findIndex(orderedVerts, e[0]);
692 splitVerts = SubList<label>(orderedVerts, sz-(i0+1), i0+1);
693 splitWeights = SubList<scalar>(orderedWeights, sz-(i0+1), i0+1);
697 label i0 = findIndex(orderedVerts, e[0]);
698 label i1 = findIndex(orderedVerts, e[1]);
700 if (i0 == -1 || i1 == -1)
702 FatalErrorIn("getSplitVerts")
703 << "Did not find edge in projected vertices." << nl
704 << "region:" << regionI << nl
705 << "spanPoints:" << spanPoints
706 << " coords:" << surf.localPoints()[spanPoints[0]]
707 << surf.localPoints()[spanPoints[1]] << nl
710 << " coords:" << surf.localPoints()[e[0]]
711 << surf.localPoints()[e[1]] << nl
712 << "orderedVerts:" << orderedVerts << nl
713 << abort(FatalError);
718 splitVerts = SubList<label>(orderedVerts, i1-i0-1, i0+1);
719 splitWeights = SubList<scalar>(orderedWeights, i1-i0-1, i0+1);
723 splitVerts = SubList<label>(orderedVerts, i0-i1-1, i1+1);
725 splitWeights = SubList<scalar>(orderedWeights, i0-i1-1, i1+1);
726 reverse(splitWeights);
732 label collapseBase(triSurface& surf, const scalar minLen)
734 label nTotalSplit = 0;
740 // Detect faces to collapse
741 // ~~~~~~~~~~~~~~~~~~~~~~~~
743 // -1 or edge the face is collapsed onto.
744 labelList faceToEdge(surf.size(), -1);
746 // Calculate faceToEdge (face collapses)
747 markCollapsedFaces(surf, minLen, faceToEdge);
750 // Find regions of connected collapsed faces
751 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
753 // per face -1 or region
754 labelList collapseRegion(surf.size(), -1);
756 label nRegions = markRegions(surf, faceToEdge, collapseRegion);
758 Pout<< "Detected " << nRegions << " regions of faces to be collapsed"
761 // Pick up all vertices on outside of region
762 labelListList outsideVerts
764 getOutsideVerts(surf, collapseRegion, nRegions)
767 // For all regions determine maximum distance between points
768 List<labelPair> spanPoints(nRegions);
769 labelListList orderedVertices(nRegions);
770 List<scalarField> orderedWeights(nRegions);
772 forAll(spanPoints, regionI)
774 spanPoints[regionI] = getSpanPoints(surf, outsideVerts[regionI]);
776 Pout<< "For region " << regionI << " found extrema at points "
777 << surf.localPoints()[spanPoints[regionI][0]]
778 << surf.localPoints()[spanPoints[regionI][1]]
781 // Project all non-span points onto the span edge.
785 outsideVerts[regionI],
787 orderedVertices[regionI],
788 orderedWeights[regionI]
791 Pout<< "For region:" << regionI
792 << " span:" << spanPoints[regionI]
793 << " orderedVerts:" << orderedVertices[regionI]
794 << " orderedWeights:" << orderedWeights[regionI]
802 outsideVerts[regionI]
810 // Actually split the edges
811 // ~~~~~~~~~~~~~~~~~~~~~~~~
814 const List<labelledTri>& localFaces = surf.localFaces();
815 const edgeList& edges = surf.edges();
819 // Storage for new triangles.
820 DynamicList<labelledTri> newTris(surf.size());
822 // Whether face has been dealt with (either copied/split or deleted)
823 boolList faceHandled(surf.size(), false);
828 const edge& e = edges[edgeI];
830 // Detect if edge is inbetween collapseRegion and non-collapse face
831 label regionI = edgeType(surf, collapseRegion, edgeI);
835 // inbetween collapsed faces. nothing needs to be done.
837 else if (regionI == -1)
839 // edge inbetween uncollapsed faces. Handle these later on.
843 // some faces around edge are collapsed.
845 // Find additional set of points on edge to be used to split
846 // the remaining faces.
848 labelList splitVerts;
849 scalarField splitWeights;
855 orderedVertices[regionI],
856 orderedWeights[regionI],
863 if (splitVerts.size())
865 // Split edge using splitVerts. All non-collapsed triangles
866 // using edge will get split.
870 const pointField& localPoints = surf.localPoints();
871 Pout<< "edge " << edgeI << ' ' << e
873 << localPoints[e[0]] << ' ' << localPoints[e[1]]
874 << " split into edges with extra points:"
876 forAll(splitVerts, i)
878 Pout<< " " << splitVerts[i] << " weight "
879 << splitWeights[i] << nl;
883 const labelList& eFaces = surf.edgeFaces()[edgeI];
887 label faceI = eFaces[i];
889 if (!faceHandled[faceI] && faceToEdge[faceI] == -1)
891 // Split face to use vertices.
900 faceHandled[faceI] = true;
909 // Copy all unsplit faces
910 forAll(faceHandled, faceI)
912 if (!faceHandled[faceI] && faceToEdge[faceI] == -1)
914 newTris.append(localFaces[faceI]);
918 Pout<< "collapseBase : splitting " << nSplit << " triangles"
921 nTotalSplit += nSplit;
928 // Pack the triangles
931 Pout<< "Resetting surface from " << surf.size() << " to "
932 << newTris.size() << " triangles" << endl;
933 surf = triSurface(newTris, surf.patches(), surf.localPoints());
936 fileName fName("bla" + name(iter) + ".obj");
937 Pout<< "Writing surf to " << fName << endl;
944 // Remove any unused vertices
945 surf = triSurface(surf.localFaces(), surf.patches(), surf.localPoints());
951 // ************************************************************************* //