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