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
This commit is contained in:
Mark Olesen
2017-05-08 14:57:47 +02:00
parent da8ea0f21a
commit 0e7630feca
12 changed files with 384 additions and 297 deletions

View File

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

View File

@ -34,7 +34,7 @@ Description
#include "triSurface.H" #include "triSurface.H"
#include "triSurfaceMesh.H" #include "triSurfaceMesh.H"
#include "surfaceIntersection.H" #include "surfaceIntersection.H"
#include "OFstream.H" #include "OBJstream.H"
using namespace Foam; using namespace Foam;
@ -172,7 +172,7 @@ int main(int argc, char *argv[])
{ {
Info<< "surf1-cuts: " << cuts.surf1EdgeCuts() << nl Info<< "surf1-cuts: " << cuts.surf1EdgeCuts() << nl
<< "surf2-cuts: " << cuts.surf2EdgeCuts() << nl << "surf2-cuts: " << cuts.surf2EdgeCuts() << nl
<< "face-pairs: " << cuts.facePairToEdge() << nl << "face-pairs: " << cuts.facePairToEdgeId() << nl
<< "edges: " << cuts.cutEdges() << nl; << "edges: " << cuts.cutEdges() << nl;
} }
@ -198,7 +198,7 @@ int main(int argc, char *argv[])
{ {
Info<< "surf1-cuts: " << cuts.surf1EdgeCuts() << nl Info<< "surf1-cuts: " << cuts.surf1EdgeCuts() << nl
<< "surf2-cuts: " << cuts.surf2EdgeCuts() << nl << "surf2-cuts: " << cuts.surf2EdgeCuts() << nl
<< "face-pairs: " << cuts.facePairToEdge() << nl << "face-pairs: " << cuts.facePairToEdgeId() << nl
<< "edges: " << cuts.cutEdges() << nl; << "edges: " << cuts.cutEdges() << nl;
} }
} }
@ -209,20 +209,7 @@ int main(int argc, char *argv[])
if (points.size() || edges.size()) if (points.size() || edges.size())
{ {
Info<<"write to " << outputFile << nl; Info<<"write to " << outputFile << nl;
OBJstream(outputFile).write(edges, points);
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; Info<< "End\n" << endl;

View File

@ -99,7 +99,7 @@ typedef CGAL::AABB_face_graph_triangle_primitive
typedef CGAL::AABB_traits<K, Primitive> Traits; typedef CGAL::AABB_traits<K, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> Tree; 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; Segment_intersection;
#endif // NO_CGAL #endif // NO_CGAL
@ -477,7 +477,6 @@ label dupNonManifoldPoints(triSurface& s, labelList& pointMap)
List<labelledTri> newFaces(s); List<labelledTri> newFaces(s);
label nNonManifold = 0; label nNonManifold = 0;
forAll(pf, pointI) forAll(pf, pointI)
{ {
const labelList& pFaces = pf[pointI]; const labelList& pFaces = pf[pointI];
@ -1257,10 +1256,10 @@ autoPtr<extendedFeatureEdgeMesh> createEdgeMesh
const triSurface& s1 = surf1; const triSurface& s1 = surf1;
const triSurface& s2 = surf2; const triSurface& s2 = surf2;
forAllConstIter(labelPairLookup, inter.facePairToEdge(), iter) forAllConstIters(inter.facePairToEdgeId(), iter)
{ {
const label& cutEdgeI = iter();
const labelPair& facePair = iter.key(); const labelPair& facePair = iter.key();
const label cutEdgeI = iter.object();
const edge& fE = inter.cutEdges()[cutEdgeI]; const edge& fE = inter.cutEdges()[cutEdgeI];

View File

@ -73,7 +73,7 @@ Foam::surfaceFeaturesExtraction::method::New
dictionaryConstructorTable::iterator cstrIter = dictionaryConstructorTable::iterator cstrIter =
dictionaryConstructorTablePtr_->find(methodName); dictionaryConstructorTablePtr_->find(methodName);
if (cstrIter == dictionaryConstructorTablePtr_->end()) if (!cstrIter.found())
{ {
FatalIOErrorInFunction FatalIOErrorInFunction
( (

View File

@ -84,6 +84,8 @@ int main(int argc, char *argv[])
forAllConstIter(dictionary, dict, iter) forAllConstIter(dictionary, dict, iter)
{ {
const word& dictName = iter().keyword();
if (!iter().isDict()) if (!iter().isDict())
{ {
continue; continue;
@ -106,7 +108,7 @@ int main(int argc, char *argv[])
const word outputName = const word outputName =
fileName fileName
( (
surfaceDict.lookupOrDefault<word>("output", iter().keyword()) surfaceDict.lookupOrDefault<word>("output", dictName)
).lessExt(); ).lessExt();
// The "surfaces" entry is normally optional, but if the sub-dictionary // The "surfaces" entry is normally optional, but if the sub-dictionary
@ -115,7 +117,7 @@ int main(int argc, char *argv[])
// additional switch. // additional switch.
if if
( (
iter().keyword() == "surfaces" // mandatory dictName == "surfaces" // mandatory
|| surfaceDict.found("surfaces") // or optional || surfaceDict.found("surfaces") // or optional
) )
{ {
@ -123,14 +125,14 @@ int main(int argc, char *argv[])
} }
else else
{ {
loader.select(iter().keyword()); loader.select(dictName);
} }
if (loader.selected().empty()) if (loader.selected().empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "No surfaces specified/found for entry: " << "No surfaces specified/found for entry: "
<< iter().keyword() << exit(FatalError); << dictName << exit(FatalError);
} }
// DebugVar(loader.available()); // DebugVar(loader.available());
// DebugVar(outputName); // DebugVar(outputName);
@ -153,7 +155,7 @@ int main(int argc, char *argv[])
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Problem loading surface(s) for entry: " << "Problem loading surface(s) for entry: "
<< iter().keyword() << exit(FatalError); << dictName << exit(FatalError);
} }
triSurface surf = surfPtr(); triSurface surf = surfPtr();

View File

@ -134,7 +134,7 @@ surface2.nas
// - If other dictionaries contain a 'surfaces' entry, // - If other dictionaries contain a 'surfaces' entry,
// it will be taken for the input. // it will be taken for the input.
// //
surfaces dummyName
{ {
extractionMethod extractFromSurface; extractionMethod extractFromSurface;
@ -169,4 +169,39 @@ surfaces
writeObj yes; 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;
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -129,8 +129,7 @@ void dumpFaces
const Map<label>& connectedFaces const Map<label>& connectedFaces
) )
{ {
Info<< "Dumping connectedFaces as Lightwave .obj file to " << fName Info<< "Dumping connectedFaces as .obj file to " << fName << nl;
<< "\nThis can be visualized with e.g. javaview (www.javaview.de)\n\n";
OFstream os(fName); OFstream os(fName);

View File

@ -27,56 +27,37 @@ License
#include "triSurface.H" #include "triSurface.H"
#include "surfaceIntersection.H" #include "surfaceIntersection.H"
#include "meshTools.H" #include "meshTools.H"
#include "OFstream.H" #include "OBJstream.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam namespace Foam
{ {
defineTypeNameAndDebug(edgeSurface, 0); defineTypeNameAndDebug(edgeSurface, 0);
}
// file-scope
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // Write points in obj format
static void writeObjPoints(const UList<point>& pts, Ostream& os)
// Write whole pointField and edges to stream
void Foam::edgeSurface::writeOBJ
(
const pointField& points,
const edgeList& edges,
Ostream& os
)
{ {
forAll(points, pointi) forAll(pts, i)
{ {
const point& pt = points[pointi]; const point& pt = pts[i];
os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
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;
} }
} }
// Write whole pointField and selected edges to stream // 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 edgeList& edges,
const labelList& edgeLabels, const labelList& edgeLabels,
Ostream& os Ostream& os
) )
{ {
forAll(points, pointi) writeObjPoints(points, os);
{
const point& pt = points[pointi];
os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl;
}
forAll(edgeLabels, i) forAll(edgeLabels, i)
{ {
const edge& e = edges[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. // Pointedges in edgeSurface indices only.
void Foam::edgeSurface::calcPointEdges() void Foam::edgeSurface::calcPointEdges()
@ -253,29 +238,16 @@ Foam::edgeSurface::edgeSurface
} }
// Add intersection edges to faceEdges // Add intersection edges to faceEdges
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
forAllConstIter(labelPairLookup, inter.facePairToEdge(), iter) forAllConstIters(inter.facePairToEdgeId(), iter)
{ {
// The faceId from the correct surface
const label facei = iter.key()[isFirstSurface ? 0 : 1];
// Edge label in intersection // Edge label in intersection
const label edgeI = iter(); const label edgeI = iter.object();
// Get the face from the correct surface
const FixedList<label, 2>& twoFaces = iter.key();
label facei;
if (isFirstSurface)
{
facei = twoFaces[0];
}
else
{
facei = twoFaces[1];
}
// Store on face-edge addressing. (note: offset edge) // Store on face-edge addressing. (note: offset edge)
allFaceEdges[facei].append(edgeI + nSurfaceEdges_); allFaceEdges[facei].append(edgeI + nSurfaceEdges_);
@ -312,18 +284,17 @@ Foam::edgeSurface::edgeSurface
<< " to " << faceFName << endl; << " to " << faceFName << endl;
OFstream fStream(faceFName); OFstream fStream(faceFName);
writeOBJ(points_, edges_, fEdges, fStream); writeObjEdges(points_, edges_, fEdges, fStream);
} }
} }
Pout<< "edgeSurface : Dumping edges to edges.obj" << endl; Pout<< "edgeSurface : Dumping edges to edges.obj" << endl;
OFstream eStream("edges.obj"); OBJstream("edges.obj").write(edges_, points_);
writeOBJ(points_, edges_, eStream);
Pout<< "edgeSurface : Dumping intersectionEdges to" Pout<< "edgeSurface : Dumping intersectionEdges to"
<< " intersectionEdges.obj" << endl; << " intersectionEdges.obj" << endl;
OFstream intEdgesStream("intersectionEdges.obj");
OFstream intEdgesStream("intersectionEdges.obj");
labelList edgeLabels(edges_.size() - nSurfaceEdges_); labelList edgeLabels(edges_.size() - nSurfaceEdges_);
label i = 0; label i = 0;
@ -332,7 +303,7 @@ Foam::edgeSurface::edgeSurface
edgeLabels[i++] = edgeI; edgeLabels[i++] = edgeI;
} }
writeOBJ(points_, edges_, edgeLabels, intEdgesStream); writeObjEdges(points_, edges_, edgeLabels, intEdgesStream);
} }
} }

View File

@ -93,25 +93,12 @@ private:
//- From face to our edges_ //- From face to our edges_
labelListList faceEdges_; labelListList faceEdges_;
//- Constructed from above: pointEdges //- Constructed from above: pointEdges
labelListList pointEdges_; labelListList pointEdges_;
// Private Member Functions // 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 //- Calculate pointEdges
void calcPointEdges(); void calcPointEdges();

View File

@ -25,7 +25,7 @@ License
#include "surfaceIntersection.H" #include "surfaceIntersection.H"
#include "triSurfaceSearch.H" #include "triSurfaceSearch.H"
#include "OFstream.H" #include "OBJstream.H"
#include "labelPairHashes.H" #include "labelPairHashes.H"
#include "triSurface.H" #include "triSurface.H"
#include "pointIndexHit.H" #include "pointIndexHit.H"
@ -47,7 +47,7 @@ void Foam::surfaceIntersection::setOptions(const dictionary& dict)
{ {
dict.readIfPresent("tolerance", tolerance_); dict.readIfPresent("tolerance", tolerance_);
dict.readIfPresent("allowEdgeHits", allowEdgeHits_); dict.readIfPresent("allowEdgeHits", allowEdgeHits_);
dict.readIfPresent("avoidDuplicates", avoidDuplicates_); dict.readIfPresent("snap", snapToEnd_);
dict.readIfPresent("warnDegenerate", warnDegenerate_); dict.readIfPresent("warnDegenerate", warnDegenerate_);
} }
@ -101,42 +101,64 @@ void Foam::surfaceIntersection::storeIntersection
} }
} }
labelPairLookup::const_iterator iter = facePairToVertex_.find(twoFaces);
if (iter == facePairToVertex_.end()) // Get existing edge, or create a null edge (with -1)
edge& thisEdge = facePairToEdge_(twoFaces);
const label pointCount = thisEdge.count();
if (pointCount == 0)
{ {
// New intersection. Store face-face intersection. // First intersection of the faces - record it.
thisEdge.insert(cutPointId);
if (debug & 4) if (debug & 4)
{ {
Pout<< "intersect faces " << twoFaces Pout<< "intersect faces " << twoFaces
<< " point-1: " << cutPointId << " = " << " point-1: " << cutPointId << " = "
<< allCutPoints[cutPointId] << endl; << allCutPoints[cutPointId] << endl;
} }
continue;
facePairToVertex_.insert(twoFaces, cutPointId);
} }
else if (*iter == cutPointId) else if (pointCount == 2)
{ {
// Avoid creating an edge if cutPointId had already been used // This occurs for ugly surfaces with shards that result in multiple
// cuts very near a snapped end point.
if (debug & 4) if (debug & 4)
{ {
Pout<< "intersect faces " << twoFaces Pout<< "suppressed double intersection " << twoFaces
<< " dup-point: " << cutPointId << endl; << thisEdge << endl;
} }
continue;
} }
else
if (thisEdge.insert(cutPointId))
{ {
const label nextEdgeId = allCutEdges.size(); // Second intersection of the faces - this is an edge,
const edge nextEdge(*iter, cutPointId, true); // with special treatment:
// - avoid duplicate points: addressed by the insert() above
// - avoid degenerate lengths
// - avoid duplicate edges - can occur with really dirty geometry
// Second occurrence of surf1-surf2 intersection. if (edgeToId_.found(thisEdge))
// Or rather the face on surf1 intersects a face on
// surface2 twice -> we found edge.
// Check whether perhaps degenerate
if (nextEdge.mag(allCutPoints) < SMALL)
{ {
// Already have this edgeId, but not for this intersection.
thisEdge.sort();
if (facePairToEdge_.insert(twoFaces, thisEdge))
{
if (debug & 4)
{
Pout<< "reuse edge - faces " << twoFaces << " edge#"
<< edgeToId_[thisEdge] << " edge " << thisEdge
<< " = " << thisEdge.line(allCutPoints)
<< endl;
}
}
}
else if (thisEdge.mag(allCutPoints) < SMALL)
{
// Degenerate length
// - eg, end snapping was disabled or somehow failed.
// Don't normally emit warnings, since these also arise for // Don't normally emit warnings, since these also arise for
// manifold connections. For example, // manifold connections. For example,
// //
@ -147,10 +169,6 @@ void Foam::surfaceIntersection::storeIntersection
// //
// The plane is correctly pierced at the '.' by both edge-1 // The plane is correctly pierced at the '.' by both edge-1
// and edge-2, which belong to the same originating face. // and edge-2, which belong to the same originating face.
//
// Unfortunately cannot suppress the second hit either, since
// it might already have been used for another face-pair
// intersection.
// Filter/merge away the extraneous points later. // Filter/merge away the extraneous points later.
if (warnDegenerate_ > 0) if (warnDegenerate_ > 0)
@ -159,31 +177,55 @@ void Foam::surfaceIntersection::storeIntersection
WarningInFunction WarningInFunction
<< "Degenerate edge between faces " << twoFaces << "Degenerate edge between faces " << twoFaces
<< " on 1st/2nd surface with points " << " on 1st/2nd surface with points "
<< nextEdge.line(allCutPoints) << thisEdge.line(allCutPoints)
<< endl; << endl;
} }
else if (debug & 4) else if (debug & 4)
{ {
Pout<< "degenerate edge face-pair " << twoFaces << " " Pout<< "degenerate edge face-pair " << twoFaces << " "
<< *iter << " point " << allCutPoints[*iter] << thisEdge[0] << " point " << allCutPoints[thisEdge[0]]
<< endl; << endl;
} }
// This is a failed edge - undo this second interaction
thisEdge.erase(cutPointId);
} }
else if (facePairToEdge_.insert(twoFaces, nextEdgeId)) else
{ {
// Record complete (line) intersection of two faces // This is a new edge.
const label edgeId = allCutEdges.size();
allCutEdges.append(nextEdge); if (facePairToEdgeId_.insert(twoFaces, edgeId))
if (debug & 4)
{ {
Pout<< "create edge - faces " << twoFaces << " edge#" // Record complete (line) intersection of two faces
<< nextEdgeId << " edge " << nextEdge thisEdge.sort();
<< " = " << nextEdge.line(allCutPoints) edgeToId_.insert(thisEdge, edgeId);
<< endl; allCutEdges.append(thisEdge);
if (debug & 4)
{
Pout<< "create edge - faces " << twoFaces << " edge#"
<< edgeId << " edge " << thisEdge
<< " = " << thisEdge.line(allCutPoints)
<< endl;
}
}
else
{
// Faces already had an intersection
// This should not fail, but for safety.
Info<<"WARN " << twoFaces
<< " already intersected= " << thisEdge << endl;
thisEdge.erase(cutPointId);
} }
} }
} }
else
{
// Duplicate point - usually zero-length edge from snapping
// - can discard this face/face interaction entirely
facePairToEdge_.erase(twoFaces);
}
} }
} }
@ -212,7 +254,7 @@ void Foam::surfaceIntersection::classifyHit
List<DynamicList<label>>& surfEdgeCuts List<DynamicList<label>>& surfEdgeCuts
) )
{ {
const edge& e = surf1.edges()[edgeI]; const edge& e1 = surf1.edges()[edgeI];
const labelList& facesA = surf1.edgeFaces()[edgeI]; const labelList& facesA = surf1.edgeFaces()[edgeI];
@ -233,10 +275,10 @@ void Foam::surfaceIntersection::classifyHit
const label edgeEnd = const label edgeEnd =
classify classify
( (
surf1PointTol[e.start()], surf1PointTol[e1.start()],
surf1PointTol[e.end()], surf1PointTol[e1.end()],
pHit.hitPoint(), pHit.hitPoint(),
e, e1,
surf1Pts surf1Pts
); );
@ -248,8 +290,8 @@ void Foam::surfaceIntersection::classifyHit
if (debug & 2) if (debug & 2)
{ {
Pout<< "hit-type[1] " << pHit.hitPoint() << " is surf1:" Pout<< "hit-type[1] " << pHit.hitPoint() << " is surf1:"
<< " end point of edge[" << edgeI << "] " << e << " end point of edge[" << edgeI << "] " << e1
<< "==" << e.line(surf1Pts) << "==" << e1.line(surf1Pts)
<< " surf2: vertex " << f2[nearLabel] << " surf2: vertex " << f2[nearLabel]
<< " coord:" << surf2Pts[f2[nearLabel]] << " coord:" << surf2Pts[f2[nearLabel]]
<< " - suppressed" << endl; << " - suppressed" << endl;
@ -258,7 +300,6 @@ void Foam::surfaceIntersection::classifyHit
else else
{ {
// 2. Edge hits point. Cut edge with new point. // 2. Edge hits point. Cut edge with new point.
bool cached = false;
label cutPointId = -1; label cutPointId = -1;
const label nearVert = f2[nearLabel]; const label nearVert = f2[nearLabel];
@ -269,22 +310,25 @@ void Foam::surfaceIntersection::classifyHit
{ {
const point& nearPt = surf1Pts[nearVert]; const point& nearPt = surf1Pts[nearVert];
if (mag(pHit.hitPoint() - nearPt) < surf1PointTol[nearVert]) if
(
mag(pHit.hitPoint() - nearPt)
< surf1PointTol[nearVert]
)
{ {
cutPointId = allCutPoints.size(); cutPointId = allCutPoints.size();
if (avoidDuplicates_) if (snapToEnd_)
{ {
if (edgeEndAsCut_.insert(nearVert, cutPointId)) if (snappedEnds_.insert(nearVert, cutPointId))
{ {
// First time with this end-point // Initial snap
allCutPoints.append(nearPt); allCutPoints.append(nearPt);
} }
else else
{ {
// Already seen this end point // Already snapped this point.
cutPointId = edgeEndAsCut_[nearVert]; cutPointId = snappedEnds_[nearVert];
cached = true;
} }
} }
else else
@ -297,11 +341,11 @@ void Foam::surfaceIntersection::classifyHit
if (debug & 2) if (debug & 2)
{ {
Pout<< "hit-type[2] " << pHit.hitPoint() << " is surf1:" Pout<< "hit-type[2] " << pHit.hitPoint() << " is surf1:"
<< " from edge[" << edgeI << "] " << e << " from edge[" << edgeI << "] " << e1
<< " surf2: vertex " << f2[nearLabel] << " surf2: vertex " << f2[nearLabel]
<< " coord:" << surf2Pts[f2[nearLabel]] << " coord:" << surf2Pts[f2[nearLabel]]
<< " - " << " - "
<< (cached ? "cached" : "stored") << endl; << (cutPointId >= 0 ? "snapped" : "stored") << endl;
} }
if (cutPointId == -1) if (cutPointId == -1)
@ -339,7 +383,7 @@ void Foam::surfaceIntersection::classifyHit
const label edge2I = getEdge(surf2, surf2Facei, nearLabel); const label edge2I = getEdge(surf2, surf2Facei, nearLabel);
const edge& e2 = surf2.edges()[edge2I]; const edge& e2 = surf2.edges()[edge2I];
const label nearVert = (edgeEnd == 0 ? e.start() : e.end()); const label nearVert = e1[edgeEnd];
label cutPointId = -1; label cutPointId = -1;
@ -367,22 +411,23 @@ void Foam::surfaceIntersection::classifyHit
if if
( (
mag(pHit.hitPoint() - nearPt) < surf1PointTol[nearVert] mag(pHit.hitPoint() - nearPt)
< surf1PointTol[nearVert]
) )
{ {
cutPointId = allCutPoints.size(); cutPointId = allCutPoints.size();
if (avoidDuplicates_) if (snapToEnd_)
{ {
if (edgeEndAsCut_.insert(nearVert, cutPointId)) if (snappedEnds_.insert(nearVert, cutPointId))
{ {
// First time with this end-point // Initial snap
allCutPoints.append(nearPt); allCutPoints.append(nearPt);
} }
else else
{ {
// Already seen this end point // Already snapped this point.
cutPointId = edgeEndAsCut_[nearVert]; cutPointId = snappedEnds_[nearVert];
handling = 2; // cached handling = 2; // cached
} }
} }
@ -401,8 +446,8 @@ void Foam::surfaceIntersection::classifyHit
if (debug & 2) if (debug & 2)
{ {
Pout<< "hit-type[3] " << pHit.hitPoint() << " is surf1:" Pout<< "hit-type[3] " << pHit.hitPoint() << " is surf1:"
<< " end point of edge[" << edgeI << "] " << e << " end point of edge[" << edgeI << "] " << e1
<< "==" << e.line(surf1Pts) << "==" << e1.line(surf1Pts)
<< " surf2: edge[" << edge2I << "] " << e2 << " surf2: edge[" << edge2I << "] " << e2
<< " coords:" << e2.line(surf2Pts) << " coords:" << e2.line(surf2Pts)
<< " - " << " - "
@ -482,9 +527,9 @@ void Foam::surfaceIntersection::classifyHit
if (edgeEdgeIntersection_.insert(intersect)) if (edgeEdgeIntersection_.insert(intersect))
{ {
handling = 1; handling = 1;
forAll(e, edgepti) forAll(e1, edgepti)
{ {
const label endId = e[edgepti]; const label endId = e1[edgepti];
const point& nearPt = surf1Pts[endId]; const point& nearPt = surf1Pts[endId];
if if
@ -495,9 +540,9 @@ void Foam::surfaceIntersection::classifyHit
{ {
cutPointId = allCutPoints.size(); cutPointId = allCutPoints.size();
if (avoidDuplicates_) if (snapToEnd_)
{ {
if (edgeEndAsCut_.insert(endId, cutPointId)) if (snappedEnds_.insert(endId, cutPointId))
{ {
// First time with this end-point // First time with this end-point
allCutPoints.append(nearPt); allCutPoints.append(nearPt);
@ -505,7 +550,7 @@ void Foam::surfaceIntersection::classifyHit
else else
{ {
// Already seen this end point // Already seen this end point
cutPointId = edgeEndAsCut_[endId]; cutPointId = snappedEnds_[endId];
handling = 2; // cached handling = 2; // cached
} }
} }
@ -524,8 +569,8 @@ void Foam::surfaceIntersection::classifyHit
if (debug & 2) if (debug & 2)
{ {
Pout<< "hit-type[4] " << pHit.hitPoint() << " is surf1:" Pout<< "hit-type[4] " << pHit.hitPoint() << " is surf1:"
<< " from edge[" << edgeI << "] " << e << " from edge[" << edgeI << "] " << e1
<< "==" << e.line(surf1Pts) << "==" << e1.line(surf1Pts)
<< " surf2: edge[" << edge2I << "] " << e2 << " surf2: edge[" << edge2I << "] " << e2
<< " coords:" << e2.line(surf2Pts) << " coords:" << e2.line(surf2Pts)
<< " - " << " - "
@ -549,18 +594,28 @@ void Foam::surfaceIntersection::classifyHit
if (handling) if (handling)
{ {
const vector eVec = e1.unitVec(surf1Pts);
const labelList& facesB = surf2.edgeFaces()[edge2I]; const labelList& facesB = surf2.edgeFaces()[edge2I];
forAll(facesB, faceBI) forAll(facesB, faceBI)
{ {
storeIntersection // Intersecting edge should be non-coplanar with face
if
( (
cutFrom, mag((surf2.faceNormals()[facesB[faceBI]] & eVec))
facesA, > 0.01
facesB[faceBI], )
allCutPoints, {
cutPointId, storeIntersection
allCutEdges (
); cutFrom,
facesA,
facesB[faceBI],
allCutPoints,
cutPointId,
allCutEdges
);
}
} }
} }
} }
@ -577,8 +632,8 @@ void Foam::surfaceIntersection::classifyHit
// Vertex on/near surf2; vertex away from surf2 // Vertex on/near surf2; vertex away from surf2
// otherVert on outside of surf2 // otherVert on outside of surf2
const label nearVert = (edgeEnd == 0 ? e.start() : e.end()); const label nearVert = (edgeEnd == 0 ? e1.start() : e1.end());
const label otherVert = (edgeEnd == 0 ? e.end() : e.start()); const label otherVert = (edgeEnd == 0 ? e1.end() : e1.start());
const point& nearPt = surf1Pts[nearVert]; const point& nearPt = surf1Pts[nearVert];
const point& otherPt = surf1Pts[otherVert]; const point& otherPt = surf1Pts[otherVert];
@ -592,9 +647,9 @@ void Foam::surfaceIntersection::classifyHit
bool cached = false; bool cached = false;
label cutPointId = allCutPoints.size(); label cutPointId = allCutPoints.size();
if (avoidDuplicates_) if (snapToEnd_)
{ {
if (edgeEndAsCut_.insert(nearVert, cutPointId)) if (snappedEnds_.insert(nearVert, cutPointId))
{ {
// First time with this end-point // First time with this end-point
allCutPoints.append(nearPt); allCutPoints.append(nearPt);
@ -602,7 +657,7 @@ void Foam::surfaceIntersection::classifyHit
else else
{ {
// Already seen this end point // Already seen this end point
cutPointId = edgeEndAsCut_[nearVert]; cutPointId = snappedEnds_[nearVert];
cached = true; cached = true;
} }
} }
@ -617,8 +672,8 @@ void Foam::surfaceIntersection::classifyHit
{ {
Pout<< "hit-type[5] " << pHit.hitPoint() Pout<< "hit-type[5] " << pHit.hitPoint()
<< " shifted to " << nearPt << " shifted to " << nearPt
<< " from edge[" << edgeI << "] " << e << " from edge[" << edgeI << "] " << e1
<< "==" << e.line(surf1Pts) << "==" << e1.line(surf1Pts)
<< " hits surf2 face[" << surf2Facei << "]" << " hits surf2 face[" << surf2Facei << "]"
<< " - " << " - "
<< (cached ? "cached" : "stored") << endl; << (cached ? "cached" : "stored") << endl;
@ -640,7 +695,7 @@ void Foam::surfaceIntersection::classifyHit
if (debug & 2) if (debug & 2)
{ {
Pout<< "hit-type[5] " << pHit.hitPoint() Pout<< "hit-type[5] " << pHit.hitPoint()
<< " from edge[" << edgeI << "] " << e << " from edge[" << edgeI << "] " << e1
<< " hits inside of surf2 face[" << surf2Facei << "]" << " hits inside of surf2 face[" << surf2Facei << "]"
<< " - discarded" << endl; << " - discarded" << endl;
} }
@ -652,8 +707,8 @@ void Foam::surfaceIntersection::classifyHit
if (debug & 2) if (debug & 2)
{ {
Pout<< "hit-type[6] " << pHit.hitPoint() Pout<< "hit-type[6] " << pHit.hitPoint()
<< " from edge[" << edgeI << "] " << e << " from edge[" << edgeI << "] " << e1
<< "==" << e.line(surf1Pts) << "==" << e1.line(surf1Pts)
<< " hits surf2 face[" << surf2Facei << "]" << " hits surf2 face[" << surf2Facei << "]"
<< " - stored" << endl; << " - stored" << endl;
} }
@ -680,8 +735,8 @@ void Foam::surfaceIntersection::classifyHit
// Cut all edges of surf1 with surf2. Sets // Cut all edges of surf1 with surf2. Sets
// - cutPoints : coordinates of cutPoints // - cutPoints : coordinates of cutPoints
// - cutEdges : newly created edges between cutPoints // - cutEdges : newly created edges between cutPoints
// - facePairToVertex : hash from face1I and face2I to (first) cutPoint // - facePairToVertex : hash from face1I and face2I to edge
// - facePairToEdge : hash from face1I and face2I to cutEdge // - facePairToEdgeId : hash from face1I and face2I to index in cutEdge
// - surfEdgeCuts : gives for each edge the cutPoints // - surfEdgeCuts : gives for each edge the cutPoints
// (in order from start to end) // (in order from start to end)
// //
@ -716,7 +771,7 @@ void Foam::surfaceIntersection::doCutEdges
// An edge may intersect multiple faces // An edge may intersect multiple faces
// - mask out faces that have already been hit before trying again // - mask out faces that have already been hit before trying again
// - never intersect with faces attached to the edge itself // - never intersect with faces attached to the edge itself
DynamicList<label> maskFaces(8); DynamicList<label> maskFaces(32);
treeDataTriSurface::findAllIntersectOp treeDataTriSurface::findAllIntersectOp
allIntersectOp(searchTree, maskFaces); allIntersectOp(searchTree, maskFaces);
@ -732,8 +787,12 @@ void Foam::surfaceIntersection::doCutEdges
const point ptEnd = const point ptEnd =
surf1Pts[e.end()] + 0.5*surf1PointTol[e.end()]*edgeVec; surf1Pts[e.end()] + 0.5*surf1PointTol[e.end()]*edgeVec;
// Never intersect with faces attached to the edge itself // Never intersect with faces attached directly to the edge itself,
maskFaces = surf1.edgeFaces()[edgeI]; // nor with faces attached to its end points. This mask contains
// some duplicates, but filtering them out is less efficient.
maskFaces = surf1.pointFaces()[e.start()];
maskFaces.append(surf1.pointFaces()[e.end()]);
while (true) while (true)
{ {
pointIndexHit pHit = searchTree.findLine pointIndexHit pHit = searchTree.findLine
@ -833,24 +892,110 @@ void Foam::surfaceIntersection::doCutEdges
// These temporaries are now unneeded: // These temporaries are now unneeded:
edgeEdgeIntersection_.clear(); edgeEdgeIntersection_.clear();
edgeEndAsCut_.clear(); snappedEnds_.clear();
intersection::setPlanarTol(oldTol); intersection::setPlanarTol(oldTol);
} }
void Foam::surfaceIntersection::joinDisconnected
(
DynamicList<edge>& allCutEdges
)
{
// This simple heuristic seems to work just as well (or better) than
// more complicated schemes
//
// For any face/face intersection that only appears once,
// consider which other faces/points are involved and connect between
// those points.
// Just do a simple connect-the-dots?
Pair<Map<labelPairHashSet>> missedFacePoint;
// Stage 1:
// - Extract "faceId -> (faceId, pointId)"
// for all face/face pairs that only have one interaction
forAllConstIters(facePairToEdge_, iter)
{
const labelPair& twoFaces = iter.key();
const edge& e = iter.object();
if (e.count() == 1)
{
// minVertex = -1 (unused), maxVertex = pointId
const label pointId = e.maxVertex();
missedFacePoint[0](twoFaces[0]).insert
(
labelPair(twoFaces[1], pointId)
);
missedFacePoint[1](twoFaces[1]).insert
(
labelPair(twoFaces[0], pointId)
);
}
}
// Stage 2:
// - anything with two cross-interactions could cause a new edge:
edgeHashSet newEdges;
forAll(missedFacePoint, sidei)
{
const auto& mapping = missedFacePoint[sidei];
forAllConstIters(mapping, iter)
{
const auto& connect = iter.object();
if (connect.size() == 2)
{
// exactly two face/face cross-interactions
edge e;
for (const auto& facePoint : connect)
{
e.insert(facePoint.second());
}
e.sort();
// Only consider edges with two unique ends,
// and do not introduce duplicates
if (e.count() == 2 && !edgeToId_.found(e))
{
newEdges.insert(e);
}
}
}
}
label edgeId = allCutEdges.size();
edgeList newEdgesLst = newEdges.sortedToc();
for (const auto& e : newEdgesLst)
{
// Record complete (line) intersection of two faces
allCutEdges.append(e);
edgeToId_.insert(e, edgeId);
++edgeId;
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::surfaceIntersection::surfaceIntersection() Foam::surfaceIntersection::surfaceIntersection()
: :
tolerance_(1e-3), tolerance_(1e-3),
allowEdgeHits_(true), allowEdgeHits_(true),
avoidDuplicates_(true), snapToEnd_(true),
warnDegenerate_(0), warnDegenerate_(0),
cutPoints_(0), cutPoints_(0),
cutEdges_(0), cutEdges_(0),
facePairToVertex_(0),
facePairToEdge_(0), facePairToEdge_(0),
facePairToEdgeId_(0),
surf1EdgeCuts_(0), surf1EdgeCuts_(0),
surf2EdgeCuts_(0) surf2EdgeCuts_(0)
{} {}
@ -865,12 +1010,12 @@ Foam::surfaceIntersection::surfaceIntersection
: :
tolerance_(1e-3), tolerance_(1e-3),
allowEdgeHits_(true), allowEdgeHits_(true),
avoidDuplicates_(true), snapToEnd_(true),
warnDegenerate_(0), warnDegenerate_(0),
cutPoints_(0), cutPoints_(0),
cutEdges_(0), cutEdges_(0),
facePairToVertex_(2*max(query1.surface().size(), query2.surface().size())),
facePairToEdge_(2*max(query1.surface().size(), query2.surface().size())), facePairToEdge_(2*max(query1.surface().size(), query2.surface().size())),
facePairToEdgeId_(2*max(query1.surface().size(), query2.surface().size())),
surf1EdgeCuts_(0), surf1EdgeCuts_(0),
surf2EdgeCuts_(0) surf2EdgeCuts_(0)
{ {
@ -931,6 +1076,9 @@ Foam::surfaceIntersection::surfaceIntersection
edgeCuts2 edgeCuts2
); );
// join disconnected intersection points
joinDisconnected(allCutEdges);
// Transfer to straight label(List)List // Transfer to straight label(List)List
transfer(edgeCuts2, surf2EdgeCuts_); transfer(edgeCuts2, surf2EdgeCuts_);
cutEdges_.transfer(allCutEdges); cutEdges_.transfer(allCutEdges);
@ -946,8 +1094,7 @@ Foam::surfaceIntersection::surfaceIntersection
Pout<< "surfaceIntersection : Writing intersection to intEdges.obj" Pout<< "surfaceIntersection : Writing intersection to intEdges.obj"
<< endl; << endl;
OFstream intStream("intEdges.obj"); OBJstream("intEdges.obj").write(cutEdges_, cutPoints_);
writeOBJ(cutPoints_, cutEdges_, intStream);
// Dump all cut edges to files // Dump all cut edges to files
Pout<< "Dumping cut edges of surface1 to surf1EdgeCuts.obj" << endl; Pout<< "Dumping cut edges of surface1 to surf1EdgeCuts.obj" << endl;
@ -960,9 +1107,9 @@ Foam::surfaceIntersection::surfaceIntersection
} }
// Temporaries // Temporaries
facePairToVertex_.clear(); facePairToEdge_.clear();
// // Cleanup any duplicate cuts? // Cleanup any duplicate cuts?
// mergeEdges(); // mergeEdges();
} }
@ -975,12 +1122,12 @@ Foam::surfaceIntersection::surfaceIntersection
: :
tolerance_(1e-3), tolerance_(1e-3),
allowEdgeHits_(true), allowEdgeHits_(true),
avoidDuplicates_(true), snapToEnd_(true),
warnDegenerate_(0), warnDegenerate_(0),
cutPoints_(0), cutPoints_(0),
cutEdges_(0), cutEdges_(0),
facePairToVertex_(2*query1.surface().size()),
facePairToEdge_(2*query1.surface().size()), facePairToEdge_(2*query1.surface().size()),
facePairToEdgeId_(2*query1.surface().size()),
surf1EdgeCuts_(0), surf1EdgeCuts_(0),
surf2EdgeCuts_(0) surf2EdgeCuts_(0)
{ {
@ -1013,6 +1160,9 @@ Foam::surfaceIntersection::surfaceIntersection
edgeCuts1 edgeCuts1
); );
// join disconnected intersection points
joinDisconnected(allCutEdges);
// Transfer to straight label(List)List // Transfer to straight label(List)List
transfer(edgeCuts1, surf1EdgeCuts_); transfer(edgeCuts1, surf1EdgeCuts_);
cutEdges_.transfer(allCutEdges); cutEdges_.transfer(allCutEdges);
@ -1039,8 +1189,7 @@ Foam::surfaceIntersection::surfaceIntersection
Pout<< "surfaceIntersection : Writing intersection to intEdges.obj" Pout<< "surfaceIntersection : Writing intersection to intEdges.obj"
<< endl; << endl;
OFstream intStream("intEdges.obj"); OBJstream("intEdges.obj").write(cutEdges_, cutPoints_);
writeOBJ(cutPoints_, cutEdges_, intStream);
// Dump all cut edges to files // Dump all cut edges to files
Pout<< "Dumping cut edges of surface1 to surf1EdgeCuts.obj" << endl; Pout<< "Dumping cut edges of surface1 to surf1EdgeCuts.obj" << endl;
@ -1049,7 +1198,7 @@ Foam::surfaceIntersection::surfaceIntersection
} }
// Temporaries // Temporaries
facePairToVertex_.clear(); facePairToEdge_.clear();
// // Cleanup any duplicate cuts? // // Cleanup any duplicate cuts?
// mergeEdges(); // mergeEdges();
@ -1066,12 +1215,12 @@ Foam::surfaceIntersection::surfaceIntersection
: :
tolerance_(1e-3), tolerance_(1e-3),
allowEdgeHits_(true), allowEdgeHits_(true),
avoidDuplicates_(true), snapToEnd_(true),
warnDegenerate_(0), warnDegenerate_(0),
cutPoints_(0), cutPoints_(0),
cutEdges_(0), cutEdges_(0),
facePairToVertex_(2*max(surf1.size(), surf2.size())),
facePairToEdge_(2*max(surf1.size(), surf2.size())), facePairToEdge_(2*max(surf1.size(), surf2.size())),
facePairToEdgeId_(2*max(surf1.size(), surf2.size())),
surf1EdgeCuts_(0), surf1EdgeCuts_(0),
surf2EdgeCuts_(0) surf2EdgeCuts_(0)
{ {
@ -1180,8 +1329,7 @@ Foam::surfaceIntersection::surfaceIntersection
Pout<< "surfaceIntersection : Writing intersection to intEdges.obj" Pout<< "surfaceIntersection : Writing intersection to intEdges.obj"
<< endl; << endl;
OFstream intStream("intEdges.obj"); OBJstream("intEdges.obj").write(cutEdges_, cutPoints_);
writeOBJ(cutPoints_, cutEdges_, intStream);
// Dump all cut edges to files // Dump all cut edges to files
Pout<< "Dumping cut edges of surface1 to surf1EdgeCuts.obj" << endl; Pout<< "Dumping cut edges of surface1 to surf1EdgeCuts.obj" << endl;
@ -1193,37 +1341,8 @@ Foam::surfaceIntersection::surfaceIntersection
writeIntersectedEdges(surf2, surf2EdgeCuts_, edge2Stream); writeIntersectedEdges(surf2, surf2EdgeCuts_, edge2Stream);
} }
// Debugging stuff
{
// Check all facePairToVertex is used.
labelHashSet usedPoints;
forAllConstIter(labelPairLookup, facePairToEdge_, iter)
{
const label edgeI = iter();
const edge& e = cutEdges_[edgeI];
usedPoints.insert(e[0]);
usedPoints.insert(e[1]);
}
forAllConstIter(labelPairLookup, facePairToVertex_, iter)
{
const label pointi = iter();
if (!usedPoints.found(pointi))
{
WarningInFunction
<< "Problem: cut point:" << pointi
<< " coord:" << cutPoints_[pointi]
<< " not used by any edge" << endl;
}
}
}
// Temporaries // Temporaries
facePairToVertex_.clear(); facePairToEdge_.clear();
// // Cleanup any duplicate cuts? // // Cleanup any duplicate cuts?
// mergeEdges(); // mergeEdges();
@ -1244,9 +1363,9 @@ const Foam::edgeList& Foam::surfaceIntersection::cutEdges() const
} }
const Foam::labelPairLookup& Foam::surfaceIntersection::facePairToEdge() const const Foam::labelPairLookup& Foam::surfaceIntersection::facePairToEdgeId() const
{ {
return facePairToEdge_; return facePairToEdgeId_;
} }
@ -1349,9 +1468,9 @@ void Foam::surfaceIntersection::mergeEdges()
// if (nUniqEdges < cutEdges_.size()) // if (nUniqEdges < cutEdges_.size())
// { // {
// // Additional safety, in case the edge was replaced? // // Additional safety, in case the edge was replaced?
// forAllIter(labelPairLookup, facePairToEdge_, iter) // forAllIters(facePairToEdge_, iter)
// { // {
// iter() = edgeNumbering[iter()]; // iter.object() = edgeNumbering[iter.object()];
// } // }
// } // }

View File

@ -50,7 +50,7 @@ Description
Property | Description | Type | Default value Property | Description | Type | Default value
tolerance | Edge-length tolerance | scalar | 1e-3 tolerance | Edge-length tolerance | scalar | 1e-3
allowEdgeHits | Edge-end cuts another edge | bool | true 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 warnDegenerate | Number of warnings about degenerate edges | label | 0
\endtable \endtable
@ -66,11 +66,11 @@ SourceFiles
#include "DynamicList.H" #include "DynamicList.H"
#include "point.H" #include "point.H"
#include "edge.H" #include "edgeHashes.H"
#include "labelPairHashes.H"
#include "typeInfo.H"
#include "edgeList.H" #include "edgeList.H"
#include "labelPairHashes.H"
#include "pointIndexHit.H" #include "pointIndexHit.H"
#include "typeInfo.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -82,6 +82,14 @@ class triSurfaceSearch;
class triSurface; class triSurface;
class edgeIntersections; 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 Class surfaceIntersection Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -104,8 +112,8 @@ class surfaceIntersection
//- Allow edge-ends to cut another edge. //- Allow edge-ends to cut another edge.
bool allowEdgeHits_; bool allowEdgeHits_;
//- Avoid creating duplicate cuts near edge ends //- Snap cut points near edge ends (default: true)
bool avoidDuplicates_; bool snapToEnd_;
//- Maximum number of warnings about degenerate edges //- Maximum number of warnings about degenerate edges
label warnDegenerate_; label warnDegenerate_;
@ -117,27 +125,29 @@ class surfaceIntersection
// Reference into cutPoints. // Reference into cutPoints.
edgeList cutEdges_; 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 //- From face on surf1 and face on surf2 to intersection edge
// (label in cutEdges) labelPairEdgeLookup facePairToEdge_;
labelPairLookup facePairToEdge_;
//- Edges on surf1 that are cut. From edge on surf1 to label in cutPoint //- From face on surf1 and face on surf2 to intersection edgeId
// If multiple cuts:sorted from edge.start to edge.end // (label in cutEdges)
labelPairLookup facePairToEdgeId_;
//- Edges on surf1 that are cut.
// From edgeId on surf1 to location in cutPoint
labelListList surf1EdgeCuts_; labelListList surf1EdgeCuts_;
//- Edges on surf2 that are cut. From edge on surf2 to label in cutPoint //- Edges on surf2 that are cut.
// If multiple cuts:sorted from edge.start to edge.end // From edgeId on surf2 to location in cutPoint
labelListList surf2EdgeCuts_; labelListList surf2EdgeCuts_;
//- Temporary storage to manage edge-edge self-intersections. //- 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 //- Temporary storage to manage cuts/intersections from the edge ends
Map<label> edgeEndAsCut_; Map<label> snappedEnds_;
//- Temporary storage
EdgeMap<label> edgeToId_;
// Private Member Functions // Private Member Functions
@ -145,17 +155,6 @@ class surfaceIntersection
//- Adjust intersection options according to the dictionary entries //- Adjust intersection options according to the dictionary entries
void setOptions(const dictionary& dict); 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<..>> //- Transfer contents of List<DynamicList<..>> to List<List<..>>
template<class T> template<class T>
static void transfer(List<DynamicList<T>>&, List<List<T>>&); static void transfer(List<DynamicList<T>>&, List<List<T>>&);
@ -201,8 +200,8 @@ class surfaceIntersection
const UList<point>& points const UList<point>& points
); );
//- Update reference between faceA and faceB. Updates facePairToVertex_ //- Update reference between faceA and faceB.
// (first occurrence of face pair) and facePairToEdge_ (second occ.) // Updates facePairToEdge_ and facePairToEdgeId_ (on the second hit)
void storeIntersection void storeIntersection
( (
const enum originatingType cutFrom, const enum originatingType cutFrom,
@ -241,6 +240,9 @@ class surfaceIntersection
List<DynamicList<label>>& surfEdgeCuts List<DynamicList<label>>& surfEdgeCuts
); );
//- Join disconnected intersection points
void joinDisconnected(DynamicList<edge>& allCutEdges);
public: public:
@ -292,7 +294,7 @@ public:
const edgeList& cutEdges() const; const edgeList& cutEdges() const;
//- Lookup of pairs of faces to created edges //- Lookup of pairs of faces to created edges
const labelPairLookup& facePairToEdge() const; const labelPairLookup& facePairToEdgeId() const;
//- Access either surf1EdgeCuts (isFirstSurface = true) or //- Access either surf1EdgeCuts (isFirstSurface = true) or
// surf2EdgeCuts // surf2EdgeCuts

View File

@ -29,13 +29,14 @@ License
#include "labelPairHashes.H" #include "labelPairHashes.H"
#include "OFstream.H" #include "OFstream.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
void Foam::surfaceIntersection::writeOBJ namespace Foam
( {
const List<point>& pts,
Ostream& os // file-scope
) // Write points in obj format
static void writeObjPoints(const UList<point>& pts, Ostream& os)
{ {
forAll(pts, i) 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) // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
{
const edge& e = edges[i];
os << "l " << e.start()+1 << ' ' << e.end()+1 << nl;
}
}
// Get minimum length of all edges connected to point // Get minimum length of all edges connected to point
@ -254,8 +242,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();
writeOBJ(pts, os); writeObjPoints(pts, os);
writeOBJ(cutPoints(), os); writeObjPoints(cutPoints(), os);
forAll(edgeCutVerts, edgeI) forAll(edgeCutVerts, edgeI)
{ {