ENH: improvements for surfaceIntersection (issue #450)

- adjust for updates in 'develop'

- change surfaceIntersection constructor to take a dictionary of
  options.

        tolerance      | Edge-length tolerance          | scalar | 1e-3
        allowEdgeHits  | Edge-end cuts another edge     | bool   | true
        avoidDuplicates | Reduce the number of duplicate points    | bool | true
        warnDegenerate | Number of warnings about degenerate edges | label | 0
This commit is contained in:
Mark Olesen
2017-04-28 08:49:45 +02:00
parent cd5ca147a7
commit 11c5456628
16 changed files with 1251 additions and 748 deletions

View File

@ -0,0 +1,3 @@
Test-surfaceIntersection.C
EXE = $(FOAM_USER_APPBIN)/Test-surfaceIntersection

View File

@ -0,0 +1,9 @@
EXE_INC = \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/edgeMesh/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/triSurface/lnInclude
EXE_LIBS = \
-lfiniteVolume \
-lmeshTools -ledgeMesh

View File

@ -0,0 +1,234 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Application
Test-surfaceIntersection
Description
Test surface-surface intersection
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "Time.H"
#include "triSurface.H"
#include "triSurfaceMesh.H"
#include "surfaceIntersection.H"
#include "OFstream.H"
using namespace Foam;
autoPtr<triSurface> loadSurface
(
const Foam::Time& runTime,
const fileName& surfName
)
{
Info<< "Reading surface " << surfName << endl;
const fileName fallback =
runTime.constantPath()/triSurfaceMesh::meshSubDir/surfName;
autoPtr<triSurface> surfPtr;
if (isFile(surfName))
{
surfPtr.set(new triSurface(surfName));
}
else if (isFile(fallback))
{
surfPtr.set(new triSurface(fallback));
}
else
{
FatalErrorInFunction
<< "No such file:" << surfName << exit(FatalError);
}
return surfPtr;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
argList::addNote
(
"Intersection of two surfaces. Writes obj file"
);
argList::addBoolOption
(
"debug2",
"set surfaceIntersection debug=2"
);
argList::addBoolOption
(
"debug4",
"set surfaceIntersection debug=4"
);
argList::addBoolOption
(
"print",
"print information about cuts, etc"
);
argList::addBoolOption
(
"mergeEdges",
"merge duplicate edges"
);
argList::addOption
(
"mergePoints",
"mergeTol",
"merge points (and edges) using the specified tolerance"
);
#include "addDictOption.H"
argList::addNote
(
"test intersect of two surfaces. Writes obj file"
);
argList::noParallel();
argList::noFunctionObjects();
argList::validArgs.append("surface file");
argList::validArgs.append("surface file");
#include "setRootCase.H"
#include "createTime.H"
const word outputFile(args.executable() + ".obj");
const fileName surf1Name(args[1]);
triSurface surf1 = loadSurface(runTime, surf1Name)();
Info<< surf1Name << " statistics:" << endl;
surf1.writeStats(Info);
Info<< endl;
const fileName surf2Name(args[2]);
triSurface surf2 = loadSurface(runTime, surf2Name)();
Info<< surf2Name << " statistics:" << endl;
surf2.writeStats(Info);
Info<< endl;
if (args.optionFound("debug2"))
{
surfaceIntersection::debug |= 2;
}
if (args.optionFound("debug4"))
{
surfaceIntersection::debug |= 4;
}
const bool optPrint = args.optionFound("print");
dictionary intersectOptions;
if (args.optionFound("dict"))
{
intersectOptions = IOdictionary
(
IOobject
(
args["dict"],
runTime,
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
)
);
}
intersectOptions.writeEntry("intersectOptions", Info);
Info<< endl;
triSurfaceSearch query1(surf1);
triSurfaceSearch query2(surf2);
surfaceIntersection cuts(query1, query2, intersectOptions);
Info<<"intersection "
<< cuts.cutPoints().size() << " points "
<< cuts.cutEdges().size() << " edges" << nl;
if (optPrint)
{
Info<< "surf1-cuts: " << cuts.surf1EdgeCuts() << nl
<< "surf2-cuts: " << cuts.surf2EdgeCuts() << nl
<< "face-pairs: " << cuts.facePairToEdge() << nl
<< "edges: " << cuts.cutEdges() << nl;
}
word mergeOp;
if (args.optionFound("mergePoints"))
{
cuts.mergePoints(args.optionRead<scalar>("mergePoints"));
mergeOp = "mergePoints";
}
else if (args.optionFound("mergeEdges"))
{
cuts.mergeEdges();
mergeOp = "mergeEdges";
}
if (!mergeOp.empty())
{
Info<< mergeOp << ": "
<< cuts.cutPoints().size() << " points "
<< cuts.cutEdges().size() << " edges" << nl;
if (optPrint)
{
Info<< "surf1-cuts: " << cuts.surf1EdgeCuts() << nl
<< "surf2-cuts: " << cuts.surf2EdgeCuts() << nl
<< "face-pairs: " << cuts.facePairToEdge() << nl
<< "edges: " << cuts.cutEdges() << nl;
}
}
const pointField& points = cuts.cutPoints();
const edgeList& edges = cuts.cutEdges();
if (points.size() || edges.size())
{
Info<<"write to " << outputFile << nl;
OFstream os(outputFile);
forAll(points, pointi)
{
const point& pt = points[pointi];
os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
}
forAll(edges, edgei)
{
const edge& e = edges[edgei];
os << "l " << e.start()+1 << ' ' << e.end()+1 << nl;
}
}
Info<< "End\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -0,0 +1,7 @@
#!/bin/sh
cd ${0%/*} || exit 1 # Run from this directory
wclean libso extractionMethod
wclean .
#------------------------------------------------------------------------------

View File

@ -0,0 +1,9 @@
#!/bin/sh
cd ${0%/*} || exit 1 # Run from this directory
# Parse arguments for library compilation
. $WM_PROJECT_DIR/wmake/scripts/AllwmakeParseArguments
(wmake libso extractionMethod && wmake)
#------------------------------------------------------------------------------

View File

@ -1,6 +1,7 @@
method = . method = .
$(method)/surfaceFeaturesExtraction.C $(method)/surfaceFeaturesExtraction.C
$(method)/extractFromSurface.C
$(method)/extractFromFile.C $(method)/extractFromFile.C
$(method)/extractFromNone.C
$(method)/extractFromSurface.C
LIB = $(FOAM_LIBBIN)/libsurfaceFeatureExtract LIB = $(FOAM_LIBBIN)/libsurfaceFeatureExtract

View File

@ -24,7 +24,6 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "extractFromFile.H" #include "extractFromFile.H"
#include "ListOps.H"
#include "edgeMesh.H" #include "edgeMesh.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"

View File

@ -0,0 +1,81 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "extractFromNone.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace surfaceFeaturesExtraction
{
addNamedToRunTimeSelectionTable
(
method,
extractFromNone,
dictionary,
none
);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::surfaceFeaturesExtraction::extractFromNone::extractFromNone
(
const dictionary& dict
)
:
method()
{
const dictionary& coeffDict = dict.subOrEmptyDict("extractFromNoneCoeffs");
coeffDict.readIfPresent("includedAngle", includedAngle_);
coeffDict.readIfPresent("geometricTestOnly", geometricTestOnly_);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::surfaceFeaturesExtraction::extractFromNone::~extractFromNone()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::autoPtr<Foam::surfaceFeatures>
Foam::surfaceFeaturesExtraction::extractFromNone::features
(
const triSurface& surf
) const
{
return autoPtr<surfaceFeatures>(new surfaceFeatures(surf));
}
// ************************************************************************* //

View File

@ -0,0 +1,91 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::surfaceFeaturesExtraction::extractFromNone
Description
Run-time selectable surface feature extraction.
SourceFiles
extractionMethod.C
\*---------------------------------------------------------------------------*/
#ifndef surfaceFeaturesExtraction_extractFromNone_H
#define surfaceFeaturesExtraction_extractFromNone_H
#include "surfaceFeaturesExtraction.H"
#include "dictionary.H"
#include "Switch.H"
#include "triSurface.H"
#include "edgeIntersections.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace surfaceFeaturesExtraction
{
/*---------------------------------------------------------------------------*\
Class surfaceFeaturesExtraction::extractFromNone Declaration
\*---------------------------------------------------------------------------*/
class extractFromNone
:
public method
{
public:
// Constructors
//- Construct from dictionary
extractFromNone(const dictionary& dict);
//- Destructor
virtual ~extractFromNone();
//- Extracted features from surface (no-op)
virtual autoPtr<surfaceFeatures> features
(
const triSurface& surf
) const override;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace surfaceFeaturesExtraction
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -26,12 +26,6 @@ License
#include "extractFromSurface.H" #include "extractFromSurface.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
#include "triSurface.H"
#include "triSurfaceSearch.H"
#include "scalarField.H"
#include "edgeIntersections.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam namespace Foam

View File

@ -56,10 +56,6 @@ class extractFromSurface
: :
public method public method
{ {
bool selfIntersection_;
public: public:
// Constructors // Constructors

View File

@ -29,12 +29,17 @@ Group
Description Description
Extracts and writes surface features to file. All but the basic feature Extracts and writes surface features to file. All but the basic feature
extraction is WIP. extraction is a work-in-progress.
Curvature calculation is an implementation of the algorithm from: The curvature calculation is an implementation of the algorithm from:
\verbatim
"Estimating Curvatures and their Derivatives on Triangle Meshes" "Estimating Curvatures and their Derivatives on Triangle Meshes"
by S. Rusinkiewicz by S. Rusinkiewicz
3DPVT'04 Proceedings of the 3D Data Processing,
Visualization, and Transmission, 2nd International Symposium
Pages 486-493
http://gfx.cs.princeton.edu/pubs/_2004_ECA/curvpaper.pdf
\endverbatim
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -60,6 +65,7 @@ Description
#include "point.H" #include "point.H"
#include "triadField.H" #include "triadField.H"
#include "transform.H" #include "transform.H"
#include "triSurfaceLoader.H"
using namespace Foam; using namespace Foam;
@ -367,23 +373,6 @@ triSurfacePointScalarField calcCurvature
} }
bool edgesConnected(const edge& e1, const edge& e2)
{
if
(
e1.start() == e2.start()
|| e1.start() == e2.end()
|| e1.end() == e2.start()
|| e1.end() == e2.end()
)
{
return true;
}
return false;
}
scalar calcProximityOfFeaturePoints scalar calcProximityOfFeaturePoints
( (
const List<pointIndexHit>& hitList, const List<pointIndexHit>& hitList,
@ -462,7 +451,7 @@ scalar calcProximityOfFeatureEdges
const edge& e2 = efem.edges()[pHit2.index()]; const edge& e2 = efem.edges()[pHit2.index()];
// Don't refine if the edges are connected to each other // Don't refine if the edges are connected to each other
if (!edgesConnected(e1, e2)) if (!e1.connects(e2))
{ {
scalar curDist = scalar curDist =
mag(pHit1.hitPoint() - pHit2.hitPoint()); mag(pHit1.hitPoint() - pHit2.hitPoint());
@ -480,25 +469,12 @@ scalar calcProximityOfFeatureEdges
void dumpBox(const treeBoundBox& bb, const fileName& fName) void dumpBox(const treeBoundBox& bb, const fileName& fName)
{ {
OFstream str(fName); OFstream os(fName);
Info<< "Dumping bounding box " << bb << " as lines to obj file " Info<< "Dumping bounding box " << bb << " as lines to obj file "
<< str.name() << endl; << os.name() << endl;
meshTools::writeOBJ(os, bb);
pointField boxPoints(bb.points());
forAll(boxPoints, i)
{
meshTools::writeOBJ(str, boxPoints[i]);
}
forAll(treeBoundBox::edges, i)
{
const edge& e = treeBoundBox::edges[i];
str<< "l " << e[0]+1 << ' ' << e[1]+1 << nl;
}
} }
@ -866,62 +842,6 @@ void writeStats(const extendedFeatureEdgeMesh& fem, Ostream& os)
} }
// Read and combine all surfaces into a single one
autoPtr<triSurface> loadSurfaces(Time& runTime, const wordList& surfNames)
{
List<labelledTri> faces;
pointField points;
label regoff = 0; // region offset
forAll(surfNames, surfi)
{
const word& surfName = surfNames[surfi];
triSurface addsurf(runTime.constantPath()/"triSurface"/surfName);
List<labelledTri> addfaces(addsurf.xferFaces());
List<point> addpoints(addsurf.xferPoints());
if (surfi)
{
const label ptoff = points.size(); // point offset
forAll(addfaces, facei)
{
labelledTri& f = addfaces[facei];
forAll(f, fi)
{
f[fi] += ptoff;
}
f.region() += regoff;
}
faces.append(addfaces);
points.append(addpoints);
}
else
{
faces.transfer(addfaces);
points.transfer(addpoints);
}
regoff += addsurf.patches().size();
}
return autoPtr<triSurface>
(
new triSurface
(
faces,
geometricSurfacePatchList(),
points,
true
)
);
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
argList::addNote argList::addNote
@ -939,25 +859,15 @@ int main(int argc, char *argv[])
const word dictName("surfaceFeatureExtractDict"); const word dictName("surfaceFeatureExtractDict");
#include "setSystemRunTimeDictionaryIO.H" #include "setSystemRunTimeDictionaryIO.H"
// Will be using triSurface, so filter according to what is supported
fileNameList validSurfaceFiles = readDir
(
runTime.path()/runTime.constant()/"triSurface",
fileName::FILE
);
inplaceSubsetList
(
validSurfaceFiles,
[](const fileName& f){ return triSurface::canRead(f); }
);
// sort and eliminate duplicates (eg, files with/without .gz)
inplaceUniqueSort(validSurfaceFiles);
Info<< "Reading " << dictName << nl << endl; Info<< "Reading " << dictName << nl << endl;
const IOdictionary dict(dictIO); const IOdictionary dict(dictIO);
// Loader for available triSurface surface files
triSurfaceLoader loader(runTime);
// Where to write VTK output files
const fileName vtkOutputDir = runTime.constantPath()/"triSurface";
forAllConstIter(dictionary, dict, iter) forAllConstIter(dictionary, dict, iter)
{ {
if (!iter().isDict()) if (!iter().isDict())
@ -972,115 +882,88 @@ int main(int argc, char *argv[])
continue; continue;
} }
autoPtr<surfaceFeaturesExtraction::method> extractPtr = autoPtr<surfaceFeaturesExtraction::method> extractor =
surfaceFeaturesExtraction::method::New surfaceFeaturesExtraction::method::New
( (
surfaceDict surfaceDict
); );
const surfaceFeaturesExtraction::method& extract = extractPtr(); // The output name, cleansed of extensions
// Optional "output" entry, or the dictionary name.
// Output name, cleansed of extensions const word outputName =
const word sFeatFileName =
fileName fileName
( (
surfaceDict.lookupOrDefault<word>("output", iter().keyword()) surfaceDict.lookupOrDefault<word>("output", iter().keyword())
).lessExt(); ).lessExt();
wordList surfFileNames; // The "surfaces" entry is normally optional, but if the sub-dictionary
// is itself called "surfaces", then this becomes mandatory.
// This provides a simple means of handling both situations without an
// additional switch.
if if
( (
iter().keyword() == "surfaces" // mandatory iter().keyword() == "surfaces" // mandatory
|| surfaceDict.found("surfaces") // or optional || surfaceDict.found("surfaces") // or optional
) )
{ {
wordReList regexs(surfaceDict.lookup("surfaces")); loader.select(wordReList(surfaceDict.lookup("surfaces")));
labelList selected = findStrings(regexs, validSurfaceFiles);
surfFileNames.setSize(selected.size());
forAll(selected, i)
{
surfFileNames[i] = validSurfaceFiles[selected[i]].name();
}
if (surfFileNames.empty())
{
FatalErrorInFunction
<< "No surfaces specified/found for entry: "
<< iter().keyword()
<< exit(FatalError);
}
} }
else else
{ {
surfFileNames.setSize(1); loader.select(iter().keyword());
surfFileNames[0] = iter().keyword();
const fileName file
(
runTime.constantPath()/"triSurface"/surfFileNames[0]
);
if (!isFile(file))
{
FatalErrorInFunction
<< "No surface: " << file.name()
<< exit(FatalError);
}
} }
// DebugVar(surfFileNames); if (loader.selected().empty())
// DebugVar(sFeatFileName); {
FatalErrorInFunction
<< "No surfaces specified/found for entry: "
<< iter().keyword() << exit(FatalError);
}
// DebugVar(loader.available());
// DebugVar(outputName);
Info<< "Surfaces : "; Info<< "Surfaces : ";
if (surfFileNames.size() == 1) if (loader.selected().size() == 1)
{ {
Info<< surfFileNames[0] << nl; Info<< loader.selected()[0] << nl;
} }
else else
{ {
Info<< flatOutput(surfFileNames) << nl; Info<< flatOutput(loader.selected()) << nl;
}
Info<< "Output : " << outputName << nl;
// Load a single file, or load and combine multiple selected files
autoPtr<triSurface> surfPtr = loader.load();
if (!surfPtr.valid() || surfPtr().empty())
{
FatalErrorInFunction
<< "Problem loading surface(s) for entry: "
<< iter().keyword() << exit(FatalError);
} }
Info<< "Output : " << sFeatFileName << nl; triSurface surf = surfPtr();
const Switch writeVTK = surfaceDict.lookupOrDefault<Switch> const Switch writeVTK = surfaceDict.lookupOrDefault<Switch>
( (
"writeVTK", Switch::OFF "writeVTK",
Switch::OFF
); );
const Switch writeObj = surfaceDict.lookupOrDefault<Switch> const Switch writeObj = surfaceDict.lookupOrDefault<Switch>
( (
"writeObj", Switch::OFF "writeObj",
); Switch::OFF
const Switch curvature = surfaceDict.lookupOrDefault<Switch>
(
"curvature", Switch::OFF
);
const Switch featureProximity = surfaceDict.lookupOrDefault<Switch>
(
"featureProximity", Switch::OFF
);
const Switch closeness = surfaceDict.lookupOrDefault<Switch>
(
"closeness", Switch::OFF
); );
Info<< "write VTK: " << writeVTK << nl; Info<< "write VTK: " << writeVTK << nl;
Info<< nl << "Feature line extraction is only valid on closed manifold " Info<< "Feature line extraction is only valid on closed manifold "
<< "surfaces." << endl; << "surfaces." << nl;
Info<< nl << "Statistics:" << nl;
// Read and combine all surfaces into a single one
autoPtr<triSurface> surfPtr = loadSurfaces(runTime, surfFileNames);
triSurface surf = surfPtr();
Info<< "Statistics:" << endl;
surf.writeStats(Info); surf.writeStats(Info);
Info<< endl; Info<< nl;
// need plain faces if outputting VTK format // need plain faces if outputting VTK format
faceList faces; faceList faces;
@ -1097,19 +980,19 @@ int main(int argc, char *argv[])
// Either construct features from surface & featureAngle or read set. // Either construct features from surface & featureAngle or read set.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
autoPtr<surfaceFeatures> set = extract.features(surf); autoPtr<surfaceFeatures> features = extractor().features(surf);
// Trim set // Trim set
// ~~~~~~~~ // ~~~~~~~~
if (surfaceDict.isDict("trimFeatures")) if (surfaceDict.isDict("trimFeatures"))
{ {
dictionary trimDict = surfaceDict.subDict("trimFeatures"); const dictionary& trimDict = surfaceDict.subDict("trimFeatures");
const scalar minLen =
trimDict.lookupOrAddDefault<scalar>("minLen", -GREAT);
const scalar minLen =
trimDict.lookupOrDefault<scalar>("minLen", 0);
const label minElem = const label minElem =
trimDict.lookupOrAddDefault<label>("minElem", 0); trimDict.lookupOrDefault<label>("minElem", 0);
// Trim away small groups of features // Trim away small groups of features
if (minLen > 0 || minElem > 0) if (minLen > 0 || minElem > 0)
@ -1125,7 +1008,10 @@ int main(int argc, char *argv[])
<< minElem << endl; << minElem << endl;
} }
set().trimFeatures(minLen, minElem, extract.includedAngle()); features().trimFeatures
(
minLen, minElem, extractor().includedAngle()
);
} }
} }
@ -1134,8 +1020,9 @@ int main(int argc, char *argv[])
// ~~~~~~ // ~~~~~~
// Convert to marked edges, points // Convert to marked edges, points
List<surfaceFeatures::edgeStatus> edgeStat(set().toStatus()); List<surfaceFeatures::edgeStatus> edgeStat(features().toStatus());
// Option: "subsetFeatures" (dictionary)
if (surfaceDict.isDict("subsetFeatures")) if (surfaceDict.isDict("subsetFeatures"))
{ {
const dictionary& subsetDict = surfaceDict.subDict const dictionary& subsetDict = surfaceDict.subDict
@ -1143,6 +1030,7 @@ int main(int argc, char *argv[])
"subsetFeatures" "subsetFeatures"
); );
// Suboption: "insideBox"
if (subsetDict.found("insideBox")) if (subsetDict.found("insideBox"))
{ {
treeBoundBox bb(subsetDict.lookup("insideBox")()); treeBoundBox bb(subsetDict.lookup("insideBox")());
@ -1152,6 +1040,7 @@ int main(int argc, char *argv[])
deleteBox(surf, bb, false, edgeStat); deleteBox(surf, bb, false, edgeStat);
} }
// Suboption: "outsideBox"
else if (subsetDict.found("outsideBox")) else if (subsetDict.found("outsideBox"))
{ {
treeBoundBox bb(subsetDict.lookup("outsideBox")()); treeBoundBox bb(subsetDict.lookup("outsideBox")());
@ -1186,17 +1075,15 @@ int main(int argc, char *argv[])
( (
surf, surf,
1e-5, //tol, 1e-5, //tol,
extract.includedAngle(), extractor().includedAngle(),
edgeI edgeI
); );
} }
} }
} }
const Switch openEdges = // Suboption: "openEdges" (false: remove open edges)
subsetDict.lookupOrDefault<Switch>("openEdges", "yes"); if (!subsetDict.lookupOrDefault<bool>("openEdges", true))
if (!openEdges)
{ {
Info<< "Removing all open edges" Info<< "Removing all open edges"
<< " (edges with 1 connected face)" << endl; << " (edges with 1 connected face)" << endl;
@ -1210,6 +1097,7 @@ int main(int argc, char *argv[])
} }
} }
// Suboption: "plane"
if (subsetDict.found("plane")) if (subsetDict.found("plane"))
{ {
plane cutPlane(subsetDict.lookup("plane")()); plane cutPlane(subsetDict.lookup("plane")());
@ -1225,7 +1113,7 @@ int main(int argc, char *argv[])
surfaceFeatures newSet(surf); surfaceFeatures newSet(surf);
newSet.setFromStatus(edgeStat, extract.includedAngle()); newSet.setFromStatus(edgeStat, extractor().includedAngle());
Info<< nl Info<< nl
<< "Initial feature set:" << nl << "Initial feature set:" << nl
@ -1263,7 +1151,7 @@ int main(int argc, char *argv[])
( (
newSet, newSet,
runTime, runTime,
sFeatFileName + ".extendedFeatureEdgeMesh", outputName + ".extendedFeatureEdgeMesh",
surfBaffleRegions surfBaffleRegions
); );
@ -1292,40 +1180,41 @@ int main(int argc, char *argv[])
feMesh.add(addFeMesh); feMesh.add(addFeMesh);
} }
if (surfaceDict.lookupOrDefault<bool>("selfIntersection", false)) if (surfaceDict.lookupOrDefault<bool>("selfIntersection", false))
{ {
// TODO: perturb tolerance // TODO: perturbance tolerance?
triSurfaceSearch query(surf); triSurfaceSearch query(surf);
surfaceIntersection intersect surfaceIntersection intersect(query, surfaceDict);
intersect.mergePoints(5*SMALL);
labelPair sizeInfo
( (
query, intersect.cutPoints().size(),
surfaceDict.lookupOrDefault<scalar> intersect.cutEdges().size()
(
"planarTolerance",
surfaceIntersection::defaultTolerance
)
); );
// surf.write("selfIntersection-input.obj");
Info<<"self-intersection "
<< intersect.cutEdges().size() << " edges "
<< intersect.cutPoints().size() << " points" << nl;
if (intersect.cutEdges().size()) if (intersect.cutEdges().size())
{ {
extendedEdgeMesh addMesh extendedEdgeMesh addMesh
( (
xferCopy<pointField>(intersect.cutPoints()), intersect.cutPoints(),
xferCopy<edgeList>(intersect.cutEdges()) intersect.cutEdges()
); );
addMesh.mergePoints(5*SMALL);
feMesh.add(addMesh); feMesh.add(addMesh);
sizeInfo[0] = addMesh.points().size();
sizeInfo[1] = addMesh.edges().size();
} }
Info<< "Self intersection:" << nl
<< " points : " << sizeInfo[0] << nl
<< " edges : " << sizeInfo[1] << nl;
} }
Info<< nl Info<< nl
<< "Final feature set:" << nl; << "Final feature set:" << nl;
writeStats(feMesh, Info); writeStats(feMesh, Info);
@ -1337,111 +1226,47 @@ int main(int argc, char *argv[])
if (writeObj) if (writeObj)
{ {
feMesh.writeObj(feMesh.path()/sFeatFileName); feMesh.writeObj(feMesh.path()/outputName);
} }
feMesh.write(); feMesh.write();
// Write a featureEdgeMesh for backwards compatibility // Write a featureEdgeMesh for backwards compatibility
featureEdgeMesh bfeMesh if (true)
( {
IOobject featureEdgeMesh bfeMesh
( (
sFeatFileName + ".eMesh", // name IOobject
runTime.constant(), // instance (
"triSurface", outputName + ".eMesh", // name
runTime, // registry runTime.constant(), // instance
IOobject::NO_READ, "triSurface",
IOobject::AUTO_WRITE, runTime, // registry
false IOobject::NO_READ,
), IOobject::AUTO_WRITE,
feMesh.points(), false
feMesh.edges() ),
); feMesh.points(),
feMesh.edges()
);
Info<< nl << "Writing featureEdgeMesh to " Info<< nl << "Writing featureEdgeMesh to "
<< bfeMesh.objectPath() << endl; << bfeMesh.objectPath() << endl;
bfeMesh.regIOobject::write(); bfeMesh.regIOobject::write();
}
// Find close features // Option: "closeness"
if (surfaceDict.lookupOrDefault<bool>("closeness", false))
// // Dummy trim operation to mark features
// labelList featureEdgeIndexing = newSet.trimFeatures(-GREAT, 0);
// scalarField surfacePtFeatureIndex(surf.points().size(), -1);
// forAll(newSet.featureEdges(), eI)
// {
// const edge& e = surf.edges()[newSet.featureEdges()[eI]];
// surfacePtFeatureIndex[surf.meshPoints()[e.start()]] =
// featureEdgeIndexing[newSet.featureEdges()[eI]];
// surfacePtFeatureIndex[surf.meshPoints()[e.end()]] =
// featureEdgeIndexing[newSet.featureEdges()[eI]];
// }
// if (writeVTK)
// {
// vtkSurfaceWriter().write
// (
// runTime.constant()/"triSurface", // outputDir
// sFeatFileName, // surfaceName
// surf.points(),
// faces,
// "surfacePtFeatureIndex", // fieldName
// surfacePtFeatureIndex,
// true, // isNodeValues
// true // verbose
// );
// }
// Random rndGen(343267);
// treeBoundBox surfBB
// (
// treeBoundBox(searchSurf.bounds()).extend(rndGen, 1e-4)
// );
// surfBB.min() -= Foam::point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
// surfBB.max() += Foam::point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
// indexedOctree<treeDataEdge> ftEdTree
// (
// treeDataEdge
// (
// false,
// surf.edges(),
// surf.localPoints(),
// newSet.featureEdges()
// ),
// surfBB,
// 8, // maxLevel
// 10, // leafsize
// 3.0 // duplicity
// );
// labelList nearPoints = ftEdTree.findBox
// (
// treeBoundBox
// (
// sPt - featureSearchSpan*Foam::vector::one,
// sPt + featureSearchSpan*Foam::vector::one
// )
// );
if (closeness)
{ {
Info<< nl << "Extracting internal and external closeness of " Info<< nl << "Extracting internal and external closeness of "
<< "surface." << endl; << "surface." << endl;
triSurfaceMesh searchSurf triSurfaceMesh searchSurf
( (
IOobject IOobject
( (
sFeatFileName + ".closeness", outputName + ".closeness",
runTime.constant(), runTime.constant(),
"triSurface", "triSurface",
runTime, runTime,
@ -1481,8 +1306,8 @@ int main(int argc, char *argv[])
// Info<< "span " << span << endl; // Info<< "span " << span << endl;
pointField start(searchSurf.faceCentres() - span*normals); const pointField start(searchSurf.faceCentres() - span*normals);
pointField end(searchSurf.faceCentres() + span*normals); const pointField end(searchSurf.faceCentres() + span*normals);
const pointField& faceCentres = searchSurf.faceCentres(); const pointField& faceCentres = searchSurf.faceCentres();
List<List<pointIndexHit>> allHitInfo; List<List<pointIndexHit>> allHitInfo;
@ -1649,7 +1474,7 @@ int main(int argc, char *argv[])
( (
IOobject IOobject
( (
sFeatFileName + ".internalCloseness", outputName + ".internalCloseness",
runTime.constant(), runTime.constant(),
"triSurface", "triSurface",
runTime, runTime,
@ -1667,7 +1492,7 @@ int main(int argc, char *argv[])
( (
IOobject IOobject
( (
sFeatFileName + ".externalCloseness", outputName + ".externalCloseness",
runTime.constant(), runTime.constant(),
"triSurface", "triSurface",
runTime, runTime,
@ -1685,8 +1510,8 @@ int main(int argc, char *argv[])
{ {
vtkSurfaceWriter().write vtkSurfaceWriter().write
( (
runTime.constantPath()/"triSurface",// outputDir vtkOutputDir,
sFeatFileName, // surfaceName outputName,
meshedSurfRef meshedSurfRef
( (
surf.points(), surf.points(),
@ -1700,8 +1525,8 @@ int main(int argc, char *argv[])
vtkSurfaceWriter().write vtkSurfaceWriter().write
( (
runTime.constantPath()/"triSurface",// outputDir vtkOutputDir,
sFeatFileName, // surfaceName outputName,
meshedSurfRef meshedSurfRef
( (
surf.points(), surf.points(),
@ -1715,8 +1540,8 @@ int main(int argc, char *argv[])
} }
} }
// Option: "curvature"
if (curvature) if (surfaceDict.lookupOrDefault<bool>("curvature", false))
{ {
Info<< nl << "Extracting curvature of surface at the points." Info<< nl << "Extracting curvature of surface at the points."
<< endl; << endl;
@ -1726,7 +1551,7 @@ int main(int argc, char *argv[])
triSurfacePointScalarField k = calcCurvature triSurfacePointScalarField k = calcCurvature
( (
sFeatFileName, outputName,
runTime, runTime,
surf, surf,
pointNormals, pointNormals,
@ -1739,8 +1564,8 @@ int main(int argc, char *argv[])
{ {
vtkSurfaceWriter().write vtkSurfaceWriter().write
( (
runTime.constantPath()/"triSurface",// outputDir vtkOutputDir,
sFeatFileName, // surfaceName outputName,
meshedSurfRef meshedSurfRef
( (
surf.points(), surf.points(),
@ -1754,8 +1579,8 @@ int main(int argc, char *argv[])
} }
} }
// Option: "featureProximity"
if (featureProximity) if (surfaceDict.lookupOrDefault<bool>("featureProximity", false))
{ {
Info<< nl << "Extracting proximity of close feature points and " Info<< nl << "Extracting proximity of close feature points and "
<< "edges to the surface" << endl; << "edges to the surface" << endl;
@ -1802,7 +1627,7 @@ int main(int argc, char *argv[])
( (
IOobject IOobject
( (
sFeatFileName + ".featureProximity", outputName + ".featureProximity",
runTime.constant(), runTime.constant(),
"triSurface", "triSurface",
runTime, runTime,
@ -1820,8 +1645,8 @@ int main(int argc, char *argv[])
{ {
vtkSurfaceWriter().write vtkSurfaceWriter().write
( (
runTime.constantPath()/"triSurface",// outputDir vtkOutputDir,
sFeatFileName, // surfaceName outputName,
meshedSurfRef meshedSurfRef
( (
surf.points(), surf.points(),

View File

@ -16,7 +16,7 @@ FoamFile
surface1.stl surface1.stl
{ {
// How to obtain raw features (extractFromFile || extractFromSurface) // How to obtain raw features (extractFromFile | extractFromSurface | none)
extractionMethod extractFromSurface; extractionMethod extractFromSurface;
extractFromSurfaceCoeffs extractFromSurfaceCoeffs
@ -28,19 +28,25 @@ surface1.stl
includedAngle 120; includedAngle 120;
// Do not mark region edges // Do not mark region edges
geometricTestOnly yes; geometricTestOnly yes;
} }
// Generate additional features from self-intersect
selfIntersection false;
// Tolerance for surface intersections
tolerance 1e-3;
// Write options // Write options
// Write features to obj format for postprocessing // Write features to obj format for postprocessing
writeObj yes; writeObj yes;
} }
surface2.nas surface2.nas
{ {
// How to obtain raw features (extractFromFile || extractFromSurface) // How to obtain raw features (extractFromFile | extractFromSurface | none)
extractionMethod extractFromFile; extractionMethod extractFromFile;
extractFromFileCoeffs extractFromFileCoeffs
@ -91,36 +97,42 @@ surface2.nas
} }
// Output the curvature of the surface // Output the curvature of the surface
curvature no; curvature no;
// Output the proximity of feature points and edges to each other // Output the proximity of feature points and edges to each other
featureProximity no; featureProximity no;
// The maximum search distance to use when looking for other feature // The maximum search distance to use when looking for other feature
// points and edges // points and edges
maxFeatureProximity 1; maxFeatureProximity 1;
// Out put the closeness of surface elements to other surface elements. // Out put the closeness of surface elements to other surface elements.
closeness no; closeness no;
// Generate additional features from self-intersect
selfIntersection false;
// Tolerance for surface intersections
tolerance 1e-3;
// Write options // Write options
// Write features to obj format for postprocessing // Write features to obj format for postprocessing
writeObj yes; writeObj yes;
// Write surface proximity and curvature fields to vtk format // Write surface proximity and curvature fields to vtk format
// for postprocessing // for postprocessing
writeVTK no; writeVTK no;
} }
// Handle multiple surfaces // Handle single or multiple surfaces
// //
// - If the dictionary is named 'surfaces', it must also contain a 'surfaces' // - If the dictionary is named 'surfaces', it must also contain a 'surfaces'
// entry (wordRe list). // entry (wordRe list).
// //
// - If other dictionaries may contain a 'surfaces' entry, it will be taken // - If other dictionaries contain a 'surfaces' entry,
// for the input. // it will be taken for the input.
// //
surfaces surfaces
{ {
@ -131,24 +143,30 @@ surfaces
// Base output name (optional) // Base output name (optional)
// output surfaces; // output surfaces;
// Generate features from self-intersect // Generate additional features from self-intersect
selfIntersection true; selfIntersection true;
// Tolerance for self-intersect // Tolerance for surface intersections
planarTolerance 1e-3; tolerance 1e-3;
extractFromSurfaceCoeffs extractFromSurfaceCoeffs
{ {
includedAngle 120; includedAngle 120;
// Do not mark region edges // Do not mark region edges
geometricTestOnly yes; geometricTestOnly yes;
}
extractFromNoneCoeffs
{
includedAngle 120;
} }
// Write options // Write options
// Write features to obj format for postprocessing // Write features to obj format for postprocessing
writeObj yes; writeObj yes;
} }
// ************************************************************************* // // ************************************************************************* //

View File

@ -41,11 +41,19 @@ Description
hit of both faces and an edge is created between the retrieved vertex and hit of both faces and an edge is created between the retrieved vertex and
the new one. the new one.
Note: when doing intersecting itself uses intersection::planarTol() as a Note: when doing intersecting itself uses 'tolerance' as a fraction of
fraction of
current edge length to determine if intersection is a point-touching one current edge length to determine if intersection is a point-touching one
instead of an edge-piercing action. instead of an edge-piercing action.
Some constructors allow a dictionary of intersection controls:
\table
Property | Description | Type | Default value
tolerance | Edge-length tolerance | scalar | 1e-3
allowEdgeHits | Edge-end cuts another edge | bool | true
avoidDuplicates | Reduce the number of duplicate points | bool | true
warnDegenerate | Number of warnings about degenerate edges | label | 0
\endtable
SourceFiles SourceFiles
surfaceIntersection.C surfaceIntersection.C
surfaceIntersectionFuncs.C surfaceIntersectionFuncs.C
@ -75,7 +83,7 @@ class triSurface;
class edgeIntersections; class edgeIntersections;
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class surfaceIntersection Declaration Class surfaceIntersection Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
class surfaceIntersection class surfaceIntersection
@ -91,13 +99,22 @@ class surfaceIntersection
}; };
//- Tolerance for intersections //- Tolerance for intersections
scalar planarTol_; scalar tolerance_;
//- Allow edge-ends to cut another edge.
bool allowEdgeHits_;
//- Avoid creating duplicate cuts near edge ends
bool avoidDuplicates_;
//- Maximum number of warnings about degenerate edges
label warnDegenerate_;
//- Newly introduced points. //- Newly introduced points.
pointField cutPoints_; pointField cutPoints_;
//- Newly introduced edges (are on both surfaces). Reference into //- Newly introduced edges (are on both surfaces).
// cutPoints. // Reference into cutPoints.
edgeList cutEdges_; edgeList cutEdges_;
//- From face on surf1 and face on surf2 to intersection point //- From face on surf1 and face on surf2 to intersection point
@ -116,18 +133,27 @@ class surfaceIntersection
// If multiple cuts:sorted from edge.start to edge.end // If multiple cuts:sorted from edge.start to edge.end
labelListList surf2EdgeCuts_; labelListList surf2EdgeCuts_;
//- Temporary storage to manage edge-edge self-intersections.
HashSet<edge, Hash<edge>> edgeEdgeIntersection_;
//- Temporary storage to manage cuts/intersections from the edge ends
Map<label> edgeEndAsCut_;
// Private Member Functions // Private Member Functions
//- Write point in obj format. //- Adjust intersection options according to the dictionary entries
static void writeOBJ(const point& pt, Ostream& os); void setOptions(const dictionary& dict);
//- Write points in obj format
static void writeOBJ(const List<point>& pts, Ostream& os);
//- Write points and edges in obj format //- Write points and edges in obj format
static void writeOBJ static void writeOBJ
( (
const List<point>&, const List<point>& pts,
const List<edge>&, const List<edge>& edges,
Ostream& Ostream& os
); );
//- Transfer contents of List<DynamicList<..>> to List<List<..>> //- Transfer contents of List<DynamicList<..>> to List<List<..>>
@ -149,9 +175,6 @@ class surfaceIntersection
// to new (-1 if element removed) // to new (-1 if element removed)
static void removeDuplicates(const labelList& map, labelList& labels); static void removeDuplicates(const labelList& map, labelList& labels);
//- Apply map to elements of a labelList
static void inlineRemap(const labelList& map, labelList& elems);
// Remove all duplicate and degenerate elements. Return unique elements // Remove all duplicate and degenerate elements. Return unique elements
// and map from old to new. // and map from old to new.
static edgeList filterEdges(const edgeList&, labelList& map); static edgeList filterEdges(const edgeList&, labelList& map);
@ -159,30 +182,6 @@ class surfaceIntersection
//- Remove all duplicate elements. //- Remove all duplicate elements.
static labelList filterLabels(const labelList& elems, labelList& map); static labelList filterLabels(const labelList& elems, labelList& map);
//- Do some checks if edge and face (resulting from hit)
// should not be considered. Returns true if can be discarded.
static bool excludeEdgeHit
(
const triSurface& surf,
const label edgeI,
const label facei,
const scalar tol
);
////- Given edge (eStart - eEnd) and normal direction construct plane
//// and intersect all edges of hitFace with it.
//// Return the edge and coordinate of hit.
//static pointIndexHit faceEdgeIntersection
//(
// const triSurface&,
// const label hitFacei,
//
// const vector& n,
// const point& eStart,
// const point& eEnd
//);
//- Debugging: Dump intersected edges to stream //- Debugging: Dump intersected edges to stream
void writeIntersectedEdges void writeIntersectedEdges
( (
@ -199,7 +198,7 @@ class surfaceIntersection
const scalar endTol, const scalar endTol,
const point& p, const point& p,
const edge& e, const edge& e,
const pointField& points const UList<point>& points
); );
//- Update reference between faceA and faceB. Updates facePairToVertex_ //- Update reference between faceA and faceB. Updates facePairToVertex_
@ -209,8 +208,9 @@ class surfaceIntersection
const enum originatingType cutFrom, const enum originatingType cutFrom,
const labelList& facesA, const labelList& facesA,
const label faceB, const label faceB,
DynamicList<edge>&, const UList<point>& allCutPoints,
DynamicList<point>& const label cutPointId,
DynamicList<edge>& allCutEdges
); );
//- Investigate pHit to whether is case of point hits point, //- Investigate pHit to whether is case of point hits point,
@ -224,8 +224,8 @@ class surfaceIntersection
const label edgeI, const label edgeI,
const pointIndexHit& pHit, const pointIndexHit& pHit,
DynamicList<edge>& allCutEdges,
DynamicList<point>& allCutPoints, DynamicList<point>& allCutPoints,
DynamicList<edge>& allCutEdges,
List<DynamicList<label>>& surfEdgeCuts List<DynamicList<label>>& surfEdgeCuts
); );
@ -236,8 +236,8 @@ class surfaceIntersection
const triSurfaceSearch& querySurf2, const triSurfaceSearch& querySurf2,
const enum originatingType cutFrom, const enum originatingType cutFrom,
DynamicList<edge>& allCutEdges,
DynamicList<point>& allCutPoints, DynamicList<point>& allCutPoints,
DynamicList<edge>& allCutEdges,
List<DynamicList<label>>& surfEdgeCuts List<DynamicList<label>>& surfEdgeCuts
); );
@ -246,9 +246,6 @@ public:
// Public Data, Declarations // Public Data, Declarations
//- The default planarTol for intersections.
static const scalar defaultTolerance;
ClassName("surfaceIntersection"); ClassName("surfaceIntersection");
@ -263,7 +260,7 @@ public:
( (
const triSurfaceSearch& querySurf1, const triSurfaceSearch& querySurf1,
const triSurfaceSearch& querySurf2, const triSurfaceSearch& querySurf2,
const scalar planarTol = surfaceIntersection::defaultTolerance const dictionary& dict = dictionary::null
); );
//- Construct from self-intersections. //- Construct from self-intersections.
@ -271,7 +268,7 @@ public:
surfaceIntersection surfaceIntersection
( (
const triSurfaceSearch& querySurf1, const triSurfaceSearch& querySurf1,
const scalar planarTol = surfaceIntersection::defaultTolerance const dictionary& dict = dictionary::null
); );
//- Construct from precalculated intersection information. //- Construct from precalculated intersection information.
@ -288,21 +285,33 @@ public:
// Member Functions // Member Functions
//- The list of cut points
const pointField& cutPoints() const; const pointField& cutPoints() const;
//- The list of created edges
const edgeList& cutEdges() const; const edgeList& cutEdges() const;
const labelPairLookup& facePairToVertex() const; //- Lookup of pairs of faces to created edges
const labelPairLookup& facePairToEdge() const; const labelPairLookup& facePairToEdge() const;
//- Access either surf1EdgeCuts (isFirstSurface = true) or //- Access either surf1EdgeCuts (isFirstSurface = true) or
// surf2EdgeCuts // surf2EdgeCuts
const labelListList& edgeCuts(const bool isFirstSurf) const; const labelListList& edgeCuts(const bool isFirstSurf) const;
//- List of cut points on edges of surface1
const labelListList& surf1EdgeCuts() const; const labelListList& surf1EdgeCuts() const;
//- List of cut points on edges of surface2
const labelListList& surf2EdgeCuts() const; const labelListList& surf2EdgeCuts() const;
//- Geometric merge points (points within mergeDist) prior to
// automatically calling mergeEdges().
void mergePoints(const scalar mergeDist);
//- Merge duplicate edges
void mergeEdges();
}; };

View File

@ -24,19 +24,24 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "surfaceIntersection.H" #include "surfaceIntersection.H"
#include "triSurface.H"
#include "triSurfaceSearch.H" #include "triSurfaceSearch.H"
#include "labelPairHashes.H" #include "labelPairHashes.H"
#include "OFstream.H" #include "OFstream.H"
#include "HashSet.H"
#include "triSurface.H"
#include "pointIndexHit.H"
#include "meshTools.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::surfaceIntersection::writeOBJ(const point& pt, Ostream& os) void Foam::surfaceIntersection::writeOBJ
(
const List<point>& pts,
Ostream& os
)
{ {
os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl; forAll(pts, i)
{
const point& pt = pts[i];
os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
}
} }
@ -47,15 +52,13 @@ void Foam::surfaceIntersection::writeOBJ
Ostream& os Ostream& os
) )
{ {
forAll(pts, i) writeOBJ(pts, os);
{
writeOBJ(pts[i], os);
}
forAll(edges, i) forAll(edges, i)
{ {
const edge& e = edges[i]; const edge& e = edges[i];
os << "l " << e.start()+1 << ' ' << e.end()+1 << endl; os << "l " << e.start()+1 << ' ' << e.end()+1 << nl;
} }
} }
@ -162,20 +165,6 @@ void Foam::surfaceIntersection::removeDuplicates
} }
// Remap.
void Foam::surfaceIntersection::inlineRemap
(
const labelList& map,
labelList& elems
)
{
forAll(elems, elemI)
{
elems[elemI] = map[elems[elemI]];
}
}
// Remove all duplicate and degenerate elements. Return unique elements and // Remove all duplicate and degenerate elements. Return unique elements and
// map from old to new. // map from old to new.
Foam::edgeList Foam::surfaceIntersection::filterEdges Foam::edgeList Foam::surfaceIntersection::filterEdges
@ -265,14 +254,8 @@ void Foam::surfaceIntersection::writeIntersectedEdges
// Dump all points (surface followed by cutPoints) // Dump all points (surface followed by cutPoints)
const pointField& pts = surf.localPoints(); const pointField& pts = surf.localPoints();
forAll(pts, pointi) writeOBJ(pts, os);
{ writeOBJ(cutPoints(), os);
writeOBJ(pts[pointi], os);
}
forAll(cutPoints(), cutPointi)
{
writeOBJ(cutPoints()[cutPointi], os);
}
forAll(edgeCutVerts, edgeI) forAll(edgeCutVerts, edgeI)
{ {
@ -284,16 +267,16 @@ void Foam::surfaceIntersection::writeIntersectedEdges
// Start of original edge to first extra point // Start of original edge to first extra point
os << "l " << e.start()+1 << ' ' os << "l " << e.start()+1 << ' '
<< extraVerts[0] + surf.nPoints() + 1 << endl; << extraVerts[0] + surf.nPoints() + 1 << nl;
for (label i = 1; i < extraVerts.size(); i++) for (label i = 1; i < extraVerts.size(); i++)
{ {
os << "l " << extraVerts[i-1] + surf.nPoints() + 1 << ' ' os << "l " << extraVerts[i-1] + surf.nPoints() + 1 << ' '
<< extraVerts[i] + surf.nPoints() + 1 << endl; << extraVerts[i] + surf.nPoints() + 1 << nl;
} }
os << "l " << extraVerts.last() + surf.nPoints() + 1 os << "l " << extraVerts.last() + surf.nPoints() + 1
<< ' ' << e.end()+1 << endl; << ' ' << e.end()+1 << nl;
} }
} }
} }
@ -306,7 +289,7 @@ Foam::label Foam::surfaceIntersection::classify
const scalar endTol, const scalar endTol,
const point& p, const point& p,
const edge& e, const edge& e,
const pointField& points const UList<point>& points
) )
{ {
if (mag(p - points[e.start()]) < startTol) if (mag(p - points[e.start()]) < startTol)