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/>.
28 Extracts and writes surface features to file
30 \*---------------------------------------------------------------------------*/
34 #include "triSurface.H"
37 #include "surfaceFeatures.H"
38 #include "featureEdgeMesh.H"
39 #include "extendedFeatureEdgeMesh.H"
40 #include "treeBoundBox.H"
41 #include "meshTools.H"
43 #include "unitConversion.H"
47 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
49 void dumpBox(const treeBoundBox& bb, const fileName& fName)
53 Info<< "Dumping bounding box " << bb << " as lines to obj file "
54 << str.name() << endl;
57 pointField boxPoints(bb.points());
61 meshTools::writeOBJ(str, boxPoints[i]);
64 forAll(treeBoundBox::edges, i)
66 const edge& e = treeBoundBox::edges[i];
68 str<< "l " << e[0]+1 << ' ' << e[1]+1 << nl;
73 // Deletes all edges inside/outside bounding box from set.
76 const triSurface& surf,
77 const treeBoundBox& bb,
78 const bool removeInside,
79 List<surfaceFeatures::edgeStatus>& edgeStat
82 forAll(edgeStat, edgeI)
84 const point eMid = surf.edges()[edgeI].centre(surf.localPoints());
86 if (removeInside ? bb.contains(eMid) : !bb.contains(eMid))
88 edgeStat[edgeI] = surfaceFeatures::NONE;
94 // Unmark non-manifold edges if individual triangles are not features
97 const triSurface& surf,
98 const scalar includedAngle,
99 List<surfaceFeatures::edgeStatus>& edgeStat
102 scalar minCos = Foam::cos(degToRad(180.0 - includedAngle));
104 const labelListList& edgeFaces = surf.edgeFaces();
106 forAll(edgeFaces, edgeI)
108 const labelList& eFaces = edgeFaces[edgeI];
110 if (eFaces.size() > 2)
112 label i0 = eFaces[0];
113 //const labelledTri& f0 = surf[i0];
114 const vector& n0 = surf.faceNormals()[i0];
116 //Pout<< "edge:" << edgeI << " n0:" << n0 << endl;
120 for (label i = 1; i < eFaces.size(); i++)
122 //const labelledTri& f = surf[i];
123 const vector& n = surf.faceNormals()[eFaces[i]];
125 //Pout<< " mag(n&n0): " << mag(n&n0) << endl;
127 if (mag(n&n0) < minCos)
136 edgeStat[edgeI] = surfaceFeatures::NONE;
145 int main(int argc, char *argv[])
149 "extract and write surface features to file"
151 argList::noParallel();
152 argList::validArgs.append("surface");
153 argList::validArgs.append("output set");
159 "construct feature set from included angle [0..180]"
165 "use existing feature set from file"
171 "remove features shorter than the specified cumulative length"
177 "remove features with fewer than the specified number of edges"
182 "((x0 y0 z0)(x1 y1 z1))",
183 "remove edges outside specified bounding box"
188 "((x0 y0 z0)(x1 y1 z1))",
189 "remove edges within specified bounding box"
191 argList::addBoolOption
194 "write extendedFeatureEdgeMesh obj files"
197 # include "setRootCase.H"
198 # include "createTime.H"
200 Info<< "Feature line extraction is only valid on closed manifold surfaces."
203 bool writeObj = args.optionFound("writeObj");
205 const fileName surfFileName = args[1];
206 const fileName outFileName = args[2];
208 Info<< "Surface : " << surfFileName << nl
209 << "Output feature set : " << outFileName << nl
212 fileName sFeatFileName = surfFileName.lessExt().name();
218 triSurface surf(surfFileName);
220 Info<< "Statistics:" << endl;
221 surf.writeStats(Info);
225 // Either construct features from surface&featureangle or read set.
226 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
228 surfaceFeatures set(surf);
230 if (args.optionFound("set"))
232 const fileName setName = args["set"];
234 Info<< "Reading existing feature set from file " << setName << endl;
236 set = surfaceFeatures(surf, setName);
238 else if (args.optionFound("includedAngle"))
240 const scalar includedAngle = args.optionRead<scalar>("includedAngle");
242 Info<< "Constructing feature set from included angle " << includedAngle
245 set = surfaceFeatures(surf, includedAngle);
247 // Info<< nl << "Writing initial features" << endl;
248 // set.write("initial.fSet");
249 // set.writeObj("initial");
253 FatalErrorIn(args.executable())
254 << "No initial feature set. Provide either one"
255 << " of -set (to read existing set)" << nl
256 << " or -includedAngle (to new set construct from angle)"
261 << "Initial feature set:" << nl
262 << " feature points : " << set.featurePoints().size() << nl
263 << " feature edges : " << set.featureEdges().size() << nl
265 << " region edges : " << set.nRegionEdges() << nl
266 << " external edges : " << set.nExternalEdges() << nl
267 << " internal edges : " << set.nInternalEdges() << nl
274 scalar minLen = -GREAT;
275 if (args.optionReadIfPresent("minLen", minLen))
277 Info<< "Removing features of length < " << minLen << endl;
281 if (args.optionReadIfPresent("minElem", minElem))
283 Info<< "Removing features with number of edges < " << minElem << endl;
286 // Trim away small groups of features
287 if (minElem > 0 || minLen > 0)
289 set.trimFeatures(minLen, minElem);
290 Info<< endl << "Removed small features" << endl;
297 // Convert to marked edges, points
298 List<surfaceFeatures::edgeStatus> edgeStat(set.toStatus());
300 if (args.optionFound("subsetBox"))
304 args.optionLookup("subsetBox")()
307 Info<< "Removing all edges outside bb " << bb << endl;
308 dumpBox(bb, "subsetBox.obj");
318 else if (args.optionFound("deleteBox"))
322 args.optionLookup("deleteBox")()
325 Info<< "Removing all edges inside bb " << bb << endl;
326 dumpBox(bb, "deleteBox.obj");
337 surfaceFeatures newSet(surf);
338 newSet.setFromStatus(edgeStat);
340 Info<< endl << "Writing trimmed features to " << outFileName << endl;
341 newSet.write(outFileName);
343 // Info<< endl << "Writing edge objs." << endl;
344 // newSet.writeObj("final");
347 << "Final feature set:" << nl
348 << " feature points : " << newSet.featurePoints().size() << nl
349 << " feature edges : " << newSet.featureEdges().size() << nl
351 << " region edges : " << newSet.nRegionEdges() << nl
352 << " external edges : " << newSet.nExternalEdges() << nl
353 << " internal edges : " << newSet.nInternalEdges() << nl
356 // Extracting and writing a extendedFeatureEdgeMesh
358 extendedFeatureEdgeMesh feMesh
362 sFeatFileName + ".extendedFeatureEdgeMesh"
365 Info<< nl << "Writing extendedFeatureEdgeMesh to " << feMesh.objectPath()
370 feMesh.writeObj(surfFileName.lessExt().name());
376 // Write a featureEdgeMesh for backwards compatibility
378 featureEdgeMesh bfeMesh
382 surfFileName.lessExt().name() + ".eMesh", // name
383 runTime.constant(), // instance
387 IOobject::AUTO_WRITE,
394 Info<< nl << "Writing featureEdgeMesh to "
395 << bfeMesh.objectPath() << endl;
397 bfeMesh.regIOobject::write();
400 Info<< "End\n" << endl;
406 // ************************************************************************* //