From 73ec082aa7171e8a78ae2e1180bd1e15d6ffbce4 Mon Sep 17 00:00:00 2001 From: laurence Date: Tue, 20 Mar 2012 17:46:34 +0000 Subject: [PATCH] ENH: surfaceFeatureExtract: Use a dictionary instead of command line options --- .../surfaceFeatureExtract.C | 1297 +++++++++-------- .../surfaceFeatureExtractDict | 86 ++ 2 files changed, 737 insertions(+), 646 deletions(-) create mode 100644 applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtractDict diff --git a/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtract.C b/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtract.C index c2baec519e..bf44c1cd77 100644 --- a/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtract.C +++ b/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtract.C @@ -74,30 +74,6 @@ scalarField calcCurvature(const triSurface& surf) // The rest of this function adapted from // CGAL-3.7/examples/Jet_fitting_3/Mesh_estimation.cpp - // Licensed under CGAL-3.7/LICENSE.FREE_USE - - // Copyright (c) 1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007 - // Utrecht University (The Netherlands), ETH Zurich (Switzerland), Freie - // Universitaet Berlin (Germany), INRIA Sophia-Antipolis (France), - // Martin-Luther-University Halle-Wittenberg (Germany), Max-Planck-Institute - // Saarbruecken (Germany), RISC Linz (Austria), and Tel-Aviv University - // (Israel). All rights reserved. - - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT - // OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR - // THE USE OR OTHER DEALINGS IN THE SOFTWARE. //Vertex property map, with std::map typedef std::map Vertex2int_map_type; @@ -503,358 +479,344 @@ int main(int argc, char *argv[]) "extract and write surface features to file" ); argList::noParallel(); - argList::validArgs.append("surface"); - argList::validArgs.append("output set"); argList::addOption ( - "includedAngle", - "degrees", - "construct feature set from included angle [0..180]" + "dict", + "word", + "name of dictionary to provide feature extraction information" ); - argList::addOption - ( - "set", - "name", - "use existing feature set from file" - ); - argList::addOption - ( - "minLen", - "scalar", - "remove features shorter than the specified cumulative length" - ); - argList::addOption - ( - "minElem", - "int", - "remove features with fewer than the specified number of edges" - ); - argList::addOption - ( - "subsetBox", - "((x0 y0 z0)(x1 y1 z1))", - "remove edges outside specified bounding box" - ); - argList::addOption - ( - "deleteBox", - "((x0 y0 z0)(x1 y1 z1))", - "remove edges within specified bounding box" - ); - argList::addBoolOption - ( - "writeObj", - "write extendedFeatureEdgeMesh obj files" - ); - argList::addBoolOption - ( - "writeVTK", - "write extendedFeatureEdgeMesh vtk files" - ); - argList::addBoolOption - ( - "closeness", - "span to look for surface closeness" - ); - argList::addOption - ( - "featureProximity", - "scalar", - "distance to look for close features" - ); - argList::addBoolOption - ( - "writeVTK", - "write surface property VTK files" - ); - argList::addBoolOption - ( - "manifoldEdgesOnly", - "remove any non-manifold (open or more than two connected faces) edges" - ); - argList::addOption - ( - "plane", - "(nx ny nz)(z0 y0 z0)", - "use a plane to create feature edges for 2D meshing" - ); - -# ifdef ENABLE_CURVATURE - argList::addBoolOption - ( - "curvature", - "calculate curvature and closeness fields" - ); -# endif - # include "setRootCase.H" # include "createTime.H" - bool writeVTK = args.optionFound("writeVTK"); - - bool writeObj = args.optionFound("writeObj"); - - bool curvature = args.optionFound("curvature"); - - if (curvature && env("FOAM_SIGFPE")) - { - WarningIn(args.executable()) - << "Detected floating point exception trapping (FOAM_SIGFPE)." - << " This might give" << nl - << " problems when calculating curvature on straight angles" - << " (infinite curvature)" << nl - << " Switch it off in case of problems." << endl; - } - - - Info<< "Feature line extraction is only valid on closed manifold surfaces." - << endl; - - const fileName surfFileName = args[1]; - const fileName outFileName = args[2]; - - Info<< "Surface : " << surfFileName << nl - << "Output feature set : " << outFileName << nl - << endl; - - fileName sFeatFileName = surfFileName.lessExt().name(); - - - // Read - // ~~~~ - - triSurface surf(surfFileName); - - Info<< "Statistics:" << endl; - surf.writeStats(Info); - Info<< endl; - - faceList faces(surf.size()); - - forAll(surf, fI) - { - faces[fI] = surf[fI].triFaceFace(); - } - - // Either construct features from surface&featureangle or read set. - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - surfaceFeatures set(surf); - - if (args.optionFound("set")) - { - const fileName setName = args["set"]; - - Info<< "Reading existing feature set from file " << setName << endl; - - set = surfaceFeatures(surf, setName); - } - else if (args.optionFound("includedAngle")) - { - const scalar includedAngle = args.optionRead("includedAngle"); - - Info<< "Constructing feature set from included angle " << includedAngle - << endl; - - set = surfaceFeatures(surf, includedAngle); - - // Info<< nl << "Writing initial features" << endl; - // set.write("initial.fSet"); - // set.writeObj("initial"); - } - else - { - FatalErrorIn(args.executable()) - << "No initial feature set. Provide either one" - << " of -set (to read existing set)" << nl - << " or -includedAngle (to new set construct from angle)" - << exit(FatalError); - } - - Info<< nl - << "Initial feature set:" << nl - << " feature points : " << set.featurePoints().size() << nl - << " feature edges : " << set.featureEdges().size() << nl - << " of which" << nl - << " region edges : " << set.nRegionEdges() << nl - << " external edges : " << set.nExternalEdges() << nl - << " internal edges : " << set.nInternalEdges() << nl - << endl; - - - // Trim set - // ~~~~~~~~ - - scalar minLen = -GREAT; - if (args.optionReadIfPresent("minLen", minLen)) - { - Info<< "Removing features of length < " << minLen << endl; - } - - label minElem = 0; - if (args.optionReadIfPresent("minElem", minElem)) - { - Info<< "Removing features with number of edges < " << minElem << endl; - } - - // Trim away small groups of features - if (minElem > 0 || minLen > 0) - { - set.trimFeatures(minLen, minElem); - Info<< endl << "Removed small features" << endl; - } - - - // Subset - // ~~~~~~ - - // Convert to marked edges, points - List edgeStat(set.toStatus()); - - if (args.optionFound("subsetBox")) - { - treeBoundBox bb - ( - args.optionLookup("subsetBox")() - ); - - Info<< "Removing all edges outside bb " << bb << endl; - dumpBox(bb, "subsetBox.obj"); - - deleteBox - ( - surf, - bb, - false, - edgeStat - ); - } - else if (args.optionFound("deleteBox")) - { - treeBoundBox bb - ( - args.optionLookup("deleteBox")() - ); - - Info<< "Removing all edges inside bb " << bb << endl; - dumpBox(bb, "deleteBox.obj"); - - deleteBox - ( - surf, - bb, - true, - edgeStat - ); - } - - if (args.optionFound("manifoldEdgesOnly")) - { - Info<< "Removing all non-manifold edges" << endl; - - forAll(edgeStat, edgeI) - { - if (surf.edgeFaces()[edgeI].size() != 2) - { - edgeStat[edgeI] = surfaceFeatures::NONE; - } - } - } - - if (args.optionFound("plane")) - { - plane cutPlane(args.optionLookup("plane")()); - - deleteEdges - ( - surf, - cutPlane, - edgeStat - ); - - Info<< "Only edges that intersect the plane with normal " - << cutPlane.normal() << " and base point " << cutPlane.refPoint() - << " will be included as feature edges."<< endl; - } - - - surfaceFeatures newSet(surf); - newSet.setFromStatus(edgeStat); - - //Info<< endl << "Writing trimmed features to " << outFileName << endl; - //newSet.write(outFileName); - - // Info<< endl << "Writing edge objs." << endl; - // newSet.writeObj("final"); - - Info<< nl - << "Final feature set:" << nl - << " feature points : " << newSet.featurePoints().size() << nl - << " feature edges : " << newSet.featureEdges().size() << nl - << " of which" << nl - << " region edges : " << newSet.nRegionEdges() << nl - << " external edges : " << newSet.nExternalEdges() << nl - << " internal edges : " << newSet.nInternalEdges() << nl - << endl; - - // Extracting and writing a extendedFeatureEdgeMesh - extendedFeatureEdgeMesh feMesh + word dictName ( - newSet, - runTime, - sFeatFileName + ".extendedFeatureEdgeMesh" + args.optionLookupOrDefault("dict", "surfaceFeatureExtractDict") ); - Info<< nl << "Writing extendedFeatureEdgeMesh to " << feMesh.objectPath() - << endl; + Info<< "Reading " << dictName << nl << endl; - if (writeObj) - { - feMesh.writeObj(surfFileName.lessExt().name()); - } - - feMesh.write(); - - // Write a featureEdgeMesh for backwards compatibility - { - featureEdgeMesh bfeMesh - ( - IOobject - ( - surfFileName.lessExt().name() + ".eMesh", // name - runTime.constant(), // instance - "triSurface", - runTime, // registry - IOobject::NO_READ, - IOobject::AUTO_WRITE, - false - ), - feMesh.points(), - feMesh.edges() - ); - - Info<< nl << "Writing featureEdgeMesh to " - << bfeMesh.objectPath() << endl; - - bfeMesh.regIOobject::write(); - } - - triSurfaceMesh searchSurf + IOdictionary dict ( IOobject ( - sFeatFileName + ".closeness", - runTime.constant(), - "triSurface", + dictName, + runTime.system(), runTime, - IOobject::NO_READ, - IOobject::NO_WRITE - ), - surf + IOobject::MUST_READ, + IOobject::NO_WRITE, + false + ) ); + forAllConstIter(dictionary, dict, iter) + { + dictionary surfaceDict = dict.subDict(iter().keyword()); + + const fileName surfFileName = iter().keyword(); + const fileName sFeatFileName = surfFileName.lessExt().name(); + + Info<< "Surface : " << surfFileName << nl << endl; + + const Switch writeVTK = + surfaceDict.lookupOrAddDefault("writeVTK", "off"); + const Switch writeObj = + surfaceDict.lookupOrAddDefault("writeObj", "off"); + const Switch writeFeatureEdgeMesh = + surfaceDict.lookupOrAddDefault + ( + "writeFeatureEdgeMesh", + "off" + ); + + const Switch curvature = + surfaceDict.lookupOrAddDefault("curvature", "off"); + const Switch featureProximity = + surfaceDict.lookupOrAddDefault("featureProximity", "off"); + const Switch closeness = + surfaceDict.lookupOrAddDefault("closeness", "off"); + + const word extractionMethod = surfaceDict.lookup("extractionMethod"); + + +#ifndef ENABLE_CURVATURE + if (curvature) + { + WarningIn(args.executable()) + << "Curvature calculation has been requested but " + << args.executable() << " has not " << nl + << " been compiled with CGAL. " + << "Skipping the curvature calculation." << endl; + } +#else + if (curvature && env("FOAM_SIGFPE")) + { + WarningIn(args.executable()) + << "Detected floating point exception trapping (FOAM_SIGFPE)." + << " This might give" << nl + << " problems when calculating curvature on straight angles" + << " (infinite curvature)" << nl + << " Switch it off in case of problems." << endl; + } +#endif + + + Info<< nl << "Feature line extraction is only valid on closed manifold " + << "surfaces." << endl; + + // Read + // ~~~~ + + triSurface surf("constant/triSurface/" + surfFileName); + + Info<< "Statistics:" << endl; + surf.writeStats(Info); + Info<< endl; + + faceList faces(surf.size()); + + forAll(surf, fI) + { + faces[fI] = surf[fI].triFaceFace(); + } + + + // Either construct features from surface & featureAngle or read set. + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + surfaceFeatures set(surf); + + if (extractionMethod == "extractFromFile") + { + const fileName featureEdgeFile = + surfaceDict.subDict("extractFromFile").lookup + ( + "featureEdgeFile" + ); + + edgeMesh eMesh(featureEdgeFile); + + // Sometimes duplicate edges are present. Remove them. + eMesh.mergeEdges(); + + Info<< nl << "Reading existing feature edges from file " + << featureEdgeFile << endl; + + set = surfaceFeatures(surf, eMesh.points(), eMesh.edges()); + } + else if (extractionMethod == "extractFromSurface") + { + const scalar includedAngle = + readScalar + ( + surfaceDict.subDict("extractFromSurface").lookup + ( + "includedAngle" + ) + ); + + Info<< nl << "Constructing feature set from included angle " + << includedAngle << endl; + + set = surfaceFeatures(surf, includedAngle); + } + else + { + FatalErrorIn(args.executable()) + << "No initial feature set. Provide either one" + << " of extractFromFile (to read existing set)" << nl + << " or extractFromSurface (to construct new set from angle)" + << exit(FatalError); + } + + Info<< nl + << "Initial feature set:" << nl + << " feature points : " << set.featurePoints().size() << nl + << " feature edges : " << set.featureEdges().size() << nl + << " of which" << nl + << " region edges : " << set.nRegionEdges() << nl + << " external edges : " << set.nExternalEdges() << nl + << " internal edges : " << set.nInternalEdges() << nl + << endl; + + + // Trim set + // ~~~~~~~~ + + if (surfaceDict.isDict("trimFeatures")) + { + dictionary trimDict = surfaceDict.subDict("trimFeatures"); + + scalar minLen = + trimDict.lookupOrAddDefault("minLen", -GREAT); + + label minElem = trimDict.lookupOrAddDefault