diff --git a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict index cc975eb9708ac93b1a478343b34363b0ef3a0587..205c767600bede32ffba05d4a2bd0873598b7511 100644 --- a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict +++ b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict @@ -274,6 +274,14 @@ addLayersControls // Create buffer region for new layer terminations nBufferCellsNoExtrude 0; + + + // Overall max number of layer addition iterations + nLayerIter 50; + + // Max number of iterations after which relaxed meshQuality controls + // get used. + nRelaxedIter 20; } @@ -335,6 +343,16 @@ meshQualityControls nSmoothScale 4; //- amount to scale back displacement at error points errorReduction 0.75; + + + + // Optional : some meshing phases allow usage of relaxed rules. + // See e.g. addLayersControls::nRelaxedIter. + relaxed + { + //- Maximum non-orthogonality allowed. Set to 180 to disable. + maxNonOrtho 75; + } } diff --git a/applications/utilities/surface/surfaceCheck/surfaceCheck.C b/applications/utilities/surface/surfaceCheck/surfaceCheck.C index e7b789007475cfd40617116532e1e0a98a0cc3d8..4731ed3ec25c6bb37750f25e7daa23369e26b9ba 100644 --- a/applications/utilities/surface/surfaceCheck/surfaceCheck.C +++ b/applications/utilities/surface/surfaceCheck/surfaceCheck.C @@ -171,11 +171,11 @@ int main(int argc, char *argv[]) argList::validArgs.clear(); argList::validArgs.append("surface file"); - argList::validOptions.insert("noSelfIntersection", ""); + argList::validOptions.insert("checkSelfIntersection", ""); argList::validOptions.insert("verbose", ""); argList args(argc, argv); - bool checkSelfIntersection = !args.options().found("noSelfIntersection"); + bool checkSelfIntersection = args.options().found("checkSelfIntersection"); bool verbose = args.options().found("verbose"); fileName surfFileName(args.additionalArgs()[0]); diff --git a/src/OpenFOAM/meshes/boundBox/boundBox.H b/src/OpenFOAM/meshes/boundBox/boundBox.H index e41b6efa46139795a8bb8f83f10e2329bc375fd0..38b852ef66a429a414911dd04545d9568e79745a 100644 --- a/src/OpenFOAM/meshes/boundBox/boundBox.H +++ b/src/OpenFOAM/meshes/boundBox/boundBox.H @@ -174,7 +174,7 @@ public: // Query - //- Completely contains other boundingBox? (inside or on edge) + //- Overlaps/touches boundingBox? bool overlaps(const boundBox& bb) const { return diff --git a/src/OpenFOAM/meshes/meshShapes/face/face.H b/src/OpenFOAM/meshes/meshShapes/face/face.H index 07dd39f93fc2cfad8fe3225e0704ecd54e737f1f..25a4f8fbce5b70f44c74ffd36a7c42c45e14ce99 100644 --- a/src/OpenFOAM/meshes/meshShapes/face/face.H +++ b/src/OpenFOAM/meshes/meshShapes/face/face.H @@ -222,16 +222,16 @@ public: ) const; //- Fast intersection with a ray. - // For a hit, the pointHit.distance() is the line parameter t : - // intersection=p+t*q. Only defined for FULL_RAY or - // HALF_RAY. + // Does face-center decomposition and returns triangle intersection + // point closest to p. See triangle::intersection for details. pointHit intersection ( const point& p, const vector& q, const point& ctr, const pointField& meshPoints, - const intersection::algorithm alg + const intersection::algorithm alg, + const scalar tol = 0.0 ) const; //- Return nearest point to face diff --git a/src/OpenFOAM/meshes/meshShapes/face/faceIntersection.C b/src/OpenFOAM/meshes/meshShapes/face/faceIntersection.C index b514af77499d00e66844fff35bcf9e78c48e0c9e..c5f9a80250b00e433d139011a9e2d2c7b33b28a3 100644 --- a/src/OpenFOAM/meshes/meshShapes/face/faceIntersection.C +++ b/src/OpenFOAM/meshes/meshShapes/face/faceIntersection.C @@ -136,7 +136,8 @@ Foam::pointHit Foam::face::intersection const vector& q, const point& ctr, const pointField& meshPoints, - const intersection::algorithm alg + const intersection::algorithm alg, + const scalar tol ) const { scalar nearestHitDist = VGREAT; @@ -154,7 +155,7 @@ Foam::pointHit Foam::face::intersection meshPoints[f[pI]], meshPoints[f[fcIndex(pI)]], ctr - ).intersection(p, q, alg); + ).intersection(p, q, alg, tol); if (curHit.hit()) { diff --git a/src/OpenFOAM/meshes/primitiveShapes/triangle/triangle.H b/src/OpenFOAM/meshes/primitiveShapes/triangle/triangle.H index b24149300f5bd1aa8bd7939c0eb2a7f2c13c7671..11650466360bc6fc58f76aaf6a9c8a4c7ce026d5 100644 --- a/src/OpenFOAM/meshes/primitiveShapes/triangle/triangle.H +++ b/src/OpenFOAM/meshes/primitiveShapes/triangle/triangle.H @@ -153,7 +153,7 @@ public: inline scalar sweptVol(const triangle& t) const; //- Return point intersection with a ray. - // For a hit, the distance is signed. Positive number + // For a hit, the distance is signed. Positive number // represents the point in front of triangle. // In case of miss pointHit is set to nearest point // on triangle and its distance to the distance between @@ -166,15 +166,20 @@ public: const intersection::direction dir = intersection::VECTOR ) const; - //- Fast intersection with a ray. - // For a hit, the pointHit.distance() is the line parameter t : - // intersection=p+t*q. Only defined for VISIBLE, FULL_RAY or - // HALF_RAY. + //- Fast intersection with a ray. Distance is normalised distance + // to the intersection (normalised with the vector magnitude). + // For a hit, the distance is signed. Positive number + // represents the point in front of triangle. In case of miss + // pointHit position is undefined. + // Only defined for VISIBLE, FULL_RAY or + // HALF_RAY. tol increases the virtual size of the triangle + // by a relative factor. inline pointHit intersection ( const point& p, const vector& q, - const intersection::algorithm alg + const intersection::algorithm alg, + const scalar tol = 0.0 ) const; //- Return nearest point to p on triangle diff --git a/src/OpenFOAM/meshes/primitiveShapes/triangle/triangleI.H b/src/OpenFOAM/meshes/primitiveShapes/triangle/triangleI.H index ad7ed2ea8bdd307ad249437a5d0e756ee4e31f74..33b3cab15e67775129d8997818a299add2d687f9 100644 --- a/src/OpenFOAM/meshes/primitiveShapes/triangle/triangleI.H +++ b/src/OpenFOAM/meshes/primitiveShapes/triangle/triangleI.H @@ -439,7 +439,8 @@ inline pointHit triangle<Point, PointRef>::intersection ( const point& orig, const vector& dir, - const intersection::algorithm alg + const intersection::algorithm alg, + const scalar tol ) const { const vector edge1 = b_ - a_; @@ -457,99 +458,61 @@ inline pointHit triangle<Point, PointRef>::intersection if (alg == intersection::VISIBLE) { // Culling branch - if (det < SMALL) + if (det < ROOTVSMALL) { - // return miss + // Ray on wrong side of triangle. Return miss return intersection; } - /* calculate distance from a_ to ray origin */ - const vector tVec = orig-a_; - - /* calculate U parameter and test bounds */ - scalar u = tVec & pVec; - - if (u < 0.0 || u > det) - { - // return miss - return intersection; - } - - /* prepare to test V parameter */ - const vector qVec = tVec ^ edge1; - - /* calculate V parameter and test bounds */ - scalar v = dir & qVec; - - if (v < 0.0 || u + v > det) - { - // return miss - return intersection; - } - - /* calculate t, scale parameters, ray intersects triangle */ - scalar t = edge2 & qVec; - scalar inv_det = 1.0 / det; - t *= inv_det; - u *= inv_det; - v *= inv_det; - - intersection.setHit(); - intersection.setPoint(a_ + u*edge1 + v*edge2); - intersection.setDistance(t); } else if (alg == intersection::HALF_RAY || alg == intersection::FULL_RAY) { // Non-culling branch - if (det > -SMALL && det < SMALL) + if (det > -ROOTVSMALL && det < ROOTVSMALL) { - // return miss + // Ray parallel to triangle. Return miss return intersection; } - const scalar inv_det = 1.0 / det; + } - /* calculate distance from a_ to ray origin */ - const vector tVec = orig - a_; - /* calculate U parameter and test bounds */ - const scalar u = (tVec & pVec)*inv_det; + const scalar inv_det = 1.0 / det; - if (u < 0.0 || u > 1.0) - { - // return miss - return intersection; - } - /* prepare to test V parameter */ - const vector qVec = tVec ^ edge1; - /* calculate V parameter and test bounds */ - const scalar v = (dir & qVec) * inv_det; + /* calculate distance from a_ to ray origin */ + const vector tVec = orig-a_; - if (v < 0.0 || u + v > 1.0) - { - // return miss - return intersection; - } - /* calculate t, ray intersects triangle */ - const scalar t = (edge2 & qVec) * inv_det; + /* calculate U parameter and test bounds */ + const scalar u = (tVec & pVec)*inv_det; - if (alg == intersection::HALF_RAY && t < 0) - { - // return miss - return intersection; - } + if (u < -tol || u > 1.0+tol) + { + // return miss + return intersection; + } - intersection.setHit(); - intersection.setPoint(a_ + u*edge1 + v*edge2); - intersection.setDistance(t); + /* prepare to test V parameter */ + const vector qVec = tVec ^ edge1; + + /* calculate V parameter and test bounds */ + const scalar v = (dir & qVec) * inv_det; + + if (v < -tol || u + v > 1.0+tol) + { + // return miss + return intersection; } - else + + /* calculate t, scale parameters, ray intersects triangle */ + const scalar t = (edge2 & qVec) * inv_det; + + if (alg == intersection::HALF_RAY && t < -tol) { - FatalErrorIn - ( - "triangle<Point, PointRef>::intersection(const point&" - ", const vector&, const intersection::algorithm)" - ) << "intersection only defined for VISIBLE, FULL_RAY or HALF_RAY" - << abort(FatalError); + // Wrong side of orig. Return miss + return intersection; } + intersection.setHit(); + intersection.setPoint(a_ + u*edge1 + v*edge2); + intersection.setDistance(t); + return intersection; } @@ -622,7 +585,7 @@ inline bool triangle<Point, PointRef>::classify bool hit = false; - if (Foam::mag(u1) < SMALL) + if (Foam::mag(u1) < ROOTVSMALL) { beta = u0/u2; diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.H b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.H index 9ae910b5a71c19965794151be42ef0d9759603d4..c0b7668d0ac6e68c56ab8a5a6546a61ce48b289d 100644 --- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.H +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.H @@ -38,7 +38,6 @@ SourceFiles #include "autoPtr.H" #include "dictionary.H" -#include "boolList.H" #include "wallPoint.H" #include "searchableSurfaces.H" #include "refinementSurfaces.H" diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriver.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriver.C index 8d3c0e1e76bc2adaa66e67ffbc402c8c0f87fa43..0859e37d33f40f0aa0a6b7d371f0af443f0a7aaa 100644 --- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriver.C +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriver.C @@ -2292,7 +2292,7 @@ bool Foam::autoLayerDriver::cellsUseFace Foam::label Foam::autoLayerDriver::checkAndUnmark ( const addPatchCellLayer& addLayer, - const dictionary& motionDict, + const dictionary& meshQualityDict, const indirectPrimitivePatch& pp, const fvMesh& newMesh, @@ -2304,7 +2304,7 @@ Foam::label Foam::autoLayerDriver::checkAndUnmark // Check the resulting mesh for errors Info<< nl << "Checking mesh with layer ..." << endl; faceSet wrongFaces(newMesh, "wrongFaces", newMesh.nFaces()/1000); - motionSmoother::checkMesh(false, newMesh, motionDict, wrongFaces); + motionSmoother::checkMesh(false, newMesh, meshQualityDict, wrongFaces); Info<< "Detected " << returnReduce(wrongFaces.size(), sumOp<label>()) << " illegal faces" << " (concave, zero area or negative cell pyramid volume)" @@ -2474,8 +2474,8 @@ void Foam::autoLayerDriver::mergePatchFacesUndo << " (cos:" << minCos << ')' << nl << " - as long as the resulting face doesn't become concave" << " by more than " - << layerParams.concaveAngle() - << " degrees (0=straight, 180=fully concave)" << nl + << layerParams.concaveAngle() << " degrees" << nl + << " (0=straight, 180=fully concave)" << nl << endl; label nChanged = mergePatchFacesUndo(minCos, concaveCos, motionDict); @@ -2709,8 +2709,12 @@ void Foam::autoLayerDriver::addLayers boolList flaggedCells; boolList flaggedFaces; - while (true) + for (label iteration = 0; iteration < layerParams.nLayerIter(); iteration++) { + Info<< nl + << "Layer addition iteration " << iteration << nl + << "--------------------------" << endl; + // Make sure displacement is equal on both sides of coupled patches. syncPatchDisplacement ( @@ -2951,10 +2955,23 @@ void Foam::autoLayerDriver::addLayers } // Unset the extrusion at the pp. + const dictionary& meshQualityDict = + ( + iteration < layerParams.nRelaxedIter() + ? motionDict + : motionDict.subDict("relaxed") + ); + + if (iteration >= layerParams.nRelaxedIter()) + { + Info<< "Switched to relaxed meshQuality constraints." << endl; + } + + label nTotChanged = checkAndUnmark ( addLayer, - motionDict, + meshQualityDict, pp, newMesh, @@ -2976,6 +2993,8 @@ void Foam::autoLayerDriver::addLayers // Reset mesh points and start again meshMover.movePoints(oldPoints); meshMover.correct(); + + Info<< endl; } diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C index e891cf761c7e452fa5003016cb4d92b868312997..9c4e0a17c521b8e06b4b2ecceb18ed80bb917d06 100644 --- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C @@ -95,7 +95,7 @@ Foam::label Foam::autoRefineDriver::readFeatureEdges Info<< "Refinement level " << featureLevels[i] << " for all cells crossed by feature " << featFileName << " (" << featureMeshes[i].points().size() << " points, " - << featureMeshes[i].edges().size() << ")." << endl; + << featureMeshes[i].edges().size() << " edges)." << endl; } Info<< "Read feature lines in = " diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.C index ddf162dd0f2910d2aaaf89a0f2465a26b86926b7..dfdc16e919961eaf6fcebcb8de19237b354c95dc 100644 --- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.C +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.C @@ -211,8 +211,24 @@ Foam::layerParameters::layerParameters ( readLabel(dict.lookup("nBufferCellsNoExtrude")) ), - nSnap_(readLabel(dict.lookup("nSnap"))) -{} + nSnap_(readLabel(dict.lookup("nSnap"))), + nLayerIter_(readLabel(dict.lookup("nLayerIter"))), + nRelaxedIter_(labelMax) +{ + if (dict.found("nRelaxedIter")) + { + dict.lookup("nRelaxedIter") >> nRelaxedIter_; + } + + if (nLayerIter_ < 0 || nRelaxedIter_ < 0) + { + FatalErrorIn("layerParameters::layerParameters(..)") + << "Layer iterations should be >= 0." << endl + << "nLayerIter:" << nLayerIter_ + << " nRelaxedIter:" << nRelaxedIter_ + << exit(FatalError); + } +} // Construct from dictionary @@ -276,8 +292,24 @@ Foam::layerParameters::layerParameters ( readLabel(dict.lookup("nBufferCellsNoExtrude")) ), - nSnap_(readLabel(dict.lookup("nRelaxIter"))) + nSnap_(readLabel(dict.lookup("nRelaxIter"))), + nLayerIter_(readLabel(dict.lookup("nLayerIter"))), + nRelaxedIter_(labelMax) { + if (dict.found("nRelaxedIter")) + { + dict.lookup("nRelaxedIter") >> nRelaxedIter_; + } + if (nLayerIter_ < 0 || nRelaxedIter_ < 0) + { + FatalErrorIn("layerParameters::layerParameters(..)") + << "Layer iterations should be >= 0." << endl + << "nLayerIter:" << nLayerIter_ + << " nRelaxedIter:" << nRelaxedIter_ + << exit(FatalError); + } + + const dictionary& layersDict = dict.subDict("layers"); forAll(boundaryMesh, patchI) diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.H b/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.H index d96ce97cbd2167d6f1aa51d736e5fd6a9baca943..e3d3702bfd2ed0b0d9e5d606ffaaa2c433efd1b1 100644 --- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.H +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.H @@ -105,6 +105,10 @@ class layerParameters label nSnap_; + label nLayerIter_; + + label nRelaxedIter_; + // Private Member Functions @@ -196,26 +200,20 @@ public: return nGrow_; } - // Number of smoothing iterations of surface normals + //- Number of smoothing iterations of surface normals label nSmoothSurfaceNormals() const { return nSmoothSurfaceNormals_; } - // Number of smoothing iterations of interior mesh movement - // direction + //- Number of smoothing iterations of interior mesh movement + // direction label nSmoothNormals() const { return nSmoothNormals_; } - // Smooth layer thickness over surface patches - label nSmoothThickness() const - { - return nSmoothThickness_; - } - - // Stop layer growth on highly warped cells + //- Stop layer growth on highly warped cells scalar maxFaceThicknessRatio() const { return maxFaceThicknessRatio_; @@ -226,20 +224,26 @@ public: return layerTerminationCos_; } - // Reduce layer growth where ratio thickness to medial - // distance is large + //- Smooth layer thickness over surface patches + label nSmoothThickness() const + { + return nSmoothThickness_; + } + + //- Reduce layer growth where ratio thickness to medial + // distance is large scalar maxThicknessToMedialRatio() const { return maxThicknessToMedialRatio_; } - // Angle used to pick up medial axis points + //- Angle used to pick up medial axis points scalar minMedianAxisAngleCos() const { return minMedianAxisAngleCos_; } - // Create buffer region for new layer terminations + //- Create buffer region for new layer terminations label nBufferCellsNoExtrude() const { return nBufferCellsNoExtrude_; @@ -249,6 +253,24 @@ public: { return nSnap_; } + + // Overall + + //- Number of overall layer addition iterations + label nLayerIter() const + { + return nLayerIter_; + } + + //- Number of iterations after which relaxed motion rules + // are to be used. + label nRelaxedIter() const + { + return nRelaxedIter_; + } + + + }; diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/pointData/pointData.H b/src/autoMesh/autoHexMesh/autoHexMeshDriver/pointData/pointData.H index ffb8a15d05505dbc74ec6703a1afdda3d7d53012..d27c62929d94e9ab167682fe5df98e6cb394cb1a 100644 --- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/pointData/pointData.H +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/pointData/pointData.H @@ -42,9 +42,7 @@ SourceFiles #include "point.H" #include "label.H" -#include "scalar.H" #include "tensor.H" -#include "pTraits.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/pointData/pointDataI.H b/src/autoMesh/autoHexMesh/autoHexMeshDriver/pointData/pointDataI.H index 234d569f85010eb6feac5c26a70acf52cb57102a..9832bbf877d0fe53c81b2f679a21aecd091dfbc9 100644 --- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/pointData/pointDataI.H +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/pointData/pointDataI.H @@ -22,8 +22,6 @@ License along with OpenFOAM; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -Description - \*---------------------------------------------------------------------------*/ #include "polyMesh.H" diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H index 0025f333323020779c7b72e7bbac2984afcf8121..06004c8a6e00bc12c093cb36afb2782638b4b2d3 100644 --- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H +++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H @@ -47,7 +47,6 @@ SourceFiles #include "hexRef8.H" #include "mapPolyMesh.H" #include "autoPtr.H" -#include "pointIOField.H" #include "labelPair.H" #include "indirectPrimitivePatch.H" #include "pointFieldsFwd.H" diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C index d42ac05b2233d1657f30a6511c825344c531924e..7aabbc6321cf9132e9e5c271d46e15abd7e00673 100644 --- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C +++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C @@ -328,7 +328,7 @@ Foam::label Foam::meshRefinement::markFeatureRefinement // Database to pass into trackedParticle::move trackedParticle::trackData td(cloud, maxFeatureLevel); - // Track all particles to their end position. + // Track all particles to their end position (= starting feature point) cloud.move(td); // Reset level diff --git a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H index e8fd3614018be8a862d01814eb150be7de5aa953..cee48bbe1f5effc3ed9cc0f6ad59193c87dce62e 100644 --- a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H +++ b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H @@ -38,7 +38,6 @@ SourceFiles #ifndef refinementSurfaces_H #define refinementSurfaces_H -#include "PackedBoolList.H" #include "triSurfaceGeoMesh.H" #include "triSurfaceFields.H" #include "vectorList.H" diff --git a/src/autoMesh/autoHexMesh/trackedParticle/ExactParticle.C b/src/autoMesh/autoHexMesh/trackedParticle/ExactParticle.C index bcf92e9747c92c3cdfd18c5ab63a002d47917681..237e35276c33e528be26b13430bc078ea66baab4 100644 --- a/src/autoMesh/autoHexMesh/trackedParticle/ExactParticle.C +++ b/src/autoMesh/autoHexMesh/trackedParticle/ExactParticle.C @@ -102,23 +102,7 @@ Foam::scalar Foam::ExactParticle<ParticleType>::trackToFace } } - - if (hitFacei != -1) - { - if (trackFraction > 1.0) - { - // Nearest intersection beyond endPosition so we hit endPosition. - this->position_ = endPosition; - this->facei_ = -1; - return 1.0; - } - else - { - this->position_ = intersection; - this->facei_ = hitFacei; - } - } - else + if (hitFacei == -1) { // Did not find any intersection. Fall back to original approximate // algorithm @@ -129,8 +113,23 @@ Foam::scalar Foam::ExactParticle<ParticleType>::trackToFace ); } + if (trackFraction >= (1.0-SMALL)) + { + // Nearest intersection beyond endPosition so we hit endPosition. + trackFraction = 1.0; + this->position_ = endPosition; + this->facei_ = -1; + return 1.0; + } + else + { + this->position_ = intersection; + this->facei_ = hitFacei; + } + - // Normal situation (trackFraction 0..1) + // Normal situation (trackFraction 0..1). Straight copy + // of Particle::trackToFace. bool internalFace = this->cloud().internalFace(this->facei_); diff --git a/src/dynamicMesh/motionSmoother/motionSmoother.C b/src/dynamicMesh/motionSmoother/motionSmoother.C index 18f5c85478e301085d49ca0eb05980d00a96e333..4f40827f4b3a8030217e79098e6716f8db96e018 100644 --- a/src/dynamicMesh/motionSmoother/motionSmoother.C +++ b/src/dynamicMesh/motionSmoother/motionSmoother.C @@ -825,6 +825,28 @@ bool Foam::motionSmoother::scaleMesh const bool smoothMesh, const label nAllowableErrors ) +{ + return scaleMesh + ( + checkFaces, + baffles, + paramDict_, + paramDict_, + smoothMesh, + nAllowableErrors + ); +} + + +bool Foam::motionSmoother::scaleMesh +( + labelList& checkFaces, + const List<labelPair>& baffles, + const dictionary& paramDict, + const dictionary& meshQualityDict, + const bool smoothMesh, + const label nAllowableErrors +) { if (!smoothMesh && adaptPatchIDs_.empty()) { @@ -859,9 +881,9 @@ bool Foam::motionSmoother::scaleMesh } const scalar errorReduction = - readScalar(paramDict_.lookup("errorReduction")); + readScalar(paramDict.lookup("errorReduction")); const label nSmoothScale = - readLabel(paramDict_.lookup("nSmoothScale")); + readLabel(paramDict.lookup("nSmoothScale")); // Note: displacement_ should already be synced already from setDisplacement @@ -921,7 +943,7 @@ bool Foam::motionSmoother::scaleMesh // Check. Returns parallel number of incorrect faces. faceSet wrongFaces(mesh_, "wrongFaces", mesh_.nFaces()/100+100); - checkMesh(false, mesh_, paramDict_, checkFaces, baffles, wrongFaces); + checkMesh(false, mesh_, meshQualityDict, checkFaces, baffles, wrongFaces); if (returnReduce(wrongFaces.size(), sumOp<label>()) <= nAllowableErrors) { diff --git a/src/dynamicMesh/motionSmoother/motionSmoother.H b/src/dynamicMesh/motionSmoother/motionSmoother.H index e5777a366459e75bde147a3e7e420a719ea3a361..e4aeac6f50756ec9a5f27da2602aa80ddad26036 100644 --- a/src/dynamicMesh/motionSmoother/motionSmoother.H +++ b/src/dynamicMesh/motionSmoother/motionSmoother.H @@ -52,7 +52,7 @@ Description @endverbatim Note - Shared points (parallel): a processor can have points which are part of + - Shared points (parallel): a processor can have points which are part of pp on another processor but have no pp itself (i.e. it has points and/or edges but no faces of pp). Hence we have to be careful when e.g. synchronising displacements that the value from the processor which has @@ -61,10 +61,13 @@ Note else. The combine operator used will give preference to non-zero values. - Various routines take baffles. These are sets of boundary faces that + - Various routines take baffles. These are sets of boundary faces that are treated as a single internal face. This is a hack used to apply movement to internal faces. + - Mesh constraints are looked up from the supplied dictionary. (uses + recursive lookup) + SourceFiles motionSmoother.C motionSmootherTemplates.C @@ -395,6 +398,17 @@ public: const label nAllow = 0 ); + //- Move mesh with externally provided mesh constraints + bool scaleMesh + ( + labelList& checkFaces, + const List<labelPair>& baffles, + const dictionary& paramDict, + const dictionary& meshQualityDict, + const bool smoothMesh = true, + const label nAllow = 0 + ); + //- Update topology void updateMesh(); diff --git a/src/dynamicMesh/motionSmoother/motionSmootherCheck.C b/src/dynamicMesh/motionSmoother/motionSmootherCheck.C index 06996c541f9270b8300eb5da110c9dfc521ed95b..7fcb9f1e7ac70660201f2a760565ac691aefd526 100644 --- a/src/dynamicMesh/motionSmoother/motionSmootherCheck.C +++ b/src/dynamicMesh/motionSmoother/motionSmootherCheck.C @@ -28,19 +28,6 @@ License #include "polyMeshGeometry.H" #include "IOmanip.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - - -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // - - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - - -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - - // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // bool Foam::motionSmoother::checkMesh @@ -74,17 +61,50 @@ bool Foam::motionSmoother::checkMesh labelHashSet& wrongFaces ) { - const scalar maxNonOrtho(readScalar(dict.lookup("maxNonOrtho"))); - const scalar minVol(readScalar(dict.lookup("minVol"))); - const scalar maxConcave(readScalar(dict.lookup("maxConcave"))); - const scalar minArea(readScalar(dict.lookup("minArea"))); - const scalar maxIntSkew(readScalar(dict.lookup("maxInternalSkewness"))); - const scalar maxBounSkew(readScalar(dict.lookup("maxBoundarySkewness"))); - const scalar minWeight(readScalar(dict.lookup("minFaceWeight"))); - const scalar minVolRatio(readScalar(dict.lookup("minVolRatio"))); - const scalar minTwist(readScalar(dict.lookup("minTwist"))); - const scalar minTriangleTwist(readScalar(dict.lookup("minTriangleTwist"))); - const scalar minDet(readScalar(dict.lookup("minDeterminant"))); + const scalar maxNonOrtho + ( + readScalar(dict.lookup("maxNonOrtho", true)) + ); + const scalar minVol + ( + readScalar(dict.lookup("minVol", true)) + ); + const scalar maxConcave + ( + readScalar(dict.lookup("maxConcave", true)) + ); + const scalar minArea + ( + readScalar(dict.lookup("minArea", true)) + ); + const scalar maxIntSkew + ( + readScalar(dict.lookup("maxInternalSkewness", true)) + ); + const scalar maxBounSkew + ( + readScalar(dict.lookup("maxBoundarySkewness", true)) + ); + const scalar minWeight + ( + readScalar(dict.lookup("minFaceWeight", true)) + ); + const scalar minVolRatio + ( + readScalar(dict.lookup("minVolRatio", true)) + ); + const scalar minTwist + ( + readScalar(dict.lookup("minTwist", true)) + ); + const scalar minTriangleTwist + ( + readScalar(dict.lookup("minTriangleTwist", true)) + ); + const scalar minDet + ( + readScalar(dict.lookup("minDeterminant", true)) + ); label nWrongFaces = 0; @@ -389,17 +409,50 @@ bool Foam::motionSmoother::checkMesh labelHashSet& wrongFaces ) { - const scalar maxNonOrtho(readScalar(dict.lookup("maxNonOrtho"))); - const scalar minVol(readScalar(dict.lookup("minVol"))); - const scalar maxConcave(readScalar(dict.lookup("maxConcave"))); - const scalar minArea(readScalar(dict.lookup("minArea"))); - const scalar maxIntSkew(readScalar(dict.lookup("maxInternalSkewness"))); - const scalar maxBounSkew(readScalar(dict.lookup("maxBoundarySkewness"))); - const scalar minWeight(readScalar(dict.lookup("minFaceWeight"))); - const scalar minVolRatio(readScalar(dict.lookup("minVolRatio"))); - const scalar minTwist(readScalar(dict.lookup("minTwist"))); - const scalar minTriangleTwist(readScalar(dict.lookup("minTriangleTwist"))); - const scalar minDet(readScalar(dict.lookup("minDeterminant"))); + const scalar maxNonOrtho + ( + readScalar(dict.lookup("maxNonOrtho", true)) + ); + const scalar minVol + ( + readScalar(dict.lookup("minVol", true)) + ); + const scalar maxConcave + ( + readScalar(dict.lookup("maxConcave", true)) + ); + const scalar minArea + ( + readScalar(dict.lookup("minArea", true)) + ); + const scalar maxIntSkew + ( + readScalar(dict.lookup("maxInternalSkewness", true)) + ); + const scalar maxBounSkew + ( + readScalar(dict.lookup("maxBoundarySkewness", true)) + ); + const scalar minWeight + ( + readScalar(dict.lookup("minFaceWeight", true)) + ); + const scalar minVolRatio + ( + readScalar(dict.lookup("minVolRatio", true)) + ); + const scalar minTwist + ( + readScalar(dict.lookup("minTwist", true)) + ); + const scalar minTriangleTwist + ( + readScalar(dict.lookup("minTriangleTwist", true)) + ); + const scalar minDet + ( + readScalar(dict.lookup("minDeterminant", true)) + ); label nWrongFaces = 0; diff --git a/src/meshTools/directMapped/directMappedPolyPatch/directMappedPolyPatch.C b/src/meshTools/directMapped/directMappedPolyPatch/directMappedPolyPatch.C index 9dbe7e8c1331ef7a68bdb0d4ade891b8aa002aef..61697be9b3adc0d9c979e0799f7adf955784f35a 100644 --- a/src/meshTools/directMapped/directMappedPolyPatch/directMappedPolyPatch.C +++ b/src/meshTools/directMapped/directMappedPolyPatch/directMappedPolyPatch.C @@ -31,6 +31,9 @@ License #include "mapDistribute.H" #include "meshTools.H" #include "OFstream.H" +#include "Random.H" +#include "treeDataFace.H" +#include "indexedOctree.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/meshTools/indexedOctree/indexedOctree.C b/src/meshTools/indexedOctree/indexedOctree.C index 2131c3aaf6ef936fcf18bbe8f4cc39ffcdde93c5..4f555649996a3deb0ed264dedb43451002ad8479 100644 --- a/src/meshTools/indexedOctree/indexedOctree.C +++ b/src/meshTools/indexedOctree/indexedOctree.C @@ -29,6 +29,12 @@ License #include "meshTools.H" #include "OFstream.H" +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +template <class Type> +Foam::scalar Foam::indexedOctree<Type>::perturbTol_ = 10*SMALL; + + // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // Does bb intersect a sphere around sample? Or is any corner point of bb @@ -203,7 +209,7 @@ Foam::indexedOctree<Type>::divide || bb.min()[2] >= bb.max()[2] ) { - FatalErrorIn("indexedOctree<Type>::divide") + FatalErrorIn("indexedOctree<Type>::divide(..)") << "Badly formed bounding box:" << bb << abort(FatalError); } @@ -674,100 +680,815 @@ void Foam::indexedOctree<Type>::findNearest } +template <class Type> +Foam::treeBoundBox Foam::indexedOctree<Type>::subBbox +( + const label parentNodeI, + const direction octant +) const +{ + // Get type of node at octant + const node& nod = nodes_[parentNodeI]; + labelBits index = nod.subNodes_[octant]; + + if (isNode(index)) + { + // Use stored bb + return nodes_[getNode(index)].bb_; + } + else + { + // Calculate subBb + return nod.bb_.subBbox(octant); + } +} + + +// Takes a bb and a point on/close to the edge of the bb and pushes the point +// inside by a small fraction. +template <class Type> +Foam::point Foam::indexedOctree<Type>::pushPoint +( + const treeBoundBox& bb, + const point& pt, + const bool pushInside +) +{ + // Get local length scale. + const vector perturbVec = perturbTol_*(bb.span()); + + point perturbedPt(pt); + + // Modify all components which are close to any face of the bb to be + // well inside/outside them. + + if (pushInside) + { + for (direction dir = 0; dir < vector::nComponents; dir++) + { + if (mag(pt[dir]-bb.min()[dir]) < mag(perturbVec[dir])) + { + // Close to 'left' side. Push well beyond left side. + scalar perturbDist = perturbVec[dir] + ROOTVSMALL; + perturbedPt[dir] = bb.min()[dir] + perturbDist; + } + else if (mag(pt[dir]-bb.max()[dir]) < mag(perturbVec[dir])) + { + // Close to 'right' side. Push well beyond right side. + scalar perturbDist = perturbVec[dir] + ROOTVSMALL; + perturbedPt[dir] = bb.max()[dir] - perturbDist; + } + } + } + else + { + for (direction dir = 0; dir < vector::nComponents; dir++) + { + if (mag(pt[dir]-bb.min()[dir]) < mag(perturbVec[dir])) + { + scalar perturbDist = perturbVec[dir] + ROOTVSMALL; + perturbedPt[dir] = bb.min()[dir] - perturbDist; + } + else if (mag(pt[dir]-bb.max()[dir]) < mag(perturbVec[dir])) + { + scalar perturbDist = perturbVec[dir] + ROOTVSMALL; + perturbedPt[dir] = bb.max()[dir] + perturbDist; + } + } + } + + if (debug) + { + if (pushInside != bb.contains(perturbedPt)) + { + FatalErrorIn("indexedOctree<Type>::pushPoint(..)") + << "pushed point:" << pt + << " to:" << perturbedPt + << " wanted side:" << pushInside + << " obtained side:" << bb.contains(perturbedPt) + << " of bb:" << bb + << abort(FatalError); + } + } + + return perturbedPt; +} + + +// Takes a bb and a point on the edge of the bb and pushes the point +// outside by a small fraction. +template <class Type> +Foam::point Foam::indexedOctree<Type>::pushPoint +( + const treeBoundBox& bb, + const direction faceID, + const point& pt, + const bool pushInside +) +{ + // Get local length scale. + const vector perturbVec = perturbTol_*bb.span(); + + point perturbedPt(pt); + + // Modify all components which are close to any face of the bb to be + // well outside them. + + if (faceID == 0) + { + FatalErrorIn("indexedOctree<Type>::pushPoint(..)") + << abort(FatalError); + } + + if (faceID & treeBoundBox::LEFTBIT) + { + if (pushInside) + { + perturbedPt[0] = bb.min()[0] + (perturbVec[0] + ROOTVSMALL); + } + else + { + perturbedPt[0] = bb.min()[0] - (perturbVec[0] + ROOTVSMALL); + } + } + else if (faceID & treeBoundBox::RIGHTBIT) + { + if (pushInside) + { + perturbedPt[0] = bb.max()[0] - (perturbVec[0] + ROOTVSMALL); + } + else + { + perturbedPt[0] = bb.max()[0] + (perturbVec[0] + ROOTVSMALL); + } + } + + if (faceID & treeBoundBox::BOTTOMBIT) + { + if (pushInside) + { + perturbedPt[1] = bb.min()[1] + (perturbVec[1] + ROOTVSMALL); + } + else + { + perturbedPt[1] = bb.min()[1] - (perturbVec[1] + ROOTVSMALL); + } + } + else if (faceID & treeBoundBox::TOPBIT) + { + if (pushInside) + { + perturbedPt[1] = bb.max()[1] - (perturbVec[1] + ROOTVSMALL); + } + else + { + perturbedPt[1] = bb.max()[1] + (perturbVec[1] + ROOTVSMALL); + } + } + + if (faceID & treeBoundBox::BACKBIT) + { + if (pushInside) + { + perturbedPt[2] = bb.min()[2] + (perturbVec[2] + ROOTVSMALL); + } + else + { + perturbedPt[2] = bb.min()[2] - (perturbVec[2] + ROOTVSMALL); + } + } + else if (faceID & treeBoundBox::FRONTBIT) + { + if (pushInside) + { + perturbedPt[2] = bb.max()[2] - (perturbVec[2] + ROOTVSMALL); + } + else + { + perturbedPt[2] = bb.max()[2] + (perturbVec[2] + ROOTVSMALL); + } + } + + if (debug) + { + if (pushInside != bb.contains(perturbedPt)) + { + FatalErrorIn("indexedOctree<Type>::pushPoint(..)") + << "pushed point:" << pt << " on face:" << faceString(faceID) + << " to:" << perturbedPt + << " wanted side:" << pushInside + << " obtained side:" << bb.contains(perturbedPt) + << " of bb:" << bb + << abort(FatalError); + } + } + + return perturbedPt; +} + + +// Guarantees that if pt is on a face it gets perturbed so it is away +// from the face edges. +// If pt is not on a face does nothing. +template <class Type> +Foam::point Foam::indexedOctree<Type>::pushPointIntoFace +( + const treeBoundBox& bb, + const vector& dir, // end-start + const point& pt +) +{ + if (debug) + { + if (bb.posBits(pt) != 0) + { + FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)") + << " bb:" << bb << endl + << "does not contain point " << pt << abort(FatalError); + } + } + + + // Handle two cases: + // - point exactly on multiple faces. Push away from all but one. + // - point on a single face. Push away from edges of face. + + direction ptFaceID = bb.faceBits(pt); + + direction nFaces = 0; + FixedList<direction, 3> faceIndices; + + if (ptFaceID & treeBoundBox::LEFTBIT) + { + faceIndices[nFaces++] = treeBoundBox::LEFT; + } + else if (ptFaceID & treeBoundBox::RIGHTBIT) + { + faceIndices[nFaces++] = treeBoundBox::RIGHT; + } + + if (ptFaceID & treeBoundBox::BOTTOMBIT) + { + faceIndices[nFaces++] = treeBoundBox::BOTTOM; + } + else if (ptFaceID & treeBoundBox::TOPBIT) + { + faceIndices[nFaces++] = treeBoundBox::TOP; + } + + if (ptFaceID & treeBoundBox::BACKBIT) + { + faceIndices[nFaces++] = treeBoundBox::BACK; + } + else if (ptFaceID & treeBoundBox::FRONTBIT) + { + faceIndices[nFaces++] = treeBoundBox::FRONT; + } + + + // Determine the face we want to keep the point on + + direction keepFaceID; + + if (nFaces == 0) + { + // Return original point + return pt; + } + else if (nFaces == 1) + { + keepFaceID = faceIndices[0]; + } + else + { + // Determine best face out of faceIndices[0 .. nFaces-1]. + // The best face is the one most perpendicular to the ray direction. + + keepFaceID = faceIndices[0]; + scalar maxInproduct = mag(treeBoundBox::faceNormals[keepFaceID] & dir); + + for (direction i = 1; i < nFaces; i++) + { + direction face = faceIndices[i]; + scalar s = mag(treeBoundBox::faceNormals[face] & dir); + if (s > maxInproduct) + { + maxInproduct = s; + keepFaceID = face; + } + } + } + + + // 1. Push point into bb, away from all corners + + point facePoint(pushPoint(bb, pt, true)); + direction faceID = 0; + + // 2. Snap it back onto the preferred face + + if (keepFaceID == treeBoundBox::LEFT) + { + facePoint.x() = bb.min().x(); + faceID = treeBoundBox::LEFTBIT; + } + else if (keepFaceID == treeBoundBox::RIGHT) + { + facePoint.x() = bb.max().x(); + faceID = treeBoundBox::RIGHTBIT; + } + else if (keepFaceID == treeBoundBox::BOTTOM) + { + facePoint.y() = bb.min().y(); + faceID = treeBoundBox::BOTTOMBIT; + } + else if (keepFaceID == treeBoundBox::TOP) + { + facePoint.y() = bb.max().y(); + faceID = treeBoundBox::TOPBIT; + } + else if (keepFaceID == treeBoundBox::BACK) + { + facePoint.z() = bb.min().z(); + faceID = treeBoundBox::BACKBIT; + } + else if (keepFaceID == treeBoundBox::FRONT) + { + facePoint.z() = bb.max().z(); + faceID = treeBoundBox::FRONTBIT; + } + + + if (debug) + { + if (faceID != bb.faceBits(facePoint)) + { + FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)") + << "Pushed point from " << pt + << " on face:" << ptFaceID << " of bb:" << bb << endl + << "onto " << facePoint + << " on face:" << faceID + << " which is not consistent with geometric face " + << bb.faceBits(facePoint) + << abort(FatalError); + } + if (bb.posBits(facePoint) != 0) + { + FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)") + << " bb:" << bb << endl + << "does not contain perturbed point " + << facePoint << abort(FatalError); + } + } + + + return facePoint; +} + + +//// Takes a bb and a point on the outside of the bb. Checks if on multiple faces +//// and if so perturbs point so it is only on one face. +//template <class Type> +//void Foam::indexedOctree<Type>::checkMultipleFaces +//( +// const treeBoundBox& bb, +// const vector& dir, // end-start +// pointIndexHit& faceHitInfo, +// direction& faceID +//) +//{ +// // Do the quick elimination of no or one face. +// if +// ( +// (faceID == 0) +// || (faceID == treeBoundBox::LEFTBIT) +// || (faceID == treeBoundBox::RIGHTBIT) +// || (faceID == treeBoundBox::BOTTOMBIT) +// || (faceID == treeBoundBox::TOPBIT) +// || (faceID == treeBoundBox::BACKBIT) +// || (faceID == treeBoundBox::FRONTBIT) +// ) +// { +// return; +// } +// +// +// // Check the direction of vector w.r.t. faces being intersected. +// FixedList<scalar, 6> inproducts(-GREAT); +// +// direction nFaces = 0; +// +// if (faceID & treeBoundBox::LEFTBIT) +// { +// inproducts[treeBoundBox::LEFT] = mag +// ( +// treeBoundBox::faceNormals[treeBoundBox::LEFT] +// & dir +// ); +// nFaces++; +// } +// if (faceID & treeBoundBox::RIGHTBIT) +// { +// inproducts[treeBoundBox::RIGHT] = mag +// ( +// treeBoundBox::faceNormals[treeBoundBox::RIGHT] +// & dir +// ); +// nFaces++; +// } +// +// if (faceID & treeBoundBox::BOTTOMBIT) +// { +// inproducts[treeBoundBox::BOTTOM] = mag +// ( +// treeBoundBox::faceNormals[treeBoundBox::BOTTOM] +// & dir +// ); +// nFaces++; +// } +// if (faceID & treeBoundBox::TOPBIT) +// { +// inproducts[treeBoundBox::TOP] = mag +// ( +// treeBoundBox::faceNormals[treeBoundBox::TOP] +// & dir +// ); +// nFaces++; +// } +// +// if (faceID & treeBoundBox::BACKBIT) +// { +// inproducts[treeBoundBox::BACK] = mag +// ( +// treeBoundBox::faceNormals[treeBoundBox::BACK] +// & dir +// ); +// nFaces++; +// } +// if (faceID & treeBoundBox::FRONTBIT) +// { +// inproducts[treeBoundBox::FRONT] = mag +// ( +// treeBoundBox::faceNormals[treeBoundBox::FRONT] +// & dir +// ); +// nFaces++; +// } +// +// if (nFaces == 0 || nFaces == 1 || nFaces > 3) +// { +// FatalErrorIn("indexedOctree<Type>::checkMultipleFaces(..)") +// << "Problem : nFaces:" << nFaces << abort(FatalError); +// } +// +// // Keep point on most perpendicular face; shift it away from the aligned +// // ones. +// // E.g. line hits top and left face: +// // a +// // ----+----+ +// // | | +// // | | +// // +----+ +// // Shift point down (away from top): +// // +// // a+----+ +// // ----| | +// // | | +// // +----+ +// +// label maxIndex = -1; +// scalar maxInproduct = -GREAT; +// +// for (direction i = 0; i < 6; i++) +// { +// if (inproducts[i] > maxInproduct) +// { +// maxInproduct = inproducts[i]; +// maxIndex = i; +// } +// } +// +// if (maxIndex == -1) +// { +// FatalErrorIn("indexedOctree<Type>::checkMultipleFaces(..)") +// << "Problem maxIndex:" << maxIndex << " inproducts:" << inproducts +// << abort(FatalError); +// } +// +// const point oldPoint(faceHitInfo.rawPoint()); +// const direction oldFaceID = faceID; +// +// // 1. Push point into bb, away from all corners +// +// faceHitInfo.rawPoint() = pushPoint(bb, oldFaceID, oldPoint, true); +// +// // 2. Snap it back onto the preferred face +// +// if (maxIndex == treeBoundBox::LEFT) +// { +// faceHitInfo.rawPoint().x() = bb.min().x(); +// faceID = treeBoundBox::LEFTBIT; +// } +// else if (maxIndex == treeBoundBox::RIGHT) +// { +// faceHitInfo.rawPoint().x() = bb.max().x(); +// faceID = treeBoundBox::RIGHTBIT; +// } +// else if (maxIndex == treeBoundBox::BOTTOM) +// { +// faceHitInfo.rawPoint().y() = bb.min().y(); +// faceID = treeBoundBox::BOTTOMBIT; +// } +// else if (maxIndex == treeBoundBox::TOP) +// { +// faceHitInfo.rawPoint().y() = bb.max().y(); +// faceID = treeBoundBox::TOPBIT; +// } +// else if (maxIndex == treeBoundBox::BACK) +// { +// faceHitInfo.rawPoint().z() = bb.min().z(); +// faceID = treeBoundBox::BACKBIT; +// } +// else if (maxIndex == treeBoundBox::FRONT) +// { +// faceHitInfo.rawPoint().z() = bb.max().z(); +// faceID = treeBoundBox::FRONTBIT; +// } +// +// Pout<< "From ray:" << dir +// << " from point:" << oldPoint +// << " on faces:" << faceString(oldFaceID) +// << " of bb:" << bb +// << " with inprods:" << inproducts +// << " maxIndex:" << maxIndex << endl +// << "perturbed to point:" << faceHitInfo.rawPoint() +// << " on face:" << faceString(faceID) +// << endl; +// +// +// if (debug) +// { +// if (faceID != bb.faceBits(faceHitInfo.rawPoint())) +// { +// FatalErrorIn("indexedOctree<Type>::checkMultipleFaces(..)") +// << "Pushed point from " << oldPoint +// << " on face:" << oldFaceID << " of bb:" << bb << endl +// << "onto " << faceHitInfo.rawPoint() +// << " on face:" << faceID +// << " which is not consistent with geometric face " +// << bb.faceBits(faceHitInfo.rawPoint()) +// << abort(FatalError); +// } +// } +//} + + +// Get parent node and octant. Return false if top of tree reached. +template <class Type> +bool Foam::indexedOctree<Type>::walkToParent +( + const label nodeI, + const direction octant, + + label& parentNodeI, + label& parentOctant +) const +{ + parentNodeI = nodes_[nodeI].parent_; + + if (parentNodeI == -1) + { + // Reached edge of tree + return false; + } + + const node& parentNode = nodes_[parentNodeI]; + + // Find octant nodeI is in. + parentOctant = 255; + + for (direction i = 0; i < parentNode.subNodes_.size(); i++) + { + labelBits index = parentNode.subNodes_[i]; + + if (isNode(index) && getNode(index) == nodeI) + { + parentOctant = i; + break; + } + } + + if (parentOctant == 255) + { + FatalErrorIn("walkToParent(..)") + << "Problem: no parent found for octant:" << octant + << " node:" << nodeI + << abort(FatalError); + } + + return true; +} + + // Walk tree to neighbouring node. Gets current position as // node and octant in this node and walks in the direction given by -// the faceID (one of treeBoundBox::LEFTBIT, RIGHTBIT etc.) +// the facePointBits (combination of treeBoundBox::LEFTBIT, TOPBIT etc.) // Returns false if edge of tree hit. template <class Type> bool Foam::indexedOctree<Type>::walkToNeighbour ( const point& facePoint, - const direction faceID, // direction to walk in + const direction faceID, // face(s) that facePoint is on label& nodeI, direction& octant ) const { + label oldNodeI = nodeI; + direction oldOctant = octant; + // Find out how to test for octant. Say if we want to go left we need // to traverse up the tree until we hit a node where our octant is // on the right. + // Coordinate direction to test + const direction X = treeBoundBox::RIGHTHALF; + const direction Y = treeBoundBox::TOPHALF; + const direction Z = treeBoundBox::FRONTHALF; + direction octantMask = 0; - direction valueMask = 0; + direction wantedValue = 0; if ((faceID & treeBoundBox::LEFTBIT) != 0) { - // We want to go left so check if in right octant. - octantMask |= treeBoundBox::RIGHTHALF; - valueMask |= treeBoundBox::RIGHTHALF; + // We want to go left so check if in right octant (i.e. x-bit is set) + octantMask |= X; + wantedValue |= X; } else if ((faceID & treeBoundBox::RIGHTBIT) != 0) { - octantMask |= treeBoundBox::RIGHTHALF; // valueMask already 0 + octantMask |= X; // wantedValue already 0 } if ((faceID & treeBoundBox::BOTTOMBIT) != 0) { - octantMask |= treeBoundBox::TOPHALF; - valueMask |= treeBoundBox::TOPHALF; + // Want to go down so check for y-bit set. + octantMask |= Y; + wantedValue |= Y; } else if ((faceID & treeBoundBox::TOPBIT) != 0) { - octantMask |= treeBoundBox::TOPHALF; + // Want to go up so check for y-bit not set. + octantMask |= Y; } if ((faceID & treeBoundBox::BACKBIT) != 0) { - octantMask |= treeBoundBox::FRONTHALF; - valueMask |= treeBoundBox::FRONTHALF; + octantMask |= Z; + wantedValue |= Z; } else if ((faceID & treeBoundBox::FRONTBIT) != 0) { - octantMask |= treeBoundBox::FRONTHALF; + octantMask |= Z; } + // So now we have the coordinate directions in the octant we need to check + // and the resulting value. + + /* + // +---+---+ + // | | | + // | | | + // | | | + // +---+-+-+ + // | | | | + // | a+-+-+ + // | |\| | + // +---+-+-+ + // \ + // + // e.g. ray is at (a) in octant 0(or 4) with faceIDs : LEFTBIT+TOPBIT. + // If we would be in octant 1(or 5) we could go to the correct octant + // in the same node by just flipping the x and y bits (exoring). + // But if we are not in octant 1/5 we have to go up until we are. + // In general for leftbit+topbit: + // - we have to check for x and y : octantMask = 011 + // - the checked bits have to be : wantedValue = ?01 + */ + + //Pout<< "For point " << facePoint << endl; + // Go up until we have chance to cross to the wanted direction - while (valueMask != (octant & octantMask)) + while (wantedValue != (octant & octantMask)) { - label parentNodeI = nodes_[nodeI].parent_; + // Go up to the parent. - if (parentNodeI == -1) + // Remove the directions that are not on the boundary of the parent. + // See diagram above + if (wantedValue & X) // && octantMask&X { - // Reached edge of tree - return false; + // Looking for right octant. + if (octant & X) + { + // My octant is one of the left ones so punch out the x check + octantMask &= ~X; + wantedValue &= ~X; + } + } + else + { + if (!(octant & X)) + { + // My octant is right but I want to go left. + octantMask &= ~X; + wantedValue &= ~X; + } } - const node& parentNode = nodes_[parentNodeI]; - - // Find octant nodeI is in. - direction parentOctant = 255; - - for (direction i = 0; i < parentNode.subNodes_.size(); i++) + if (wantedValue & Y) { - labelBits index = parentNode.subNodes_[i]; + if (octant & Y) + { + octantMask &= ~Y; + wantedValue &= ~Y; + } + } + else + { + if (!(octant & Y)) + { + octantMask &= ~Y; + wantedValue &= ~Y; + } + } - if (isNode(index) && getNode(index) == nodeI) + if (wantedValue & Z) + { + if (octant & Z) + { + octantMask &= ~Z; + wantedValue &= ~Z; + } + } + else + { + if (!(octant & Z)) { - parentOctant = i; - break; + octantMask &= ~Z; + wantedValue &= ~Z; } } - if (parentOctant == 255) + + label parentNodeI; + label parentOctant; + walkToParent(nodeI, octant, parentNodeI, parentOctant); + + if (parentNodeI == -1) { - FatalErrorIn("walkToNeighbour") - << abort(FatalError); + // Reached edge of tree + return false; } + + //Pout<< " walked from node:" << nodeI << " octant:" << octant + // << " bb:" << nodes_[nodeI].bb_.subBbox(octant) << endl + // << " to:" << parentNodeI << " octant:" << parentOctant + // << " bb:" << nodes_[parentNodeI].bb_.subBbox(parentOctant) + // << endl; + // + //Pout<< " octantMask:" << octantMask + // << " wantedValue:" << wantedValue << endl; + nodeI = parentNodeI; octant = parentOctant; } - // So now we hit the correct parent node. Switch to the correct octant + // So now we hit the correct parent node. Switch to the correct octant. + // Is done by jumping to the 'other half' so if e.g. in x direction in + // right half we now jump to the left half. octant ^= octantMask; + //Pout<< " to node:" << nodeI << " octant:" << octant + // << " subBb:" <<subBbox(nodeI, octant) << endl; + + + if (debug) + { + const treeBoundBox subBb(subBbox(nodeI, octant)); + + if (!subBb.contains(facePoint)) + { + FatalErrorIn("indexedOctree<Type>::walkToNeighbour(..)") + << "When searching for " << facePoint + << " ended up in node:" << nodeI + << " octant:" << octant + << " with bb:" << subBb + << abort(FatalError); + } + } + + // See if we need to travel down. Note that we already go into the - // the first level ourselves (instead of having findNode decide) since - // the facePoint is now exactly on the mid of the node so there could - // be truncation problems. + // the first level ourselves (instead of having findNode decide) labelBits index = nodes_[nodeI].subNodes_[octant]; if (isNode(index)) @@ -778,49 +1499,82 @@ bool Foam::indexedOctree<Type>::walkToNeighbour octant = getOctant(node); } + + if (debug) + { + const treeBoundBox subBb(subBbox(nodeI, octant)); + + if (nodeI == oldNodeI && octant == oldOctant) + { + FatalErrorIn("indexedOctree<Type>::walkToNeighbour(..)") + << "Did not go to neighbour when searching for " << facePoint + << endl + << " starting from face:" << faceString(faceID) + << " node:" << nodeI + << " octant:" << octant + << " bb:" << subBb + << abort(FatalError); + } + + if (!subBb.contains(facePoint)) + { + FatalErrorIn("indexedOctree<Type>::walkToNeighbour(..)") + << "When searching for " << facePoint + << " ended up in node:" << nodeI + << " octant:" << octant + << " bb:" << subBb + << abort(FatalError); + } + } + + return true; } -// Return unique number for the face of a bounding box a point is on. -// (number is single bit but not really nessecary) -// Return 0 if point not on any face of bb. template <class Type> -Foam::direction Foam::indexedOctree<Type>::getFace +Foam::word Foam::indexedOctree<Type>::faceString ( - const treeBoundBox& bb, - const point& pt + const direction faceID ) { - direction faceID = 0; + word desc; - if (pt.x() <= bb.min().x()) + if (faceID == 0) { - faceID |= treeBoundBox::LEFTBIT; + desc = "noFace"; } - if (pt.x() >= bb.max().x()) + if (faceID & treeBoundBox::LEFTBIT) { - faceID |= treeBoundBox::RIGHTBIT; + if (!desc.empty()) desc += "+"; + desc += "left"; } - - if (pt.y() <= bb.min().y()) + if (faceID & treeBoundBox::RIGHTBIT) { - faceID |= treeBoundBox::BOTTOMBIT; + if (!desc.empty()) desc += "+"; + desc += "right"; } - if (pt.y() >= bb.max().y()) + if (faceID & treeBoundBox::BOTTOMBIT) { - faceID |= treeBoundBox::TOPBIT; + if (!desc.empty()) desc += "+"; + desc += "bottom"; } - - if (pt.z() <= bb.min().z()) + if (faceID & treeBoundBox::TOPBIT) { - faceID |= treeBoundBox::BACKBIT; + if (!desc.empty()) desc += "+"; + desc += "top"; } - if (pt.z() >= bb.max().z()) + if (faceID & treeBoundBox::BACKBIT) { - faceID |= treeBoundBox::FRONTBIT; + if (!desc.empty()) desc += "+"; + desc += "back"; } - return faceID; + if (faceID & treeBoundBox::FRONTBIT) + { + if (!desc.empty()) desc += "+"; + desc += "front"; + } + return desc; } @@ -829,21 +1583,37 @@ Foam::direction Foam::indexedOctree<Type>::getFace // hitInfo.point = point on shape // Else return a miss and the bounding box face hit: // hitInfo.point = coordinate of intersection of ray with bounding box -// faceID = index of bounding box face +// hitBits = posbits of point on bounding box template <class Type> void Foam::indexedOctree<Type>::traverseNode ( const bool findAny, + const point& treeStart, + const vector& treeVec, + const point& start, const point& end, - const vector& dir, const label nodeI, const direction octant, pointIndexHit& hitInfo, - direction& faceID + direction& hitBits ) const { + if (debug) + { + const treeBoundBox octantBb(subBbox(nodeI, octant)); + + if (octantBb.posBits(start) != 0) + { + FatalErrorIn("indexedOctree<Type>::traverseNode(..)") + << "Node:" << nodeI << " octant:" << octant + << " bb:" << octantBb << endl + << "does not contain point " << start << abort(FatalError); + } + } + + const node& nod = nodes_[nodeI]; labelBits index = nod.subNodes_[octant]; @@ -909,49 +1679,72 @@ void Foam::indexedOctree<Type>::traverseNode // Nothing intersected in this node // Traverse to end of node. Do by ray tracing back from end and finding // intersection with bounding box of node. + // start point is now considered to be inside bounding box. + + const treeBoundBox octantBb(subBbox(nodeI, octant)); point pt; + bool intersected = octantBb.intersects + ( + end, //treeStart, + (start-end), //treeVec, - if (isNode(index)) - { - const treeBoundBox& subBb = nodes_[getNode(index)].bb_; + end, + start, - if (!subBb.intersects(end, start, pt)) - { - faceID = 0; + pt, + hitBits + ); - FatalErrorIn("indexedOctree<Type>::traverseNode(..)") - << "Did not hit side of box " << subBb - << " with ray from " << start << " to " << end - << abort(FatalError); - } - else - { - faceID = getFace(subBb, pt); - } + + if (intersected) + { + // Return miss. Set misspoint to face. + hitInfo.setPoint(pt); } else { - const treeBoundBox subBb(nod.bb_.subBbox(octant)); + // Rare case: did not find intersection of ray with octantBb. Can + // happen if end is on face/edge of octantBb. Do like + // lagrangian and re-track with perturbed vector (slightly pushed out + // of bounding box) - if (!subBb.intersects(end, start, pt)) - { - faceID = 0; + point perturbedEnd(pushPoint(octantBb, end, false)); - FatalErrorIn("indexedOctree<Type>::traverseNode(..)") - << "Did not hit side of box " << subBb - << " with ray from " << start << " to " << end - << abort(FatalError); - } - else + + //if (debug) { - faceID = getFace(subBb, pt); + // Dump octantBb to obj + writeOBJ(nodeI, octant); + // Dump ray to obj as well + { + OFstream str("ray.obj"); + meshTools::writeOBJ(str, start); + meshTools::writeOBJ(str, end); + str << "l 1 2" << nl; + } + WarningIn("indexedOctree<Type>::traverseNode(..)") + << "Did not intersect ray from endpoint:" << end + << " to startpoint:" << start + << " with bounding box:" << octantBb << nl + << "Re-intersecting with perturbed endpoint:" << perturbedEnd + << endl; } - } + traverseNode + ( + findAny, + treeStart, + treeVec, + start, + perturbedEnd, + nodeI, + octant, - // Return miss. Set misspoint to face. - hitInfo.setPoint(pt); + hitInfo, + hitBits + ); + } } @@ -963,40 +1756,75 @@ Foam::pointIndexHit Foam::indexedOctree<Type>::findLine const point& treeStart, const point& treeEnd, const label startNodeI, - const direction startOctant + const direction startOctant, + const bool verbose ) const { - const vector dir(treeEnd - treeStart); + const vector treeVec(treeEnd - treeStart); // Current node as parent+octant label nodeI = startNodeI; direction octant = startOctant; + if (verbose) + { + Pout<< "findLine : treeStart:" << treeStart + << " treeEnd:" << treeEnd << endl + << "node:" << nodeI + << " octant:" << octant + << " bb:" << subBbox(nodeI, octant) << endl; + } + // Current position. Initialize to miss pointIndexHit hitInfo(false, treeStart, -1); - // Side of current bounding box current point is on - direction faceID = 0; - - while (true) + //while (true) + label i = 0; + for (; i < 100000; i++) { + if (verbose) + { + Pout<< "iter:" << i + << " at startPoint:" << hitInfo.rawPoint() << endl + << " node:" << nodeI + << " octant:" << octant + << " bb:" << subBbox(nodeI, octant) << endl; + } + + // Ray-trace to end of current node. Updates point (either on triangle // in case of hit or on node bounding box in case of miss) - point startPoint(hitInfo.rawPoint()); + const treeBoundBox octantBb(subBbox(nodeI, octant)); + + // Make sure point is away from any edges/corners + point startPoint + ( + pushPointIntoFace + ( + octantBb, + treeVec, + hitInfo.rawPoint() + ) + ); + + // Faces of current bounding box current point is on + direction hitFaceID = 0; traverseNode ( findAny, + treeStart, + treeVec, + startPoint, // Note: pass in copy since hitInfo // also used in return value. - treeEnd, - dir, + treeEnd, // pass in overall end so is nicely outside bb nodeI, octant, hitInfo, - faceID + hitFaceID ); // Did we hit a triangle? @@ -1005,29 +1833,48 @@ Foam::pointIndexHit Foam::indexedOctree<Type>::findLine break; } - if (faceID == 0) + if (hitFaceID == 0) { - // Was never inside the tree. Return miss. + // endpoint inside the tree. Return miss. break; } - //Pout<< "findLine : treeStart:" << treeStart - // << " treeEnd:" << treeEnd - // << " tracked from " << startPoint << " to edge of nodeBb:" - // << hitInfo.missPoint() - // << " node:" << nodeI << " octant:" << octant - // << " subBb:" - // << nodes_[nodeI].bb_.subBbox(octant) - // << endl; + + if (verbose) + { + Pout<< " iter:" << i + << " hit face:" << faceString(hitFaceID) + << " at:" << hitInfo.rawPoint() << nl + << " node:" << nodeI + << " octant:" << octant + << " bb:" << subBbox(nodeI, octant) << nl + << " walking to neighbour containing:" + << pushPoint + ( + octantBb, + hitFaceID, + hitInfo.rawPoint(), + false // push outside of octantBb + ) + << endl; + } // Nothing hit so we are on face of bounding box (given as node+octant+ - // faceID). Traverse to neighbouring node. + // position bits). Traverse to neighbouring node. Use slightly perturbed + // point. bool ok = walkToNeighbour ( - hitInfo.rawPoint(), // point on face - faceID, // direction to walk in + pushPoint + ( + octantBb, + hitFaceID, + hitInfo.rawPoint(), + false // push outside of octantBb + ), + hitFaceID, // face(s) that hitInfo is on + nodeI, octant ); @@ -1037,7 +1884,53 @@ Foam::pointIndexHit Foam::indexedOctree<Type>::findLine // Hit the edge of the tree. Return miss. break; } + + if (verbose) + { + const treeBoundBox octantBb(subBbox(nodeI, octant)); + Pout<< " walked for point:" << hitInfo.rawPoint() << endl + << " to neighbour node:" << nodeI + << " octant:" << octant + << " face:" << faceString(octantBb.faceBits(hitInfo.rawPoint())) + << " of octantBb:" << octantBb << endl + << endl; + } + } + + if (i == 100000) + { + // Probably in loop. + if (!verbose) + { + // Redo intersection but now with verbose flag switched on. + return findLine + ( + findAny, + treeStart, + treeEnd, + startNodeI, + startOctant, + true //verbose + ); + } + if (debug) + { + FatalErrorIn("indexedOctree<Type>::findLine(..)") + << "Got stuck in loop raytracing from:" << treeStart + << " to:" << treeEnd << endl + << "inside top box:" << subBbox(startNodeI, startOctant) + << abort(FatalError); + } + else + { + WarningIn("indexedOctree<Type>::findLine(..)") + << "Got stuck in loop raytracing from:" << treeStart + << " to:" << treeEnd << endl + << "inside top box:" << subBbox(startNodeI, startOctant) + << endl; + } } + return hitInfo; } @@ -1057,6 +1950,9 @@ Foam::pointIndexHit Foam::indexedOctree<Type>::findLine { const treeBoundBox& treeBb = nodes_[0].bb_; + // No effort is made to deal with points which are on edge of tree + // bounding box for now. + direction startBit = treeBb.posBits(start); direction endBit = treeBb.posBits(end); @@ -1066,6 +1962,9 @@ Foam::pointIndexHit Foam::indexedOctree<Type>::findLine return pointIndexHit(false, vector::zero, -1); } + + // Trim segment to treeBb + point trackStart(start); point trackEnd(end); @@ -1087,6 +1986,7 @@ Foam::pointIndexHit Foam::indexedOctree<Type>::findLine } } + // Find lowest level tree node that start is in. labelBits index = findNode(0, trackStart); @@ -1234,32 +2134,6 @@ void Foam::indexedOctree<Type>::writeOBJ str<< "l " << e[0]+pointVertI+1 << ' ' << e[1]+pointVertI+1 << nl; } - - - //// Dump triangles - //if (isContent(index)) - //{ - // const labelList& indices = contents_[getContent(index)]; - // const triSurface& surf = shapes_.surface(); - // const pointField& points = surf.points(); - // - // forAll(indices, i) - // { - // label shapeI = indices[i]; - // - // const labelledTri& f = surf[shapeI]; - // - // meshTools::writeOBJ(str, points[f[0]]); - // vertI++; - // meshTools::writeOBJ(str, points[f[1]]); - // vertI++; - // meshTools::writeOBJ(str, points[f[2]]); - // vertI++; - // - // str<< "l " << vertI-2 << ' ' << vertI-1 << ' ' << vertI << ' ' - // << vertI-2 << nl; - // } - //} } @@ -1305,6 +2179,14 @@ Foam::indexedOctree<Type>::indexedOctree contents_(0), nodeTypes_(0) { + if (debug) + { + Pout<< "indexedOctree<Type>::indexedOctree:" << nl + << " shapes:" << shapes.size() << nl + << " bb:" << bb << nl + << endl; + } + if (shapes.size() == 0) { return; @@ -1409,7 +2291,6 @@ Foam::indexedOctree<Type>::indexedOctree nodes_.transfer(nodes); nodes.clear(); - if (debug) { label nEntries = 0; @@ -1418,14 +2299,18 @@ Foam::indexedOctree<Type>::indexedOctree nEntries += contents_[i].size(); } - Pout<< "indexedOctree<Type>::indexedOctree : finished construction:" + Pout<< "indexedOctree<Type>::indexedOctree" + << " : finished construction of tree of:" << shapes.typeName << nl + << " bb:" << this->bb() << nl << " shapes:" << shapes.size() << nl << " nLevels:" << nLevels << nl << " treeNodes:" << nodes_.size() << nl << " nEntries:" << nEntries << nl - << " per treeLeaf:" << nEntries/contents.size() << nl - << " per shape (duplicity):" << nEntries/shapes.size() << nl + << " per treeLeaf:" + << scalar(nEntries)/contents.size() << nl + << " per shape (duplicity):" + << scalar(nEntries)/shapes.size() << nl << endl; } } @@ -1447,6 +2332,13 @@ Foam::indexedOctree<Type>::indexedOctree // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // +template <class Type> +Foam::scalar& Foam::indexedOctree<Type>::perturbTol() +{ + return perturbTol_; +} + + template <class Type> Foam::pointIndexHit Foam::indexedOctree<Type>::findNearest ( @@ -1570,6 +2462,16 @@ Foam::labelBits Foam::indexedOctree<Type>::findNode const node& nod = nodes_[nodeI]; + if (debug) + { + if (!nod.bb_.contains(sample)) + { + FatalErrorIn("findNode(..)") + << "Cannot find " << sample << " in node " << nodeI + << abort(FatalError); + } + } + direction octant = nod.bb_.subOctant(sample); labelBits index = nod.subNodes_[octant]; diff --git a/src/meshTools/indexedOctree/indexedOctree.H b/src/meshTools/indexedOctree/indexedOctree.H index b4aad9a3052f520a6ffd599a921f31645f32e933..6c2bfa3c6e6f1408f6b80dfa6375ab60ba511522 100644 --- a/src/meshTools/indexedOctree/indexedOctree.H +++ b/src/meshTools/indexedOctree/indexedOctree.H @@ -128,6 +128,15 @@ public: private: + // Static data + + //- Relative peturbation tolerance. Determines when point is + // considered to be close to face/edge of bb of node. + // The tolerance is relative to the bounding box of the smallest + // node. + static scalar perturbTol_; + + // Private data //- Underlying shapes for geometric queries. @@ -144,8 +153,9 @@ private: // Private Member Functions - //- Like above but now bb is implicitly provided as parent bb + mid - // + octant + //- Helper: does bb intersect a sphere around sample? Or is any + // corner point of bb closer than nearestDistSqr to sample. + // (bb is implicitly provided as parent bb + octant) static bool overlaps ( const treeBoundBox& parentBb, @@ -215,6 +225,60 @@ private: point& nearestPoint ) const; + //- Return bbox of octant + treeBoundBox subBbox + ( + const label parentNodeI, + const direction octant + ) const; + + //- Helper: take a point on/close to face of bb and push it + // inside or outside of bb. + static point pushPoint + ( + const treeBoundBox&, + const point&, + const bool pushInside + ); + + //- Helper: take a point on face of bb and push it + // inside or outside of bb. + static point pushPoint + ( + const treeBoundBox&, + const direction, + const point&, + const bool pushInside + ); + + //- Helper: take point on face(s) of bb and push it away from + // edges of face. + static point pushPointIntoFace + ( + const treeBoundBox& bb, + const vector& dir, // end-start + const point& pt + ); + + ////- Push point on multiple faces away from any corner/edge. + //static void checkMultipleFaces + //( + // const treeBoundBox& bb, + // const vector& dir, // end-start + // pointIndexHit& faceHitInfo, + // direction& faceID + //); + + //- Walk to parent of node+octant. + bool walkToParent + ( + const label nodeI, + const direction octant, + + label& parentNodeI, + label& parentOctant + ) const; + //- Walk tree to neighbouring node. Return false if edge of tree // hit. bool walkToNeighbour @@ -225,8 +289,8 @@ private: direction& octant ) const; - //- Categorize point on bounding box. - static direction getFace(const treeBoundBox&, const point&); + //- Debug: return verbose the bounding box faces + static word faceString(const direction faceID); //- Traverse a node. If intersects a triangle return first // intersection point. @@ -235,9 +299,11 @@ private: void traverseNode ( const bool findAny, + const point& treeStart, + const vector& treeVec, + const point& start, const point& end, - const vector& dir, const label nodeI, const direction octantI, @@ -252,7 +318,8 @@ private: const point& treeStart, const point& treeEnd, const label startNodeI, - const direction startOctantI + const direction startOctantI, + const bool verbose = false ) const; //- Find any or nearest intersection of line between start and end. @@ -310,6 +377,10 @@ private: public: + //- Get the perturbation tolerance + static scalar& perturbTol(); + + // Constructors //- Construct null @@ -505,6 +576,7 @@ public: const point& sample ); + // Write //- Print tree. Either print all indices (printContent = true) or diff --git a/src/meshTools/indexedOctree/treeDataCell.H b/src/meshTools/indexedOctree/treeDataCell.H index 4f09188942e52ed86bdeccdbc7e8365013b4e0f9..100dcb62cf7659a852daf95532ec31f0e3bfde4a 100644 --- a/src/meshTools/indexedOctree/treeDataCell.H +++ b/src/meshTools/indexedOctree/treeDataCell.H @@ -37,9 +37,7 @@ SourceFiles #ifndef treeDataCell_H #define treeDataCell_H -#include "treeBoundBox.H" #include "treeBoundBoxList.H" -#include "labelList.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/meshTools/indexedOctree/treeDataEdge.C b/src/meshTools/indexedOctree/treeDataEdge.C index c4bb08f3744ac1f6360660ca037c4a0041debfd8..12f347c16483afff5664c6295b9211123f6c69f2 100644 --- a/src/meshTools/indexedOctree/treeDataEdge.C +++ b/src/meshTools/indexedOctree/treeDataEdge.C @@ -22,16 +22,15 @@ License along with OpenFOAM; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -Description - \*---------------------------------------------------------------------------*/ #include "treeDataEdge.H" #include "indexedOctree.H" -#include "polyMesh.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // +defineTypeNameAndDebug(Foam::treeDataEdge, 0); + // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // diff --git a/src/meshTools/indexedOctree/treeDataEdge.H b/src/meshTools/indexedOctree/treeDataEdge.H index 916bad870ec358ff4e2b6ff8ab13eab2bb6fb736..5dad366b3b624121c54dad883bc4c4259ef1ddb0 100644 --- a/src/meshTools/indexedOctree/treeDataEdge.H +++ b/src/meshTools/indexedOctree/treeDataEdge.H @@ -36,8 +36,6 @@ SourceFiles #ifndef treeDataEdge_H #define treeDataEdge_H -#include "treeBoundBox.H" -#include "pointField.H" #include "treeBoundBoxList.H" #include "linePointRef.H" diff --git a/src/meshTools/indexedOctree/treeDataPoint.C b/src/meshTools/indexedOctree/treeDataPoint.C index c64fc04ee584282fa9e74747a6f3700d4a1e5eb8..5303156518e93277e21f8b110de84f78456b9dc4 100644 --- a/src/meshTools/indexedOctree/treeDataPoint.C +++ b/src/meshTools/indexedOctree/treeDataPoint.C @@ -32,6 +32,11 @@ Description #include "polyMesh.H" #include "triangleFuncs.H" +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +defineTypeNameAndDebug(Foam::treeDataPoint, 0); + + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // Construct from components diff --git a/src/meshTools/indexedOctree/treeDataTriSurface.C b/src/meshTools/indexedOctree/treeDataTriSurface.C index 06a496ee881c9f71db430c8bd01fbd59416f28f7..ea519291e3a275351622082b35d45413ddab825d 100644 --- a/src/meshTools/indexedOctree/treeDataTriSurface.C +++ b/src/meshTools/indexedOctree/treeDataTriSurface.C @@ -22,8 +22,6 @@ License along with OpenFOAM; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -Description - \*---------------------------------------------------------------------------*/ #include "treeDataTriSurface.H" @@ -226,7 +224,7 @@ Foam::label Foam::treeDataTriSurface::getVolumeType if (!pHit.hit()) { - FatalErrorIn("treeDataTriSurface::getVolumeType") + FatalErrorIn("treeDataTriSurface::getVolumeType(..)") << "treeBb:" << treeBb << " sample:" << sample << " pHit:" << pHit @@ -238,7 +236,8 @@ Foam::label Foam::treeDataTriSurface::getVolumeType surface_, sample, pHit.index(), - pHit.hitPoint() + pHit.hitPoint(), + indexedOctree<treeDataTriSurface>::perturbTol() ); if (t == triSurfaceTools::UNKNOWN) @@ -255,12 +254,13 @@ Foam::label Foam::treeDataTriSurface::getVolumeType } else { - FatalErrorIn("treeDataTriSurface::getVolumeType") + FatalErrorIn("treeDataTriSurface::getVolumeType(..)") << "problem" << abort(FatalError); return indexedOctree<treeDataTriSurface>::UNKNOWN; } } + // Check if any point on triangle is inside cubeBb. bool Foam::treeDataTriSurface::overlaps ( @@ -305,6 +305,7 @@ bool Foam::treeDataTriSurface::overlaps // Now we have the difficult case: all points are outside but connecting // edges might go through cube. Use fast intersection of bounding box. + //return triangleFuncs::intersectBbExact(p0, p1, p2, cubeBb); return triangleFuncs::intersectBb(p0, p1, p2, cubeBb); } @@ -445,7 +446,15 @@ bool Foam::treeDataTriSurface::intersects const vector dir(end - start); - pointHit inter = tri.intersection(start, dir, intersection::HALF_RAY); + // Use relative tolerance (from octree) to determine intersection. + + pointHit inter = tri.intersection + ( + start, + dir, + intersection::HALF_RAY, + indexedOctree<treeDataTriSurface>::perturbTol() + ); if (inter.hit() && inter.distance() <= 1) { @@ -459,6 +468,16 @@ bool Foam::treeDataTriSurface::intersects { return false; } + + + //- Using exact intersections + //pointHit info = f.tri(points).intersectionExact(start, end); + // + //if (info.hit()) + //{ + // intersectionPoint = info.hitPoint(); + //} + //return info.hit(); } diff --git a/src/meshTools/meshSearch/meshSearch.C b/src/meshTools/meshSearch/meshSearch.C index ef1aa46f67430fc9cbb4b2870c334f51130ca556..2c803a277251bf72faff28f83dbd889d11fbeeef 100644 --- a/src/meshTools/meshSearch/meshSearch.C +++ b/src/meshTools/meshSearch/meshSearch.C @@ -27,9 +27,11 @@ License #include "meshSearch.H" #include "polyMesh.H" #include "indexedOctree.H" -#include "pointIndexHit.H" #include "DynamicList.H" #include "demandDrivenData.H" +#include "treeDataCell.H" +#include "treeDataFace.H" +#include "treeDataPoint.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // diff --git a/src/meshTools/meshSearch/meshSearch.H b/src/meshTools/meshSearch/meshSearch.H index 7b99a7159c5e6dfee2d1eff12a7697d72c564b1c..c8d44bdd489b045469538fbcb0179cbc59571b10 100644 --- a/src/meshTools/meshSearch/meshSearch.H +++ b/src/meshTools/meshSearch/meshSearch.H @@ -37,9 +37,6 @@ SourceFiles #ifndef meshSearch_H #define meshSearch_H -#include "treeDataCell.H" -#include "treeDataFace.H" -#include "treeDataPoint.H" #include "pointIndexHit.H" #include "Cloud.H" #include "passiveParticle.H" @@ -51,6 +48,10 @@ namespace Foam // Forward declaration of classes class polyMesh; +class treeDataCell; +class treeDataFace; +class treeDataPoint; +template<class Type> class indexedOctree; /*---------------------------------------------------------------------------*\ Class meshSearch Declaration diff --git a/src/meshTools/octree/treeBoundBox.C b/src/meshTools/octree/treeBoundBox.C index ce62c471924a26b1d138f2d49b0e6c91a42dd5b7..6133bc3106f9c3e8e07edd53b0d3e7a639211bda 100644 --- a/src/meshTools/octree/treeBoundBox.C +++ b/src/meshTools/octree/treeBoundBox.C @@ -309,12 +309,14 @@ bool Foam::treeBoundBox::overlaps // This makes sure that posBits tests 'inside' bool Foam::treeBoundBox::intersects ( + const point& overallStart, + const vector& overallVec, const point& start, const point& end, - point& pt + point& pt, + direction& ptOnFaces ) const { - const vector vec(end - start); const direction endBits = posBits(end); pt = start; @@ -325,80 +327,106 @@ bool Foam::treeBoundBox::intersects if (ptBits == 0) { // pt inside bb + ptOnFaces = faceBits(pt); return true; } if ((ptBits & endBits) != 0) { // pt and end in same block outside of bb + ptOnFaces = faceBits(pt); return false; } if (ptBits & LEFTBIT) { // Intersect with plane V=min, n=-1,0,0 - if (Foam::mag(vec.x()) > VSMALL) + if (Foam::mag(overallVec.x()) > VSMALL) + { + scalar s = (min().x() - overallStart.x())/overallVec.x(); + pt.x() = min().x(); + pt.y() = overallStart.y() + overallVec.y()*s; + pt.z() = overallStart.z() + overallVec.z()*s; + } + else { - scalar s = (min().x() - pt.x())/vec.x(); + // Vector not in x-direction. But still intersecting bb planes. + // So must be close - just snap to bb. pt.x() = min().x(); - pt.y() = pt.y() + vec.y()*s; - pt.z() = pt.z() + vec.z()*s; } } - if (ptBits & RIGHTBIT) + else if (ptBits & RIGHTBIT) { // Intersect with plane V=max, n=1,0,0 - if (Foam::mag(vec.x()) > VSMALL) + if (Foam::mag(overallVec.x()) > VSMALL) + { + scalar s = (max().x() - overallStart.x())/overallVec.x(); + pt.x() = max().x(); + pt.y() = overallStart.y() + overallVec.y()*s; + pt.z() = overallStart.z() + overallVec.z()*s; + } + else { - scalar s = (max().x() - pt.x())/vec.x(); pt.x() = max().x(); - pt.y() = pt.y() + vec.y()*s; - pt.z() = pt.z() + vec.z()*s; } } - - if (ptBits & BOTTOMBIT) + else if (ptBits & BOTTOMBIT) { // Intersect with plane V=min, n=0,-1,0 - if (Foam::mag(vec.y()) > VSMALL) + if (Foam::mag(overallVec.y()) > VSMALL) { - scalar s = (min().y() - pt.y())/vec.y(); - pt.x() = pt.x() + vec.x()*s; + scalar s = (min().y() - overallStart.y())/overallVec.y(); + pt.x() = overallStart.x() + overallVec.x()*s; pt.y() = min().y(); - pt.z() = pt.z() + vec.z()*s; + pt.z() = overallStart.z() + overallVec.z()*s; + } + else + { + pt.x() = min().y(); } } - if (ptBits & TOPBIT) + else if (ptBits & TOPBIT) { // Intersect with plane V=max, n=0,1,0 - if (Foam::mag(vec.y()) > VSMALL) + if (Foam::mag(overallVec.y()) > VSMALL) + { + scalar s = (max().y() - overallStart.y())/overallVec.y(); + pt.x() = overallStart.x() + overallVec.x()*s; + pt.y() = max().y(); + pt.z() = overallStart.z() + overallVec.z()*s; + } + else { - scalar s = (max().y() - pt.y())/vec.y(); - pt.x() = pt.x() + vec.x()*s; pt.y() = max().y(); - pt.z() = pt.z() + vec.z()*s; } } - - if (ptBits & BACKBIT) + else if (ptBits & BACKBIT) { // Intersect with plane V=min, n=0,0,-1 - if (Foam::mag(vec.z()) > VSMALL) + if (Foam::mag(overallVec.z()) > VSMALL) + { + scalar s = (min().z() - overallStart.z())/overallVec.z(); + pt.x() = overallStart.x() + overallVec.x()*s; + pt.y() = overallStart.y() + overallVec.y()*s; + pt.z() = min().z(); + } + else { - scalar s = (min().z() - pt.z())/vec.z(); - pt.x() = pt.x() + vec.x()*s; - pt.y() = pt.y() + vec.y()*s; pt.z() = min().z(); } } - if (ptBits & FRONTBIT) + else if (ptBits & FRONTBIT) { // Intersect with plane V=max, n=0,0,1 - if (Foam::mag(vec.z()) > VSMALL) + if (Foam::mag(overallVec.z()) > VSMALL) + { + scalar s = (max().z() - overallStart.z())/overallVec.z(); + pt.x() = overallStart.x() + overallVec.x()*s; + pt.y() = overallStart.y() + overallVec.y()*s; + pt.z() = max().z(); + } + else { - scalar s = (max().z() - pt.z())/vec.z(); - pt.x() = pt.x() + vec.x()*s; - pt.y() = pt.y() + vec.y()*s; pt.z() = max().z(); } } @@ -406,6 +434,18 @@ bool Foam::treeBoundBox::intersects } +bool Foam::treeBoundBox::intersects +( + const point& start, + const point& end, + point& pt +) const +{ + direction ptBits; + return intersects(start, end-start, start, end, pt, ptBits); +} + + // this.bb fully contains bb bool Foam::treeBoundBox::contains(const treeBoundBox& bb) const { @@ -452,6 +492,40 @@ bool Foam::treeBoundBox::contains(const vector& dir, const point& pt) const } +// Code position of pt on bounding box faces +Foam::direction Foam::treeBoundBox::faceBits(const point& pt) const +{ + direction faceBits = 0; + if (pt.x() == min().x()) + { + faceBits |= LEFTBIT; + } + else if (pt.x() == max().x()) + { + faceBits |= RIGHTBIT; + } + + if (pt.y() == min().y()) + { + faceBits |= BOTTOMBIT; + } + else if (pt.y() == max().y()) + { + faceBits |= TOPBIT; + } + + if (pt.z() == min().z()) + { + faceBits |= BACKBIT; + } + else if (pt.z() == max().z()) + { + faceBits |= FRONTBIT; + } + return faceBits; +} + + // Code position of point relative to box Foam::direction Foam::treeBoundBox::posBits(const point& pt) const { @@ -461,7 +535,7 @@ Foam::direction Foam::treeBoundBox::posBits(const point& pt) const { posBits |= LEFTBIT; } - if (pt.x() > max().x()) + else if (pt.x() > max().x()) { posBits |= RIGHTBIT; } @@ -470,7 +544,7 @@ Foam::direction Foam::treeBoundBox::posBits(const point& pt) const { posBits |= BOTTOMBIT; } - if (pt.y() > max().y()) + else if (pt.y() > max().y()) { posBits |= TOPBIT; } @@ -479,7 +553,7 @@ Foam::direction Foam::treeBoundBox::posBits(const point& pt) const { posBits |= BACKBIT; } - if (pt.z() > max().z()) + else if (pt.z() > max().z()) { posBits |= FRONTBIT; } diff --git a/src/meshTools/octree/treeBoundBox.H b/src/meshTools/octree/treeBoundBox.H index 77498b2935212cf1b49a29892a20e270657bdad9..69791e04a85b8ddac668cc924a0f46f48b67a5b4 100644 --- a/src/meshTools/octree/treeBoundBox.H +++ b/src/meshTools/octree/treeBoundBox.H @@ -120,12 +120,12 @@ public: enum faceBit { NOFACE = 0, - LEFTBIT = 0x1 << LEFT, - RIGHTBIT = 0x1 << RIGHT, - BOTTOMBIT = 0x1 << BOTTOM, - TOPBIT = 0x1 << TOP, - BACKBIT = 0x1 << BACK, - FRONTBIT = 0x1 << FRONT, + LEFTBIT = 0x1 << LEFT, //1 + RIGHTBIT = 0x1 << RIGHT, //2 + BOTTOMBIT = 0x1 << BOTTOM, //4 + TOPBIT = 0x1 << TOP, //8 + BACKBIT = 0x1 << BACK, //16 + FRONTBIT = 0x1 << FRONT, //32 }; //- Edges codes. @@ -265,9 +265,25 @@ public: //- Overlaps boundingSphere (centre + sqr(radius))? bool overlaps(const point&, const scalar radiusSqr) const; - //- Intersects segment; set point to intersection position, + //- Intersects segment; set point to intersection position and face, // return true if intersection found. - // (intPt argument used during calculation even if not intersecting) + // (pt argument used during calculation even if not intersecting). + // Calculates intersections from outside supplied vector + // (overallStart, overallVec). This is so when + // e.g. tracking through lots of consecutive boxes + // (typical octree) we're not accumulating truncation errors. Set + // to start, (end-start) if not used. + bool intersects + ( + const point& overallStart, + const vector& overallVec, + const point& start, + const point& end, + point& pt, + direction& ptBits + ) const; + + //- Like above but does not return faces point is on bool intersects ( const point& start, @@ -285,6 +301,9 @@ public: // dir would cause it to go inside. bool contains(const vector& dir, const point&) const; + //- Code position of pt on bounding box faces + direction faceBits(const point& pt) const; + //- Position of point relative to bounding box direction posBits(const point&) const; diff --git a/src/meshTools/triSurface/orientedSurface/orientedSurface.C b/src/meshTools/triSurface/orientedSurface/orientedSurface.C index 10e1fa8f2f930e9457352190159ea80584ef3623..113bdf58f4be9dc3b0317e7b0dfedd1441309df4 100644 --- a/src/meshTools/triSurface/orientedSurface/orientedSurface.C +++ b/src/meshTools/triSurface/orientedSurface/orientedSurface.C @@ -238,7 +238,8 @@ void Foam::orientedSurface::propagateOrientation s, samplePoint, nearestFaceI, - nearestPt + nearestPt, + 10*SMALL ); if (side == triSurfaceTools::UNKNOWN) diff --git a/src/meshTools/triSurface/triSurfaceTools/triSurfaceTools.C b/src/meshTools/triSurface/triSurfaceTools/triSurfaceTools.C index 08138f450be02188245c335841a6a3f638ae1974..b89afdab63b372cb73ad5839afec77febf4d14d0 100644 --- a/src/meshTools/triSurface/triSurfaceTools/triSurfaceTools.C +++ b/src/meshTools/triSurface/triSurfaceTools/triSurfaceTools.C @@ -2203,7 +2203,8 @@ Foam::triSurfaceTools::sideType Foam::triSurfaceTools::surfaceSide const triSurface& surf, const point& sample, const label nearestFaceI, // nearest face - const point& nearestPoint // nearest point on nearest face + const point& nearestPoint, // nearest point on nearest face + const scalar tol ) { const labelledTri& f = surf[nearestFaceI]; @@ -2217,7 +2218,7 @@ Foam::triSurfaceTools::sideType Foam::triSurfaceTools::surfaceSide points[f[0]], points[f[1]], points[f[2]] - ).classify(nearestPoint, 1E-6, nearType, nearLabel); + ).classify(nearestPoint, tol, nearType, nearLabel); if (nearType == triPointRef::NONE) { diff --git a/src/meshTools/triSurface/triSurfaceTools/triSurfaceTools.H b/src/meshTools/triSurface/triSurfaceTools/triSurfaceTools.H index 8ddac22a2994296ec86010bac901d3abe02d05d7..b88d460b77bbc934438df741bc351375eab62ce4 100644 --- a/src/meshTools/triSurface/triSurfaceTools/triSurfaceTools.H +++ b/src/meshTools/triSurface/triSurfaceTools/triSurfaceTools.H @@ -454,13 +454,14 @@ public: //- Given nearest point (to sample) on surface determines which side // sample is. Uses either face normal, edge normal or point normal - // (non-trivial). Feed in output of e.g. triangle::classify. + // (non-trivial). Uses triangle::classify. static sideType surfaceSide ( const triSurface& surf, const point& sample, const label nearestFaceI, // nearest face - const point& nearestPt // nearest point on nearest face + const point& nearestPt, // nearest point on nearest face + const scalar tol // tolerance for nearness test. ); // Triangulation of faces diff --git a/src/meshTools/triSurface/triangleFuncs/triangleFuncs.C b/src/meshTools/triSurface/triangleFuncs/triangleFuncs.C index be83b6326cc52d558ce6130ffac5d77c3388bc9c..1bef529b0325f6242c8ce98574eafe9b4b4c398b 100644 --- a/src/meshTools/triSurface/triangleFuncs/triangleFuncs.C +++ b/src/meshTools/triSurface/triangleFuncs/triangleFuncs.C @@ -22,8 +22,6 @@ License along with OpenFOAM; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -Description - \*---------------------------------------------------------------------------*/ #include "triangleFuncs.H" @@ -31,8 +29,6 @@ Description #include "treeBoundBox.H" #include "SortableList.H" #include "boolList.H" -#include "scalar.H" - // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // @@ -170,7 +166,6 @@ bool Foam::triangleFuncs::intersectAxesBundle } - // Intersect triangle with bounding box. Return true if // any of the faces of bb intersect triangle. // Note: so returns false if triangle inside bb. @@ -262,6 +257,272 @@ bool Foam::triangleFuncs::intersectBb } +//// Intersect triangle with bounding box. Return true if +//// any of the faces of bb intersect triangle. +//// Note: so returns false if triangle inside bb. +//bool Foam::triangleFuncs::intersectBbExact +//( +// const point& p0, +// const point& p1, +// const point& p2, +// const treeBoundBox& cubeBb +//) +//{ +// const point& min = cubeBb.min(); +// const point& max = cubeBb.max(); +// +// const point& cube0 = min; +// const point cube1(min.x(), min.y(), max.z()); +// const point cube2(max.x(), min.y(), max.z()); +// const point cube3(max.x(), min.y(), min.z()); +// +// const point cube4(min.x(), max.y(), min.z()); +// const point cube5(min.x(), max.y(), max.z()); +// const point& cube6 = max; +// const point cube7(max.x(), max.y(), min.z()); +// +// // Test intersection of triangle with twelve edges of box. +// { +// triPointRef tri(p0, p1, p2); +// if (tri.intersectionExact(cube0, cube1).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(cube1, cube2).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(cube2, cube3).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(cube3, cube0).hit()) +// { +// return true; +// } +// +// if (tri.intersectionExact(cube4, cube5).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(cube5, cube6).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(cube6, cube7).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(cube7, cube4).hit()) +// { +// return true; +// } +// +// if (tri.intersectionExact(cube0, cube4).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(cube1, cube5).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(cube2, cube6).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(cube3, cube7).hit()) +// { +// return true; +// } +// } +// // Test intersection of triangle edges with bounding box +// { +// triPointRef tri(cube0, cube1, cube2); +// if (tri.intersectionExact(p0, p1).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p1, p2).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p2, p0).hit()) +// { +// return true; +// } +// } +// { +// triPointRef tri(cube2, cube3, cube0); +// if (tri.intersectionExact(p0, p1).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p1, p2).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p2, p0).hit()) +// { +// return true; +// } +// } +// { +// triPointRef tri(cube4, cube5, cube6); +// if (tri.intersectionExact(p0, p1).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p1, p2).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p2, p0).hit()) +// { +// return true; +// } +// } +// { +// triPointRef tri(cube6, cube7, cube4); +// if (tri.intersectionExact(p0, p1).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p1, p2).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p2, p0).hit()) +// { +// return true; +// } +// } +// +// +// { +// triPointRef tri(cube4, cube5, cube1); +// if (tri.intersectionExact(p0, p1).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p1, p2).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p2, p0).hit()) +// { +// return true; +// } +// } +// { +// triPointRef tri(cube1, cube0, cube4); +// if (tri.intersectionExact(p0, p1).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p1, p2).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p2, p0).hit()) +// { +// return true; +// } +// } +// { +// triPointRef tri(cube7, cube6, cube2); +// if (tri.intersectionExact(p0, p1).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p1, p2).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p2, p0).hit()) +// { +// return true; +// } +// } +// { +// triPointRef tri(cube2, cube3, cube7); +// if (tri.intersectionExact(p0, p1).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p1, p2).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p2, p0).hit()) +// { +// return true; +// } +// } +// +// { +// triPointRef tri(cube0, cube4, cube7); +// if (tri.intersectionExact(p0, p1).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p1, p2).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p2, p0).hit()) +// { +// return true; +// } +// } +// { +// triPointRef tri(cube7, cube3, cube0); +// if (tri.intersectionExact(p0, p1).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p1, p2).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p2, p0).hit()) +// { +// return true; +// } +// } +// { +// triPointRef tri(cube1, cube5, cube6); +// if (tri.intersectionExact(p0, p1).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p1, p2).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p2, p0).hit()) +// { +// return true; +// } +// } +// { +// triPointRef tri(cube6, cube2, cube1); +// if (tri.intersectionExact(p0, p1).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p1, p2).hit()) +// { +// return true; +// } +// if (tri.intersectionExact(p2, p0).hit()) +// { +// return true; +// } +// } +// return false; +//} + + bool Foam::triangleFuncs::intersect ( const point& va0, @@ -470,145 +731,4 @@ bool Foam::triangleFuncs::intersect } -bool Foam::triangleFuncs::classify -( - const point& baseVertex, - const vector& E0, - const vector& E1, - const vector& n, - const point& pInter, - const scalar tol, - label& nearType, - label& nearLabel -) -{ - // Get largest component of normal - scalar magX = Foam::mag(n.x()); - scalar magY = Foam::mag(n.y()); - scalar magZ = Foam::mag(n.z()); - - label i0 = -1; - if ((magX >= magY) && (magX >= magZ)) - { - i0 = 0; - } - else if ((magY >= magX) && (magY >= magZ)) - { - i0 = 1; - } - else - { - i0 = 2; - } - - // Get other components - label i1 = (i0 + 1) % 3; - label i2 = (i1 + 1) % 3; - - scalar u1 = E0[i1]; - scalar v1 = E0[i2]; - - scalar u2 = E1[i1]; - scalar v2 = E1[i2]; - - scalar det = v2*u1 - u2*v1; - - scalar u0 = pInter[i1] - baseVertex[i1]; - scalar v0 = pInter[i2] - baseVertex[i2]; - - scalar alpha = 0; - scalar beta = 0; - - bool hit = false; - - if (Foam::mag(u1) < ROOTVSMALL) - { - beta = u0/u2; - - alpha = (v0 - beta*v2)/v1; - - hit = ((alpha >= 0) && ((alpha + beta) <= 1)); - } - else - { - beta = (v0*u1 - u0*v1)/det; - - alpha = (u0 - beta*u2)/u1; - - hit = ((alpha >= 0) && ((alpha + beta) <= 1)); - } - - // - // Now alpha, beta are the coordinates in the triangle local coordinate - // system E0, E1 - // - - nearType = NONE; - nearLabel = -1; - - if (mag(alpha+beta-1) < tol) - { - // On edge between vert 1-2 (=edge 1) - - if (mag(alpha) < tol) - { - nearType = POINT; - nearLabel = 2; - } - else if (mag(beta) < tol) - { - nearType = POINT; - nearLabel = 1; - } - else if ((alpha >= 0) && (alpha <= 1) && (beta >= 0) && (beta <= 1)) - { - nearType = EDGE; - nearLabel = 1; - } - } - else if (mag(alpha) < tol) - { - // On edge between vert 2-0 (=edge 2) - - if (mag(beta) < tol) - { - nearType = POINT; - nearLabel = 0; - } - else if (mag(beta-1) < tol) - { - nearType = POINT; - nearLabel = 2; - } - else if ((beta >= 0) && (beta <= 1)) - { - nearType = EDGE; - nearLabel = 2; - } - } - else if (mag(beta) < tol) - { - // On edge between vert 0-1 (= edge 0) - - if (mag(alpha) < tol) - { - nearType = POINT; - nearLabel = 0; - } - else if (mag(alpha-1) < tol) - { - nearType = POINT; - nearLabel = 1; - } - else if ((alpha >= 0) && (alpha <= 1)) - { - nearType = EDGE; - nearLabel = 0; - } - } - - return hit; -} - - // ************************************************************************* // diff --git a/src/meshTools/triSurface/triangleFuncs/triangleFuncs.H b/src/meshTools/triSurface/triangleFuncs/triangleFuncs.H index 1180e10195399aa79640a86e7a5c9eeecce3939d..0aa2a4c1c406bdb76ce407d559deb2fe4314bccc 100644 --- a/src/meshTools/triSurface/triangleFuncs/triangleFuncs.H +++ b/src/meshTools/triSurface/triangleFuncs/triangleFuncs.H @@ -147,25 +147,6 @@ public: point& pInter0, point& pInter1 ); - - - //- Classify point on triangle plane w.r.t. triangle edges. - // - inside/outside (returned) - // - near point (0, 1, 2) - // - near edge (0, 1, 2). Note: edges are counted from starting vertex - // so e.g. edge 2 is from f[2] to f[0] - static bool classify - ( - const point& baseVertex, - const vector& E0, - const vector& E1, - const vector& n, - const point& pInter, - const scalar tol, - label& nearType, - label& nearLabel - ); - }; diff --git a/tutorials/mesh/snappyHexMesh/iglooWithFridges/constant/triSurface/fridgeA.eMesh b/tutorials/mesh/snappyHexMesh/iglooWithFridges/constant/triSurface/fridgeA.eMesh new file mode 100644 index 0000000000000000000000000000000000000000..ff7aab4b8f14cabed8622a7ddcb1e4ec2b635b2f --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/iglooWithFridges/constant/triSurface/fridgeA.eMesh @@ -0,0 +1,58 @@ +/*---------------------------------------------------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.3.1 | +| \\ / A nd | Web: http://www.openfoam.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ + +FoamFile +{ + version 2.0; + format ascii; + + root ".."; + case "cavity"; + instance ""constant""; + local "polyMesh"; + + class featureEdgeMesh; + object points; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// Points +( +(1.99 1.99 0.01) //0 +(3.01 1.99 0.01) //1 +(3.01 3.01 0.01) //2 +(1.99 3.01 0.01) //3 + +(1.99 1.99 2.01) //4 +(3.01 1.99 2.01) //5 +(3.01 3.01 2.01) //6 +(1.99 3.01 2.01) //7 +) + +// Edges +( +(0 1) +(1 2) +(2 3) +(3 0) + +(4 5) +(5 6) +(6 7) +(7 4) + +(0 4) +(1 5) +(2 6) +(3 7) +) + + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/iglooWithFridges/system/snappyHexMeshDict b/tutorials/mesh/snappyHexMesh/iglooWithFridges/system/snappyHexMeshDict index 19ef2afec1d08e169d49fd7907cc518d0eccd94b..be30045c6d4d77a2bf014349a0e4890ff5d963bd 100644 --- a/tutorials/mesh/snappyHexMesh/iglooWithFridges/system/snappyHexMeshDict +++ b/tutorials/mesh/snappyHexMesh/iglooWithFridges/system/snappyHexMeshDict @@ -143,10 +143,10 @@ castellatedMeshControls // This is a featureEdgeMesh, read from constant/triSurface for now. features ( -// { -// file "fridgeA.eMesh"; -// level 3; -// } + { + file "fridgeA.eMesh"; + level 3; + } ); @@ -308,6 +308,10 @@ addLayersControls // Create buffer region for new layer terminations nBufferCellsNoExtrude 0; + + + // Overall max number of layer addition iterations + nLayerIter 50; } diff --git a/tutorials/mesh/snappyHexMesh/motorBike/system/snappyHexMeshDict b/tutorials/mesh/snappyHexMesh/motorBike/system/snappyHexMeshDict index 3f0ff0417e6b92047878cb285aa71452c8fd3c74..0d84177d8b422d750ef38dbf1536c4ba8383c6dc 100644 --- a/tutorials/mesh/snappyHexMesh/motorBike/system/snappyHexMeshDict +++ b/tutorials/mesh/snappyHexMesh/motorBike/system/snappyHexMeshDict @@ -160,7 +160,7 @@ snapControls //- Relative distance for points to be attracted by surface feature point // or edge. True distance is this factor times local // maximum edge length. - tolerance 4; + tolerance 4.0; //- Number of mesh displacement relaxation iterations. nSolveIter 30; @@ -182,344 +182,14 @@ addLayersControls nSurfaceLayers 1; } - motorBike_frt-fairing:001%1 - { - nSurfaceLayers 1; - } - - motorBike_windshield:002%2 - { - nSurfaceLayers 1; - } - - motorBike_rr-wh-rim:005%5 - { - nSurfaceLayers 1; - } - - motorBike_rr-wh-rim:010%10 - { - nSurfaceLayers 1; - } - - motorBike_fr-wh-rim:011%11 - { - nSurfaceLayers 1; - } - - motorBike_fr-wh-brake-disk:012%12 - { - nSurfaceLayers 1; - } - - motorBike_frame:016-shadow%13 - { - nSurfaceLayers 1; - } - - motorBike_rear-susp:014%14 - { - nSurfaceLayers 1; - } - - motorBike_rear-susp:014-shadow%15 - { - nSurfaceLayers 1; - } - - motorBike_frame:016%16 - { - nSurfaceLayers 1; - } - - motorBike_rr-wh-rim:005-shadow%17 - { - nSurfaceLayers 1; - } - - motorBike_rr-wh-chain-hub:022%22 - { - nSurfaceLayers 1; - } - - motorBike_rearseat%24 - { - nSurfaceLayers 1; - } - - motorBike_frt-fairing%25 - { - nSurfaceLayers 1; - } - - motorBike_windshield%26 - { - nSurfaceLayers 1; - } - - motorBike_headlights%27 - { - nSurfaceLayers 1; - } - - motorBike_driversseat%28 - { - nSurfaceLayers 1; - } - - motorBike_rear-body%29 - { - nSurfaceLayers 1; - } - - motorBike_fuel-tank%30 - { - nSurfaceLayers 1; - } - - motorBike_exhaust%31 - { - nSurfaceLayers 1; - } - - motorBike_rr-wh-rim%32 - { - nSurfaceLayers 1; - } - - motorBike_fr-mud-guard%33 - { - nSurfaceLayers 1; - } - - motorBike_fr-wh-rim%34 - { - nSurfaceLayers 1; - } - - motorBike_fr-wh-brake-disk%35 - { - nSurfaceLayers 1; - } - - motorBike_fr-brake-caliper%36 - { - nSurfaceLayers 1; - } - - motorBike_fr-wh-tyre%37 - { - nSurfaceLayers 1; - } - - motorBike_hbars%38 - { - nSurfaceLayers 1; - } - - motorBike_fr-forks%39 - { - nSurfaceLayers 1; - } - - motorBike_chain%40 - { - nSurfaceLayers 1; - } - - motorBike_rr-wh-tyre%41 - { - nSurfaceLayers 1; - } - - motorBike_square-dial%42 - { - nSurfaceLayers 1; - } - - motorBike_round-dial%43 - { - nSurfaceLayers 1; - } - - motorBike_dial-holder%44 - { - nSurfaceLayers 1; - } - - motorBike_rear-susp%45 - { - nSurfaceLayers 1; - } - - motorBike_rear-brake-lights%46 - { - nSurfaceLayers 1; - } - - motorBike_rear-light-bracket%47 - { - nSurfaceLayers 1; - } - - motorBike_frame%48 - { - nSurfaceLayers 1; - } - - motorBike_rear-mud-guard%49 - { - nSurfaceLayers 1; - } - - motorBike_rear-susp-spring-damp%50 - { - nSurfaceLayers 1; - } - - motorBike_fairing-inner-plate%51 - { - nSurfaceLayers 1; - } - - motorBike_clutch-housing%52 - { - nSurfaceLayers 1; - } - - motorBike_radiator%53 - { - nSurfaceLayers 1; - } - - motorBike_water-pipe%54 - { - nSurfaceLayers 1; - } - - motorBike_water-pump%55 - { - nSurfaceLayers 1; - } - - motorBike_engine%56 - { - nSurfaceLayers 1; - } - - motorBike_rear-shock-link%57 - { - nSurfaceLayers 1; - } - - motorBike_rear-brake-fluid-pot-bracket%58 - { - nSurfaceLayers 1; - } - - motorBike_rear-brake-fluid-pot%59 - { - nSurfaceLayers 1; - } - - motorBike_footpeg%60 - { - nSurfaceLayers 1; - } - - motorBike_rr-wh-chain-hub%61 - { - nSurfaceLayers 1; - } - - motorBike_rear-brake-caliper%62 - { - nSurfaceLayers 1; - } - - motorBike_rider-helmet%65 - { - nSurfaceLayers 1; - } - - motorBike_rider-visor%66 - { - nSurfaceLayers 1; - } - - motorBike_rider-boots%67 - { - nSurfaceLayers 1; - } - - motorBike_rider-gloves%68 - { - nSurfaceLayers 1; - } - - motorBike_rider-body%69 - { - nSurfaceLayers 1; - } - - motorBike_frame:0%70 - { - nSurfaceLayers 1; - } - - motorBike_frt-fairing:001-shadow%74 - { - nSurfaceLayers 1; - } - - motorBike_windshield-shadow%75 - { - nSurfaceLayers 1; - } - - motorBike_fr-mud-guard-shadow%81 - { - nSurfaceLayers 1; - } - - motorBike_fr-wh-brake-disk-shadow%83 - { - nSurfaceLayers 1; - } - - motorBike_rear-mud-guard-shadow%84 - { - nSurfaceLayers 1; - } - - motorBike_rear-susp-spring-damp-shadow%85 - { - nSurfaceLayers 1; - } - - motorBike_radiator-shadow%86 - { - nSurfaceLayers 1; - } - - motorBike_rear-shock-link-shadow%87 - { - nSurfaceLayers 1; - } - - motorBike_rear-brake-fluid-pot-bracket-shadow%88 - { - nSurfaceLayers 1; - } - - motorBike_rr-wh-chain-hub-shadow%89 + "motorBike_.*" { nSurfaceLayers 1; } } // Expansion factor for layer mesh - expansionRatio 1; + expansionRatio 1.0; //- Wanted thickness of final added cell layer. If multiple layers // is the @@ -569,6 +239,10 @@ addLayersControls // Create buffer region for new layer terminations nBufferCellsNoExtrude 0; + + + // Overall max number of layer addition iterations + nLayerIter 50; }