Salome HOME
57158be4bdab7313e233756ba1cf53bd185be3f3
[modules/geom.git] / src / GEOMImpl / GEOMImpl_ShapeProximityDriver.cxx
1 // Copyright (C) 2022-2023  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include <GEOMImpl_ShapeProximityDriver.hxx>
21 #include <GEOMImpl_IProximity.hxx>
22 #include <GEOMImpl_Types.hxx>
23
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>
37 #include <TopoDS.hxx>
38
39 namespace {
40   static void tessellateShape(const TopoDS_Shape& theShape)
41   {
42     Standard_Boolean isTessellate = Standard_False;
43     TopLoc_Location aLoc;
44     for (TopExp_Explorer anExp(theShape, TopAbs_FACE); anExp.More() && !isTessellate; anExp.Next())
45     {
46       Handle(Poly_Triangulation) aTria = BRep_Tool::Triangulation(TopoDS::Face(anExp.Value()), aLoc);
47       isTessellate = aTria.IsNull();
48     }
49     for (TopExp_Explorer anExp(theShape, TopAbs_EDGE); anExp.More() && !isTessellate; anExp.Next())
50     {
51       Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(TopoDS::Edge(anExp.Value()), aLoc);
52       isTessellate = aPoly.IsNull();
53     }
54
55     if (isTessellate)
56     {
57       BRepMesh_IncrementalMesh aMesher(theShape, 0.1);
58       Standard_ProgramError_Raise_if(!aMesher.IsDone(), "Meshing failed");
59     }
60   }
61
62   static Standard_Real paramOnCurve(const BRepAdaptor_Curve& theCurve, const gp_Pnt& thePoint, const Standard_Real theTol)
63   {
64     Extrema_ExtPC aParamSearch(thePoint, theCurve, theCurve.FirstParameter(), theCurve.LastParameter());
65     if (aParamSearch.IsDone())
66     {
67       Standard_Integer anIndMin = 0, aNbExt = aParamSearch.NbExt();
68       Standard_Real aSqDistMin = RealLast();
69       for (Standard_Integer i = 1; i <= aNbExt; ++i)
70       {
71         if (aParamSearch.SquareDistance(i) < aSqDistMin)
72         {
73           anIndMin = i;
74           aSqDistMin = aParamSearch.SquareDistance(i);
75         }
76       }
77       if (anIndMin != 0 && aSqDistMin <= theTol * theTol)
78       {
79         return aParamSearch.Point(anIndMin).Parameter();
80       }
81     }
82     return 0.5 * (theCurve.FirstParameter() + theCurve.LastParameter());
83   }
84
85   static void paramsOnSurf(const BRepAdaptor_Surface& theSurf, const gp_Pnt& thePoint, const Standard_Real theTol,
86                            Standard_Real& theU, Standard_Real& theV)
87   {
88     Extrema_ExtPS aParamSearch(thePoint, theSurf, Precision::PConfusion(), Precision::PConfusion());
89     if (aParamSearch.IsDone())
90     {
91       Standard_Integer anIndMin = 0, aNbExt = aParamSearch.NbExt();
92       Standard_Real aSqDistMin = RealLast();
93       for (Standard_Integer i = 1; i <= aNbExt; ++i)
94       {
95         if (aParamSearch.SquareDistance(i) < aSqDistMin)
96         {
97           anIndMin = i;
98           aSqDistMin = aParamSearch.SquareDistance(i);
99         }
100       }
101       if (anIndMin != 0 && aSqDistMin <= theTol * theTol)
102       {
103         return aParamSearch.Point(anIndMin).Parameter(theU, theV);
104       }
105     }
106     theU = 0.5 * (theSurf.FirstUParameter() + theSurf.LastUParameter());
107     theV = 0.5 * (theSurf.FirstVParameter() + theSurf.LastVParameter());
108   }
109
110   static Standard_Real extremaEE(const TopoDS_Edge& theEdge1, const TopoDS_Edge& theEdge2,
111                                  gp_Pnt& thePoint1, gp_Pnt& thePoint2)
112   {
113     BRepAdaptor_Curve aCurve1(theEdge1);
114     BRepAdaptor_Curve aCurve2(theEdge2);
115
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());
125   
126     Standard_Real aU1 = paramOnCurve(aCurve1, thePoint1, 2*aTol1);
127     Standard_Real aU2 = paramOnCurve(aCurve2, thePoint2, 2*aTol2);
128
129     Standard_Real aValue = -1.0;
130     Extrema_LocateExtCC anExtr(aCurve1, aCurve2, aU1, aU2);
131     if (anExtr.IsDone())
132     {
133       aValue = Sqrt(anExtr.SquareDistance());
134
135       Extrema_POnCurv aP1, aP2;
136       anExtr.Point(aP1, aP2);
137       thePoint1 = aP1.Value();
138       thePoint2 = aP2.Value();
139     }
140     return aValue;
141   }
142
143   static Standard_Real extremaPE(const gp_Pnt&      thePoint,
144                                  const TopoDS_Edge& theEdge,
145                                  gp_Pnt&            thePointOnEdge)
146   {
147     BRepAdaptor_Curve aCurve (theEdge);
148     
149     TopLoc_Location aLoc;
150     Standard_Real aTol = BRep_Tool::Tolerance(theEdge);
151     Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D (theEdge, aLoc);
152     if (!aPoly.IsNull())
153       aTol = Max (aTol, aPoly->Deflection());
154     
155     Standard_Real aParam = paramOnCurve (aCurve, thePointOnEdge, 2*aTol);
156     
157     Standard_Real aValue = -1.0;
158     Extrema_LocateExtPC anExtr (thePoint, aCurve, aParam, Precision::PConfusion());
159     if (anExtr.IsDone())
160     {
161       aValue = Sqrt(anExtr.SquareDistance());
162       
163       Extrema_POnCurv aPointOnCurve = anExtr.Point();
164       thePointOnEdge = aPointOnCurve.Value();
165     }
166     return aValue;
167   }
168   
169   static Standard_Real extremaPF(const gp_Pnt&      thePoint,
170                                  const TopoDS_Face& theFace,
171                                  gp_Pnt&            thePointOnFace)
172   {
173     BRepAdaptor_Surface aSurf (theFace);
174     
175     TopLoc_Location aLoc;
176     Standard_Real aTol = BRep_Tool::Tolerance(theFace);
177     Handle(Poly_Triangulation) aTria = BRep_Tool::Triangulation (theFace, aLoc);
178     if (!aTria.IsNull())
179       aTol = Max (aTol, aTria->Deflection());
180     
181     Standard_Real aU, aV;
182     paramsOnSurf(aSurf, thePointOnFace, 2*aTol, aU, aV);
183     
184     Standard_Real aValue = -1.0;
185     Extrema_GenLocateExtPS anExtr (aSurf);
186     anExtr.Perform (thePoint, aU, aV);
187     if (anExtr.IsDone())
188     {
189       aValue = Sqrt(anExtr.SquareDistance());
190       
191       Extrema_POnSurf aPointOnSurf = anExtr.Point();
192       thePointOnFace = aPointOnSurf.Value();
193     }
194     return aValue;
195   }
196
197   static Standard_Real extremaEF(const TopoDS_Edge& theEdge, const TopoDS_Face& theFace,
198                                  gp_Pnt& thePonE, gp_Pnt& thePonF)
199   {
200     BRepAdaptor_Curve aCurve(theEdge);
201     BRepAdaptor_Surface aSurf(theFace);
202
203     TopLoc_Location aLoc;
204     Standard_Real aTolEdge = BRep_Tool::Tolerance(theEdge);
205     Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D (theEdge, aLoc);
206     if (!aPoly.IsNull())
207       aTolEdge = Max (aTolEdge, aPoly->Deflection());
208     Standard_Real aTolFace = BRep_Tool::Tolerance(theFace);
209     Handle(Poly_Triangulation) aTria = BRep_Tool::Triangulation (theFace, aLoc);
210     if (!aTria.IsNull())
211       aTolFace = Max (aTolFace, aTria->Deflection());
212   
213     Standard_Real aP = paramOnCurve(aCurve, thePonE, 2*aTolEdge);
214     Standard_Real aU, aV;
215     paramsOnSurf(aSurf, thePonF, 2*aTolFace, aU, aV);
216
217     Standard_Real aValue = -1.0;
218     Extrema_GenLocateExtCS anExtr(aCurve, aSurf, aP, aU, aV, Precision::PConfusion(), Precision::PConfusion());
219     if (anExtr.IsDone())
220     {
221       aValue = Sqrt(anExtr.SquareDistance());
222       thePonE = anExtr.PointOnCurve().Value();
223       thePonF = anExtr.PointOnSurface().Value();
224     }
225     return aValue;
226   }
227
228   static Standard_Real extremaFF(const TopoDS_Face& theFace1, const TopoDS_Face& theFace2,
229                                  gp_Pnt& thePoint1, gp_Pnt& thePoint2)
230   {
231     BRepAdaptor_Surface aSurf1(theFace1);
232     BRepAdaptor_Surface aSurf2(theFace2);
233
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());
243   
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);
248
249     Standard_Real aValue = -1.0;
250     Extrema_GenLocateExtSS anExtr(aSurf1, aSurf2, aU1, aV1, aU2, aV2, Precision::PConfusion(), Precision::PConfusion());
251     if (anExtr.IsDone())
252     {
253       aValue = Sqrt(anExtr.SquareDistance());
254       thePoint1 = anExtr.PointOnS1().Value();
255       thePoint2 = anExtr.PointOnS2().Value();
256     }
257     return aValue;
258   }
259 }
260
261 //=======================================================================
262 //function : GetID
263 //purpose  :
264 //=======================================================================
265 const Standard_GUID& GEOMImpl_ShapeProximityDriver::GetID()
266 {
267   static Standard_GUID aShapeProximityDriver("1C3449A6-E4EB-407D-B623-89261C4BA785");
268   return aShapeProximityDriver;
269 }
270
271 //=======================================================================
272 //function : Execute
273 //purpose  :
274 //=======================================================================
275 Standard_Integer GEOMImpl_ShapeProximityDriver::Execute(Handle(TFunction_Logbook)& log) const
276 {
277   if (Label().IsNull())
278     return 0;
279
280   Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());
281   GEOMImpl_IProximity aProximity (aFunction);
282
283   Handle(GEOM_Function) aShapeFunc1, aShapeFunc2;
284   aProximity.GetShapes(aShapeFunc1, aShapeFunc2);
285   if (aShapeFunc1.IsNull() || aShapeFunc2.IsNull())
286     return 0;
287
288   TopoDS_Shape aShape1 = aShapeFunc1->GetValue();
289   TopoDS_Shape aShape2 = aShapeFunc2->GetValue();
290
291   Standard_Real aValue = -1.0;
292
293   if (aFunction->GetType() == PROXIMITY_COARSE)
294   {
295     // tessellate shapes if there is no mesh exists
296     tessellateShape(aShape1);
297     tessellateShape(aShape2);
298
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));
305     aCalcProx.Perform();
306
307     if (aCalcProx.IsDone())
308     {
309       aValue = aCalcProx.Proximity();
310       aProximity.SetProximityPoints(aCalcProx.ProximityPoint1(),
311                                     aCalcProx.ProximityPoint2());
312       aProximity.SetStatusOfPoints((Standard_Integer)aCalcProx.ProxPntStatus1(),
313                                    (Standard_Integer)aCalcProx.ProxPntStatus2());
314     }
315     else
316       Standard_ConstructionError::Raise("Failed to compute coarse proximity");
317   }
318   else if (aFunction->GetType() == PROXIMITY_PRECISE)
319   {
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();
324
325     TopAbs_ShapeEnum aType1 = aShape1.ShapeType();
326     TopAbs_ShapeEnum aType2 = aShape2.ShapeType();
327
328     gp_Pnt aPnt1, aPnt2;
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;
335
336     if (aType1 == TopAbs_EDGE)
337     {
338       if (aType2 == TopAbs_EDGE)
339       {
340         if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
341             aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
342         {
343           aValue = extremaEE(TopoDS::Edge(aShape1), TopoDS::Edge(aShape2), aPnt1, aPnt2);
344         }
345         else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER &&
346                  aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
347         {
348           aValue = extremaPE(aPnt1, TopoDS::Edge(aShape2), aPnt2);
349         }
350         else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
351                  aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER)
352         {
353           aValue = extremaPE(aPnt2, TopoDS::Edge(aShape1), aPnt1);
354         }
355       }
356       else if (aType2 == TopAbs_FACE)
357       {
358         if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
359             aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
360         {
361           aValue = extremaEF(TopoDS::Edge(aShape1), TopoDS::Face(aShape2), aPnt1, aPnt2);
362         }
363         else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER &&
364                  aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
365         {
366           aValue = extremaPF(aPnt1, TopoDS::Face(aShape2), aPnt2);
367         }
368         else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
369                  aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER)
370         {
371           aValue = extremaPE(aPnt2, TopoDS::Edge(aShape1), aPnt1);
372         }
373       }
374     }
375     else if (aType1 == TopAbs_FACE)
376     {
377       if (aType2 == TopAbs_EDGE)
378       {
379         if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
380             aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
381         {
382           aValue = extremaEF(TopoDS::Edge(aShape2), TopoDS::Face(aShape1), aPnt2, aPnt1);
383         }
384         else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER &&
385                  aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
386         {
387           aValue = extremaPE(aPnt1, TopoDS::Edge(aShape2), aPnt2);
388         }
389         else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
390                  aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER)
391         {
392           aValue = extremaPF(aPnt2, TopoDS::Face(aShape1), aPnt1);
393         }
394       }
395       else if (aType2 == TopAbs_FACE)
396       {
397         if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
398             aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
399         {
400           aValue = extremaFF(TopoDS::Face(aShape1), TopoDS::Face(aShape2), aPnt1, aPnt2);
401         }
402         else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER &&
403                  aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
404         {
405           aValue = extremaPF(aPnt1, TopoDS::Face(aShape2), aPnt2);
406         }
407         else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
408                  aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER)
409         {
410           aValue = extremaPF(aPnt2, TopoDS::Face(aShape1), aPnt1);
411         }
412       }
413     }
414
415     if (aValue >= 0)
416       aProximity.SetProximityPoints(aPnt1, aPnt2);
417     else
418       Standard_ConstructionError::Raise("Failed to compute precise proximity");
419   }
420   else
421   {
422     Standard_ConstructionError::Raise("incorrect algorithm");
423   }
424
425   aProximity.SetValue(aValue);
426   log->SetTouched(Label());
427   return 1;
428 }
429
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)
437 {
438   if (Label().IsNull())
439     return false;
440
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);
445
446   if (aFunc->GetType() == PROXIMITY_COARSE)
447     theOperationName = "PROXIMITY_COARSE";
448   else if (aFunc->GetType() == PROXIMITY_PRECISE)
449     theOperationName = "PROXIMITY_PRECISE";
450
451   AddParam(theParams, "Shape1", aShape1);
452   AddParam(theParams, "Shape2", aShape2);
453
454   return false;
455 }
456
457 IMPLEMENT_STANDARD_RTTIEXT(GEOMImpl_ShapeProximityDriver, GEOM_BaseDriver)