Skip to content
Snippets Groups Projects
Commit 0e7630fe authored by Mark OLESEN's avatar Mark OLESEN
Browse files

ENH: improved handling of 'unresolved' surface intersections (issue #450)

- the heuristic for matching unresolved intersections is a relatively
  simple matching scheme that seems to be more robust than attempting to walk
  the geometry or the cuts.

- avoid false positives for self intersection
parent da8ea0f2
Branches
Tags
No related merge requests found
Showing
with 382 additions and 295 deletions
EXE_INC = \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/edgeMesh/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/surfMesh/lnInclude \
-I$(LIB_SRC)/triSurface/lnInclude
EXE_LIBS = \
-lfiniteVolume \
-lmeshTools -ledgeMesh
-lmeshTools
......@@ -34,7 +34,7 @@ Description
#include "triSurface.H"
#include "triSurfaceMesh.H"
#include "surfaceIntersection.H"
#include "OFstream.H"
#include "OBJstream.H"
using namespace Foam;
......@@ -172,7 +172,7 @@ int main(int argc, char *argv[])
{
Info<< "surf1-cuts: " << cuts.surf1EdgeCuts() << nl
<< "surf2-cuts: " << cuts.surf2EdgeCuts() << nl
<< "face-pairs: " << cuts.facePairToEdge() << nl
<< "face-pairs: " << cuts.facePairToEdgeId() << nl
<< "edges: " << cuts.cutEdges() << nl;
}
......@@ -198,7 +198,7 @@ int main(int argc, char *argv[])
{
Info<< "surf1-cuts: " << cuts.surf1EdgeCuts() << nl
<< "surf2-cuts: " << cuts.surf2EdgeCuts() << nl
<< "face-pairs: " << cuts.facePairToEdge() << nl
<< "face-pairs: " << cuts.facePairToEdgeId() << nl
<< "edges: " << cuts.cutEdges() << nl;
}
}
......@@ -209,20 +209,7 @@ int main(int argc, char *argv[])
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;
}
OBJstream(outputFile).write(edges, points);
}
Info<< "End\n" << endl;
......
......@@ -99,7 +99,7 @@ typedef CGAL::AABB_face_graph_triangle_primitive
typedef CGAL::AABB_traits<K, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> Tree;
typedef boost::optional<Tree::Intersection_and_primitive_id<Segment>::Type >
typedef boost::optional<Tree::Intersection_and_primitive_id<Segment>::Type>
Segment_intersection;
#endif // NO_CGAL
......@@ -477,7 +477,6 @@ label dupNonManifoldPoints(triSurface& s, labelList& pointMap)
List<labelledTri> newFaces(s);
label nNonManifold = 0;
forAll(pf, pointI)
{
const labelList& pFaces = pf[pointI];
......@@ -1257,10 +1256,10 @@ autoPtr<extendedFeatureEdgeMesh> createEdgeMesh
const triSurface& s1 = surf1;
const triSurface& s2 = surf2;
forAllConstIter(labelPairLookup, inter.facePairToEdge(), iter)
forAllConstIters(inter.facePairToEdgeId(), iter)
{
const label& cutEdgeI = iter();
const labelPair& facePair = iter.key();
const label cutEdgeI = iter.object();
const edge& fE = inter.cutEdges()[cutEdgeI];
......
......@@ -73,7 +73,7 @@ Foam::surfaceFeaturesExtraction::method::New
dictionaryConstructorTable::iterator cstrIter =
dictionaryConstructorTablePtr_->find(methodName);
if (cstrIter == dictionaryConstructorTablePtr_->end())
if (!cstrIter.found())
{
FatalIOErrorInFunction
(
......
......@@ -84,6 +84,8 @@ int main(int argc, char *argv[])
forAllConstIter(dictionary, dict, iter)
{
const word& dictName = iter().keyword();
if (!iter().isDict())
{
continue;
......@@ -106,7 +108,7 @@ int main(int argc, char *argv[])
const word outputName =
fileName
(
surfaceDict.lookupOrDefault<word>("output", iter().keyword())
surfaceDict.lookupOrDefault<word>("output", dictName)
).lessExt();
// The "surfaces" entry is normally optional, but if the sub-dictionary
......@@ -115,7 +117,7 @@ int main(int argc, char *argv[])
// additional switch.
if
(
iter().keyword() == "surfaces" // mandatory
dictName == "surfaces" // mandatory
|| surfaceDict.found("surfaces") // or optional
)
{
......@@ -123,14 +125,14 @@ int main(int argc, char *argv[])
}
else
{
loader.select(iter().keyword());
loader.select(dictName);
}
if (loader.selected().empty())
{
FatalErrorInFunction
<< "No surfaces specified/found for entry: "
<< iter().keyword() << exit(FatalError);
<< dictName << exit(FatalError);
}
// DebugVar(loader.available());
// DebugVar(outputName);
......@@ -153,7 +155,7 @@ int main(int argc, char *argv[])
{
FatalErrorInFunction
<< "Problem loading surface(s) for entry: "
<< iter().keyword() << exit(FatalError);
<< dictName << exit(FatalError);
}
triSurface surf = surfPtr();
......
......@@ -134,7 +134,7 @@ surface2.nas
// - If other dictionaries contain a 'surfaces' entry,
// it will be taken for the input.
//
surfaces
dummyName
{
extractionMethod extractFromSurface;
......@@ -169,4 +169,39 @@ surfaces
writeObj yes;
}
// Handle single or multiple surfaces
//
// - If the dictionary is named 'surfaces', it must also contain a 'surfaces'
// entry (wordRe list).
//
// - If other dictionaries contain a 'surfaces' entry,
// it will be taken for the input.
//
surfaces
{
extractionMethod extractFromNone;
surfaces (surface1.stl surface2.nas);
// Base output name (optional)
// output surfaces;
// Generate additional features from self-intersect
selfIntersection true;
// Tolerance for surface intersections
tolerance 1e-3;
extractFromNoneCoeffs
{
includedAngle 0;
}
// Write options
// Write features to obj format for postprocessing
writeObj yes;
}
// ************************************************************************* //
......@@ -129,8 +129,7 @@ void dumpFaces
const Map<label>& connectedFaces
)
{
Info<< "Dumping connectedFaces as Lightwave .obj file to " << fName
<< "\nThis can be visualized with e.g. javaview (www.javaview.de)\n\n";
Info<< "Dumping connectedFaces as .obj file to " << fName << nl;
OFstream os(fName);
......
......@@ -27,56 +27,37 @@ License
#include "triSurface.H"
#include "surfaceIntersection.H"
#include "meshTools.H"
#include "OFstream.H"
#include "OBJstream.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(edgeSurface, 0);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// Write whole pointField and edges to stream
void Foam::edgeSurface::writeOBJ
(
const pointField& points,
const edgeList& edges,
Ostream& os
)
// file-scope
// Write points in obj format
static void writeObjPoints(const UList<point>& pts, Ostream& os)
{
forAll(points, pointi)
forAll(pts, i)
{
const point& pt = points[pointi];
os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl;
}
forAll(edges, edgeI)
{
const edge& e = edges[edgeI];
os << "l " << e.start()+1 << ' ' << e.end()+1 << endl;
const point& pt = pts[i];
os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
}
}
// Write whole pointField and selected edges to stream
void Foam::edgeSurface::writeOBJ
void writeObjEdges
(
const pointField& points,
const UList<point>& points,
const edgeList& edges,
const labelList& edgeLabels,
Ostream& os
)
{
forAll(points, pointi)
{
const point& pt = points[pointi];
writeObjPoints(points, os);
os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl;
}
forAll(edgeLabels, i)
{
const edge& e = edges[edgeLabels[i]];
......@@ -85,6 +66,10 @@ void Foam::edgeSurface::writeOBJ
}
}
} // End namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// Pointedges in edgeSurface indices only.
void Foam::edgeSurface::calcPointEdges()
......@@ -253,29 +238,16 @@ Foam::edgeSurface::edgeSurface
}
// Add intersection edges to faceEdges
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
forAllConstIter(labelPairLookup, inter.facePairToEdge(), iter)
forAllConstIters(inter.facePairToEdgeId(), iter)
{
// Edge label in intersection
const label edgeI = iter();
// Get the face from the correct surface
const FixedList<label, 2>& twoFaces = iter.key();
// The faceId from the correct surface
const label facei = iter.key()[isFirstSurface ? 0 : 1];
label facei;
if (isFirstSurface)
{
facei = twoFaces[0];
}
else
{
facei = twoFaces[1];
}
// Edge label in intersection
const label edgeI = iter.object();
// Store on face-edge addressing. (note: offset edge)
allFaceEdges[facei].append(edgeI + nSurfaceEdges_);
......@@ -312,18 +284,17 @@ Foam::edgeSurface::edgeSurface
<< " to " << faceFName << endl;
OFstream fStream(faceFName);
writeOBJ(points_, edges_, fEdges, fStream);
writeObjEdges(points_, edges_, fEdges, fStream);
}
}
Pout<< "edgeSurface : Dumping edges to edges.obj" << endl;
OFstream eStream("edges.obj");
writeOBJ(points_, edges_, eStream);
OBJstream("edges.obj").write(edges_, points_);
Pout<< "edgeSurface : Dumping intersectionEdges to"
<< " intersectionEdges.obj" << endl;
OFstream intEdgesStream("intersectionEdges.obj");
OFstream intEdgesStream("intersectionEdges.obj");
labelList edgeLabels(edges_.size() - nSurfaceEdges_);
label i = 0;
......@@ -332,7 +303,7 @@ Foam::edgeSurface::edgeSurface
edgeLabels[i++] = edgeI;
}
writeOBJ(points_, edges_, edgeLabels, intEdgesStream);
writeObjEdges(points_, edges_, edgeLabels, intEdgesStream);
}
}
......
......@@ -93,25 +93,12 @@ private:
//- From face to our edges_
labelListList faceEdges_;
//- Constructed from above: pointEdges
labelListList pointEdges_;
// Private Member Functions
//- Dump edges in obj format
static void writeOBJ(const pointField&, const edgeList&, Ostream&);
//- Dump selected edges in obj format
static void writeOBJ
(
const pointField&,
const edgeList&,
const labelList&,
Ostream&
);
//- Calculate pointEdges
void calcPointEdges();
......
......@@ -50,7 +50,7 @@ Description
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
snap | Snap near end-points | bool | true
warnDegenerate | Number of warnings about degenerate edges | label | 0
\endtable
......@@ -66,11 +66,11 @@ SourceFiles
#include "DynamicList.H"
#include "point.H"
#include "edge.H"
#include "labelPairHashes.H"
#include "typeInfo.H"
#include "edgeHashes.H"
#include "edgeList.H"
#include "labelPairHashes.H"
#include "pointIndexHit.H"
#include "typeInfo.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -82,6 +82,14 @@ class triSurfaceSearch;
class triSurface;
class edgeIntersections;
//- Key is non-commutative pair of labels. Value is commutative pair of labels
typedef LabelPairMap<edge> labelPairEdgeLookup;
//- Map from edge back to all parents (pairs of faces)
typedef EdgeMap<labelPairHashSet> edgelabelPairHashLookup;
/*---------------------------------------------------------------------------*\
Class surfaceIntersection Declaration
\*---------------------------------------------------------------------------*/
......@@ -104,8 +112,8 @@ class surfaceIntersection
//- Allow edge-ends to cut another edge.
bool allowEdgeHits_;
//- Avoid creating duplicate cuts near edge ends
bool avoidDuplicates_;
//- Snap cut points near edge ends (default: true)
bool snapToEnd_;
//- Maximum number of warnings about degenerate edges
label warnDegenerate_;
......@@ -117,27 +125,29 @@ class surfaceIntersection
// Reference into cutPoints.
edgeList cutEdges_;
//- From face on surf1 and face on surf2 to intersection point
// (label in cutPoints)
labelPairLookup facePairToVertex_;
//- From face on surf1 and face on surf2 to intersection edge
labelPairEdgeLookup facePairToEdge_;
//- From face on surf1 and face on surf2 to intersection edgeId
// (label in cutEdges)
labelPairLookup facePairToEdge_;
labelPairLookup facePairToEdgeId_;
//- Edges on surf1 that are cut. From edge on surf1 to label in cutPoint
// If multiple cuts:sorted from edge.start to edge.end
//- Edges on surf1 that are cut.
// From edgeId on surf1 to location in cutPoint
labelListList surf1EdgeCuts_;
//- Edges on surf2 that are cut. From edge on surf2 to label in cutPoint
// If multiple cuts:sorted from edge.start to edge.end
//- Edges on surf2 that are cut.
// From edgeId on surf2 to location in cutPoint
labelListList surf2EdgeCuts_;
//- Temporary storage to manage edge-edge self-intersections.
HashSet<edge, Hash<edge>> edgeEdgeIntersection_;
edgeHashSet edgeEdgeIntersection_;
//- Temporary storage to manage cuts/intersections from the edge ends
Map<label> edgeEndAsCut_;
Map<label> snappedEnds_;
//- Temporary storage
EdgeMap<label> edgeToId_;
// Private Member Functions
......@@ -145,17 +155,6 @@ class surfaceIntersection
//- 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>& pts,
const List<edge>& edges,
Ostream& os
);
//- Transfer contents of List<DynamicList<..>> to List<List<..>>
template<class T>
static void transfer(List<DynamicList<T>>&, List<List<T>>&);
......@@ -201,8 +200,8 @@ class surfaceIntersection
const UList<point>& points
);
//- Update reference between faceA and faceB. Updates facePairToVertex_
// (first occurrence of face pair) and facePairToEdge_ (second occ.)
//- Update reference between faceA and faceB.
// Updates facePairToEdge_ and facePairToEdgeId_ (on the second hit)
void storeIntersection
(
const enum originatingType cutFrom,
......@@ -241,6 +240,9 @@ class surfaceIntersection
List<DynamicList<label>>& surfEdgeCuts
);
//- Join disconnected intersection points
void joinDisconnected(DynamicList<edge>& allCutEdges);
public:
......@@ -292,7 +294,7 @@ public:
const edgeList& cutEdges() const;
//- Lookup of pairs of faces to created edges
const labelPairLookup& facePairToEdge() const;
const labelPairLookup& facePairToEdgeId() const;
//- Access either surf1EdgeCuts (isFirstSurface = true) or
// surf2EdgeCuts
......
......@@ -29,13 +29,14 @@ License
#include "labelPairHashes.H"
#include "OFstream.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
void Foam::surfaceIntersection::writeOBJ
(
const List<point>& pts,
Ostream& os
)
namespace Foam
{
// file-scope
// Write points in obj format
static void writeObjPoints(const UList<point>& pts, Ostream& os)
{
forAll(pts, i)
{
......@@ -44,23 +45,10 @@ void Foam::surfaceIntersection::writeOBJ
}
}
} // End namespace Foam
void Foam::surfaceIntersection::writeOBJ
(
const List<point>& pts,
const List<edge>& edges,
Ostream& os
)
{
writeOBJ(pts, os);
forAll(edges, i)
{
const edge& e = edges[i];
os << "l " << e.start()+1 << ' ' << e.end()+1 << nl;
}
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// Get minimum length of all edges connected to point
......@@ -254,8 +242,8 @@ void Foam::surfaceIntersection::writeIntersectedEdges
// Dump all points (surface followed by cutPoints)
const pointField& pts = surf.localPoints();
writeOBJ(pts, os);
writeOBJ(cutPoints(), os);
writeObjPoints(pts, os);
writeObjPoints(cutPoints(), os);
forAll(edgeCutVerts, edgeI)
{
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment