fa39fff236fb8384cec829aaeda00564d452b46f
[occt.git] / src / BRepOffsetAPI / BRepOffsetAPI_ThruSections.cxx
1 // Created on: 1995-07-18
2 // Created by: Joelle CHAUVET
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 // Modified:    Mon Jan 12 10:50:10 1998
18 //              gestion automatique de l'origine et de l'orientation
19 //              avec la methode ArrangeWires
20 // Modified:    Mon Jan 19 10:11:56 1998
21 //              traitement des cas particuliers cylindre, cone, plan 
22 //              (methodes DetectKPart et CreateKPart)
23 // Modified:    Mon Feb 23 09:28:46 1998
24 //              traitement des sections avec nombre d'elements different
25 //              + quelques ameliorations pour les cas particuliers
26 //              + cas de la derniere section ponctuelle
27 // Modified:    Mon Apr  6 15:47:44 1998
28 //              traitement des cas particuliers deplace dans BRepFill 
29 // Modified:    Thu Apr 30 15:24:17 1998
30 //              separation sections fermees / sections ouvertes + debug 
31 // Modified:    Fri Jul 10 11:23:35 1998
32 //              surface de CreateSmoothed par concatenation,approximation
33 //              et segmentation (PRO13924, CTS21295)
34 // Modified:    Tue Jul 21 16:48:35 1998
35 //              pb de ratio (BUC60281) 
36 // Modified:    Thu Jul 23 11:38:36 1998
37 //              sections bouclantes
38 // Modified:    Fri Aug 28 10:13:44 1998
39 //              traitement des sections ponctuelles
40 //              dans l'historique (cf. loft06 et loft09)
41 //              et dans le cas des solides
42 // Modified:    Tue Nov  3 10:06:15 1998
43 //              utilisation de BRepFill_CompatibleWires
44
45 #include <BRep_Builder.hxx>
46 #include <BRep_Tool.hxx>
47 #include <BRepBuilderAPI_FindPlane.hxx>
48 #include <BRepBuilderAPI_MakeFace.hxx>
49 #include <BRepClass3d_SolidClassifier.hxx>
50 #include <BRepFill_CompatibleWires.hxx>
51 #include <BRepFill_Generator.hxx>
52 #include <BRepLib.hxx>
53 #include <BRepOffsetAPI_ThruSections.hxx>
54 #include <BRepTools_WireExplorer.hxx>
55 #include <BSplCLib.hxx>
56 #include <Geom2d_Line.hxx>
57 #include <Geom_BezierCurve.hxx>
58 #include <Geom_BSplineCurve.hxx>
59 #include <Geom_BSplineSurface.hxx>
60 #include <Geom_Conic.hxx>
61 #include <Geom_Curve.hxx>
62 #include <Geom_Plane.hxx>
63 #include <Geom_TrimmedCurve.hxx>
64 #include <GeomAbs_Shape.hxx>
65 #include <GeomConvert.hxx>
66 #include <GeomConvert_ApproxCurve.hxx>
67 #include <GeomConvert_CompCurveToBSplineCurve.hxx>
68 #include <GeomFill_AppSurf.hxx>
69 #include <GeomFill_Line.hxx>
70 #include <GeomFill_SectionGenerator.hxx>
71 #include <gp_Dir2d.hxx>
72 #include <gp_Pnt.hxx>
73 #include <gp_Pnt2d.hxx>
74 #include <Precision.hxx>
75 #include <Standard_DomainError.hxx>
76 #include <Standard_NullObject.hxx>
77 #include <TColgp_Array1OfPnt.hxx>
78 #include <TopAbs.hxx>
79 #include <TopExp.hxx>
80 #include <TopLoc_Location.hxx>
81 #include <TopoDS.hxx>
82 #include <TopoDS_Edge.hxx>
83 #include <TopoDS_Face.hxx>
84 #include <TopoDS_Iterator.hxx>
85 #include <TopoDS_Shape.hxx>
86 #include <TopoDS_Solid.hxx>
87 #include <TopoDS_Vertex.hxx>
88 #include <TopoDS_Wire.hxx>
89 #include <TopTools_Array1OfShape.hxx>
90 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
91 #include <TopTools_ListIteratorOfListOfShape.hxx>
92
93 //=======================================================================
94 //function : PreciseUpar
95 //purpose  : pins the u-parameter of surface close to U-knot
96 //           to this U-knot
97 //=======================================================================
98 static Standard_Real PreciseUpar(const Standard_Real anUpar,
99   const Handle(Geom_BSplineSurface)& aSurface)
100 {
101   Standard_Real Tol = Precision::PConfusion();
102   Standard_Integer i1, i2;
103
104   aSurface->LocateU(anUpar, Tol, i1, i2);
105   Standard_Real U1 = aSurface->UKnot(i1);
106   Standard_Real U2 = aSurface->UKnot(i2);
107
108   Standard_Real NewU = anUpar;
109
110   NewU = (anUpar - U1 < U2 - anUpar)? U1 : U2;
111   return NewU;
112 }
113
114 //=======================================================================
115 //function :  PerformPlan
116 //purpose  : Construct a plane of filling if exists
117 //=======================================================================
118
119 static Standard_Boolean PerformPlan(const TopoDS_Wire& W,
120   const Standard_Real presPln,
121   TopoDS_Face& theFace)
122 {
123   Standard_Boolean isDegen = Standard_True;
124   TopoDS_Iterator iter(W);
125   for (; iter.More(); iter.Next())
126   {
127     const TopoDS_Edge& anEdge = TopoDS::Edge(iter.Value());
128     if (!BRep_Tool::Degenerated(anEdge))
129       isDegen = Standard_False;
130   }
131   if (isDegen)
132     return Standard_True;
133
134   Standard_Boolean Ok = Standard_False;
135   if (!W.IsNull()) {
136     BRepBuilderAPI_FindPlane Searcher( W, presPln );
137     if (Searcher.Found())
138     {
139       theFace = BRepBuilderAPI_MakeFace(Searcher.Plane(), W);
140       Ok = Standard_True;
141     }
142     else // try to find another surface
143     {
144       BRepBuilderAPI_MakeFace MF( W );
145       if (MF.IsDone())
146       {
147         theFace = MF.Face();
148         Ok = Standard_True;
149       }
150     }
151   }
152
153   return Ok;
154 }
155
156 //=============================================================================
157 //function :  IsSameOriented
158 //purpose  : Checks whether aFace is oriented to the same side as aShell or not
159 //=============================================================================
160
161 static Standard_Boolean IsSameOriented(const TopoDS_Shape& aFace,
162   const TopoDS_Shape& aShell)
163 {
164   TopExp_Explorer Explo(aFace, TopAbs_EDGE);
165   TopoDS_Shape anEdge = Explo.Current();
166   TopAbs_Orientation Or1 = anEdge.Orientation();
167
168   TopTools_IndexedDataMapOfShapeListOfShape EFmap;
169   TopExp::MapShapesAndAncestors( aShell, TopAbs_EDGE, TopAbs_FACE, EFmap );
170
171   const TopoDS_Shape& AdjacentFace = EFmap.FindFromKey(anEdge).First();
172   TopoDS_Shape theEdge;
173   for (Explo.Init(AdjacentFace, TopAbs_EDGE); Explo.More(); Explo.Next())
174   {
175     theEdge = Explo.Current();
176     if (theEdge.IsSame(anEdge))
177       break;
178   }
179
180   TopAbs_Orientation Or2 = theEdge.Orientation();
181   if (Or1 == Or2)
182     return Standard_False;
183   return Standard_True;
184 }
185
186 //=======================================================================
187 //function : MakeSolid
188 //purpose  : 
189 //=======================================================================
190
191 static TopoDS_Solid MakeSolid(TopoDS_Shell& shell, const TopoDS_Wire& wire1,
192   const TopoDS_Wire& wire2, const Standard_Real presPln,
193   TopoDS_Face& face1, TopoDS_Face& face2)
194 {
195   if (shell.IsNull())
196     throw StdFail_NotDone("Thrusections is not build");
197   Standard_Boolean B = shell.Closed();
198   BRep_Builder BB;
199
200   if (!B)
201   {
202     // It is necessary to close the extremities 
203     B =  PerformPlan(wire1, presPln, face1);
204     if (B) {
205       B =  PerformPlan(wire2, presPln, face2);
206       if (B) {
207         if (!face1.IsNull() && !IsSameOriented( face1, shell ))
208           face1.Reverse();
209         if (!face2.IsNull() && !IsSameOriented( face2, shell ))
210           face2.Reverse();
211
212         if (!face1.IsNull())
213           BB.Add(shell, face1);
214         if (!face2.IsNull())
215           BB.Add(shell, face2);
216
217         shell.Closed(Standard_True);
218       }
219     }
220   }
221
222   TopoDS_Solid solid;
223   BB.MakeSolid(solid); 
224   BB.Add(solid, shell);
225
226   // verify the orientation the solid
227   BRepClass3d_SolidClassifier clas3d(solid);
228   clas3d.PerformInfinitePoint(Precision::Confusion());
229   if (clas3d.State() == TopAbs_IN) {
230     BB.MakeSolid(solid); 
231     TopoDS_Shape aLocalShape = shell.Reversed();
232     BB.Add(solid, TopoDS::Shell(aLocalShape));
233     //    B.Add(solid, TopoDS::Shell(newShell.Reversed()));
234   }
235
236   solid.Closed(Standard_True);
237   return solid;
238 }
239
240
241 //=======================================================================
242 //function : BRepOffsetAPI_ThruSections
243 //purpose  : 
244 //=======================================================================
245
246 BRepOffsetAPI_ThruSections::BRepOffsetAPI_ThruSections(const Standard_Boolean isSolid, const Standard_Boolean ruled,
247   const Standard_Real pres3d):
248 myIsSolid(isSolid), myIsRuled(ruled), myPres3d(pres3d)
249 {
250   myWCheck = Standard_True;
251   //----------------------------
252   myParamType = Approx_ChordLength; 
253   myDegMax    = 8; 
254   myContinuity = GeomAbs_C2;
255   myCritWeights[0] = .4; 
256   myCritWeights[1] = .2; 
257   myCritWeights[2] = .4; 
258   myUseSmoothing = Standard_False;
259 }
260
261
262 //=======================================================================
263 //function : Init
264 //purpose  : 
265 //=======================================================================
266
267 void BRepOffsetAPI_ThruSections::Init(const Standard_Boolean isSolid, const Standard_Boolean ruled,
268   const Standard_Real pres3d)
269 {
270   myIsSolid = isSolid;
271   myIsRuled = ruled;
272   myPres3d = pres3d;
273   myWCheck = Standard_True;
274   //----------------------------
275   myParamType = Approx_ChordLength; 
276   myDegMax    = 6; 
277   myContinuity = GeomAbs_C2;
278   myCritWeights[0] = .4; 
279   myCritWeights[1] = .2; 
280   myCritWeights[2] = .4; 
281   myUseSmoothing = Standard_False;
282
283 }
284
285
286 //=======================================================================
287 //function : AddWire
288 //purpose  : 
289 //=======================================================================
290
291 void BRepOffsetAPI_ThruSections::AddWire(const TopoDS_Wire& wire)
292 {
293   myWires.Append(wire);
294 }
295
296 //=======================================================================
297 //function : AddVertex
298 //purpose  : 
299 //=======================================================================
300
301 void BRepOffsetAPI_ThruSections::AddVertex(const TopoDS_Vertex& aVertex)
302 {
303   BRep_Builder BB;
304
305   TopoDS_Edge DegEdge;
306   BB.MakeEdge( DegEdge );
307   BB.Add( DegEdge, aVertex.Oriented(TopAbs_FORWARD) );
308   BB.Add( DegEdge, aVertex.Oriented(TopAbs_REVERSED) );
309   BB.Degenerated( DegEdge, Standard_True );
310
311   TopoDS_Wire DegWire;
312   BB.MakeWire( DegWire );
313   BB.Add( DegWire, DegEdge );
314   DegWire.Closed( Standard_True );
315
316   myWires.Append( DegWire );
317 }
318
319 //=======================================================================
320 //function : CheckCompatibility
321 //purpose  : 
322 //=======================================================================
323
324 void BRepOffsetAPI_ThruSections::CheckCompatibility(const Standard_Boolean check)
325 {
326   myWCheck = check;
327 }
328
329
330 //=======================================================================
331 //function : Build
332 //purpose  : 
333 //=======================================================================
334
335 void BRepOffsetAPI_ThruSections::Build()
336 {
337   //Check set of section for right configuration of punctual sections
338   Standard_Integer i;
339   TopExp_Explorer explo;
340   for (i = 2; i <= myWires.Length()-1; i++)
341   {
342     Standard_Boolean wdeg = Standard_True;
343     for (explo.Init(myWires(i), TopAbs_EDGE); explo.More(); explo.Next())
344     {
345       const TopoDS_Edge& anEdge = TopoDS::Edge(explo.Current());
346       wdeg = wdeg && (BRep_Tool::Degenerated(anEdge));
347     }
348     if (wdeg)
349       throw Standard_Failure("Wrong usage of punctual sections");
350   }
351   if (myWires.Length() <= 2)
352   {
353     Standard_Boolean wdeg = Standard_True;
354     for (i = 1; i <= myWires.Length(); i++)
355       for (explo.Init(myWires(i), TopAbs_EDGE); explo.More(); explo.Next())
356       {
357         const TopoDS_Edge& anEdge = TopoDS::Edge(explo.Current());
358         wdeg = wdeg && (BRep_Tool::Degenerated(anEdge));
359       }
360       if (wdeg)
361         throw Standard_Failure("Wrong usage of punctual sections");
362   }
363
364   if (myWCheck) {
365     // compute origin and orientation on wires to avoid twisted results
366     // and update wires to have same number of edges
367
368     // use BRepFill_CompatibleWires
369     TopTools_SequenceOfShape WorkingSections;
370     WorkingSections.Clear();
371     TopTools_DataMapOfShapeListOfShape WorkingMap;
372     WorkingMap.Clear();
373
374     // Calculate the working sections
375     BRepFill_CompatibleWires Georges(myWires);
376     Georges.Perform();
377     if (Georges.IsDone()) {
378       WorkingSections = Georges.Shape();
379       WorkingMap = Georges.Generated();
380     }
381     myWires = WorkingSections;
382   }
383
384   try {
385     // Calculate the resulting shape
386     if (myWires.Length() == 2 || myIsRuled) {
387       // create a ruled shell
388       CreateRuled();
389     }
390     else {
391       // create a smoothed shell
392       CreateSmoothed();
393     }
394   }
395   catch (Standard_Failure)
396   {
397     NotDone();
398     return;
399   }
400   // Encode the Regularities
401   BRepLib::EncodeRegularity(myShape);
402 }
403
404
405 //=======================================================================
406 //function : CreateRuled
407 //purpose  : 
408 //=======================================================================
409
410 void BRepOffsetAPI_ThruSections::CreateRuled()
411 {
412   Standard_Integer nbSects = myWires.Length();
413   BRepFill_Generator aGene;
414   //  for (Standard_Integer i=1; i<=nbSects; i++) {
415   Standard_Integer i;
416   for (i=1; i<=nbSects; i++) {
417     aGene.AddWire(TopoDS::Wire(myWires(i)));
418   }
419   aGene.Perform();
420   TopoDS_Shell shell = aGene.Shell();
421
422   if (myIsSolid) {
423
424     // check if the first wire is the same as the last
425     Standard_Boolean vClosed = (myWires(1).IsSame(myWires(nbSects))) ;
426
427     if (vClosed) {
428
429       TopoDS_Solid solid;      
430       BRep_Builder B;
431       B.MakeSolid(solid); 
432       B.Add(solid, shell);
433
434       // verify the orientation of the solid
435       BRepClass3d_SolidClassifier clas3d(solid);
436       clas3d.PerformInfinitePoint(Precision::Confusion());
437       if (clas3d.State() == TopAbs_IN) {
438         B.MakeSolid(solid); 
439         TopoDS_Shape aLocalShape = shell.Reversed();
440         B.Add(solid, TopoDS::Shell(aLocalShape));
441         //      B.Add(solid, TopoDS::Shell(shell.Reversed()));
442       }
443       myShape = solid;
444
445     }
446
447     else {
448
449       TopoDS_Wire wire1 = TopoDS::Wire(myWires.First());
450       TopoDS_Wire wire2 = TopoDS::Wire(myWires.Last());
451       myShape = MakeSolid(shell, wire1, wire2, myPres3d, myFirst, myLast);
452
453     }
454
455     Done();
456   }
457
458   else {
459     myShape = shell;
460     Done();
461   }
462
463   // history
464   BRepTools_WireExplorer anExp1, anExp2;
465   TopTools_IndexedDataMapOfShapeListOfShape M;
466   TopExp::MapShapesAndAncestors(shell, TopAbs_EDGE, TopAbs_FACE, M);
467   TopTools_ListIteratorOfListOfShape it;
468
469   TopTools_IndexedDataMapOfShapeListOfShape MV;
470   TopExp::MapShapesAndAncestors(shell, TopAbs_VERTEX, TopAbs_FACE, MV);
471
472   for (i=1; i<=nbSects-1; i++) {
473
474     const TopoDS_Wire& wire1 = TopoDS::Wire(myWires(i));
475     const TopoDS_Wire& wire2 = TopoDS::Wire(myWires(i+1));
476
477     anExp1.Init(wire1);
478     anExp2.Init(wire2);
479
480     Standard_Boolean tantque = anExp1.More() && anExp2.More();
481
482     while (tantque) {
483
484       const TopoDS_Shape& edge1 = anExp1.Current();
485       const TopoDS_Shape& edge2 = anExp2.Current();
486       Standard_Boolean degen1 = BRep_Tool::Degenerated(anExp1.Current());
487       Standard_Boolean degen2 = BRep_Tool::Degenerated(anExp2.Current());
488
489       TopTools_MapOfShape MapFaces;
490       if (degen2){
491         TopoDS_Vertex Vdegen = TopExp::FirstVertex(TopoDS::Edge(edge2));
492         for (it.Initialize(MV.FindFromKey(Vdegen)); it.More(); it.Next()) {
493           MapFaces.Add(it.Value());
494         }
495       }
496       else {
497         for (it.Initialize(M.FindFromKey(edge2)); it.More(); it.Next()) {
498           MapFaces.Add(it.Value());
499         }
500       }
501
502       if (degen1) {
503         TopoDS_Vertex Vdegen = TopExp::FirstVertex(TopoDS::Edge(edge1));
504         for (it.Initialize(MV.FindFromKey(Vdegen)); it.More(); it.Next()) {
505           const TopoDS_Shape& Face = it.Value();
506           if (MapFaces.Contains(Face)) {
507             myGenerated.Bind(edge1, Face);
508             break;
509           }
510         }
511       }
512       else {
513         for (it.Initialize(M.FindFromKey(edge1)); it.More(); it.Next()) {
514           const TopoDS_Shape& Face = it.Value();
515           if (MapFaces.Contains(Face)) {
516             myGenerated.Bind(edge1, Face);
517             break;
518           }
519         }
520       }
521
522       if (!degen1) anExp1.Next();
523       if (!degen2) anExp2.Next();
524
525       tantque = anExp1.More() && anExp2.More();
526       if (degen1) tantque = anExp2.More();
527       if (degen2) tantque = anExp1.More();
528
529     }
530
531   }
532
533 }
534
535 //=======================================================================
536 //function : CreateSmoothed
537 //purpose  : 
538 //=======================================================================
539
540 void BRepOffsetAPI_ThruSections::CreateSmoothed()
541 {
542   // initialisation
543   Standard_Integer nbSects = myWires.Length();
544   BRepTools_WireExplorer anExp;
545
546   Standard_Boolean w1Point = Standard_True;
547   // check if the first wire is punctual
548   for(anExp.Init(TopoDS::Wire(myWires(1))); anExp.More(); anExp.Next()) {
549     w1Point = w1Point && (BRep_Tool::Degenerated(anExp.Current()));
550   }
551
552   Standard_Boolean w2Point = Standard_True;
553   // check if the last wire is punctual
554   for(anExp.Init(TopoDS::Wire(myWires(nbSects))); anExp.More(); anExp.Next()) {
555     w2Point = w2Point && (BRep_Tool::Degenerated(anExp.Current()));
556   }
557
558   Standard_Boolean vClosed = Standard_False;
559   // check if the first wire is the same as last
560   if (myWires(1).IsSame(myWires(myWires.Length()))) vClosed = Standard_True;
561
562   // find the dimension
563   Standard_Integer nbEdges=0;
564   if (!w1Point) {
565     for(anExp.Init(TopoDS::Wire(myWires(1))); anExp.More(); anExp.Next()) {
566       nbEdges++;
567     }
568   }
569   else {
570     for(anExp.Init(TopoDS::Wire(myWires(2))); anExp.More(); anExp.Next()) {
571       nbEdges++;
572     }
573   }
574
575   // recover the shapes
576   Standard_Boolean uClosed = Standard_True;
577   TopTools_Array1OfShape shapes(1, nbSects*nbEdges);
578   Standard_Integer nb=0, i, j;
579
580   for (i=1; i<=nbSects; i++) {
581     const TopoDS_Wire& wire = TopoDS::Wire(myWires(i));
582     if (!wire.Closed()) {
583       // check if the vertices are the same
584       TopoDS_Vertex V1, V2;
585       TopExp::Vertices(wire,V1,V2);
586       if ( !V1.IsSame(V2)) uClosed = Standard_False;
587     }
588     if ( (i==1 && w1Point) || (i==nbSects && w2Point) ) {
589       // if the wire is punctual
590       anExp.Init(TopoDS::Wire(wire));
591       for(j=1; j<=nbEdges; j++) {
592         nb++;
593         shapes(nb) = anExp.Current();
594       }
595     }
596     else {
597       // otherwise
598       for(anExp.Init(TopoDS::Wire(wire)); anExp.More(); anExp.Next()) {
599         nb++;
600         shapes(nb) = anExp.Current();
601       }
602     }
603   }
604
605   // create the new surface
606   TopoDS_Shell shell;
607   TopoDS_Face face;
608   TopoDS_Wire W;
609   TopoDS_Edge edge, edge1, edge2, edge3, edge4, couture;
610   TopTools_Array1OfShape vcouture(1, nbEdges);
611
612   BRep_Builder B;
613   B.MakeShell(shell);
614
615   TopoDS_Wire newW1, newW2;
616   BRep_Builder BW1, BW2;
617   BW1.MakeWire(newW1);
618   BW2.MakeWire(newW2);
619
620   TopLoc_Location loc;
621   TopoDS_Vertex v1f,v1l,v2f,v2l;
622
623   Standard_Integer nbPnts = 21;
624   TColgp_Array2OfPnt points(1, nbPnts, 1, nbSects);
625
626   // concatenate each section to get a total surface that will be segmented
627   Handle(Geom_BSplineSurface) TS;
628   TS = TotalSurf(shapes,nbSects,nbEdges,w1Point,w2Point,vClosed);
629
630   if(TS.IsNull()) {
631     return;
632   }
633
634   TopoDS_Shape firstEdge;
635   for (i=1; i<=nbEdges; i++) {  
636
637     // segmentation of TS
638     Handle(Geom_BSplineSurface) surface;
639     surface = Handle(Geom_BSplineSurface)::DownCast(TS->Copy());
640     Standard_Real Ui1,Ui2,V0,V1;
641     Ui1 = i-1;
642     Ui2 = i;
643     Ui1 = PreciseUpar(Ui1, surface);
644     Ui2 = PreciseUpar(Ui2, surface);
645     V0  = surface->VKnot(surface->FirstVKnotIndex());
646     V1  = surface->VKnot(surface->LastVKnotIndex());
647     surface->Segment(Ui1,Ui2,V0,V1);
648
649     // return vertices
650     edge =  TopoDS::Edge(shapes(i));
651     TopExp::Vertices(edge,v1f,v1l);
652     if (edge.Orientation() == TopAbs_REVERSED)
653       TopExp::Vertices(edge,v1l,v1f);
654     firstEdge = edge;
655
656     edge =  TopoDS::Edge(shapes((nbSects-1)*nbEdges+i));
657     TopExp::Vertices(edge,v2f,v2l);
658     if (edge.Orientation() == TopAbs_REVERSED)
659       TopExp::Vertices(edge,v2l,v2f);
660
661     // make the face
662     B.MakeFace(face, surface, Precision::Confusion());
663
664     // make the wire
665     B.MakeWire(W);
666
667     // make the missing edges
668     Standard_Real f1, f2, l1, l2;
669     surface->Bounds(f1,l1,f2,l2);
670
671     // --- edge 1
672     if ( w1Point ) {
673       // copy the degenerated edge
674       TopoDS_Shape aLocalShape = shapes(1).EmptyCopied();
675       edge1 =  TopoDS::Edge(aLocalShape);
676       //      edge1 =  TopoDS::Edge(shapes(1).EmptyCopied());
677       edge1.Orientation(TopAbs_FORWARD);
678     }
679     else {
680       B.MakeEdge(edge1, surface->VIso(f2), Precision::Confusion());
681     }
682     v1f.Orientation(TopAbs_FORWARD);
683     B.Add(edge1, v1f);
684     v1l.Orientation(TopAbs_REVERSED);
685     B.Add(edge1, v1l);
686     B.Range(edge1, f1, l1);
687     // processing of looping sections
688     // store edges of the 1st section
689     if (vClosed)
690       vcouture(i) = edge1;
691
692
693     // --- edge 2
694     if (vClosed)
695       edge2 = TopoDS::Edge(vcouture(i));
696     else {
697       if ( w2Point ) {
698         // copy of the degenerated edge
699         TopoDS_Shape aLocalShape = shapes(nbSects*nbEdges).EmptyCopied();
700         edge2 =  TopoDS::Edge(aLocalShape);
701         //      edge2 =  TopoDS::Edge(shapes(nbSects*nbEdges).EmptyCopied());
702         edge2.Orientation(TopAbs_FORWARD);
703       }
704       else {
705         B.MakeEdge(edge2, surface->VIso(l2), Precision::Confusion());
706       }
707       v2f.Orientation(TopAbs_FORWARD);
708       B.Add(edge2, v2f);
709       v2l.Orientation(TopAbs_REVERSED);
710       B.Add(edge2, v2l);
711       B.Range(edge2, f1, l1);
712     }
713     edge2.Reverse();
714
715
716     // --- edge 3
717     if (i==1) {
718       B.MakeEdge(edge3, surface->UIso(f1), Precision::Confusion());
719       v1f.Orientation(TopAbs_FORWARD);
720       B.Add(edge3, v1f);
721       v2f.Orientation(TopAbs_REVERSED);
722       B.Add(edge3, v2f);
723       B.Range(edge3, f2, l2);
724       if (uClosed) {
725         couture = edge3;
726       }
727     }
728     else {
729       edge3 = edge4;
730     }
731     edge3.Reverse();
732
733     // --- edge 4
734     if ( uClosed && i==nbEdges) {
735       edge4 = couture;
736     }
737     else {
738       B.MakeEdge(edge4, surface->UIso(l1), Precision::Confusion());
739       v1l.Orientation(TopAbs_FORWARD);
740       B.Add(edge4, v1l);
741       v2l.Orientation(TopAbs_REVERSED);
742       B.Add(edge4, v2l);
743       B.Range(edge4, f2, l2);
744     }
745
746     B.Add(W,edge1);
747     B.Add(W,edge4);
748     B.Add(W,edge2);
749     B.Add(W,edge3);
750
751     // set PCurve
752     if (vClosed) {
753       B.UpdateEdge(edge1,
754         new Geom2d_Line(gp_Pnt2d(0,f2),gp_Dir2d(1,0)),
755         new Geom2d_Line(gp_Pnt2d(0,l2),gp_Dir2d(1,0)),face,
756         Precision::Confusion());
757       B.Range(edge1,face,f1,l1);
758     }
759     else {
760       B.UpdateEdge(edge1,new Geom2d_Line(gp_Pnt2d(0,f2),gp_Dir2d(1,0)),face,
761         Precision::Confusion());
762       B.Range(edge1,face,f1,l1);
763       B.UpdateEdge(edge2,new Geom2d_Line(gp_Pnt2d(0,l2),gp_Dir2d(1,0)),face,
764         Precision::Confusion());
765       B.Range(edge2,face,f1,l1);
766     }
767
768     if ( uClosed && nbEdges ==1 )  {
769       B.UpdateEdge(edge3,
770         new Geom2d_Line(gp_Pnt2d(l1,0),gp_Dir2d(0,1)),
771         new Geom2d_Line(gp_Pnt2d(f1,0),gp_Dir2d(0,1)),face,
772         Precision::Confusion());
773       B.Range(edge3,face,f2,l2);
774
775     }
776     else {
777       B.UpdateEdge(edge3,new Geom2d_Line(gp_Pnt2d(f1,0),gp_Dir2d(0,1)),face,
778         Precision::Confusion());
779       B.Range(edge3,face,f2,l2);
780       B.UpdateEdge(edge4,new Geom2d_Line(gp_Pnt2d(l1,0),gp_Dir2d(0,1)),face,
781         Precision::Confusion());
782       B.Range(edge4,face,f2,l2);
783     }
784     B.Add(face,W);
785     B.Add(shell, face);
786
787     // complete newW1 newW2
788     TopoDS_Edge edge12 = edge1;
789     TopoDS_Edge edge22 = edge2;
790     edge12.Reverse();
791     edge22.Reverse();
792     BW1.Add(newW1, edge12);
793     BW2.Add(newW2, edge22);
794
795     // history
796     myGenerated.Bind(firstEdge, face);
797   }
798
799   if (uClosed && w1Point && w2Point)
800     shell.Closed(Standard_True);
801
802   if (myIsSolid) {
803
804     if (vClosed) {
805
806       TopoDS_Solid solid;
807       B.MakeSolid(solid); 
808       B.Add(solid, shell);
809
810       // verify the orientation the solid
811       BRepClass3d_SolidClassifier clas3d(solid);
812       clas3d.PerformInfinitePoint(Precision::Confusion());
813       if (clas3d.State() == TopAbs_IN) {
814         B.MakeSolid(solid); 
815         TopoDS_Shape aLocalShape = shell.Reversed();
816         B.Add(solid, TopoDS::Shell(aLocalShape));
817         //      B.Add(solid, TopoDS::Shell(shell.Reversed()));
818       }
819       myShape = solid;
820
821     }
822
823     else {
824       myShape = MakeSolid(shell, newW1, newW2, myPres3d, myFirst, myLast);
825     }
826
827     Done();
828   }
829
830   else {
831     myShape = shell;
832     Done();
833   }
834
835   TopExp_Explorer ex(myShape,TopAbs_EDGE);
836   while (ex.More()) {
837     const TopoDS_Edge& CurE = TopoDS::Edge(ex.Current());
838     B.SameRange(CurE, Standard_False);
839     B.SameParameter(CurE, Standard_False);
840     Standard_Real tol = BRep_Tool::Tolerance(CurE);
841     BRepLib::SameParameter(CurE,tol);
842     ex.Next();
843   }
844 }
845
846 //=======================================================================
847 //function : EdgeToBSpline
848 //purpose  : auxiliary -- get curve from edge and convert it to bspline
849 //           parameterized from 0 to 1
850 //=======================================================================
851
852 // NOTE: this code duplicates the same function in BRepFill_NSections.cxx
853 static Handle(Geom_BSplineCurve) EdgeToBSpline (const TopoDS_Edge& theEdge)
854 {
855   Handle(Geom_BSplineCurve) aBSCurve;
856   if (BRep_Tool::Degenerated(theEdge)) {
857     // degenerated edge : construction of a point curve
858     TColStd_Array1OfReal aKnots (1,2);
859     aKnots(1) = 0.;
860     aKnots(2) = 1.;
861
862     TColStd_Array1OfInteger aMults (1,2);
863     aMults(1) = 2;
864     aMults(2) = 2;
865
866     TColgp_Array1OfPnt aPoles(1,2);
867     TopoDS_Vertex vf, vl;
868     TopExp::Vertices(theEdge,vl,vf);
869     aPoles(1) = BRep_Tool::Pnt(vf);
870     aPoles(2) = BRep_Tool::Pnt(vl);
871
872     aBSCurve = new Geom_BSplineCurve (aPoles, aKnots, aMults, 1);
873   }
874   else
875   {
876     // get the curve of the edge
877     TopLoc_Location aLoc;
878     Standard_Real aFirst, aLast;
879     Handle(Geom_Curve) aCurve = BRep_Tool::Curve (theEdge, aLoc, aFirst, aLast);
880     if (aCurve.IsNull())
881       throw Standard_NullObject("Null 3D curve in edge");
882
883     // convert its part used by edge to bspline; note that if edge curve is bspline,
884     // conversion made via trimmed curve is still needed -- it will copy it, segment 
885     // as appropriate, and remove periodicity if it is periodic (deadly for approximator)
886     Handle(Geom_TrimmedCurve) aTrimCurve = new Geom_TrimmedCurve (aCurve, aFirst, aLast);
887
888     // special treatment of conic curve
889     if (aTrimCurve->BasisCurve()->IsKind(STANDARD_TYPE(Geom_Conic)))
890     {
891       const Handle(Geom_Curve)& aCurveTrimmed = aTrimCurve; // to avoid ambiguity
892       GeomConvert_ApproxCurve anAppr (aCurveTrimmed, Precision::Confusion(), GeomAbs_C1, 16, 14);
893       if (anAppr.HasResult())
894         aBSCurve = anAppr.Curve();
895     }
896
897     // general case
898     if (aBSCurve.IsNull())
899       aBSCurve = GeomConvert::CurveToBSplineCurve (aTrimCurve);
900
901     // apply transformation if needed
902     if (! aLoc.IsIdentity())
903       aBSCurve->Transform (aLoc.Transformation());
904
905     // reparameterize to [0,1]
906     TColStd_Array1OfReal aKnots (1, aBSCurve->NbKnots());
907     aBSCurve->Knots (aKnots);
908     BSplCLib::Reparametrize (0., 1., aKnots);
909     aBSCurve->SetKnots (aKnots);
910   }
911
912   // reverse curve if edge is reversed
913   if (theEdge.Orientation() == TopAbs_REVERSED)
914     aBSCurve->Reverse();
915
916   return aBSCurve;
917 }
918
919 //=======================================================================
920 //function : TotalSurf
921 //purpose  : 
922 //=======================================================================
923
924 Handle(Geom_BSplineSurface) BRepOffsetAPI_ThruSections::
925                           TotalSurf(const TopTools_Array1OfShape& shapes,
926                                     const Standard_Integer NbSects,
927                                     const Standard_Integer NbEdges,
928                                     const Standard_Boolean w1Point,
929                                     const Standard_Boolean w2Point,
930                                     const Standard_Boolean vClosed) const
931 {
932   Standard_Integer i,j,jdeb=1,jfin=NbSects;
933   TopoDS_Vertex vf,vl;
934
935   GeomFill_SectionGenerator section;
936   Handle(Geom_BSplineSurface) surface;
937   Handle(Geom_BSplineCurve) BS, BS1;
938   Handle(Geom_TrimmedCurve) curvTrim;
939
940   if (w1Point) {
941     jdeb++;
942     TopoDS_Edge edge =  TopoDS::Edge(shapes(1));
943     TopExp::Vertices(edge,vl,vf);
944     TColgp_Array1OfPnt Extremities(1,2);
945     Extremities(1) = BRep_Tool::Pnt(vf);
946     Extremities(2) = BRep_Tool::Pnt(vl);
947     TColStd_Array1OfReal Bounds(1,2);
948     Bounds(1) = 0.;
949     Bounds(2) = 1.;
950     TColStd_Array1OfInteger Mult(1,2);
951     Mult(1) = 2;
952     Mult(2) = 2;
953     Handle(Geom_BSplineCurve) BSPoint
954       = new Geom_BSplineCurve(Extremities,Bounds,Mult,1);
955     section.AddCurve(BSPoint);
956   }
957
958   if (w2Point) {
959     jfin--;
960   }
961
962   for (j=jdeb; j<=jfin; j++) {
963
964     // case of looping sections 
965     if (j==jfin && vClosed) {
966       section.AddCurve(BS1);
967     }
968
969     else {
970       // read the first edge to initialise CompBS;
971       TopoDS_Edge aPrevEdge = TopoDS::Edge (shapes((j-1)*NbEdges+1));
972       Handle(Geom_BSplineCurve) curvBS = EdgeToBSpline (aPrevEdge);
973
974       // initialization
975       GeomConvert_CompCurveToBSplineCurve CompBS(curvBS);
976
977       for (i=2; i<=NbEdges; i++) {  
978         // read the edge
979         TopoDS_Edge aNextEdge = TopoDS::Edge (shapes((j-1)*NbEdges+i));
980         Standard_Real aTolV = Precision::Confusion();  
981         TopExp::Vertices(aNextEdge,vf,vl);
982         aTolV = Max(aTolV, BRep_Tool::Tolerance(vf));
983         aTolV = Max(aTolV, BRep_Tool::Tolerance(vl));
984         aTolV = Min(aTolV, 1.e-3);
985         curvBS = EdgeToBSpline (aNextEdge);
986
987         // concatenation
988         CompBS.Add(curvBS, aTolV, Standard_True, Standard_False, 1);
989       }
990
991       // return the final section
992       BS = CompBS.BSplineCurve();
993       section.AddCurve(BS);
994
995       // case of looping sections
996       if (j==jdeb && vClosed) {
997         BS1 = BS;
998       }
999
1000     }
1001   }
1002
1003   if (w2Point) {
1004     TopoDS_Edge edge =  TopoDS::Edge(shapes(NbSects*NbEdges));
1005     TopExp::Vertices(edge,vl,vf);
1006     TColgp_Array1OfPnt Extremities(1,2);
1007     Extremities(1) = BRep_Tool::Pnt(vf);
1008     Extremities(2) = BRep_Tool::Pnt(vl);
1009     TColStd_Array1OfReal Bounds(1,2);
1010     Bounds(1) = 0.;
1011     Bounds(2) = 1.;
1012     TColStd_Array1OfInteger Mult(1,2);
1013     Mult(1) = 2;
1014     Mult(2) = 2;
1015     Handle(Geom_BSplineCurve) BSPoint
1016       = new Geom_BSplineCurve(Extremities,Bounds,Mult,1);
1017     section.AddCurve(BSPoint);
1018   }
1019
1020   section.Perform(Precision::PConfusion());
1021   Handle(GeomFill_Line) line = new GeomFill_Line(NbSects);
1022
1023   Standard_Integer nbIt = 3;
1024   if(myPres3d <= 1.e-3) nbIt = 0;
1025
1026   Standard_Integer degmin = 2, degmax = Max(myDegMax, degmin);
1027   Standard_Boolean SpApprox = Standard_True;
1028
1029   GeomFill_AppSurf anApprox(degmin, degmax, myPres3d, myPres3d, nbIt);
1030   anApprox.SetContinuity(myContinuity);
1031
1032   if(myUseSmoothing) {
1033     anApprox.SetCriteriumWeight(myCritWeights[0], myCritWeights[1], myCritWeights[2]);
1034     anApprox.PerformSmoothing(line, section);
1035   } 
1036   else {
1037     anApprox.SetParType(myParamType);
1038     anApprox.Perform(line, section, SpApprox);
1039   }
1040
1041   if(anApprox.IsDone()) {
1042     surface = 
1043       new Geom_BSplineSurface(anApprox.SurfPoles(), anApprox.SurfWeights(),
1044       anApprox.SurfUKnots(), anApprox.SurfVKnots(),
1045       anApprox.SurfUMults(), anApprox.SurfVMults(),
1046       anApprox.UDegree(), anApprox.VDegree());
1047   }
1048
1049   return surface;
1050
1051 }
1052
1053 //=======================================================================
1054 //function : FirstShape
1055 //purpose  : 
1056 //=======================================================================
1057
1058 const TopoDS_Shape& BRepOffsetAPI_ThruSections::FirstShape() const
1059 {
1060   return myFirst;
1061 }
1062
1063 //=======================================================================
1064 //function : LastShape
1065 //purpose  : 
1066 //=======================================================================
1067
1068 const TopoDS_Shape& BRepOffsetAPI_ThruSections::LastShape() const
1069 {
1070   return myLast;
1071 }
1072
1073 //=======================================================================
1074 //function : GeneratedFace
1075 //purpose  : 
1076 //=======================================================================
1077
1078 TopoDS_Shape BRepOffsetAPI_ThruSections::GeneratedFace(const TopoDS_Shape& edge) const
1079 {
1080   TopoDS_Shape bid;
1081   if (myGenerated.IsBound(edge)) {
1082     return myGenerated(edge);
1083   }
1084   else {
1085     return bid;
1086   }
1087 }
1088
1089
1090 //=======================================================================
1091 //function : CriteriumWeight
1092 //purpose  : returns the Weights associated  to the criterium used in
1093 //           the  optimization.
1094 //=======================================================================
1095 //
1096 void BRepOffsetAPI_ThruSections::CriteriumWeight(Standard_Real& W1, Standard_Real& W2, Standard_Real& W3) const 
1097 {
1098   W1 = myCritWeights[0];
1099   W2 = myCritWeights[1];
1100   W3 = myCritWeights[2];
1101 }
1102 //=======================================================================
1103 //function : SetCriteriumWeight
1104 //purpose  : 
1105 //=======================================================================
1106
1107 void BRepOffsetAPI_ThruSections::SetCriteriumWeight(const Standard_Real W1, const Standard_Real W2, const Standard_Real W3)
1108 {
1109   if (W1 < 0 || W2 < 0 || W3 < 0 ) throw Standard_DomainError();
1110   myCritWeights[0] = W1;
1111   myCritWeights[1] = W2;
1112   myCritWeights[2] = W3;
1113 }
1114 //=======================================================================
1115 //function : SetContinuity
1116 //purpose  : 
1117 //=======================================================================
1118
1119 void BRepOffsetAPI_ThruSections::SetContinuity (const GeomAbs_Shape TheCont)
1120 {
1121   myContinuity = TheCont;
1122 }
1123
1124 //=======================================================================
1125 //function : Continuity
1126 //purpose  : 
1127 //=======================================================================
1128
1129 GeomAbs_Shape BRepOffsetAPI_ThruSections::Continuity () const
1130 {
1131   return myContinuity;
1132 }
1133
1134 //=======================================================================
1135 //function : SetParType
1136 //purpose  : 
1137 //=======================================================================
1138
1139 void BRepOffsetAPI_ThruSections::SetParType (const Approx_ParametrizationType ParType)
1140 {
1141   myParamType = ParType;
1142 }
1143
1144 //=======================================================================
1145 //function : ParType
1146 //purpose  : 
1147 //=======================================================================
1148
1149 Approx_ParametrizationType BRepOffsetAPI_ThruSections::ParType () const
1150 {
1151   return myParamType;
1152 }
1153
1154 //=======================================================================
1155 //function : SetMaxDegree
1156 //purpose  : 
1157 //=======================================================================
1158
1159 void BRepOffsetAPI_ThruSections:: SetMaxDegree(const Standard_Integer MaxDeg)
1160 {
1161   myDegMax = MaxDeg;
1162 }
1163
1164 //=======================================================================
1165 //function : MaxDegree
1166 //purpose  : 
1167 //=======================================================================
1168
1169 Standard_Integer  BRepOffsetAPI_ThruSections::MaxDegree () const
1170 {
1171   return myDegMax;
1172 }
1173
1174 //=======================================================================
1175 //function : SetSmoothing
1176 //purpose  : 
1177 //=======================================================================
1178
1179 void BRepOffsetAPI_ThruSections::SetSmoothing(const Standard_Boolean UseVar)
1180 {
1181   myUseSmoothing = UseVar;
1182 }
1183
1184 //=======================================================================
1185 //function : UseSmoothing
1186 //purpose  : 
1187 //=======================================================================
1188
1189 Standard_Boolean BRepOffsetAPI_ThruSections::UseSmoothing () const
1190 {
1191   return myUseSmoothing;
1192 }
1193
1194
1195
1196
1197