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