0028427: Data Exchange - Update Reference Manual for STEP format
[occt.git] / src / StepToTopoDS / StepToTopoDS_GeometricTool.cxx
1 // Created on: 1995-01-06
2 // Created by: Frederic MAUPAS
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 //pdn 11.01.99 #144 bm1_pe_t4 protection of exceptions in draw
18 //    abv 13.04.99 S4136: eliminate BRepAPI::Precision()
19
20 #include <BRep_Builder.hxx>
21 #include <BRep_Tool.hxx>
22 #include <BRepTools.hxx>
23 #include <BRepTools_WireExplorer.hxx>
24 #include <ElCLib.hxx>
25 #include <ElSLib.hxx>
26 #include <Geom2d_Curve.hxx>
27 #include <Geom2d_Line.hxx>
28 #include <Geom2d_TrimmedCurve.hxx>
29 #include <Geom2dAPI_InterCurveCurve.hxx>
30 #include <Geom2dAPI_ProjectPointOnCurve.hxx>
31 #include <Geom_BoundedCurve.hxx>
32 #include <Geom_BSplineCurve.hxx>
33 #include <Geom_BSplineSurface.hxx>
34 #include <Geom_ConicalSurface.hxx>
35 #include <Geom_Curve.hxx>
36 #include <Geom_CylindricalSurface.hxx>
37 #include <Geom_Line.hxx>
38 #include <Geom_Plane.hxx>
39 #include <Geom_SphericalSurface.hxx>
40 #include <Geom_ToroidalSurface.hxx>
41 #include <GeomAbs_CurveType.hxx>
42 #include <GeomAbs_Shape.hxx>
43 #include <GeomAdaptor_Curve.hxx>
44 #include <GeomAPI_ProjectPointOnCurve.hxx>
45 #include <GeomAPI_ProjectPointOnSurf.hxx>
46 #include <gp_Vec2d.hxx>
47 #include <Precision.hxx>
48 #include <Standard_ErrorHandler.hxx>
49 #include <Standard_Failure.hxx>
50 #include <StepGeom_CartesianPoint.hxx>
51 #include <StepGeom_Direction.hxx>
52 #include <StepGeom_Line.hxx>
53 #include <StepGeom_Pcurve.hxx>
54 #include <StepGeom_PcurveOrSurface.hxx>
55 #include <StepGeom_SeamCurve.hxx>
56 #include <StepGeom_Surface.hxx>
57 #include <StepGeom_SurfaceCurve.hxx>
58 #include <StepGeom_Vector.hxx>
59 #include <StepRepr_DefinitionalRepresentation.hxx>
60 #include <StepShape_Edge.hxx>
61 #include <StepShape_EdgeLoop.hxx>
62 #include <StepShape_OrientedEdge.hxx>
63 #include <StepToTopoDS.hxx>
64 #include <StepToTopoDS_GeometricTool.hxx>
65 #include <TopExp.hxx>
66 #include <TopExp_Explorer.hxx>
67 #include <TopoDS.hxx>
68 #include <Transfer_TransientProcess.hxx>
69
70 // ----------------------------------------------------------------------------
71 // Method  : HasPCurve
72 // Purpose : returns true if the surface curve has at least one pcurve lying
73 //on the surface
74 // ----------------------------------------------------------------------------
75 Standard_Integer StepToTopoDS_GeometricTool::PCurve
76   (const Handle(StepGeom_SurfaceCurve)& SurfCurve,
77    const Handle(StepGeom_Surface)&      BasisSurf,
78    Handle(StepGeom_Pcurve)& thePCurve,  const Standard_Integer last)
79 {
80   Standard_Integer NbAssGeom = SurfCurve->NbAssociatedGeometry();
81   thePCurve.Nullify();
82   for (Standard_Integer i= last+1; i<=NbAssGeom; i++) {
83     thePCurve = SurfCurve->AssociatedGeometryValue(i).Pcurve();
84     if (!thePCurve.IsNull()) {
85       if (thePCurve->BasisSurface() == BasisSurf) return i;
86     }
87   }
88   thePCurve.Nullify();
89   return 0;
90 }
91
92 // ----------------------------------------------------------------------------
93 // Method  : IsSeamCurve
94 // Purpose : Two edges of the same wire references the same oriented edge
95 //           Then the surface_curve is a seam curve
96 // ----------------------------------------------------------------------------
97
98 Standard_Boolean  StepToTopoDS_GeometricTool::IsSeamCurve
99 (const Handle(StepGeom_SurfaceCurve)& SurfCurve,
100  const Handle(StepGeom_Surface)&      Surf,
101  const Handle(StepShape_Edge)&         StepEdge,
102  const Handle(StepShape_EdgeLoop)&     EdgeLoop)
103 {
104   if (SurfCurve->IsKind(STANDARD_TYPE(StepGeom_SeamCurve)))
105     return Standard_True;
106   
107   if (SurfCurve->NbAssociatedGeometry() != 2) return Standard_False;
108
109   Handle(StepGeom_Pcurve) StepPCurve1 =
110     SurfCurve->AssociatedGeometryValue(1).Pcurve();
111   Handle(StepGeom_Pcurve) StepPCurve2 = 
112     SurfCurve->AssociatedGeometryValue(2).Pcurve();
113
114   // Do the two pcurves lye on the same surface ?
115
116   if ((!StepPCurve1.IsNull() && !StepPCurve2.IsNull()) && 
117       (StepPCurve1->BasisSurface() == Surf) &&
118       (StepPCurve2->BasisSurface()== Surf)) {
119
120     Standard_Integer NbEdge = EdgeLoop->NbEdgeList();
121     Standard_Integer nbOE = 0;
122
123     Handle(StepShape_OrientedEdge) OrEdge;
124
125     for (Standard_Integer i = 1; i <= NbEdge; i ++ ) {
126       OrEdge = EdgeLoop->EdgeListValue(i);
127       if (StepEdge == OrEdge->EdgeElement()) nbOE ++;
128     }
129     // two oriented edges of the same wire share the same edge
130     if (nbOE == 2) return Standard_True;
131   }
132   return Standard_False;
133 }
134
135 // ----------------------------------------------------------------------------
136 // Method  : IsLikeSeam
137 // Purpose : The two pcurves lies on the same surface but on different wires.
138 //           This is typical situation in CATIA BRep : a cylinder is coded
139 //           with two faces on the same 'Closed' BSplineSurf, which in the
140 //           range of gp_Resolution is not identified as closed
141 // ----------------------------------------------------------------------------
142
143 Standard_Boolean  StepToTopoDS_GeometricTool::IsLikeSeam
144 (const Handle(StepGeom_SurfaceCurve)& SurfCurve,
145  const Handle(StepGeom_Surface)&      Surf,
146  const Handle(StepShape_Edge)&         StepEdge,
147  const Handle(StepShape_EdgeLoop)&     EdgeLoop)
148 {
149   if (SurfCurve->NbAssociatedGeometry() != 2) return Standard_False;
150
151   Handle(StepGeom_Pcurve) StepPCurve1 = 
152     SurfCurve->AssociatedGeometryValue(1).Pcurve();
153   Handle(StepGeom_Pcurve) StepPCurve2 = 
154     SurfCurve->AssociatedGeometryValue(2).Pcurve();
155   
156   // Do the two pcurves lye on the same surface ?
157   
158   if ((!StepPCurve1.IsNull() && !StepPCurve2.IsNull()) && 
159       (StepPCurve1->BasisSurface() == Surf) &&
160       (StepPCurve2->BasisSurface() == Surf)) {
161     
162     Standard_Integer NbEdge = EdgeLoop->NbEdgeList();
163     Standard_Integer nbOE = 0;
164
165     Handle(StepShape_OrientedEdge) OrEdge;
166
167     for (Standard_Integer i = 1; i <= NbEdge; i ++ ) {
168       OrEdge = EdgeLoop->EdgeListValue(i);
169       if (StepEdge == OrEdge->EdgeElement()) nbOE ++;
170     }
171     // the two oriented edges are not in the same wire
172     if (nbOE == 1) {
173       // check is the two pcurve are not indentical ?
174       Handle(StepGeom_Line) line1 = Handle(StepGeom_Line)::DownCast
175         (StepPCurve1->ReferenceToCurve()->ItemsValue(1));
176       Handle(StepGeom_Line) line2 = Handle(StepGeom_Line)::DownCast
177         (StepPCurve2->ReferenceToCurve()->ItemsValue(1));
178       if (!line1.IsNull() && !line2.IsNull()) {
179         // Same Origin in X OR Y && Same Vector ??
180         // WITHIN A given tolerance !!!
181         Standard_Real DeltaX = Abs(line1->Pnt()->CoordinatesValue(1) -
182           line2->Pnt()->CoordinatesValue(1));
183         Standard_Real DeltaY = Abs(line1->Pnt()->CoordinatesValue(2) -
184           line2->Pnt()->CoordinatesValue(2));
185
186         Standard_Real DeltaDirX =
187           Abs(line1->Dir()->Orientation()->DirectionRatiosValue(1) -
188           line2->Dir()->Orientation()->DirectionRatiosValue(1));
189         Standard_Real DeltaDirY =
190           Abs(line1->Dir()->Orientation()->DirectionRatiosValue(2) -
191           line2->Dir()->Orientation()->DirectionRatiosValue(2));
192
193         Standard_Real preci2d = Precision::PConfusion(); //:S4136: Parametric(BRepAPI::Precision(),10);
194
195         if ((DeltaX < preci2d) || (DeltaY < preci2d))
196           return ((DeltaDirX < preci2d) && (DeltaDirY < preci2d));
197         else return Standard_False;
198
199         // Warning : la manipulation de tolerances dans ce contexte est un
200         //           peu trop dangeureux.
201         //           il serait preferable de plus de ne pas restreindre au
202         //           cas de deux lignes.
203         //           un mode plus convenable de detection serait de se servir
204         //           des isos (ou bords naturels) de la surface de base
205         //           et de detecter que les deux courbes se trouvent sur le
206         //           bord de fermeture.
207         //           il faut toutefois prevoir le cas ou les deux courbes
208         //           sont confondues (ex : CATIA, "couture" de separation
209         //           en deux faces d un support periodique.
210         //  Ce travail reste evidement A FAIRE !!! ...
211       }
212       else return Standard_False;
213     }
214     return Standard_False;
215   }
216   return Standard_False;
217 }
218
219 // ----------------------------------------------------------------------------
220 // Method  : UpdateParam3d
221 // Purpose : According to the type of curve update parameter (w1>w2)
222 //           This situation occurs when an edge crosses the parametric origin.
223 // ----------------------------------------------------------------------------
224
225 Standard_Boolean  StepToTopoDS_GeometricTool::UpdateParam3d
226 (const Handle(Geom_Curve)& theCurve, Standard_Real& w1, Standard_Real& w2,
227  const Standard_Real preci)
228 {
229   // w1 et/ou w2 peuvent etre en dehors des bornes naturelles de la courbe.
230   // On donnera alors la valeur en bout a w1 et/ou w2
231   
232   Standard_Real cf = theCurve->FirstParameter();
233   Standard_Real cl = theCurve->LastParameter();
234
235   if (theCurve->IsKind(STANDARD_TYPE(Geom_BoundedCurve)) && !theCurve->IsClosed()) {
236     if (w1 < cf) {
237 #ifdef OCCT_DEBUG
238       cout << "Update Edge First Parameter to Curve First Parameter" << endl;
239 #endif
240       w1 = cf;
241     }
242     else if (w1 > cl) {
243 #ifdef OCCT_DEBUG
244       cout << "Update Edge First Parameter to Curve Last Parameter" << endl;
245 #endif
246       w1 = cl;
247     }
248     if (w2 < cf) {
249 #ifdef OCCT_DEBUG
250       cout << "Update Edge Last Parameter to Curve First Parameter" << endl;
251 #endif
252       w2 = cf;
253     }
254     else if (w2 > cl) {
255 #ifdef OCCT_DEBUG
256       cout << "Update Edge Last Parameter to Curve Last Parameter" << endl;
257 #endif
258       w2 = cl;
259     }
260   }
261
262   if (w1 < w2) return Standard_True;
263
264   if (theCurve->IsPeriodic()) 
265     ElCLib::AdjustPeriodic(cf,cl,Precision::PConfusion(),w1,w2); //:a7 abv 11 Feb 98: preci -> PConfusion()
266   else if (theCurve->IsClosed()) {
267     // l'un des points projecte se trouve sur l'origine du parametrage
268     // de la courbe 3D. L algo a donne cl +- preci au lieu de cf ou vice-versa
269     // DANGER precision 3d applique a une espace 1d
270
271     // w2 = cf au lieu de w2 = cl
272     if (Abs(w2 - cf) < Precision::PConfusion() /*preci*/)  w2 = cl;
273     // w1 = cl au lieu de w1 = cf
274     else if (Abs(w1 - cl) < Precision::PConfusion() /*preci*/)  w1 = cf;
275
276     // on se trouve dans un cas ou l origine est traversee
277     // illegal sur une courbe fermee non periodique
278     // on inverse quand meme les parametres !!!!!!
279     else {
280       //:S4136 abv 20 Apr 99: r0701_ug.stp #6230: add check in 3d
281       if (theCurve->Value(w1).Distance(theCurve->Value(cf)) < preci) w1 = cf;
282       if (theCurve->Value(w2).Distance(theCurve->Value(cl)) < preci) w2 = cl;
283       if (w1 > w2) {
284 #ifdef OCCT_DEBUG
285         cout << "Warning : parameter range of edge crossing non periodic curve origin" << endl;
286 #endif
287         Standard_Real tmp = w1;
288         w1 = w2;
289         w2 = tmp;
290       }
291     }
292   }
293   // The curve is closed within the 3D tolerance
294   else if (theCurve->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
295     Handle(Geom_BSplineCurve) aBSpline = 
296       Handle(Geom_BSplineCurve)::DownCast(theCurve);
297     if (aBSpline->StartPoint().Distance(aBSpline->EndPoint()) <= preci ) {
298 //:S4136        <= BRepAPI::Precision()) {
299       // l'un des points projecte se trouve sur l'origine du parametrage
300       // de la courbe 3D. L algo a donne cl +- preci au lieu de cf ou vice-versa
301       // DANGER precision 3d applique a une espace 1d
302       
303       // w2 = cf au lieu de w2 = cl
304       if      (Abs(w2 - cf) < Precision::PConfusion()) w2 = cl ;
305       // w1 = cl au lieu de w1 = cf
306       else if (Abs(w1 - cl) < Precision::PConfusion()) w1 =  cf;
307
308       // on se trouve dans un cas ou l origine est traversee
309       // illegal sur une courbe fermee non periodique
310       // on inverse quand meme les parametres !!!!!!
311       else {
312 #ifdef OCCT_DEBUG
313         cout << "Warning : parameter range of edge crossing non periodic curve origin" << endl;
314 #endif
315         Standard_Real tmp = w1;
316         w1 = w2;
317         w2 = tmp;
318       }
319     }
320     //abv 15.03.00 #72 bm1_pe_t4 protection of exceptions in draw
321     else if ( w1 > w2 ) {
322 #ifdef OCCT_DEBUG
323       cout << "Warning: parameter range is bad; curve reversed" << endl;
324 #endif
325       w1 = theCurve->ReversedParameter ( w1 );
326       w2 = theCurve->ReversedParameter ( w2 );
327       theCurve->Reverse();
328     }
329 //:j9 abv 11 Dec 98: PRO7747 #4875, after :j8:    else 
330     if (w1 == w2) {  //gka 10.07.1998 file PRO7656 entity 33334
331       w1 = cf; w2 = cl;
332       return Standard_False;
333     }
334   }
335   else {
336 #ifdef OCCT_DEBUG
337     cout << "UpdateParam3d Failed" << endl;
338     cout << "  - Curve Type : " << theCurve->DynamicType() << endl;
339     cout << "  - Param 1    : " << w1 << endl;
340     cout << "  - Param 2    : " << w2 << endl;
341 #endif
342     //abv 15.03.00 #72 bm1_pe_t4 protection of exceptions in draw
343     if ( w1 > w2 ) {
344 #ifdef OCCT_DEBUG
345       cout << "Warning: parameter range is bad; curve reversed" << endl;
346 #endif
347       w1 = theCurve->ReversedParameter ( w1 );
348       w2 = theCurve->ReversedParameter ( w2 );
349       theCurve->Reverse();
350     }
351     //pdn 11.01.99 #144 bm1_pe_t4 protection of exceptions in draw
352     if (w1 == w2) {
353       w1 -= Precision::PConfusion();
354       w2 += Precision::PConfusion();
355     }
356     return Standard_False;
357   }
358   return Standard_True;
359 }