1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend 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 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "MeshedSurface.H"
27 #include "UnsortedMeshedSurface.H"
28 #include "MeshedSurfaceProxy.H"
29 #include "mergePoints.H"
32 #include "polyBoundaryMesh.H"
37 #include "primitivePatch.H"
38 #include "addToRunTimeSelectionTable.H"
40 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
43 inline bool Foam::MeshedSurface<Face>::isTri()
50 Foam::wordHashSet Foam::MeshedSurface<Face>::readTypes()
52 return wordHashSet(*fileExtensionConstructorTablePtr_);
57 Foam::wordHashSet Foam::MeshedSurface<Face>::writeTypes()
59 return wordHashSet(*writefileExtensionMemberFunctionTablePtr_);
63 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
66 bool Foam::MeshedSurface<Face>::canReadType
74 readTypes() | FriendType::readTypes(),
83 bool Foam::MeshedSurface<Face>::canWriteType
91 writeTypes() | ProxyType::writeTypes(),
100 bool Foam::MeshedSurface<Face>::canRead
102 const fileName& name,
106 word ext = name.ext();
109 ext = name.lessExt().ext();
111 return canReadType(ext, verbose);
116 void Foam::MeshedSurface<Face>::write
118 const fileName& name,
119 const MeshedSurface<Face>& surf
124 Info<< "MeshedSurface::write"
125 "(const fileName&, const MeshedSurface&) : "
126 "writing to " << name
130 const word ext = name.ext();
132 typename writefileExtensionMemberFunctionTable::iterator mfIter =
133 writefileExtensionMemberFunctionTablePtr_->find(ext);
135 if (mfIter == writefileExtensionMemberFunctionTablePtr_->end())
137 // no direct writer, delegate to proxy if possible
138 wordHashSet supported = ProxyType::writeTypes();
140 if (supported.found(ext))
142 MeshedSurfaceProxy<Face>(surf).write(name);
148 "MeshedSurface::write"
149 "(const fileName&, const MeshedSurface&)"
150 ) << "Unknown file extension " << ext << nl << nl
151 << "Valid types are :" << endl
152 << (supported | writeTypes())
158 mfIter()(name, surf);
163 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
166 Foam::MeshedSurface<Face>::MeshedSurface()
168 ParentType(List<Face>(), pointField())
173 Foam::MeshedSurface<Face>::MeshedSurface
175 const Xfer<pointField >& pointLst,
176 const Xfer<List<Face> >& faceLst,
177 const Xfer<surfZoneList>& zoneLst
180 ParentType(List<Face>(), pointField()),
183 reset(pointLst, faceLst, zoneLst);
188 Foam::MeshedSurface<Face>::MeshedSurface
190 const Xfer<pointField>& pointLst,
191 const Xfer<List<Face> >& faceLst,
192 const UList<label>& zoneSizes,
193 const UList<word>& zoneNames
196 ParentType(List<Face>(), pointField())
198 reset(pointLst, faceLst, Xfer<surfZoneList>());
200 if (zoneSizes.size())
202 if (zoneNames.size())
204 addZones(zoneSizes, zoneNames);
215 Foam::MeshedSurface<Face>::MeshedSurface
217 const MeshedSurface<Face>& surf
220 ParentType(surf.faces(), surf.points()),
221 zones_(surf.surfZones())
226 Foam::MeshedSurface<Face>::MeshedSurface
228 const UnsortedMeshedSurface<Face>& surf
231 ParentType(List<Face>(), surf.points())
234 this->storedZones().transfer(surf.sortedZones(faceMap));
236 const List<Face>& origFaces = surf.faces();
237 List<Face> newFaces(origFaces.size());
239 // this is somewhat like ListOps reorder and/or IndirectList
240 forAll(newFaces, faceI)
242 newFaces[faceI] = origFaces[faceMap[faceI]];
245 this->storedFaces().transfer(newFaces);
250 Foam::MeshedSurface<Face>::MeshedSurface(const surfMesh& mesh)
252 ParentType(List<Face>(), pointField())
254 // same face type as surfMesh
255 MeshedSurface<face> surf
257 xferCopy(mesh.points()),
258 xferCopy(mesh.faces()),
259 xferCopy(mesh.surfZones())
262 this->transcribe(surf);
267 Foam::MeshedSurface<Face>::MeshedSurface
269 const polyBoundaryMesh& bMesh,
270 const bool useGlobalPoints
273 ParentType(List<Face>(), pointField())
275 const polyMesh& mesh = bMesh.mesh();
276 const polyPatchList& bPatches = bMesh;
278 // Get a single patch for all boundaries
279 primitivePatch allBoundary
284 mesh.nFaces() - mesh.nInternalFaces(),
285 mesh.nInternalFaces()
290 // use global/local points:
291 const pointField& bPoints =
293 useGlobalPoints ? mesh.points() : allBoundary.localPoints()
296 // global/local face addressing:
297 const List<Face>& bFaces =
299 useGlobalPoints ? allBoundary : allBoundary.localFaces()
304 surfZoneList newZones(bPatches.size());
306 label startFaceI = 0;
308 forAll(bPatches, patchI)
310 const polyPatch& p = bPatches[patchI];
314 newZones[nZone] = surfZone
323 startFaceI += p.size();
327 newZones.setSize(nZone);
329 // same face type as the polyBoundaryMesh
330 MeshedSurface<face> surf
337 this->transcribe(surf);
342 Foam::MeshedSurface<Face>::MeshedSurface
344 const fileName& name,
348 ParentType(List<Face>(), pointField())
355 Foam::MeshedSurface<Face>::MeshedSurface(const fileName& name)
357 ParentType(List<Face>(), pointField())
364 Foam::MeshedSurface<Face>::MeshedSurface
370 ParentType(List<Face>(), pointField())
386 // same face type as surfMesh
387 MeshedSurface<face> surf
389 xferMove(mesh.storedPoints()),
390 xferMove(mesh.storedFaces()),
391 xferMove(mesh.storedZones())
394 this->transcribe(surf);
399 Foam::MeshedSurface<Face>::MeshedSurface
401 const Xfer< UnsortedMeshedSurface<Face> >& surf
404 ParentType(List<Face>(), pointField())
411 Foam::MeshedSurface<Face>::MeshedSurface
413 const Xfer< MeshedSurface<Face> >& surf
416 ParentType(List<Face>(), pointField())
423 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
426 Foam::MeshedSurface<Face>::~MeshedSurface()
430 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
433 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
436 void Foam::MeshedSurface<Face>::remapFaces
438 const UList<label>& faceMap
441 // recalculate the zone start/size
442 if (!faceMap.empty())
444 surfZoneList& zones = storedZones();
446 if (zones.size() == 1)
448 // optimized for single zone case
449 zones[0].size() = faceMap.size();
451 else if (zones.size())
457 surfZone& zone = zones[zoneI];
460 zone.start() = newFaceI;
461 origEndI += zone.size();
463 for (label faceI = newFaceI; faceI < faceMap.size(); ++faceI)
465 if (faceMap[faceI] < origEndI)
476 zone.size() = newFaceI - zone.start();
483 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
486 void Foam::MeshedSurface<Face>::clear()
488 ParentType::clearOut();
490 storedPoints().clear();
491 storedFaces().clear();
492 storedZones().clear();
497 void Foam::MeshedSurface<Face>::movePoints(const pointField& newPoints)
499 // Remove all geometry dependent data
500 ParentType::clearTopology();
502 // Adapt for new point position
503 ParentType::movePoints(newPoints);
506 storedPoints() = newPoints;
511 void Foam::MeshedSurface<Face>::scalePoints(const scalar& scaleFactor)
514 if (scaleFactor > 0 && scaleFactor != 1.0)
516 // Remove all geometry dependent data
517 ParentType::clearTopology();
519 // Adapt for new point position
520 ParentType::movePoints(pointField());
522 storedPoints() *= scaleFactor;
528 void Foam::MeshedSurface<Face>::reset
530 const Xfer<pointField>& pointLst,
531 const Xfer<List<Face> >& faceLst,
532 const Xfer<surfZoneList>& zoneLst
535 ParentType::clearOut();
537 // Take over new primitive data.
538 // Optimized to avoid overwriting data at all
539 if (!pointLst->empty())
541 storedPoints().transfer(pointLst());
544 if (!faceLst->empty())
546 storedFaces().transfer(faceLst());
549 if (!zoneLst->empty())
551 storedZones().transfer(zoneLst());
557 void Foam::MeshedSurface<Face>::reset
559 const Xfer<List<point> >& pointLst,
560 const Xfer<List<Face> >& faceLst,
561 const Xfer<surfZoneList>& zoneLst
564 ParentType::clearOut();
566 // Take over new primitive data.
567 // Optimized to avoid overwriting data at all
568 if (!pointLst->empty())
570 storedPoints().transfer(pointLst());
573 if (!faceLst->empty())
575 storedFaces().transfer(faceLst());
578 if (!zoneLst->empty())
580 storedZones().transfer(zoneLst());
585 // Remove badly degenerate faces, double faces.
587 void Foam::MeshedSurface<Face>::cleanup(const bool verbose)
589 // merge points (already done for STL, TRI)
590 stitchFaces(SMALL, verbose);
593 this->checkTopology(verbose);
598 bool Foam::MeshedSurface<Face>::stitchFaces
604 pointField& pointLst = this->storedPoints();
607 labelList pointMap(pointLst.size());
608 pointField newPoints(pointLst.size());
610 bool hasMerged = mergePoints(pointLst, tol, verbose, pointMap, newPoints);
619 Info<< "MeshedSurface::stitchFaces : Renumbering all faces"
623 // Set the coordinates to the merged ones
624 pointLst.transfer(newPoints);
626 List<Face>& faceLst = this->storedFaces();
628 List<label> faceMap(faceLst.size());
630 // Reset the point labels to the unique points array
632 forAll(faceLst, faceI)
634 Face& f = faceLst[faceI];
637 f[fp] = pointMap[f[fp]];
640 // for extra safety: collapse face as well
641 if (f.collapse() >= 3)
643 if (newFaceI != faceI)
645 faceLst[newFaceI] = f;
647 faceMap[newFaceI] = faceI;
652 Pout<< "MeshedSurface::stitchFaces : "
653 << "Removing collapsed face " << faceI << endl
654 << " vertices :" << f << endl;
659 if (newFaceI != faceLst.size())
663 Pout<< "MeshedSurface::stitchFaces : "
664 << "Removed " << faceLst.size() - newFaceI
667 faceLst.setSize(newFaceI);
672 // Merging points might have changed geometric factors
673 ParentType::clearOut();
678 // Remove badly degenerate faces and double faces.
680 bool Foam::MeshedSurface<Face>::checkFaces
685 bool changed = false;
686 List<Face>& faceLst = this->storedFaces();
688 List<label> faceMap(faceLst.size());
691 // Detect badly labelled faces and mark degenerate faces
692 const label maxPointI = this->points().size() - 1;
693 forAll(faceLst, faceI)
695 Face& f = faceLst[faceI];
697 // avoid degenerate faces
698 if (f.collapse() >= 3)
702 if (f[fp] < 0 || f[fp] > maxPointI)
704 FatalErrorIn("MeshedSurface::checkFaces(bool)")
706 << " uses point indices outside point range 0.."
712 faceMap[faceI] = faceI;
725 "MeshedSurface::checkFaces(bool verbose)"
726 ) << "face[" << faceI << "] = " << f
727 << " does not have three unique vertices" << endl;
732 // Detect doubled faces
733 // do not touch the faces
734 const labelListList& fFaces = this->faceFaces();
736 forAll(faceLst, faceI)
738 // skip already collapsed faces:
739 if (faceMap[faceI] < 0)
744 const Face& f = faceLst[faceI];
746 // duplicate face check
748 const labelList& neighbours = fFaces[faceI];
750 // Check if faceNeighbours use same points as this face.
751 // Note: discards normal information - sides of baffle are merged.
752 forAll(neighbours, neighI)
754 const label neiFaceI = neighbours[neighI];
756 if (neiFaceI <= faceI || faceMap[neiFaceI] < 0)
758 // lower numbered faces already checked
759 // skip neighbours that are themselves collapsed
763 const Face& nei = faceLst[neiFaceI];
773 "MeshedSurface::checkFaces(bool verbose)"
774 ) << "faces share the same vertices:" << nl
775 << " face[" << faceI << "] : " << f << nl
776 << " face[" << neiFaceI << "] : " << nei << endl;
777 // printFace(Warning, " ", f, points());
778 // printFace(Warning, " ", nei, points());
787 faceMap[faceI] = faceI;
797 // Done to keep numbering constant in phase 1
799 if (changed || newFaceI < faceLst.size())
807 "MeshedSurface::checkFaces(bool verbose)"
808 ) << "Removed " << faceLst.size() - newFaceI
809 << " illegal faces." << endl;
812 // compress the face list
814 forAll(faceLst, faceI)
816 if (faceMap[faceI] >= 0)
818 if (newFaceI != faceI)
820 faceLst[newFaceI] = faceLst[faceI];
822 faceMap[newFaceI] = faceI;
827 faceLst.setSize(newFaceI);
832 // Topology can change because of renumbering
833 ParentType::clearOut();
839 Foam::label Foam::MeshedSurface<Face>::triangulate()
843 const_cast<List<label>&>(List<label>::null())
849 Foam::label Foam::MeshedSurface<Face>::triangulate
851 List<label>& faceMapOut
855 label maxTri = 0; // the maximum number of triangles for any single face
856 List<Face>& faceLst = this->storedFaces();
858 // determine how many triangles will be needed
859 forAll(faceLst, faceI)
861 const label n = faceLst[faceI].nTriangles();
870 if (nTri <= faceLst.size())
872 if (!faceMapOut.empty())
879 List<Face> newFaces(nTri);
882 // reuse storage from optional faceMap
883 if (!faceMapOut.empty())
885 faceMap.transfer(faceMapOut);
887 faceMap.setSize(nTri);
889 // remember the number of *additional* faces
890 nTri -= faceLst.size();
892 if (this->points().empty())
894 // triangulate without points
895 // simple face triangulation around f[0]
897 forAll(faceLst, faceI)
899 const Face& f = faceLst[faceI];
901 for (label fp = 1; fp < f.size() - 1; ++fp)
903 label fp1 = f.fcIndex(fp);
905 newFaces[newFaceI] = triFace(f[0], f[fp], f[fp1]);
906 faceMap[newFaceI] = faceI;
913 // triangulate with points
914 List<face> tmpTri(maxTri);
917 forAll(faceLst, faceI)
919 // 'face' not '<Face>'
920 const face& f = faceLst[faceI];
923 f.triangles(this->points(), nTmp, tmpTri);
924 for (label triI = 0; triI < nTmp; triI++)
926 newFaces[newFaceI] = Face
928 static_cast<UList<label>&>(tmpTri[triI])
930 faceMap[newFaceI] = faceI;
936 faceLst.transfer(newFaces);
939 // optionally return the faceMap
940 faceMapOut.transfer(faceMap);
943 // Topology can change because of renumbering
944 ParentType::clearOut();
952 Foam::MeshedSurface<Face> Foam::MeshedSurface<Face>::subsetMesh
954 const labelHashSet& include,
959 const pointField& locPoints = this->localPoints();
960 const List<Face>& locFaces = this->localFaces();
963 // Fill pointMap, faceMap
964 PatchTools::subsetMap(*this, include, pointMap, faceMap);
966 // Create compact coordinate list and forward mapping array
967 pointField newPoints(pointMap.size());
968 labelList oldToNew(locPoints.size());
969 forAll(pointMap, pointI)
971 newPoints[pointI] = locPoints[pointMap[pointI]];
972 oldToNew[pointMap[pointI]] = pointI;
975 // create/copy a new zones list, each zone with zero size
976 surfZoneList newZones(this->surfZones());
977 forAll(newZones, zoneI)
979 newZones[zoneI].size() = 0;
982 // Renumber face node labels
983 List<Face> newFaces(faceMap.size());
984 forAll(faceMap, faceI)
986 const label origFaceI = faceMap[faceI];
987 newFaces[faceI] = Face(locFaces[origFaceI]);
989 // Renumber labels for face
990 Face& f = newFaces[faceI];
993 f[fp] = oldToNew[f[fp]];
998 // recalculate the zones start/size
1002 // adjust zone sizes
1003 forAll(newZones, zoneI)
1005 surfZone& zone = newZones[zoneI];
1007 // adjust zone start
1008 zone.start() = newFaceI;
1009 origEndI += zone.size();
1011 for (label faceI = newFaceI; faceI < faceMap.size(); ++faceI)
1013 if (faceMap[faceI] < origEndI)
1024 zone.size() = newFaceI - zone.start();
1028 // construct a sub-surface
1029 return MeshedSurface
1031 xferMove(newPoints),
1038 template<class Face>
1039 Foam::MeshedSurface<Face>
1040 Foam::MeshedSurface<Face>::subsetMesh
1042 const labelHashSet& include
1045 labelList pointMap, faceMap;
1046 return subsetMesh(include, pointMap, faceMap);
1051 template<class Face>
1052 void Foam::MeshedSurface<Face>::transfer
1054 MeshedSurface<Face>& surf
1059 xferMove(surf.storedPoints()),
1060 xferMove(surf.storedFaces()),
1061 xferMove(surf.storedZones())
1066 template<class Face>
1067 void Foam::MeshedSurface<Face>::transfer
1069 UnsortedMeshedSurface<Face>& surf
1075 surfZoneList zoneLst = surf.sortedZones(faceMap);
1077 if (zoneLst.size() <= 1)
1081 xferMove(surf.storedPoints()),
1082 xferMove(surf.storedFaces()),
1083 Xfer<surfZoneList>()
1088 List<Face>& oldFaces = surf.storedFaces();
1089 List<Face> newFaces(faceMap.size());
1091 forAll(faceMap, faceI)
1093 newFaces[faceI].transfer(oldFaces[faceMap[faceI]]);
1098 xferMove(surf.storedPoints()),
1109 template<class Face>
1110 Foam::Xfer< Foam::MeshedSurface<Face> >
1111 Foam::MeshedSurface<Face>::xfer()
1113 return xferMove(*this);
1117 // Read from file, determine format from extension
1118 template<class Face>
1119 bool Foam::MeshedSurface<Face>::read(const fileName& name)
1121 word ext = name.ext();
1124 fileName unzipName = name.lessExt();
1125 return read(unzipName, unzipName.ext());
1129 return read(name, ext);
1134 // Read from file in given format
1135 template<class Face>
1136 bool Foam::MeshedSurface<Face>::read
1138 const fileName& name,
1144 // read via selector mechanism
1145 transfer(New(name, ext)());
1150 template<class Face>
1151 void Foam::MeshedSurface<Face>::write
1154 const word& surfName
1157 MeshedSurfaceProxy<Face>(*this).write(t, surfName);
1160 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1162 template<class Face>
1163 void Foam::MeshedSurface<Face>::operator=(const MeshedSurface& surf)
1167 this->storedPoints() = surf.points();
1168 this->storedFaces() = surf.faces();
1169 this->storedZones() = surf.surfZones();
1173 template<class Face>
1174 Foam::MeshedSurface<Face>::operator
1175 Foam::MeshedSurfaceProxy<Face>() const
1177 return MeshedSurfaceProxy<Face>
1185 // * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * //
1187 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
1189 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1191 #include "MeshedSurfaceZones.C"
1192 #include "MeshedSurfaceIO.C"
1193 #include "MeshedSurfaceNew.C"
1195 // ************************************************************************* //