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 "MeshedSurface.H"
28 #include "UnsortedMeshedSurface.H"
29 #include "MeshedSurfaceProxy.H"
30 #include "mergePoints.H"
33 #include "polyBoundaryMesh.H"
36 #include "primitivePatch.H"
37 #include "addToRunTimeSelectionTable.H"
39 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
42 inline bool Foam::MeshedSurface<Face>::isTri()
49 Foam::wordHashSet Foam::MeshedSurface<Face>::readTypes()
51 return wordHashSet(*fileExtensionConstructorTablePtr_);
56 Foam::wordHashSet Foam::MeshedSurface<Face>::writeTypes()
58 return wordHashSet(*writefileExtensionMemberFunctionTablePtr_);
62 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
65 bool Foam::MeshedSurface<Face>::canReadType
73 readTypes() | FriendType::readTypes(),
82 bool Foam::MeshedSurface<Face>::canWriteType
90 writeTypes() | ProxyType::writeTypes(),
99 bool Foam::MeshedSurface<Face>::canRead
101 const fileName& name,
105 word ext = name.ext();
108 ext = name.lessExt().ext();
110 return canReadType(ext, verbose);
115 void Foam::MeshedSurface<Face>::write
117 const fileName& name,
118 const MeshedSurface<Face>& surf
123 Info<< "MeshedSurface::write"
124 "(const fileName&, const MeshedSurface&) : "
125 "writing to " << name
129 const word ext = name.ext();
131 typename writefileExtensionMemberFunctionTable::iterator mfIter =
132 writefileExtensionMemberFunctionTablePtr_->find(ext);
134 if (mfIter == writefileExtensionMemberFunctionTablePtr_->end())
136 // no direct writer, delegate to proxy if possible
137 wordHashSet supported = ProxyType::writeTypes();
139 if (supported.found(ext))
141 MeshedSurfaceProxy<Face>(surf).write(name);
147 "MeshedSurface::write"
148 "(const fileName&, const MeshedSurface&)"
149 ) << "Unknown file extension " << ext << nl << nl
150 << "Valid types are :" << endl
151 << (supported | writeTypes())
157 mfIter()(name, surf);
162 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
165 Foam::MeshedSurface<Face>::MeshedSurface()
167 ParentType(List<Face>(), pointField())
172 Foam::MeshedSurface<Face>::MeshedSurface
174 const Xfer< pointField >& pointLst,
175 const Xfer< List<Face> >& faceLst,
176 const Xfer< surfZoneList >& zoneLst
179 ParentType(List<Face>(), pointField()),
182 reset(pointLst, faceLst, zoneLst);
187 Foam::MeshedSurface<Face>::MeshedSurface
189 const Xfer< pointField >& pointLst,
190 const Xfer< List<Face> >& faceLst,
191 const UList<label>& zoneSizes,
192 const UList<word>& zoneNames
195 ParentType(List<Face>(), pointField())
197 reset(pointLst, faceLst, Xfer<surfZoneList>());
199 if (zoneSizes.size())
201 if (zoneNames.size())
203 addZones(zoneSizes, zoneNames);
214 Foam::MeshedSurface<Face>::MeshedSurface
216 const MeshedSurface<Face>& surf
219 ParentType(surf.faces(), surf.points()),
220 zones_(surf.surfZones())
225 Foam::MeshedSurface<Face>::MeshedSurface
227 const UnsortedMeshedSurface<Face>& surf
230 ParentType(List<Face>(), surf.points())
233 this->storedZones().transfer(surf.sortedZones(faceMap));
235 const List<Face>& origFaces = surf.faces();
236 List<Face> newFaces(origFaces.size());
238 // this is somewhat like ListOps reorder and/or IndirectList
239 forAll(newFaces, faceI)
241 newFaces[faceI] = origFaces[faceMap[faceI]];
244 this->storedFaces().transfer(newFaces);
249 Foam::MeshedSurface<Face>::MeshedSurface(const surfMesh& mesh)
251 ParentType(List<Face>(), pointField())
253 // same face type as surfMesh
254 MeshedSurface<face> surf
256 xferCopy(mesh.points()),
257 xferCopy(mesh.faces()),
258 xferCopy(mesh.surfZones())
261 this->transcribe(surf);
266 Foam::MeshedSurface<Face>::MeshedSurface
268 const polyBoundaryMesh& bMesh,
269 const bool useGlobalPoints
272 ParentType(List<Face>(), pointField())
274 const polyMesh& mesh = bMesh.mesh();
275 const polyPatchList& bPatches = bMesh;
277 // Get a single patch for all boundaries
278 primitivePatch allBoundary
283 mesh.nFaces() - mesh.nInternalFaces(),
284 mesh.nInternalFaces()
289 // use global/local points:
290 const pointField& bPoints =
292 useGlobalPoints ? mesh.points() : allBoundary.localPoints()
295 // global/local face addressing:
296 const List<Face>& bFaces =
298 useGlobalPoints ? allBoundary : allBoundary.localFaces()
303 surfZoneList newZones(bPatches.size());
305 label startFaceI = 0;
307 forAll(bPatches, patchI)
309 const polyPatch& p = bPatches[patchI];
313 newZones[nZone] = surfZone
322 startFaceI += p.size();
326 newZones.setSize(nZone);
328 // same face type as the polyBoundaryMesh
329 MeshedSurface<face> surf
336 this->transcribe(surf);
341 Foam::MeshedSurface<Face>::MeshedSurface
343 const fileName& name,
347 ParentType(List<Face>(), pointField())
354 Foam::MeshedSurface<Face>::MeshedSurface(const fileName& name)
356 ParentType(List<Face>(), pointField())
363 Foam::MeshedSurface<Face>::MeshedSurface
369 ParentType(List<Face>(), pointField())
385 // same face type as surfMesh
386 MeshedSurface<face> surf
388 xferMove(mesh.storedPoints()),
389 xferMove(mesh.storedFaces()),
390 xferMove(mesh.storedZones())
393 this->transcribe(surf);
398 Foam::MeshedSurface<Face>::MeshedSurface
400 const Xfer< UnsortedMeshedSurface<Face> >& surf
403 ParentType(List<Face>(), pointField())
410 Foam::MeshedSurface<Face>::MeshedSurface
412 const Xfer< MeshedSurface<Face> >& surf
415 ParentType(List<Face>(), pointField())
422 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
425 Foam::MeshedSurface<Face>::~MeshedSurface()
429 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
432 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
435 void Foam::MeshedSurface<Face>::remapFaces
437 const UList<label>& faceMap
440 // recalculate the zone start/size
441 if (&faceMap && faceMap.size())
443 surfZoneList& zones = storedZones();
445 if (zones.size() == 1)
447 // optimized for single zone case
448 zones[0].size() = faceMap.size();
450 else if (zones.size())
456 surfZone& zone = zones[zoneI];
459 zone.start() = newFaceI;
460 origEndI += zone.size();
462 for (label faceI = newFaceI; faceI < faceMap.size(); ++faceI)
464 if (faceMap[faceI] < origEndI)
475 zone.size() = newFaceI - zone.start();
482 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
485 void Foam::MeshedSurface<Face>::clear()
487 ParentType::clearOut();
489 storedPoints().clear();
490 storedFaces().clear();
491 storedZones().clear();
496 void Foam::MeshedSurface<Face>::movePoints(const pointField& newPoints)
498 // Remove all geometry dependent data
499 ParentType::clearTopology();
501 // Adapt for new point position
502 ParentType::movePoints(newPoints);
505 storedPoints() = newPoints;
510 void Foam::MeshedSurface<Face>::scalePoints(const scalar& scaleFactor)
513 if (scaleFactor > 0 && scaleFactor != 1.0)
515 // Remove all geometry dependent data
516 ParentType::clearTopology();
518 // Adapt for new point position
519 ParentType::movePoints(pointField());
521 storedPoints() *= scaleFactor;
527 void Foam::MeshedSurface<Face>::reset
529 const Xfer< pointField >& pointLst,
530 const Xfer< List<Face> >& faceLst,
531 const Xfer< surfZoneList >& zoneLst
534 ParentType::clearOut();
536 // Take over new primitive data.
537 // Optimized to avoid overwriting data at all
540 storedPoints().transfer(pointLst());
545 storedFaces().transfer(faceLst());
550 storedZones().transfer(zoneLst());
556 void Foam::MeshedSurface<Face>::reset
558 const Xfer< List<point> >& pointLst,
559 const Xfer< List<Face> >& faceLst,
560 const Xfer< surfZoneList >& zoneLst
563 ParentType::clearOut();
565 // Take over new primitive data.
566 // Optimized to avoid overwriting data at all
569 storedPoints().transfer(pointLst());
574 storedFaces().transfer(faceLst());
579 storedZones().transfer(zoneLst());
584 // Remove badly degenerate faces, double faces.
586 void Foam::MeshedSurface<Face>::cleanup(const bool verbose)
588 // merge points (already done for STL, TRI)
589 stitchFaces(SMALL, verbose);
592 this->checkTopology(verbose);
597 bool Foam::MeshedSurface<Face>::stitchFaces
603 pointField& pointLst = this->storedPoints();
606 labelList pointMap(pointLst.size());
607 pointField newPoints(pointLst.size());
609 bool hasMerged = mergePoints(pointLst, tol, verbose, pointMap, newPoints);
618 Info<< "MeshedSurface::stitchFaces : Renumbering all faces"
622 // Set the coordinates to the merged ones
623 pointLst.transfer(newPoints);
625 List<Face>& faceLst = this->storedFaces();
627 List<label> faceMap(faceLst.size());
629 // Reset the point labels to the unique points array
631 forAll(faceLst, faceI)
633 Face& f = faceLst[faceI];
636 f[fp] = pointMap[f[fp]];
639 // for extra safety: collapse face as well
640 if (f.collapse() >= 3)
642 if (newFaceI != faceI)
644 faceLst[newFaceI] = f;
646 faceMap[newFaceI] = faceI;
651 Pout<< "MeshedSurface::stitchFaces : "
652 << "Removing collapsed face " << faceI << endl
653 << " vertices :" << f << endl;
658 if (newFaceI != faceLst.size())
662 Pout<< "MeshedSurface::stitchFaces : "
663 << "Removed " << faceLst.size() - newFaceI
666 faceLst.setSize(newFaceI);
671 // Merging points might have changed geometric factors
672 ParentType::clearOut();
677 // Remove badly degenerate faces and double faces.
679 bool Foam::MeshedSurface<Face>::checkFaces
684 bool changed = false;
685 List<Face>& faceLst = this->storedFaces();
687 List<label> faceMap(faceLst.size());
690 // Detect badly labelled faces and mark degenerate faces
691 const label maxPointI = this->points().size() - 1;
692 forAll(faceLst, faceI)
694 Face& f = faceLst[faceI];
696 // avoid degenerate faces
697 if (f.collapse() >= 3)
701 if (f[fp] < 0 || f[fp] > maxPointI)
703 FatalErrorIn("MeshedSurface::checkFaces(bool)")
705 << " uses point indices outside point range 0.."
711 faceMap[faceI] = faceI;
724 "MeshedSurface::checkFaces(bool verbose)"
725 ) << "face[" << faceI << "] = " << f
726 << " does not have three unique vertices" << endl;
731 // Detect doubled faces
732 // do not touch the faces
733 const labelListList& fFaces = this->faceFaces();
735 forAll(faceLst, faceI)
737 // skip already collapsed faces:
738 if (faceMap[faceI] < 0)
743 const Face& f = faceLst[faceI];
745 // duplicate face check
747 const labelList& neighbours = fFaces[faceI];
749 // Check if faceNeighbours use same points as this face.
750 // Note: discards normal information - sides of baffle are merged.
751 forAll(neighbours, neighI)
753 const label neiFaceI = neighbours[neighI];
755 if (neiFaceI <= faceI || faceMap[neiFaceI] < 0)
757 // lower numbered faces already checked
758 // skip neighbours that are themselves collapsed
762 const Face& nei = faceLst[neiFaceI];
772 "MeshedSurface::checkFaces(bool verbose)"
773 ) << "faces share the same vertices:" << nl
774 << " face[" << faceI << "] : " << f << nl
775 << " face[" << neiFaceI << "] : " << nei << endl;
776 // printFace(Warning, " ", f, points());
777 // printFace(Warning, " ", nei, points());
786 faceMap[faceI] = faceI;
796 // Done to keep numbering constant in phase 1
798 if (changed || newFaceI < faceLst.size())
806 "MeshedSurface::checkFaces(bool verbose)"
807 ) << "Removed " << faceLst.size() - newFaceI
808 << " illegal faces." << endl;
811 // compress the face list
813 forAll(faceLst, faceI)
815 if (faceMap[faceI] >= 0)
817 if (newFaceI != faceI)
819 faceLst[newFaceI] = faceLst[faceI];
821 faceMap[newFaceI] = faceI;
826 faceLst.setSize(newFaceI);
831 // Topology can change because of renumbering
832 ParentType::clearOut();
838 Foam::label Foam::MeshedSurface<Face>::triangulate()
842 const_cast<List<label>&>(List<label>::null())
848 Foam::label Foam::MeshedSurface<Face>::triangulate
850 List<label>& faceMapOut
854 label maxTri = 0; // the maximum number of triangles for any single face
855 List<Face>& faceLst = this->storedFaces();
857 // determine how many triangles will be needed
858 forAll(faceLst, faceI)
860 const label n = faceLst[faceI].nTriangles();
869 if (nTri <= faceLst.size())
878 List<Face> newFaces(nTri);
881 // reuse storage from optional faceMap
884 faceMap.transfer(faceMapOut);
886 faceMap.setSize(nTri);
888 // remember the number of *additional* faces
889 nTri -= faceLst.size();
891 if (this->points().empty())
893 // triangulate without points
894 // simple face triangulation around f[0]
896 forAll(faceLst, faceI)
898 const Face& f = faceLst[faceI];
900 for (label fp = 1; fp < f.size() - 1; ++fp)
902 label fp1 = f.fcIndex(fp);
904 newFaces[newFaceI] = triFace(f[0], f[fp], f[fp1]);
905 faceMap[newFaceI] = faceI;
912 // triangulate with points
913 List<face> tmpTri(maxTri);
916 forAll(faceLst, faceI)
918 // 'face' not '<Face>'
919 const face& f = faceLst[faceI];
922 f.triangles(this->points(), nTmp, tmpTri);
923 for (label triI = 0; triI < nTmp; triI++)
925 newFaces[newFaceI] = Face
927 static_cast<UList<label>&>(tmpTri[triI])
929 faceMap[newFaceI] = faceI;
935 faceLst.transfer(newFaces);
938 // optionally return the faceMap
941 faceMapOut.transfer(faceMap);
945 // Topology can change because of renumbering
946 ParentType::clearOut();
954 Foam::MeshedSurface<Face> Foam::MeshedSurface<Face>::subsetMesh
956 const labelHashSet& include,
961 const pointField& locPoints = this->localPoints();
962 const List<Face>& locFaces = this->localFaces();
965 // Fill pointMap, faceMap
966 PatchTools::subsetMap(*this, include, pointMap, faceMap);
968 // Create compact coordinate list and forward mapping array
969 pointField newPoints(pointMap.size());
970 labelList oldToNew(locPoints.size());
971 forAll(pointMap, pointI)
973 newPoints[pointI] = locPoints[pointMap[pointI]];
974 oldToNew[pointMap[pointI]] = pointI;
977 // create/copy a new zones list, each zone with zero size
978 surfZoneList newZones(this->surfZones());
979 forAll(newZones, zoneI)
981 newZones[zoneI].size() = 0;
984 // Renumber face node labels
985 List<Face> newFaces(faceMap.size());
986 forAll(faceMap, faceI)
988 const label origFaceI = faceMap[faceI];
989 newFaces[faceI] = Face(locFaces[origFaceI]);
991 // Renumber labels for face
992 Face& f = newFaces[faceI];
995 f[fp] = oldToNew[f[fp]];
1000 // recalculate the zones start/size
1004 // adjust zone sizes
1005 forAll(newZones, zoneI)
1007 surfZone& zone = newZones[zoneI];
1009 // adjust zone start
1010 zone.start() = newFaceI;
1011 origEndI += zone.size();
1013 for (label faceI = newFaceI; faceI < faceMap.size(); ++faceI)
1015 if (faceMap[faceI] < origEndI)
1026 zone.size() = newFaceI - zone.start();
1030 // construct a sub-surface
1031 return MeshedSurface
1033 xferMove(newPoints),
1040 template<class Face>
1041 Foam::MeshedSurface<Face>
1042 Foam::MeshedSurface<Face>::subsetMesh
1044 const labelHashSet& include
1047 labelList pointMap, faceMap;
1048 return subsetMesh(include, pointMap, faceMap);
1053 template<class Face>
1054 void Foam::MeshedSurface<Face>::transfer
1056 MeshedSurface<Face>& surf
1061 xferMove(surf.storedPoints()),
1062 xferMove(surf.storedFaces()),
1063 xferMove(surf.storedZones())
1068 template<class Face>
1069 void Foam::MeshedSurface<Face>::transfer
1071 UnsortedMeshedSurface<Face>& surf
1077 surfZoneList zoneLst = surf.sortedZones(faceMap);
1079 if (zoneLst.size() <= 1)
1083 xferMove(surf.storedPoints()),
1084 xferMove(surf.storedFaces()),
1085 Xfer<surfZoneList>()
1090 List<Face>& oldFaces = surf.storedFaces();
1091 List<Face> newFaces(faceMap.size());
1093 forAll(faceMap, faceI)
1095 newFaces[faceI].transfer(oldFaces[faceMap[faceI]]);
1100 xferMove(surf.storedPoints()),
1111 template<class Face>
1112 Foam::Xfer< Foam::MeshedSurface<Face> >
1113 Foam::MeshedSurface<Face>::xfer()
1115 return xferMove(*this);
1119 // Read from file, determine format from extension
1120 template<class Face>
1121 bool Foam::MeshedSurface<Face>::read(const fileName& name)
1123 word ext = name.ext();
1126 fileName unzipName = name.lessExt();
1127 return read(unzipName, unzipName.ext());
1131 return read(name, ext);
1136 // Read from file in given format
1137 template<class Face>
1138 bool Foam::MeshedSurface<Face>::read
1140 const fileName& name,
1146 // read via selector mechanism
1147 transfer(New(name, ext)());
1152 template<class Face>
1153 void Foam::MeshedSurface<Face>::write
1156 const word& surfName
1159 MeshedSurfaceProxy<Face>(*this).write(t, surfName);
1162 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1164 template<class Face>
1165 void Foam::MeshedSurface<Face>::operator=(const MeshedSurface& surf)
1169 this->storedPoints() = surf.points();
1170 this->storedFaces() = surf.faces();
1171 this->storedZones() = surf.surfZones();
1175 template<class Face>
1176 Foam::MeshedSurface<Face>::operator
1177 Foam::MeshedSurfaceProxy<Face>() const
1179 return MeshedSurfaceProxy<Face>
1187 // * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * //
1189 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
1191 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1193 #include "MeshedSurfaceZones.C"
1194 #include "MeshedSurfaceIO.C"
1195 #include "MeshedSurfaceNew.C"
1197 // ************************************************************************* //