1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
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
13 the Free Software Foundation, either version 3 of the License, or
14 (at your 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, 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"
35 #include "primitivePatch.H"
36 #include "addToRunTimeSelectionTable.H"
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
41 inline bool Foam::MeshedSurface<Face>::isTri()
48 Foam::wordHashSet Foam::MeshedSurface<Face>::readTypes()
50 return wordHashSet(*fileExtensionConstructorTablePtr_);
55 Foam::wordHashSet Foam::MeshedSurface<Face>::writeTypes()
57 return wordHashSet(*writefileExtensionMemberFunctionTablePtr_);
61 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
64 bool Foam::MeshedSurface<Face>::canReadType
70 return fileFormats::surfaceFormatsCore::checkSupport
72 readTypes() | FriendType::readTypes(),
81 bool Foam::MeshedSurface<Face>::canWriteType
87 return fileFormats::surfaceFormatsCore::checkSupport
89 writeTypes() | ProxyType::writeTypes(),
98 bool Foam::MeshedSurface<Face>::canRead
100 const fileName& name,
104 word ext = name.ext();
107 ext = name.lessExt().ext();
109 return canReadType(ext, verbose);
114 void Foam::MeshedSurface<Face>::write
116 const fileName& name,
117 const MeshedSurface<Face>& surf
122 Info<< "MeshedSurface::write"
123 "(const fileName&, const MeshedSurface&) : "
124 "writing to " << name
128 const word ext = name.ext();
130 typename writefileExtensionMemberFunctionTable::iterator mfIter =
131 writefileExtensionMemberFunctionTablePtr_->find(ext);
133 if (mfIter == writefileExtensionMemberFunctionTablePtr_->end())
135 // no direct writer, delegate to proxy if possible
136 wordHashSet supported = ProxyType::writeTypes();
138 if (supported.found(ext))
140 MeshedSurfaceProxy<Face>(surf).write(name);
146 "MeshedSurface::write"
147 "(const fileName&, const MeshedSurface&)"
148 ) << "Unknown file extension " << ext << nl << nl
149 << "Valid types are :" << endl
150 << (supported | writeTypes())
156 mfIter()(name, surf);
161 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
164 Foam::MeshedSurface<Face>::MeshedSurface()
166 ParentType(List<Face>(), pointField())
171 Foam::MeshedSurface<Face>::MeshedSurface
173 const Xfer<pointField>& pointLst,
174 const Xfer<List<Face> >& faceLst,
175 const Xfer<surfZoneList>& zoneLst
178 ParentType(List<Face>(), pointField()),
181 reset(pointLst, faceLst, zoneLst);
186 Foam::MeshedSurface<Face>::MeshedSurface
188 const Xfer<pointField>& pointLst,
189 const Xfer<List<Face> >& faceLst,
190 const labelUList& zoneSizes,
191 const UList<word>& zoneNames
194 ParentType(List<Face>(), pointField())
196 reset(pointLst, faceLst, Xfer<surfZoneList>());
198 if (zoneSizes.size())
200 if (zoneNames.size())
202 addZones(zoneSizes, zoneNames);
213 Foam::MeshedSurface<Face>::MeshedSurface
215 const MeshedSurface<Face>& surf
218 ParentType(surf.faces(), surf.points()),
219 zones_(surf.surfZones())
224 Foam::MeshedSurface<Face>::MeshedSurface
226 const UnsortedMeshedSurface<Face>& surf
229 ParentType(List<Face>(), surf.points())
232 this->storedZones().transfer(surf.sortedZones(faceMap));
234 const List<Face>& origFaces = surf.faces();
235 List<Face> newFaces(origFaces.size());
237 // this is somewhat like ListOps reorder and/or IndirectList
238 forAll(newFaces, faceI)
240 newFaces[faceI] = origFaces[faceMap[faceI]];
243 this->storedFaces().transfer(newFaces);
248 Foam::MeshedSurface<Face>::MeshedSurface(const surfMesh& mesh)
250 ParentType(List<Face>(), pointField())
252 // same face type as surfMesh
253 MeshedSurface<face> surf
255 xferCopy(mesh.points()),
256 xferCopy(mesh.faces()),
257 xferCopy(mesh.surfZones())
260 this->transcribe(surf);
265 Foam::MeshedSurface<Face>::MeshedSurface
267 const polyBoundaryMesh& bMesh,
268 const bool useGlobalPoints
271 ParentType(List<Face>(), pointField())
273 const polyMesh& mesh = bMesh.mesh();
274 const polyPatchList& bPatches = bMesh;
276 // Get a single patch for all boundaries
277 primitivePatch allBoundary
282 mesh.nFaces() - mesh.nInternalFaces(),
283 mesh.nInternalFaces()
288 // use global/local points:
289 const pointField& bPoints =
291 useGlobalPoints ? mesh.points() : allBoundary.localPoints()
294 // global/local face addressing:
295 const List<Face>& bFaces =
297 useGlobalPoints ? allBoundary : allBoundary.localFaces()
302 surfZoneList newZones(bPatches.size());
304 label startFaceI = 0;
306 forAll(bPatches, patchI)
308 const polyPatch& p = bPatches[patchI];
312 newZones[nZone] = surfZone
321 startFaceI += p.size();
325 newZones.setSize(nZone);
327 // same face type as the polyBoundaryMesh
328 MeshedSurface<face> surf
335 this->transcribe(surf);
340 Foam::MeshedSurface<Face>::MeshedSurface
342 const fileName& name,
346 ParentType(List<Face>(), pointField())
353 Foam::MeshedSurface<Face>::MeshedSurface(const fileName& name)
355 ParentType(List<Face>(), pointField())
362 Foam::MeshedSurface<Face>::MeshedSurface
368 ParentType(List<Face>(), pointField())
377 IOobject::MUST_READ_IF_MODIFIED,
384 // same face type as surfMesh
385 MeshedSurface<face> surf
387 xferMove(mesh.storedPoints()),
388 xferMove(mesh.storedFaces()),
389 xferMove(mesh.storedZones())
392 this->transcribe(surf);
397 Foam::MeshedSurface<Face>::MeshedSurface
399 const Xfer<UnsortedMeshedSurface<Face> >& surf
402 ParentType(List<Face>(), pointField())
409 Foam::MeshedSurface<Face>::MeshedSurface
411 const Xfer<MeshedSurface<Face> >& surf
414 ParentType(List<Face>(), pointField())
421 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
424 Foam::MeshedSurface<Face>::~MeshedSurface()
428 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
431 void Foam::MeshedSurface<Face>::remapFaces
433 const labelUList& faceMap
436 // recalculate the zone start/size
437 if (&faceMap && faceMap.size())
439 surfZoneList& zones = storedZones();
441 if (zones.size() == 1)
443 // optimized for single zone case
444 zones[0].size() = faceMap.size();
446 else if (zones.size())
452 surfZone& zone = zones[zoneI];
455 zone.start() = newFaceI;
456 origEndI += zone.size();
458 for (label faceI = newFaceI; faceI < faceMap.size(); ++faceI)
460 if (faceMap[faceI] < origEndI)
471 zone.size() = newFaceI - zone.start();
478 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
481 void Foam::MeshedSurface<Face>::clear()
483 ParentType::clearOut();
485 storedPoints().clear();
486 storedFaces().clear();
487 storedZones().clear();
492 void Foam::MeshedSurface<Face>::movePoints(const pointField& newPoints)
494 // Remove all geometry dependent data
495 ParentType::clearTopology();
497 // Adapt for new point position
498 ParentType::movePoints(newPoints);
501 storedPoints() = newPoints;
506 void Foam::MeshedSurface<Face>::scalePoints(const scalar scaleFactor)
509 if (scaleFactor > 0 && scaleFactor != 1.0)
511 // Remove all geometry dependent data
512 ParentType::clearTopology();
514 // Adapt for new point position
515 ParentType::movePoints(pointField());
517 storedPoints() *= scaleFactor;
523 void Foam::MeshedSurface<Face>::reset
525 const Xfer<pointField>& pointLst,
526 const Xfer<List<Face> >& faceLst,
527 const Xfer<surfZoneList>& zoneLst
530 ParentType::clearOut();
532 // Take over new primitive data.
533 // Optimized to avoid overwriting data at all
536 storedPoints().transfer(pointLst());
541 storedFaces().transfer(faceLst());
546 storedZones().transfer(zoneLst());
552 void Foam::MeshedSurface<Face>::reset
554 const Xfer<List<point> >& pointLst,
555 const Xfer<List<Face> >& faceLst,
556 const Xfer<surfZoneList>& zoneLst
559 ParentType::clearOut();
561 // Take over new primitive data.
562 // Optimized to avoid overwriting data at all
565 storedPoints().transfer(pointLst());
570 storedFaces().transfer(faceLst());
575 storedZones().transfer(zoneLst());
580 // Remove badly degenerate faces, double faces.
582 void Foam::MeshedSurface<Face>::cleanup(const bool verbose)
584 // merge points (already done for STL, TRI)
585 stitchFaces(SMALL, verbose);
588 this->checkTopology(verbose);
593 bool Foam::MeshedSurface<Face>::stitchFaces
599 pointField& pointLst = this->storedPoints();
602 labelList pointMap(pointLst.size());
603 pointField newPoints(pointLst.size());
605 bool hasMerged = mergePoints(pointLst, tol, verbose, pointMap, newPoints);
614 Info<< "MeshedSurface::stitchFaces : Renumbering all faces"
618 // Set the coordinates to the merged ones
619 pointLst.transfer(newPoints);
621 List<Face>& faceLst = this->storedFaces();
623 List<label> faceMap(faceLst.size());
625 // Reset the point labels to the unique points array
627 forAll(faceLst, faceI)
629 Face& f = faceLst[faceI];
632 f[fp] = pointMap[f[fp]];
635 // for extra safety: collapse face as well
636 if (f.collapse() >= 3)
638 if (newFaceI != faceI)
640 faceLst[newFaceI] = f;
642 faceMap[newFaceI] = faceI;
647 Pout<< "MeshedSurface::stitchFaces : "
648 << "Removing collapsed face " << faceI << endl
649 << " vertices :" << f << endl;
654 if (newFaceI != faceLst.size())
658 Pout<< "MeshedSurface::stitchFaces : "
659 << "Removed " << faceLst.size() - newFaceI
662 faceLst.setSize(newFaceI);
667 // Merging points might have changed geometric factors
668 ParentType::clearOut();
673 // Remove badly degenerate faces and double faces.
675 bool Foam::MeshedSurface<Face>::checkFaces
680 bool changed = false;
681 List<Face>& faceLst = this->storedFaces();
683 List<label> faceMap(faceLst.size());
686 // Detect badly labelled faces and mark degenerate faces
687 const label maxPointI = this->points().size() - 1;
688 forAll(faceLst, faceI)
690 Face& f = faceLst[faceI];
692 // avoid degenerate faces
693 if (f.collapse() >= 3)
697 if (f[fp] < 0 || f[fp] > maxPointI)
699 FatalErrorIn("MeshedSurface::checkFaces(bool)")
701 << " uses point indices outside point range 0.."
707 faceMap[faceI] = faceI;
720 "MeshedSurface::checkFaces(bool verbose)"
721 ) << "face[" << faceI << "] = " << f
722 << " does not have three unique vertices" << endl;
727 // Detect doubled faces
728 // do not touch the faces
729 const labelListList& fFaces = this->faceFaces();
731 forAll(faceLst, faceI)
733 // skip already collapsed faces:
734 if (faceMap[faceI] < 0)
739 const Face& f = faceLst[faceI];
741 // duplicate face check
743 const labelList& neighbours = fFaces[faceI];
745 // Check if faceNeighbours use same points as this face.
746 // Note: discards normal information - sides of baffle are merged.
747 forAll(neighbours, neighI)
749 const label neiFaceI = neighbours[neighI];
751 if (neiFaceI <= faceI || faceMap[neiFaceI] < 0)
753 // lower numbered faces already checked
754 // skip neighbours that are themselves collapsed
758 const Face& nei = faceLst[neiFaceI];
768 "MeshedSurface::checkFaces(bool verbose)"
769 ) << "faces share the same vertices:" << nl
770 << " face[" << faceI << "] : " << f << nl
771 << " face[" << neiFaceI << "] : " << nei << endl;
772 // printFace(Warning, " ", f, points());
773 // printFace(Warning, " ", nei, points());
782 faceMap[faceI] = faceI;
792 // Done to keep numbering constant in phase 1
794 if (changed || newFaceI < faceLst.size())
802 "MeshedSurface::checkFaces(bool verbose)"
803 ) << "Removed " << faceLst.size() - newFaceI
804 << " illegal faces." << endl;
807 // compress the face list
809 forAll(faceLst, faceI)
811 if (faceMap[faceI] >= 0)
813 if (newFaceI != faceI)
815 faceLst[newFaceI] = faceLst[faceI];
817 faceMap[newFaceI] = faceI;
822 faceLst.setSize(newFaceI);
827 // Topology can change because of renumbering
828 ParentType::clearOut();
834 Foam::label Foam::MeshedSurface<Face>::triangulate()
838 const_cast<List<label>&>(List<label>::null())
844 Foam::label Foam::MeshedSurface<Face>::triangulate
846 List<label>& faceMapOut
850 label maxTri = 0; // the maximum number of triangles for any single face
851 List<Face>& faceLst = this->storedFaces();
853 // determine how many triangles will be needed
854 forAll(faceLst, faceI)
856 const label n = faceLst[faceI].nTriangles();
865 if (nTri <= faceLst.size())
874 List<Face> newFaces(nTri);
877 // reuse storage from optional faceMap
880 faceMap.transfer(faceMapOut);
882 faceMap.setSize(nTri);
884 // remember the number of *additional* faces
885 nTri -= faceLst.size();
887 if (this->points().empty())
889 // triangulate without points
890 // simple face triangulation around f[0]
892 forAll(faceLst, faceI)
894 const Face& f = faceLst[faceI];
896 for (label fp = 1; fp < f.size() - 1; ++fp)
898 label fp1 = f.fcIndex(fp);
900 newFaces[newFaceI] = triFace(f[0], f[fp], f[fp1]);
901 faceMap[newFaceI] = faceI;
908 // triangulate with points
909 List<face> tmpTri(maxTri);
912 forAll(faceLst, faceI)
914 // 'face' not '<Face>'
915 const face& f = faceLst[faceI];
918 f.triangles(this->points(), nTmp, tmpTri);
919 for (label triI = 0; triI < nTmp; triI++)
921 newFaces[newFaceI] = Face
923 static_cast<labelUList&>(tmpTri[triI])
925 faceMap[newFaceI] = faceI;
931 faceLst.transfer(newFaces);
934 // optionally return the faceMap
937 faceMapOut.transfer(faceMap);
941 // Topology can change because of renumbering
942 ParentType::clearOut();
950 Foam::MeshedSurface<Face> Foam::MeshedSurface<Face>::subsetMesh
952 const labelHashSet& include,
957 const pointField& locPoints = this->localPoints();
958 const List<Face>& locFaces = this->localFaces();
961 // Fill pointMap, faceMap
962 PatchTools::subsetMap(*this, include, pointMap, faceMap);
964 // Create compact coordinate list and forward mapping array
965 pointField newPoints(pointMap.size());
966 labelList oldToNew(locPoints.size());
967 forAll(pointMap, pointI)
969 newPoints[pointI] = locPoints[pointMap[pointI]];
970 oldToNew[pointMap[pointI]] = pointI;
973 // create/copy a new zones list, each zone with zero size
974 surfZoneList newZones(this->surfZones());
975 forAll(newZones, zoneI)
977 newZones[zoneI].size() = 0;
980 // Renumber face node labels
981 List<Face> newFaces(faceMap.size());
982 forAll(faceMap, faceI)
984 const label origFaceI = faceMap[faceI];
985 newFaces[faceI] = Face(locFaces[origFaceI]);
987 // Renumber labels for face
988 Face& f = newFaces[faceI];
991 f[fp] = oldToNew[f[fp]];
996 // recalculate the zones start/size
1000 // adjust zone sizes
1001 forAll(newZones, zoneI)
1003 surfZone& zone = newZones[zoneI];
1005 // adjust zone start
1006 zone.start() = newFaceI;
1007 origEndI += zone.size();
1009 for (label faceI = newFaceI; faceI < faceMap.size(); ++faceI)
1011 if (faceMap[faceI] < origEndI)
1022 zone.size() = newFaceI - zone.start();
1026 // construct a sub-surface
1027 return MeshedSurface
1029 xferMove(newPoints),
1036 template<class Face>
1037 Foam::MeshedSurface<Face> Foam::MeshedSurface<Face>::subsetMesh
1039 const labelHashSet& include
1042 labelList pointMap, faceMap;
1043 return subsetMesh(include, pointMap, faceMap);
1048 template<class Face>
1049 void Foam::MeshedSurface<Face>::transfer
1051 MeshedSurface<Face>& surf
1056 xferMove(surf.storedPoints()),
1057 xferMove(surf.storedFaces()),
1058 xferMove(surf.storedZones())
1063 template<class Face>
1064 void Foam::MeshedSurface<Face>::transfer
1066 UnsortedMeshedSurface<Face>& surf
1072 surfZoneList zoneLst = surf.sortedZones(faceMap);
1074 if (zoneLst.size() <= 1)
1078 xferMove(surf.storedPoints()),
1079 xferMove(surf.storedFaces()),
1080 Xfer<surfZoneList>()
1085 List<Face>& oldFaces = surf.storedFaces();
1086 List<Face> newFaces(faceMap.size());
1088 forAll(faceMap, faceI)
1090 newFaces[faceI].transfer(oldFaces[faceMap[faceI]]);
1095 xferMove(surf.storedPoints()),
1106 template<class Face>
1107 Foam::Xfer<Foam::MeshedSurface<Face> > Foam::MeshedSurface<Face>::xfer()
1109 return xferMove(*this);
1113 // Read from file, determine format from extension
1114 template<class Face>
1115 bool Foam::MeshedSurface<Face>::read(const fileName& name)
1117 word ext = name.ext();
1120 fileName unzipName = name.lessExt();
1121 return read(unzipName, unzipName.ext());
1125 return read(name, ext);
1130 // Read from file in given format
1131 template<class Face>
1132 bool Foam::MeshedSurface<Face>::read
1134 const fileName& name,
1140 // read via selector mechanism
1141 transfer(New(name, ext)());
1146 template<class Face>
1147 void Foam::MeshedSurface<Face>::write
1150 const word& surfName
1153 MeshedSurfaceProxy<Face>(*this).write(t, surfName);
1157 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1159 template<class Face>
1160 void Foam::MeshedSurface<Face>::operator=(const MeshedSurface& surf)
1164 this->storedPoints() = surf.points();
1165 this->storedFaces() = surf.faces();
1166 this->storedZones() = surf.surfZones();
1170 template<class Face>
1171 Foam::MeshedSurface<Face>::operator Foam::MeshedSurfaceProxy<Face>() const
1173 return MeshedSurfaceProxy<Face>
1182 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1184 #include "MeshedSurfaceZones.C"
1185 #include "MeshedSurfaceIO.C"
1186 #include "MeshedSurfaceNew.C"
1188 // ************************************************************************* //