ENH: region-wise self intersection for surfaceFeatureExtract (issue #450)

This commit is contained in:
Mark Olesen
2017-05-29 18:57:25 +02:00
parent 034ddfa78f
commit dfafe6075a
5 changed files with 168 additions and 50 deletions

View File

@ -83,7 +83,7 @@ Description
#include "edgeIntersections.H" #include "edgeIntersections.H"
#include "meshTools.H" #include "meshTools.H"
#include "DynamicField.H" #include "DynamicField.H"
#include "Enum.H"
#ifndef NO_CGAL #ifndef NO_CGAL
@ -1514,8 +1514,8 @@ int main(int argc, char *argv[])
{ {
argList::noParallel(); argList::noParallel();
argList::validArgs.append("action"); argList::validArgs.append("action");
argList::validArgs.append("surface file"); argList::validArgs.append("surfaceFile1");
argList::validArgs.append("surface file"); argList::validArgs.append("surfaceFile2");
argList::addBoolOption argList::addBoolOption
( (
@ -1553,24 +1553,30 @@ int main(int argc, char *argv[])
" 'mixed' (keep all)" " 'mixed' (keep all)"
); );
argList::addNote
(
"Valid actions: \"intersection\", \"union\", \"difference\""
);
#include "setRootCase.H" #include "setRootCase.H"
#include "createTime.H" #include "createTime.H"
const word action(args[1]); const word action(args[1]);
const HashTable<booleanSurface::booleanOpType> validActions const Enum<booleanSurface::booleanOpType> validActions
{ {
{"intersection", booleanSurface::INTERSECTION}, { booleanSurface::INTERSECTION, "intersection" },
{"union", booleanSurface::UNION}, { booleanSurface::UNION, "union" },
{"difference", booleanSurface::DIFFERENCE} { booleanSurface::DIFFERENCE, "difference" }
}; };
if (!validActions.found(action)) if (!validActions.hasEnum(action))
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Unsupported action " << action << endl << "Unsupported action " << action << endl
<< "Supported actions:" << validActions.toc() << abort(FatalError); << "Supported actions:" << validActions << nl
<< abort(FatalError);
} }

View File

@ -149,8 +149,21 @@ int main(int argc, char *argv[])
} }
Info<< "Output : " << outputName << nl; Info<< "Output : " << outputName << nl;
triSurfaceLoader::loadingOption loadingOption =
triSurfaceLoader::loadingOptionNames.lookupOrDefault
(
"loadingOption",
surfaceDict,
triSurfaceLoader::loadingOption::OFFSET_REGION
);
Info<<"loading with "
<< triSurfaceLoader::loadingOptionNames[loadingOption]
<< endl;
// Load a single file, or load and combine multiple selected files // Load a single file, or load and combine multiple selected files
autoPtr<triSurface> surfPtr = loader.load(); autoPtr<triSurface> surfPtr = loader.load(loadingOption);
if (!surfPtr.valid() || surfPtr().empty()) if (!surfPtr.valid() || surfPtr().empty())
{ {
FatalErrorInFunction FatalErrorInFunction
@ -390,14 +403,21 @@ int main(int argc, char *argv[])
feMesh.add(addFeMesh); feMesh.add(addFeMesh);
} }
if (surfaceDict.lookupOrDefault<bool>("selfIntersection", false)) const surfaceIntersection::intersectionType selfIntersect =
{ surfaceIntersection::selfIntersectionNames.lookupOrDefault
// TODO: perturbance tolerance? (
"intersectionMethod",
surfaceDict,
surfaceIntersection::NONE
);
if (selfIntersect != surfaceIntersection::NONE)
{
triSurfaceSearch query(surf); triSurfaceSearch query(surf);
surfaceIntersection intersect(query, surfaceDict); surfaceIntersection intersect(query, surfaceDict);
intersect.mergePoints(5*SMALL); // Remove rounding noise - could make adjustable
intersect.mergePoints(10*SMALL);
labelPair sizeInfo labelPair sizeInfo
( (
@ -413,14 +433,15 @@ int main(int argc, char *argv[])
intersect.cutEdges() intersect.cutEdges()
); );
addMesh.mergePoints(5*SMALL);
feMesh.add(addMesh); feMesh.add(addMesh);
sizeInfo[0] = addMesh.points().size(); sizeInfo[0] = addMesh.points().size();
sizeInfo[1] = addMesh.edges().size(); sizeInfo[1] = addMesh.edges().size();
} }
Info<< nl Info<< nl
<< "Self intersection:" << nl << "intersection: "
<< surfaceIntersection::selfIntersectionNames[selfIntersect]
<< nl
<< " points : " << sizeInfo[0] << nl << " points : " << sizeInfo[0] << nl
<< " edges : " << sizeInfo[1] << nl; << " edges : " << sizeInfo[1] << nl;
} }

View File

@ -16,7 +16,7 @@ FoamFile
surface1.stl surface1.stl
{ {
// How to obtain raw features (extractFromFile | extractFromSurface | none) // How to obtain raw features (none | extractFromFile | extractFromSurface)
extractionMethod extractFromSurface; extractionMethod extractFromSurface;
// Mark edges whose adjacent surface normals are at an angle less // Mark edges whose adjacent surface normals are at an angle less
@ -36,8 +36,8 @@ surface1.stl
geometricTestOnly yes; geometricTestOnly yes;
} */ } */
// Generate additional features from self-intersect // Generate additional intersection features (none | self | region)
selfIntersection false; intersectionMethod none;
// Tolerance for surface intersections // Tolerance for surface intersections
tolerance 1e-3; tolerance 1e-3;
@ -51,7 +51,7 @@ surface1.stl
surface2.nas surface2.nas
{ {
// How to obtain raw features (extractFromFile | extractFromSurface | none) // How to obtain raw features (none | extractFromFile | extractFromSurface)
extractionMethod extractFromFile; extractionMethod extractFromFile;
extractFromFileCoeffs extractFromFileCoeffs
@ -114,8 +114,8 @@ surface2.nas
// Out put the closeness of surface elements to other surface elements. // Out put the closeness of surface elements to other surface elements.
closeness no; closeness no;
// Generate additional features from self-intersect // Generate additional intersection features (none | self | region)
selfIntersection false; intersectionMethod none;
// Tolerance for surface intersections // Tolerance for surface intersections
tolerance 1e-3; tolerance 1e-3;
@ -148,8 +148,8 @@ dummyName
// Base output name (optional) // Base output name (optional)
// output surfaces; // output surfaces;
// Generate additional features from self-intersect // Generate additional intersection features (none | self | region)
selfIntersection true; intersectionMethod self;
// Tolerance for surface intersections // Tolerance for surface intersections
tolerance 1e-3; tolerance 1e-3;
@ -183,8 +183,8 @@ surfaces
// Base output name (optional) // Base output name (optional)
// output surfaces; // output surfaces;
// Generate additional features from self-intersect // Generate additional intersection features (none | self | region)
selfIntersection true; intersectionMethod self;
// Tolerance for surface intersections // Tolerance for surface intersections
tolerance 1e-3; tolerance 1e-3;
@ -193,8 +193,7 @@ surfaces
noneCoeffs noneCoeffs
{ {
includedAngle 0; includedAngle 0;
} } */
*/
// Write options // Write options

View File

@ -27,6 +27,7 @@ License
#include "triSurfaceSearch.H" #include "triSurfaceSearch.H"
#include "OBJstream.H" #include "OBJstream.H"
#include "labelPairHashes.H" #include "labelPairHashes.H"
#include "PackedBoolList.H"
#include "triSurface.H" #include "triSurface.H"
#include "pointIndexHit.H" #include "pointIndexHit.H"
#include "mergePoints.H" #include "mergePoints.H"
@ -40,6 +41,14 @@ namespace Foam
defineTypeNameAndDebug(surfaceIntersection, 0); defineTypeNameAndDebug(surfaceIntersection, 0);
} }
const Foam::Enum<Foam::surfaceIntersection::intersectionType>
Foam::surfaceIntersection::selfIntersectionNames
{
{ intersectionType::SELF, "self" },
{ intersectionType::SELF_REGION, "region" },
{ intersectionType::NONE, "none" },
};
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
@ -54,7 +63,7 @@ void Foam::surfaceIntersection::setOptions(const dictionary& dict)
void Foam::surfaceIntersection::storeIntersection void Foam::surfaceIntersection::storeIntersection
( (
const enum originatingType cutFrom, const enum intersectionType cutFrom,
const labelList& facesA, const labelList& facesA,
const label faceB, const label faceB,
const UList<point>& allCutPoints, const UList<point>& allCutPoints,
@ -85,6 +94,7 @@ void Foam::surfaceIntersection::storeIntersection
break; break;
} }
case surfaceIntersection::SELF: case surfaceIntersection::SELF:
case surfaceIntersection::SELF_REGION:
{ {
// Lookup should be commutativity - use sorted order // Lookup should be commutativity - use sorted order
if (faceA < faceB) if (faceA < faceB)
@ -99,6 +109,10 @@ void Foam::surfaceIntersection::storeIntersection
} }
break; break;
} }
case surfaceIntersection::NONE:
return;
break;
} }
@ -245,7 +259,7 @@ void Foam::surfaceIntersection::classifyHit
const triSurface& surf1, const triSurface& surf1,
const scalarField& surf1PointTol, const scalarField& surf1PointTol,
const triSurface& surf2, const triSurface& surf2,
const enum originatingType cutFrom, const enum intersectionType cutFrom,
const label edgeI, const label edgeI,
const pointIndexHit& pHit, const pointIndexHit& pHit,
@ -306,7 +320,11 @@ void Foam::surfaceIntersection::classifyHit
// For self-intersection, we have tolerances for each point // For self-intersection, we have tolerances for each point
// (surf2 is actually surf1) so we shift the hit to coincide // (surf2 is actually surf1) so we shift the hit to coincide
// identically. // identically.
if (cutFrom == surfaceIntersection::SELF) if
(
cutFrom == surfaceIntersection::SELF
|| cutFrom == surfaceIntersection::SELF_REGION
)
{ {
const point& nearPt = surf1Pts[nearVert]; const point& nearPt = surf1Pts[nearVert];
@ -392,7 +410,15 @@ void Foam::surfaceIntersection::classifyHit
// >0: store point/edge-cut. Attempt to create new edge. // >0: store point/edge-cut. Attempt to create new edge.
// <0: store point/edge-cut only // <0: store point/edge-cut only
int handling = (allowEdgeHits_ ? 1 : 0); int handling = (allowEdgeHits_ ? 1 : 0);
if (allowEdgeHits_ && cutFrom == surfaceIntersection::SELF) if
(
allowEdgeHits_
&&
(
cutFrom == surfaceIntersection::SELF
|| cutFrom == surfaceIntersection::SELF_REGION
)
)
{ {
// The edge-edge intersection is hashed as an 'edge' to // The edge-edge intersection is hashed as an 'edge' to
// exploit the commutative lookup. // exploit the commutative lookup.
@ -513,12 +539,18 @@ void Foam::surfaceIntersection::classifyHit
switch (cutFrom) switch (cutFrom)
{ {
case surfaceIntersection::FIRST: case surfaceIntersection::FIRST:
{
handling = 1; handling = 1;
break; break;
}
case surfaceIntersection::SECOND: case surfaceIntersection::SECOND:
{
handling = -1; handling = -1;
break; break;
}
case surfaceIntersection::SELF: case surfaceIntersection::SELF:
case surfaceIntersection::SELF_REGION:
{
// The edge-edge intersection is hashed as an 'edge' to // The edge-edge intersection is hashed as an 'edge' to
// exploit the commutative lookup. // exploit the commutative lookup.
// Ie, only do the cut once // Ie, only do the cut once
@ -563,6 +595,12 @@ void Foam::surfaceIntersection::classifyHit
} }
} }
} }
break;
}
case surfaceIntersection::NONE:
return;
break; break;
} }
@ -744,7 +782,7 @@ void Foam::surfaceIntersection::doCutEdges
( (
const triSurface& surf1, const triSurface& surf1,
const triSurfaceSearch& querySurf2, const triSurfaceSearch& querySurf2,
const enum originatingType cutFrom, const enum intersectionType cutFrom,
DynamicList<point>& allCutPoints, DynamicList<point>& allCutPoints,
DynamicList<edge>& allCutEdges, DynamicList<edge>& allCutEdges,
@ -766,13 +804,21 @@ void Foam::surfaceIntersection::doCutEdges
const indexedOctree<treeDataPrimitivePatch<triSurface>>& searchTree const indexedOctree<treeDataPrimitivePatch<triSurface>>& searchTree
= querySurf2.tree(); = querySurf2.tree();
if (cutFrom == surfaceIntersection::SELF) if
(
cutFrom == surfaceIntersection::SELF
|| cutFrom == surfaceIntersection::SELF_REGION
)
{ {
// 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(32); DynamicList<label> maskFaces(32);
// Optionally prevent intersection within a single region.
// Like self-intersect, but only if regions are different
PackedBoolList maskRegions(32);
treeDataTriSurface::findAllIntersectOp treeDataTriSurface::findAllIntersectOp
allIntersectOp(searchTree, maskFaces); allIntersectOp(searchTree, maskFaces);
@ -787,6 +833,15 @@ 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;
maskRegions.clear();
if (cutFrom == surfaceIntersection::SELF_REGION)
{
for (auto& facei : surf1.edgeFaces()[edgeI])
{
maskRegions.set(surf1[facei].region());
}
}
// Never intersect with faces attached directly to the edge itself, // Never intersect with faces attached directly to the edge itself,
// nor with faces attached to its end points. This mask contains // nor with faces attached to its end points. This mask contains
// some duplicates, but filtering them out is less efficient. // some duplicates, but filtering them out is less efficient.
@ -809,6 +864,11 @@ void Foam::surfaceIntersection::doCutEdges
maskFaces.append(pHit.index()); maskFaces.append(pHit.index());
if (maskRegions[surf1[pHit.index()].region()])
{
continue;
}
classifyHit classifyHit
( (
surf1, surf1,
@ -1133,6 +1193,27 @@ Foam::surfaceIntersection::surfaceIntersection
{ {
setOptions(dict); setOptions(dict);
const intersectionType cutFrom = selfIntersectionNames.lookupOrDefault
(
"intersectionMethod",
dict,
intersectionType::SELF
);
if (cutFrom == intersectionType::NONE)
{
if (debug)
{
Pout<< "Skipping self-intersection (selected: none)" << endl;
}
// Temporaries
facePairToEdge_.clear();
facePairToEdgeId_.clear();
return;
}
const triSurface& surf1 = query1.surface(); const triSurface& surf1 = query1.surface();
// //
@ -1154,7 +1235,7 @@ Foam::surfaceIntersection::surfaceIntersection
( (
surf1, surf1,
query1, query1,
surfaceIntersection::SELF, cutFrom,
allCutPoints, allCutPoints,
allCutEdges, allCutEdges,
edgeCuts1 edgeCuts1
@ -1402,17 +1483,16 @@ void Foam::surfaceIntersection::mergePoints(const scalar mergeDist)
pointField newPoints; pointField newPoints;
labelList pointMap; labelList pointMap;
const bool hasMerged = Foam::mergePoints const label nMerged = Foam::mergePoints
( (
cutPoints_, cutPoints_,
mergeDist, mergeDist,
false, false,
pointMap, pointMap,
newPoints, newPoints
vector::zero
); );
if (hasMerged) if (nMerged)
{ {
cutPoints_.transfer(newPoints); cutPoints_.transfer(newPoints);

View File

@ -52,6 +52,7 @@ Description
allowEdgeHits | Edge-end cuts another edge | bool | true allowEdgeHits | Edge-end cuts another edge | bool | true
snap | Snap near end-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
intersectionMethod | Control for self intersection | (self,region,none)
\endtable \endtable
SourceFiles SourceFiles
@ -71,6 +72,7 @@ SourceFiles
#include "labelPairHashes.H" #include "labelPairHashes.H"
#include "pointIndexHit.H" #include "pointIndexHit.H"
#include "typeInfo.H" #include "typeInfo.H"
#include "Enum.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -96,15 +98,25 @@ typedef EdgeMap<labelPairHashSet> edgelabelPairHashLookup;
class surfaceIntersection class surfaceIntersection
{ {
// Private data public:
//- Surface intersection types for classify, doCutEdges //- Surface intersection types for classify, doCutEdges
enum originatingType enum intersectionType
{ {
FIRST, //!< First surface FIRST, //!< First surface
SECOND, //!< Second surface SECOND, //!< Second surface
SELF //!< Self-intersection SELF, //!< Self-intersection
}; SELF_REGION, //!< Self-intersection, region-wise only
NONE //!< None = invalid (for input only)
};
//- The user-selectable self-intersection enumeration names
static const Enum<intersectionType> selfIntersectionNames;
private:
// Private data
//- Tolerance for intersections //- Tolerance for intersections
scalar tolerance_; scalar tolerance_;
@ -204,7 +216,7 @@ class surfaceIntersection
// Updates facePairToEdge_ and facePairToEdgeId_ (on the second hit) // Updates facePairToEdge_ and facePairToEdgeId_ (on the second hit)
void storeIntersection void storeIntersection
( (
const enum originatingType cutFrom, const enum intersectionType cutFrom,
const labelList& facesA, const labelList& facesA,
const label faceB, const label faceB,
const UList<point>& allCutPoints, const UList<point>& allCutPoints,
@ -219,7 +231,7 @@ class surfaceIntersection
const triSurface& surf1, const triSurface& surf1,
const scalarField& surf1PointTol, const scalarField& surf1PointTol,
const triSurface& surf2, const triSurface& surf2,
const enum originatingType cutFrom, const enum intersectionType cutFrom,
const label edgeI, const label edgeI,
const pointIndexHit& pHit, const pointIndexHit& pHit,
@ -233,7 +245,7 @@ class surfaceIntersection
( (
const triSurface& surf1, const triSurface& surf1,
const triSurfaceSearch& querySurf2, const triSurfaceSearch& querySurf2,
const enum originatingType cutFrom, const enum intersectionType cutFrom,
DynamicList<point>& allCutPoints, DynamicList<point>& allCutPoints,
DynamicList<edge>& allCutEdges, DynamicList<edge>& allCutEdges,