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