From dfafe6075aa3a18bfeecf48e203b555b4f737bff Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Mon, 29 May 2017 18:57:25 +0200 Subject: [PATCH] ENH: region-wise self intersection for surfaceFeatureExtract (issue #450) --- .../surfaceBooleanFeatures.C | 24 +++-- .../surfaceFeatureExtract.C | 35 ++++-- .../surfaceFeatureExtractDict | 23 ++-- .../surfaceIntersection/surfaceIntersection.C | 102 ++++++++++++++++-- .../surfaceIntersection/surfaceIntersection.H | 34 ++++-- 5 files changed, 168 insertions(+), 50 deletions(-) diff --git a/applications/utilities/surface/surfaceBooleanFeatures/surfaceBooleanFeatures.C b/applications/utilities/surface/surfaceBooleanFeatures/surfaceBooleanFeatures.C index 1d0dfae584a..52c5d9c0895 100644 --- a/applications/utilities/surface/surfaceBooleanFeatures/surfaceBooleanFeatures.C +++ b/applications/utilities/surface/surfaceBooleanFeatures/surfaceBooleanFeatures.C @@ -83,7 +83,7 @@ Description #include "edgeIntersections.H" #include "meshTools.H" #include "DynamicField.H" - +#include "Enum.H" #ifndef NO_CGAL @@ -1514,8 +1514,8 @@ int main(int argc, char *argv[]) { argList::noParallel(); argList::validArgs.append("action"); - argList::validArgs.append("surface file"); - argList::validArgs.append("surface file"); + argList::validArgs.append("surfaceFile1"); + argList::validArgs.append("surfaceFile2"); argList::addBoolOption ( @@ -1553,24 +1553,30 @@ int main(int argc, char *argv[]) " 'mixed' (keep all)" ); + argList::addNote + ( + "Valid actions: \"intersection\", \"union\", \"difference\"" + ); + #include "setRootCase.H" #include "createTime.H" const word action(args[1]); - const HashTable<booleanSurface::booleanOpType> validActions + const Enum<booleanSurface::booleanOpType> validActions { - {"intersection", booleanSurface::INTERSECTION}, - {"union", booleanSurface::UNION}, - {"difference", booleanSurface::DIFFERENCE} + { booleanSurface::INTERSECTION, "intersection" }, + { booleanSurface::UNION, "union" }, + { booleanSurface::DIFFERENCE, "difference" } }; - if (!validActions.found(action)) + if (!validActions.hasEnum(action)) { FatalErrorInFunction << "Unsupported action " << action << endl - << "Supported actions:" << validActions.toc() << abort(FatalError); + << "Supported actions:" << validActions << nl + << abort(FatalError); } diff --git a/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtract.C b/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtract.C index 29187c7cfe3..7cd22735a72 100644 --- a/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtract.C +++ b/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtract.C @@ -149,8 +149,21 @@ int main(int argc, char *argv[]) } 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 - autoPtr<triSurface> surfPtr = loader.load(); + autoPtr<triSurface> surfPtr = loader.load(loadingOption); if (!surfPtr.valid() || surfPtr().empty()) { FatalErrorInFunction @@ -390,14 +403,21 @@ int main(int argc, char *argv[]) feMesh.add(addFeMesh); } - if (surfaceDict.lookupOrDefault<bool>("selfIntersection", false)) - { - // TODO: perturbance tolerance? + const surfaceIntersection::intersectionType selfIntersect = + surfaceIntersection::selfIntersectionNames.lookupOrDefault + ( + "intersectionMethod", + surfaceDict, + surfaceIntersection::NONE + ); + if (selfIntersect != surfaceIntersection::NONE) + { triSurfaceSearch query(surf); surfaceIntersection intersect(query, surfaceDict); - intersect.mergePoints(5*SMALL); + // Remove rounding noise - could make adjustable + intersect.mergePoints(10*SMALL); labelPair sizeInfo ( @@ -413,14 +433,15 @@ int main(int argc, char *argv[]) intersect.cutEdges() ); - addMesh.mergePoints(5*SMALL); feMesh.add(addMesh); sizeInfo[0] = addMesh.points().size(); sizeInfo[1] = addMesh.edges().size(); } Info<< nl - << "Self intersection:" << nl + << "intersection: " + << surfaceIntersection::selfIntersectionNames[selfIntersect] + << nl << " points : " << sizeInfo[0] << nl << " edges : " << sizeInfo[1] << nl; } diff --git a/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtractDict b/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtractDict index 65322152987..89f5b9c6b78 100644 --- a/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtractDict +++ b/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtractDict @@ -16,7 +16,7 @@ FoamFile surface1.stl { - // How to obtain raw features (extractFromFile | extractFromSurface | none) + // How to obtain raw features (none | extractFromFile | extractFromSurface) extractionMethod extractFromSurface; // Mark edges whose adjacent surface normals are at an angle less @@ -36,8 +36,8 @@ surface1.stl geometricTestOnly yes; } */ - // Generate additional features from self-intersect - selfIntersection false; + // Generate additional intersection features (none | self | region) + intersectionMethod none; // Tolerance for surface intersections tolerance 1e-3; @@ -51,7 +51,7 @@ surface1.stl surface2.nas { - // How to obtain raw features (extractFromFile | extractFromSurface | none) + // How to obtain raw features (none | extractFromFile | extractFromSurface) extractionMethod extractFromFile; extractFromFileCoeffs @@ -114,8 +114,8 @@ surface2.nas // Out put the closeness of surface elements to other surface elements. closeness no; - // Generate additional features from self-intersect - selfIntersection false; + // Generate additional intersection features (none | self | region) + intersectionMethod none; // Tolerance for surface intersections tolerance 1e-3; @@ -148,8 +148,8 @@ dummyName // Base output name (optional) // output surfaces; - // Generate additional features from self-intersect - selfIntersection true; + // Generate additional intersection features (none | self | region) + intersectionMethod self; // Tolerance for surface intersections tolerance 1e-3; @@ -183,8 +183,8 @@ surfaces // Base output name (optional) // output surfaces; - // Generate additional features from self-intersect - selfIntersection true; + // Generate additional intersection features (none | self | region) + intersectionMethod self; // Tolerance for surface intersections tolerance 1e-3; @@ -193,8 +193,7 @@ surfaces noneCoeffs { includedAngle 0; - } - */ + } */ // Write options diff --git a/src/meshTools/triSurface/booleanOps/surfaceIntersection/surfaceIntersection.C b/src/meshTools/triSurface/booleanOps/surfaceIntersection/surfaceIntersection.C index 5592d95362f..8c552335d46 100644 --- a/src/meshTools/triSurface/booleanOps/surfaceIntersection/surfaceIntersection.C +++ b/src/meshTools/triSurface/booleanOps/surfaceIntersection/surfaceIntersection.C @@ -27,6 +27,7 @@ License #include "triSurfaceSearch.H" #include "OBJstream.H" #include "labelPairHashes.H" +#include "PackedBoolList.H" #include "triSurface.H" #include "pointIndexHit.H" #include "mergePoints.H" @@ -40,6 +41,14 @@ namespace Foam 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 * * * * * * * * * * * // @@ -54,7 +63,7 @@ void Foam::surfaceIntersection::setOptions(const dictionary& dict) void Foam::surfaceIntersection::storeIntersection ( - const enum originatingType cutFrom, + const enum intersectionType cutFrom, const labelList& facesA, const label faceB, const UList<point>& allCutPoints, @@ -85,6 +94,7 @@ void Foam::surfaceIntersection::storeIntersection break; } case surfaceIntersection::SELF: + case surfaceIntersection::SELF_REGION: { // Lookup should be commutativity - use sorted order if (faceA < faceB) @@ -99,6 +109,10 @@ void Foam::surfaceIntersection::storeIntersection } break; } + + case surfaceIntersection::NONE: + return; + break; } @@ -245,7 +259,7 @@ void Foam::surfaceIntersection::classifyHit const triSurface& surf1, const scalarField& surf1PointTol, const triSurface& surf2, - const enum originatingType cutFrom, + const enum intersectionType cutFrom, const label edgeI, const pointIndexHit& pHit, @@ -306,7 +320,11 @@ void Foam::surfaceIntersection::classifyHit // For self-intersection, we have tolerances for each point // (surf2 is actually surf1) so we shift the hit to coincide // identically. - if (cutFrom == surfaceIntersection::SELF) + if + ( + cutFrom == surfaceIntersection::SELF + || cutFrom == surfaceIntersection::SELF_REGION + ) { 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 only 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 // exploit the commutative lookup. @@ -513,12 +539,18 @@ void Foam::surfaceIntersection::classifyHit switch (cutFrom) { case surfaceIntersection::FIRST: + { handling = 1; break; + } case surfaceIntersection::SECOND: + { handling = -1; break; + } case surfaceIntersection::SELF: + case surfaceIntersection::SELF_REGION: + { // The edge-edge intersection is hashed as an 'edge' to // exploit the commutative lookup. // Ie, only do the cut once @@ -563,6 +595,12 @@ void Foam::surfaceIntersection::classifyHit } } } + + break; + } + + case surfaceIntersection::NONE: + return; break; } @@ -744,7 +782,7 @@ void Foam::surfaceIntersection::doCutEdges ( const triSurface& surf1, const triSurfaceSearch& querySurf2, - const enum originatingType cutFrom, + const enum intersectionType cutFrom, DynamicList<point>& allCutPoints, DynamicList<edge>& allCutEdges, @@ -766,13 +804,21 @@ void Foam::surfaceIntersection::doCutEdges const indexedOctree<treeDataPrimitivePatch<triSurface>>& searchTree = querySurf2.tree(); - if (cutFrom == surfaceIntersection::SELF) + if + ( + cutFrom == surfaceIntersection::SELF + || cutFrom == surfaceIntersection::SELF_REGION + ) { // An edge may intersect multiple faces // - mask out faces that have already been hit before trying again // - never intersect with faces attached to the edge itself 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 allIntersectOp(searchTree, maskFaces); @@ -787,6 +833,15 @@ void Foam::surfaceIntersection::doCutEdges const point ptEnd = 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, // nor with faces attached to its end points. This mask contains // some duplicates, but filtering them out is less efficient. @@ -809,6 +864,11 @@ void Foam::surfaceIntersection::doCutEdges maskFaces.append(pHit.index()); + if (maskRegions[surf1[pHit.index()].region()]) + { + continue; + } + classifyHit ( surf1, @@ -1133,6 +1193,27 @@ Foam::surfaceIntersection::surfaceIntersection { 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(); // @@ -1154,7 +1235,7 @@ Foam::surfaceIntersection::surfaceIntersection ( surf1, query1, - surfaceIntersection::SELF, + cutFrom, allCutPoints, allCutEdges, edgeCuts1 @@ -1402,17 +1483,16 @@ void Foam::surfaceIntersection::mergePoints(const scalar mergeDist) pointField newPoints; labelList pointMap; - const bool hasMerged = Foam::mergePoints + const label nMerged = Foam::mergePoints ( cutPoints_, mergeDist, false, pointMap, - newPoints, - vector::zero + newPoints ); - if (hasMerged) + if (nMerged) { cutPoints_.transfer(newPoints); diff --git a/src/meshTools/triSurface/booleanOps/surfaceIntersection/surfaceIntersection.H b/src/meshTools/triSurface/booleanOps/surfaceIntersection/surfaceIntersection.H index 93e15669eeb..d91ef507dd6 100644 --- a/src/meshTools/triSurface/booleanOps/surfaceIntersection/surfaceIntersection.H +++ b/src/meshTools/triSurface/booleanOps/surfaceIntersection/surfaceIntersection.H @@ -52,6 +52,7 @@ Description allowEdgeHits | Edge-end cuts another edge | bool | true snap | Snap near end-points | bool | true warnDegenerate | Number of warnings about degenerate edges | label | 0 + intersectionMethod | Control for self intersection | (self,region,none) \endtable SourceFiles @@ -71,6 +72,7 @@ SourceFiles #include "labelPairHashes.H" #include "pointIndexHit.H" #include "typeInfo.H" +#include "Enum.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -96,15 +98,25 @@ typedef EdgeMap<labelPairHashSet> edgelabelPairHashLookup; class surfaceIntersection { - // Private data +public: + + //- Surface intersection types for classify, doCutEdges + enum intersectionType + { + FIRST, //!< First surface + SECOND, //!< Second surface + 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; - //- Surface intersection types for classify, doCutEdges - enum originatingType - { - FIRST, //!< First surface - SECOND, //!< Second surface - SELF //!< Self-intersection - }; + +private: + + // Private data //- Tolerance for intersections scalar tolerance_; @@ -204,7 +216,7 @@ class surfaceIntersection // Updates facePairToEdge_ and facePairToEdgeId_ (on the second hit) void storeIntersection ( - const enum originatingType cutFrom, + const enum intersectionType cutFrom, const labelList& facesA, const label faceB, const UList<point>& allCutPoints, @@ -219,7 +231,7 @@ class surfaceIntersection const triSurface& surf1, const scalarField& surf1PointTol, const triSurface& surf2, - const enum originatingType cutFrom, + const enum intersectionType cutFrom, const label edgeI, const pointIndexHit& pHit, @@ -233,7 +245,7 @@ class surfaceIntersection ( const triSurface& surf1, const triSurfaceSearch& querySurf2, - const enum originatingType cutFrom, + const enum intersectionType cutFrom, DynamicList<point>& allCutPoints, DynamicList<edge>& allCutEdges, -- GitLab