// 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 #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); } } //================================================== // 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); if (aSubfacesMap.Extent() == 2) // detect cone { const TopoDS_Face* aFaces[2] = { &TopoDS::Face (aSubfacesMap.FindKey (1)), &TopoDS::Face (aSubfacesMap.FindKey (2)) }; TopLoc_Location aLocSurf[2]; const Handle(Geom_Surface)* aSurfaces[2] = { &BRep_Tool::Surface (*aFaces[0], aLocSurf[0]), &BRep_Tool::Surface (*aFaces[1], aLocSurf[1]) }; Standard_Integer aConIndex = 0; Handle(Geom_ConicalSurface) aGeomCone = Handle(Geom_ConicalSurface)::DownCast (*aSurfaces[0]); Handle(Geom_Plane) aGeomPln; if (!aGeomCone.IsNull()) { aGeomPln = Handle(Geom_Plane)::DownCast (*aSurfaces[1]); } else { aConIndex = 1; aGeomCone = Handle(Geom_ConicalSurface)::DownCast (*aSurfaces[1]); aGeomPln = Handle(Geom_Plane)::DownCast (*aSurfaces[0]); } if (!aGeomCone.IsNull() && !aGeomPln.IsNull() && aGeomPln->Position().Direction().IsEqual (aGeomCone->Position().Direction(), Precision::Angular())) { const gp_Cone aCone = BRepAdaptor_Surface (*aFaces[aConIndex]).Cone(); const Standard_Real aRad1 = aCone.RefRadius(); const Standard_Real aHeight = (aRad1 != 0.0) ? aRad1 / Abs (Tan (aCone.SemiAngle())) : aCone.Location().Distance (aGeomPln->Location().Transformed (aLocSurf[aConIndex == 0 ? 1 : 0])); const Standard_Real aRad2 = (aRad1 != 0.0) ? 0.0 : Tan (aCone.SemiAngle()) * aHeight; gp_Trsf aTrsf; aTrsf.SetTransformation (aCone.Position(), gp_Ax3()); Handle(Select3D_SensitiveCylinder) aSensSCyl = new Select3D_SensitiveCylinder (theOwner, aRad1, aRad2, aHeight, aTrsf); theSelection->Add (aSensSCyl); break; } } if (aSubfacesMap.Extent() == 3) // detect cylinder or truncated cone { const TopoDS_Face* aFaces[3] = { &TopoDS::Face (aSubfacesMap.FindKey (1)), &TopoDS::Face (aSubfacesMap.FindKey (2)), &TopoDS::Face (aSubfacesMap.FindKey (3)) }; TopLoc_Location aLocSurf[3]; const Handle(Geom_Surface)* aSurfaces[3] = { &BRep_Tool::Surface (*aFaces[0], aLocSurf[0]), &BRep_Tool::Surface (*aFaces[1], aLocSurf[1]), &BRep_Tool::Surface (*aFaces[2], aLocSurf[2]) }; Standard_Integer aConIndex = -1, aNbPlanes = 0; Handle(Geom_ConicalSurface) aGeomCone; Handle(Geom_CylindricalSurface) aGeomCyl; Handle(Geom_Plane) aGeomPlanes[2]; const TopLoc_Location* aGeomPlanesLoc[2]; for (Standard_Integer aSurfIter = 0; aSurfIter < 3; ++aSurfIter) { const Handle(Geom_Surface)& aSurf = *aSurfaces[aSurfIter]; if (aConIndex == -1) { aGeomCone = Handle (Geom_ConicalSurface)::DownCast (aSurf); if (!aGeomCone.IsNull()) { aConIndex = aSurfIter; continue; } aGeomCyl = Handle (Geom_CylindricalSurface)::DownCast (aSurf); if (!aGeomCyl.IsNull()) { aConIndex = aSurfIter; continue; } } if (aNbPlanes < 2) { aGeomPlanes[aNbPlanes] = Handle(Geom_Plane)::DownCast (aSurf); if (!aGeomPlanes[aNbPlanes].IsNull()) { aGeomPlanesLoc[aNbPlanes] = &aLocSurf[aSurfIter]; ++aNbPlanes; } } } if (!aGeomCone.IsNull()) { if (!aGeomPlanes[0].IsNull() && !aGeomPlanes[1].IsNull() && aGeomPlanes[0]->Position().Direction().IsEqual (aGeomCone->Position().Direction(), Precision::Angular()) && aGeomPlanes[1]->Position().Direction().IsEqual (aGeomCone->Position().Direction(), Precision::Angular())) { const gp_Cone aCone = BRepAdaptor_Surface (*aFaces[aConIndex]).Cone(); const Standard_Real aRad1 = aCone.RefRadius(); const Standard_Real aHeight = aGeomPlanes[0]->Location().Transformed (*aGeomPlanesLoc[0]) .Distance (aGeomPlanes[1]->Location().Transformed (*aGeomPlanesLoc[1])); gp_Trsf aTrsf; aTrsf.SetTransformation (aCone.Position(), gp_Ax3()); const Standard_Real aTriangleHeight = (aCone.SemiAngle() > 0.0) ? aRad1 / Tan (aCone.SemiAngle()) : aRad1 / Tan (Abs (aCone.SemiAngle())) - aHeight; const Standard_Real aRad2 = (aCone.SemiAngle() > 0.0) ? aRad1 * (aTriangleHeight + aHeight) / aTriangleHeight : aRad1 * aTriangleHeight / (aTriangleHeight + aHeight); Handle(Select3D_SensitiveCylinder) aSensSCyl = new Select3D_SensitiveCylinder (theOwner, aRad1, aRad2, aHeight, aTrsf); theSelection->Add (aSensSCyl); break; } } else if (!aGeomCyl.IsNull()) { if (!aGeomPlanes[0].IsNull() && !aGeomPlanes[1].IsNull() && aGeomPlanes[0]->Position().Direction().IsParallel (aGeomCyl->Position().Direction(), Precision::Angular()) && aGeomPlanes[1]->Position().Direction().IsParallel (aGeomCyl->Position().Direction(), Precision::Angular())) { const gp_Cylinder aCyl = BRepAdaptor_Surface (*aFaces[aConIndex]).Cylinder(); const Standard_Real aRad = aCyl.Radius(); const Standard_Real aHeight = aGeomPlanes[0]->Location().Transformed (*aGeomPlanesLoc[0]) .Distance (aGeomPlanes[1]->Location().Transformed (*aGeomPlanesLoc[1])); gp_Trsf aTrsf; gp_Ax3 aPos = aCyl.Position(); if (aGeomPlanes[0]->Position().IsCoplanar (aGeomPlanes[1]->Position(), Precision::Angular(), Precision::Angular())) { // cylinders created as a prism have an inverse vector of the cylindrical surface aPos.SetDirection (aPos.Direction().Reversed()); } aTrsf.SetTransformation (aPos, gp_Ax3()); Handle(Select3D_SensitiveCylinder) aSensSCyl = new Select3D_SensitiveCylinder (theOwner, aRad, aRad, aHeight, aTrsf); theSelection->Add (aSensSCyl); break; } } } for (Standard_Integer aShIndex = 1; aShIndex <= aSubfacesMap.Extent(); ++aShIndex) { ComputeSensitive (aSubfacesMap.FindKey (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(); 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, aTriangulation->Node (anIndices[anIndex])); } } else { for (Standard_Integer anIndex (anIndices.Lower()), aPntId (1); anIndex <= anIndices.Upper(); ++anIndex, ++aPntId) { aResultPoints->SetValue (aPntId, aTriangulation->Node (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: { const gp_Circ aCircle = 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)) { TopLoc_Location aLocSurf; const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface (theFace, aLocSurf); if (Handle(Geom_SphericalSurface) aGeomSphere = Handle(Geom_SphericalSurface)::DownCast (aSurf)) { bool isFullSphere = theFace.NbChildren() == 0; if (theFace.NbChildren() == 1) { const TopoDS_Iterator aWireIter (theFace); const TopoDS_Wire& aWire = TopoDS::Wire (aWireIter.Value()); if (aWire.NbChildren() == 4) { Standard_Integer aNbSeamEdges = 0, aNbDegenEdges = 0; for (TopoDS_Iterator anEdgeIter (aWire); anEdgeIter.More(); anEdgeIter.Next()) { const TopoDS_Edge& anEdge = TopoDS::Edge (anEdgeIter.Value()); aNbSeamEdges += BRep_Tool::IsClosed (anEdge, theFace); aNbDegenEdges += BRep_Tool::Degenerated (anEdge); } isFullSphere = aNbSeamEdges == 2 && aNbDegenEdges == 2; } } if (isFullSphere) { gp_Sphere aSphere = BRepAdaptor_Surface (theFace).Sphere(); Handle(Select3D_SensitiveSphere) aSensSphere = new Select3D_SensitiveSphere (theOwner, aSphere.Position().Axis().Location(), aSphere.Radius()); theSensitiveList.Append (aSensSphere); return Standard_True; } } 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, 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; }