2ecc36d40dafba9747dcd59264e8edfb1141bf9b
[occt.git] / src / BRepBuilderAPI / BRepBuilderAPI_FastSewing.cxx
1 // Created on: 2015-04-24
2 // Created by: NIKOLAI BUKHALOV
3 // Copyright (c) 2015 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <BRepBuilderAPI_FastSewing.hxx>
17
18 #include <BRepTools_Quilt.hxx>
19 #include <Bnd_Box.hxx>
20
21 #include <Geom2d_Line.hxx>
22 #include <Geom2d_TrimmedCurve.hxx>
23 #include <Geom_Curve.hxx>
24 #include <Geom_RectangularTrimmedSurface.hxx>
25 #include <Geom_Surface.hxx>
26
27 #include <Precision.hxx>
28
29 #include <Standard_NullObject.hxx>
30
31 #include <TopExp_Explorer.hxx>
32 #include <TopoDS.hxx>
33 #include <TopTools_MapOfShape.hxx>
34
35
36 IMPLEMENT_STANDARD_RTTIEXT(BRepBuilderAPI_FastSewing,Standard_Transient)
37
38 //=======================================================================
39 //function : IntersetctionOfSets
40 //purpose  : Returns minimal value of intersection result
41 //=======================================================================
42 static Standard_Integer
43       IntersectionOfSets( const NCollection_List<Standard_Integer>& theSet1,
44                           const NCollection_List<Standard_Integer>& theSet2)
45 {
46   const Standard_Integer anIntMax = IntegerLast();
47   Standard_Integer aRetVal = anIntMax;
48   for(NCollection_List<Standard_Integer>::Iterator
49                             anIt1 = theSet1.begin().Iterator();
50                             anIt1.More(); anIt1.Next())
51   {
52     const Standard_Integer aVal1 = anIt1.Value();
53     for(NCollection_List<Standard_Integer>::Iterator
54                             anIt2 = theSet2.begin().Iterator();
55                             anIt2.More(); anIt2.Next())
56     {
57       const Standard_Integer aVal2 = anIt2.Value();
58       if(aVal1 == aVal2)
59       {
60         //theIntersectionResult.Append(aVal1);
61         if(aVal1 < aRetVal)
62           aRetVal = aVal1;
63       }
64     }
65   }
66
67   if(aRetVal == anIntMax)
68     return -1;
69
70   return aRetVal;
71 }
72
73 //=======================================================================
74 //function : Get2DCurve
75 //purpose  : 
76 //=======================================================================
77 static Handle(Geom2d_Curve)
78             Get2DCurve( const Standard_Integer theIndex,
79                         const Standard_Real theUfirst,
80                         const Standard_Real theUlast,
81                         const Standard_Real theVfirst,
82                         const Standard_Real theVlast,
83                         const Standard_Boolean theIsReverse = Standard_False)
84 {
85   if((theIndex < 0) || (theIndex > 3))
86     throw Standard_OutOfRange("BRepBuilderAPI_FastSewing.cxx, Get2DCurve(): OUT of Range");
87   
88   Handle(Geom2d_Curve) a2dCurv;
89
90   if(!theIsReverse)
91   {
92     switch(theIndex)
93     {
94     case 0:
95       a2dCurv = 
96             new Geom2d_TrimmedCurve(new Geom2d_Line(
97                                           gp_Pnt2d(0.0, theVfirst), gp_Dir2d(1.0,0.0)),
98                                           theUfirst, theUlast);
99       break;
100     case 1:
101       a2dCurv = 
102             new Geom2d_TrimmedCurve(new Geom2d_Line(
103                                           gp_Pnt2d(theUlast, 0.0), gp_Dir2d(0.0,1.0)),
104                                           theVfirst, theVlast);
105       break;
106     case 2:
107       a2dCurv = 
108             new Geom2d_TrimmedCurve(new Geom2d_Line(
109                                           gp_Pnt2d(0.0, theVlast), gp_Dir2d(1.0,0.0)),
110                                           theUfirst, theUlast);
111       break;
112     case 3:
113       a2dCurv =
114             new Geom2d_TrimmedCurve(new Geom2d_Line(
115                                           gp_Pnt2d(theUfirst, 0.0), gp_Dir2d(0.0,1.0)),
116                                           theVfirst, theVlast);
117       break;
118     default:
119       break;
120     }  
121   }
122   else
123   {
124     switch(theIndex)
125     {
126     case 0:
127       a2dCurv = 
128             new Geom2d_TrimmedCurve(new Geom2d_Line(
129                                           gp_Pnt2d(theUfirst+theUlast, theVfirst),
130                                                           gp_Dir2d(-1.0,0.0)),
131                                           theUfirst, theUlast);
132       break;
133     case 1:
134       a2dCurv = 
135             new Geom2d_TrimmedCurve(new Geom2d_Line(
136                                           gp_Pnt2d(theUlast, theVfirst+theVlast),
137                                                           gp_Dir2d(0.0,-1.0)),
138                                           theVfirst, theVlast);
139       break;
140     case 2:
141       a2dCurv = 
142             new Geom2d_TrimmedCurve(new Geom2d_Line(
143                                           gp_Pnt2d(theUfirst+theUlast, theVlast), 
144                                                           gp_Dir2d(-1.0,0.0)),
145                                           theUfirst, theUlast);
146       break;
147     case 3:
148       a2dCurv = 
149             new Geom2d_TrimmedCurve(new Geom2d_Line(
150                                           gp_Pnt2d(theUfirst, theVfirst+theVlast),
151                                                           gp_Dir2d(0.0,-1.0)),
152                                           theVfirst, theVlast);
153       break;
154     default:
155       break;
156     }  
157   }
158
159   return a2dCurv;
160 }
161
162 //=======================================================================
163 //function : Constructor
164 //purpose  : 
165 //=======================================================================
166 BRepBuilderAPI_FastSewing::
167         BRepBuilderAPI_FastSewing( const Standard_Real theTol):
168   myTolerance(theTol),
169   myStatusList(0)
170 {
171 }
172
173 //=======================================================================
174 //function : Add
175 //purpose  : 
176 //=======================================================================
177 Standard_Boolean BRepBuilderAPI_FastSewing::Add(const TopoDS_Shape& theShape)
178 {
179   Standard_Boolean aResult = Standard_False;
180   if(theShape.IsNull())
181   {
182     SetStatus(FS_EmptyInput);
183     return aResult;
184   }
185
186   TopTools_MapOfShape aMS;
187   //aMS.Add(theShape);
188   TopExp_Explorer aFExp(theShape,TopAbs_FACE);
189   for (; aFExp.More(); aFExp.Next())
190   {
191     const TopoDS_Face& aFace = TopoDS::Face(aFExp.Current());
192     if(aMS.Add(aFace))
193     {
194       Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace);
195       if(aSurf.IsNull())
196       {
197         SetStatus(FS_FaceWithNullSurface);
198         continue;
199       }
200
201       if(aSurf->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface)))
202       {
203         SetStatus(FS_NotNaturalBoundsFace);
204         continue;
205       }
206
207       Standard_Real aUf = 0.0, aUl = 0.0, aVf = 0.0, aVl = 0.0;
208       aSurf->Bounds(aUf, aUl, aVf, aVl);
209
210       if(Precision::IsInfinite(aUf) || Precision::IsInfinite(aUl) ||
211          Precision::IsInfinite(aVf) || Precision::IsInfinite(aVl))
212       {
213         SetStatus(FS_InfiniteSurface);
214         continue;
215       }
216
217       FS_Face aFFace;
218       aFFace.mySrcFace = aFace;
219       aFFace.myID = myFaceVec.Length();//because start index is 0
220       myFaceVec.Append(aFFace);
221       aResult = Standard_True;
222     }
223   }
224
225   return aResult;
226 }
227
228 //=======================================================================
229 //function : Add
230 //purpose  : 
231 //=======================================================================
232 Standard_Boolean BRepBuilderAPI_FastSewing::Add(const Handle(Geom_Surface)& theSurface)
233 {
234   if(theSurface.IsNull())
235   {
236     SetStatus(FS_FaceWithNullSurface);
237     return Standard_False;
238   }
239
240   if(theSurface->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface)))
241   {
242     SetStatus(FS_NotNaturalBoundsFace);
243     return Standard_False;
244   }
245
246   Standard_Real aUf = 0.0, aUl = 0.0, aVf = 0.0, aVl = 0.0;
247   theSurface->Bounds(aUf, aUl, aVf, aVl);
248
249   if(Precision::IsInfinite(aUf) || Precision::IsInfinite(aUl) ||
250     Precision::IsInfinite(aVf) || Precision::IsInfinite(aVl))
251   {
252     SetStatus(FS_InfiniteSurface);
253     return Standard_False;
254   }
255
256   FS_Face aFace;
257
258   BRep_Builder aBuilder;
259   aBuilder.MakeFace(aFace.mySrcFace);
260   aBuilder.MakeFace(aFace.mySrcFace, theSurface, myTolerance);
261   aBuilder.NaturalRestriction(aFace.mySrcFace, Standard_True);
262
263   aFace.myID = myFaceVec.Length();//because start index is 0
264   myFaceVec.Append(aFace);
265
266   return Standard_True;
267 }
268
269
270 //=======================================================================
271 //function : Perform
272 //purpose  : 
273 //=======================================================================
274 void BRepBuilderAPI_FastSewing::Perform(void)
275 {
276   if(myFaceVec.IsEmpty())
277   {
278     SetStatus(FS_EmptyInput);
279     return;
280   }
281
282   try
283   {
284     {
285       // create vertices having unique coordinates
286       Standard_Real aRange = Compute3DRange();
287       Handle(NCollection_IncAllocator) anAlloc = new NCollection_IncAllocator;
288       NCollection_CellFilter<NodeInspector> 
289         aCells(Max(myTolerance, aRange/IntegerLast()), anAlloc);
290
291       for(Standard_Integer i = myFaceVec.Lower(); i <= myFaceVec.Upper(); i++)
292       {
293         FindVertexes(i, aCells);
294       }
295     }
296
297     for(Standard_Integer i = myFaceVec.Lower(); i <= myFaceVec.Upper(); i++)
298     {
299       FindEdges(i);
300     }
301
302     //Create topological structures
303
304     for(Standard_Integer i = myVertexVec.Lower(); i <= myVertexVec.Upper(); i++)
305     {
306       myVertexVec.ChangeValue(i).CreateTopologicalVertex(myTolerance);
307     }
308
309     //Edges
310     for(Standard_Integer i = myEdgeVec.Lower(); i <= myEdgeVec.Upper(); i++)
311     {
312       myEdgeVec.ChangeValue(i).CreateTopologicalEdge(myVertexVec, myFaceVec, myTolerance);
313     }
314
315     //Shell
316     BRepTools_Quilt aQuilt;
317
318     //Faces
319     for(Standard_Integer i = myFaceVec.Lower(); i <= myFaceVec.Upper(); i++)
320     {
321       FS_Face& aFace = myFaceVec.ChangeValue(i);
322       aFace.CreateTopologicalWire(myEdgeVec, myTolerance);
323       aFace.CreateTopologicalFace();
324       aQuilt.Add(aFace.myRetFace);
325     }
326
327     myResShape = aQuilt.Shells();
328   }
329   catch(Standard_Failure)
330   {
331     SetStatus(FS_Exception);
332 #ifdef OCCT_DEBUG
333     //Standard_Failure::Caught()->Print(cout);
334 #endif
335     return;
336   }
337 }
338
339 //=======================================================================
340 //function : UpdateEdgeInfo
341 //purpose  : 
342 //=======================================================================
343 void BRepBuilderAPI_FastSewing::UpdateEdgeInfo( const Standard_Integer theIDPrevVertex,
344                                                 const Standard_Integer theIDCurrVertex,
345                                                 const Standard_Integer theFaceID,
346                                                 const Standard_Integer theIDCurvOnFace)
347 {
348   //Indeed, two vertices combine into one edge only.
349   const Standard_Integer anEdgeID = 
350                       IntersectionOfSets(myVertexVec.Value(theIDPrevVertex).myEdges,
351                                           myVertexVec.Value(theIDCurrVertex).myEdges);
352
353   //For DEBUG mode only
354   Standard_ProgramError_Raise_if(anEdgeID < 0, 
355         "BRepBuilderAPI_FastSewing::UpdateEdgeInfo: Update not existing edge.");
356
357   FS_Edge& anEdge = myEdgeVec.ChangeValue(anEdgeID);
358   anEdge.myFaces.Append(theFaceID);
359   FS_Face& aFace = myFaceVec.ChangeValue(theFaceID);
360   aFace.SetEdge(theIDCurvOnFace, anEdge.myID);
361 }
362
363 //=======================================================================
364 //function : CreateNewEdge
365 //purpose  : Creates FS_Edge
366 //=======================================================================
367 void BRepBuilderAPI_FastSewing::CreateNewEdge(const Standard_Integer theIDPrevVertex,
368                                               const Standard_Integer theIDCurrVertex,
369                                               const Standard_Integer theFaceID,
370                                               const Standard_Integer theIDCurvOnFace)
371 {
372   FS_Edge anEdge(theIDPrevVertex, theIDCurrVertex);
373   anEdge.myID = myEdgeVec.Length(); //because start index is 0
374
375
376   anEdge.myFaces.Append(theFaceID);
377   FS_Face& aFace = myFaceVec.ChangeValue(theFaceID);
378   aFace.SetEdge(theIDCurvOnFace, anEdge.myID);
379
380   myVertexVec.ChangeValue(theIDPrevVertex).myEdges.Append(anEdge.myID);
381
382   if(theIDPrevVertex == theIDCurrVertex)
383   {//the Edge is degenerated
384     SetStatus(FS_Degenerated);
385   }
386   else
387   {
388     myVertexVec.ChangeValue(theIDCurrVertex).myEdges.Append(anEdge.myID);
389   }
390
391   myEdgeVec.Append(anEdge);
392 }
393
394 //=======================================================================
395 //function : FindVertexes
396 //purpose  : 
397 //=======================================================================
398 void BRepBuilderAPI_FastSewing::
399             FindVertexes(const Standard_Integer theSurfID,
400             NCollection_CellFilter<NodeInspector>& theCells)
401 {
402   const Standard_Integer aNbPoints = 4;
403   FS_Face& aFace = myFaceVec.ChangeValue(theSurfID);
404   const Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace.mySrcFace);
405   Standard_Real aUf = 0.0, aUl = 0.0, aVf = 0.0, aVl = 0.0;
406   aSurf->Bounds(aUf, aUl, aVf, aVl);
407
408   const gp_Pnt aPnts[aNbPoints] = { aSurf->Value(aUf, aVf),
409                                     aSurf->Value(aUl, aVf),
410                                     aSurf->Value(aUl, aVl),
411                                     aSurf->Value(aUf, aVl)};
412
413   for(Standard_Integer i = 0; i < aNbPoints; i++)
414   {
415     FS_Vertex aVert;
416
417     NodeInspector anInspector(myVertexVec, aPnts[i], myTolerance);
418     Bnd_Box aBox;
419     aBox.Add(aPnts[i]);
420     aBox.Enlarge(myTolerance);
421
422     theCells.Inspect(aBox.CornerMin().XYZ(), aBox.CornerMax().XYZ(), anInspector);
423     NodeInspector::Target aResID = anInspector.GetResult();
424
425     if(aResID < 0)
426     {//Add new Vertex
427       aVert.myID = myVertexVec.Length(); //because start index is 0
428       aVert.myPnt = aPnts[i];
429       aVert.myFaces.Append(theSurfID);
430       myVertexVec.Append(aVert);
431       aFace.SetVertex(i, aVert.myID);
432
433       theCells.Add(aVert.myID, aBox.CornerMin().XYZ(), aBox.CornerMax().XYZ());
434     }
435     else
436     {//Change existing vertex
437       aFace.SetVertex(i, aResID);
438       myVertexVec.ChangeValue(aResID).myFaces.Append(theSurfID);
439     }
440   }
441 }
442
443 //=======================================================================
444 //function : FindEdges
445 //purpose  : 
446 //=======================================================================
447 void BRepBuilderAPI_FastSewing::FindEdges(const Standard_Integer theSurfID)
448 {
449   const Standard_Integer aNbPoints = 4;
450   FS_Face& aFace = myFaceVec.ChangeValue(theSurfID);
451
452   const Standard_Integer aFirstInd[aNbPoints] = {0, 1, 3, 0};
453   const Standard_Integer aLastInd[aNbPoints] = {1, 2, 2, 3};
454
455   for(Standard_Integer i = 0; i < aNbPoints; i++)
456   {
457     const Standard_Integer  aFirstVertIndex = aFirstInd[i],
458                             aLastVertIndex = aLastInd[i];
459     const Standard_Integer  aFirstVertID = aFace.myVertices[aFirstVertIndex],
460                             aLastVertID  = aFace.myVertices[aLastVertIndex];
461
462     if(aFirstVertID == aLastVertID)
463     {//Edge is degenerated.
464       CreateNewEdge(aFirstVertID, aLastVertID, theSurfID, i);
465       continue;
466     }
467
468     //Must be minimal element from list
469     const Standard_Integer anIntRes = 
470                     IntersectionOfSets(myVertexVec.Value(aFirstVertID).myFaces,
471                     myVertexVec.Value(aLastVertID).myFaces);
472     
473     if((anIntRes < 0) || (anIntRes >= theSurfID))
474     {
475       CreateNewEdge(aFirstVertID, aLastVertID, theSurfID, i);
476     }
477     else
478     {//if(theSurfID > anIntRes) => The edge has been processed earlier
479       UpdateEdgeInfo(aFirstVertID, aLastVertID, theSurfID, i);
480     }
481   }
482 }
483
484 //=======================================================================
485 //function : GetStatuses
486 //purpose  : 
487 //=======================================================================
488 BRepBuilderAPI_FastSewing::FS_VARStatuses 
489       BRepBuilderAPI_FastSewing::GetStatuses(Standard_OStream* const theOS)
490 {
491   if(!theOS)
492     return myStatusList;
493
494   if(!myStatusList)
495   {
496     *theOS << "Fast Sewing OK!\n";
497     return myStatusList;
498   }
499
500   //Number of bits
501   const Standard_Integer aNumMax = 8*sizeof(myStatusList);
502   FS_Statuses anIDS = static_cast<FS_Statuses>(0x0001);
503   for(Standard_Integer i = 1; i <= aNumMax; i++,
504                   anIDS = static_cast<FS_Statuses>(anIDS << 1))
505   {
506     if((anIDS & myStatusList) == 0)
507       continue;
508
509     switch(anIDS)
510     {
511     case FS_Degenerated:
512       *theOS << "Degenerated case. Try to reduce tolerance.\n";
513       break;
514     case FS_FindVertexError:
515       *theOS << "Error while creating list of vertices.\n";
516       break;
517     case FS_FindEdgeError:
518       *theOS << "Error while creating list of edges.\n";
519       break;
520     case FS_Exception:
521       *theOS << "Exception during the operation.\n";
522       break;
523     case FS_FaceWithNullSurface:
524       *theOS << "Source face has null surface.\n";
525       break;
526     case FS_NotNaturalBoundsFace:
527       *theOS << "Source face has trimmed surface.\n";
528       break;
529     case FS_InfiniteSurface:
530       *theOS << "Source face has the surface with infinite boundaries.\n";
531       break;
532     case FS_EmptyInput:
533       *theOS << "Empty source data.\n";
534       break;
535
536
537     default:
538       return myStatusList;
539     }
540   }
541
542   return myStatusList;
543 }
544
545 //=======================================================================
546 //function : Compute3DRange
547 //purpose  : 
548 //=======================================================================
549 Standard_Real BRepBuilderAPI_FastSewing::Compute3DRange()
550 {
551   Bnd_Box aBox;
552
553   for(Standard_Integer i = myFaceVec.Lower(); i <= myFaceVec.Upper(); i++)
554   {
555     FS_Face& aFace = myFaceVec.ChangeValue(i);
556     const Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace.mySrcFace);
557     if(aSurf.IsNull())
558       continue;
559     Standard_Real aUf = 0.0, aUl = 0.0, aVf = 0.0, aVl = 0.0;
560     aSurf->Bounds(aUf, aUl, aVf, aVl);
561     
562     aBox.Add(aSurf->Value(aUf, aVf));
563     aBox.Add(aSurf->Value(aUl, aVf));
564     aBox.Add(aSurf->Value(aUl, aVl));
565     aBox.Add(aSurf->Value(aUf, aVl));
566   }
567
568   Standard_Real aXm = 0.0, aYm = 0.0, aZm = 0.0, aXM = 0.0, aYM = 0.0, aZM = 0.0;
569   aBox.Get(aXm, aYm, aZm, aXM, aYM, aZM);
570   Standard_Real aDelta = aXM - aXm;
571   aDelta = Max(aDelta, aYM - aYm);
572   aDelta = Max(aDelta, aZM - aZm);
573
574   return aDelta;
575 }
576
577 //=======================================================================
578 //function : NodeInspector constructor
579 //purpose  : 
580 //=======================================================================
581 BRepBuilderAPI_FastSewing::NodeInspector::
582                       NodeInspector(const NCollection_Vector<FS_Vertex>& theVec,
583                                     const gp_Pnt& thePnt,
584                                     const Standard_Real theTol):
585 myVecOfVertexes(theVec), myPoint(thePnt), myResID(-1)
586 {
587   mySQToler = theTol*theTol;
588 }
589
590 //=======================================================================
591 //function : ::NodeInspector::Inspect
592 //purpose  : 
593 //=======================================================================
594 NCollection_CellFilter_Action BRepBuilderAPI_FastSewing::
595                                   NodeInspector::Inspect(const Target theID)
596 {
597   const gp_Pnt& aPt = myVecOfVertexes.Value(theID).myPnt;
598   const Standard_Real aSQDist = aPt.SquareDistance(myPoint);
599   if(aSQDist < mySQToler)
600   {
601     mySQToler = aSQDist;
602     myResID = theID;
603   }
604
605   return CellFilter_Keep;
606 }
607
608 //=======================================================================
609 //function : ::FS_Edge::CreateTopologicalEdge
610 //purpose  : 
611 //=======================================================================
612 void BRepBuilderAPI_FastSewing::FS_Edge::
613           CreateTopologicalEdge(const NCollection_Vector<FS_Vertex>& theVertexVec,
614                                 const NCollection_Vector<FS_Face>& theFaceVec,
615                                 const Standard_Real theTol)
616 {
617   BRep_Builder aBuilder;
618
619   TopoDS_Vertex aV1 = theVertexVec(myVertices[0]).myTopoVert;
620   TopoDS_Vertex aV2 = theVertexVec(myVertices[1]).myTopoVert;
621
622   aV1.Orientation(TopAbs_FORWARD);
623   aV2.Orientation(TopAbs_REVERSED);
624
625   Handle(Geom_Curve) a3dCurv;
626   TopLoc_Location aLocation;
627
628   const FS_Face& aFace = theFaceVec.Value(myFaces.Value(myFaces.Lower()));
629
630   //3D-curves in 1st and 2nd faces are considered to be in same-range
631   const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(aFace.mySrcFace, aLocation);
632
633   Standard_Real aUf = 0.0, aUl = 0.0, aVf = 0.0, aVl = 0.0;
634   aSurf->Bounds(aUf, aUl, aVf, aVl);
635
636   Standard_Integer anEdgeID = -1;
637   for(Standard_Integer anInd = 0; anInd < 4; anInd++)
638   {
639     if(myID == aFace.myEdges[anInd])
640     {
641       anEdgeID = anInd;
642       break;
643     }
644   }
645
646   //For DEBUG mode only
647   Standard_ProgramError_Raise_if(anEdgeID < 0, 
648         "BRepBuilderAPI_FastSewing::FS_Edge::CreateTopologicalEdge: Single edge.");
649
650   if(IsDegenerated())
651   {
652     Handle(Geom2d_Curve) a2dCurv = Get2DCurve(anEdgeID, aUf, aUl, aVf, aVl);
653     const Standard_Real aFPar = a2dCurv->FirstParameter(),
654                         aLPar = a2dCurv->LastParameter();
655
656     aBuilder.MakeEdge(myTopoEdge);
657     aBuilder.UpdateEdge(myTopoEdge, a2dCurv, aSurf, aLocation, theTol);
658     aBuilder.Add(myTopoEdge, aV1);
659     aBuilder.Add(myTopoEdge, aV2);
660     aBuilder.Range(myTopoEdge, aFPar, aLPar);
661     aBuilder.Degenerated(myTopoEdge, Standard_True);
662     return;
663   }
664
665   switch(anEdgeID)
666   {
667   case 0:
668     a3dCurv = aSurf->VIso(aVf);
669     break;
670   case 1:
671     a3dCurv = aSurf->UIso(aUl);
672     break;
673   case 2:
674     a3dCurv = aSurf->VIso(aVl);
675     break;
676   case 3:
677     a3dCurv = aSurf->UIso(aUf);
678     break;
679   default:
680     throw Standard_OutOfRange("FS_Edge::CreateTopologicalEdge()");
681     break;
682   }
683
684   aBuilder.MakeEdge(myTopoEdge, a3dCurv, theTol);
685   aBuilder.Add(myTopoEdge, aV1);
686   aBuilder.Add(myTopoEdge, aV2);
687   aBuilder.Range(myTopoEdge, a3dCurv->FirstParameter(), a3dCurv->LastParameter());
688 }
689
690 //=======================================================================
691 //function : ::FS_Face::CreateTopologicalWire
692 //purpose  : 
693 //=======================================================================
694 void BRepBuilderAPI_FastSewing::FS_Face::
695                 CreateTopologicalWire(const NCollection_Vector<FS_Edge>& theEdgeVec,
696                 const Standard_Real theToler)
697 {
698   TopLoc_Location aLocation;
699   //3D-curves in 1st and 2nd faces are considered to be in same-range
700   const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(mySrcFace, aLocation);
701   Standard_Real aUf = 0.0, aUl = 0.0, aVf = 0.0, aVl = 0.0;
702   aSurf->Bounds(aUf, aUl, aVf, aVl);
703
704   BRep_Builder aB;
705   aB.MakeWire(myWire);
706   for(Standard_Integer anEdge = 0; anEdge < 4; anEdge++)
707   {
708     Standard_ProgramError_Raise_if(myEdges[anEdge] < 0, 
709       "BRepBuilderAPI_FastSewing::FS_Face::CreateTopologicalWire: Wire is not closed.");
710
711     const BRepBuilderAPI_FastSewing::FS_Edge& aFSEdge = theEdgeVec.Value(myEdges[anEdge]);
712     TopAbs_Orientation anOri = anEdge < 2 ? TopAbs_FORWARD : TopAbs_REVERSED;
713     TopoDS_Edge anTopE = aFSEdge.myTopoEdge;
714
715     if(aFSEdge.IsDegenerated())
716     {
717       anTopE.Orientation(anOri);
718       aB.Add(myWire, anTopE);
719       continue;
720     }
721
722     //Check if 3D and 2D-curve have same-orientation.
723     //If it is not, 2d-curve will be reversed.
724     {
725       Standard_Real aFirstPar = 0.0, aLastPar = 0.0;
726
727       const Handle(Geom_Curve) a3dCurv = BRep_Tool::Curve(anTopE, aFirstPar, aLastPar);
728       Handle(Geom2d_Curve) a2dCurv = Get2DCurve(anEdge, aUf, aUl, aVf, aVl);
729       const gp_Pnt aPref(a3dCurv->Value(aFirstPar));
730       const gp_Pnt2d aP2df(a2dCurv->Value(aFirstPar)), aP2dl(a2dCurv->Value(aLastPar));
731       gp_Pnt aP3df(aSurf->Value(aP2df.X(), aP2df.Y()));
732       gp_Pnt aP3dl(aSurf->Value(aP2dl.X(), aP2dl.Y()));
733       aP3df.Transform(aLocation);
734       aP3dl.Transform(aLocation);
735       const Standard_Real aSqD1 = aP3df.SquareDistance(aPref);
736       const Standard_Real aSqD2 = aP3dl.SquareDistance(aPref);
737
738       if(aSqD2 < aSqD1)
739       {
740         a2dCurv = Get2DCurve(anEdge, aUf, aUl, aVf, aVl, Standard_True);
741         anOri = TopAbs::Reverse(anOri);
742       }
743
744       aB.UpdateEdge(anTopE, a2dCurv, aSurf, aLocation, theToler);
745     }
746
747     anTopE.Orientation(anOri);
748
749     aB.Add(myWire, anTopE);
750   }
751
752   myWire.Closed(Standard_True);
753 }
754
755 //=======================================================================
756 //function : ::FS_Face::CreateTopologicalFace
757 //purpose  : 
758 //=======================================================================
759 void BRepBuilderAPI_FastSewing::FS_Face::CreateTopologicalFace()
760 {
761   Standard_ProgramError_Raise_if(myWire.IsNull(), 
762       "BRepBuilderAPI_FastSewing::FS_Face::CreateTopologicalFace: Cannot create wire.");
763
764   BRep_Builder aBuilder;
765   myRetFace = TopoDS::Face(mySrcFace.EmptyCopied());
766   aBuilder.Add(myRetFace, myWire);
767   aBuilder.NaturalRestriction(myRetFace, Standard_True);
768 }