mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
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:
3
applications/test/surfaceIntersection/Make/files
Normal file
3
applications/test/surfaceIntersection/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
Test-surfaceIntersection.C
|
||||
|
||||
EXE = $(FOAM_USER_APPBIN)/Test-surfaceIntersection
|
||||
9
applications/test/surfaceIntersection/Make/options
Normal file
9
applications/test/surfaceIntersection/Make/options
Normal 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
|
||||
234
applications/test/surfaceIntersection/Test-surfaceIntersection.C
Normal file
234
applications/test/surfaceIntersection/Test-surfaceIntersection.C
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
7
applications/utilities/surface/surfaceFeatureExtract/Allwclean
Executable file
7
applications/utilities/surface/surfaceFeatureExtract/Allwclean
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
cd ${0%/*} || exit 1 # Run from this directory
|
||||
|
||||
wclean libso extractionMethod
|
||||
wclean .
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
9
applications/utilities/surface/surfaceFeatureExtract/Allwmake
Executable file
9
applications/utilities/surface/surfaceFeatureExtract/Allwmake
Executable 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)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
@ -1,6 +1,7 @@
|
||||
method = .
|
||||
$(method)/surfaceFeaturesExtraction.C
|
||||
$(method)/extractFromSurface.C
|
||||
$(method)/extractFromFile.C
|
||||
$(method)/extractFromNone.C
|
||||
$(method)/extractFromSurface.C
|
||||
|
||||
LIB = $(FOAM_LIBBIN)/libsurfaceFeatureExtract
|
||||
|
||||
@ -24,7 +24,6 @@ License
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "extractFromFile.H"
|
||||
#include "ListOps.H"
|
||||
#include "edgeMesh.H"
|
||||
#include "addToRunTimeSelectionTable.H"
|
||||
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -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
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -26,12 +26,6 @@ License
|
||||
#include "extractFromSurface.H"
|
||||
#include "addToRunTimeSelectionTable.H"
|
||||
|
||||
#include "triSurface.H"
|
||||
#include "triSurfaceSearch.H"
|
||||
#include "scalarField.H"
|
||||
#include "edgeIntersections.H"
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
|
||||
@ -56,10 +56,6 @@ class extractFromSurface
|
||||
:
|
||||
public method
|
||||
{
|
||||
|
||||
bool selfIntersection_;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
@ -29,12 +29,17 @@ Group
|
||||
|
||||
Description
|
||||
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:
|
||||
|
||||
"Estimating Curvatures and their Derivatives on Triangle Meshes"
|
||||
by S. Rusinkiewicz
|
||||
The curvature calculation is an implementation of the algorithm from:
|
||||
\verbatim
|
||||
"Estimating Curvatures and their Derivatives on Triangle Meshes"
|
||||
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 "triadField.H"
|
||||
#include "transform.H"
|
||||
#include "triSurfaceLoader.H"
|
||||
|
||||
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
|
||||
(
|
||||
const List<pointIndexHit>& hitList,
|
||||
@ -462,7 +451,7 @@ scalar calcProximityOfFeatureEdges
|
||||
const edge& e2 = efem.edges()[pHit2.index()];
|
||||
|
||||
// Don't refine if the edges are connected to each other
|
||||
if (!edgesConnected(e1, e2))
|
||||
if (!e1.connects(e2))
|
||||
{
|
||||
scalar curDist =
|
||||
mag(pHit1.hitPoint() - pHit2.hitPoint());
|
||||
@ -480,25 +469,12 @@ scalar calcProximityOfFeatureEdges
|
||||
|
||||
void dumpBox(const treeBoundBox& bb, const fileName& fName)
|
||||
{
|
||||
OFstream str(fName);
|
||||
OFstream os(fName);
|
||||
|
||||
Info<< "Dumping bounding box " << bb << " as lines to obj file "
|
||||
<< str.name() << endl;
|
||||
<< os.name() << endl;
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
meshTools::writeOBJ(os, bb);
|
||||
}
|
||||
|
||||
|
||||
@ -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[])
|
||||
{
|
||||
argList::addNote
|
||||
@ -939,25 +859,15 @@ int main(int argc, char *argv[])
|
||||
const word dictName("surfaceFeatureExtractDict");
|
||||
#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;
|
||||
|
||||
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)
|
||||
{
|
||||
if (!iter().isDict())
|
||||
@ -972,115 +882,88 @@ int main(int argc, char *argv[])
|
||||
continue;
|
||||
}
|
||||
|
||||
autoPtr<surfaceFeaturesExtraction::method> extractPtr =
|
||||
autoPtr<surfaceFeaturesExtraction::method> extractor =
|
||||
surfaceFeaturesExtraction::method::New
|
||||
(
|
||||
surfaceDict
|
||||
);
|
||||
|
||||
const surfaceFeaturesExtraction::method& extract = extractPtr();
|
||||
|
||||
// Output name, cleansed of extensions
|
||||
const word sFeatFileName =
|
||||
// The output name, cleansed of extensions
|
||||
// Optional "output" entry, or the dictionary name.
|
||||
const word outputName =
|
||||
fileName
|
||||
(
|
||||
surfaceDict.lookupOrDefault<word>("output", iter().keyword())
|
||||
).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
|
||||
(
|
||||
iter().keyword() == "surfaces" // mandatory
|
||||
|| surfaceDict.found("surfaces") // or optional
|
||||
iter().keyword() == "surfaces" // mandatory
|
||||
|| surfaceDict.found("surfaces") // or optional
|
||||
)
|
||||
{
|
||||
wordReList regexs(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);
|
||||
}
|
||||
loader.select(wordReList(surfaceDict.lookup("surfaces")));
|
||||
}
|
||||
else
|
||||
{
|
||||
surfFileNames.setSize(1);
|
||||
surfFileNames[0] = iter().keyword();
|
||||
|
||||
const fileName file
|
||||
(
|
||||
runTime.constantPath()/"triSurface"/surfFileNames[0]
|
||||
);
|
||||
|
||||
if (!isFile(file))
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "No surface: " << file.name()
|
||||
<< exit(FatalError);
|
||||
}
|
||||
loader.select(iter().keyword());
|
||||
}
|
||||
|
||||
// DebugVar(surfFileNames);
|
||||
// DebugVar(sFeatFileName);
|
||||
if (loader.selected().empty())
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "No surfaces specified/found for entry: "
|
||||
<< iter().keyword() << exit(FatalError);
|
||||
}
|
||||
// DebugVar(loader.available());
|
||||
// DebugVar(outputName);
|
||||
|
||||
|
||||
Info<< "Surfaces : ";
|
||||
if (surfFileNames.size() == 1)
|
||||
if (loader.selected().size() == 1)
|
||||
{
|
||||
Info<< surfFileNames[0] << nl;
|
||||
Info<< loader.selected()[0] << nl;
|
||||
}
|
||||
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>
|
||||
(
|
||||
"writeVTK", Switch::OFF
|
||||
"writeVTK",
|
||||
Switch::OFF
|
||||
);
|
||||
const Switch writeObj = surfaceDict.lookupOrDefault<Switch>
|
||||
(
|
||||
"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
|
||||
"writeObj",
|
||||
Switch::OFF
|
||||
);
|
||||
|
||||
Info<< "write VTK: " << writeVTK << nl;
|
||||
|
||||
Info<< nl << "Feature line extraction is only valid on closed manifold "
|
||||
<< "surfaces." << endl;
|
||||
Info<< "Feature line extraction is only valid on closed manifold "
|
||||
<< "surfaces." << nl;
|
||||
|
||||
|
||||
// Read and combine all surfaces into a single one
|
||||
|
||||
autoPtr<triSurface> surfPtr = loadSurfaces(runTime, surfFileNames);
|
||||
triSurface surf = surfPtr();
|
||||
|
||||
Info<< "Statistics:" << endl;
|
||||
Info<< nl << "Statistics:" << nl;
|
||||
surf.writeStats(Info);
|
||||
Info<< endl;
|
||||
Info<< nl;
|
||||
|
||||
// need plain faces if outputting VTK format
|
||||
faceList faces;
|
||||
@ -1097,19 +980,19 @@ int main(int argc, char *argv[])
|
||||
// Either construct features from surface & featureAngle or read set.
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
autoPtr<surfaceFeatures> set = extract.features(surf);
|
||||
autoPtr<surfaceFeatures> features = extractor().features(surf);
|
||||
|
||||
// Trim set
|
||||
// ~~~~~~~~
|
||||
|
||||
if (surfaceDict.isDict("trimFeatures"))
|
||||
{
|
||||
dictionary trimDict = surfaceDict.subDict("trimFeatures");
|
||||
const scalar minLen =
|
||||
trimDict.lookupOrAddDefault<scalar>("minLen", -GREAT);
|
||||
const dictionary& trimDict = surfaceDict.subDict("trimFeatures");
|
||||
|
||||
const scalar minLen =
|
||||
trimDict.lookupOrDefault<scalar>("minLen", 0);
|
||||
const label minElem =
|
||||
trimDict.lookupOrAddDefault<label>("minElem", 0);
|
||||
trimDict.lookupOrDefault<label>("minElem", 0);
|
||||
|
||||
// Trim away small groups of features
|
||||
if (minLen > 0 || minElem > 0)
|
||||
@ -1125,7 +1008,10 @@ int main(int argc, char *argv[])
|
||||
<< 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
|
||||
List<surfaceFeatures::edgeStatus> edgeStat(set().toStatus());
|
||||
List<surfaceFeatures::edgeStatus> edgeStat(features().toStatus());
|
||||
|
||||
// Option: "subsetFeatures" (dictionary)
|
||||
if (surfaceDict.isDict("subsetFeatures"))
|
||||
{
|
||||
const dictionary& subsetDict = surfaceDict.subDict
|
||||
@ -1143,6 +1030,7 @@ int main(int argc, char *argv[])
|
||||
"subsetFeatures"
|
||||
);
|
||||
|
||||
// Suboption: "insideBox"
|
||||
if (subsetDict.found("insideBox"))
|
||||
{
|
||||
treeBoundBox bb(subsetDict.lookup("insideBox")());
|
||||
@ -1152,6 +1040,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
deleteBox(surf, bb, false, edgeStat);
|
||||
}
|
||||
// Suboption: "outsideBox"
|
||||
else if (subsetDict.found("outsideBox"))
|
||||
{
|
||||
treeBoundBox bb(subsetDict.lookup("outsideBox")());
|
||||
@ -1186,17 +1075,15 @@ int main(int argc, char *argv[])
|
||||
(
|
||||
surf,
|
||||
1e-5, //tol,
|
||||
extract.includedAngle(),
|
||||
extractor().includedAngle(),
|
||||
edgeI
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Switch openEdges =
|
||||
subsetDict.lookupOrDefault<Switch>("openEdges", "yes");
|
||||
|
||||
if (!openEdges)
|
||||
// Suboption: "openEdges" (false: remove open edges)
|
||||
if (!subsetDict.lookupOrDefault<bool>("openEdges", true))
|
||||
{
|
||||
Info<< "Removing all open edges"
|
||||
<< " (edges with 1 connected face)" << endl;
|
||||
@ -1210,6 +1097,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// Suboption: "plane"
|
||||
if (subsetDict.found("plane"))
|
||||
{
|
||||
plane cutPlane(subsetDict.lookup("plane")());
|
||||
@ -1225,7 +1113,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
|
||||
surfaceFeatures newSet(surf);
|
||||
newSet.setFromStatus(edgeStat, extract.includedAngle());
|
||||
newSet.setFromStatus(edgeStat, extractor().includedAngle());
|
||||
|
||||
Info<< nl
|
||||
<< "Initial feature set:" << nl
|
||||
@ -1263,7 +1151,7 @@ int main(int argc, char *argv[])
|
||||
(
|
||||
newSet,
|
||||
runTime,
|
||||
sFeatFileName + ".extendedFeatureEdgeMesh",
|
||||
outputName + ".extendedFeatureEdgeMesh",
|
||||
surfBaffleRegions
|
||||
);
|
||||
|
||||
@ -1292,40 +1180,41 @@ int main(int argc, char *argv[])
|
||||
feMesh.add(addFeMesh);
|
||||
}
|
||||
|
||||
|
||||
if (surfaceDict.lookupOrDefault<bool>("selfIntersection", false))
|
||||
{
|
||||
// TODO: perturb tolerance
|
||||
// TODO: perturbance tolerance?
|
||||
|
||||
triSurfaceSearch query(surf);
|
||||
surfaceIntersection intersect
|
||||
surfaceIntersection intersect(query, surfaceDict);
|
||||
|
||||
intersect.mergePoints(5*SMALL);
|
||||
|
||||
labelPair sizeInfo
|
||||
(
|
||||
query,
|
||||
surfaceDict.lookupOrDefault<scalar>
|
||||
(
|
||||
"planarTolerance",
|
||||
surfaceIntersection::defaultTolerance
|
||||
)
|
||||
intersect.cutPoints().size(),
|
||||
intersect.cutEdges().size()
|
||||
);
|
||||
|
||||
// surf.write("selfIntersection-input.obj");
|
||||
|
||||
Info<<"self-intersection "
|
||||
<< intersect.cutEdges().size() << " edges "
|
||||
<< intersect.cutPoints().size() << " points" << nl;
|
||||
|
||||
if (intersect.cutEdges().size())
|
||||
{
|
||||
extendedEdgeMesh addMesh
|
||||
(
|
||||
xferCopy<pointField>(intersect.cutPoints()),
|
||||
xferCopy<edgeList>(intersect.cutEdges())
|
||||
intersect.cutPoints(),
|
||||
intersect.cutEdges()
|
||||
);
|
||||
|
||||
addMesh.mergePoints(5*SMALL);
|
||||
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
|
||||
<< "Final feature set:" << nl;
|
||||
writeStats(feMesh, Info);
|
||||
@ -1337,111 +1226,47 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (writeObj)
|
||||
{
|
||||
feMesh.writeObj(feMesh.path()/sFeatFileName);
|
||||
feMesh.writeObj(feMesh.path()/outputName);
|
||||
}
|
||||
|
||||
feMesh.write();
|
||||
|
||||
// Write a featureEdgeMesh for backwards compatibility
|
||||
featureEdgeMesh bfeMesh
|
||||
(
|
||||
IOobject
|
||||
if (true)
|
||||
{
|
||||
featureEdgeMesh bfeMesh
|
||||
(
|
||||
sFeatFileName + ".eMesh", // name
|
||||
runTime.constant(), // instance
|
||||
"triSurface",
|
||||
runTime, // registry
|
||||
IOobject::NO_READ,
|
||||
IOobject::AUTO_WRITE,
|
||||
false
|
||||
),
|
||||
feMesh.points(),
|
||||
feMesh.edges()
|
||||
);
|
||||
IOobject
|
||||
(
|
||||
outputName + ".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;
|
||||
Info<< nl << "Writing featureEdgeMesh to "
|
||||
<< bfeMesh.objectPath() << endl;
|
||||
|
||||
bfeMesh.regIOobject::write();
|
||||
bfeMesh.regIOobject::write();
|
||||
}
|
||||
|
||||
// Find close features
|
||||
|
||||
// // 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)
|
||||
// Option: "closeness"
|
||||
if (surfaceDict.lookupOrDefault<bool>("closeness", false))
|
||||
{
|
||||
Info<< nl << "Extracting internal and external closeness of "
|
||||
<< "surface." << endl;
|
||||
|
||||
|
||||
triSurfaceMesh searchSurf
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
sFeatFileName + ".closeness",
|
||||
outputName + ".closeness",
|
||||
runTime.constant(),
|
||||
"triSurface",
|
||||
runTime,
|
||||
@ -1481,8 +1306,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
// Info<< "span " << span << endl;
|
||||
|
||||
pointField start(searchSurf.faceCentres() - span*normals);
|
||||
pointField end(searchSurf.faceCentres() + span*normals);
|
||||
const pointField start(searchSurf.faceCentres() - span*normals);
|
||||
const pointField end(searchSurf.faceCentres() + span*normals);
|
||||
const pointField& faceCentres = searchSurf.faceCentres();
|
||||
|
||||
List<List<pointIndexHit>> allHitInfo;
|
||||
@ -1649,7 +1474,7 @@ int main(int argc, char *argv[])
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
sFeatFileName + ".internalCloseness",
|
||||
outputName + ".internalCloseness",
|
||||
runTime.constant(),
|
||||
"triSurface",
|
||||
runTime,
|
||||
@ -1667,7 +1492,7 @@ int main(int argc, char *argv[])
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
sFeatFileName + ".externalCloseness",
|
||||
outputName + ".externalCloseness",
|
||||
runTime.constant(),
|
||||
"triSurface",
|
||||
runTime,
|
||||
@ -1685,8 +1510,8 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
vtkSurfaceWriter().write
|
||||
(
|
||||
runTime.constantPath()/"triSurface",// outputDir
|
||||
sFeatFileName, // surfaceName
|
||||
vtkOutputDir,
|
||||
outputName,
|
||||
meshedSurfRef
|
||||
(
|
||||
surf.points(),
|
||||
@ -1700,8 +1525,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
vtkSurfaceWriter().write
|
||||
(
|
||||
runTime.constantPath()/"triSurface",// outputDir
|
||||
sFeatFileName, // surfaceName
|
||||
vtkOutputDir,
|
||||
outputName,
|
||||
meshedSurfRef
|
||||
(
|
||||
surf.points(),
|
||||
@ -1715,8 +1540,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (curvature)
|
||||
// Option: "curvature"
|
||||
if (surfaceDict.lookupOrDefault<bool>("curvature", false))
|
||||
{
|
||||
Info<< nl << "Extracting curvature of surface at the points."
|
||||
<< endl;
|
||||
@ -1726,7 +1551,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
triSurfacePointScalarField k = calcCurvature
|
||||
(
|
||||
sFeatFileName,
|
||||
outputName,
|
||||
runTime,
|
||||
surf,
|
||||
pointNormals,
|
||||
@ -1739,8 +1564,8 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
vtkSurfaceWriter().write
|
||||
(
|
||||
runTime.constantPath()/"triSurface",// outputDir
|
||||
sFeatFileName, // surfaceName
|
||||
vtkOutputDir,
|
||||
outputName,
|
||||
meshedSurfRef
|
||||
(
|
||||
surf.points(),
|
||||
@ -1754,8 +1579,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (featureProximity)
|
||||
// Option: "featureProximity"
|
||||
if (surfaceDict.lookupOrDefault<bool>("featureProximity", false))
|
||||
{
|
||||
Info<< nl << "Extracting proximity of close feature points and "
|
||||
<< "edges to the surface" << endl;
|
||||
@ -1802,7 +1627,7 @@ int main(int argc, char *argv[])
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
sFeatFileName + ".featureProximity",
|
||||
outputName + ".featureProximity",
|
||||
runTime.constant(),
|
||||
"triSurface",
|
||||
runTime,
|
||||
@ -1820,8 +1645,8 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
vtkSurfaceWriter().write
|
||||
(
|
||||
runTime.constantPath()/"triSurface",// outputDir
|
||||
sFeatFileName, // surfaceName
|
||||
vtkOutputDir,
|
||||
outputName,
|
||||
meshedSurfRef
|
||||
(
|
||||
surf.points(),
|
||||
|
||||
@ -16,7 +16,7 @@ FoamFile
|
||||
|
||||
surface1.stl
|
||||
{
|
||||
// How to obtain raw features (extractFromFile || extractFromSurface)
|
||||
// How to obtain raw features (extractFromFile | extractFromSurface | none)
|
||||
extractionMethod extractFromSurface;
|
||||
|
||||
extractFromSurfaceCoeffs
|
||||
@ -28,19 +28,25 @@ surface1.stl
|
||||
includedAngle 120;
|
||||
|
||||
// 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 features to obj format for postprocessing
|
||||
writeObj yes;
|
||||
writeObj yes;
|
||||
}
|
||||
|
||||
|
||||
surface2.nas
|
||||
{
|
||||
// How to obtain raw features (extractFromFile || extractFromSurface)
|
||||
// How to obtain raw features (extractFromFile | extractFromSurface | none)
|
||||
extractionMethod extractFromFile;
|
||||
|
||||
extractFromFileCoeffs
|
||||
@ -91,36 +97,42 @@ surface2.nas
|
||||
}
|
||||
|
||||
// Output the curvature of the surface
|
||||
curvature no;
|
||||
curvature no;
|
||||
|
||||
// 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
|
||||
// points and edges
|
||||
maxFeatureProximity 1;
|
||||
maxFeatureProximity 1;
|
||||
|
||||
// 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 features to obj format for postprocessing
|
||||
writeObj yes;
|
||||
writeObj yes;
|
||||
|
||||
// Write surface proximity and curvature fields to vtk format
|
||||
// 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'
|
||||
// entry (wordRe list).
|
||||
//
|
||||
// - If other dictionaries may contain a 'surfaces' entry, it will be taken
|
||||
// for the input.
|
||||
// - If other dictionaries contain a 'surfaces' entry,
|
||||
// it will be taken for the input.
|
||||
//
|
||||
surfaces
|
||||
{
|
||||
@ -131,24 +143,30 @@ surfaces
|
||||
// Base output name (optional)
|
||||
// output surfaces;
|
||||
|
||||
// Generate features from self-intersect
|
||||
// Generate additional features from self-intersect
|
||||
selfIntersection true;
|
||||
|
||||
// Tolerance for self-intersect
|
||||
planarTolerance 1e-3;
|
||||
// Tolerance for surface intersections
|
||||
tolerance 1e-3;
|
||||
|
||||
extractFromSurfaceCoeffs
|
||||
{
|
||||
includedAngle 120;
|
||||
|
||||
// Do not mark region edges
|
||||
geometricTestOnly yes;
|
||||
geometricTestOnly yes;
|
||||
}
|
||||
|
||||
extractFromNoneCoeffs
|
||||
{
|
||||
includedAngle 120;
|
||||
|
||||
}
|
||||
|
||||
// Write options
|
||||
|
||||
// Write features to obj format for postprocessing
|
||||
writeObj yes;
|
||||
writeObj yes;
|
||||
}
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -41,11 +41,19 @@ Description
|
||||
hit of both faces and an edge is created between the retrieved vertex and
|
||||
the new one.
|
||||
|
||||
Note: when doing intersecting itself uses intersection::planarTol() as a
|
||||
fraction of
|
||||
Note: when doing intersecting itself uses 'tolerance' as a fraction of
|
||||
current edge length to determine if intersection is a point-touching one
|
||||
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
|
||||
surfaceIntersection.C
|
||||
surfaceIntersectionFuncs.C
|
||||
@ -75,7 +83,7 @@ class triSurface;
|
||||
class edgeIntersections;
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class surfaceIntersection Declaration
|
||||
Class surfaceIntersection Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class surfaceIntersection
|
||||
@ -91,13 +99,22 @@ class surfaceIntersection
|
||||
};
|
||||
|
||||
//- 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.
|
||||
pointField cutPoints_;
|
||||
|
||||
//- Newly introduced edges (are on both surfaces). Reference into
|
||||
// cutPoints.
|
||||
//- Newly introduced edges (are on both surfaces).
|
||||
// Reference into cutPoints.
|
||||
edgeList cutEdges_;
|
||||
|
||||
//- 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
|
||||
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
|
||||
|
||||
//- Write point in obj format.
|
||||
static void writeOBJ(const point& pt, Ostream& os);
|
||||
//- Adjust intersection options according to the dictionary entries
|
||||
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
|
||||
static void writeOBJ
|
||||
(
|
||||
const List<point>&,
|
||||
const List<edge>&,
|
||||
Ostream&
|
||||
const List<point>& pts,
|
||||
const List<edge>& edges,
|
||||
Ostream& os
|
||||
);
|
||||
|
||||
//- Transfer contents of List<DynamicList<..>> to List<List<..>>
|
||||
@ -149,9 +175,6 @@ class surfaceIntersection
|
||||
// to new (-1 if element removed)
|
||||
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
|
||||
// and map from old to new.
|
||||
static edgeList filterEdges(const edgeList&, labelList& map);
|
||||
@ -159,30 +182,6 @@ class surfaceIntersection
|
||||
//- Remove all duplicate elements.
|
||||
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
|
||||
void writeIntersectedEdges
|
||||
(
|
||||
@ -199,7 +198,7 @@ class surfaceIntersection
|
||||
const scalar endTol,
|
||||
const point& p,
|
||||
const edge& e,
|
||||
const pointField& points
|
||||
const UList<point>& points
|
||||
);
|
||||
|
||||
//- Update reference between faceA and faceB. Updates facePairToVertex_
|
||||
@ -209,8 +208,9 @@ class surfaceIntersection
|
||||
const enum originatingType cutFrom,
|
||||
const labelList& facesA,
|
||||
const label faceB,
|
||||
DynamicList<edge>&,
|
||||
DynamicList<point>&
|
||||
const UList<point>& allCutPoints,
|
||||
const label cutPointId,
|
||||
DynamicList<edge>& allCutEdges
|
||||
);
|
||||
|
||||
//- Investigate pHit to whether is case of point hits point,
|
||||
@ -224,8 +224,8 @@ class surfaceIntersection
|
||||
const label edgeI,
|
||||
const pointIndexHit& pHit,
|
||||
|
||||
DynamicList<edge>& allCutEdges,
|
||||
DynamicList<point>& allCutPoints,
|
||||
DynamicList<edge>& allCutEdges,
|
||||
List<DynamicList<label>>& surfEdgeCuts
|
||||
);
|
||||
|
||||
@ -236,8 +236,8 @@ class surfaceIntersection
|
||||
const triSurfaceSearch& querySurf2,
|
||||
const enum originatingType cutFrom,
|
||||
|
||||
DynamicList<edge>& allCutEdges,
|
||||
DynamicList<point>& allCutPoints,
|
||||
DynamicList<edge>& allCutEdges,
|
||||
List<DynamicList<label>>& surfEdgeCuts
|
||||
);
|
||||
|
||||
@ -246,9 +246,6 @@ public:
|
||||
|
||||
// Public Data, Declarations
|
||||
|
||||
//- The default planarTol for intersections.
|
||||
static const scalar defaultTolerance;
|
||||
|
||||
ClassName("surfaceIntersection");
|
||||
|
||||
|
||||
@ -263,7 +260,7 @@ public:
|
||||
(
|
||||
const triSurfaceSearch& querySurf1,
|
||||
const triSurfaceSearch& querySurf2,
|
||||
const scalar planarTol = surfaceIntersection::defaultTolerance
|
||||
const dictionary& dict = dictionary::null
|
||||
);
|
||||
|
||||
//- Construct from self-intersections.
|
||||
@ -271,7 +268,7 @@ public:
|
||||
surfaceIntersection
|
||||
(
|
||||
const triSurfaceSearch& querySurf1,
|
||||
const scalar planarTol = surfaceIntersection::defaultTolerance
|
||||
const dictionary& dict = dictionary::null
|
||||
);
|
||||
|
||||
//- Construct from precalculated intersection information.
|
||||
@ -288,21 +285,33 @@ public:
|
||||
|
||||
// Member Functions
|
||||
|
||||
//- The list of cut points
|
||||
const pointField& cutPoints() const;
|
||||
|
||||
//- The list of created edges
|
||||
const edgeList& cutEdges() const;
|
||||
|
||||
const labelPairLookup& facePairToVertex() const;
|
||||
|
||||
//- Lookup of pairs of faces to created edges
|
||||
const labelPairLookup& facePairToEdge() const;
|
||||
|
||||
//- Access either surf1EdgeCuts (isFirstSurface = true) or
|
||||
// surf2EdgeCuts
|
||||
const labelListList& edgeCuts(const bool isFirstSurf) const;
|
||||
|
||||
//- List of cut points on edges of surface1
|
||||
const labelListList& surf1EdgeCuts() const;
|
||||
|
||||
//- List of cut points on edges of surface2
|
||||
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();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -24,19 +24,24 @@ License
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "surfaceIntersection.H"
|
||||
#include "triSurface.H"
|
||||
#include "triSurfaceSearch.H"
|
||||
#include "labelPairHashes.H"
|
||||
#include "OFstream.H"
|
||||
#include "HashSet.H"
|
||||
#include "triSurface.H"
|
||||
#include "pointIndexHit.H"
|
||||
#include "meshTools.H"
|
||||
|
||||
// * * * * * * * * * * * * * 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
|
||||
)
|
||||
{
|
||||
forAll(pts, i)
|
||||
{
|
||||
writeOBJ(pts[i], os);
|
||||
}
|
||||
writeOBJ(pts, os);
|
||||
|
||||
forAll(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
|
||||
// map from old to new.
|
||||
Foam::edgeList Foam::surfaceIntersection::filterEdges
|
||||
@ -265,14 +254,8 @@ void Foam::surfaceIntersection::writeIntersectedEdges
|
||||
// Dump all points (surface followed by cutPoints)
|
||||
const pointField& pts = surf.localPoints();
|
||||
|
||||
forAll(pts, pointi)
|
||||
{
|
||||
writeOBJ(pts[pointi], os);
|
||||
}
|
||||
forAll(cutPoints(), cutPointi)
|
||||
{
|
||||
writeOBJ(cutPoints()[cutPointi], os);
|
||||
}
|
||||
writeOBJ(pts, os);
|
||||
writeOBJ(cutPoints(), os);
|
||||
|
||||
forAll(edgeCutVerts, edgeI)
|
||||
{
|
||||
@ -284,16 +267,16 @@ void Foam::surfaceIntersection::writeIntersectedEdges
|
||||
|
||||
// Start of original edge to first extra point
|
||||
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++)
|
||||
{
|
||||
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
|
||||
<< ' ' << e.end()+1 << endl;
|
||||
<< ' ' << e.end()+1 << nl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -306,7 +289,7 @@ Foam::label Foam::surfaceIntersection::classify
|
||||
const scalar endTol,
|
||||
const point& p,
|
||||
const edge& e,
|
||||
const pointField& points
|
||||
const UList<point>& points
|
||||
)
|
||||
{
|
||||
if (mag(p - points[e.start()]) < startTol)
|
||||
|
||||
Reference in New Issue
Block a user