1 // Copyright (C) 2022-2024 CEA, EDF, OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include <GEOMImpl_ShapeProximityDriver.hxx>
21 #include <GEOMImpl_IProximity.hxx>
22 #include <GEOMImpl_Types.hxx>
24 #include <BRep_Tool.hxx>
25 #include <BRepAdaptor_Curve.hxx>
26 #include <BRepAdaptor_Surface.hxx>
27 #include <BRepExtrema_ShapeProximity.hxx>
28 #include <BRepMesh_IncrementalMesh.hxx>
29 #include <Extrema_ExtPC.hxx>
30 #include <Extrema_ExtPS.hxx>
31 #include <Extrema_GenLocateExtCS.hxx>
32 #include <Extrema_GenLocateExtSS.hxx>
33 #include <Extrema_GenLocateExtPS.hxx>
34 #include <Extrema_LocateExtCC.hxx>
35 #include <Extrema_LocateExtPC.hxx>
36 #include <TopExp_Explorer.hxx>
40 static void tessellateShape(const TopoDS_Shape& theShape)
42 Standard_Boolean isTessellate = Standard_False;
44 for (TopExp_Explorer anExp(theShape, TopAbs_FACE); anExp.More() && !isTessellate; anExp.Next())
46 Handle(Poly_Triangulation) aTria = BRep_Tool::Triangulation(TopoDS::Face(anExp.Value()), aLoc);
47 isTessellate = aTria.IsNull();
49 for (TopExp_Explorer anExp(theShape, TopAbs_EDGE); anExp.More() && !isTessellate; anExp.Next())
51 Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(TopoDS::Edge(anExp.Value()), aLoc);
52 isTessellate = aPoly.IsNull();
57 BRepMesh_IncrementalMesh aMesher(theShape, 0.1);
58 Standard_ProgramError_Raise_if(!aMesher.IsDone(), "Meshing failed");
62 static Standard_Real paramOnCurve(const BRepAdaptor_Curve& theCurve, const gp_Pnt& thePoint, const Standard_Real theTol)
64 Extrema_ExtPC aParamSearch(thePoint, theCurve, theCurve.FirstParameter(), theCurve.LastParameter());
65 if (aParamSearch.IsDone())
67 Standard_Integer anIndMin = 0, aNbExt = aParamSearch.NbExt();
68 Standard_Real aSqDistMin = RealLast();
69 for (Standard_Integer i = 1; i <= aNbExt; ++i)
71 if (aParamSearch.SquareDistance(i) < aSqDistMin)
74 aSqDistMin = aParamSearch.SquareDistance(i);
77 if (anIndMin != 0 && aSqDistMin <= theTol * theTol)
79 return aParamSearch.Point(anIndMin).Parameter();
82 return 0.5 * (theCurve.FirstParameter() + theCurve.LastParameter());
85 static void paramsOnSurf(const BRepAdaptor_Surface& theSurf, const gp_Pnt& thePoint, const Standard_Real theTol,
86 Standard_Real& theU, Standard_Real& theV)
88 Extrema_ExtPS aParamSearch(thePoint, theSurf, Precision::PConfusion(), Precision::PConfusion());
89 if (aParamSearch.IsDone())
91 Standard_Integer anIndMin = 0, aNbExt = aParamSearch.NbExt();
92 Standard_Real aSqDistMin = RealLast();
93 for (Standard_Integer i = 1; i <= aNbExt; ++i)
95 if (aParamSearch.SquareDistance(i) < aSqDistMin)
98 aSqDistMin = aParamSearch.SquareDistance(i);
101 if (anIndMin != 0 && aSqDistMin <= theTol * theTol)
103 return aParamSearch.Point(anIndMin).Parameter(theU, theV);
106 theU = 0.5 * (theSurf.FirstUParameter() + theSurf.LastUParameter());
107 theV = 0.5 * (theSurf.FirstVParameter() + theSurf.LastVParameter());
110 static Standard_Real extremaEE(const TopoDS_Edge& theEdge1, const TopoDS_Edge& theEdge2,
111 gp_Pnt& thePoint1, gp_Pnt& thePoint2)
113 BRepAdaptor_Curve aCurve1(theEdge1);
114 BRepAdaptor_Curve aCurve2(theEdge2);
116 TopLoc_Location aLoc;
117 Standard_Real aTol1 = BRep_Tool::Tolerance(theEdge1);
118 Handle(Poly_Polygon3D) aPoly1 = BRep_Tool::Polygon3D (theEdge1, aLoc);
119 if (!aPoly1.IsNull())
120 aTol1 = Max (aTol1, aPoly1->Deflection());
121 Standard_Real aTol2 = BRep_Tool::Tolerance(theEdge2);
122 Handle(Poly_Polygon3D) aPoly2 = BRep_Tool::Polygon3D (theEdge2, aLoc);
123 if (!aPoly2.IsNull())
124 aTol2 = Max (aTol2, aPoly2->Deflection());
126 Standard_Real aU1 = paramOnCurve(aCurve1, thePoint1, 2*aTol1);
127 Standard_Real aU2 = paramOnCurve(aCurve2, thePoint2, 2*aTol2);
129 Standard_Real aValue = -1.0;
130 Extrema_LocateExtCC anExtr(aCurve1, aCurve2, aU1, aU2);
133 aValue = Sqrt(anExtr.SquareDistance());
135 Extrema_POnCurv aP1, aP2;
136 anExtr.Point(aP1, aP2);
137 thePoint1 = aP1.Value();
138 thePoint2 = aP2.Value();
143 static Standard_Real extremaPE(const gp_Pnt& thePoint,
144 const TopoDS_Edge& theEdge,
145 gp_Pnt& thePointOnEdge)
147 BRepAdaptor_Curve aCurve (theEdge);
149 TopLoc_Location aLoc;
150 Standard_Real aTol = BRep_Tool::Tolerance(theEdge);
151 Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D (theEdge, aLoc);
153 aTol = Max (aTol, aPoly->Deflection());
155 Standard_Real aParam = paramOnCurve (aCurve, thePointOnEdge, 2*aTol);
157 Standard_Real aValue = -1.0;
158 Extrema_LocateExtPC anExtr (thePoint, aCurve, aParam, Precision::PConfusion());
161 aValue = Sqrt(anExtr.SquareDistance());
163 Extrema_POnCurv aPointOnCurve = anExtr.Point();
164 thePointOnEdge = aPointOnCurve.Value();
169 static Standard_Real extremaPF(const gp_Pnt& thePoint,
170 const TopoDS_Face& theFace,
171 gp_Pnt& thePointOnFace)
173 BRepAdaptor_Surface aSurf (theFace);
175 TopLoc_Location aLoc;
176 Standard_Real aTol = BRep_Tool::Tolerance(theFace);
177 Handle(Poly_Triangulation) aTria = BRep_Tool::Triangulation (theFace, aLoc);
179 aTol = Max (aTol, aTria->Deflection());
181 Standard_Real aU, aV;
182 paramsOnSurf(aSurf, thePointOnFace, 2*aTol, aU, aV);
184 Standard_Real aValue = -1.0;
185 Extrema_GenLocateExtPS anExtr (aSurf);
186 anExtr.Perform (thePoint, aU, aV);
189 aValue = Sqrt(anExtr.SquareDistance());
191 Extrema_POnSurf aPointOnSurf = anExtr.Point();
192 thePointOnFace = aPointOnSurf.Value();
197 static Standard_Real extremaEF(const TopoDS_Edge& theEdge, const TopoDS_Face& theFace,
198 gp_Pnt& thePonE, gp_Pnt& thePonF)
200 BRepAdaptor_Curve aCurve(theEdge);
201 BRepAdaptor_Surface aSurf(theFace);
203 TopLoc_Location aLoc;
204 Standard_Real aTolEdge = BRep_Tool::Tolerance(theEdge);
205 Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D (theEdge, aLoc);
207 aTolEdge = Max (aTolEdge, aPoly->Deflection());
208 Standard_Real aTolFace = BRep_Tool::Tolerance(theFace);
209 Handle(Poly_Triangulation) aTria = BRep_Tool::Triangulation (theFace, aLoc);
211 aTolFace = Max (aTolFace, aTria->Deflection());
213 Standard_Real aP = paramOnCurve(aCurve, thePonE, 2*aTolEdge);
214 Standard_Real aU, aV;
215 paramsOnSurf(aSurf, thePonF, 2*aTolFace, aU, aV);
217 Standard_Real aValue = -1.0;
218 Extrema_GenLocateExtCS anExtr(aCurve, aSurf, aP, aU, aV, Precision::PConfusion(), Precision::PConfusion());
221 aValue = Sqrt(anExtr.SquareDistance());
222 thePonE = anExtr.PointOnCurve().Value();
223 thePonF = anExtr.PointOnSurface().Value();
228 static Standard_Real extremaFF(const TopoDS_Face& theFace1, const TopoDS_Face& theFace2,
229 gp_Pnt& thePoint1, gp_Pnt& thePoint2)
231 BRepAdaptor_Surface aSurf1(theFace1);
232 BRepAdaptor_Surface aSurf2(theFace2);
234 TopLoc_Location aLoc;
235 Standard_Real aTol1 = BRep_Tool::Tolerance(theFace1);
236 Handle(Poly_Triangulation) aTria1 = BRep_Tool::Triangulation (theFace1, aLoc);
237 if (!aTria1.IsNull())
238 aTol1 = Max (aTol1, aTria1->Deflection());
239 Standard_Real aTol2 = BRep_Tool::Tolerance(theFace2);
240 Handle(Poly_Triangulation) aTria2 = BRep_Tool::Triangulation (theFace2, aLoc);
241 if (!aTria2.IsNull())
242 aTol2 = Max (aTol2, aTria2->Deflection());
244 Standard_Real aU1, aV1;
245 paramsOnSurf(aSurf1, thePoint1, 2*aTol1, aU1, aV1);
246 Standard_Real aU2, aV2;
247 paramsOnSurf(aSurf2, thePoint2, 2*aTol2, aU2, aV2);
249 Standard_Real aValue = -1.0;
250 Extrema_GenLocateExtSS anExtr(aSurf1, aSurf2, aU1, aV1, aU2, aV2, Precision::PConfusion(), Precision::PConfusion());
253 aValue = Sqrt(anExtr.SquareDistance());
254 thePoint1 = anExtr.PointOnS1().Value();
255 thePoint2 = anExtr.PointOnS2().Value();
261 //=======================================================================
264 //=======================================================================
265 const Standard_GUID& GEOMImpl_ShapeProximityDriver::GetID()
267 static Standard_GUID aShapeProximityDriver("1C3449A6-E4EB-407D-B623-89261C4BA785");
268 return aShapeProximityDriver;
271 //=======================================================================
274 //=======================================================================
275 Standard_Integer GEOMImpl_ShapeProximityDriver::Execute(Handle(TFunction_Logbook)& log) const
277 if (Label().IsNull())
280 Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());
281 GEOMImpl_IProximity aProximity (aFunction);
283 Handle(GEOM_Function) aShapeFunc1, aShapeFunc2;
284 aProximity.GetShapes(aShapeFunc1, aShapeFunc2);
285 if (aShapeFunc1.IsNull() || aShapeFunc2.IsNull())
288 TopoDS_Shape aShape1 = aShapeFunc1->GetValue();
289 TopoDS_Shape aShape2 = aShapeFunc2->GetValue();
291 Standard_Real aValue = -1.0;
293 if (aFunction->GetType() == PROXIMITY_COARSE)
295 // tessellate shapes if there is no mesh exists
296 tessellateShape(aShape1);
297 tessellateShape(aShape2);
299 // compute proximity basing on the tessellation
300 BRepExtrema_ShapeProximity aCalcProx;
301 aCalcProx.LoadShape1(aShape1);
302 aCalcProx.LoadShape2(aShape2);
303 aCalcProx.SetNbSamples1(aProximity.GetNbSamples(PROXIMITY_ARG_SAMPLES1));
304 aCalcProx.SetNbSamples2(aProximity.GetNbSamples(PROXIMITY_ARG_SAMPLES2));
307 if (aCalcProx.IsDone())
309 aValue = aCalcProx.Proximity();
310 aProximity.SetProximityPoints(aCalcProx.ProximityPoint1(),
311 aCalcProx.ProximityPoint2());
312 aProximity.SetStatusOfPoints((Standard_Integer)aCalcProx.ProxPntStatus1(),
313 (Standard_Integer)aCalcProx.ProxPntStatus2());
316 Standard_ConstructionError::Raise("Failed to compute coarse proximity");
318 else if (aFunction->GetType() == PROXIMITY_PRECISE)
320 // coarse proximity value
321 // in some cases this value cannot be precised
322 // it can be precised only if at least one point is in the middle of the shape
323 aValue = aProximity.GetValue();
325 TopAbs_ShapeEnum aType1 = aShape1.ShapeType();
326 TopAbs_ShapeEnum aType2 = aShape2.ShapeType();
329 BRepExtrema_ProximityDistTool::ProxPnt_Status aStatus1, aStatus2;
330 Standard_Integer intStatus1, intStatus2;
331 aProximity.GetProximityPoints(aPnt1, aPnt2);
332 aProximity.GetStatusOfPoints(intStatus1, intStatus2);
333 aStatus1 = (BRepExtrema_ProximityDistTool::ProxPnt_Status)intStatus1;
334 aStatus2 = (BRepExtrema_ProximityDistTool::ProxPnt_Status)intStatus2;
336 if (aType1 == TopAbs_EDGE)
338 if (aType2 == TopAbs_EDGE)
340 if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
341 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
343 aValue = extremaEE(TopoDS::Edge(aShape1), TopoDS::Edge(aShape2), aPnt1, aPnt2);
345 else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER &&
346 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
348 aValue = extremaPE(aPnt1, TopoDS::Edge(aShape2), aPnt2);
350 else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
351 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER)
353 aValue = extremaPE(aPnt2, TopoDS::Edge(aShape1), aPnt1);
356 else if (aType2 == TopAbs_FACE)
358 if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
359 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
361 aValue = extremaEF(TopoDS::Edge(aShape1), TopoDS::Face(aShape2), aPnt1, aPnt2);
363 else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER &&
364 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
366 aValue = extremaPF(aPnt1, TopoDS::Face(aShape2), aPnt2);
368 else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
369 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER)
371 aValue = extremaPE(aPnt2, TopoDS::Edge(aShape1), aPnt1);
375 else if (aType1 == TopAbs_FACE)
377 if (aType2 == TopAbs_EDGE)
379 if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
380 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
382 aValue = extremaEF(TopoDS::Edge(aShape2), TopoDS::Face(aShape1), aPnt2, aPnt1);
384 else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER &&
385 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
387 aValue = extremaPE(aPnt1, TopoDS::Edge(aShape2), aPnt2);
389 else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
390 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER)
392 aValue = extremaPF(aPnt2, TopoDS::Face(aShape1), aPnt1);
395 else if (aType2 == TopAbs_FACE)
397 if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
398 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
400 aValue = extremaFF(TopoDS::Face(aShape1), TopoDS::Face(aShape2), aPnt1, aPnt2);
402 else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER &&
403 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
405 aValue = extremaPF(aPnt1, TopoDS::Face(aShape2), aPnt2);
407 else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
408 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER)
410 aValue = extremaPF(aPnt2, TopoDS::Face(aShape1), aPnt1);
416 aProximity.SetProximityPoints(aPnt1, aPnt2);
418 Standard_ConstructionError::Raise("Failed to compute precise proximity");
422 Standard_ConstructionError::Raise("incorrect algorithm");
425 aProximity.SetValue(aValue);
426 log->SetTouched(Label());
430 //=======================================================================
431 //function : GetCreationInformation
432 //purpose : Returns a name of creation operation and names and values of creation parameters
433 //=======================================================================
434 bool GEOMImpl_ShapeProximityDriver::GetCreationInformation(
435 std::string& theOperationName,
436 std::vector<GEOM_Param>& theParams)
438 if (Label().IsNull())
441 Handle(GEOM_Function) aFunc = GEOM_Function::GetFunction(Label());
442 GEOMImpl_IProximity aProxFunc(aFunc);
443 Handle(GEOM_Function) aShape1, aShape2;
444 aProxFunc.GetShapes(aShape1, aShape2);
446 if (aFunc->GetType() == PROXIMITY_COARSE)
447 theOperationName = "PROXIMITY_COARSE";
448 else if (aFunc->GetType() == PROXIMITY_PRECISE)
449 theOperationName = "PROXIMITY_PRECISE";
451 AddParam(theParams, "Shape1", aShape1);
452 AddParam(theParams, "Shape2", aShape2);
457 IMPLEMENT_STANDARD_RTTIEXT(GEOMImpl_ShapeProximityDriver, GEOM_BaseDriver)