// Created on: 1995-03-14 // Created by: Robert COUBLANC // Copyright (c) 1995-1999 Matra Datavision // Copyright (c) 1999-2014 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BVH_PRIMITIVE_LIMIT 800000 //================================================== // function: PreBuildBVH // purpose : Pre-builds BVH tree for heavyweight // sensitive entities with sub-elements // amount more than BVH_PRIMITIVE_LIMIT //================================================== void StdSelect_BRepSelectionTool::PreBuildBVH (const Handle(SelectMgr_Selection)& theSelection) { for (NCollection_Vector::Iterator aSelEntIter (theSelection->Entities()); aSelEntIter.More(); aSelEntIter.Next()) { const Handle(Select3D_SensitiveEntity)& aSensitive = aSelEntIter.Value()->BaseSensitive(); if (aSensitive->NbSubElements() >= BVH_PRIMITIVE_LIMIT) { aSensitive->BVH(); } if (!aSensitive->IsInstance (STANDARD_TYPE(Select3D_SensitiveGroup))) { continue; } Handle(Select3D_SensitiveGroup) aGroup = Handle(Select3D_SensitiveGroup)::DownCast (aSensitive); for (Select3D_IndexedMapOfEntity::Iterator aSubEntitiesIter (aGroup->Entities()); aSubEntitiesIter.More(); aSubEntitiesIter.Next()) { const Handle(Select3D_SensitiveEntity)& aSubEntity = aSubEntitiesIter.Value(); if (aSubEntity->NbSubElements() >= BVH_PRIMITIVE_LIMIT) { aSubEntity->BVH(); } } } } //================================================== // Function: Load // Purpose : //================================================== void StdSelect_BRepSelectionTool::Load (const Handle(SelectMgr_Selection)& theSelection, const TopoDS_Shape& theShape, const TopAbs_ShapeEnum theType, const Standard_Real theDeflection, const Standard_Real theDeviationAngle, const Standard_Boolean isAutoTriangulation, const Standard_Integer thePriority, const Standard_Integer theNbPOnEdge, const Standard_Real theMaxParam) { Standard_Integer aPriority = (thePriority == -1) ? GetStandardPriority (theShape, theType) : thePriority; if (isAutoTriangulation && !BRepTools::Triangulation (theShape, Precision::Infinite(), true)) { BRepMesh_IncrementalMesh aMesher(theShape, theDeflection, Standard_False, theDeviationAngle); } Handle(StdSelect_BRepOwner) aBrepOwner; switch (theType) { case TopAbs_VERTEX: case TopAbs_EDGE: case TopAbs_WIRE: case TopAbs_FACE: case TopAbs_SHELL: case TopAbs_SOLID: case TopAbs_COMPSOLID: { TopTools_IndexedMapOfShape aSubShapes; TopExp::MapShapes (theShape, theType, aSubShapes); Standard_Boolean isComesFromDecomposition = !((aSubShapes.Extent() == 1) && (theShape == aSubShapes (1))); for (Standard_Integer aShIndex = 1; aShIndex <= aSubShapes.Extent(); ++aShIndex) { const TopoDS_Shape& aSubShape = aSubShapes (aShIndex); aBrepOwner = new StdSelect_BRepOwner (aSubShape, aPriority, isComesFromDecomposition); ComputeSensitive (aSubShape, aBrepOwner, theSelection, theDeflection, theDeviationAngle, theNbPOnEdge, theMaxParam, isAutoTriangulation); } break; } default: { aBrepOwner = new StdSelect_BRepOwner (theShape, aPriority); ComputeSensitive (theShape, aBrepOwner, theSelection, theDeflection, theDeviationAngle, theNbPOnEdge, theMaxParam, isAutoTriangulation); } } } //================================================== // Function: Load // Purpose : //================================================== void StdSelect_BRepSelectionTool::Load (const Handle(SelectMgr_Selection)& theSelection, const Handle(SelectMgr_SelectableObject)& theSelectableObj, const TopoDS_Shape& theShape, const TopAbs_ShapeEnum theType, const Standard_Real theDeflection, const Standard_Real theDeviationAngle, const Standard_Boolean isAutoTriangulation, const Standard_Integer thePriority, const Standard_Integer theNbPOnEdge, const Standard_Real theMaxParam) { Load (theSelection, theShape, theType, theDeflection, theDeviationAngle, isAutoTriangulation, thePriority, theNbPOnEdge, theMaxParam); // loading of selectables... for (NCollection_Vector::Iterator aSelEntIter (theSelection->Entities()); aSelEntIter.More(); aSelEntIter.Next()) { const Handle(SelectMgr_EntityOwner)& anOwner = aSelEntIter.Value()->BaseSensitive()->OwnerId(); anOwner->SetSelectable (theSelectableObj); } PreBuildBVH (theSelection); } //================================================== // Function: ComputeSensitive // Purpose : //================================================== void StdSelect_BRepSelectionTool::ComputeSensitive (const TopoDS_Shape& theShape, const Handle(SelectMgr_EntityOwner)& theOwner, const Handle(SelectMgr_Selection)& theSelection, const Standard_Real theDeflection, const Standard_Real theDeviationAngle, const Standard_Integer theNbPOnEdge, const Standard_Real theMaxParam, const Standard_Boolean isAutoTriangulation) { switch (theShape.ShapeType()) { case TopAbs_VERTEX: { theSelection->Add (new Select3D_SensitivePoint (theOwner, BRep_Tool::Pnt (TopoDS::Vertex (theShape)))); break; } case TopAbs_EDGE: { Handle(Select3D_SensitiveEntity) aSensitive; GetEdgeSensitive (theShape, theOwner, theSelection, theDeflection, theDeviationAngle, theNbPOnEdge, theMaxParam, aSensitive); if (!aSensitive.IsNull()) { theSelection->Add (aSensitive); } break; } case TopAbs_WIRE: { BRepTools_WireExplorer aWireExp (TopoDS::Wire (theShape)); Handle (Select3D_SensitiveEntity) aSensitive; Handle (Select3D_SensitiveWire) aWireSensitive = new Select3D_SensitiveWire (theOwner); theSelection->Add (aWireSensitive); while (aWireExp.More()) { GetEdgeSensitive (aWireExp.Current(), theOwner, theSelection, theDeflection, theDeviationAngle, theNbPOnEdge, theMaxParam, aSensitive); if (!aSensitive.IsNull()) { aWireSensitive->Add (aSensitive); } aWireExp.Next(); } break; } case TopAbs_FACE: { const TopoDS_Face& aFace = TopoDS::Face (theShape); Select3D_EntitySequence aSensitiveList; GetSensitiveForFace (aFace, theOwner, aSensitiveList, isAutoTriangulation, theNbPOnEdge, theMaxParam); for (Select3D_EntitySequenceIter aSensIter (aSensitiveList); aSensIter.More(); aSensIter.Next()) { theSelection->Add (aSensIter.Value()); } break; } case TopAbs_SHELL: case TopAbs_SOLID: case TopAbs_COMPSOLID: { TopTools_IndexedMapOfShape aSubfacesMap; TopExp::MapShapes (theShape, TopAbs_FACE, aSubfacesMap); for (Standard_Integer aShIndex = 1; aShIndex <= aSubfacesMap.Extent(); ++aShIndex) { ComputeSensitive (aSubfacesMap (aShIndex), theOwner, theSelection, theDeflection, theDeviationAngle, theNbPOnEdge, theMaxParam, isAutoTriangulation); } break; } case TopAbs_COMPOUND: default: { TopExp_Explorer anExp; // sub-vertices for (anExp.Init (theShape, TopAbs_VERTEX, TopAbs_EDGE); anExp.More(); anExp.Next()) { ComputeSensitive (anExp.Current(), theOwner, theSelection, theDeflection, theDeviationAngle, theNbPOnEdge, theMaxParam, isAutoTriangulation); } // sub-edges for (anExp.Init (theShape, TopAbs_EDGE, TopAbs_FACE); anExp.More(); anExp.Next()) { ComputeSensitive (anExp.Current(), theOwner, theSelection, theDeflection, theDeviationAngle, theNbPOnEdge, theMaxParam, isAutoTriangulation); } // sub-wires for (anExp.Init (theShape, TopAbs_WIRE, TopAbs_FACE); anExp.More(); anExp.Next()) { ComputeSensitive (anExp.Current(), theOwner, theSelection, theDeflection, theDeviationAngle, theNbPOnEdge, theMaxParam, isAutoTriangulation); } // sub-faces TopTools_IndexedMapOfShape aSubfacesMap; TopExp::MapShapes (theShape, TopAbs_FACE, aSubfacesMap); for (Standard_Integer aShIndex = 1; aShIndex <= aSubfacesMap.Extent(); ++aShIndex) { ComputeSensitive (aSubfacesMap (aShIndex), theOwner, theSelection, theDeflection, theDeviationAngle, theNbPOnEdge, theMaxParam, isAutoTriangulation); } } } } //================================================== // Function: GetPointsFromPolygon // Purpose : //================================================== static Handle(TColgp_HArray1OfPnt) GetPointsFromPolygon (const TopoDS_Edge& theEdge) { Handle(TColgp_HArray1OfPnt) aResultPoints; TopLoc_Location aLocation; Handle(Poly_Polygon3D) aPolygon = BRep_Tool::Polygon3D (theEdge, aLocation); if (!aPolygon.IsNull()) { const TColgp_Array1OfPnt& aNodes = aPolygon->Nodes(); aResultPoints = new TColgp_HArray1OfPnt (1, aNodes.Length()); if (aLocation.IsIdentity()) { for (Standard_Integer aNodeId (aNodes.Lower()), aPntId (1); aNodeId <= aNodes.Upper(); ++aNodeId, ++aPntId) { aResultPoints->SetValue (aPntId, aNodes.Value (aNodeId)); } } else { for (Standard_Integer aNodeId (aNodes.Lower()), aPntId (1); aNodeId <= aNodes.Upper(); ++aNodeId, ++aPntId) { aResultPoints->SetValue (aPntId, aNodes.Value (aNodeId).Transformed (aLocation)); } } return aResultPoints; } Handle(Poly_Triangulation) aTriangulation; Handle(Poly_PolygonOnTriangulation) anHIndices; BRep_Tool::PolygonOnTriangulation (theEdge, anHIndices, aTriangulation, aLocation); if (!anHIndices.IsNull()) { const TColStd_Array1OfInteger& anIndices = anHIndices->Nodes(); const TColgp_Array1OfPnt& aNodes = aTriangulation->Nodes(); aResultPoints = new TColgp_HArray1OfPnt (1, anIndices.Length()); if (aLocation.IsIdentity()) { for (Standard_Integer anIndex (anIndices.Lower()), aPntId (1); anIndex <= anIndices.Upper(); ++anIndex, ++aPntId) { aResultPoints->SetValue (aPntId, aNodes (anIndices (anIndex))); } } else { for (Standard_Integer anIndex (anIndices.Lower()), aPntId (1); anIndex <= anIndices.Upper(); ++anIndex, ++aPntId) { aResultPoints->SetValue (aPntId, aNodes (anIndices (anIndex)).Transformed (aLocation)); } } return aResultPoints; } return aResultPoints; } //================================================== // Function: FindLimits // Purpose : //================================================== static Standard_Boolean FindLimits (const Adaptor3d_Curve& theCurve, const Standard_Real theLimit, Standard_Real& theFirst, Standard_Real& theLast) { theFirst = theCurve.FirstParameter(); theLast = theCurve.LastParameter(); Standard_Boolean isFirstInf = Precision::IsNegativeInfinite (theFirst); Standard_Boolean isLastInf = Precision::IsPositiveInfinite (theLast); if (isFirstInf || isLastInf) { gp_Pnt aPnt1, aPnt2; Standard_Real aDelta = 1.0; Standard_Integer anIterCount = 0; if (isFirstInf && isLastInf) { do { if (anIterCount++ >= 100000) return Standard_False; aDelta *= 2.0; theFirst = - aDelta; theLast = aDelta; theCurve.D0 (theFirst, aPnt1); theCurve.D0 (theLast, aPnt2); } while (aPnt1.Distance (aPnt2) < theLimit); } else if (isFirstInf) { theCurve.D0 (theLast, aPnt2); do { if (anIterCount++ >= 100000) return Standard_False; aDelta *= 2.0; theFirst = theLast - aDelta; theCurve.D0 (theFirst, aPnt1); } while (aPnt1.Distance (aPnt2) < theLimit); } else if (isLastInf) { theCurve.D0 (theFirst, aPnt1); do { if (anIterCount++ >= 100000) return Standard_False; aDelta *= 2.0; theLast = theFirst + aDelta; theCurve.D0 (theLast, aPnt2); } while (aPnt1.Distance (aPnt2) < theLimit); } } return Standard_True; } //===================================================== // Function : GetEdgeSensitive // Purpose : //===================================================== void StdSelect_BRepSelectionTool::GetEdgeSensitive (const TopoDS_Shape& theShape, const Handle(SelectMgr_EntityOwner)& theOwner, const Handle(SelectMgr_Selection)& theSelection, const Standard_Real theDeflection, const Standard_Real theDeviationAngle, const Standard_Integer theNbPOnEdge, const Standard_Real theMaxParam, Handle(Select3D_SensitiveEntity)& theSensitive) { const TopoDS_Edge& anEdge = TopoDS::Edge (theShape); // try to get points from existing polygons Handle(TColgp_HArray1OfPnt) aPoints = GetPointsFromPolygon (anEdge); if (!aPoints.IsNull() && !aPoints->IsEmpty()) { if (aPoints->Length() == 2) { // don't waste memory, create a segment theSensitive = new Select3D_SensitiveSegment (theOwner, aPoints->First(), aPoints->Last()); } else { theSensitive = new Select3D_SensitiveCurve (theOwner, aPoints); } return; } BRepAdaptor_Curve cu3d; try { OCC_CATCH_SIGNALS cu3d.Initialize (anEdge); } catch (Standard_NullObject const&) { return; } Standard_Real aParamFirst = cu3d.FirstParameter(); Standard_Real aParamLast = cu3d.LastParameter(); switch (cu3d.GetType()) { case GeomAbs_Line: { BRep_Tool::Range (anEdge, aParamFirst, aParamLast); theSensitive = new Select3D_SensitiveSegment (theOwner, cu3d.Value (aParamFirst), cu3d.Value (aParamLast)); break; } case GeomAbs_Circle: { Handle (Geom_Circle) aCircle = new Geom_Circle (cu3d.Circle()); if (aCircle->Radius() <= Precision::Confusion()) { theSelection->Add (new Select3D_SensitivePoint (theOwner, aCircle->Location())); } else { theSensitive = new Select3D_SensitiveCircle (theOwner, aCircle, aParamFirst, aParamLast, Standard_False, 16); } break; } default: { // reproduce drawing behaviour // TODO: remove copy-paste from StdPrs_Curve and some others... if (FindLimits (cu3d, theMaxParam, aParamFirst, aParamLast)) { Standard_Integer aNbIntervals = cu3d.NbIntervals (GeomAbs_C1); TColStd_Array1OfReal anIntervals (1, aNbIntervals + 1); cu3d.Intervals (anIntervals, GeomAbs_C1); Standard_Real aV1, aV2; Standard_Integer aNumberOfPoints; TColgp_SequenceOfPnt aPointsSeq; for (Standard_Integer anIntervalId = 1; anIntervalId <= aNbIntervals; ++anIntervalId) { aV1 = anIntervals (anIntervalId); aV2 = anIntervals (anIntervalId + 1); if (aV2 > aParamFirst && aV1 < aParamLast) { aV1 = Max (aV1, aParamFirst); aV2 = Min (aV2, aParamLast); GCPnts_TangentialDeflection anAlgo (cu3d, aV1, aV2, theDeviationAngle, theDeflection); aNumberOfPoints = anAlgo.NbPoints(); for (Standard_Integer aPntId = 1; aPntId < aNumberOfPoints; ++aPntId) { aPointsSeq.Append (anAlgo.Value (aPntId)); } if (aNumberOfPoints > 0 && anIntervalId == aNbIntervals) { aPointsSeq.Append (anAlgo.Value (aNumberOfPoints)); } } } aPoints = new TColgp_HArray1OfPnt (1, aPointsSeq.Length()); for (Standard_Integer aPntId = 1; aPntId <= aPointsSeq.Length(); ++aPntId) { aPoints->SetValue (aPntId, aPointsSeq.Value (aPntId)); } theSensitive = new Select3D_SensitiveCurve (theOwner, aPoints); break; } // simple subdivisions Standard_Integer nbintervals = 1; if (cu3d.GetType() == GeomAbs_BSplineCurve) { nbintervals = cu3d.NbKnots() - 1; nbintervals = Max (1, nbintervals / 3); } Standard_Real aParam; Standard_Integer aPntNb = Max (2, theNbPOnEdge * nbintervals); Standard_Real aParamDelta = (aParamLast - aParamFirst) / (aPntNb - 1); Handle(TColgp_HArray1OfPnt) aPointArray = new TColgp_HArray1OfPnt (1, aPntNb); for (Standard_Integer aPntId = 1; aPntId <= aPntNb; ++aPntId) { aParam = aParamFirst + aParamDelta * (aPntId - 1); aPointArray->SetValue (aPntId, cu3d.Value (aParam)); } theSensitive = new Select3D_SensitiveCurve (theOwner, aPointArray); } break; } } //======================================================================= //function : GetSensitiveEntityForFace //purpose : //======================================================================= Standard_Boolean StdSelect_BRepSelectionTool::GetSensitiveForFace (const TopoDS_Face& theFace, const Handle(SelectMgr_EntityOwner)& theOwner, Select3D_EntitySequence& theSensitiveList, const Standard_Boolean /*theAutoTriangulation*/, const Standard_Integer NbPOnEdge, const Standard_Real theMaxParam, const Standard_Boolean theInteriorFlag) { TopLoc_Location aLoc; if (Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (theFace, aLoc)) { Handle(Select3D_SensitiveTriangulation) STG = new Select3D_SensitiveTriangulation (theOwner, aTriangulation, aLoc, theInteriorFlag); theSensitiveList.Append (STG); return Standard_True; } // for faces with triangulation bugs or without autotriangulation .... // very ugly and should not even exist ... BRepAdaptor_Surface BS (theFace); if (BS.GetType() == GeomAbs_Plane) { const Standard_Real aFirstU = BS.FirstUParameter() <= -Precision::Infinite() ? -theMaxParam : BS.FirstUParameter(); const Standard_Real aLastU = BS.LastUParameter() >= Precision::Infinite() ? theMaxParam : BS.LastUParameter(); const Standard_Real aFirstV = BS.FirstVParameter() <= -Precision::Infinite() ? -theMaxParam : BS.FirstVParameter(); const Standard_Real aLastV = BS.LastVParameter() >= Precision::Infinite() ? theMaxParam : BS.LastVParameter(); Handle(TColgp_HArray1OfPnt) aPlanePnts = new TColgp_HArray1OfPnt (1, 5); BS.D0 (aFirstU, aFirstV, aPlanePnts->ChangeValue (1)); BS.D0 (aLastU, aFirstV, aPlanePnts->ChangeValue (2)); BS.D0 (aLastU, aLastV, aPlanePnts->ChangeValue (3)); BS.D0 (aFirstU, aLastV, aPlanePnts->ChangeValue (4)); aPlanePnts->SetValue (5, aPlanePnts->Value (1)); // if the plane is "infinite", it is sensitive only on the border limited by MaxParam const bool isInfinite = aFirstU == -theMaxParam && aLastU == theMaxParam && aFirstV == -theMaxParam && aLastV == theMaxParam; theSensitiveList.Append (new Select3D_SensitiveFace (theOwner, aPlanePnts, theInteriorFlag && !isInfinite ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY)); return Standard_True; } // This is construction of a sensitive polygon from the exterior contour of the face... // It is not good at all, but... TopoDS_Wire aWire; { TopExp_Explorer anExpWiresInFace (theFace, TopAbs_WIRE); if (anExpWiresInFace.More()) { // believing that this is the first... to be seen aWire = TopoDS::Wire (anExpWiresInFace.Current()); } } if (aWire.IsNull()) { return Standard_False; } TColgp_SequenceOfPnt aWirePoints; Standard_Boolean isFirstExp = Standard_True; BRepAdaptor_Curve cu3d; for (BRepTools_WireExplorer aWireExplorer (aWire); aWireExplorer.More(); aWireExplorer.Next()) { try { OCC_CATCH_SIGNALS cu3d.Initialize (aWireExplorer.Current()); } catch (Standard_NullObject const&) { continue; } Standard_Real wf = 0.0, wl = 0.0; BRep_Tool::Range (aWireExplorer.Current(), wf, wl); if (Abs (wf - wl) <= Precision::Confusion()) { #ifdef OCCT_DEBUG std::cout<<" StdSelect_BRepSelectionTool : Curve where ufirst = ulast ...."<= ff; wc -= dw) { aWirePoints.Append (cu3d.Value (wc)); } } } else { if (cu3d.Circle().Radius() <= Precision::Confusion()) { theSensitiveList.Append (new Select3D_SensitivePoint (theOwner, cu3d.Circle().Location())); } else { theSensitiveList.Append (new Select3D_SensitiveCircle (theOwner, new Geom_Circle (cu3d.Circle()), theInteriorFlag, 16)); } } } else { Standard_Real ff = wf, ll = wl; Standard_Real dw = (Max (wf, wl) - Min (wf, wl)) / (Standard_Real )Max (2, NbPOnEdge - 1); if (aWireExplorer.Orientation() == TopAbs_FORWARD) { for (Standard_Real wc = wf + dw; wc <= wl; wc += dw) { aWirePoints.Append (cu3d.Value (wc)); } } else if (aWireExplorer.Orientation() == TopAbs_REVERSED) { for (Standard_Real wc = ll - dw; wc >= ff; wc -= dw) { aWirePoints.Append (cu3d.Value (wc)); } } } break; } default: { Standard_Real ff = wf, ll = wl; Standard_Real dw = (Max (wf, wl) - Min (wf, wl)) / (Standard_Real )Max (2, NbPOnEdge - 1); if (aWireExplorer.Orientation()==TopAbs_FORWARD) { for (Standard_Real wc = wf + dw; wc <= wl; wc += dw) { aWirePoints.Append (cu3d.Value (wc)); } } else if (aWireExplorer.Orientation() == TopAbs_REVERSED) { for (Standard_Real wc = ll - dw; wc >= ff; wc -= dw) { aWirePoints.Append (cu3d.Value (wc)); } } } } } Handle(TColgp_HArray1OfPnt) aFacePoints = new TColgp_HArray1OfPnt (1, aWirePoints.Length()); { Standard_Integer aPntIndex = 1; for (TColgp_SequenceOfPnt::Iterator aPntIter (aWirePoints); aPntIter.More(); aPntIter.Next()) { aFacePoints->SetValue (aPntIndex++, aPntIter.Value()); } } // 1 if only one circular edge if (aFacePoints->Array1().Length() == 2) { theSensitiveList.Append (new Select3D_SensitiveCurve (theOwner, aFacePoints)); } else if (aFacePoints->Array1().Length() > 2) { theSensitiveList.Append (new Select3D_SensitiveFace (theOwner, aFacePoints, theInteriorFlag ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY)); } return Standard_True; }