0024002: Overall code and build procedure refactoring -- automatic
[occt.git] / src / BRepAlgo / BRepAlgo.cxx
1 // Created on: 1997-03-10
2 // Created by: Stagiaire Francois DUMONT
3 // Copyright (c) 1997-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
18 #include <BRep_Tool.hxx>
19 #include <BRepAdaptor_Curve.hxx>
20 #include <BRepAlgo.hxx>
21 #include <BRepLib.hxx>
22 #include <BRepLib_MakeEdge.hxx>
23 #include <BRepLib_MakeWire.hxx>
24 #include <BRepTools_WireExplorer.hxx>
25 #include <ElCLib.hxx>
26 #include <Geom_Curve.hxx>
27 #include <Geom_TrimmedCurve.hxx>
28 #include <GeomAbs_CurveType.hxx>
29 #include <GeomConvert.hxx>
30 #include <GeomConvert_CompCurveToBSplineCurve.hxx>
31 #include <GeomLProp.hxx>
32 #include <gp_Pnt.hxx>
33 #include <Precision.hxx>
34 #include <ShapeFix_Shape.hxx>
35 #include <Standard_ConstructionError.hxx>
36 #include <TColGeom_Array1OfBSplineCurve.hxx>
37 #include <TColGeom_HArray1OfBSplineCurve.hxx>
38 #include <TColGeom_SequenceOfCurve.hxx>
39 #include <TColStd_Array1OfBoolean.hxx>
40 #include <TColStd_Array1OfReal.hxx>
41 #include <TColStd_SequenceOfBoolean.hxx>
42 #include <TColStd_SequenceOfReal.hxx>
43 #include <TopExp.hxx>
44 #include <TopLoc_Location.hxx>
45 #include <TopoDS.hxx>
46 #include <TopoDS_Edge.hxx>
47 #include <TopoDS_Shape.hxx>
48 #include <TopoDS_Vertex.hxx>
49 #include <TopoDS_Wire.hxx>
50 #include <TopTools_SequenceOfShape.hxx>
51
52 //Temporary
53 #//include <DrawTrSurf.hxx>
54
55
56 //=======================================================================
57 //function : ConcatenateWire
58 //purpose  : 
59 //=======================================================================
60
61 TopoDS_Wire  BRepAlgo::ConcatenateWire(const TopoDS_Wire& W,
62   const GeomAbs_Shape Option,
63   const Standard_Real TolAngular) 
64 {
65
66
67   Standard_Integer        nb_curve,                         //number of curves in the Wire
68     index;
69   BRepTools_WireExplorer  WExp(W) ;
70   TopoDS_Edge             edge;
71   TopLoc_Location         L ;
72   Standard_Real           First=0.,Last=0.,                       //extremal values for the curve
73     First0 = 0.,
74     toler = 0.,
75     tolleft,tolright;                 //Vertex tolerances
76   TopoDS_Vertex           Vfirst,Vlast;                     //Vertex of the Wire
77   gp_Pnt                  Pfirst,Plast;            //, Pint;  corresponding points
78
79   BRepLib_MakeWire        MakeResult;                       
80   Standard_Real           closed_tolerance =0.0;
81   Standard_Boolean        closed_flag = Standard_False ;
82
83   nb_curve = 0;
84
85   while ( WExp.More()){                                     //computation of the curve number
86     nb_curve++ ;
87     WExp.Next();
88   }
89
90   if (nb_curve > 1) {
91     TColGeom_Array1OfBSplineCurve tab(0,nb_curve-1);          //array of the wire's curve
92     TColStd_Array1OfReal tabtolvertex(0,nb_curve-2);          //array of the tolerance's vertex
93
94     WExp.Init(W);
95
96     for (index=0 ;index<nb_curve; index++){                   //main loop
97       edge = WExp.Current() ;
98       const Handle(Geom_Curve)& aCurve = BRep_Tool::Curve(edge, L, First, Last);
99       Handle(Geom_TrimmedCurve) aTrCurve = new Geom_TrimmedCurve(aCurve, First, Last);
100       tab(index) = GeomConvert::CurveToBSplineCurve(aTrCurve); //storage in a array 
101       tab(index)->Transform(L.Transformation());
102       GeomConvert::C0BSplineToC1BSplineCurve(tab(index),Precision::Confusion());
103
104       if (index >= 1){                                         //continuity test loop
105         if (edge.Orientation()==TopAbs_REVERSED)
106           tab(index)->Reverse();
107         tolleft=BRep_Tool::Tolerance(TopExp::LastVertex(edge));
108         tolright=BRep_Tool::Tolerance(TopExp::FirstVertex(edge));
109         tabtolvertex(index-1)=Max(tolleft,tolright);
110       }
111
112       if(index==0){                                           //storage of the first edge features
113         First0=First;
114         if(edge.Orientation()==TopAbs_REVERSED){             //(usefull for the closed wire) 
115           Vfirst=TopExp::LastVertex(edge);
116           tab(index)->Reverse();
117         }
118         else
119           Vfirst=TopExp::FirstVertex(edge);
120       }
121
122       if(index==nb_curve-1){                                  //storage of the last edge features
123         if(edge.Orientation()==TopAbs_REVERSED)
124           Vlast=TopExp::FirstVertex(edge);
125         else
126           Vlast=TopExp::LastVertex(edge);
127       }
128       WExp.Next() ; 
129     }
130
131     if (BRep_Tool::Tolerance(Vfirst)>BRep_Tool::Tolerance(Vlast)) //computation of the closing tolerance
132       toler=BRep_Tool::Tolerance(Vfirst);
133     else
134       toler=BRep_Tool::Tolerance(Vlast);
135
136     Pfirst=BRep_Tool::Pnt(Vfirst);
137     Plast=BRep_Tool::Pnt(Vlast); 
138
139     if ((Pfirst.Distance(Plast)<=toler)&&                   //C0 continuity test at the closing point
140       (GeomLProp::Continuity(tab(nb_curve-1),tab(0),Last,First0,
141       Standard_True,Standard_True, 
142       toler, TolAngular)>=GeomAbs_G1)) 
143     {
144       closed_tolerance =toler;                                        //if ClosedG1!=0 it will be True and
145       closed_flag = Standard_True ;
146     }                                                        //with the toler value
147     Handle(TColGeom_HArray1OfBSplineCurve)  concatcurve;     //array of the concatenated curves
148     Handle(TColStd_HArray1OfInteger)        ArrayOfIndices;  //array of the remining Vertex
149     if (Option==GeomAbs_G1)
150       GeomConvert::ConcatG1(tab,
151       tabtolvertex,
152       concatcurve,
153       closed_flag,
154       closed_tolerance) ;    //G1 concatenation
155     else
156       GeomConvert::ConcatC1(tab,
157       tabtolvertex,
158       ArrayOfIndices,
159       concatcurve,
160       closed_flag,
161       closed_tolerance);   //C1 concatenation
162
163     for (index=0;index<=(concatcurve->Length()-1);index++){    //building of the resulting Wire
164       BRepLib_MakeEdge EdgeBuilder(concatcurve->Value(index));
165       edge = EdgeBuilder.Edge();
166       MakeResult.Add(edge);
167     } 
168
169   }
170   else {
171
172     WExp.Init(W);
173
174     edge = WExp.Current() ;
175     const Handle(Geom_Curve)& aC = BRep_Tool::Curve(edge,L,First,Last);
176     Handle(Geom_BSplineCurve) aBS  = GeomConvert::CurveToBSplineCurve(new Geom_TrimmedCurve(aC,First,Last));
177     aBS->Transform(L.Transformation());
178     GeomConvert::C0BSplineToC1BSplineCurve(aBS, Precision::Confusion());
179     if (edge.Orientation()==TopAbs_REVERSED)
180     {
181       aBS->Reverse();
182     }
183
184     BRepLib_MakeEdge EdgeBuilder(aBS);
185     edge = EdgeBuilder.Edge();
186     MakeResult.Add(edge);
187   }
188   return MakeResult.Wire() ;  
189
190 }
191
192 //=======================================================================
193 //function : ConcatenateWireC0
194 //purpose  : 
195 //=======================================================================
196
197 TopoDS_Edge  BRepAlgo::ConcatenateWireC0(const TopoDS_Wire& aWire)
198 {
199   Standard_Real LinTol = Precision::Confusion();
200   Standard_Real AngTol = Precision::Angular();
201
202   TopoDS_Edge ResEdge;
203
204   TopoDS_Wire theWire = aWire;
205   BRepLib::BuildCurves3d(theWire);
206   Handle(ShapeFix_Shape) Fixer = new ShapeFix_Shape(theWire);
207   Fixer->SetPrecision(LinTol);
208   Fixer->SetMaxTolerance(LinTol);
209   Fixer->Perform();
210   theWire = TopoDS::Wire(Fixer->Shape());
211
212   TColGeom_SequenceOfCurve CurveSeq;
213   TColStd_SequenceOfReal FparSeq;
214   TColStd_SequenceOfReal LparSeq;
215   TColStd_SequenceOfReal TolSeq;
216   TColStd_SequenceOfBoolean IsFwdSeq;
217   GeomAbs_CurveType CurType = GeomAbs_OtherCurve;
218   TopoDS_Vertex FirstVertex, LastVertex;
219
220   BRepTools_WireExplorer wexp(theWire);
221
222   for (; wexp.More(); wexp.Next()) {
223     TopoDS_Edge anEdge = wexp.Current();
224     Standard_Real fpar, lpar;
225     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, fpar, lpar);
226
227     if (aCurve.IsNull())
228       continue;
229
230     GeomAdaptor_Curve  aGACurve(aCurve);
231     GeomAbs_CurveType  aType       = aGACurve.GetType();
232     Handle(Geom_Curve) aBasisCurve = aGACurve.Curve();
233     Standard_Boolean   isFwd       = (wexp.Orientation() != TopAbs_REVERSED);
234
235     if (aBasisCurve->IsPeriodic()) {
236       ElCLib::AdjustPeriodic
237         (aBasisCurve->FirstParameter(), aBasisCurve->LastParameter(),
238         Precision::PConfusion(), fpar, lpar);
239     }
240
241     if (CurveSeq.IsEmpty()) {
242       CurveSeq.Append(aCurve);
243       FparSeq.Append(fpar);
244       LparSeq.Append(lpar);
245       IsFwdSeq.Append(isFwd);
246       CurType     = aType;
247       FirstVertex = wexp.CurrentVertex();
248     } else {
249       Standard_Boolean isSameCurve = Standard_False;
250       Standard_Real NewFpar = RealFirst(), NewLpar = RealLast();
251       GeomAdaptor_Curve GAprevcurve(CurveSeq.Last());
252
253       if (aCurve == CurveSeq.Last()) {
254         NewFpar = fpar;
255         NewLpar = lpar;
256         isSameCurve = Standard_True;
257       } else if (aType == CurType &&
258         aType != GeomAbs_BezierCurve &&
259         aType != GeomAbs_BSplineCurve &&
260         aType != GeomAbs_OtherCurve) {
261           switch (aType) {
262           case GeomAbs_Line:
263             {
264               gp_Lin aLine    = aGACurve.Line();
265               gp_Lin PrevLine = GAprevcurve.Line(); 
266
267               if (aLine.Contains(PrevLine.Location(), LinTol) &&
268                 aLine.Direction().IsParallel(PrevLine.Direction(), AngTol)) {
269                   gp_Pnt P1 = ElCLib::Value(fpar, aLine);
270                   gp_Pnt P2 = ElCLib::Value(lpar, aLine);
271
272                   NewFpar = ElCLib::Parameter(PrevLine, P1);
273                   NewLpar = ElCLib::Parameter(PrevLine, P2);
274                   isSameCurve = Standard_True;
275               }
276               break;
277             }
278           case GeomAbs_Circle:
279             {
280               gp_Circ aCircle    = aGACurve.Circle();
281               gp_Circ PrevCircle = GAprevcurve.Circle();
282
283               if (aCircle.Location().Distance(PrevCircle.Location()) <= LinTol &&
284                 Abs(aCircle.Radius() - PrevCircle.Radius()) <= LinTol &&
285                 aCircle.Axis().IsParallel(PrevCircle.Axis(), AngTol)) {
286                   gp_Pnt P1 = ElCLib::Value(fpar, aCircle);
287                   gp_Pnt P2 = ElCLib::Value(lpar, aCircle);
288
289                   NewFpar = ElCLib::Parameter(PrevCircle, P1);
290                   NewLpar = ElCLib::Parameter(PrevCircle, P2);
291                   isSameCurve = Standard_True;
292               }
293               break;
294             }
295           case GeomAbs_Ellipse:
296             {
297               gp_Elips anEllipse   = aGACurve.Ellipse();
298               gp_Elips PrevEllipse = GAprevcurve.Ellipse();
299
300               if (anEllipse.Focus1().Distance(PrevEllipse.Focus1()) <= LinTol &&
301                 anEllipse.Focus2().Distance(PrevEllipse.Focus2()) <= LinTol &&
302                 Abs(anEllipse.MajorRadius() - PrevEllipse.MajorRadius()) <= LinTol &&
303                 Abs(anEllipse.MinorRadius() - PrevEllipse.MinorRadius()) <= LinTol &&
304                 anEllipse.Axis().IsParallel(PrevEllipse.Axis(), AngTol)) {
305                   gp_Pnt P1 = ElCLib::Value(fpar, anEllipse);
306                   gp_Pnt P2 = ElCLib::Value(lpar, anEllipse);
307
308                   NewFpar = ElCLib::Parameter(PrevEllipse, P1);
309                   NewLpar = ElCLib::Parameter(PrevEllipse, P2);
310                   isSameCurve = Standard_True;
311               }
312               break;
313             }
314           case GeomAbs_Hyperbola:
315             {
316               gp_Hypr aHypr    = aGACurve.Hyperbola();
317               gp_Hypr PrevHypr = GAprevcurve.Hyperbola();
318
319               if (aHypr.Focus1().Distance(PrevHypr.Focus1()) <= LinTol &&
320                 aHypr.Focus2().Distance(PrevHypr.Focus2()) <= LinTol &&
321                 Abs(aHypr.MajorRadius() - PrevHypr.MajorRadius()) <= LinTol &&
322                 Abs(aHypr.MinorRadius() - PrevHypr.MinorRadius()) <= LinTol &&
323                 aHypr.Axis().IsParallel(PrevHypr.Axis(), AngTol)) {
324                   gp_Pnt P1 = ElCLib::Value(fpar, aHypr);
325                   gp_Pnt P2 = ElCLib::Value(lpar, aHypr);
326
327                   NewFpar = ElCLib::Parameter(PrevHypr, P1);
328                   NewLpar = ElCLib::Parameter(PrevHypr, P2);
329                   isSameCurve = Standard_True;
330               }
331               break;
332             }
333           case GeomAbs_Parabola:
334             {
335               gp_Parab aParab    = aGACurve.Parabola();
336               gp_Parab PrevParab = GAprevcurve.Parabola();
337
338               if (aParab.Location().Distance(PrevParab.Location()) <= LinTol &&
339                 aParab.Focus().Distance(PrevParab.Focus()) <= LinTol &&
340                 Abs(aParab.Focal() - PrevParab.Focal()) <= LinTol &&
341                 aParab.Axis().IsParallel(PrevParab.Axis(), AngTol)) {
342                   gp_Pnt P1 = ElCLib::Value(fpar, aParab);
343                   gp_Pnt P2 = ElCLib::Value(lpar, aParab);
344
345                   NewFpar = ElCLib::Parameter(PrevParab, P1);
346                   NewLpar = ElCLib::Parameter(PrevParab, P2);
347                   isSameCurve = Standard_True;
348               }
349               break;
350             }
351           default:
352             break;
353           } //end of switch
354       } //end of else
355
356       if (isSameCurve) {
357         const Standard_Boolean isSameDir = (isFwd == IsFwdSeq.Last());
358
359         if (aBasisCurve->IsPeriodic()) {
360           // Treat periodic curves.
361           const Standard_Real aPeriod = aBasisCurve->Period();
362
363           if (isSameDir) {
364             // Check if first parameter is greater then the last one.
365             while (NewFpar > NewLpar) {
366               NewFpar -= aPeriod;
367             }
368           } else { // !isSameDir
369             // Check if last parameter is greater then the first one.
370             while (NewLpar > NewFpar) {
371               NewLpar -= aPeriod;
372             }
373
374             // Change parameters
375             const Standard_Real aTmpPar = NewLpar;
376
377             NewLpar = NewFpar;
378             NewFpar = aTmpPar;
379           }
380
381           // Udjust parameters on periodic curves.
382           if (IsFwdSeq.Last()) {
383             // The current curve should be after the previous one.
384             ElCLib::AdjustPeriodic(LparSeq.Last(), LparSeq.Last() + aPeriod,
385               Precision::PConfusion(), NewFpar, NewLpar);
386           } else {
387             // The current curve should be before the previous one.
388             ElCLib::AdjustPeriodic(FparSeq.Last() - aPeriod, FparSeq.Last(),
389               Precision::PConfusion(), NewFpar, NewLpar);
390           }
391         } else if (!isSameDir) {
392           // Not periodic curves. Opposite dirs.
393           const Standard_Real aTmpPar = NewLpar;
394
395           NewLpar = NewFpar;
396           NewFpar = aTmpPar;
397         }
398
399         if (IsFwdSeq.Last()) {
400           // Update last parameter 
401           LparSeq(LparSeq.Length()) = NewLpar;
402         } else {
403           // Update first parameter 
404           FparSeq(FparSeq.Length()) = NewFpar;
405         }
406       } else {
407         // Add new curve.
408         CurveSeq.Append(aCurve);
409         FparSeq.Append(fpar);
410         LparSeq.Append(lpar);
411         IsFwdSeq.Append(isFwd);
412         TolSeq.Append(BRep_Tool::Tolerance(wexp.CurrentVertex()));
413         CurType = aType;
414       }
415     }
416   }
417
418   LastVertex = wexp.CurrentVertex();
419   TolSeq.Append(BRep_Tool::Tolerance(LastVertex));
420
421   Standard_Boolean isReverse = Standard_False;
422
423   if (!IsFwdSeq.IsEmpty()) {
424     isReverse = !IsFwdSeq(1);
425   }
426
427   TopoDS_Vertex FirstVtx_final = (isReverse)? LastVertex : FirstVertex;
428   FirstVtx_final.Orientation(TopAbs_FORWARD);
429   TopoDS_Vertex LastVtx_final = (isReverse)? FirstVertex : LastVertex;
430   LastVtx_final.Orientation(TopAbs_REVERSED);
431
432   if (CurveSeq.IsEmpty())
433     return ResEdge;
434
435   Standard_Integer nb_curve = CurveSeq.Length();   //number of curves
436   TColGeom_Array1OfBSplineCurve tab(0,nb_curve-1);                    //array of the curves
437   TColStd_Array1OfReal tabtolvertex(0,nb_curve-1); //(0,nb_curve-2);  //array of the tolerances
438
439   Standard_Integer i;
440
441   if (nb_curve > 1)
442   {
443     for (i = 1; i <= nb_curve; i++)
444     {
445       if (CurveSeq(i)->IsInstance(STANDARD_TYPE(Geom_TrimmedCurve)))
446         CurveSeq(i) = (*((Handle(Geom_TrimmedCurve)*)&(CurveSeq(i))))->BasisCurve();
447
448       Handle(Geom_TrimmedCurve) aTrCurve = new Geom_TrimmedCurve(CurveSeq(i), FparSeq(i), LparSeq(i));
449       tab(i-1) = GeomConvert::CurveToBSplineCurve(aTrCurve);
450       GeomConvert::C0BSplineToC1BSplineCurve(tab(i-1), Precision::Confusion());
451
452       if (!IsFwdSeq(i)) {
453         tab(i-1)->Reverse();
454       }
455
456       //Temporary
457       //char* name = new char[100];
458       //sprintf(name, "c%d", i);
459       //DrawTrSurf::Set(name, tab(i-1));
460
461       if (i > 1)
462         tabtolvertex(i-2) = TolSeq(i-1) * 5.;
463     }
464     tabtolvertex(nb_curve-1) = TolSeq(TolSeq.Length()) * 5.;
465
466     Standard_Boolean closed_flag = Standard_False;
467     Standard_Real closed_tolerance = 0.;
468     if (FirstVertex.IsSame(LastVertex) &&
469       GeomLProp::Continuity(tab(0), tab(nb_curve-1),
470       tab(0)->FirstParameter(),
471       tab(nb_curve-1)->LastParameter(),
472       Standard_False, Standard_False, LinTol, AngTol) >= GeomAbs_G1)
473     {
474       closed_flag = Standard_True ;
475       closed_tolerance = BRep_Tool::Tolerance(FirstVertex);
476     }
477
478     Handle(TColGeom_HArray1OfBSplineCurve)  concatcurve;     //array of the concatenated curves
479     Handle(TColStd_HArray1OfInteger)        ArrayOfIndices;  //array of the remining Vertex
480     GeomConvert::ConcatC1(tab,
481       tabtolvertex,
482       ArrayOfIndices,
483       concatcurve,
484       closed_flag,
485       closed_tolerance);   //C1 concatenation
486
487     if (concatcurve->Length() > 1)
488     {
489       Standard_Real MaxTolVer = LinTol;
490       for (i = 1; i <= TolSeq.Length(); i++)
491         if (TolSeq(i) > MaxTolVer)
492           MaxTolVer = TolSeq(i);
493       MaxTolVer *= 5.;
494
495       GeomConvert_CompCurveToBSplineCurve Concat(concatcurve->Value(concatcurve->Lower()));
496
497       for (i = concatcurve->Lower()+1; i <= concatcurve->Upper(); i++)
498         Concat.Add( concatcurve->Value(i), MaxTolVer, Standard_True );
499
500       concatcurve->SetValue(concatcurve->Lower(), Concat.BSplineCurve());
501     }
502
503     ResEdge = BRepLib_MakeEdge(concatcurve->Value(concatcurve->Lower()),
504       FirstVtx_final, LastVtx_final,
505       concatcurve->Value(concatcurve->Lower())->FirstParameter(),
506       concatcurve->Value(concatcurve->Lower())->LastParameter());
507   }
508   else
509   {
510     if (CurveSeq(1)->IsInstance(STANDARD_TYPE(Geom_TrimmedCurve)))
511       CurveSeq(1) = (*((Handle(Geom_TrimmedCurve)*)&(CurveSeq(1))))->BasisCurve();
512
513     Handle(Geom_Curve) aCopyCurve =
514       Handle(Geom_Curve)::DownCast(CurveSeq(1)->Copy());
515
516     ResEdge = BRepLib_MakeEdge(aCopyCurve,
517       FirstVtx_final, LastVtx_final,
518       FparSeq(1), LparSeq(1));
519   }
520
521   if (isReverse)
522     ResEdge.Reverse();
523
524   return ResEdge;
525 }