1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 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 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 "triSurface.H"
28 #include "demandDrivenData.H"
33 #include "SortableList.H"
34 #include "PackedBoolList.H"
36 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
41 defineTypeNameAndDebug(Foam::triSurface, 0);
45 Foam::fileName Foam::triSurface::triSurfInstance(const Time& d)
47 fileName foamName(d.caseName() + ".ftr");
49 // Search back through the time directories list to find the time
50 // closest to and lower than current time
52 instantList ts = d.times();
55 for (i=ts.size()-1; i>=0; i--)
57 if (ts[i].value() <= d.timeOutputValue())
63 // Noting that the current directory has already been searched
64 // for mesh data, start searching from the previously stored time directory
68 for (label j=i; j>=0; j--)
70 if (isFile(d.path()/ts[j].name()/typeName/foamName))
74 Pout<< " triSurface::triSurfInstance(const Time& d)"
75 << "reading " << foamName
76 << " from " << ts[j].name()/typeName
87 Pout<< " triSurface::triSurfInstance(const Time& d)"
88 << "reading " << foamName
89 << " from constant/" << endl;
95 Foam::List<Foam::labelledTri> Foam::triSurface::convertToTri
97 const faceList& faces,
98 const label defaultRegion
101 List<labelledTri> triFaces(faces.size());
103 forAll(triFaces, faceI)
105 const face& f = faces[faceI];
111 "triSurface::convertToTri"
112 "(const faceList&, const label)"
113 ) << "Face at position " << faceI
114 << " does not have three vertices:" << f
115 << abort(FatalError);
118 labelledTri& tri = triFaces[faceI];
123 tri.region() = defaultRegion;
130 Foam::List<Foam::labelledTri> Foam::triSurface::convertToTri
132 const triFaceList& faces,
133 const label defaultRegion
136 List<labelledTri> triFaces(faces.size());
138 forAll(triFaces, faceI)
140 const triFace& f = faces[faceI];
142 labelledTri& tri = triFaces[faceI];
147 tri.region() = defaultRegion;
154 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
156 void Foam::triSurface::printTriangle
160 const labelledTri& f,
161 const pointField& points
165 << pre.c_str() << "vertex numbers:"
166 << f[0] << ' ' << f[1] << ' ' << f[2] << endl
167 << pre.c_str() << "vertex coords :"
168 << points[f[0]] << ' ' << points[f[1]] << ' ' << points[f[2]]
169 << pre.c_str() << "region :" << f.region() << endl
174 Foam::string Foam::triSurface::getLineNoComment(IFstream& is)
181 while ((line.empty() || line[0] == '#') && is.good());
187 // Remove non-triangles, double triangles.
188 void Foam::triSurface::checkTriangles(const bool verbose)
190 // Simple check on indices ok.
191 const label maxPointI = points().size() - 1;
195 const labelledTri& f = (*this)[faceI];
199 (f[0] < 0) || (f[0] > maxPointI)
200 || (f[1] < 0) || (f[1] > maxPointI)
201 || (f[2] < 0) || (f[2] > maxPointI)
204 FatalErrorIn("triSurface::checkTriangles(bool)")
206 << " uses point indices outside point range 0.."
213 // 1. mark invalid faces
215 // Done to keep numbering constant in phase 1
217 // List of valid triangles
218 boolList valid(size(), true);
219 bool hasInvalid = false;
221 const labelListList& fFaces = faceFaces();
225 const labelledTri& f = (*this)[faceI];
227 if ((f[0] == f[1]) || (f[0] == f[2]) || (f[1] == f[2]))
229 // 'degenerate' triangle check
230 valid[faceI] = false;
237 "triSurface::checkTriangles(bool verbose)"
238 ) << "triangle " << faceI
239 << " does not have three unique vertices:\n";
240 printTriangle(Warning, " ", f, points());
245 // duplicate triangle check
246 const labelList& neighbours = fFaces[faceI];
248 // Check if faceNeighbours use same points as this face.
249 // Note: discards normal information - sides of baffle are merged.
250 forAll(neighbours, neighbourI)
252 if (neighbours[neighbourI] <= faceI)
254 // lower numbered faces already checked
258 const labelledTri& n = (*this)[neighbours[neighbourI]];
262 ((f[0] == n[0]) || (f[0] == n[1]) || (f[0] == n[2]))
263 && ((f[1] == n[0]) || (f[1] == n[1]) || (f[1] == n[2]))
264 && ((f[2] == n[0]) || (f[2] == n[1]) || (f[2] == n[2]))
267 valid[faceI] = false;
274 "triSurface::checkTriangles(bool verbose)"
275 ) << "triangles share the same vertices:\n"
276 << " face 1 :" << faceI << endl;
277 printTriangle(Warning, " ", f, points());
282 << neighbours[neighbourI] << endl;
283 printTriangle(Warning, " ", n, points());
300 const labelledTri& f = (*this)[faceI];
301 (*this)[newFaceI++] = f;
309 "triSurface::checkTriangles(bool verbose)"
310 ) << "Removing " << size() - newFaceI
311 << " illegal faces." << endl;
313 (*this).setSize(newFaceI);
315 // Topology can change because of renumbering
321 // Check/fix edges with more than two triangles
322 void Foam::triSurface::checkEdges(const bool verbose)
324 const labelListList& eFaces = edgeFaces();
326 forAll(eFaces, edgeI)
328 const labelList& myFaces = eFaces[edgeI];
332 FatalErrorIn("triSurface::checkEdges(bool verbose)")
333 << "Edge " << edgeI << " with vertices " << edges()[edgeI]
334 << " has no edgeFaces"
337 else if (myFaces.size() > 2)
341 "triSurface::checkEdges(bool verbose)"
342 ) << "Edge " << edgeI << " with vertices " << edges()[edgeI]
343 << " has more than 2 faces connected to it : " << myFaces
350 // Read triangles, points from Istream
351 bool Foam::triSurface::read(Istream& is)
353 is >> patches_ >> storedPoints() >> storedFaces();
359 // Read from file in given format
360 bool Foam::triSurface::read
362 const fileName& name,
367 if (check && !exists(name))
371 "triSurface::read(const fileName&, const word&, const bool)"
372 ) << "Cannnot read " << name << exit(FatalError);
377 fileName unzipName = name.lessExt();
379 // Do not check for existence. Let IFstream do the unzipping.
380 return read(unzipName, unzipName.ext(), false);
382 else if (ext == "ftr")
384 return read(IFstream(name)());
386 else if (ext == "stl")
388 return readSTL(name);
390 else if (ext == "stlb")
392 return readSTL(name);
394 else if (ext == "gts")
396 return readGTS(name);
398 else if (ext == "obj")
400 return readOBJ(name);
402 else if (ext == "off")
404 return readOFF(name);
406 else if (ext == "tri")
408 return readTRI(name);
410 else if (ext == "ac")
414 else if (ext == "nas")
416 return readNAS(name);
422 "triSurface::read(const fileName&, const word&)"
423 ) << "unknown file extension " << ext
424 << ". Supported extensions are '.ftr', '.stl', '.stlb', '.gts'"
425 << ", '.obj', '.ac', '.off', '.nas' and '.tri'"
433 // Write to file in given format
434 void Foam::triSurface::write
436 const fileName& name,
443 return write(OFstream(name)());
445 else if (ext == "stl")
447 return writeSTLASCII(OFstream(name)());
449 else if (ext == "stlb")
451 ofstream outFile(name.c_str(), std::ios::binary);
453 writeSTLBINARY(outFile);
455 else if (ext == "gts")
457 return writeGTS(sort, OFstream(name)());
459 else if (ext == "obj")
461 writeOBJ(sort, OFstream(name)());
463 else if (ext == "off")
465 writeOFF(sort, OFstream(name)());
467 else if (ext == "vtk")
469 writeVTK(sort, OFstream(name)());
471 else if (ext == "tri")
473 writeTRI(sort, OFstream(name)());
475 else if (ext == "dx")
477 writeDX(sort, OFstream(name)());
479 else if (ext == "ac")
481 writeAC(OFstream(name)());
483 else if (ext == "smesh")
485 writeSMESH(sort, OFstream(name)());
491 "triSurface::write(const fileName&, const word&, const bool)"
492 ) << "unknown file extension " << ext
493 << ". Supported extensions are '.ftr', '.stl', '.stlb', "
494 << "'.gts', '.obj', '.vtk'"
495 << ", '.off', '.dx', '.smesh', '.ac' and '.tri'"
501 // Returns patch info. Sets faceMap to the indexing according to patch
502 // numbers. Patch numbers start at 0.
503 Foam::surfacePatchList Foam::triSurface::calcPatches(labelList& faceMap) const
505 // Sort according to region numbers of labelledTri
506 SortableList<label> sortedRegion(size());
508 forAll(sortedRegion, faceI)
510 sortedRegion[faceI] = operator[](faceI).region();
514 faceMap = sortedRegion.indices();
517 label maxRegion = patches_.size()-1; // for non-compacted regions
524 operator[](faceMap[faceMap.size() - 1]).region()
528 // Get new region list
529 surfacePatchList newPatches(maxRegion + 1);
534 label region = operator[](faceI).region();
536 newPatches[region].size()++;
540 // Fill rest of patch info
542 label startFaceI = 0;
543 forAll(newPatches, newPatchI)
545 surfacePatch& newPatch = newPatches[newPatchI];
547 label oldPatchI = newPatchI;
550 newPatch.start() = startFaceI;
553 // Take over any information from existing patches
554 if ((oldPatchI < patches_.size()) && (patches_[oldPatchI].name() != ""))
556 newPatch.name() = patches_[oldPatchI].name();
560 newPatch.name() = word("patch") + name(newPatchI);
565 (oldPatchI < patches_.size())
566 && (patches_[oldPatchI].geometricType() != "")
569 newPatch.geometricType() = patches_[oldPatchI].geometricType();
573 newPatch.geometricType() = "empty";
576 startFaceI += newPatch.size();
583 void Foam::triSurface::setDefaultPatches()
587 // Get names, types and sizes
588 surfacePatchList newPatches(calcPatches(faceMap));
590 // Take over names and types (but not size)
591 patches_.setSize(newPatches.size());
593 forAll(newPatches, patchI)
595 patches_[patchI].name() = newPatches[patchI].name();
596 patches_[patchI].geometricType() = newPatches[patchI].geometricType();
601 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
603 Foam::triSurface::triSurface()
605 ParentType(List<Face>(), pointField()),
607 sortedEdgeFacesPtr_(NULL),
613 Foam::triSurface::triSurface
615 const List<labelledTri>& triangles,
616 const geometricSurfacePatchList& patches,
617 const pointField& points
620 ParentType(triangles, points),
622 sortedEdgeFacesPtr_(NULL),
627 Foam::triSurface::triSurface
629 List<labelledTri>& triangles,
630 const geometricSurfacePatchList& patches,
635 ParentType(triangles, points, reUse),
637 sortedEdgeFacesPtr_(NULL),
642 Foam::triSurface::triSurface
644 const List<labelledTri>& triangles,
645 const pointField& points
648 ParentType(triangles, points),
650 sortedEdgeFacesPtr_(NULL),
657 Foam::triSurface::triSurface
659 const triFaceList& triangles,
660 const pointField& points
663 ParentType(convertToTri(triangles, 0), points),
665 sortedEdgeFacesPtr_(NULL),
672 Foam::triSurface::triSurface(const fileName& name)
674 ParentType(List<Face>(), pointField()),
676 sortedEdgeFacesPtr_(NULL),
679 word ext = name.ext();
687 Foam::triSurface::triSurface(Istream& is)
689 ParentType(List<Face>(), pointField()),
691 sortedEdgeFacesPtr_(NULL),
700 Foam::triSurface::triSurface(const Time& d)
702 ParentType(List<Face>(), pointField()),
704 sortedEdgeFacesPtr_(NULL),
707 fileName foamFile(d.caseName() + ".ftr");
709 fileName foamPath(d.path()/triSurfInstance(d)/typeName/foamFile);
711 IFstream foamStream(foamPath);
719 Foam::triSurface::triSurface(const triSurface& ts)
721 ParentType(ts, ts.points()),
722 patches_(ts.patches()),
723 sortedEdgeFacesPtr_(NULL),
728 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
730 Foam::triSurface::~triSurface()
736 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
738 void Foam::triSurface::clearTopology()
740 ParentType::clearTopology();
741 deleteDemandDrivenData(sortedEdgeFacesPtr_);
742 deleteDemandDrivenData(edgeOwnerPtr_);
746 void Foam::triSurface::clearPatchMeshAddr()
748 ParentType::clearPatchMeshAddr();
752 void Foam::triSurface::clearOut()
754 ParentType::clearOut();
757 clearPatchMeshAddr();
761 const Foam::labelListList& Foam::triSurface::sortedEdgeFaces() const
763 if (!sortedEdgeFacesPtr_)
765 calcSortedEdgeFaces();
768 return *sortedEdgeFacesPtr_;
772 const Foam::labelList& Foam::triSurface::edgeOwner() const
779 return *edgeOwnerPtr_;
784 void Foam::triSurface::movePoints(const pointField& newPoints)
786 // Remove all geometry dependent data
787 deleteDemandDrivenData(sortedEdgeFacesPtr_);
789 // Adapt for new point position
790 ParentType::movePoints(newPoints);
793 storedPoints() = newPoints;
798 void Foam::triSurface::scalePoints(const scalar& scaleFactor)
801 if (scaleFactor > 0 && scaleFactor != 1.0)
803 // Remove all geometry dependent data
806 // Adapt for new point position
807 ParentType::movePoints(pointField());
809 storedPoints() *= scaleFactor;
814 // Remove non-triangles, double triangles.
815 void Foam::triSurface::cleanup(const bool verbose)
817 // Merge points (already done for STL, TRI)
818 stitchTriangles(pointField(points()), SMALL, verbose);
820 // Merging points might have changed geometric factors
823 checkTriangles(verbose);
829 // Finds area, starting at faceI, delimited by borderEdge. Marks all visited
830 // faces (from face-edge-face walk) with currentZone.
831 void Foam::triSurface::markZone
833 const boolList& borderEdge,
835 const label currentZone,
839 // List of faces whose faceZone has been set.
840 labelList changedFaces(1, faceI);
844 // Pick up neighbours of changedFaces
845 DynamicList<label> newChangedFaces(2*changedFaces.size());
847 forAll(changedFaces, i)
849 label faceI = changedFaces[i];
851 const labelList& fEdges = faceEdges()[faceI];
855 label edgeI = fEdges[i];
857 if (!borderEdge[edgeI])
859 const labelList& eFaces = edgeFaces()[edgeI];
863 label nbrFaceI = eFaces[j];
865 if (faceZone[nbrFaceI] == -1)
867 faceZone[nbrFaceI] = currentZone;
868 newChangedFaces.append(nbrFaceI);
870 else if (faceZone[nbrFaceI] != currentZone)
874 "triSurface::markZone(const boolList&,"
875 "const label, const label, labelList&) const"
877 << "Zones " << faceZone[nbrFaceI]
878 << " at face " << nbrFaceI
879 << " connects to zone " << currentZone
880 << " at face " << faceI
881 << abort(FatalError);
888 if (newChangedFaces.empty())
893 changedFaces.transfer(newChangedFaces);
898 // Finds areas delimited by borderEdge (or 'real' edges).
899 // Fills faceZone accordingly
900 Foam::label Foam::triSurface::markZones
902 const boolList& borderEdge,
906 faceZone.setSize(size());
909 if (borderEdge.size() != nEdges())
913 "triSurface::markZones"
914 "(const boolList&, labelList&)"
916 << "borderEdge boolList not same size as number of edges" << endl
917 << "borderEdge:" << borderEdge.size() << endl
918 << "nEdges :" << nEdges()
924 for (label startFaceI = 0;; zoneI++)
926 // Find first non-coloured face
927 for (; startFaceI < size(); startFaceI++)
929 if (faceZone[startFaceI] == -1)
935 if (startFaceI >= size())
940 faceZone[startFaceI] = zoneI;
942 markZone(borderEdge, startFaceI, zoneI, faceZone);
949 void Foam::triSurface::subsetMeshMap
951 const boolList& include,
956 const List<labelledTri>& locFaces = localFaces();
961 faceMap.setSize(locFaces.size());
963 pointMap.setSize(nPoints());
965 boolList pointHad(nPoints(), false);
967 forAll(include, oldFacei)
969 if (include[oldFacei])
971 // Store new faces compact
972 faceMap[faceI++] = oldFacei;
974 // Renumber labels for triangle
975 const labelledTri& tri = locFaces[oldFacei];
981 pointMap[pointI++] = a;
988 pointMap[pointI++] = b;
995 pointMap[pointI++] = c;
1001 faceMap.setSize(faceI);
1003 pointMap.setSize(pointI);
1007 Foam::triSurface Foam::triSurface::subsetMesh
1009 const boolList& include,
1010 labelList& pointMap,
1014 const pointField& locPoints = localPoints();
1015 const List<labelledTri>& locFaces = localFaces();
1017 // Fill pointMap, faceMap
1018 subsetMeshMap(include, pointMap, faceMap);
1021 // Create compact coordinate list and forward mapping array
1022 pointField newPoints(pointMap.size());
1023 labelList oldToNew(locPoints.size());
1024 forAll(pointMap, pointi)
1026 newPoints[pointi] = locPoints[pointMap[pointi]];
1027 oldToNew[pointMap[pointi]] = pointi;
1030 // Renumber triangle node labels and compact
1031 List<labelledTri> newTriangles(faceMap.size());
1033 forAll(faceMap, facei)
1035 // Get old vertex labels
1036 const labelledTri& tri = locFaces[faceMap[facei]];
1038 newTriangles[facei][0] = oldToNew[tri[0]];
1039 newTriangles[facei][1] = oldToNew[tri[1]];
1040 newTriangles[facei][2] = oldToNew[tri[2]];
1041 newTriangles[facei].region() = tri.region();
1044 // Construct subsurface
1045 return triSurface(newTriangles, patches(), newPoints, true);
1049 void Foam::triSurface::write
1051 const fileName& name,
1052 const bool sortByRegion
1055 write(name, name.ext(), sortByRegion);
1059 void Foam::triSurface::write(Ostream& os) const
1061 os << patches() << endl;
1063 //Note: Write with global point numbering
1064 os << points() << nl
1065 << static_cast<const List<labelledTri>&>(*this) << endl;
1067 // Check state of Ostream
1068 os.check("triSurface::write(Ostream&)");
1072 void Foam::triSurface::write(const Time& d) const
1074 fileName foamFile(d.caseName() + ".ftr");
1076 fileName foamPath(d.path()/triSurfInstance(d)/typeName/foamFile);
1078 OFstream foamStream(foamPath);
1084 void Foam::triSurface::writeStats(Ostream& os) const
1086 // Unfortunately nPoints constructs meshPoints() so do compact version
1088 PackedBoolList pointIsUsed(points().size());
1091 boundBox bb = boundBox::invertedBox;
1095 const labelledTri& f = operator[](triI);
1099 label pointI = f[fp];
1100 if (pointIsUsed.set(pointI, 1))
1102 bb.min() = ::Foam::min(bb.min(), points()[pointI]);
1103 bb.max() = ::Foam::max(bb.max(), points()[pointI]);
1109 os << "Triangles : " << size() << endl
1110 << "Vertices : " << nPoints << endl
1111 << "Bounding Box : " << bb << endl;
1115 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1117 void Foam::triSurface::operator=(const triSurface& ts)
1119 List<labelledTri>::operator=(ts);
1121 storedPoints() = ts.points();
1122 patches_ = ts.patches();
1126 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
1128 Foam::Ostream& Foam::operator<<(Ostream& os, const triSurface& sm)
1135 // ************************************************************************* //