1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2010 OpenCFD Ltd.
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
72 readTypes() | FriendType::readTypes(),
81 bool Foam::MeshedSurface<Face>::canWriteType
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 UList<label>& 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())
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 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
431 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
434 void Foam::MeshedSurface<Face>::remapFaces
436 const UList<label>& faceMap
439 // recalculate the zone start/size
440 if (&faceMap && faceMap.size())
442 surfZoneList& zones = storedZones();
444 if (zones.size() == 1)
446 // optimized for single zone case
447 zones[0].size() = faceMap.size();
449 else if (zones.size())
455 surfZone& zone = zones[zoneI];
458 zone.start() = newFaceI;
459 origEndI += zone.size();
461 for (label faceI = newFaceI; faceI < faceMap.size(); ++faceI)
463 if (faceMap[faceI] < origEndI)
474 zone.size() = newFaceI - zone.start();
481 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
484 void Foam::MeshedSurface<Face>::clear()
486 ParentType::clearOut();
488 storedPoints().clear();
489 storedFaces().clear();
490 storedZones().clear();
495 void Foam::MeshedSurface<Face>::movePoints(const pointField& newPoints)
497 // Remove all geometry dependent data
498 ParentType::clearTopology();
500 // Adapt for new point position
501 ParentType::movePoints(newPoints);
504 storedPoints() = newPoints;
509 void Foam::MeshedSurface<Face>::scalePoints(const scalar& scaleFactor)
512 if (scaleFactor > 0 && scaleFactor != 1.0)
514 // Remove all geometry dependent data
515 ParentType::clearTopology();
517 // Adapt for new point position
518 ParentType::movePoints(pointField());
520 storedPoints() *= scaleFactor;
526 void Foam::MeshedSurface<Face>::reset
528 const Xfer< pointField >& pointLst,
529 const Xfer< List<Face> >& faceLst,
530 const Xfer< surfZoneList >& zoneLst
533 ParentType::clearOut();
535 // Take over new primitive data.
536 // Optimized to avoid overwriting data at all
539 storedPoints().transfer(pointLst());
544 storedFaces().transfer(faceLst());
549 storedZones().transfer(zoneLst());
555 void Foam::MeshedSurface<Face>::reset
557 const Xfer< List<point> >& pointLst,
558 const Xfer< List<Face> >& faceLst,
559 const Xfer< surfZoneList >& zoneLst
562 ParentType::clearOut();
564 // Take over new primitive data.
565 // Optimized to avoid overwriting data at all
568 storedPoints().transfer(pointLst());
573 storedFaces().transfer(faceLst());
578 storedZones().transfer(zoneLst());
583 // Remove badly degenerate faces, double faces.
585 void Foam::MeshedSurface<Face>::cleanup(const bool verbose)
587 // merge points (already done for STL, TRI)
588 stitchFaces(SMALL, verbose);
591 this->checkTopology(verbose);
596 bool Foam::MeshedSurface<Face>::stitchFaces
602 pointField& pointLst = this->storedPoints();
605 labelList pointMap(pointLst.size());
606 pointField newPoints(pointLst.size());
608 bool hasMerged = mergePoints(pointLst, tol, verbose, pointMap, newPoints);
617 Info<< "MeshedSurface::stitchFaces : Renumbering all faces"
621 // Set the coordinates to the merged ones
622 pointLst.transfer(newPoints);
624 List<Face>& faceLst = this->storedFaces();
626 List<label> faceMap(faceLst.size());
628 // Reset the point labels to the unique points array
630 forAll(faceLst, faceI)
632 Face& f = faceLst[faceI];
635 f[fp] = pointMap[f[fp]];
638 // for extra safety: collapse face as well
639 if (f.collapse() >= 3)
641 if (newFaceI != faceI)
643 faceLst[newFaceI] = f;
645 faceMap[newFaceI] = faceI;
650 Pout<< "MeshedSurface::stitchFaces : "
651 << "Removing collapsed face " << faceI << endl
652 << " vertices :" << f << endl;
657 if (newFaceI != faceLst.size())
661 Pout<< "MeshedSurface::stitchFaces : "
662 << "Removed " << faceLst.size() - newFaceI
665 faceLst.setSize(newFaceI);
670 // Merging points might have changed geometric factors
671 ParentType::clearOut();
676 // Remove badly degenerate faces and double faces.
678 bool Foam::MeshedSurface<Face>::checkFaces
683 bool changed = false;
684 List<Face>& faceLst = this->storedFaces();
686 List<label> faceMap(faceLst.size());
689 // Detect badly labelled faces and mark degenerate faces
690 const label maxPointI = this->points().size() - 1;
691 forAll(faceLst, faceI)
693 Face& f = faceLst[faceI];
695 // avoid degenerate faces
696 if (f.collapse() >= 3)
700 if (f[fp] < 0 || f[fp] > maxPointI)
702 FatalErrorIn("MeshedSurface::checkFaces(bool)")
704 << " uses point indices outside point range 0.."
710 faceMap[faceI] = faceI;
723 "MeshedSurface::checkFaces(bool verbose)"
724 ) << "face[" << faceI << "] = " << f
725 << " does not have three unique vertices" << endl;
730 // Detect doubled faces
731 // do not touch the faces
732 const labelListList& fFaces = this->faceFaces();
734 forAll(faceLst, faceI)
736 // skip already collapsed faces:
737 if (faceMap[faceI] < 0)
742 const Face& f = faceLst[faceI];
744 // duplicate face check
746 const labelList& neighbours = fFaces[faceI];
748 // Check if faceNeighbours use same points as this face.
749 // Note: discards normal information - sides of baffle are merged.
750 forAll(neighbours, neighI)
752 const label neiFaceI = neighbours[neighI];
754 if (neiFaceI <= faceI || faceMap[neiFaceI] < 0)
756 // lower numbered faces already checked
757 // skip neighbours that are themselves collapsed
761 const Face& nei = faceLst[neiFaceI];
771 "MeshedSurface::checkFaces(bool verbose)"
772 ) << "faces share the same vertices:" << nl
773 << " face[" << faceI << "] : " << f << nl
774 << " face[" << neiFaceI << "] : " << nei << endl;
775 // printFace(Warning, " ", f, points());
776 // printFace(Warning, " ", nei, points());
785 faceMap[faceI] = faceI;
795 // Done to keep numbering constant in phase 1
797 if (changed || newFaceI < faceLst.size())
805 "MeshedSurface::checkFaces(bool verbose)"
806 ) << "Removed " << faceLst.size() - newFaceI
807 << " illegal faces." << endl;
810 // compress the face list
812 forAll(faceLst, faceI)
814 if (faceMap[faceI] >= 0)
816 if (newFaceI != faceI)
818 faceLst[newFaceI] = faceLst[faceI];
820 faceMap[newFaceI] = faceI;
825 faceLst.setSize(newFaceI);
830 // Topology can change because of renumbering
831 ParentType::clearOut();
837 Foam::label Foam::MeshedSurface<Face>::triangulate()
841 const_cast<List<label>&>(List<label>::null())
847 Foam::label Foam::MeshedSurface<Face>::triangulate
849 List<label>& faceMapOut
853 label maxTri = 0; // the maximum number of triangles for any single face
854 List<Face>& faceLst = this->storedFaces();
856 // determine how many triangles will be needed
857 forAll(faceLst, faceI)
859 const label n = faceLst[faceI].nTriangles();
868 if (nTri <= faceLst.size())
877 List<Face> newFaces(nTri);
880 // reuse storage from optional faceMap
883 faceMap.transfer(faceMapOut);
885 faceMap.setSize(nTri);
887 // remember the number of *additional* faces
888 nTri -= faceLst.size();
890 if (this->points().empty())
892 // triangulate without points
893 // simple face triangulation around f[0]
895 forAll(faceLst, faceI)
897 const Face& f = faceLst[faceI];
899 for (label fp = 1; fp < f.size() - 1; ++fp)
901 label fp1 = f.fcIndex(fp);
903 newFaces[newFaceI] = triFace(f[0], f[fp], f[fp1]);
904 faceMap[newFaceI] = faceI;
911 // triangulate with points
912 List<face> tmpTri(maxTri);
915 forAll(faceLst, faceI)
917 // 'face' not '<Face>'
918 const face& f = faceLst[faceI];
921 f.triangles(this->points(), nTmp, tmpTri);
922 for (label triI = 0; triI < nTmp; triI++)
924 newFaces[newFaceI] = Face
926 static_cast<UList<label>&>(tmpTri[triI])
928 faceMap[newFaceI] = faceI;
934 faceLst.transfer(newFaces);
937 // optionally return the faceMap
940 faceMapOut.transfer(faceMap);
944 // Topology can change because of renumbering
945 ParentType::clearOut();
953 Foam::MeshedSurface<Face> Foam::MeshedSurface<Face>::subsetMesh
955 const labelHashSet& include,
960 const pointField& locPoints = this->localPoints();
961 const List<Face>& locFaces = this->localFaces();
964 // Fill pointMap, faceMap
965 PatchTools::subsetMap(*this, include, pointMap, faceMap);
967 // Create compact coordinate list and forward mapping array
968 pointField newPoints(pointMap.size());
969 labelList oldToNew(locPoints.size());
970 forAll(pointMap, pointI)
972 newPoints[pointI] = locPoints[pointMap[pointI]];
973 oldToNew[pointMap[pointI]] = pointI;
976 // create/copy a new zones list, each zone with zero size
977 surfZoneList newZones(this->surfZones());
978 forAll(newZones, zoneI)
980 newZones[zoneI].size() = 0;
983 // Renumber face node labels
984 List<Face> newFaces(faceMap.size());
985 forAll(faceMap, faceI)
987 const label origFaceI = faceMap[faceI];
988 newFaces[faceI] = Face(locFaces[origFaceI]);
990 // Renumber labels for face
991 Face& f = newFaces[faceI];
994 f[fp] = oldToNew[f[fp]];
999 // recalculate the zones start/size
1003 // adjust zone sizes
1004 forAll(newZones, zoneI)
1006 surfZone& zone = newZones[zoneI];
1008 // adjust zone start
1009 zone.start() = newFaceI;
1010 origEndI += zone.size();
1012 for (label faceI = newFaceI; faceI < faceMap.size(); ++faceI)
1014 if (faceMap[faceI] < origEndI)
1025 zone.size() = newFaceI - zone.start();
1029 // construct a sub-surface
1030 return MeshedSurface
1032 xferMove(newPoints),
1039 template<class Face>
1040 Foam::MeshedSurface<Face>
1041 Foam::MeshedSurface<Face>::subsetMesh
1043 const labelHashSet& include
1046 labelList pointMap, faceMap;
1047 return subsetMesh(include, pointMap, faceMap);
1052 template<class Face>
1053 void Foam::MeshedSurface<Face>::transfer
1055 MeshedSurface<Face>& surf
1060 xferMove(surf.storedPoints()),
1061 xferMove(surf.storedFaces()),
1062 xferMove(surf.storedZones())
1067 template<class Face>
1068 void Foam::MeshedSurface<Face>::transfer
1070 UnsortedMeshedSurface<Face>& surf
1076 surfZoneList zoneLst = surf.sortedZones(faceMap);
1078 if (zoneLst.size() <= 1)
1082 xferMove(surf.storedPoints()),
1083 xferMove(surf.storedFaces()),
1084 Xfer<surfZoneList>()
1089 List<Face>& oldFaces = surf.storedFaces();
1090 List<Face> newFaces(faceMap.size());
1092 forAll(faceMap, faceI)
1094 newFaces[faceI].transfer(oldFaces[faceMap[faceI]]);
1099 xferMove(surf.storedPoints()),
1110 template<class Face>
1111 Foam::Xfer< Foam::MeshedSurface<Face> >
1112 Foam::MeshedSurface<Face>::xfer()
1114 return xferMove(*this);
1118 // Read from file, determine format from extension
1119 template<class Face>
1120 bool Foam::MeshedSurface<Face>::read(const fileName& name)
1122 word ext = name.ext();
1125 fileName unzipName = name.lessExt();
1126 return read(unzipName, unzipName.ext());
1130 return read(name, ext);
1135 // Read from file in given format
1136 template<class Face>
1137 bool Foam::MeshedSurface<Face>::read
1139 const fileName& name,
1145 // read via selector mechanism
1146 transfer(New(name, ext)());
1151 template<class Face>
1152 void Foam::MeshedSurface<Face>::write
1155 const word& surfName
1158 MeshedSurfaceProxy<Face>(*this).write(t, surfName);
1161 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1163 template<class Face>
1164 void Foam::MeshedSurface<Face>::operator=(const MeshedSurface& surf)
1168 this->storedPoints() = surf.points();
1169 this->storedFaces() = surf.faces();
1170 this->storedZones() = surf.surfZones();
1174 template<class Face>
1175 Foam::MeshedSurface<Face>::operator
1176 Foam::MeshedSurfaceProxy<Face>() const
1178 return MeshedSurfaceProxy<Face>
1186 // * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * //
1188 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
1190 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1192 #include "MeshedSurfaceZones.C"
1193 #include "MeshedSurfaceIO.C"
1194 #include "MeshedSurfaceNew.C"
1196 // ************************************************************************* //