From 78aade75692bf11cd7cf06d74e4b5a5a367a7012 Mon Sep 17 00:00:00 2001 From: knosulko Date: Fri, 5 Aug 2022 12:44:29 +0300 Subject: [PATCH] 0033017: Implement an algorithm to find a proximity between a pair of shapes Extend "proximity" command to be able to compute the proximity value; Implement classes for calculate proximity value between two shapes; Add possibility to set up the number of sample points for the input shapes; Add tests lowalgos/proximity. --- dox/upgrade/upgrade.md | 5 + .../BRepExtrema_ProximityDistTool.cxx | 460 ++++++++++++++++++ .../BRepExtrema_ProximityDistTool.hxx | 200 ++++++++ .../BRepExtrema_ProximityValueTool.cxx | 161 ++++++ .../BRepExtrema_ProximityValueTool.hxx | 126 +++++ .../BRepExtrema_SelfIntersection.hxx | 4 +- .../BRepExtrema_ShapeProximity.cxx | 87 +++- .../BRepExtrema_ShapeProximity.hxx | 109 ++++- src/BRepExtrema/BRepExtrema_TriangleSet.cxx | 201 ++++++-- src/BRepExtrema/BRepExtrema_TriangleSet.hxx | 53 +- src/BRepExtrema/FILES | 4 + src/BRepTest/BRepTest_ExtremaCommands.cxx | 108 ++-- src/BVH/BVH_Tools.hxx | 142 ++++-- tests/lowalgos/grids.list | 1 + tests/lowalgos/proximity/A1 | 24 + tests/lowalgos/proximity/A2 | 26 + tests/lowalgos/proximity/A3 | 28 ++ tests/lowalgos/proximity/A4 | 26 + tests/lowalgos/proximity/A5 | 31 ++ tests/lowalgos/proximity/B1 | 28 ++ tests/lowalgos/proximity/B2 | 28 ++ tests/lowalgos/proximity/B3 | 28 ++ tests/lowalgos/proximity/B4 | 28 ++ tests/lowalgos/proximity/B5 | 27 + tests/lowalgos/proximity/B6 | 27 + tests/lowalgos/proximity/C1 | 29 ++ tests/lowalgos/proximity/C2 | 29 ++ tests/lowalgos/proximity/C3 | 28 ++ tests/lowalgos/proximity/C4 | 28 ++ tests/lowalgos/proximity/D1 | 28 ++ tests/lowalgos/proximity/D2 | 26 + tests/lowalgos/proximity/D3 | 33 ++ tests/lowalgos/proximity/E1 | 30 ++ tests/lowalgos/proximity/E2 | 27 + tests/lowalgos/proximity/end | 19 + 35 files changed, 2098 insertions(+), 141 deletions(-) create mode 100644 src/BRepExtrema/BRepExtrema_ProximityDistTool.cxx create mode 100644 src/BRepExtrema/BRepExtrema_ProximityDistTool.hxx create mode 100644 src/BRepExtrema/BRepExtrema_ProximityValueTool.cxx create mode 100644 src/BRepExtrema/BRepExtrema_ProximityValueTool.hxx create mode 100644 tests/lowalgos/proximity/A1 create mode 100644 tests/lowalgos/proximity/A2 create mode 100644 tests/lowalgos/proximity/A3 create mode 100644 tests/lowalgos/proximity/A4 create mode 100644 tests/lowalgos/proximity/A5 create mode 100644 tests/lowalgos/proximity/B1 create mode 100644 tests/lowalgos/proximity/B2 create mode 100644 tests/lowalgos/proximity/B3 create mode 100644 tests/lowalgos/proximity/B4 create mode 100644 tests/lowalgos/proximity/B5 create mode 100644 tests/lowalgos/proximity/B6 create mode 100644 tests/lowalgos/proximity/C1 create mode 100644 tests/lowalgos/proximity/C2 create mode 100644 tests/lowalgos/proximity/C3 create mode 100644 tests/lowalgos/proximity/C4 create mode 100644 tests/lowalgos/proximity/D1 create mode 100644 tests/lowalgos/proximity/D2 create mode 100644 tests/lowalgos/proximity/D3 create mode 100644 tests/lowalgos/proximity/E1 create mode 100644 tests/lowalgos/proximity/E2 create mode 100644 tests/lowalgos/proximity/end diff --git a/dox/upgrade/upgrade.md b/dox/upgrade/upgrade.md index 329bbacb9f..7bf9c8d2dd 100644 --- a/dox/upgrade/upgrade.md +++ b/dox/upgrade/upgrade.md @@ -2338,3 +2338,8 @@ or to include system OpenGL headers in advance (with help of `OpenGl_GlNative.hx Method `StdPrs_ToolTriangulatedShape::Normal()` has been removed. Please use `BRepLib_ToolTriangulatedShape::ComputeNormals()` to fill in normal attributes in triangulation and fetch them directly using `Poly_Triangulation::Normal()`. + +@subsection upgrade_occt770_shapeproximity BRepExtrema_ShapeProximity + +A new way of using the `BRepExtrema_ShapeProximity` class was provided for computing a proximity value between two shapes. +If at initialization of the `BRepExtrema_ShapeProximity` class the *theTolerance* parameter is not defined (Precision::Infinite() by default), the proximity value will be computed. diff --git a/src/BRepExtrema/BRepExtrema_ProximityDistTool.cxx b/src/BRepExtrema/BRepExtrema_ProximityDistTool.cxx new file mode 100644 index 0000000000..cd51510d76 --- /dev/null +++ b/src/BRepExtrema/BRepExtrema_ProximityDistTool.cxx @@ -0,0 +1,460 @@ +// Created on: 2022-08-08 +// Created by: Kseniya NOSULKO +// Copyright (c) 2022 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include +#include +#include +#include +#include +#include +#include + +//======================================================================= +//function : BRepExtrema_ProximityDistTool +//purpose : Creates new unitialized tool +//======================================================================= +BRepExtrema_ProximityDistTool::BRepExtrema_ProximityDistTool() +: myMinDistance (std::numeric_limits::max()), + myProxDist (-1.), + myPntStatus1 (ProxPnt_Status_UNKNOWN), + myPntStatus2 (ProxPnt_Status_UNKNOWN), + myNbSamples1 (0), + myProxVtxIdx1 (-1) +{ +} + +//======================================================================= +//function : BRepExtrema_ProximityDistTool +//purpose : Creates new tool for the given element sets +//======================================================================= +BRepExtrema_ProximityDistTool::BRepExtrema_ProximityDistTool (const Handle(BRepExtrema_TriangleSet)& theSet1, + const Standard_Integer theNbSamples1, + const Handle(BRepExtrema_TriangleSet)& theSet2, + const BRepExtrema_ShapeList& theShapeList1, + const BRepExtrema_ShapeList& theShapeList2) +: myMinDistance (std::numeric_limits::max()), + myProxDist (-1.), + myPntStatus1 (ProxPnt_Status_UNKNOWN), + myPntStatus2 (ProxPnt_Status_UNKNOWN), + myNbSamples1 (theNbSamples1), + myProxVtxIdx1 (-1) +{ + LoadTriangleSets (theSet1, theSet2); + LoadShapeLists (theShapeList1, theShapeList2); +} + +//======================================================================= +//function : LoadTriangleSets +//purpose : Loads the given element sets into the tool +//======================================================================= +void BRepExtrema_ProximityDistTool::LoadTriangleSets (const Handle(BRepExtrema_TriangleSet)& theSet1, + const Handle(BRepExtrema_TriangleSet)& theSet2) +{ + mySet1 = theSet1; + mySet2 = theSet2; +} + +//======================================================================= +//function : LoadTriangleSets +//purpose : Loads the given list of subshapes into the proximity tool +//======================================================================= +void BRepExtrema_ProximityDistTool::LoadShapeLists (const BRepExtrema_ShapeList& theShapeList1, + const BRepExtrema_ShapeList& theShapeList2) +{ + myShapeList1 = theShapeList1; + myShapeList2 = theShapeList2; +} +//======================================================================= +//function : Perform +//purpose : Performs searching of the proximity distance +//======================================================================= +void BRepExtrema_ProximityDistTool::Perform() +{ + SetBVHSet (mySet2.get()); + + const BVH_Array3d& aVertices1 = mySet1->GetVertices(); + Standard_Integer aVtxSize = (Standard_Integer)aVertices1.size(); + Standard_Integer aVtxStep = Max (myNbSamples1 <= 0 ? 1 : aVtxSize / myNbSamples1, 1); + for (Standard_Integer aVtxIdx = 0; aVtxIdx < aVtxSize; aVtxIdx += aVtxStep) + { + myDistance = std::numeric_limits::max(); + myMinDistance = std::numeric_limits::max(); + myIsDone = Standard_False; + SetObject (aVertices1[aVtxIdx]); + + ComputeDistance(); + + if (!IsDone() && myProxDist < 0.) return; + + if (IsDone() && myDistance > myProxDist) + { + myPnt1 = aVertices1[aVtxIdx]; + myPnt2 = myExtremaPoint; + myProxDist = myDistance; + myProxVtxIdx1 = aVtxIdx; + myProxPrjState = myExtPrjState; + } + } + + myIsDone = myProxDist > -1.; + + if (myIsDone) + { + DefineStatusProxPnt(); + } +} + +static Standard_Real pointBoxSquareMaxDistance (const BVH_Vec3d& thePoint, + const BVH_Vec3d& theCMin, + const BVH_Vec3d& theCMax) +{ + Standard_Real aDist = 0; + for (int i = 0; i < 3; ++i) + { + if (thePoint[i] <= 0.5 * (theCMax[i] + theCMin[i])) { Standard_Real d = theCMax[i] - thePoint[i]; d *= d; aDist += d; } + else { Standard_Real d = thePoint[i] - theCMin[i]; d *= d; aDist += d; } + } + return aDist; +} + +//======================================================================= +//function : Branch rejection +//purpose : Defines the rules for node rejection by bounding box +//======================================================================= +Standard_Boolean BRepExtrema_ProximityDistTool::RejectNode (const BVH_Vec3d& theCornerMin, + const BVH_Vec3d& theCornerMax, + Standard_Real& theMetric) const +{ + theMetric = sqrt (BVH_Tools::PointBoxSquareDistance (myObject, + theCornerMin, + theCornerMax)); + + Standard_Real aMaxMetric = sqrt (pointBoxSquareMaxDistance (myObject, + theCornerMin, + theCornerMax)); + + return theMetric > myDistance || aMaxMetric < myProxDist; +} + +//======================================================================= +//function : Leaf acceptance +//purpose : Defines the rules for leaf acceptance +//======================================================================= +Standard_Boolean BRepExtrema_ProximityDistTool::Accept (const Standard_Integer theTrgIdx, + const Standard_Real&) +{ + BVH_Vec3d aTrgVert1; + BVH_Vec3d aTrgVert2; + BVH_Vec3d aTrgVert3; + + BVH_PrjState aBVH_PrjState; + Standard_Integer aNumberOfFirstNode = -1; + Standard_Integer aNumberOfLastNode = -1; + + mySet2->GetVertices (theTrgIdx, aTrgVert1, aTrgVert2, aTrgVert3); + + BVH_Vec3d aNearestPnt = BVH_Tools::PointTriangleProjection (myObject, + aTrgVert1, aTrgVert2, aTrgVert3, + &aBVH_PrjState, + &aNumberOfFirstNode, &aNumberOfLastNode); + + PrjState aPrjState (theTrgIdx, aBVH_PrjState, aNumberOfFirstNode, aNumberOfLastNode); + BVH_Vec3d aDirect = myObject - aNearestPnt; + Standard_Real aSqDistance = aDirect.Dot(aDirect); + + if (aSqDistance > Precision::SquareConfusion()) // point belongs to triangle + { + const BVH_Vec3d aAB = aTrgVert2 - aTrgVert1; + + BVH_Vec3d aNorm; + if (aTrgVert2.IsEqual (aTrgVert3)) // is this degenerate triangle (= segment) + { + const BVH_Vec3d aAP = myObject - aTrgVert1; + aNorm = BVH_Vec3d::Cross (BVH_Vec3d::Cross (aAP, aAB), aAB); + } + else + { + const BVH_Vec3d aAC = aTrgVert3 - aTrgVert1; + aNorm = BVH_Vec3d::Cross (aAB, aAC); + } + + Standard_Real aNormSqLen = aNorm.Dot (aNorm); + + // check if the distance is under perpendicular + const BVH_Vec3d aCrossCross = BVH_Vec3d::Cross (aDirect, aNorm); + Standard_Real aCrossCrossSqLen = aCrossCross.Dot (aCrossCross); + if (aCrossCrossSqLen > Precision::SquareConfusion() * aSqDistance * aNormSqLen) + { + // the distance is not under perpendicular + if (myMinDistance - sqrt (aSqDistance) > Precision::Confusion()) + { + myMinDistance = sqrt (aSqDistance); + myMinDistPoint = aNearestPnt; + myMinPrjState = aPrjState; + } + + return Standard_False; + } + } + + // the distance is under perpendicular + if (myDistance - sqrt (aSqDistance) > Precision::Confusion()) + { + myDistance = sqrt (aSqDistance); + myExtremaPoint = aNearestPnt; + myExtPrjState = aPrjState; + + return Standard_True; + } + + return Standard_False; +} + +//======================================================================= +//function : ComputeDistance +//purpose : Computes the distance between object and BVH tree +//======================================================================= +Standard_Real BRepExtrema_ProximityDistTool::ComputeDistance() +{ + myIsDone = this->Select() > 0; + + if (!myIsDone) + { + if (myMinDistance < std::numeric_limits::max()) + { + myExtremaPoint = myMinDistPoint; + myExtPrjState = myMinPrjState; + myIsDone = true; + } + + myDistance = myMinDistance; + } + + return myDistance; +} + +static Standard_Boolean isNodeOnBorder (const Standard_Integer theNodeIdx, const Handle (Poly_Triangulation)& theTr) +{ + Poly_Connect aPolyConnect (theTr); + + Standard_Integer aContTrg; //index of triangle containing exploring node + for (aPolyConnect.Initialize (theNodeIdx); aPolyConnect.More(); aPolyConnect.Next()) + { + aContTrg = aPolyConnect.Value(); + + Standard_Integer aContTrgNodes[3]; + theTr->Triangle (aContTrg).Get (aContTrgNodes[0], aContTrgNodes[1], aContTrgNodes[2]); //indices of nodes of the triangle + + Standard_Integer aAdjTrg[3]; + aPolyConnect.Triangles (aContTrg, aAdjTrg[0], aAdjTrg[1], aAdjTrg[2]); //indices of adjacent triangles + + for (Standard_Integer j = 0; j < 3; j++) + { + Standard_Integer k = (j + 1) % 3; + if (aAdjTrg[j] == 0) //free segment of triangle + { + //aContTrgNodes[j], aContTrgNodes[k] are ends of free segment and it is a part of border + if (aContTrgNodes[j] == theNodeIdx || aContTrgNodes[k] == theNodeIdx) + { + return Standard_True; + } + } + } + } + + return Standard_False; +} + +//======================================================================= +//function : defineStatusProxPnt1 +//purpose : Defines the status of proximity point from 1st BVH +//======================================================================= +void BRepExtrema_ProximityDistTool::defineStatusProxPnt1() +{ + Standard_Integer aFaceID1 = mySet1->GetShapeIDOfVtx (myProxVtxIdx1); + + if (myShapeList1 (aFaceID1).ShapeType() == TopAbs_EDGE) + { + const BVH_Array3d& aVertices1 = mySet1->GetVertices(); + Standard_Integer aVtxSize = (Standard_Integer)aVertices1.size(); + Standard_Integer aLastIdx = aVtxSize - 1; + + if ((aVertices1[0] - aVertices1[aLastIdx]).Modulus() < Precision::Confusion()) // if closed + { + myPntStatus1 = ProxPnt_Status_MIDDLE; + return; + } + + if (myProxVtxIdx1 == 0 || myProxVtxIdx1 == aLastIdx) + { + myPntStatus1 = ProxPnt_Status_BORDER; + } + else + { + myPntStatus1 = ProxPnt_Status_MIDDLE; + } + } + else if (myShapeList1 (aFaceID1).ShapeType() == TopAbs_FACE) + { + Standard_Integer aNodeIdx = mySet1->GetVtxIdxInShape (myProxVtxIdx1) + 1; + + TopLoc_Location aLocation; + const TopoDS_Face& aF = TopoDS::Face (myShapeList1 (aFaceID1)); + Handle (Poly_Triangulation) aTr = BRep_Tool::Triangulation (aF, aLocation); + + if (isNodeOnBorder (aNodeIdx, aTr)) + { + myPntStatus1 = ProxPnt_Status_BORDER; + } + else + { + myPntStatus1 = ProxPnt_Status_MIDDLE; + } + } +} + +//======================================================================= +//function : defineStatusProxPnt2 +//purpose : Defines the status of proximity point from 2nd BVH +//======================================================================= +void BRepExtrema_ProximityDistTool::defineStatusProxPnt2() +{ + Standard_Integer aTrgIdx = myProxPrjState.GetTrgIdx(); + Standard_Integer aFaceID2 = mySet2->GetFaceID (aTrgIdx); + + if (myShapeList2 (aFaceID2).ShapeType() == TopAbs_EDGE) + { + if (myProxPrjState.GetPrjState() == BVH_PrjState::BVH_PrjStateInTriangle_INNER) + { + return; + } + else + { + const BVH_Array3d& aVertices2 = mySet2->GetVertices(); + Standard_Integer aVtxSize = (Standard_Integer)aVertices2.size(); + Standard_Integer aLastIdx = aVtxSize - 1; + + if ((aVertices2[0] - aVertices2[aLastIdx]).Modulus() < Precision::Confusion()) // if closed + { + myPntStatus2 = ProxPnt_Status_MIDDLE; + return; + } + + NCollection_Array1 aVtxIndicesOfTrg; + mySet2->GetVtxIndices (aTrgIdx, aVtxIndicesOfTrg); + + Standard_Integer aFirstNodeNum = myProxPrjState.GetNumberOfFirstNode(); + Standard_Integer aFirstVtxIdx = aVtxIndicesOfTrg[aFirstNodeNum]; + + if (myProxPrjState.GetPrjState() == BVH_PrjState::BVH_PrjStateInTriangle_VERTEX) + { + if (aFirstVtxIdx == 0 || aFirstVtxIdx == aLastIdx) + { + myPntStatus2 = ProxPnt_Status_BORDER; + } + else + { + myPntStatus2 = ProxPnt_Status_MIDDLE; + } + } + else if (myProxPrjState.GetPrjState() == BVH_PrjState::BVH_PrjStateInTriangle_EDGE) + { + Standard_Integer aLastNodeNum = myProxPrjState.GetNumberOfLastNode(); + Standard_Integer aLastVtxIdx = aVtxIndicesOfTrg[aLastNodeNum]; + + // it could be border only in case projection is on a degenerated edge + if (aFirstVtxIdx == aLastVtxIdx && (aFirstVtxIdx == 0 || aFirstVtxIdx == aLastIdx)) + { + myPntStatus2 = ProxPnt_Status_BORDER; + } + else + { + myPntStatus2 = ProxPnt_Status_MIDDLE; + } + } + } + } + else if (myShapeList2 (aFaceID2).ShapeType() == TopAbs_FACE) + { + if (myProxPrjState.GetPrjState() == BVH_PrjState::BVH_PrjStateInTriangle_INNER) + { + myPntStatus2 = ProxPnt_Status_MIDDLE; + } + else + { + TopLoc_Location aLocation; + const TopoDS_Face& aF = TopoDS::Face (myShapeList2 (aFaceID2)); + Handle (Poly_Triangulation) aTr = BRep_Tool::Triangulation (aF, aLocation); + + NCollection_Array1 aVtxIndicesOfTrg; + mySet2->GetVtxIndices (aTrgIdx, aVtxIndicesOfTrg); + + if (myProxPrjState.GetPrjState() == BVH_PrjState::BVH_PrjStateInTriangle_VERTEX) + { + Standard_Integer aNodeNum = myProxPrjState.GetNumberOfFirstNode(); + Standard_Integer aNodeIdx = mySet2->GetVtxIdxInShape (aVtxIndicesOfTrg[aNodeNum]) + 1; + + if (isNodeOnBorder (aNodeIdx, aTr)) + { + myPntStatus2 = ProxPnt_Status_BORDER; + } + else + { + myPntStatus2 = ProxPnt_Status_MIDDLE; + } + } + else if (myProxPrjState.GetPrjState() == BVH_PrjState::BVH_PrjStateInTriangle_EDGE) + { + myPntStatus2 = ProxPnt_Status_MIDDLE; + + Poly_Connect aPolyConnect (aTr); + Standard_Integer aTrgIdxInShape = mySet2->GetTrgIdxInShape (aTrgIdx) + 1; + + Standard_Integer aAdjTrg[3]; + aPolyConnect.Triangles (aTrgIdxInShape, aAdjTrg[0], aAdjTrg[1], aAdjTrg[2]); //indices of adjacent triangles + + for (Standard_Integer j = 0; j < 3; j++) + { + Standard_Integer k = (j + 1) % 3; + if (aAdjTrg[j] == 0) //free segment of triangle + { + //aVtxIndicesOfTrg[j] and aVtxIndicesOfTrg[k] are ends of free segment and it is a part of border + if (j == myProxPrjState.GetNumberOfFirstNode() && + k == myProxPrjState.GetNumberOfLastNode()) + { + myPntStatus2 = ProxPnt_Status_BORDER; + break; + } + } + } + } //else if (myProxPrjState.GetPrjState() == BVH_PrjState::BVH_PrjStateInTriangle_EDGE) + } + } //else if (myShapeList1 (aFaceID1).ShapeType() == TopAbs_FACE) +} + +//======================================================================= +//function : DefineStatusProxPnt +//purpose : Defines the status of proximity points +//======================================================================= +void BRepExtrema_ProximityDistTool::DefineStatusProxPnt() +{ + // define the status of proximity point from 1st BVH + defineStatusProxPnt1(); + + // define the status of proximity point from 2nd BVH + defineStatusProxPnt2(); +} diff --git a/src/BRepExtrema/BRepExtrema_ProximityDistTool.hxx b/src/BRepExtrema/BRepExtrema_ProximityDistTool.hxx new file mode 100644 index 0000000000..3739fff1ad --- /dev/null +++ b/src/BRepExtrema/BRepExtrema_ProximityDistTool.hxx @@ -0,0 +1,200 @@ +// Created on: 2022-08-08 +// Created by: Kseniya NOSULKO +// Copyright (c) 2022 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _BRepExtrema_ProximityDistTool_HeaderFile +#define _BRepExtrema_ProximityDistTool_HeaderFile + +#include +#include +#include +#include +#include + +//! Tool class for computation the proximity distance from first +//! primitive set to second one that is the maximal from minimum +//! perpendicular distances. If no perpendicular distance is found, the +//! minimum distance will be returned. +//! This tool is not intended to be used independently, and is integrated +//! in other classes, implementing algorithms based on shape tessellation +//! (BRepExtrema_ProximityValueTool). +//! +//! Please note that algorithm results are approximate and depend greatly +//! on the quality of input tessellation(s). +class BRepExtrema_ProximityDistTool : public BVH_Distance +{ +public: + + typedef typename BVH_Tools::BVH_PrjStateInTriangle BVH_PrjState; + + enum ProxPnt_Status + { + ProxPnt_Status_BORDER, + ProxPnt_Status_MIDDLE, + ProxPnt_Status_UNKNOWN + }; + +public: + + //! Struct with information about projection point state from 2nd BVH, + //! providing proximity point of 2nd shape + struct PrjState + { + PrjState() + : myTrgIdx (0), + myPrjState (BVH_PrjState::BVH_PrjStateInTriangle_INNER), + myNumberOfFirstNode (0), + myNumberOfLastNode (0) + {} + + PrjState (const Standard_Integer theTrgIdx, + const BVH_PrjState thePrjState, + const Standard_Integer theNumberOfFirstNode, + const Standard_Integer theNumberOfLastNode) + : myTrgIdx (theTrgIdx), + myPrjState (thePrjState), + myNumberOfFirstNode (theNumberOfFirstNode), + myNumberOfLastNode (theNumberOfLastNode) + {} + + Standard_Integer GetTrgIdx() const { return myTrgIdx; } + + BVH_PrjState GetPrjState() const { return myPrjState; } + + Standard_Integer GetNumberOfFirstNode() const { return myNumberOfFirstNode; } + + Standard_Integer GetNumberOfLastNode() const { return myNumberOfLastNode; } + + private: + + Standard_Integer myTrgIdx; //!< Index of triangle on which the projection is located + BVH_PrjState myPrjState; //!< Position of a projection on the triangle (vertex, edge, inner) + Standard_Integer myNumberOfFirstNode; //!< The 1st vtx of the triangle edge on which the projection is located + Standard_Integer myNumberOfLastNode; //!< The 2nd vtx of the triangle edge on which the projection is located + }; + +public: + + //! Creates new unitialized tool. + Standard_EXPORT BRepExtrema_ProximityDistTool(); + + //! Creates new tool for the given element sets. + Standard_EXPORT BRepExtrema_ProximityDistTool (const Handle(BRepExtrema_TriangleSet)& theSet1, + const Standard_Integer theNbSamples1, + const Handle(BRepExtrema_TriangleSet)& theSet2, + const BRepExtrema_ShapeList& theShapeList1, + const BRepExtrema_ShapeList& theShapeList2); + +public: + + //! Loads the given element sets into the tool. + Standard_EXPORT void LoadTriangleSets (const Handle(BRepExtrema_TriangleSet)& theSet1, + const Handle(BRepExtrema_TriangleSet)& theSet2); + + //! Loads the given list of subshapes into the tool. + Standard_EXPORT void LoadShapeLists (const BRepExtrema_ShapeList& theShapeList1, + const BRepExtrema_ShapeList& theShapeList2); + + //! Performs searching of the proximity distance. + Standard_EXPORT void Perform(); + +public: //! @name Reject/Accept implementations + + //! Defines the rules for node rejection by bounding box. + Standard_EXPORT virtual Standard_Boolean RejectNode (const BVH_Vec3d& theCornerMin, + const BVH_Vec3d& theCornerMax, + Standard_Real& theMetric) const Standard_OVERRIDE; + + //! Defines the rules for leaf acceptance. + Standard_EXPORT virtual Standard_Boolean Accept (const Standard_Integer theSgmIdx, + const Standard_Real&) Standard_OVERRIDE; + + //! Returns points on triangles sets, which provide the proximity distance. + void ProximityPoints (BVH_Vec3d& thePoint1, BVH_Vec3d& thePoint2) const + { + thePoint1 = myPnt1; + thePoint2 = myPnt2; + } + + //! Returns status of points on triangles sets, which provide the proximity distance. + void ProximityPointsStatus (ProxPnt_Status& thePointStatus1, ProxPnt_Status& thePointStatus2) const + { + thePointStatus1 = myPntStatus1; + thePointStatus2 = myPntStatus2; + } + + //! Returns the computed distance + Standard_Real ProximityDistance() const { return myProxDist; } + +protected: + + //! Computes the distance between object and BVH tree. + Standard_EXPORT Standard_Real ComputeDistance(); + + //! Defines the status of proximity points. + Standard_EXPORT void DefineStatusProxPnt(); + +private: + + //! Defines the status of proximity point from 1st BVH. + void defineStatusProxPnt1(); + + //! Defines the status of proximity point from 2nd BVH. + void defineStatusProxPnt2(); + +protected: + + Standard_Real myMinDistance; //!< Minimal distance from point to BVH, could be not equal to myDistance + BVH_Vec3d myMinDistPoint; //!< Point on BVH providing the minimal distance + + BVH_Vec3d myExtremaPoint; //!< Point on BVH providing the extrema + + Standard_Real myProxDist; //!< Proximity distance + + //! Proximity points + BVH_Vec3d myPnt1, myPnt2; + + //! Proximity points' status + ProxPnt_Status myPntStatus1, myPntStatus2; + +private: + + //! Set of all mesh elements (triangles) of the 1st shape. + Handle(BRepExtrema_TriangleSet) mySet1; + //! Set of all mesh elements (triangles) of the 2nd shape. + Handle(BRepExtrema_TriangleSet) mySet2; + + //! List of subshapes of the 1st shape. + BRepExtrema_ShapeList myShapeList1; + //! List of subshapes of the 2nd shape. + BRepExtrema_ShapeList myShapeList2; + + Standard_Integer myNbSamples1; //!< Number of samples points on the first shape + + //! Vertex index from 1st BVH corresponding to proximity point of 1st shape + Standard_Integer myProxVtxIdx1; + + //! Information of projection point state from 2nd BVH providing proximity point of 2nd shape + PrjState myProxPrjState; + + //! Information of projection point state from 2nd BVH providing the extrema + PrjState myExtPrjState; + + //! Information of projection point state from 2nd BVH providing the minimal distance + PrjState myMinPrjState; + +}; + +#endif // _BRepExtrema_ProximityDistTool_HeaderFile diff --git a/src/BRepExtrema/BRepExtrema_ProximityValueTool.cxx b/src/BRepExtrema/BRepExtrema_ProximityValueTool.cxx new file mode 100644 index 0000000000..a816be8b8f --- /dev/null +++ b/src/BRepExtrema/BRepExtrema_ProximityValueTool.cxx @@ -0,0 +1,161 @@ +// Created on: 2022-08-08 +// Created by: Kseniya NOSULKO +// Copyright (c) 2022 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +//======================================================================= +//function : BRepExtrema_ProximityValueTool +//purpose : Creates new unitialized proximity tool +//======================================================================= +BRepExtrema_ProximityValueTool::BRepExtrema_ProximityValueTool() +: myDistance (std::numeric_limits::max()), + myIsDone (Standard_False), + myNbSamples1(0), + myNbSamples2(0) +{} + +//======================================================================= +//function : BRepExtrema_ProximityValueTool +//purpose : Creates new proximity tool for the given element sets +//======================================================================= +BRepExtrema_ProximityValueTool::BRepExtrema_ProximityValueTool (const Handle(BRepExtrema_TriangleSet)& theSet1, + const Handle(BRepExtrema_TriangleSet)& theSet2, + const BRepExtrema_ShapeList& theShapeList1, + const BRepExtrema_ShapeList& theShapeList2) +: myDistance (std::numeric_limits::max()), + myIsDone (Standard_False), + myNbSamples1(0), + myNbSamples2(0) +{ + LoadTriangleSets (theSet1, theSet2); + LoadShapeLists (theShapeList1, theShapeList2); +} + +//======================================================================= +//function : LoadTriangleSets +//purpose : Loads the given element sets into the proximity tool +//======================================================================= +void BRepExtrema_ProximityValueTool::LoadTriangleSets (const Handle(BRepExtrema_TriangleSet)& theSet1, + const Handle(BRepExtrema_TriangleSet)& theSet2) +{ + mySet1 = theSet1; + mySet2 = theSet2; + + myIsDone = Standard_False; +} + +//======================================================================= +//function : LoadTriangleSets +//purpose : Loads the given list of subshapes into the proximity tool +//======================================================================= +void BRepExtrema_ProximityValueTool::LoadShapeLists (const BRepExtrema_ShapeList& theShapeList1, + const BRepExtrema_ShapeList& theShapeList2) +{ + myShapeList1 = theShapeList1; + myShapeList2 = theShapeList2; + + myIsDone = Standard_False; +} + +//======================================================================= +//function : SetNbSamplePoints +//purpose : Sets number of sample points used for proximity calculation for each shape +//======================================================================= +void BRepExtrema_ProximityValueTool::SetNbSamplePoints(const Standard_Integer theSamples1, + const Standard_Integer theSamples2) +{ + myNbSamples1 = theSamples1; + myNbSamples2 = theSamples2; + + myIsDone = Standard_False; +} + +//======================================================================= +//function : computeProximityValue +//purpose : Returns the computed proximity value from first BVH to another one +//======================================================================= +Standard_Real BRepExtrema_ProximityValueTool::computeProximityDist (const Handle(BRepExtrema_TriangleSet)& theSet1, + const Standard_Integer theNbSamples1, + const Handle(BRepExtrema_TriangleSet)& theSet2, + const BRepExtrema_ShapeList& theShapeList1, + const BRepExtrema_ShapeList& theShapeList2, + BVH_Vec3d& thePoint1, + BVH_Vec3d& thePoint2, + ProxPnt_Status& thePointStatus1, + ProxPnt_Status& thePointStatus2) const +{ + BRepExtrema_ProximityDistTool aProxDistTool (theSet1, theNbSamples1, theSet2, theShapeList1, theShapeList2); + aProxDistTool.Perform(); + + if (!aProxDistTool.IsDone()) + return -1.; + + aProxDistTool.ProximityPoints (thePoint1, thePoint2); + aProxDistTool.ProximityPointsStatus (thePointStatus1, thePointStatus2); + + return aProxDistTool.ProximityDistance(); +} + +//======================================================================= +//function : Perform +//purpose : Performs the computation of the proximity value +//======================================================================= +void BRepExtrema_ProximityValueTool::Perform (Standard_Real& theTolerance) +{ + myIsDone = Standard_False; + + // max(min) dist from the 1st shape to the 2nd one + BVH_Vec3d aP1_1, aP1_2; + ProxPnt_Status aPointStatus1_1 = ProxPnt_Status::ProxPnt_Status_UNKNOWN; + ProxPnt_Status aPointStatus1_2 = ProxPnt_Status::ProxPnt_Status_UNKNOWN; + + Standard_Real aProximityDist1 = computeProximityDist (mySet1, myNbSamples1, mySet2, myShapeList1, myShapeList2, + aP1_1, aP1_2, aPointStatus1_1, aPointStatus1_2); + + if (aProximityDist1 < 0.) + return; + + // max(min) dist from the 2nd shape to t he 1st one + BVH_Vec3d aP2_1, aP2_2; + ProxPnt_Status aPointStatus2_1 = ProxPnt_Status::ProxPnt_Status_UNKNOWN; + ProxPnt_Status aPointStatus2_2 = ProxPnt_Status::ProxPnt_Status_UNKNOWN; + + Standard_Real aProximityDist2 = computeProximityDist (mySet2, myNbSamples2, mySet1, myShapeList2, myShapeList1, + aP2_2, aP2_1, aPointStatus2_2, aPointStatus2_1); + + if (aProximityDist2 < 0.) + return; + + // min dist of the two max(min) dists + if (aProximityDist1 < aProximityDist2) + { + myDistance = aProximityDist1; + myPnt1.SetCoord(aP1_1.x(), aP1_1.y(), aP1_1.z()); + myPnt2.SetCoord(aP1_2.x(), aP1_2.y(), aP1_2.z()); + myPntStatus1 = aPointStatus1_1; + myPntStatus2 = aPointStatus1_2; + } + else + { + myDistance = aProximityDist2; + myPnt1.SetCoord(aP2_1.x(), aP2_1.y(), aP2_1.z()); + myPnt2.SetCoord(aP2_2.x(), aP2_2.y(), aP2_2.z()); + myPntStatus1 = aPointStatus2_1; + myPntStatus2 = aPointStatus2_2; + } + + myIsDone = Standard_True; + theTolerance = myDistance; +} diff --git a/src/BRepExtrema/BRepExtrema_ProximityValueTool.hxx b/src/BRepExtrema/BRepExtrema_ProximityValueTool.hxx new file mode 100644 index 0000000000..09610c8d92 --- /dev/null +++ b/src/BRepExtrema/BRepExtrema_ProximityValueTool.hxx @@ -0,0 +1,126 @@ +// Created on: 2022-08-08 +// Created by: Kseniya NOSULKO +// Copyright (c) 2022 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _BRepExtrema_ProximityValueTool_HeaderFile +#define _BRepExtrema_ProximityValueTool_HeaderFile + +#include +#include + +//! Tool class for computation of the proximity value from one BVH +//! primitive set to another, solving max(min) problem. +//! This tool is not intended to be used independently, and is integrated +//! in other classes, implementing algorithms based on shape tessellation +//! (BRepExtrema_ShapeProximity and BRepExtrema_SelfIntersection). +//! +//! Please note that algorithm results are approximate and depend greatly +//! on the quality of input tessellation(s). +class BRepExtrema_ProximityValueTool +{ +public: + typedef typename BRepExtrema_ProximityDistTool::ProxPnt_Status ProxPnt_Status; + +public: + + //! Creates new unitialized proximity tool. + Standard_EXPORT BRepExtrema_ProximityValueTool(); + + //! Creates new proximity tool for the given element sets. + Standard_EXPORT BRepExtrema_ProximityValueTool (const Handle(BRepExtrema_TriangleSet)& theSet1, + const Handle(BRepExtrema_TriangleSet)& theSet2, + const BRepExtrema_ShapeList& theShapeList1, + const BRepExtrema_ShapeList& theShapeList2); + +public: + + //! Loads the given element sets into the proximity tool. + Standard_EXPORT void LoadTriangleSets (const Handle (BRepExtrema_TriangleSet)& theSet1, + const Handle (BRepExtrema_TriangleSet)& theSet2); + + //! Loads the given list of subshapes into the proximity tool. + Standard_EXPORT void LoadShapeLists (const BRepExtrema_ShapeList& theShapeList1, + const BRepExtrema_ShapeList& theShapeList2); + + //! Sets number of sample points used for proximity calculation for each shape. + //! If number is less or equal zero, all triangulation nodes are used. + Standard_EXPORT void SetNbSamplePoints (const Standard_Integer theSamples1 = 0, + const Standard_Integer theSamples2 = 0); + + //! Performs the computation of the proximity value. + Standard_EXPORT void Perform (Standard_Real& theTolerance); + + //! Is proximity test completed? + Standard_Boolean IsDone() const { return myIsDone; } + + //! Marks test results as outdated. + void MarkDirty() { myIsDone = Standard_False; } + + //! Returns the computed distance. + Standard_Real Distance() const { return myDistance; } + + //! Returns points on triangles sets, which provide the proximity distance. + void ProximityPoints(gp_Pnt& thePoint1, gp_Pnt& thePoint2) const + { + thePoint1 = myPnt1; + thePoint2 = myPnt2; + } + + //! Returns status of points on triangles sets, which provide the proximity distance. + void ProximityPointsStatus (ProxPnt_Status& thePointStatus1, ProxPnt_Status& thePointStatus2) const + { + thePointStatus1 = myPntStatus1; + thePointStatus2 = myPntStatus2; + } + +private: + + //! Returns the computed proximity value from first BVH to another one. + Standard_Real computeProximityDist (const Handle(BRepExtrema_TriangleSet)& theSet1, + const Standard_Integer theNbSamples1, + const Handle(BRepExtrema_TriangleSet)& theSet2, + const BRepExtrema_ShapeList& theShapeList1, + const BRepExtrema_ShapeList& theShapeList2, + BVH_Vec3d& thePoint1, + BVH_Vec3d& thePoint2, + ProxPnt_Status& thePointStatus1, + ProxPnt_Status& thePointStatus2) const; + +private: + + //! Set of all mesh primitives of the 1st shape. + Handle(BRepExtrema_TriangleSet) mySet1; + //! Set of all mesh primitives of the 2nd shape. + Handle(BRepExtrema_TriangleSet) mySet2; + + //! List of subshapes of the 1st shape. + BRepExtrema_ShapeList myShapeList1; + //! List of subshapes of the 2nd shape. + BRepExtrema_ShapeList myShapeList2; + + Standard_Real myDistance; //!< Distance + Standard_Boolean myIsDone; //!< State of the algorithm + + Standard_Integer myNbSamples1; //!< Number of samples points on the first shape + Standard_Integer myNbSamples2; //!< Number of samples points on the second shape + + //! Proximity points + gp_Pnt myPnt1, myPnt2; + + //! Proximity points' status + ProxPnt_Status myPntStatus1, myPntStatus2; + +}; + +#endif // _BRepExtrema_ProximityValueTool_HeaderFile diff --git a/src/BRepExtrema/BRepExtrema_SelfIntersection.hxx b/src/BRepExtrema/BRepExtrema_SelfIntersection.hxx index dbad243766..efb1b39fd0 100644 --- a/src/BRepExtrema/BRepExtrema_SelfIntersection.hxx +++ b/src/BRepExtrema/BRepExtrema_SelfIntersection.hxx @@ -18,6 +18,8 @@ #include +#include + //! Tool class for detection of self-sections in the given shape. //! This class is based on BRepExtrema_OverlapTool and thus uses //! shape tessellation to detect incorrect mesh fragments (pairs @@ -76,7 +78,7 @@ public: //! Returns sub-shape from the shape for the given index (started from 0). const TopoDS_Face& GetSubShape (const Standard_Integer theID) const { - return myFaceList.Value (theID); + return TopoDS::Face(myFaceList.Value(theID)); } //! Returns set of all the face triangles of the shape. diff --git a/src/BRepExtrema/BRepExtrema_ShapeProximity.cxx b/src/BRepExtrema/BRepExtrema_ShapeProximity.cxx index 65b2e69589..09efa4e585 100644 --- a/src/BRepExtrema/BRepExtrema_ShapeProximity.cxx +++ b/src/BRepExtrema/BRepExtrema_ShapeProximity.cxx @@ -18,6 +18,28 @@ #include #include +// Assign a map of sub-shapes (edges/faces) of a given shape +static Standard_Boolean initSubShapes(const TopoDS_Shape& theShape, + BRepExtrema_ShapeList& theSubshapesList, + Handle(BRepExtrema_TriangleSet)& theTriangleSet) +{ + theSubshapesList.Clear(); + + for (TopExp_Explorer anIter(theShape, TopAbs_FACE); anIter.More(); anIter.Next()) + { + theSubshapesList.Append(anIter.Current()); + } + + for (TopExp_Explorer anIter(theShape, TopAbs_EDGE); anIter.More(); anIter.Next()) + { + theSubshapesList.Append(anIter.Current()); + } + + if (theTriangleSet.IsNull()) + theTriangleSet = new BRepExtrema_TriangleSet; + return theTriangleSet->Init(theSubshapesList); +} + //======================================================================= //function : BRepExtrema_ShapeProximity //purpose : Creates uninitialized proximity tool @@ -25,7 +47,9 @@ BRepExtrema_ShapeProximity::BRepExtrema_ShapeProximity (const Standard_Real theTolerance) : myTolerance (theTolerance), myElementSet1 (new BRepExtrema_TriangleSet), - myElementSet2 (new BRepExtrema_TriangleSet) + myElementSet2 (new BRepExtrema_TriangleSet), + myNbSamples1 (0), + myNbSamples2 (0) { // Should be initialized later myIsInitS1 = myIsInitS2 = Standard_False; @@ -40,7 +64,9 @@ BRepExtrema_ShapeProximity::BRepExtrema_ShapeProximity (const TopoDS_Shape& theS const Standard_Real theTolerance) : myTolerance (theTolerance), myElementSet1 (new BRepExtrema_TriangleSet), - myElementSet2 (new BRepExtrema_TriangleSet) + myElementSet2 (new BRepExtrema_TriangleSet), + myNbSamples1 (0), + myNbSamples2 (0) { LoadShape1 (theShape1); LoadShape2 (theShape2); @@ -52,16 +78,18 @@ BRepExtrema_ShapeProximity::BRepExtrema_ShapeProximity (const TopoDS_Shape& theS //======================================================================= Standard_Boolean BRepExtrema_ShapeProximity::LoadShape1 (const TopoDS_Shape& theShape1) { - myFaceList1.Clear(); + myIsInitS1 = initSubShapes(theShape1, myShapeList1, myElementSet1); - for (TopExp_Explorer anIter (theShape1, TopAbs_FACE); anIter.More(); anIter.Next()) + if (myTolerance == Precision::Infinite()) { - myFaceList1.Append (static_cast (anIter.Current())); + myProxValTool.MarkDirty(); + } + else + { + myOverlapTool.MarkDirty(); } - myOverlapTool.MarkDirty(); - - return myIsInitS1 = myElementSet1->Init (myFaceList1); + return myIsInitS1; } //======================================================================= @@ -70,16 +98,18 @@ Standard_Boolean BRepExtrema_ShapeProximity::LoadShape1 (const TopoDS_Shape& the //======================================================================= Standard_Boolean BRepExtrema_ShapeProximity::LoadShape2 (const TopoDS_Shape& theShape2) { - myFaceList2.Clear(); + myIsInitS2 = initSubShapes(theShape2, myShapeList2, myElementSet2); - for (TopExp_Explorer anIter (theShape2, TopAbs_FACE); anIter.More(); anIter.Next()) + if (myTolerance == Precision::Infinite()) { - myFaceList2.Append (static_cast (anIter.Current())); + myProxValTool.MarkDirty(); + } + else + { + myOverlapTool.MarkDirty(); } - myOverlapTool.MarkDirty(); - - return myIsInitS2 = myElementSet2->Init (myFaceList2); + return myIsInitS2; } //======================================================================= @@ -88,13 +118,32 @@ Standard_Boolean BRepExtrema_ShapeProximity::LoadShape2 (const TopoDS_Shape& the //======================================================================= void BRepExtrema_ShapeProximity::Perform() { - if (!myIsInitS1 || !myIsInitS2 || myOverlapTool.IsDone()) + if (myTolerance == Precision::Infinite()) { - return; + if (!myIsInitS1 || !myIsInitS2 || myProxValTool.IsDone()) + { + return; + } + + myProxValTool.LoadTriangleSets (myElementSet1, + myElementSet2); + myProxValTool.LoadShapeLists (myShapeList1, + myShapeList2); + + myProxValTool.Perform (myTolerance); + myProxValTool.ProximityPoints(myProxPoint1, myProxPoint2); + myProxValTool.ProximityPointsStatus (myProxPntStatus1, myProxPntStatus2); } + else + { + if (!myIsInitS1 || !myIsInitS2 || myOverlapTool.IsDone()) + { + return; + } - myOverlapTool.LoadTriangleSets (myElementSet1, - myElementSet2); + myOverlapTool.LoadTriangleSets (myElementSet1, + myElementSet2); - myOverlapTool.Perform (myTolerance); + myOverlapTool.Perform (myTolerance); + } } diff --git a/src/BRepExtrema/BRepExtrema_ShapeProximity.hxx b/src/BRepExtrema/BRepExtrema_ShapeProximity.hxx index d863742136..c6f6d77721 100644 --- a/src/BRepExtrema/BRepExtrema_ShapeProximity.hxx +++ b/src/BRepExtrema/BRepExtrema_ShapeProximity.hxx @@ -16,31 +16,48 @@ #ifndef _BRepExtrema_ShapeProximity_HeaderFile #define _BRepExtrema_ShapeProximity_HeaderFile +#include +#include +#include + +#include +#include #include -//! Tool class for shape proximity detection. +//! @brief Tool class for shape proximity detection. +//! +//! First approach: //! For two given shapes and given tolerance (offset from the mesh) the algorithm allows //! to determine whether or not they are overlapped. The algorithm input consists of any //! shapes which can be decomposed into individual faces (used as basic shape elements). -//! High performance is achieved through the use of existing triangulation of faces. So -//! poly triangulation (with the desired deflection) should already be built. Note that -//! solution is approximate (and corresponds to the deflection used for triangulation). //! //! The algorithm can be run in two modes. If tolerance is set to zero, the algorithm //! will detect only intersecting faces (containing triangles with common points). If //! tolerance is set to positive value, the algorithm will also detect faces located //! on distance less than the given tolerance from each other. +//! +//! Second approach: +//! Compute the proximity value between two shapes if the tolerance is not defined (Precision::Infinite()). +//! In this case the proximity value is a minimal thickness of a layer containing both shapes. +//! +//! For the both approaches the high performance is achieved through the use of existing +//! triangulation of faces. So, poly triangulation (with the desired deflection) should already +//! be built. Note that solution is approximate (and corresponds to the deflection used for +//! triangulation). class BRepExtrema_ShapeProximity { +public: + typedef typename BRepExtrema_ProximityValueTool::ProxPnt_Status ProxPnt_Status; + public: //! Creates empty proximity tool. - Standard_EXPORT BRepExtrema_ShapeProximity (const Standard_Real theTolerance = 0.0); + Standard_EXPORT BRepExtrema_ShapeProximity (const Standard_Real theTolerance = Precision::Infinite()); //! Creates proximity tool for the given two shapes. Standard_EXPORT BRepExtrema_ShapeProximity (const TopoDS_Shape& theShape1, const TopoDS_Shape& theShape2, - const Standard_Real theTolerance = 0.0); + const Standard_Real theTolerance = Precision::Infinite()); public: @@ -56,19 +73,33 @@ public: myTolerance = theTolerance; } + //! Returns proximity value calculated for the whole input shapes. + Standard_Real Proximity() const + { + return Tolerance(); + } + //! Loads 1st shape into proximity tool. Standard_EXPORT Standard_Boolean LoadShape1 (const TopoDS_Shape& theShape1); //! Loads 2nd shape into proximity tool. Standard_EXPORT Standard_Boolean LoadShape2 (const TopoDS_Shape& theShape2); + //! Set number of sample points on the 1st shape used to compute the proximity value. + //! In case of 0, all triangulation nodes will be used. + void SetNbSamples1(const Standard_Integer theNbSamples) { myNbSamples1 = theNbSamples; } + + //! Set number of sample points on the 2nd shape used to compute the proximity value. + //! In case of 0, all triangulation nodes will be used. + void SetNbSamples2(const Standard_Integer theNbSamples) { myNbSamples2 = theNbSamples; } + //! Performs search of overlapped faces. Standard_EXPORT void Perform(); //! True if the search is completed. Standard_Boolean IsDone() const { - return myOverlapTool.IsDone(); + return myOverlapTool.IsDone() || myProxValTool.IsDone(); } //! Returns set of IDs of overlapped faces of 1st shape (started from 0). @@ -84,15 +115,15 @@ public: } //! Returns sub-shape from 1st shape with the given index (started from 0). - const TopoDS_Face& GetSubShape1 (const Standard_Integer theID) const + const TopoDS_Shape& GetSubShape1 (const Standard_Integer theID) const { - return myFaceList1.Value (theID); + return myShapeList1.Value (theID); } //! Returns sub-shape from 1st shape with the given index (started from 0). - const TopoDS_Face& GetSubShape2 (const Standard_Integer theID) const + const TopoDS_Shape& GetSubShape2 (const Standard_Integer theID) const { - return myFaceList2.Value (theID); + return myShapeList2.Value (theID); } //! Returns set of all the face triangles of the 1st shape. @@ -107,6 +138,34 @@ public: return myElementSet2; } + //! Returns the point on the 1st shape, which could be used as a reference point + //! for the value of the proximity. + const gp_Pnt& ProximityPoint1() const + { + return myProxPoint1; + } + + //! Returns the point on the 2nd shape, which could be used as a reference point + //! for the value of the proximity. + const gp_Pnt& ProximityPoint2() const + { + return myProxPoint2; + } + + //! Returns the status of point on the 1st shape, which could be used as a reference point + //! for the value of the proximity. + const ProxPnt_Status& ProxPntStatus1() const + { + return myProxPntStatus1; + } + + //! Returns the status of point on the 2nd shape, which could be used as a reference point + //! for the value of the proximity. + const ProxPnt_Status& ProxPntStatus2() const + { + return myProxPntStatus2; + } + private: //! Maximum overlapping distance. @@ -117,19 +176,39 @@ private: //! Is the 2nd shape initialized? Standard_Boolean myIsInitS2; - //! List of faces of the 1st shape. - BRepExtrema_ShapeList myFaceList1; - //! List of faces of the 2nd shape. - BRepExtrema_ShapeList myFaceList2; + //! List of subshapes of the 1st shape. + BRepExtrema_ShapeList myShapeList1; + //! List of subshapes of the 2nd shape. + BRepExtrema_ShapeList myShapeList2; //! Set of all the face triangles of the 1st shape. Handle(BRepExtrema_TriangleSet) myElementSet1; //! Set of all the face triangles of the 2nd shape. Handle(BRepExtrema_TriangleSet) myElementSet2; + //! Number of sample points on the 1st shape used to compute the proximity value + //! (if zero (default), all triangulation nodes will be used). + Standard_Integer myNbSamples1; + //! Number of sample points on the 2nd shape used to compute the proximity value + //! (if zero (default), all triangulation nodes will be used). + Standard_Integer myNbSamples2; + + //! Reference point of the proximity value on the 1st shape. + gp_Pnt myProxPoint1; + //! Reference point of the proximity value on the 2st shape. + gp_Pnt myProxPoint2; + + //! Status of reference points of the proximity value. + ProxPnt_Status myProxPntStatus1, myProxPntStatus2; + //! Overlap tool used for intersection/overlap test. BRepExtrema_OverlapTool myOverlapTool; + //! Shape-shape proximity tool used for computation of + //! the minimal diameter of a tube containing both edges or + //! the minimal thickness of a shell containing both faces. + BRepExtrema_ProximityValueTool myProxValTool; + }; #endif // _BRepExtrema_ShapeProximity_HeaderFile diff --git a/src/BRepExtrema/BRepExtrema_TriangleSet.cxx b/src/BRepExtrema/BRepExtrema_TriangleSet.cxx index 48189a4add..e1f843d809 100644 --- a/src/BRepExtrema/BRepExtrema_TriangleSet.cxx +++ b/src/BRepExtrema/BRepExtrema_TriangleSet.cxx @@ -18,6 +18,7 @@ #include #include #include +#include IMPLEMENT_STANDARD_RTTIEXT(BRepExtrema_TriangleSet, BVH_PrimitiveSet3d) @@ -114,17 +115,65 @@ void BRepExtrema_TriangleSet::Swap (const Standard_Integer theIndex1, const Stan { std::swap (myTriangles[theIndex1], myTriangles[theIndex2]); + + std::swap (myTrgIdxMap (theIndex1), + myTrgIdxMap (theIndex2)); } //======================================================================= //function : GetFaceID -//purpose : Returns face ID of the given triangle +//purpose : Returns face ID of the given vertex //======================================================================= Standard_Integer BRepExtrema_TriangleSet::GetFaceID (const Standard_Integer theIndex) const { return myTriangles[theIndex].w(); } +//======================================================================= +//function : GetShapeIDOfVtx +//purpose : Returns shape ID of the given vertex index +//======================================================================= +Standard_Integer BRepExtrema_TriangleSet::GetShapeIDOfVtx (const Standard_Integer theIndex) const +{ + return myShapeIdxOfVtxVec.Value (theIndex); +} + +//======================================================================= +//function : GetVtxIdxInShape +//purpose : Returns vertex index in tringulation of the shape, which vertex belongs, +// with the given vtx ID in whole set +//======================================================================= +Standard_Integer BRepExtrema_TriangleSet::GetVtxIdxInShape (const Standard_Integer theIndex) const +{ + Standard_Integer aShID = myShapeIdxOfVtxVec.Value (theIndex); + Standard_Integer aNumVertices = 0; + + for (Standard_Integer aSIdx = 0; aSIdx < aShID; aSIdx++) + { + aNumVertices += myNumVtxInShapeVec.Value (aSIdx); + } + + return theIndex - aNumVertices; +} + +//======================================================================= +//function : GetTrgIdxInShape +//purpose : Returns triangle index (before swapping) in tringulation of the shape, which triangle belongs, +// with the given trg ID in whole set (after swapping) +//======================================================================= +Standard_Integer BRepExtrema_TriangleSet::GetTrgIdxInShape (const Standard_Integer theIndex) const +{ + Standard_Integer aShID = GetFaceID (theIndex); + Standard_Integer aNumTriangles = 0; + + for (Standard_Integer aSIdx = 0; aSIdx < aShID; aSIdx++) + { + aNumTriangles += myNumTrgInShapeVec.Value (aSIdx); + } + + return myTrgIdxMap (theIndex) - aNumTriangles; +} + //======================================================================= //function : GetVertices //purpose : Returns vertices of the given triangle @@ -141,6 +190,21 @@ void BRepExtrema_TriangleSet::GetVertices (const Standard_Integer theIndex, theVertex3 = myVertexArray[aTriangle.z()]; } +//======================================================================= +//function : GetVertices +//purpose : Returns vertices of the given triangle +//======================================================================= +void BRepExtrema_TriangleSet::GetVtxIndices (const Standard_Integer theIndex, + NCollection_Array1& theVtxIndices) const +{ + BVH_Vec4i aTriangle = myTriangles[theIndex]; + + theVtxIndices = NCollection_Array1 (0, 2); + theVtxIndices.SetValue (0, aTriangle.x()); + theVtxIndices.SetValue (1, aTriangle.y()); + theVtxIndices.SetValue (2, aTriangle.z()); +} + //======================================================================= //function : Clear //purpose : Clears triangle set data @@ -158,41 +222,26 @@ void BRepExtrema_TriangleSet::Clear() //function : Init //purpose : Initializes triangle set //======================================================================= -Standard_Boolean BRepExtrema_TriangleSet::Init (const BRepExtrema_ShapeList& theFaces) +Standard_Boolean BRepExtrema_TriangleSet::Init (const BRepExtrema_ShapeList& theShapes) { Clear(); - for (Standard_Integer aFaceIdx = 0; aFaceIdx < theFaces.Size(); ++aFaceIdx) + Standard_Boolean isOK = Standard_True; + for (Standard_Integer aShapeIdx = 0; aShapeIdx < theShapes.Size() && isOK; ++aShapeIdx) { - TopLoc_Location aLocation; + if (theShapes (aShapeIdx).ShapeType() == TopAbs_FACE) + isOK = initFace (TopoDS::Face (theShapes(aShapeIdx)), aShapeIdx); + else if (theShapes (aShapeIdx).ShapeType() == TopAbs_EDGE) + isOK = initEdge (TopoDS::Edge (theShapes(aShapeIdx)), aShapeIdx); + } - Handle(Poly_Triangulation) aTriangulation = - BRep_Tool::Triangulation (theFaces (aFaceIdx), aLocation); + Standard_Integer aNumTrg = static_cast (myTriangles.size()); + myTrgIdxMap.Clear(); + myTrgIdxMap.ReSize (aNumTrg); - if (aTriangulation.IsNull()) - { - return Standard_False; - } - - const Standard_Integer aVertOffset = - static_cast (myVertexArray.size()) - 1; - - for (Standard_Integer aVertIdx = 1; aVertIdx <= aTriangulation->NbNodes(); ++aVertIdx) - { - gp_Pnt aVertex = aTriangulation->Node (aVertIdx); - aVertex.Transform (aLocation.Transformation()); - myVertexArray.push_back (BVH_Vec3d (aVertex.X(), aVertex.Y(), aVertex.Z())); - } - - for (Standard_Integer aTriIdx = 1; aTriIdx <= aTriangulation->NbTriangles(); ++aTriIdx) - { - Standard_Integer aVertex1, aVertex2, aVertex3; - aTriangulation->Triangle (aTriIdx).Get (aVertex1, aVertex2, aVertex3); - myTriangles.push_back (BVH_Vec4i (aVertex1 + aVertOffset, - aVertex2 + aVertOffset, - aVertex3 + aVertOffset, - aFaceIdx)); - } + for (Standard_Integer aTrgIdx = 0; aTrgIdx < aNumTrg; ++aTrgIdx) + { + myTrgIdxMap.Bind (aTrgIdx, aTrgIdx); } MarkDirty(); // needs BVH rebuilding @@ -203,3 +252,95 @@ Standard_Boolean BRepExtrema_TriangleSet::Init (const BRepExtrema_ShapeList& the return Standard_True; } +//======================================================================= +//function : initFace +//purpose : Initializes triangle set +//======================================================================= +Standard_Boolean BRepExtrema_TriangleSet::initFace (const TopoDS_Face& theFace, const Standard_Integer theIndex) +{ + TopLoc_Location aLocation; + + Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (theFace, aLocation); + if (aTriangulation.IsNull()) + { + return Standard_False; + } + + const Standard_Integer aVertOffset = + static_cast (myVertexArray.size()) - 1; + + initNodes (aTriangulation->MapNodeArray()->ChangeArray1(), aLocation.Transformation(), theIndex); + + for (Standard_Integer aTriIdx = 1; aTriIdx <= aTriangulation->NbTriangles(); ++aTriIdx) + { + Standard_Integer aVertex1; + Standard_Integer aVertex2; + Standard_Integer aVertex3; + + aTriangulation->Triangle (aTriIdx).Get (aVertex1, + aVertex2, + aVertex3); + + myTriangles.push_back (BVH_Vec4i (aVertex1 + aVertOffset, + aVertex2 + aVertOffset, + aVertex3 + aVertOffset, + theIndex)); + } + + myNumTrgInShapeVec.SetValue (theIndex, aTriangulation->NbTriangles()); + + return Standard_True; +} + +//======================================================================= +//function : initEdge +//purpose : Initializes triangle set +//======================================================================= +Standard_Boolean BRepExtrema_TriangleSet::initEdge (const TopoDS_Edge& theEdge, const Standard_Integer theIndex) +{ + TopLoc_Location aLocation; + + Handle(Poly_Polygon3D) aPolygon = BRep_Tool::Polygon3D (theEdge, aLocation); + if (aPolygon.IsNull()) + { + return Standard_False; + } + + const Standard_Integer aVertOffset = + static_cast (myVertexArray.size()) - 1; + + initNodes (aPolygon->Nodes(), aLocation.Transformation(), theIndex); + + for (Standard_Integer aVertIdx = 1; aVertIdx < aPolygon->NbNodes(); ++aVertIdx) + { + // segment as degenerate triangle + myTriangles.push_back (BVH_Vec4i (aVertIdx + aVertOffset, + aVertIdx + aVertOffset + 1, + aVertIdx + aVertOffset + 1, + theIndex)); + } + return Standard_True; +} + +//======================================================================= +//function : initNodes +//purpose : Initializes nodes +//======================================================================= +void BRepExtrema_TriangleSet::initNodes (const TColgp_Array1OfPnt& theNodes, + const gp_Trsf& theTrsf, + const Standard_Integer theIndex) +{ + for (Standard_Integer aVertIdx = 1; aVertIdx <= theNodes.Size(); ++aVertIdx) + { + gp_Pnt aVertex = theNodes.Value (aVertIdx); + + aVertex.Transform (theTrsf); + + myVertexArray.push_back (BVH_Vec3d (aVertex.X(), + aVertex.Y(), + aVertex.Z())); + myShapeIdxOfVtxVec.Append (theIndex); + } + + myNumVtxInShapeVec.SetValue (theIndex, theNodes.Size()); +} diff --git a/src/BRepExtrema/BRepExtrema_TriangleSet.hxx b/src/BRepExtrema/BRepExtrema_TriangleSet.hxx index 3b0414c75b..eb87430cb1 100644 --- a/src/BRepExtrema/BRepExtrema_TriangleSet.hxx +++ b/src/BRepExtrema/BRepExtrema_TriangleSet.hxx @@ -16,11 +16,14 @@ #ifndef _BRepExtrema_TriangleSet_HeaderFile #define _BRepExtrema_TriangleSet_HeaderFile -#include #include +#include +#include +#include +#include //! List of shapes and their IDs for collision detection. -typedef NCollection_Vector BRepExtrema_ShapeList; +typedef NCollection_Vector BRepExtrema_ShapeList; //! Triangle set corresponding to specific face. class BRepExtrema_TriangleSet : public BVH_PrimitiveSet3d @@ -59,7 +62,10 @@ public: Standard_EXPORT void Clear(); //! Initializes triangle set. - Standard_EXPORT Standard_Boolean Init (const BRepExtrema_ShapeList& theFaces); + Standard_EXPORT Standard_Boolean Init (const BRepExtrema_ShapeList& theShapes); + + //! Returns all vertices. + Standard_EXPORT const BVH_Array3d& GetVertices() const { return myVertexArray; } //! Returns vertices of the given triangle. Standard_EXPORT void GetVertices (const Standard_Integer theIndex, @@ -67,9 +73,37 @@ public: BVH_Vec3d& theVertex2, BVH_Vec3d& theVertex3) const; + //! Returns vertex indices of the given triangle. + Standard_EXPORT void GetVtxIndices (const Standard_Integer theIndex, + NCollection_Array1& theVtxIndices) const; + //! Returns face ID of the given triangle. Standard_EXPORT Standard_Integer GetFaceID (const Standard_Integer theIndex) const; + //! Returns shape ID of the given vertex index. + Standard_EXPORT Standard_Integer GetShapeIDOfVtx (const Standard_Integer theIndex) const; + + //! Returns vertex index in tringulation of the shape, which vertex belongs, + //! with the given vtx ID in whole set. + Standard_EXPORT Standard_Integer GetVtxIdxInShape (const Standard_Integer theIndex) const; + + //! Returns triangle index (before swapping) in tringulation of the shape, which triangle belongs, + //! with the given trg ID in whole set (after swapping). + Standard_EXPORT Standard_Integer GetTrgIdxInShape (const Standard_Integer theIndex) const; + +private: + + //! Initializes triangle set from the face + Standard_Boolean initFace (const TopoDS_Face& theFace, const Standard_Integer theIndex); + + //! Initializes polygon from the edge + Standard_Boolean initEdge (const TopoDS_Edge& theEdge, const Standard_Integer theIndex); + + //! Initializes nodes + void initNodes (const TColgp_Array1OfPnt& theNodes, + const gp_Trsf& theTrsf, + const Standard_Integer theIndex); + protected: //! Array of vertex indices. @@ -78,6 +112,19 @@ protected: //! Array of vertex coordinates. BVH_Array3d myVertexArray; + //! Vector of shapes' indices where index of item corresponds to index of vertex, + //! belonging to this shape. + NCollection_Vector myShapeIdxOfVtxVec; + + //! Vector of vertexes' number belonging to shape which index corresponds item's index. + NCollection_Vector myNumVtxInShapeVec; + + //! Vector of triangles' number belonging to shape which index corresponds item's index. + NCollection_Vector myNumTrgInShapeVec; + + //! Map of triangles' indices after (key) and before (value) swapping. + TColStd_DataMapOfIntegerInteger myTrgIdxMap; + public: DEFINE_STANDARD_RTTIEXT(BRepExtrema_TriangleSet, BVH_PrimitiveSet3d) diff --git a/src/BRepExtrema/FILES b/src/BRepExtrema/FILES index e9fc5d2f30..b7405afc30 100644 --- a/src/BRepExtrema/FILES +++ b/src/BRepExtrema/FILES @@ -18,6 +18,10 @@ BRepExtrema_OverlapTool.cxx BRepExtrema_OverlapTool.hxx BRepExtrema_Poly.cxx BRepExtrema_Poly.hxx +BRepExtrema_ProximityValueTool.cxx +BRepExtrema_ProximityValueTool.hxx +BRepExtrema_ProximityDistTool.cxx +BRepExtrema_ProximityDistTool.hxx BRepExtrema_SelfIntersection.cxx BRepExtrema_SelfIntersection.hxx BRepExtrema_SeqOfSolution.hxx diff --git a/src/BRepTest/BRepTest_ExtremaCommands.cxx b/src/BRepTest/BRepTest_ExtremaCommands.cxx index ee9d0f4f7d..0976a5349b 100644 --- a/src/BRepTest/BRepTest_ExtremaCommands.cxx +++ b/src/BRepTest/BRepTest_ExtremaCommands.cxx @@ -173,7 +173,7 @@ static int ShapeProximity (Draw_Interpretor& theDI, Standard_Integer theNbArgs, { if (theNbArgs < 3 || theNbArgs > 6) { - Message::SendFail() << "Usage: " << theArgs[0] << " Shape1 Shape2 [-tol ] [-profile]"; + Message::SendFail() << "Usage: " << theArgs[0] << " Shape1 Shape2 [-tol | -value] [-profile]"; return 1; } @@ -186,9 +186,11 @@ static int ShapeProximity (Draw_Interpretor& theDI, Standard_Integer theNbArgs, return 1; } - BRepExtrema_ShapeProximity aTool; + BRepExtrema_ShapeProximity aTool(0.0); Standard_Boolean aProfile = Standard_False; + Standard_Boolean isTolerance = Standard_False; + Standard_Boolean isValue = Standard_False; for (Standard_Integer anArgIdx = 3; anArgIdx < theNbArgs; ++anArgIdx) { @@ -197,6 +199,7 @@ static int ShapeProximity (Draw_Interpretor& theDI, Standard_Integer theNbArgs, if (aFlag == "-tol") { + isTolerance = Standard_True; if (++anArgIdx >= theNbArgs) { Message::SendFail() << "Error: wrong syntax at argument '" << aFlag; @@ -214,13 +217,23 @@ static int ShapeProximity (Draw_Interpretor& theDI, Standard_Integer theNbArgs, aTool.SetTolerance (aTolerance); } } - - if (aFlag == "-profile") + else if (aFlag == "-value") + { + isValue = Standard_True; + aTool.SetTolerance(Precision::Infinite()); + } + else if (aFlag == "-profile") { aProfile = Standard_True; } } + if (isTolerance && isValue) + { + Message::SendFail() << "Error: Proximity value could not be computed if the tolerance is set"; + return 1; + } + Standard_Real aInitTime = 0.0; Standard_Real aWorkTime = 0.0; @@ -264,39 +277,74 @@ static int ShapeProximity (Draw_Interpretor& theDI, Standard_Integer theNbArgs, theDI << "Executing proximity test: " << aWorkTime << "\n"; } - TopoDS_Builder aCompBuilder; - - TopoDS_Compound aFaceCompound1; - aCompBuilder.MakeCompound (aFaceCompound1); - - for (BRepExtrema_MapOfIntegerPackedMapOfInteger::Iterator anIt1 (aTool.OverlapSubShapes1()); anIt1.More(); anIt1.Next()) + if (isValue) { - TCollection_AsciiString aStr = TCollection_AsciiString (theArgs[1]) + "_" + (anIt1.Key() + 1); + theDI << "Proximity value: " << aTool.Proximity() << "\n"; - const TopoDS_Face& aFace = aTool.GetSubShape1 (anIt1.Key()); - aCompBuilder.Add (aFaceCompound1, aFace); - DBRep::Set (aStr.ToCString(), aFace); + // proximity points + TopoDS_Vertex aProxVtx1 = BRepLib_MakeVertex (aTool.ProximityPoint1()); + TopoDS_Vertex aProxVtx2 = BRepLib_MakeVertex (aTool.ProximityPoint2()); - theDI << aStr << " \n"; + DBRep::Set ("ProxPnt1", aProxVtx1); + DBRep::Set ("ProxPnt2", aProxVtx2); + + // proximity points' status + TCollection_AsciiString ProxPntStatus1; + TCollection_AsciiString ProxPntStatus2; + + switch (aTool.ProxPntStatus1()) + { + case 0: ProxPntStatus1 = "Border"; break; + case 1: ProxPntStatus1 = "Middle"; break; + default: ProxPntStatus1 = "Unknown"; + } + + switch (aTool.ProxPntStatus2()) + { + case 0: ProxPntStatus2 = "Border"; break; + case 1: ProxPntStatus2 = "Middle"; break; + default: ProxPntStatus2 = "Unknown"; + } + + theDI << " Status of ProxPnt1 on " << theArgs[1] << " : " << ProxPntStatus1 << "\n"; + theDI << " Status of ProxPnt2 on " << theArgs[2] << " : " << ProxPntStatus2 << "\n"; } - - TopoDS_Compound aFaceCompound2; - aCompBuilder.MakeCompound (aFaceCompound2); - - for (BRepExtrema_MapOfIntegerPackedMapOfInteger::Iterator anIt2 (aTool.OverlapSubShapes2()); anIt2.More(); anIt2.Next()) + else { - TCollection_AsciiString aStr = TCollection_AsciiString (theArgs[2]) + "_" + (anIt2.Key() + 1); + TopoDS_Builder aCompBuilder; - const TopoDS_Face& aFace = aTool.GetSubShape2 (anIt2.Key()); - aCompBuilder.Add (aFaceCompound2, aFace); - DBRep::Set (aStr.ToCString(), aFace); + TopoDS_Compound aFaceCompound1; + aCompBuilder.MakeCompound(aFaceCompound1); - theDI << aStr << " \n"; + for (BRepExtrema_MapOfIntegerPackedMapOfInteger::Iterator anIt1(aTool.OverlapSubShapes1()); anIt1.More(); anIt1.Next()) + { + TCollection_AsciiString aStr = TCollection_AsciiString(theArgs[1]) + "_" + (anIt1.Key() + 1); + + const TopoDS_Shape& aShape = aTool.GetSubShape1(anIt1.Key()); + aCompBuilder.Add(aFaceCompound1, aShape); + DBRep::Set(aStr.ToCString(), aShape); + + theDI << aStr << " \n"; + } + + TopoDS_Compound aFaceCompound2; + aCompBuilder.MakeCompound(aFaceCompound2); + + for (BRepExtrema_MapOfIntegerPackedMapOfInteger::Iterator anIt2(aTool.OverlapSubShapes2()); anIt2.More(); anIt2.Next()) + { + TCollection_AsciiString aStr = TCollection_AsciiString(theArgs[2]) + "_" + (anIt2.Key() + 1); + + const TopoDS_Shape& aShape = aTool.GetSubShape2(anIt2.Key()); + aCompBuilder.Add(aFaceCompound2, aShape); + DBRep::Set(aStr.ToCString(), aShape); + + theDI << aStr << " \n"; + } + + DBRep::Set((TCollection_AsciiString(theArgs[1]) + "_" + "overlapped").ToCString(), aFaceCompound1); + DBRep::Set((TCollection_AsciiString(theArgs[2]) + "_" + "overlapped").ToCString(), aFaceCompound2); } - DBRep::Set ((TCollection_AsciiString (theArgs[1]) + "_" + "overlapped").ToCString(), aFaceCompound1); - DBRep::Set ((TCollection_AsciiString (theArgs[2]) + "_" + "overlapped").ToCString(), aFaceCompound2); - return 0; } @@ -445,12 +493,14 @@ void BRepTest::ExtremaCommands (Draw_Interpretor& theCommands) aGroup); theCommands.Add ("proximity", - "proximity Shape1 Shape2 [-tol ] [-profile]" + "proximity Shape1 Shape2 [-tol | -value] [-profile]" "\n\t\t: Searches for pairs of overlapping faces of the given shapes." "\n\t\t: The options are:" "\n\t\t: -tol : non-negative tolerance value used for overlapping" "\n\t\t: test (for zero tolerance, the strict intersection" "\n\t\t: test will be performed)" + "\n\t\t: -value : compute the proximity value (minimal value which" + "\n\t\t: shows both shapes fully overlapped)" "\n\t\t: -profile : outputs execution time for main algorithm stages", __FILE__, ShapeProximity, diff --git a/src/BVH/BVH_Tools.hxx b/src/BVH/BVH_Tools.hxx index b90034778b..1aee086ffb 100644 --- a/src/BVH/BVH_Tools.hxx +++ b/src/BVH/BVH_Tools.hxx @@ -30,6 +30,15 @@ public: //! @name public types typedef typename BVH::VectorType::Type BVH_VecNt; +public: + + enum BVH_PrjStateInTriangle + { + BVH_PrjStateInTriangle_VERTEX, + BVH_PrjStateInTriangle_EDGE, + BVH_PrjStateInTriangle_INNER + }; + public: //! @name Box-Box Square distance //! Computes Square distance between Axis aligned bounding boxes @@ -113,11 +122,14 @@ public: //! @name Point-Box projection public: //! @name Point-Triangle Square distance - //! Computes square distance between point and triangle - static T PointTriangleSquareDistance (const BVH_VecNt& thePoint, - const BVH_VecNt& theNode0, - const BVH_VecNt& theNode1, - const BVH_VecNt& theNode2) + //! Find nearest point on a triangle for the given point + static BVH_VecNt PointTriangleProjection (const BVH_VecNt& thePoint, + const BVH_VecNt& theNode0, + const BVH_VecNt& theNode1, + const BVH_VecNt& theNode2, + BVH_PrjStateInTriangle* thePrjState = nullptr, + Standard_Integer* theNumberOfFirstNode = nullptr, + Standard_Integer* theNumberOfLastNode = nullptr) { const BVH_VecNt aAB = theNode1 - theNode0; const BVH_VecNt aAC = theNode2 - theNode0; @@ -128,68 +140,110 @@ public: //! @name Point-Triangle Square distance if (aABdotAP <= 0. && aACdotAP <= 0.) { - return aAP.Dot(aAP); + if (thePrjState != nullptr) + { + *thePrjState = BVH_PrjStateInTriangle_VERTEX; + *theNumberOfFirstNode = 0; + *theNumberOfLastNode = 0; + } + return theNode0; } - + const BVH_VecNt aBC = theNode2 - theNode1; const BVH_VecNt aBP = thePoint - theNode1; - - T aBAdotBP = -(aAB.Dot(aBP)); - T aBCdotBP = (aBC.Dot(aBP)); - + + T aBAdotBP = -(aAB.Dot (aBP)); + T aBCdotBP = (aBC.Dot (aBP)); + if (aBAdotBP <= 0. && aBCdotBP <= 0.) { - return (aBP.Dot(aBP)); + if (thePrjState != nullptr) + { + *thePrjState = BVH_PrjStateInTriangle_VERTEX; + *theNumberOfFirstNode = 1; + *theNumberOfLastNode = 1; + } + return theNode1; } - + const BVH_VecNt aCP = thePoint - theNode2; - - T aCBdotCP = -(aBC.Dot(aCP)); - T aCAdotCP = -(aAC.Dot(aCP)); - + + T aCBdotCP = -(aBC.Dot (aCP)); + T aCAdotCP = -(aAC.Dot (aCP)); + if (aCAdotCP <= 0. && aCBdotCP <= 0.) { - return (aCP.Dot(aCP)); + if (thePrjState != nullptr) + { + *thePrjState = BVH_PrjStateInTriangle_VERTEX; + *theNumberOfFirstNode = 2; + *theNumberOfLastNode = 2; + } + return theNode2; } - - T aACdotBP = (aAC.Dot(aBP)); - + + T aACdotBP = (aAC.Dot (aBP)); + T aVC = aABdotAP * aACdotBP + aBAdotBP * aACdotAP; - + if (aVC <= 0. && aABdotAP > 0. && aBAdotBP > 0.) { - const BVH_VecNt aDirect = aAP - aAB * (aABdotAP / (aABdotAP + aBAdotBP)); - - return (aDirect.Dot(aDirect)); + if (thePrjState != nullptr) + { + *thePrjState = BVH_PrjStateInTriangle_EDGE; + *theNumberOfFirstNode = 0; + *theNumberOfLastNode = 1; + } + return theNode0 + aAB * (aABdotAP / (aABdotAP + aBAdotBP)); } - - T aABdotCP = (aAB.Dot(aCP)); - + + T aABdotCP = (aAB.Dot (aCP)); + T aVA = aBAdotBP * aCAdotCP - aABdotCP * aACdotBP; - + if (aVA <= 0. && aBCdotBP > 0. && aCBdotCP > 0.) { - const BVH_VecNt aDirect = aBP - aBC * (aBCdotBP / (aBCdotBP + aCBdotCP)); - - return (aDirect.Dot(aDirect)); + if (thePrjState != nullptr) + { + *thePrjState = BVH_PrjStateInTriangle_EDGE; + *theNumberOfFirstNode = 1; + *theNumberOfLastNode = 2; + } + return theNode1 + aBC * (aBCdotBP / (aBCdotBP + aCBdotCP)); } - + T aVB = aABdotCP * aACdotAP + aABdotAP * aCAdotCP; - + if (aVB <= 0. && aACdotAP > 0. && aCAdotCP > 0.) { - const BVH_VecNt aDirect = aAP - aAC * (aACdotAP / (aACdotAP + aCAdotCP)); - - return (aDirect.Dot(aDirect)); + if (thePrjState != nullptr) + { + *thePrjState = BVH_PrjStateInTriangle_EDGE; + *theNumberOfFirstNode = 2; + *theNumberOfLastNode = 0; + } + return theNode0 + aAC * (aACdotAP / (aACdotAP + aCAdotCP)); } - + T aNorm = aVA + aVB + aVC; - - const BVH_VecNt& aDirect = thePoint - (theNode0 * aVA + - theNode1 * aVB + - theNode2 * aVC) / aNorm; - - return (aDirect.Dot(aDirect)); + + if (thePrjState != nullptr) + { + *thePrjState = BVH_PrjStateInTriangle_INNER; + } + + return (theNode0 * aVA + theNode1 * aVB + theNode2 * aVC) / aNorm; + } + + //! Computes square distance between point and triangle + static T PointTriangleSquareDistance (const BVH_VecNt& thePoint, + const BVH_VecNt& theNode0, + const BVH_VecNt& theNode1, + const BVH_VecNt& theNode2) + { + const BVH_VecNt aProj = PointTriangleProjection(thePoint, theNode0, theNode1, theNode2); + const BVH_VecNt aPP = aProj - thePoint; + return aPP.Dot(aPP); } public: //! @name Ray-Box Intersection diff --git a/tests/lowalgos/grids.list b/tests/lowalgos/grids.list index cb983a9781..6b1835d322 100644 --- a/tests/lowalgos/grids.list +++ b/tests/lowalgos/grids.list @@ -9,3 +9,4 @@ 009 bvh 010 progress 011 2ddeviation +012 proximity diff --git a/tests/lowalgos/proximity/A1 b/tests/lowalgos/proximity/A1 new file mode 100644 index 0000000000..2a7025c155 --- /dev/null +++ b/tests/lowalgos/proximity/A1 @@ -0,0 +1,24 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +circle c 0 0 0 1 0 0 5 +mkedge e1 c pi/2 pi +mkedge e2 c -pi/2 0 +incmesh e1 1.e-3 +incmesh e2 1.e-3 + +set log [proximity e1 e2 -value -profile] + +regexp {Proximity value: ([0-9+-.eE]*)} $log full val +set tol 1.e-3 +set expected 10.0 + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Middle + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Middle \ No newline at end of file diff --git a/tests/lowalgos/proximity/A2 b/tests/lowalgos/proximity/A2 new file mode 100644 index 0000000000..61a92c1112 --- /dev/null +++ b/tests/lowalgos/proximity/A2 @@ -0,0 +1,26 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +circle c1 0 0 0 1 0 0 1 +mkedge e1 c1 +incmesh e1 1.e-3 + +circle c2 0 0 0 0 1 0 1 +mkedge e2 c2 +incmesh e2 1.e-3 + +set log [proximity e1 e2 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-3 +set expected 2.0 + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Middle + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Middle \ No newline at end of file diff --git a/tests/lowalgos/proximity/A3 b/tests/lowalgos/proximity/A3 new file mode 100644 index 0000000000..f878329398 --- /dev/null +++ b/tests/lowalgos/proximity/A3 @@ -0,0 +1,28 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +circle c1 0 -1 0 1 0 0 1 +trim c1 c1 -pi 0 +mkedge e1 c1 +incmesh e1 1.e-3 + +circle c2 0 1 0 1 0 0 1 +trim c2 c2 0 pi +mkedge e2 c2 +incmesh e2 1.e-3 + +set log [proximity e1 e2 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-3 +set expected [expr {sqrt(5.0) - 1.}] + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Middle + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Border \ No newline at end of file diff --git a/tests/lowalgos/proximity/A4 b/tests/lowalgos/proximity/A4 new file mode 100644 index 0000000000..29c72fdc9e --- /dev/null +++ b/tests/lowalgos/proximity/A4 @@ -0,0 +1,26 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +circle c1 0 0 0 1 0 0 1 +mkedge e1 c1 +incmesh e1 1.e-3 + +circle c2 0 0 0 -1 0.5 0 1 +mkedge e2 c2 +incmesh e2 1.e-3 + +set log [proximity e1 e2 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-3 +set expected 2.0 + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Middle + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Middle \ No newline at end of file diff --git a/tests/lowalgos/proximity/A5 b/tests/lowalgos/proximity/A5 new file mode 100644 index 0000000000..19a1daed9a --- /dev/null +++ b/tests/lowalgos/proximity/A5 @@ -0,0 +1,31 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +circle c1 0 0 0 1 0 0 1 +trim c1 c1 -pi/2. pi/2. +mkedge e1 c1 +incmesh e1 1.e-3 + +circle c2 0 0 0 1 0.5 0 1 +trim c2 c2 0 pi +mkedge e2 c2 +incmesh e2 1.e-3 + +set log [proximity e1 e2 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-3 +explode e1 v +explode e2 v +distmini d e1_1 e2_1 +regexp {([-0-9.+eE]+)$} [dump d_val] full expected + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Middle + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Border \ No newline at end of file diff --git a/tests/lowalgos/proximity/B1 b/tests/lowalgos/proximity/B1 new file mode 100644 index 0000000000..68d434859b --- /dev/null +++ b/tests/lowalgos/proximity/B1 @@ -0,0 +1,28 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +plane p1 0 0 0 0 0 1 +trim p1 p1 -1 1 -1 1 +mkface f1 p1 +incmesh f1 1.e-1 + +plane p2 0 0 1 0 0 1 +trim p2 p2 -1 1 -1 1 +mkface f2 p2 +incmesh f2 1.e-1 + +set log [proximity f1 f2 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-3 +set expected 1.0 + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Border + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Border \ No newline at end of file diff --git a/tests/lowalgos/proximity/B2 b/tests/lowalgos/proximity/B2 new file mode 100644 index 0000000000..aff0e9a10b --- /dev/null +++ b/tests/lowalgos/proximity/B2 @@ -0,0 +1,28 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +plane p1 0 0 0 0 0 1 +trim p1 p1 -1 1 -1 1 +mkface f1 p1 +incmesh f1 1.e-1 + +plane p2 0 0 1 -1 0 0 +trim p2 p2 -1 1 -1 1 +mkface f2 p2 +incmesh f2 1.e-1 + +set log [proximity f1 f2 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-3 +set expected 1.0 + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Border + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Border \ No newline at end of file diff --git a/tests/lowalgos/proximity/B3 b/tests/lowalgos/proximity/B3 new file mode 100644 index 0000000000..67f0c62a6f --- /dev/null +++ b/tests/lowalgos/proximity/B3 @@ -0,0 +1,28 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +plane p1 0 0 0 0 0 1 +trim p1 p1 -1 1 -1 1 +mkface f1 p1 +incmesh f1 1.e-1 + +plane p2 0 0 0 -1 0 0 +trim p2 p2 -1 1 -1 1 +mkface f2 p2 +incmesh f2 1.e-1 + +set log [proximity f1 f2 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-3 +set expected 1.0 + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Border + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Border \ No newline at end of file diff --git a/tests/lowalgos/proximity/B4 b/tests/lowalgos/proximity/B4 new file mode 100644 index 0000000000..1250bbf6fb --- /dev/null +++ b/tests/lowalgos/proximity/B4 @@ -0,0 +1,28 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +plane p1 0 0 0 0 0 1 +trim p1 p1 -1 1 -1 1 +mkface f1 p1 +incmesh f1 1.e-1 + +plane p2 0 0 0.5 -1 0 0 +trim p2 p2 -1 1 -1 1 +mkface f2 p2 +incmesh f2 1.e-1 + +set log [proximity f1 f2 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-3 +set expected 1.0 + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Border + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Border \ No newline at end of file diff --git a/tests/lowalgos/proximity/B5 b/tests/lowalgos/proximity/B5 new file mode 100644 index 0000000000..048d1834b9 --- /dev/null +++ b/tests/lowalgos/proximity/B5 @@ -0,0 +1,27 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +plane p1 0 0 0 0 0 1 +trim p1 p1 -1 1 -1 1 +mkface f1 p1 +incmesh f1 1.e-3 + +polyline f2 -1 -1 1 -1 1 1 1 1 2 1 -1 2 -1 -1 1 +mkplane f2 f2 +incmesh f2 1.e-3 + +set log [proximity f1 f2 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-3 +set expected [expr {0.8 * sqrt(5.0)}] + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Border + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Border \ No newline at end of file diff --git a/tests/lowalgos/proximity/B6 b/tests/lowalgos/proximity/B6 new file mode 100644 index 0000000000..860919a914 --- /dev/null +++ b/tests/lowalgos/proximity/B6 @@ -0,0 +1,27 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +plane p1 0 0 0 0 0 1 +trim p1 p1 -1 1 -1 1 +mkface f1 p1 +incmesh f1 1.e-3 + +circle c 0 0 1 1 +mkedge e1 c +incmesh e1 1.e-3 + +set log [proximity f1 e1 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-3 +set expected 1.0 + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Border + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Middle \ No newline at end of file diff --git a/tests/lowalgos/proximity/C1 b/tests/lowalgos/proximity/C1 new file mode 100644 index 0000000000..457512464c --- /dev/null +++ b/tests/lowalgos/proximity/C1 @@ -0,0 +1,29 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +plane p1 0 0 0 0 0 1 +trim p1 p1 -1 1 -1 1 +mkface f1 p1 +incmesh f1 1.e-3 + +dset lo pi/2. la 0. +cylinder cy1 0 0 0 cos(la)*cos(lo) cos(la)*sin(lo) sin(la) 0.1 +trimv cy1 cy1 0 1 +mkface fcy1 cy1 +incmesh fcy1 1.e-3 + +set log [proximity f1 fcy1 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-3 +set expected 0.1 + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Middle + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Border \ No newline at end of file diff --git a/tests/lowalgos/proximity/C2 b/tests/lowalgos/proximity/C2 new file mode 100644 index 0000000000..2920e41c82 --- /dev/null +++ b/tests/lowalgos/proximity/C2 @@ -0,0 +1,29 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +plane p1 0 0 0 0 0 1 +trim p1 p1 -2 2 -2 2 +mkface f1 p1 +incmesh f1 1.e-3 + +dset lo pi/2. la pi/4. +cylinder cy1 0 0 1 cos(la)*cos(lo) cos(la)*sin(lo) sin(la) 0.1 +trimv cy1 cy1 0 1 +mkface fcy1 cy1 +incmesh fcy1 1.e-3 + +set log [proximity f1 fcy1 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-3 +set expected [expr {1. + 1.1 * sqrt(2.)/2.}] + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Middle + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Border \ No newline at end of file diff --git a/tests/lowalgos/proximity/C3 b/tests/lowalgos/proximity/C3 new file mode 100644 index 0000000000..9323eb8574 --- /dev/null +++ b/tests/lowalgos/proximity/C3 @@ -0,0 +1,28 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +cylinder cy1 0 0 1 1 0 0 0.1 +trimv cy1 cy1 0 1 +mkface fcy1 cy1 +incmesh fcy1 1.e-3 + +cylinder cy2 0 0 0 1 0 0 0.1 +trimv cy2 cy2 0 1 +mkface fcy2 cy2 +incmesh fcy2 1.e-3 + +set log [proximity fcy1 fcy2 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-3 +set expected 1.0 + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Border + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Border \ No newline at end of file diff --git a/tests/lowalgos/proximity/C4 b/tests/lowalgos/proximity/C4 new file mode 100644 index 0000000000..acbaf9ff78 --- /dev/null +++ b/tests/lowalgos/proximity/C4 @@ -0,0 +1,28 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +cylinder cy1 0 0 1 1 0 0 0.1 +trim cy1 cy1 -pi/2. pi/2. 0 1 +mkface fcy1 cy1 +incmesh fcy1 1.e-5 + +cylinder cy2 0 0 0 1 0 0 0.1 +trim cy2 cy2 pi/2. -pi/2. 0 1 +mkface fcy2 cy2 +incmesh fcy2 1.e-5 + +set log [proximity fcy1 fcy2 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-3 +set expected 1.2 + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Border + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Border \ No newline at end of file diff --git a/tests/lowalgos/proximity/D1 b/tests/lowalgos/proximity/D1 new file mode 100644 index 0000000000..2e8dccc185 --- /dev/null +++ b/tests/lowalgos/proximity/D1 @@ -0,0 +1,28 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +sphere s1 0 1 0 0 0 1 1 +trimu s1 s1 0 pi +mkface fs1 s1 +incmesh fs1 1e-3 + +sphere s2 0 -1 0 0 0 1 1 +trimu s2 s2 -pi 0 +mkface fs2 s2 +incmesh fs2 1e-3 + +set log [proximity fs1 fs2 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-2 +set expected 4.0 + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Middle + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Middle \ No newline at end of file diff --git a/tests/lowalgos/proximity/D2 b/tests/lowalgos/proximity/D2 new file mode 100644 index 0000000000..0c19db3fbb --- /dev/null +++ b/tests/lowalgos/proximity/D2 @@ -0,0 +1,26 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +sphere s1 0 1 0 0 0 1 1 +mkface fs1 s1 +incmesh fs1 1e-3 + +sphere s2 0 -1 0 0 0 1 1 +mkface fs2 s2 +incmesh fs2 1e-3 + +set log [proximity fs1 fs2 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-2 +set expected 4.0 + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Middle + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Middle \ No newline at end of file diff --git a/tests/lowalgos/proximity/D3 b/tests/lowalgos/proximity/D3 new file mode 100644 index 0000000000..8a3704cb1f --- /dev/null +++ b/tests/lowalgos/proximity/D3 @@ -0,0 +1,33 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +sphere s1 0 1 0 0 0 1 1 +trimu s1_1 s1 0 0.5*pi +trimu s1_2 s1 0.5*pi pi + +mkface fs1_1 s1_1 +mkface fs1_2 s1_2 +compound fs1_1 fs1_2 fs1 +incmesh fs1 1e-3 + +plane p1 0 0 0 0 1 0 +trim p1 p1 -2 2 -2 2 +mkface f2 p1 +incmesh f2 0.001 + +set log [proximity fs1 f2 -value -profile] + +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-2 +set expected 2.0 + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Border + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Middle \ No newline at end of file diff --git a/tests/lowalgos/proximity/E1 b/tests/lowalgos/proximity/E1 new file mode 100644 index 0000000000..0997c1139d --- /dev/null +++ b/tests/lowalgos/proximity/E1 @@ -0,0 +1,30 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +beziercurve bc1 7 10 84 0 54 96 0 145 146 0 167 167 0 185 212 0 187 234 0 176 302 0 +beziercurve bc2 8 120 72 0 170 87 0 227 118 0 238 126 0 243 157 0 203 216 0 134 281 0 94 324 0 + +mkedge e1 bc1 +mkedge e2 bc2 + +incmesh e1 1.e-3 +incmesh e2 1.e-3 + +set log [proximity e1 e2 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-3 +explode e1 v +explode e2 v +distmini d e1_2 e2_2 +regexp {([-0-9.+eE]+)$} [dump d_val] full expected + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Border + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Border \ No newline at end of file diff --git a/tests/lowalgos/proximity/E2 b/tests/lowalgos/proximity/E2 new file mode 100644 index 0000000000..ffdd658156 --- /dev/null +++ b/tests/lowalgos/proximity/E2 @@ -0,0 +1,27 @@ +puts "============" +puts "0033017: Implement an algorithm to find a proximity between a pair of shapes" +puts "===========" +puts "" + +beziercurve bc1 6 54 96 0 145 146 0 167 167 0 185 212 0 187 234 0 176 302 0 +beziercurve bc2 7 120 72 0 170 87 0 227 118 0 238 126 0 243 157 0 203 216 0 134 281 0 + +mkedge e1 bc1 +mkedge e2 bc2 + +incmesh e1 1.e-3 +incmesh e2 1.e-3 + +set log [proximity e1 e2 -value -profile] +regexp {Proximity value: ([0-9+-.eE]*)} $log full val; + +set tol 1.e-3 +set expected 76.34 + +regexp {Status of ProxPnt1 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status1 ${val2} +set expected_status1 Middle + +regexp {Status of ProxPnt2 on ([A-Za-z0-9._-]*) : ([A-Za-z]*)} $log full val1 val2 +set status2 ${val2} +set expected_status2 Middle \ No newline at end of file diff --git a/tests/lowalgos/proximity/end b/tests/lowalgos/proximity/end new file mode 100644 index 0000000000..43cebceab4 --- /dev/null +++ b/tests/lowalgos/proximity/end @@ -0,0 +1,19 @@ +set er [expr abs(${expected} - ${val})] + +if {${er} > ${tol}} { + puts "Error: bad proximity value" +} else { + puts "OK" +} + +if {${status1} != ${expected_status1}} { + puts "Error: bad 1st proximity point status" +} else { + puts "OK" +} + +if {${status2} != ${expected_status2}} { + puts "Error: bad 2nd proximity point status" +} else { + puts "OK" +} \ No newline at end of file