0022792: Globally defined symbol PI conflicts with VTK definition (Intel compiler)
[occt.git] / src / ShapeFix / ShapeFix_ComposeShell.cxx
1 // File:        ShapeFix_ComposeShell.cxx
2 // Created:     Tue Apr 27 11:34:07 1999
3 // Author:      Andrey BETENEV
4 //              <abv@doomox.nnov.matra-dtv.fr>
5 //    pdn  01.06.99 S4205: handling not-SameRange edges
6 //    abv  22.07.99 implementing patch indices
7 //    svv  10.01.00 porting on DEC
8
9 #include <ShapeFix_ComposeShell.ixx>
10
11 #include <Precision.hxx>
12 #include <gp_Pnt2d.hxx>
13 #include <gp_Lin2d.hxx>
14 #include <gp_Dir2d.hxx>
15
16 #include <TColStd_Array1OfInteger.hxx>
17 #include <TColStd_Array1OfBoolean.hxx>
18 #include <TColStd_Array1OfReal.hxx>
19 #include <TColStd_HArray1OfReal.hxx>
20 #include <TColgp_SequenceOfPnt2d.hxx>
21 #include <TColStd_SequenceOfReal.hxx>
22
23 #include <IntRes2d_IntersectionSegment.hxx>
24 #include <IntRes2d_IntersectionPoint.hxx>
25 #include <IntRes2d_Domain.hxx>
26
27 #include <Geom2dInt_GInter.hxx>
28 #include <Geom_Curve.hxx>
29 #include <Geom2d_Line.hxx>
30 #include <Geom2dAdaptor_Curve.hxx>
31 #include <GeomAdaptor_Surface.hxx>
32
33 #include <TopoDS.hxx>
34 #include <TopoDS_Vertex.hxx>
35 #include <TopoDS_Edge.hxx>
36 #include <TopoDS_Wire.hxx>
37 #include <TopoDS_Shell.hxx>
38 #include <TopoDS_Iterator.hxx>
39 #include <TopTools_MapOfShape.hxx>
40 #include <TopTools_DataMapOfShapeListOfShape.hxx>
41
42 #include <BRepTools.hxx>
43 #include <Bnd_Box2d.hxx>
44 #include <BndLib_Add2dCurve.hxx>
45 #include <BRepTopAdaptor_FClass2d.hxx>
46 #include <BRep_Tool.hxx>
47 #include <BRep_Builder.hxx>
48
49 #include <ShapeExtend.hxx>
50 #include <ShapeExtend_WireData.hxx>
51 #include <ShapeBuild_Vertex.hxx>
52 #include <ShapeBuild_Edge.hxx>
53 #include <ShapeAnalysis.hxx>
54 #include <ShapeAnalysis_Edge.hxx>
55 #include <ShapeAnalysis_WireOrder.hxx>
56 #include <ShapeFix_Wire.hxx>
57 #include <ShapeFix_Edge.hxx>
58 #include <ShapeFix_WireSegment.hxx>
59 #include <ShapeAnalysis_Curve.hxx>
60 #include <ShapeBuild_ReShape.hxx>
61 #include <ShapeAnalysis_TransferParametersProj.hxx>
62 #include <ShapeFix_Face.hxx>
63 #include <ShapeAnalysis_Surface.hxx>
64 #include <gp_Pnt.hxx>
65 #include <Extrema_ExtPC2d.hxx>
66 #include <ShapeAnalysis.hxx>
67
68 //=======================================================================
69 //function : ShapeFix_ComposeShell
70 //purpose  : 
71 //=======================================================================
72
73 ShapeFix_ComposeShell::ShapeFix_ComposeShell () : 
74        myStatus(0), myClosedMode(Standard_False)
75 {
76   myTransferParamTool = new ShapeAnalysis_TransferParametersProj;
77 }
78     
79
80 //=======================================================================
81 //function : Init
82 //purpose  : 
83 //=======================================================================
84
85 void ShapeFix_ComposeShell::Init (const Handle(ShapeExtend_CompositeSurface) &Grid,
86                                   const TopLoc_Location& L,
87                                   const TopoDS_Face &Face,
88                                   const Standard_Real Prec)
89 {
90   myGrid = Grid;
91   myUClosed = myGrid->IsUClosed();
92   myVClosed = myGrid->IsVClosed();
93   myUPeriod = myGrid->UJointValue(myGrid->NbUPatches()+1) - myGrid->UJointValue(1);
94   myVPeriod = myGrid->VJointValue(myGrid->NbVPatches()+1) - myGrid->VJointValue(1);
95
96 //  DTK-CKY 100531 : protection against very thin face
97 //  Test "isclosed" should be filtered on the overall (non trimmed) surface, must be closed
98   Handle(Geom_Surface) theSurface = BRep_Tool::Surface(Face,myLoc);
99   Standard_Real U0,U1,V0,V1;
100   theSurface->Bounds(U0,U1,V0,V1);
101   if (myUClosed) {
102     gp_Pnt P0 = theSurface->Value(U0,(V0+V1)/2.);
103     gp_Pnt P1 = theSurface->Value(U1,(V0+V1)/2.);
104     if (P0.Distance(P1) > Precision::Confusion()*10)
105       myUClosed = Standard_False;
106   }
107   if (myVClosed) {
108     gp_Pnt P0 = theSurface->Value((U0+U1)/2.,V0);
109     gp_Pnt P1 = theSurface->Value((U0+U1)/2.,V1);
110     if (P0.Distance(P1) > Precision::Confusion()*10)
111       myVClosed = Standard_False;
112   }
113 //  DTK-CKY 100531 end
114
115   myLoc  = L;
116 //smh#8
117   TopoDS_Shape tmpF = Face.Oriented ( TopAbs_FORWARD );
118   myFace = TopoDS::Face ( tmpF ); // for correct dealing with seams
119   myOrient = Face.Orientation();
120   SetPrecision(Prec);
121   myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
122
123   // Compute resolution (checking in 2d is necessary for splitting 
124   // degenerated edges and avoiding NotClosed)
125   myUResolution = myVResolution = RealLast();
126   for ( Standard_Integer i=1; i <= myGrid->NbUPatches(); i++ ) { 
127     Standard_Real uRange = myGrid->UJointValue(i+1)-myGrid->UJointValue(i);
128     for ( Standard_Integer j=1; j <= myGrid->NbVPatches(); j++ ) {
129       Standard_Real vRange = myGrid->VJointValue(j+1)-myGrid->VJointValue(j);
130       Standard_Real u1,u2,v1,v2;
131       myGrid->Patch(i,j)->Bounds(u1,u2,v1,v2);
132       GeomAdaptor_Surface GAS ( myGrid->Patch(i,j) );
133       Standard_Real ures = GAS.UResolution ( 1. )*uRange/(u2-u1);
134       Standard_Real vres = GAS.VResolution ( 1. )*vRange/(v2-v1);
135       if ( ures >0. && myUResolution > ures ) myUResolution = ures;
136       if ( vres >0. && myVResolution > vres ) myVResolution = vres;
137     }
138   }
139   if ( myUResolution == RealLast() ) myUResolution = ::Precision::Parametric ( 1. );
140   if ( myVResolution == RealLast() ) myVResolution = ::Precision::Parametric ( 1. );
141 }
142                       
143
144 //=======================================================================
145 //function : Perform
146 //purpose  : 
147 //=======================================================================
148
149 Standard_Boolean ShapeFix_ComposeShell::Perform ()
150 {
151   myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
152   myInvertEdgeStatus = Standard_False;
153
154   ShapeFix_SequenceOfWireSegment seqw; // working data: wire segments
155   
156   // Init seqw by initial set of wires (with corresponding orientation)
157   LoadWires ( seqw );
158   if(seqw.Length() == 0) { 
159     myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_FAIL6 );
160     return Standard_False;
161   }
162   
163   // Split edges in the wires by grid and add internal segments of grid (parts of cutting lines)
164   SplitByGrid ( seqw );
165   
166   // Split all the wires into segments by common vertices (intersections)
167   BreakWires ( seqw );
168
169   // Then, collect resulting wires
170   ShapeFix_SequenceOfWireSegment wires; // resulting wires
171   CollectWires ( wires, seqw );
172
173   // And construct resulting faces
174   TopTools_SequenceOfShape faces;
175   DispatchWires ( faces, wires );
176   
177   // Finally, construct resulting shell
178   if ( faces.Length() !=1 ) {
179     TopoDS_Shell S;
180     BRep_Builder B;
181     B.MakeShell ( S );
182     for ( Standard_Integer i=1; i <= faces.Length(); i++ ) 
183       B.Add ( S, faces(i) );
184     myResult = S;
185   }
186   else myResult = faces(1);
187   myResult.Orientation ( myOrient );
188   
189   myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
190   return Standard_True;
191 }
192     
193
194 //=======================================================================
195 //function : SplitEdges
196 //purpose  : 
197 //=======================================================================
198
199 void ShapeFix_ComposeShell::SplitEdges ()
200 {
201   myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
202
203   ShapeFix_SequenceOfWireSegment seqw; // working data: wire segments
204   
205   // Init seqw by initial set of wires (with corresponding orientation)
206   LoadWires ( seqw );
207   
208   // Split edges in the wires by grid and add internal segments of grid (parts of cutting lines)
209   SplitByGrid ( seqw );
210 }
211   
212
213 //=======================================================================
214 //function : Result
215 //purpose  : 
216 //=======================================================================
217
218 const TopoDS_Shape& ShapeFix_ComposeShell::Result () const
219 {
220   return myResult;
221 }
222     
223
224 //=======================================================================
225 //function : Status
226 //purpose  : 
227 //=======================================================================
228
229 Standard_Boolean ShapeFix_ComposeShell::Status (const ShapeExtend_Status status) const
230 {
231   return ShapeExtend::DecodeStatus ( myStatus, status );
232 }
233
234
235 //=======================================================================
236 // PRIVATE (working) METHODS
237 //=======================================================================
238
239 #define TOLINT             1.e-10       // precision for intersection
240   
241 // Local definitions: characteristics of intersection point
242
243 #define IOR_UNDEF          0            // undefined side
244 #define IOR_LEFT           1            // to left side of cutting line
245 #define IOR_RIGHT          2            // to right side of cutting line
246 #define IOR_BOTH           3            // crossing
247 #define IOR_POS            4            // in case of cycle on full period, whether first point is right
248
249 #define ITP_INTER          8            // crossing
250 #define ITP_BEGSEG        16            // start of tangential segment
251 #define ITP_ENDSEG        32            // stop of tangential segment
252 #define ITP_TANG          64            // tangential point
253   
254
255 //=======================================================================
256 //function : PointLineDeviation
257 //purpose  : auxilary
258 //=======================================================================
259 // Return (signed) deviation of point from line
260 static Standard_Real PointLineDeviation (const gp_Pnt2d &p, const gp_Lin2d &line)
261 {
262   gp_Dir2d dir = line.Direction();
263   gp_Dir2d n ( -dir.Y(), dir.X() );
264   return n.XY() * ( p.XY() - line.Location().XY() );
265 }
266   
267
268 //=======================================================================
269 //function : PointLinePosition
270 //purpose  : auxilary
271 //=======================================================================
272 // Define position of point relative to line
273 static Standard_Integer PointLinePosition (const gp_Pnt2d &p, const gp_Lin2d &line, 
274                                            Standard_Real &dev)
275 {
276   dev = PointLineDeviation ( p, line );
277   return ( dev > TOLINT ? IOR_LEFT : ( dev < -TOLINT ? IOR_RIGHT : IOR_UNDEF ) );
278 }
279   
280
281 //=======================================================================
282 //function : PointLinePosition
283 //purpose  : auxilary
284 //=======================================================================
285 // Define position of point relative to line
286 static Standard_Integer PointLinePosition (const gp_Pnt2d &p, const gp_Lin2d &line)
287 {
288   Standard_Real dev;
289   return PointLinePosition ( p, line, dev );
290 }
291   
292
293 //=======================================================================
294 //function : ParamPointsOnLine
295 //purpose  : auxilary
296 //=======================================================================
297 // Compute parameter of point on line
298 static inline Standard_Real ParamPointOnLine (const gp_Pnt2d &p, const gp_Lin2d &line)
299 {
300   return line.Direction().XY() * ( p.XY() - line.Location().XY() );
301 }
302   
303
304 //=======================================================================
305 //function : ParamPointsOnLine
306 //purpose  : auxilary
307 //=======================================================================
308 // Compute parameter of two points on line (as intersection of segment)
309 static Standard_Real ParamPointsOnLine (const gp_Pnt2d &p1, const gp_Pnt2d &p2, 
310                                         const gp_Lin2d &line)
311 {
312   Standard_Real dist1 = PointLineDeviation ( p1, line );
313   Standard_Real dist2 = PointLineDeviation ( p2, line );
314   // in most cases, one of points is on line
315   if ( Abs ( dist1 ) < ::Precision::PConfusion() ) {
316     if ( Abs ( dist2 ) < ::Precision::PConfusion() ) 
317       return 0.5 * ( ParamPointOnLine ( p1, line ) + ParamPointOnLine ( p2, line ) );
318     return ParamPointOnLine ( p1, line );
319   }
320   if ( Abs ( dist2 ) < ::Precision::PConfusion() ) 
321     return ParamPointOnLine ( p2, line );
322   // just protection
323   if ( dist2 * dist1 >0 ) 
324     return 0.5 * ( ParamPointOnLine ( p1, line ) + ParamPointOnLine ( p2, line ) );
325   // else compute intersection
326   return ( ParamPointOnLine ( p1, line ) * dist2 - 
327            ParamPointOnLine ( p2, line ) * dist1 ) / ( dist2 - dist1 );
328 }
329   
330
331 //=======================================================================
332 //function : ProjectPointOnLine
333 //purpose  : auxilary
334 //=======================================================================
335 // Compute projection of point on line
336 static inline gp_Pnt2d ProjectPointOnLine (const gp_Pnt2d &p, const gp_Lin2d &line)
337 {
338   return line.Location().XY() + line.Direction().XY() * ParamPointOnLine ( p, line );
339 }
340
341
342 //=======================================================================
343 //function : ApplyContext
344 //purpose  : auxilary
345 //=======================================================================
346 // Apply context to one edge in the wire and put result into this wire
347 static Standard_Integer ApplyContext (ShapeFix_WireSegment &wire, 
348                                       const Standard_Integer iedge,
349                                       const Handle(ShapeBuild_ReShape) &context)
350 {
351   TopoDS_Edge edge = wire.Edge ( iedge );
352   TopoDS_Shape res = context->Apply ( edge );
353   
354   if ( res.IsSame ( edge ) ) return 1;
355   
356   if ( res.ShapeType() == TopAbs_EDGE ) {
357     wire.SetEdge ( iedge, TopoDS::Edge ( res ) );
358     return 1;
359   }
360
361   Standard_Integer index = iedge;
362   
363   Handle(ShapeExtend_WireData) segw = new ShapeExtend_WireData;
364   segw->ManifoldMode() = Standard_False;
365   for ( TopoDS_Iterator it(res); it.More(); it.Next() ) {
366     TopoDS_Edge E = TopoDS::Edge ( it.Value() );
367     if ( ! E.IsNull() ) segw->Add ( E );
368 #ifdef DEB
369     else cout << "Error: ShapeFix_ComposeShell, ApplyContext: wrong mapping of edge" << endl;
370 #endif
371   }
372
373   // add edges into the wire in correct order
374   if ( segw->NbEdges() >0 ) {
375     Standard_Integer ind, iumin, iumax, ivmin, ivmax;
376     wire.GetPatchIndex ( iedge, iumin, iumax, ivmin, ivmax );
377     Standard_Integer nbEdges =  segw->NbEdges(); 
378     for ( Standard_Integer i=1; i <=  nbEdges; i++, index++ ) {
379       ind = (  edge.Orientation() == TopAbs_FORWARD || edge.Orientation() == TopAbs_INTERNAL ? i : segw->NbEdges()-i+1 );
380       TopoDS_Edge   aE = segw->Edge ( ind );
381       if ( i==1 ) wire.SetEdge ( index, aE );
382       else wire.AddEdge ( index, aE, iumin, iumax, ivmin, ivmax );
383     }
384   }
385 #ifdef DEB
386   else cout << "Warning: ShapeFix_ComposeShell, ApplyContext: edge is to remove - not implemented" << endl;
387 #endif
388   
389   return index - iedge;
390 }
391
392
393 //=======================================================================
394 //function : IsCoincided
395 //purpose  : auxilary
396 //=======================================================================
397 // check points coincidence
398 static inline Standard_Integer IsCoincided (const gp_Pnt2d &p1, const gp_Pnt2d &p2,
399                                             const Standard_Real UResolution,
400                                             const Standard_Real VResolution,
401                                             const Standard_Real tol)
402 {
403   //pdn Maximal accuracy is working precision of intersector.
404   Standard_Real UTolerance = UResolution * tol;
405   Standard_Real VTolerance = VResolution * tol;
406   return Abs ( p1.X() - p2.X() ) <= Max(TOLINT,UTolerance) && 
407          Abs ( p1.Y() - p2.Y() ) <= Max(TOLINT,VTolerance);
408 }
409
410
411 //=======================================================================
412 //function : GetPatchIndex
413 //purpose  : auxilary
414 //=======================================================================
415 // computes index for the patch by given parameter Param
416 static Standard_Integer GetPatchIndex (const Standard_Real Param,
417                                        const Handle(TColStd_HArray1OfReal) &Params,
418                                        const Standard_Boolean isClosed)
419 {
420   Standard_Integer NP = Params->Upper();
421   Standard_Real period = Params->Value(NP) - Params->Value(1);
422   Standard_Real shift = 0;
423   if ( isClosed ) 
424     shift = ShapeAnalysis::AdjustToPeriod ( Param, Params->Value(1), Params->Value(NP) );
425   Standard_Real p = Param + shift;
426   
427   // locate patch: the same algo as in SE_CS::LocateParameter()
428   Standard_Integer i; // svv #1
429   for ( i = 2; i < NP; i++ ) {
430 //    Standard_Real par = Params->Value(i);
431     if ( p < Params->Value(i) ) break;
432   }
433   i--;
434
435   Standard_Real ish = shift / period;
436   Standard_Integer ishift = (Standard_Integer)( ish <0 ? ish - 0.5 : ish + 0.5 ); 
437   return i - ishift * ( NP - 1 );
438 }
439
440
441 //=======================================================================
442 //function : LoadWires
443 //purpose  : 
444 //=======================================================================
445
446 void ShapeFix_ComposeShell::LoadWires (ShapeFix_SequenceOfWireSegment &seqw) const
447 {
448   seqw.Clear();
449   
450   // Init seqw by initial set of wires (with corresponding orientation)
451   for ( TopoDS_Iterator iw(myFace,Standard_False); iw.More(); iw.Next() ) {
452 //smh#8
453     TopoDS_Shape tmpW = Context()->Apply ( iw.Value() ) ;
454     if(tmpW.ShapeType() != TopAbs_WIRE) {
455       if(tmpW.ShapeType() == TopAbs_VERTEX) {
456         ShapeFix_WireSegment seg; //(( isOuter ? TopAbs_REVERSED : TopAbs_FORWARD ) );
457         seg.SetVertex(TopoDS::Vertex(tmpW));
458         seg.Orientation(tmpW.Orientation());
459         seqw.Append ( seg );
460       }
461       continue;
462     }
463     TopoDS_Wire wire = TopoDS::Wire ( tmpW );
464
465     Standard_Boolean isNonManifold = ( wire.Orientation() != TopAbs_REVERSED &&
466                                       wire.Orientation() != TopAbs_FORWARD );
467
468     
469
470     // protect against INTERNAL/EXTERNAL wires
471 //    if ( wire.Orientation() != TopAbs_REVERSED &&
472 //       wire.Orientation() != TopAbs_FORWARD ) continue;
473     
474     // determine orientation of the wire
475 //    TopoDS_Face face = TopoDS::Face ( myFace.EmptyCopied() );
476 //    B.Add ( face, wire );
477 //    Standard_Boolean isOuter = ShapeAnalysis::IsOuterBound ( face );
478
479     if(isNonManifold) {
480     
481       Handle(ShapeExtend_WireData) sbwd = new ShapeExtend_WireData ( wire ,Standard_True,Standard_False);
482       //pdn protection againts of wires w/o edges
483       Standard_Integer nbEdges =  sbwd->NbEdges();
484       if(nbEdges) {
485
486         //wire segments for non-manifold topology should have INTERNAL orientation
487         ShapeFix_WireSegment seg ( sbwd, TopAbs_INTERNAL); 
488         seqw.Append ( seg );
489       }
490     }
491     else {
492       //splitting wires containing manifold and non-manifold parts on a separate
493        //wire segment
494     
495       Handle(ShapeExtend_WireData) sbwdM = new ShapeExtend_WireData();
496       Handle(ShapeExtend_WireData) sbwdNM = new ShapeExtend_WireData();
497       sbwdNM->ManifoldMode() = Standard_False;
498       TopoDS_Iterator aIt(wire);
499       for( ; aIt.More(); aIt.Next()) {
500         TopoDS_Edge E = TopoDS::Edge ( aIt.Value() );
501         if(E.Orientation() == TopAbs_FORWARD || E.Orientation() == TopAbs_REVERSED)
502           sbwdM->Add(E);
503         else
504           sbwdNM->Add(E);
505       }
506       Standard_Integer nbMEdges =  sbwdM->NbEdges();
507       Standard_Integer nbNMEdges =  sbwdNM->NbEdges();
508       if(nbNMEdges) {
509         ShapeFix_WireSegment seg ( sbwdNM, TopAbs_INTERNAL); //(( isOuter ? TopAbs_REVERSED : TopAbs_FORWARD ) );
510         seqw.Append ( seg );
511       }
512       if(nbMEdges) {
513         // Orientation is set so as to allow the segment to be traversed in only one direction
514         // skl 01.04.2002
515         Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
516         sfw->Load ( sbwdM );
517         Standard_Integer stat=0;
518         Handle(Geom_Surface) gs = BRep_Tool::Surface(myFace);
519         if( gs->IsUPeriodic() && gs->IsVPeriodic() ) {
520           // For torus-like shapes, first reorder in 2d since reorder is indifferent in 3d
521           ShapeAnalysis_WireOrder sawo(Standard_False, 0);
522           ShapeAnalysis_Edge sae;
523           for(Standard_Integer i = 1; i <= nbMEdges; i++) {
524             Standard_Real f,l;
525            Handle(Geom2d_Curve) c2d;
526             //smh#8
527             TopoDS_Shape tmpF = myFace.Oriented(TopAbs_FORWARD);
528             if(!sae.PCurve(sbwdM->Edge(i),TopoDS::Face(tmpF),c2d,f,l))
529               continue;
530             sawo.Add(c2d->Value(f).XY(),c2d->Value(l).XY());
531           }
532           sawo.Perform();
533           stat = (sawo.Status() < 0 ? -1 : 1);
534           sfw->FixReorder(sawo);
535         }
536       
537         sfw->FixReorder();
538         if (sfw->StatusReorder(ShapeExtend_DONE3))
539           stat=-1;
540       
541         if( stat < 0 ) {
542           BRep_Builder B;
543           TopoDS_Shape dummy = myFace.EmptyCopied();
544           TopoDS_Face face = TopoDS::Face ( dummy );
545           B.Add ( face, wire );
546           Standard_Boolean isOuter = ShapeAnalysis::IsOuterBound ( face );
547           TopoDS_Wire w = sbwdM->Wire();
548           dummy = myFace.EmptyCopied();
549           face = TopoDS::Face ( dummy );
550           B.Add ( face, w );
551           Standard_Boolean isOuterAfter = ShapeAnalysis::IsOuterBound ( face );
552           if(isOuter!=isOuterAfter)
553             sbwdM->Reverse(face);
554         }
555       
556         ShapeFix_WireSegment seg ( sbwdM, TopAbs_REVERSED ); //(( isOuter ? TopAbs_REVERSED : TopAbs_FORWARD ) );
557         seqw.Append ( seg );
558       }
559     }
560     
561   }
562 }
563   
564
565 //=======================================================================
566 //function : ComputeCode
567 //purpose  : compute code for wire segment between two intersections (by deviation)
568 //=======================================================================
569
570 Standard_Integer ShapeFix_ComposeShell::ComputeCode (const Handle(ShapeExtend_WireData) &wire,
571                                                      const gp_Lin2d &line,
572                                                      const Standard_Integer begInd,
573                                                      const Standard_Integer endInd,
574                                                      const Standard_Real begPar,
575                                                      const Standard_Real endPar,
576                                                      const Standard_Boolean isInternal)
577 {
578   Standard_Integer code = IOR_UNDEF;
579   
580   ShapeAnalysis_Edge sae;
581   const Standard_Integer NPOINTS = 5; // number of points for measuring deviation
582    
583   // track special closed case: segment starts at end of edge and ends at its beginning
584   Standard_Integer special = ( begInd == endInd &&
585                                ( wire->Edge(begInd).Orientation() == TopAbs_FORWARD ||
586                     wire->Edge(begInd).Orientation() == TopAbs_INTERNAL) ==
587                                ( begPar > endPar ) ? 1 : 0);
588   if ( ! special && begInd == endInd && begPar == endPar && 
589       (myClosedMode || isInternal)) 
590     special = 1;
591
592   // for tracking cases in closed mode
593   Standard_Boolean begin=Standard_True;
594   Standard_Real shift=0;
595   gp_Pnt2d p2d0;
596   
597   // check if segment is tangency
598   // Segment is considered as tangency if deviation of pcurve from line 
599   // (in 2d) measured by NPOINTS points is less than tolerance of edge
600   // (recomputed to 2d using Resolution).
601   
602   Standard_Integer nb = wire->NbEdges();
603   
604   Standard_Integer i; // svv #1
605   for ( i=begInd; ; i++ ) {
606     if ( i > nb ) i = 1;
607     TopoDS_Edge edge = wire->Edge ( i );;
608     
609     Handle(Geom2d_Curve) c2d;
610     Standard_Real f, l;
611     if ( ! sae.PCurve ( edge, myFace, c2d, f, l, Standard_False ) ) {
612       myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL3 );
613       continue;
614     }
615     Standard_Real tol = LimitTolerance(BRep_Tool::Tolerance ( edge ));
616     Standard_Boolean isreversed = ( edge.Orientation() == TopAbs_REVERSED );
617     
618     Standard_Real par1 = ( i == begInd && special >=0 ? begPar : ( isreversed ? l : f ) );
619     Standard_Real par2 = ( i == endInd && special <=0 ? endPar : ( isreversed ? f : l ) );
620     Standard_Real dpar = ( par2 - par1 ) / ( NPOINTS - 1 );
621     Standard_Integer np = ( Abs ( dpar ) < ::Precision::PConfusion() ? 1 : NPOINTS );
622     Standard_Integer j; // svv #1
623     for ( j=0; j < np; j++ ) {
624       Standard_Real par = par1 + dpar * j;
625       gp_Pnt2d p2d = c2d->Value ( par );
626       if ( myClosedMode ) {
627         if ( myUClosed && Abs ( line.Direction().X() ) < ::Precision::PConfusion() ) {
628           if ( begin ) shift = ShapeAnalysis::AdjustByPeriod ( p2d.X(), line.Location().X(), myUPeriod );
629           else if ( ! j ) shift = ShapeAnalysis::AdjustByPeriod ( p2d.X()-p2d0.X(), 0., myUPeriod );
630           p2d.SetX ( p2d.X() + shift );
631         }
632         if ( myVClosed && Abs ( line.Direction().Y() ) < ::Precision::PConfusion() ) {
633           if ( begin ) shift = ShapeAnalysis::AdjustByPeriod ( p2d.Y(), line.Location().Y(), myVPeriod );
634           else if ( ! j ) shift = ShapeAnalysis::AdjustByPeriod ( p2d.Y()-p2d0.Y(), 0., myVPeriod );
635           p2d.SetY ( p2d.Y() + shift );
636         }
637         begin = Standard_False;
638       }
639       p2d0 = p2d;
640       Standard_Integer pos = PointLinePosition ( p2d, line );
641       if ( pos == IOR_UNDEF ) continue;
642       
643       // analyse the deviation
644       gp_Pnt2d p2dl = ProjectPointOnLine ( p2d, line );
645       if(!IsCoincided ( p2d, p2dl, myUResolution, myVResolution, tol )) {
646         if(!myClosedMode) { code = pos; break; }
647         else {
648           code |= pos;
649         }
650       }
651     }
652     if ( j < np ) { i = 0; break; } // not tangency
653     if ( i == endInd ) 
654       if ( special <=0 ) break;
655       else special = -1;
656   }
657   if ( myClosedMode ) {
658     if ( code != IOR_UNDEF && ! begin ) {
659       // in closed mode, if segment is of 2*pi length, it is BOTH
660       Standard_Real dev = PointLineDeviation ( p2d0, line );
661       if ( myUClosed && Abs ( line.Direction().X() ) < ::Precision::PConfusion() ) {
662         if ( Abs ( Abs ( dev ) - myUPeriod ) < 0.1 * myUPeriod ) {
663           code = IOR_BOTH;
664           if ( dev >0 ) code |= IOR_POS;
665         }
666         else if(code==IOR_BOTH)
667           code=IOR_UNDEF;
668       }
669       if ( myVClosed && Abs ( line.Direction().Y() ) < ::Precision::PConfusion() ) {
670         if ( Abs ( Abs ( dev ) - myVPeriod ) < 0.1 * myVPeriod ) {
671           code = IOR_BOTH;
672           if ( dev >0 ) code |= IOR_POS;
673         }
674         else if(code==IOR_BOTH)
675           code=IOR_UNDEF;
676       }
677     }
678     return code;
679   }
680   if ( i ) code = IOR_UNDEF;     // tangency
681   else if ( code == IOR_BOTH ) { // parity error in intersector
682     code = IOR_LEFT;
683     myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
684 #ifdef DEB
685     cout << "Warning: ShapeFix_ComposeShell::ComputeCode: lost intersection point" << cout;
686 #endif
687   }
688   return code;
689 }
690
691
692 //=======================================================================
693 //function : DistributeSplitPoints
694 //purpose  : auxilary
695 //=======================================================================
696 // After applying context to (seam) edge, distribute its indices on new edges,
697 // according to their parameters on that edge
698 static void DistributeSplitPoints (const Handle(ShapeExtend_WireData) &sbwd,
699                                    const TopoDS_Face myFace,
700                                    const Standard_Integer index,
701                                    const Standard_Integer nsplit, 
702                                    TColStd_SequenceOfInteger& indexes,
703                                    const TColStd_SequenceOfReal& values)
704 {
705   Standard_Boolean isreversed = ( nsplit >0 && sbwd->Edge(index).Orientation() == TopAbs_REVERSED );
706   
707   TColStd_Array1OfReal params(0,nsplit);
708   Standard_Integer i; // svv #1
709   for ( i=0; i < nsplit; i++ ) {
710     Standard_Real f, l;
711     BRep_Tool::Range ( sbwd->Edge(index+i), myFace, f, l );
712     params.SetValue ( i, ( isreversed ? l : f ) );
713   }
714   
715   for ( i=1; i <= indexes.Length() && indexes(i) < index; i++ );
716   for ( Standard_Integer shift = 1; i <= indexes.Length() && indexes(i) == index; i++ ) {
717     while (  shift < nsplit  && isreversed != (Standard_Boolean) ( values(i) > params(shift) ) ) shift++;
718     indexes.SetValue ( i, index + shift - 1 );
719   }
720   for ( ; i <= indexes.Length(); i++ ) 
721     indexes.SetValue ( i, indexes(i) + nsplit - 1 );
722 }
723
724
725 //=======================================================================
726 //function : CheckByCurve3d
727 //purpose  : auxilary
728 //=======================================================================
729 static Standard_Integer CheckByCurve3d (const gp_Pnt &pos, 
730                                         const Handle(Geom_Curve) &c3d,
731                                         const Standard_Real param,
732                                         const gp_Trsf &T,
733                                         const Standard_Real tol)
734 {
735   if ( c3d.IsNull() ) return Standard_True;
736   gp_Pnt p = c3d->Value(param);
737   if ( T.Form() != gp_Identity ) p.Transform ( T );
738   return pos.SquareDistance ( p ) <= tol * tol;
739 }
740
741
742 //=======================================================================
743 //function : DefinePatch
744 //purpose  : auxilary
745 //=======================================================================
746 static void DefinePatch (ShapeFix_WireSegment &wire, const Standard_Integer code, 
747                          const Standard_Boolean isCutByU, const Standard_Integer cutIndex,
748                          const Standard_Integer number = -1)
749 {
750   Standard_Integer nb = (number > 0 ? number : wire.NbEdges());
751   if ( isCutByU ) {
752     if ( ! ( code & IOR_LEFT ) )  wire.DefineIUMin ( nb, cutIndex );
753     if ( ! ( code & IOR_RIGHT ) ) wire.DefineIUMax ( nb, cutIndex );
754   }
755   else {
756     if ( ! ( code & IOR_RIGHT ) ) wire.DefineIVMin ( nb, cutIndex );
757     if ( ! ( code & IOR_LEFT  ) ) wire.DefineIVMax ( nb, cutIndex );
758   }
759 }
760
761
762 //=======================================================================
763 //function : DefinePatchForWire
764 //purpose  : auxilary
765 //=======================================================================
766 static void DefinePatchForWire(ShapeFix_WireSegment &wire, const Standard_Integer code, 
767                                const Standard_Boolean isCutByU, const Standard_Integer cutIndex)
768 {
769   for(Standard_Integer i = 1; i <= wire.NbEdges(); i++) 
770     DefinePatch(wire,code,isCutByU,cutIndex,i);
771 }     
772
773
774 //=======================================================================
775 //function : GetGridResolution
776 //purpose  : auxilary
777 //=======================================================================
778 static Standard_Real GetGridResolution(const Handle(TColStd_HArray1OfReal) SplitValues,
779                                        const Standard_Integer cutIndex)
780 {
781   Standard_Integer nb = SplitValues->Length();
782   Standard_Real leftLen = (cutIndex > 1  ? SplitValues->Value(cutIndex) - SplitValues->Value(cutIndex-1) :
783                            SplitValues->Value(nb) -SplitValues->Value(nb-1));
784   Standard_Real rigthLen =(cutIndex < nb ? SplitValues->Value(cutIndex+1)-SplitValues->Value(cutIndex) :
785                            SplitValues->Value(2) - SplitValues->Value(1));
786   return Min(leftLen,rigthLen)/3.;
787 }
788
789
790 //=======================================================================
791 //function : SplitWire
792 //purpose  : 
793 //=======================================================================
794
795 ShapeFix_WireSegment ShapeFix_ComposeShell::SplitWire (ShapeFix_WireSegment &wire,
796                                                        TColStd_SequenceOfInteger& indexes,
797                                                        const TColStd_SequenceOfReal& values,
798                                                        TopTools_SequenceOfShape& vertices,
799                                                        const TColStd_SequenceOfInteger &SegmentCodes,
800                                                        const Standard_Boolean isCutByU,
801                                                        const Standard_Integer cutIndex) 
802 {
803   BRep_Builder B;
804   ShapeFix_WireSegment result;
805   Handle(ShapeAnalysis_Surface) aSurfTool = 
806     new ShapeAnalysis_Surface ( BRep_Tool::Surface (myFace) );
807   Standard_Integer nbSplits = indexes.Length();
808   ShapeAnalysis_Edge sae;
809   Standard_Integer start = 1;
810   TopAbs_Orientation anWireOrient = wire.Orientation();
811   gp_Trsf T;
812   if ( ! myLoc.IsIdentity() ) T = myLoc.Inverted().Transformation();
813   
814   // Processing edge by edge (assuming that split points are sorted along the wire)
815   for ( Standard_Integer i = 1; i <= wire.NbEdges(); i++ ) {
816     
817     // for already splitted seam edge, redistribute its splitting points 
818     Standard_Integer nsplit = ApplyContext ( wire, i, Context() );
819     if ( nsplit !=1 ) {
820       DistributeSplitPoints ( wire.WireData(), myFace, i, nsplit, indexes, values );
821       if ( nsplit <=0 ) {
822 #ifdef DEB
823         cout << "Error: ShapeFix_ComposeShell::SplitWire: edge dismissed" << endl;
824 #endif
825         i--;
826         continue;
827       }
828     }
829     TopoDS_Edge edge = wire.Edge(i);
830     
831     Standard_Integer iumin, iumax, ivmin, ivmax;
832     wire.GetPatchIndex ( i, iumin, iumax, ivmin, ivmax );
833     
834     // Position code for first segment of edge
835     Standard_Integer code = SegmentCodes ( start >1 ? start-1 : SegmentCodes.Length() );
836     
837     // Defining split parameters on edge
838     Standard_Integer stop = start;
839     while ( stop <= nbSplits && indexes(stop) == i ) stop++;
840     if ( stop == start ) { 
841       result.AddEdge ( 0, edge, iumin, iumax, ivmin, ivmax );
842       if(code!=0 || wire.Orientation()!=TopAbs_EXTERNAL) // pdn 0 code handling for extertnal wires
843         DefinePatch ( result, code, isCutByU, cutIndex );
844       continue;
845     }
846     //find non-manifold vertices on edge
847     TopTools_SequenceOfShape aNMVertices;
848     TopoDS_Iterator aIt(edge,Standard_False);
849     for( ; aIt.More(); aIt.Next()) {
850       if(aIt.Value().Orientation() != TopAbs_FORWARD && 
851          aIt.Value().Orientation() != TopAbs_REVERSED)
852         aNMVertices.Append(aIt.Value());
853     }
854     
855     // Collect data on edge
856     Standard_Real tolEdge = BRep_Tool::Tolerance(edge);
857     Standard_Real tol = LimitTolerance( tolEdge );
858     TopoDS_Vertex prevV = sae.FirstVertex(edge);
859     TopoDS_Vertex lastV = sae.LastVertex(edge);
860     Standard_Real prevVTol = LimitTolerance( BRep_Tool::Tolerance(prevV) );
861     Standard_Real lastVTol = LimitTolerance( BRep_Tool::Tolerance(lastV) );
862     gp_Pnt prevVPnt = BRep_Tool::Pnt(prevV);
863     gp_Pnt lastVPnt = BRep_Tool::Pnt(lastV);
864     if ( T.Form() != gp_Identity ) {
865       prevVPnt.Transform ( T );
866       lastVPnt.Transform ( T );
867     }
868     
869     Handle(Geom_Curve) c3d;
870     Standard_Real f3d, l3d;
871     if ( ! sae.Curve3d ( edge, c3d, f3d, l3d ) ) { // not a crime
872       c3d.Nullify(); 
873       f3d = l3d = 0;
874     }
875     
876     Standard_Real firstPar, lastPar;
877     Handle(Geom2d_Curve) C2d;
878     if ( ! sae.PCurve ( edge, myFace, C2d, firstPar, lastPar ) ) {
879       myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
880     }
881     //finding sequence of non-manifold parameters
882     Standard_Integer nbNMVert = aNMVertices.Length();
883     TColStd_SequenceOfReal aNMVertParams;
884     if( nbNMVert) {
885       Geom2dAdaptor_Curve adc(C2d);
886       
887       Standard_Integer n =1;
888       for( ; n<= nbNMVert; n++) {
889         gp_Pnt apV = BRep_Tool::Pnt(TopoDS::Vertex(aNMVertices.Value(n)));
890         Standard_Real apar =firstPar;
891         Standard_Real adist2 =RealLast();
892         gp_Pnt aPproj;
893         if(!c3d.IsNull()) {
894           ShapeAnalysis_Curve asae;
895           adist2 = asae.Project(c3d,apV,Precision::Confusion(),aPproj,apar);
896           adist2 *= adist2;
897         }
898         else {
899           
900           gp_Pnt2d aP2d =  aSurfTool->ValueOfUV(apV,Precision::Confusion());
901           Extrema_ExtPC2d aExtr(aP2d,adc);
902           if(aExtr.IsDone() && aExtr.NbExt()) {
903             adist2 = aExtr.SquareDistance(1);
904             Standard_Integer index =1;
905             Standard_Integer k =2;
906             for( ; k <= aExtr.NbExt();k++) {
907               Standard_Real ad2 =  aExtr.SquareDistance(k);
908               if( ad2 <adist2) {
909                 adist2 = ad2;
910                 index =k;
911               }
912             }
913             apar = aExtr.Point(index).Parameter();
914             
915           }
916         }
917         aNMVertParams.Append(apar);
918       }
919     }
920     
921     //pdn Claculating parametric shift
922     Standard_Boolean sp = (f3d == firstPar && l3d  == lastPar);
923     Standard_Real span2d = lastPar - firstPar;
924     //    Standard_Real ln2d  = lastPar-prevPar;
925     //    Standard_Real ln3d  = l3d - f3d;
926     //    Standard_Real fact = ln2d/ln3d;
927     //    Standard_Real shift =  prevPar - f3d*fact;
928     Standard_Real prevPar = firstPar;
929     gp_Pnt2d prevPnt2d = C2d->Value(prevPar);
930     gp_Pnt2d lastPnt2d = C2d->Value(lastPar);
931     gp_Pnt prevPnt = myGrid->Value ( prevPnt2d );
932     gp_Pnt lastPnt = myGrid->Value ( lastPnt2d );
933     Standard_Boolean isPeriodic = C2d->IsPeriodic();
934     Standard_Real aPeriod = (isPeriodic ? C2d->Period() :0.);
935     
936     // Splitting edge
937     Standard_Integer NbEdgesStart = result.NbEdges();
938     Standard_Boolean splitted = Standard_False;
939     Standard_Real currPar=lastPar; //SK
940     for ( Standard_Integer j = start; j <= stop; prevPar = currPar, j++ ) {
941       if ( ! splitted && j >= stop ) { // no splitting at all
942         //      code = SegmentCodes ( j >1 ? j-1 : SegmentCodes.Length() ); // classification code
943         break;
944       }
945       currPar = ( j < stop ? values.Value(j) : lastPar );
946       
947       //fix for case when pcurve is periodic and first parameter of edge is more than 2P
948       //method ShapeBuild_Edge::CopyRanges shift pcurve to range 0-2P and parameters of cutting
949       //should be shifted too. gka SAMTECH 28.07.06
950       if(isPeriodic ) {
951         if (currPar > (Max(lastPar,firstPar) +Precision::PConfusion()) ||
952             currPar < (Min(firstPar,lastPar)- Precision::PConfusion())) {
953           Standard_Real aShift = ShapeAnalysis::AdjustByPeriod(currPar, (firstPar+lastPar)*0.5,aPeriod);
954           currPar+=aShift;
955         }
956       }
957       
958       gp_Pnt2d currPnt2d;
959       gp_Pnt currPnt;
960       
961       // Try to adjust current splitting point to previous or end of edge
962       Standard_Boolean doCut = Standard_True;
963       TopoDS_Vertex V;
964       if ( Abs ( currPar - lastPar ) < ::Precision::PConfusion() ) {
965         V = lastV;
966         doCut = Standard_False;
967       }
968       else if ( Abs ( currPar - prevPar ) < ::Precision::PConfusion() ) {
969         vertices.Append ( prevV );
970         code = SegmentCodes ( j ); // classification code - update for next segment
971         continue; // no splitting at this point, go to next one
972       } 
973       else {
974         currPnt2d = C2d->Value(currPar);
975         currPnt = myGrid->Value ( currPnt2d );
976         if ( currPnt.Distance ( lastVPnt ) <= lastVTol && 
977             lastPnt.Distance ( currPnt ) <= tol && 
978             CheckByCurve3d ( lastVPnt, c3d, f3d+(currPar-firstPar)*(l3d-f3d)/span2d, 
979                             T, lastVTol ) &&
980             lastPnt.Distance ( myGrid->Value ( C2d->Value(0.5*(currPar+lastPar)) ) ) <= tol ) {
981           V = lastV;
982           Standard_Real uRes = myUResolution;
983           Standard_Real vRes = myVResolution;
984           if(isCutByU) {
985             Standard_Real gridRes = GetGridResolution(myGrid->UJointValues(),cutIndex)/tol;
986             uRes = Min(myUResolution,gridRes);
987           }
988           else {
989             Standard_Real gridRes = GetGridResolution(myGrid->VJointValues(),cutIndex)/tol;
990             vRes = Min(myVResolution,gridRes);
991           }
992           if ( IsCoincided ( lastPnt2d, currPnt2d, uRes, vRes, tol ) &&
993               IsCoincided ( lastPnt2d, C2d->Value(0.5*(currPar+lastPar)), 
994                            uRes, vRes, tol ) ) doCut = Standard_False;
995         }
996         else if ( currPnt.Distance ( prevVPnt ) <= prevVTol && 
997                  prevPnt.Distance ( currPnt ) <= tol && 
998                  CheckByCurve3d ( prevVPnt, c3d, f3d+(currPar-firstPar)*(l3d-f3d)/span2d, 
999                                  T, prevVTol ) &&
1000                  prevPnt.Distance ( myGrid->Value ( C2d->Value(0.5*(currPar+prevPar)) ) ) <= tol ) {
1001           V = prevV;
1002           Standard_Real uRes = myUResolution;
1003           Standard_Real vRes = myVResolution;
1004           if(isCutByU) {
1005             Standard_Real gridRes = GetGridResolution(myGrid->UJointValues(),cutIndex)/tol;
1006             uRes = Min(myUResolution,gridRes);
1007           }
1008           else {
1009             Standard_Real gridRes = GetGridResolution(myGrid->VJointValues(),cutIndex)/tol;
1010             vRes = Min(myVResolution,gridRes);
1011           }
1012           if ( IsCoincided ( prevPnt2d, currPnt2d, uRes, vRes, tol ) &&
1013               IsCoincided ( prevPnt2d, C2d->Value(0.5*(currPar+prevPar)), 
1014                            uRes, vRes, tol ) ) {
1015             vertices.Append ( prevV );
1016             code = SegmentCodes ( j ); // classification code - update for next segment
1017             continue; // no splitting at this point, go to next one
1018           }
1019         }
1020         //:abv 28.05.02: OCC320 Sample_2: if maxtol = 1e-7, the vertex tolerance
1021         // is actually ignored - protect against new vertex on degenerated edge
1022         else if ( BRep_Tool::Degenerated(edge) && prevV.IsSame(lastV) ) {
1023           V = prevV;
1024         }
1025       }
1026       // classification code for current segment
1027       if ( j > start ) code = SegmentCodes ( j >1 ? j-1 : SegmentCodes.Length() );
1028       
1029       // if not adjusted, make new vertex
1030       if ( V.IsNull() ) { 
1031         B.MakeVertex ( V, currPnt.Transformed(myLoc.Transformation()), tolEdge );
1032         vertices.Append ( V );
1033       }
1034       // else adjusted to end, fill all resting vertices
1035       else if ( ! doCut ) {
1036         for ( ; j < stop; j++ ) vertices.Append ( lastV );
1037         if ( ! splitted ) break; // no splitting at all 
1038         currPar = lastPar;
1039       }
1040       else vertices.Append ( V );
1041       
1042       // When edge is about to be splitted, copy end vertices to protect
1043       // original shape from increasing tolerance after fixing SameParameter
1044       if ( ! splitted ) {
1045         //smh#8
1046         TopoDS_Shape emptyCopiedfV = prevV.EmptyCopied();
1047         TopoDS_Vertex fV = TopoDS::Vertex (emptyCopiedfV );
1048         Context()->Replace ( prevV, fV );
1049         TopoDS_Vertex lV;
1050         if ( prevV.IsSame ( lastV ) ) {
1051           //smh#8
1052           TopoDS_Shape tmpV = fV.Oriented ( lastV.Orientation() ) ;
1053           lV = TopoDS::Vertex (tmpV);
1054         }       
1055         else {
1056           //smh#8
1057           TopoDS_Shape emptyCopied = lastV.EmptyCopied();
1058           lV = TopoDS::Vertex (emptyCopied);
1059           Context()->Replace ( lastV, lV );
1060         }
1061         if ( V.IsSame ( lastV ) ) V = lV;
1062         else if ( V.IsSame ( prevV ) ) V = fV;
1063         lastV = lV;
1064         prevV = fV;
1065       }
1066       
1067       // Splitting of the edge
1068       splitted = Standard_True;
1069       prevV.Orientation ( TopAbs_FORWARD );
1070       V.Orientation ( TopAbs_REVERSED );
1071       ShapeBuild_Edge sbe;
1072       TopoDS_Edge anInitEdge = edge;
1073       Standard_Boolean ismanifold = (edge.Orientation() == TopAbs_FORWARD || 
1074                                      edge.Orientation() == TopAbs_REVERSED);
1075       if(!ismanifold)
1076         anInitEdge.Orientation(TopAbs_FORWARD);
1077       TopoDS_Edge newEdge = sbe.CopyReplaceVertices (anInitEdge, prevV, V );
1078       
1079       
1080       //addition internal vertices if they exists on edge
1081       Standard_Integer n =1;
1082       for( ; n <= aNMVertParams.Length(); n++) {
1083         Standard_Real apar = aNMVertParams.Value(n);
1084         TopoDS_Vertex aNMVert  =TopoDS::Vertex(aNMVertices.Value(n));
1085         TopoDS_Vertex atmpV = TopoDS::Vertex(Context()->Apply(aNMVert));
1086         if(fabs(apar - prevPar) <= Precision::PConfusion()) {
1087           Context()->Replace(atmpV,prevV);
1088           aNMVertParams.Remove(n);
1089           aNMVertices.Remove(n);
1090           n--;
1091         }
1092         else if(fabs(apar - currPar) <= Precision::PConfusion()) {
1093           Context()->Replace(atmpV,V);
1094           aNMVertParams.Remove(n);
1095           aNMVertices.Remove(n);
1096           n--;
1097          }
1098         if(apar > prevPar && apar < currPar) {
1099           B.Add(newEdge,atmpV);
1100           aNMVertParams.Remove(n);
1101           aNMVertices.Remove(n);
1102           n--;
1103         }
1104       }
1105       
1106       
1107       sbe.CopyPCurves ( newEdge, anInitEdge );
1108       
1109       
1110       Handle(ShapeAnalysis_TransferParameters) theTransferParamtool = GetTransferParamTool();
1111       theTransferParamtool->SetMaxTolerance(MaxTolerance());
1112       theTransferParamtool->Init(anInitEdge,myFace);
1113       theTransferParamtool->TransferRange(newEdge,prevPar,currPar,Standard_True);
1114       
1115       
1116       if(!ismanifold) {
1117         if(code == IOR_UNDEF) //tangential segment
1118           newEdge.Orientation(TopAbs_EXTERNAL);
1119         else
1120           newEdge.Orientation(edge.Orientation());
1121       }
1122       
1123       if(!sp && !BRep_Tool::Degenerated(newEdge))
1124         B.SameRange(newEdge, Standard_False);
1125       //pdn take into account 0 codes (if ext)
1126       if(code == 0 && wire.Orientation()==TopAbs_EXTERNAL){
1127         code  = ( ( isCutByU == (Standard_Boolean)( j == 1 ) ) ? 1 : 2 );
1128       }
1129       
1130       result.AddEdge ( 0, newEdge, iumin, iumax, ivmin, ivmax );
1131       DefinePatch ( result, code, isCutByU, cutIndex );
1132       
1133       // Changing prev parameters
1134       prevV = V;
1135       prevVTol = LimitTolerance( BRep_Tool::Tolerance ( V ) );
1136       prevVPnt = BRep_Tool::Pnt ( V );
1137       prevPnt = currPnt;
1138       prevPnt2d = currPnt2d;
1139     }
1140     start = stop;
1141
1142     if ( splitted ) {
1143       // record replacement in context
1144       // NOTE: order of edges in the replacing wire corresponds to FORWARD orientation of the edge
1145       TopoDS_Wire resWire;
1146       B.MakeWire ( resWire );
1147       for ( Standard_Integer k=NbEdgesStart; k < result.NbEdges(); k++ ) {
1148         if ( edge.Orientation() == TopAbs_FORWARD || edge.Orientation() == TopAbs_INTERNAL) 
1149           B.Add ( resWire, result.Edge(k+1) );
1150         else B.Add ( resWire, result.Edge(result.NbEdges()-k+NbEdgesStart) );
1151       }
1152       Context()->Replace ( edge, resWire );
1153     }
1154     else {
1155       if(anWireOrient == TopAbs_INTERNAL && code ==0) {
1156         ShapeBuild_Edge sbe;
1157         if(edge.Orientation() == TopAbs_INTERNAL)
1158           edge.Orientation(TopAbs_FORWARD);
1159         TopoDS_Edge e1 = sbe.Copy(edge,Standard_False);
1160         Handle(Geom2d_Curve) C2d2 = Handle(Geom2d_Curve)::DownCast(C2d->Copy());
1161         B.UpdateEdge(e1,C2d,C2d2,myFace,0.);
1162         e1.Orientation(TopAbs_EXTERNAL);
1163         Context()->Replace ( edge,e1);
1164         result.AddEdge ( 0,e1 , iumin, iumax, ivmin, ivmax );
1165       }
1166       else
1167         result.AddEdge ( 0, edge, iumin, iumax, ivmin, ivmax );
1168       if(code == 0 && wire.Orientation()==TopAbs_EXTERNAL){
1169         //pdn defining code for intersection of two isos
1170         code = ( ( isCutByU == (Standard_Boolean)( Abs(firstPar-currPar) < Abs(lastPar-currPar) ) ) ? 2 : 1 );
1171       }
1172       DefinePatch ( result, code, isCutByU, cutIndex );
1173     }
1174   }
1175   result.Orientation ( anWireOrient );
1176   return result;
1177 }
1178
1179
1180 //=======================================================================
1181 //function : SplitByLine
1182 //purpose  : 
1183 //=======================================================================
1184
1185 Standard_Boolean ShapeFix_ComposeShell::SplitByLine (ShapeFix_WireSegment &wire,
1186                                                      const gp_Lin2d &line, 
1187                                                      const Standard_Boolean isCutByU,
1188                                                      const Standard_Integer cutIndex,
1189                                                      TColStd_SequenceOfReal &SplitLinePar,
1190                                                      TColStd_SequenceOfInteger &SplitLineCode,
1191                                                      TopTools_SequenceOfShape &SplitLineVertex)
1192 {
1193   ShapeAnalysis_Edge sae;
1194   // prepare data on cutting line
1195   Handle(Geom2d_Line) jC2d = new Geom2d_Line ( line );
1196   Geom2dAdaptor_Curve jGAC(jC2d);
1197   
1198   TColStd_SequenceOfInteger IntEdgeInd;   // index of intersecting edge
1199   TColStd_SequenceOfReal IntEdgePar;      // parameter of intersection point on edge
1200   TColStd_SequenceOfReal IntLinePar;      // parameter of intersection point on line
1201   
1202   Standard_Boolean isnonmanifold = (wire.Orientation() == TopAbs_INTERNAL);
1203   //gka correction for non-manifold vertices SAMTECH
1204   if(wire.IsVertex()) {
1205     Handle(ShapeAnalysis_Surface) aSurfTool = new ShapeAnalysis_Surface ( BRep_Tool::Surface (myFace) );
1206     TopoDS_Vertex aVert = wire.GetVertex();
1207     gp_Pnt aP3d = BRep_Tool::Pnt(aVert);
1208     gp_Pnt2d aP2d =  aSurfTool->ValueOfUV(aP3d,Precision::Confusion());
1209     Standard_Real dev =0.;
1210     Standard_Integer code = PointLinePosition(aP2d,line,dev);
1211     if(code != IOR_UNDEF)
1212       return Standard_False;
1213     Standard_Real par = ParamPointOnLine (aP2d,line);
1214     SplitLinePar.Append ( par );
1215     //splitting codes for non-manifold topology should be tangential
1216     SplitLineCode.Append (ITP_TANG); //ITP_INTER);
1217     TopoDS_Vertex aVertNew;
1218     BRep_Builder aB;
1219     aB.MakeVertex(aVertNew,aP3d,BRep_Tool::Tolerance(aVert));
1220     aVertNew.Orientation(TopAbs_FORWARD);
1221     Context()->Replace(aVert,aVertNew);
1222     SplitLineVertex.Append (aVertNew);
1223     wire.SetVertex(aVertNew);
1224     return Standard_True;
1225   }
1226   const Handle(ShapeExtend_WireData) sewd = wire.WireData();
1227   
1228   Standard_Integer nbe = sewd->NbEdges();
1229   
1230   //:abv 31.10.01: for closed mode
1231   Standard_Integer closedDir = 0;
1232   if ( myClosedMode ) {
1233     if ( myUClosed && Abs ( line.Direction().X() ) < ::Precision::PConfusion() ) 
1234       closedDir = -1;
1235     else if ( myVClosed && Abs ( line.Direction().Y() ) < ::Precision::PConfusion() ) 
1236       closedDir = 1;
1237   }
1238   Standard_Real halfPeriod = 0.5 * ( closedDir ? closedDir <0 ? myUPeriod : myVPeriod : 0. );
1239   
1240   //============================================
1241   // make intersections and collect all data on intersection points
1242   Standard_Integer firstCode=0, prevCode=0;
1243   gp_Pnt2d firstPos, prevPos;
1244   Standard_Real firstDev=0., prevDev=0.;
1245   for (Standard_Integer iedge = 1; iedge <= nbe; iedge++) {
1246     
1247     TopoDS_Edge E= sewd->Edge ( iedge );
1248     Standard_Boolean isreversed = ( E.Orientation() == TopAbs_REVERSED );
1249       
1250     Standard_Real f, l;
1251     Handle(Geom2d_Curve) c2d;
1252     if ( ! sae.PCurve ( E, myFace, c2d, f, l, Standard_False ) ) continue;
1253       
1254     // get end points 
1255     gp_Pnt2d posf = c2d->Value(f), posl = c2d->Value(l);
1256     gp_XY pppf = posf.XY(), pppl = posl.XY();
1257     
1258     // In case of ClosedMode, adjust curve and end points to period on closed surface
1259     //:abv 16.10.01: Ziegler_CADDY01.sat -18: if pcurve is longer than period, 
1260     // ensure processing of all intersections
1261     Standard_Integer nbIter = 1;
1262     gp_Vec2d shiftNext(0.,0.);
1263     if ( myClosedMode ) {
1264       
1265       // get bounding box of pcurve
1266       ShapeAnalysis_Curve sac;
1267       Bnd_Box2d box;
1268       sac.FillBndBox ( c2d, f, l, 11, Standard_True, box );
1269       Standard_Real umin, vmin, umax, vmax;
1270       box.Get ( umin, vmin, umax, vmax );
1271         
1272       // compute shifts and adjust points adjust
1273       if ( closedDir < 0 ) {
1274         Standard_Real x = line.Location().X();
1275         Standard_Real shift = ShapeAnalysis::AdjustToPeriod ( umin, x-myUPeriod, x );
1276         if ( shift != 0. ) {
1277           c2d = Handle(Geom2d_Curve)::DownCast ( c2d->Copy() );
1278           gp_Vec2d V ( shift, 0. );
1279           c2d->Translate ( V );
1280           pppf.SetX ( pppf.X() + shift );
1281           pppl.SetX ( pppl.X() + shift );
1282         }
1283         shiftNext.SetX ( -myUPeriod );
1284         nbIter = (Standard_Integer)( 1 + Abs ( umax + shift - x ) / myUPeriod );
1285         shift = ShapeAnalysis::AdjustByPeriod ( posf.X(), x, myUPeriod );
1286         posf.SetX ( posf.X() + shift );
1287         shift = ShapeAnalysis::AdjustByPeriod ( posl.X(), x, myUPeriod );
1288         posl.SetX ( posl.X() + shift );
1289       }
1290       else if ( closedDir > 0 ) {
1291         Standard_Real y = line.Location().Y();
1292         Standard_Real shift = ShapeAnalysis::AdjustToPeriod ( vmin, y-myVPeriod, y );
1293         if ( shift != 0. ) {
1294           c2d = Handle(Geom2d_Curve)::DownCast ( c2d->Copy() );
1295           gp_Vec2d V ( 0., shift );
1296           c2d->Translate ( V );
1297           pppf.SetY ( pppf.Y() + shift );
1298           pppl.SetY ( pppl.Y() + shift );
1299         }
1300         shiftNext.SetY ( -myVPeriod );
1301         nbIter = (Standard_Integer)( 1 + Abs ( umax + shift - y ) / myVPeriod );
1302         shift = ShapeAnalysis::AdjustByPeriod ( posf.Y(), y, myVPeriod );
1303         posf.SetY ( posf.Y() + shift );
1304         shift = ShapeAnalysis::AdjustByPeriod ( posl.Y(), y, myVPeriod );
1305         posl.SetY ( posl.Y() + shift );
1306       }
1307     }
1308         
1309     // detect intersections at junction of two edges
1310     gp_Pnt2d pos = ( isreversed ? posl : posf );
1311     Standard_Real dev;
1312     Standard_Integer code = PointLinePosition ( pos, line, dev );
1313     if ( iedge ==1 ) { firstCode = code; firstPos = pos; firstDev = dev; }
1314     else if ( code == IOR_UNDEF || code != prevCode ) { 
1315       if ( ! closedDir || Abs ( dev - prevDev ) < halfPeriod ) {
1316         IntLinePar.Append ( ParamPointsOnLine ( pos, prevPos, line ) ); // !! - maybe compute exactly ?
1317         IntEdgePar.Append ( isreversed ? l : f );
1318         IntEdgeInd.Append ( iedge );
1319       }
1320     }
1321     
1322     // fill data on end point (for next edge)
1323     pos = ( isreversed ? posf : posl );
1324     prevCode = PointLinePosition ( pos, line, prevDev );
1325     prevPos = pos;
1326     
1327     // cycle with shift in order to track all possible intersections
1328     for ( Standard_Integer iter=1; iter <= nbIter; iter++ ) {
1329       
1330       // data for intersection
1331       IntRes2d_Domain iDom ( pppf, f, TOLINT, pppl, l, TOLINT );
1332       Geom2dAdaptor_Curve iGAC(c2d);
1333           
1334       // intersection
1335       Geom2dInt_GInter Inter;
1336       Inter.Perform ( jGAC, /*jDom,*/ iGAC, iDom, TOLINT, TOLINT );
1337     
1338       // Fill arrays with new intersection points
1339       if ( Inter.IsDone() ) {
1340
1341         Standard_Integer i;
1342         for ( i = 1; i <= Inter.NbPoints(); i++ ) {
1343           IntRes2d_IntersectionPoint IP = Inter.Point (i);
1344           IntLinePar.Append ( IP.ParamOnFirst() );
1345           IntEdgePar.Append ( IP.ParamOnSecond() );
1346         }
1347         for ( i = 1; i <= Inter.NbSegments(); i++ ) {
1348           IntRes2d_IntersectionSegment IS = Inter.Segment (i);
1349           if ( IS.HasFirstPoint() ) {
1350             IntRes2d_IntersectionPoint IP = IS.FirstPoint();
1351             IntLinePar.Append ( IP.ParamOnFirst() );
1352             IntEdgePar.Append ( IP.ParamOnSecond() );
1353           }
1354           if ( IS.HasLastPoint() ) {
1355             IntRes2d_IntersectionPoint IP = IS.LastPoint();
1356             IntLinePar.Append ( IP.ParamOnFirst() );
1357             IntEdgePar.Append ( IP.ParamOnSecond() );
1358           }
1359         }
1360       }
1361       
1362       if ( iter < nbIter ) {
1363         if ( iter == 1 ) c2d = Handle(Geom2d_Curve)::DownCast ( c2d->Copy() );
1364         pppf += shiftNext.XY();
1365         pppl += shiftNext.XY();
1366         c2d->Translate ( shiftNext );
1367       }
1368     }
1369       
1370     Standard_Integer start = IntEdgeInd.Length() + 1; // first of the new points
1371       
1372     // Move all points into range [f,l] (intersector sometimes gives params out of range)
1373     Standard_Integer i;
1374     for ( i = start; i <= IntEdgePar.Length(); i++ ) {
1375       if ( IntEdgePar(i) < f ) IntEdgePar.SetValue ( i, f );
1376       else if ( IntEdgePar(i) > l ) IntEdgePar.SetValue ( i, l );
1377     }
1378       
1379     // Sort by parameter on edge
1380     for ( i = IntEdgePar.Length(); i > start; i-- ) 
1381       for ( Standard_Integer j = start; j < i; j++ ) {
1382         if ( isreversed == (Standard_Boolean) ( IntEdgePar(j+1) < IntEdgePar(j) ) ) continue;
1383         IntLinePar.Exchange ( j, j+1 );
1384         IntEdgePar.Exchange ( j, j+1 );
1385       }
1386       
1387     // and fill indices
1388     for ( i = start; i <= IntEdgePar.Length(); i++ )
1389       IntEdgeInd.Append ( iedge );
1390     
1391     // Detect intersection at closing point 
1392     // Only wires which are not EXTERNAL are considered (as closed)
1393     if ( iedge == nbe && wire.Orientation() != TopAbs_EXTERNAL &&
1394         wire.Orientation() != TopAbs_INTERNAL &&
1395          ( prevCode == IOR_UNDEF || prevCode != firstCode ) ) {
1396       if ( ! closedDir || Abs ( firstDev - prevDev ) < halfPeriod ) {
1397         IntLinePar.Append ( ParamPointsOnLine ( pos, firstPos, line ) );
1398         IntEdgePar.Append ( isreversed ? f : l );
1399         IntEdgeInd.Append ( iedge );
1400       }
1401     }
1402   }
1403
1404   if ( IntEdgePar.Length() <1 ) {
1405     //pdn Defining position of wire. There is no intersection, so by any point.
1406     DefinePatchForWire ( wire, firstCode, isCutByU, cutIndex );
1407     return Standard_False; //pdn ??
1408   }
1409
1410   //======================================
1411   // Fill sequence of transition codes for intersection points
1412   TColStd_SequenceOfInteger IntCode;      // parameter of intersection point on line
1413   TColStd_SequenceOfInteger SegmentCodes; // classification codes for segments of wire
1414   
1415   // remove duplicated points to ensure correct results of ComputeCode
1416   Standard_Integer i, j = IntEdgePar.Length();
1417   if ( myClosedMode && j >1 ) {
1418     for ( i = 1; i <= IntEdgePar.Length();  ) {
1419       if ( i == j ) break;
1420       if ( IntEdgeInd(i) == IntEdgeInd(j) &&
1421            Abs ( IntEdgePar(i) - IntEdgePar(j) ) < ::Precision::PConfusion() ) {
1422         IntLinePar.Remove(i);
1423         IntEdgePar.Remove(i);
1424         IntEdgeInd.Remove(i);
1425         if ( j >i ) j--;
1426         continue;
1427       }
1428       else if ( nbe ==1 || IntEdgeInd(i) == (IntEdgeInd(j)%nbe)+1 ) {
1429         TopoDS_Edge E1 = sewd->Edge ( IntEdgeInd(j) );
1430         TopoDS_Edge E2 = sewd->Edge ( IntEdgeInd(i) );
1431         Standard_Real a1, b1, a2, b2;
1432         BRep_Tool::Range ( E1, myFace, a1, b1 );
1433         BRep_Tool::Range ( E2, myFace, a2, b2 );
1434         if ( Abs ( IntEdgePar(j) - ( E1.Orientation() == TopAbs_FORWARD ? b1 : a1 ) ) < ::Precision::PConfusion() &&
1435              Abs ( IntEdgePar(i) - ( E2.Orientation() == TopAbs_FORWARD ? a2 : b2 ) ) < ::Precision::PConfusion() ) {
1436           IntLinePar.Remove(i);
1437           IntEdgePar.Remove(i);
1438           IntEdgeInd.Remove(i);
1439           if ( j >i ) j--;
1440           continue;
1441         }
1442       }
1443       j=i++;
1444     }
1445   }
1446   
1447   // Compute segment codes (left side of line, right or tangential)
1448   for ( i=1; i <= IntEdgePar.Length(); i++ ) {
1449     j = ( i < IntEdgePar.Length() ? i + 1 : 1 );
1450     Standard_Integer code = ComputeCode ( sewd, line, IntEdgeInd(i), IntEdgeInd(j), 
1451                                           IntEdgePar(i), IntEdgePar(j),isnonmanifold );
1452     SegmentCodes.Append ( code );
1453   }
1454   
1455   // for EXTERNAL wire, i.e. another joint line, every point is double intersection
1456   if ( wire.Orientation() == TopAbs_EXTERNAL ) {
1457     for ( i=1; i <= IntEdgePar.Length(); i++ )
1458       IntCode.Append ( ITP_TANG | IOR_BOTH );
1459   }
1460   // For real (closed) wire, analyze tangencies
1461   else {
1462     if(wire.Orientation() != TopAbs_INTERNAL) {
1463     // Two consecutive tangential segments are considered as one, merge them.
1464     for ( i=1; i <= IntEdgePar.Length(); i++ ) {
1465       j = ( i > 1 ? i-1 : IntEdgePar.Length() );
1466
1467       int k = ( i < IntEdgePar.Length() ? i + 1 : 1 ); // [ACIS22539]
1468
1469       if ( SegmentCodes(j) == IOR_UNDEF && 
1470            SegmentCodes(i) == IOR_UNDEF ) {
1471
1472         // Very specific case when the constructed seam edge
1473         // overlaps with spur edge [ACIS22539]
1474         if (myClosedMode && (IntLinePar(i) - IntLinePar(j)) * (IntLinePar(k) - IntLinePar(i)) <= 0. )
1475           continue;
1476
1477         IntEdgeInd.Remove(i);
1478         IntEdgePar.Remove(i);
1479         IntLinePar.Remove(i);
1480         SegmentCodes.Remove(i);
1481         i--;
1482       }
1483     }
1484     }
1485     //pdn exit if all split points removed
1486     if ( IntEdgePar.Length() <1 ) {
1487       //DefinePatchForWire ( wire, firstCode, isCutByU, cutIndex );
1488       return Standard_False; //pdn ??
1489     }
1490     
1491     // Analyze type of intersection point and encode it
1492     // Three kinds of points (ITP): clear intersection, tangency in-point,
1493     // beginning and end of tangential segment.
1494     // Orientation (IOR) tells on which side of line edge crosses it
1495     j = IntEdgePar.Length();
1496     for ( i=1; i <= IntEdgePar.Length(); j = i++ ) {
1497       Standard_Integer codej = SegmentCodes(j);
1498       Standard_Integer codei = SegmentCodes(i);
1499       if ( myClosedMode ) {
1500         if ( ( codej & IOR_BOTH ) == IOR_BOTH ) //IOR_LEFT : IOR_RIGHT
1501           codej = ( codej & IOR_POS ? IOR_RIGHT : IOR_LEFT );
1502         if ( ( codei & IOR_BOTH ) == IOR_BOTH ) //IOR_RIGHT : IOR_LEFT
1503           codei = ( codei & IOR_POS ? IOR_LEFT : IOR_RIGHT );
1504       }
1505       Standard_Integer ipcode = ( codej | codei );
1506       if ( codej == IOR_UNDEF ) { // previous segment was tangency
1507             if ( IntLinePar(i) > IntLinePar (j) ) 
1508              ipcode |= ITP_ENDSEG; // end of segment
1509             else ipcode |= ITP_BEGSEG; // beginning of segment
1510       }
1511       else if ( codei == IOR_UNDEF ) {     // current segment is tangency
1512         if ( IntLinePar ( i < IntLinePar.Length() ? i+1 : 1 ) > IntLinePar(i) ) 
1513              ipcode |= ITP_BEGSEG; // beginning of segment
1514             else ipcode |= ITP_ENDSEG; // end of segment
1515       }
1516       //internal wire can be only tangent
1517       else if ( i == j ) ipcode |= ( ( ipcode & IOR_BOTH ) == IOR_BOTH && !isnonmanifold ? ITP_INTER : ITP_TANG );
1518       else if ( codei == codej || isnonmanifold) ipcode |= ITP_TANG; // tangency in-point
1519       else ipcode |= ITP_INTER; // standard crossing
1520       IntCode.Append ( ipcode );
1521     }
1522   }
1523   
1524   //=======================================
1525   // Split edges in the wire by intersection points and fill vertices array
1526   TopTools_SequenceOfShape IntVertices;
1527   wire = SplitWire ( wire, IntEdgeInd, IntEdgePar, IntVertices, 
1528                      SegmentCodes, isCutByU, cutIndex );
1529   
1530   // add all data to input arrays
1531   for ( i=1; i <= IntLinePar.Length(); i++ ) {
1532     SplitLinePar.Append ( IntLinePar(i) );
1533     SplitLineCode.Append ( IntCode(i) );
1534     SplitLineVertex.Append ( IntVertices(i) );
1535   }
1536   
1537   return Standard_True;
1538 }
1539
1540
1541 //=======================================================================
1542 //function : SplitByLine
1543 //purpose  : 
1544 //=======================================================================
1545
1546 void ShapeFix_ComposeShell::SplitByLine (ShapeFix_SequenceOfWireSegment &wires,
1547                                          const gp_Lin2d &line,
1548                                          const Standard_Boolean isCutByU,
1549                                          const Standard_Integer cutIndex)
1550 {
1551   TColStd_SequenceOfReal SplitLinePar;
1552   TColStd_SequenceOfInteger SplitLineCode;
1553   TopTools_SequenceOfShape SplitLineVertex;
1554   
1555   // split wires one by one, collecting data on intersection points
1556   Standard_Integer i; // svv #1
1557   for ( i=1; i <= wires.Length(); i++ ) {
1558     SplitByLine ( wires(i), line, isCutByU, cutIndex, 
1559                   SplitLinePar, SplitLineCode, SplitLineVertex );
1560   }
1561   
1562   // sort intersection points along parameter on cutting line
1563   for ( i = SplitLinePar.Length(); i >1; i-- ) 
1564     for ( Standard_Integer j=1; j < i; j++ ) {
1565       if ( SplitLinePar(j) > SplitLinePar(j+1) ) {
1566         SplitLinePar.Exchange ( j, j+1 );
1567         SplitLineCode.Exchange ( j, j+1 );
1568         SplitLineVertex.Exchange ( j, j+1 );
1569       }
1570     }
1571
1572   // merge null-length tangential segments into one-point tangencies or intersections
1573   for ( i = 1; i < SplitLinePar.Length(); i++ ) {
1574     if ( Abs ( SplitLinePar(i+1) - SplitLinePar(i) ) > ::Precision::PConfusion() ) continue;
1575     if ( ( SplitLineCode(i) & ITP_ENDSEG &&
1576            SplitLineCode(i+1) & ITP_BEGSEG ) ||
1577          ( SplitLineCode(i) & ITP_BEGSEG &&
1578            SplitLineCode(i+1) & ITP_ENDSEG ) ) {
1579       Standard_Integer code = ( SplitLineCode(i) | SplitLineCode(i+1) ) & IOR_BOTH;
1580       SplitLineCode.SetValue ( i, code | ( code == IOR_BOTH ? ITP_INTER : ITP_TANG ) );
1581       SplitLinePar.Remove(i+1);
1582       SplitLineCode.Remove(i+1);
1583       SplitLineVertex.Remove(i+1);
1584     }
1585   }
1586
1587   // go along line, split it by intersection points and create edges 
1588   // (only for internal parts, in particular not for tangential segments)
1589   BRep_Builder B;
1590   Standard_Integer parity = 0;     // 0 - out, 1 - in
1591   Standard_Integer halfparity = 0; // left/right for tangential segments
1592   Standard_Integer tanglevel = 0;  // tangency nesting level
1593   for ( i = 1; i <= SplitLinePar.Length(); i++ ) {
1594     Standard_Integer code = SplitLineCode(i);
1595     Standard_Boolean interior = ( ! tanglevel && parity % 2 ); // create an edge
1596     if ( code & ITP_INTER ) { // crossing
1597       parity++;
1598     }
1599     else if ( code & ITP_BEGSEG ) { // beginning of tangential segment
1600       tanglevel++;
1601       if ( ! halfparity ) halfparity = ( code & IOR_BOTH );
1602       else if ( halfparity != ( code & IOR_BOTH ) ) parity++;
1603     }
1604     else if ( code & ITP_ENDSEG ) { // end of tangential segment
1605       tanglevel--;
1606       if ( ! halfparity ) halfparity = ( code & IOR_BOTH );
1607       else if ( halfparity != ( code & IOR_BOTH ) ) parity++;
1608     }
1609     if ( tanglevel <0 ) {
1610 //      myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL4 );
1611 #ifdef DEB
1612       cout << "Warning: ShapeFix_ComposeShell::SplitByLine: tangency level <0 !" << endl;
1613 #endif
1614     }
1615     if ( ! interior ) continue;
1616     
1617     // apply context to vertices (to perform replacing/merging vertices)
1618 //smh#8
1619     TopoDS_Shape tmpV1 = Context()->Apply ( SplitLineVertex(i-1) );
1620     TopoDS_Shape tmpV2 = Context()->Apply ( SplitLineVertex(i) );
1621     TopoDS_Vertex V1 = TopoDS::Vertex ( tmpV1 );
1622     TopoDS_Vertex V2 = TopoDS::Vertex ( tmpV2 );
1623     // protection against creating null-length edges
1624     if ( SplitLinePar(i) - SplitLinePar(i-1) < ::Precision::PConfusion() ) {
1625
1626 #ifdef DEB
1627       cout << "Info: ShapeFix_ComposeShell::SplitByLine: Short segment ignored" << endl;
1628 #endif
1629       if ( ! V1.IsSame ( V2 ) ) { // merge coincident vertices
1630         ShapeBuild_Vertex sbv;
1631         TopoDS_Vertex V = sbv.CombineVertex ( V1, V2 );
1632         Context()->Replace ( V1, V.Oriented ( V1.Orientation() ) );
1633         Context()->Replace ( V2, V.Oriented ( V2.Orientation() ) );
1634         V1 = V2 = V;
1635 #ifdef DEB
1636         cout << "Info: ShapeFix_ComposeShell::SplitByLine: Coincided vertices merged" << endl;
1637 #endif
1638       }
1639       continue;
1640     }
1641
1642     // create an edge (without 3d curve), put it in wire segment and add to sequence
1643     // NOTE: i here is always >1
1644     TopoDS_Edge edge;
1645     B.MakeEdge ( edge );
1646     V1.Orientation ( TopAbs_FORWARD );
1647     V2.Orientation ( TopAbs_REVERSED );
1648     B.Add ( edge, V1 );
1649     B.Add ( edge, V2 );
1650     Handle(Geom2d_Line) Lin1 = new Geom2d_Line ( line );
1651     Handle(Geom2d_Line) Lin2 = new Geom2d_Line ( line );
1652     B.UpdateEdge ( edge, Lin1, Lin2, myFace, ::Precision::Confusion() );
1653     B.Range ( edge, myFace, SplitLinePar(i-1), SplitLinePar(i) );
1654     
1655     Handle(ShapeExtend_WireData) sbwd = new ShapeExtend_WireData;
1656     sbwd->Add ( edge );
1657     ShapeFix_WireSegment seg ( sbwd, TopAbs_EXTERNAL );
1658     
1659     // set patch indices
1660     DefinePatch ( seg, IOR_UNDEF, isCutByU, cutIndex );
1661     if ( ! isCutByU ) {
1662       seg.DefineIUMin ( 1, GetPatchIndex ( SplitLinePar(i-1)+::Precision::PConfusion(),
1663                                            myGrid->UJointValues(), myUClosed ) );
1664       seg.DefineIUMax ( 1, GetPatchIndex ( SplitLinePar(i)-::Precision::PConfusion(),
1665                                            myGrid->UJointValues(), myUClosed ) + 1 );
1666     }
1667     else {
1668       seg.DefineIVMin ( 1, GetPatchIndex ( SplitLinePar(i-1)+::Precision::PConfusion(),
1669                                            myGrid->VJointValues(), myVClosed ) );
1670       seg.DefineIVMax ( 1, GetPatchIndex ( SplitLinePar(i)-::Precision::PConfusion(),
1671                                            myGrid->VJointValues(), myVClosed ) + 1 );
1672     }
1673                                  
1674     wires.Append ( seg );
1675   }
1676   if ( parity % 2 ) {
1677     myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL4 );
1678 #ifdef DEB
1679     cout << "Error: ShapeFix_ComposeShell::SplitByLine: parity error" << endl;
1680 #endif
1681   }
1682   
1683   // Apply context to all wires to perform all recorded replacements/merging
1684   for ( i=1; i <= wires.Length(); i++ ) {
1685     for ( Standard_Integer j=1; j <= wires(i).NbEdges(); ) 
1686       j += ApplyContext ( wires(i), j, Context() );
1687   }
1688 }
1689     
1690
1691 //=======================================================================
1692 //function : SplitByGrid
1693 //purpose  : 
1694 //=======================================================================
1695
1696 void ShapeFix_ComposeShell::SplitByGrid (ShapeFix_SequenceOfWireSegment &seqw) 
1697 {
1698   // process splitting by U- anv V-seams (i.e. U=const and V=const curves)
1699   // closed composite surface is processed as periodic
1700   Standard_Real Uf,Ul,Vf,Vl;
1701   BRepTools::UVBounds(myFace,Uf,Ul,Vf,Vl);
1702   Standard_Real Umin,Umax,Vmin,Vmax;
1703   myGrid->Bounds(Umin,Umax,Vmin,Vmax);
1704   Standard_Real pprec = ::Precision::PConfusion();
1705   
1706   // split by u lines
1707   Standard_Integer i; // svv #1
1708   for ( i = ( myUClosed ? 1 : 2 ); i <= myGrid->NbUPatches(); i++ ) {
1709     gp_Pnt2d pos ( myGrid->UJointValue(i), 0. ); // 0. - for infinite ranges: myGrid->VJointValue(1) ;
1710     gp_Lin2d line ( pos, gp_Dir2d ( 0., 1. ) );
1711     if ( ! myClosedMode && myUClosed ) {
1712       Standard_Real period = Umax - Umin;
1713       Standard_Real X = pos.X();
1714       Standard_Real sh = ShapeAnalysis::AdjustToPeriod(X,Uf, Uf+period);
1715       for( ; X+sh <= Ul+pprec; sh += period ) {
1716         gp_Lin2d ln = line.Translated(gp_Vec2d(sh,0));
1717         Standard_Integer cutIndex = GetPatchIndex ( X+sh+pprec, myGrid->UJointValues(), myUClosed );
1718         SplitByLine ( seqw, ln, Standard_True, cutIndex );
1719       }   
1720     }
1721     else
1722       SplitByLine ( seqw, line, Standard_True, i );
1723   }
1724   
1725   // split by v lines
1726   for ( i = ( myVClosed ? 1 : 2 ); i <= myGrid->NbVPatches(); i++ ) {
1727     gp_Pnt2d pos ( 0., myGrid->VJointValue(i) );
1728     gp_Lin2d line ( pos, gp_Dir2d ( 1., 0. ) );
1729     if ( ! myClosedMode && myVClosed ) {
1730       Standard_Real period = Vmax - Vmin;
1731       Standard_Real Y = pos.Y();
1732       Standard_Real sh = ShapeAnalysis::AdjustToPeriod(Y,Vf, Vf+period);
1733       for( ; Y+sh <= Vl+pprec; sh += period) {
1734         gp_Lin2d ln = line.Translated(gp_Vec2d(0,sh));
1735         Standard_Integer cutIndex = GetPatchIndex ( Y+sh+pprec, myGrid->VJointValues(), myVClosed );
1736         SplitByLine ( seqw, ln, Standard_False, cutIndex );
1737       }   
1738     }
1739     else 
1740       SplitByLine ( seqw, line, Standard_False, i );
1741   }
1742
1743   // limit patch indices to be in range of grid (extended for periodic)
1744   Standard_Integer iumin = GetPatchIndex ( Uf+pprec, myGrid->UJointValues(), myUClosed );
1745   Standard_Integer iumax = GetPatchIndex ( Ul-pprec, myGrid->UJointValues(), myUClosed ) + 1;
1746   for ( i=1; i <= seqw.Length(); i++ ) {
1747     ShapeFix_WireSegment &wire = seqw(i);
1748     for ( Standard_Integer j=1; j <= wire.NbEdges(); j++ ) {
1749       wire.DefineIUMin ( j, iumin );
1750       wire.DefineIUMax ( j, iumax );
1751     }
1752   }
1753   Standard_Integer ivmin = GetPatchIndex ( Vf+pprec, myGrid->VJointValues(), myVClosed );
1754   Standard_Integer ivmax = GetPatchIndex ( Vl-pprec, myGrid->VJointValues(), myVClosed ) + 1;
1755   for ( i=1; i <= seqw.Length(); i++ ) {
1756     ShapeFix_WireSegment &wire = seqw(i);
1757     for ( Standard_Integer j=1; j <= wire.NbEdges(); j++ ) {
1758       wire.DefineIVMin ( j, ivmin );
1759       wire.DefineIVMax ( j, ivmax );
1760     }
1761   }
1762 }
1763     
1764
1765 //=======================================================================
1766 //function : BreakWires
1767 //purpose  : 
1768 //=======================================================================
1769
1770 void ShapeFix_ComposeShell::BreakWires (ShapeFix_SequenceOfWireSegment &seqw) 
1771 {
1772   
1773   // split all the wires by vertices
1774   TopTools_MapOfShape splitVertices;
1775   ShapeAnalysis_Edge sae;
1776   
1777   // first collect splitting vertices
1778   Standard_Integer i; // svv #1
1779   for ( i=1; i <= seqw.Length(); i++ ) {
1780     TopAbs_Orientation ori_wire = seqw(i).Orientation();
1781     if ( ori_wire != TopAbs_EXTERNAL && 
1782         ori_wire != TopAbs_INTERNAL) continue;
1783     
1784     Handle(ShapeExtend_WireData) sbwd = seqw(i).WireData();
1785     for ( Standard_Integer j=1; j <= sbwd->NbEdges(); j++ ) {
1786       TopoDS_Edge edge = sbwd->Edge ( j );
1787       TopAbs_Orientation ori_edge = (ori_wire == TopAbs_EXTERNAL ? ori_wire : edge.Orientation());
1788       if(ori_edge == TopAbs_EXTERNAL) {
1789         splitVertices.Add ( sae.FirstVertex ( edge ) );
1790         splitVertices.Add ( sae.LastVertex ( edge ) );
1791       }
1792     }
1793   }
1794   
1795   // and then split each vire
1796   // Here each wire is supposed to be connected (while probably not closed)
1797   for ( i=1; i <= seqw.Length(); i++ ) {
1798     TopAbs_Orientation ori = seqw(i).Orientation();
1799     ShapeFix_WireSegment wire = seqw(i);
1800     if(wire.IsVertex())
1801       continue;
1802     Handle(ShapeExtend_WireData) sbwd = wire.WireData();
1803     
1804     // find first vertex for split
1805     Standard_Integer j; // svv #1
1806     for ( j=1; j <= sbwd->NbEdges(); j++ ) {
1807       TopoDS_Vertex V = sae.FirstVertex ( sbwd->Edge(j) );
1808       if ( splitVertices.Contains ( V ) ) break;
1809     }
1810     if ( j > sbwd->NbEdges() ) continue; // splitting not needed
1811     
1812     // if first split of closed edge is not its start, make permutation
1813     Standard_Integer shift = 0;
1814     if ( j >1 && ! myClosedMode && wire.IsClosed() ) {
1815       TopoDS_Vertex V = sae.FirstVertex ( sbwd->Edge(1) );
1816       if ( ! splitVertices.Contains ( V ) )
1817         shift = j - 1;
1818 //      wire.SetLast ( j-1 );
1819     }
1820
1821     // perform splitting
1822     Standard_Integer nbnew = 0;
1823     ShapeFix_WireSegment newwire;
1824     TopAbs_Orientation curOri = ori;
1825     for ( Standard_Integer ind=1; ind <= sbwd->NbEdges(); ind++ ) {
1826       j = 1 + ( ind - 1 + shift ) % sbwd->NbEdges();
1827       TopoDS_Edge edge = sbwd->Edge(j);
1828       TopoDS_Vertex V = sae.FirstVertex ( edge );
1829       if ( ind==1 || splitVertices.Contains ( V ) ) {
1830         if ( newwire.NbEdges() ) {
1831           newwire.Orientation ( curOri );
1832 //        ShapeFix_WireSegment seg ( newwire, ori );
1833           seqw.InsertBefore ( i++, newwire );
1834           nbnew++;
1835         }
1836         newwire.Clear();
1837         curOri = ori;
1838       }
1839       Standard_Integer iumin, iumax, ivmin, ivmax;
1840       wire.GetPatchIndex ( j, iumin, iumax, ivmin, ivmax );
1841       if(ori == TopAbs_INTERNAL && edge.Orientation() == TopAbs_EXTERNAL ) {
1842             curOri = TopAbs_EXTERNAL;
1843             edge.Orientation(TopAbs_FORWARD);
1844         nbnew++;
1845       }
1846         
1847       newwire.AddEdge ( 0, edge, iumin, iumax, ivmin, ivmax );
1848     }
1849     if ( nbnew ) {
1850       newwire.Orientation ( curOri );
1851 //      ShapeFix_WireSegment seg ( newwire, ori );
1852       seqw.SetValue ( i, newwire );
1853     }
1854   }
1855 }
1856
1857
1858 //=======================================================================
1859 //function : IsShortSegment
1860 //purpose  : auxilary
1861 //=======================================================================
1862 // BUC60035 2053: check if wire segment is very short (in order not to skip it)
1863 // 0  - long
1864 // 1  - short even in 2d (to be taken always)
1865 // -1 - short in 3d but not in 2d (to be checked after algo and atteching to 
1866 //      another wire if alone)
1867 static Standard_Integer IsShortSegment (const ShapeFix_WireSegment &seg,
1868                                         const TopoDS_Face myFace,
1869                                         const Handle(Geom_Surface)& myGrid,
1870                                         const TopLoc_Location &myLoc,
1871                                         const Standard_Real UResolution,
1872                                         const Standard_Real VResolution)
1873 {
1874   TopoDS_Vertex Vf = seg.FirstVertex();
1875   if ( ! Vf.IsSame ( seg.LastVertex() ) ) return Standard_False;
1876
1877   gp_Pnt pnt = BRep_Tool::Pnt(Vf);
1878   Standard_Real tol = BRep_Tool::Tolerance(Vf);
1879   Standard_Real tol2 = tol*tol;
1880
1881   Standard_Integer code = 1;
1882   ShapeAnalysis_Edge sae;
1883   Handle(ShapeExtend_WireData) sbwd = seg.WireData();
1884   for ( Standard_Integer i=1; i <= sbwd->NbEdges(); i++ ) {
1885     TopoDS_Edge edge = sbwd->Edge ( i );
1886     if ( ! Vf.IsSame ( sae.LastVertex ( edge ) ) ) return Standard_False;
1887     Handle(Geom2d_Curve) c2d;
1888     Standard_Real f, l;
1889     if ( ! sae.PCurve ( edge, myFace, c2d, f, l ) ) continue;
1890
1891     // check 2d
1892     gp_Pnt2d endPnt = c2d->Value(l);
1893     gp_Pnt2d midPnt = c2d->Value((f+l)/2);
1894     if ( ! IsCoincided ( endPnt, midPnt, UResolution, VResolution, tol ) ) code = -1;
1895
1896     // check 3d
1897     gp_Pnt midPnt3d = myGrid->Value(midPnt.X(),midPnt.Y());
1898     if ( ! myLoc.IsIdentity() ) midPnt3d.Transform ( myLoc.Transformation() );
1899     if ( midPnt3d.SquareDistance(pnt) > tol2) return 0;
1900   }
1901   return code;
1902 }
1903
1904
1905 //=======================================================================
1906 //function : IsSamePatch
1907 //purpose  : auxilary
1908 //=======================================================================
1909 static Standard_Boolean IsSamePatch (const ShapeFix_WireSegment wire, 
1910                                      const Standard_Integer NU, 
1911                                      const Standard_Integer NV,
1912                                      Standard_Integer &iumin,
1913                                      Standard_Integer &iumax,
1914                                      Standard_Integer &ivmin,
1915                                      Standard_Integer &ivmax,
1916                                      const Standard_Boolean extend=Standard_False)
1917 {
1918   // get patch indices for current segment
1919   Standard_Integer jumin, jumax, jvmin, jvmax;
1920   wire.GetPatchIndex ( 1, jumin, jumax, jvmin, jvmax );
1921   
1922   // shift to the same period
1923   Standard_Integer du=0, dv=0; 
1924   if ( jumin - iumin > NU )      du =-( jumin - iumin ) / NU;
1925   else if ( iumin - jumin > NU ) du = ( iumin - jumin ) / NU;
1926   if ( jvmin - ivmin > NV )      dv =-( jvmin - ivmin ) / NV;
1927   else if ( ivmin - jvmin > NV ) dv = ( ivmin - jvmin ) / NV;
1928   if ( du ) { jumin += du * NU; jumax += du * NU; }
1929   if ( dv ) { jvmin += dv * NV; jvmax += dv * NV; }
1930   
1931   // compute common (extended) indices
1932   Standard_Integer iun = Min ( iumin, jumin );
1933   Standard_Integer iux = Max ( iumax, jumax );
1934   Standard_Integer ivn = Min ( ivmin, jvmin );
1935   Standard_Integer ivx = Max ( ivmax, jvmax );
1936   Standard_Boolean ok = ( iun == iux || iun+1 == iux ) &&
1937                         ( ivn == ivx || ivn+1 == ivx );
1938   if ( ok && extend ) { iumin = iun; iumax = iux; ivmin = ivn; ivmax = ivx; }
1939   return ok;
1940 }
1941
1942
1943 //=======================================================================
1944 //function : CollectWires
1945 //purpose  : 
1946 //=======================================================================
1947
1948 void ShapeFix_ComposeShell::CollectWires (ShapeFix_SequenceOfWireSegment &wires,
1949                                           ShapeFix_SequenceOfWireSegment &seqw) 
1950 {
1951   
1952   ShapeAnalysis_Edge sae;
1953   Standard_Integer i; // svv #1
1954   // Collect information on short closed segments
1955   TColStd_Array1OfInteger shorts(1,seqw.Length());
1956   for ( i=1; i <= seqw.Length(); i++ ) {
1957     if(seqw(i).IsVertex() || seqw(i).Orientation() == TopAbs_INTERNAL) {
1958       wires.Append(seqw(i));
1959       seqw.Remove(i);
1960       i--;
1961       continue;
1962     }
1963 #ifdef DEB
1964     for ( Standard_Integer k=1; ! myClosedMode && k <= seqw(i).NbEdges(); k++ ) 
1965       if ( ! seqw(i).CheckPatchIndex ( k ) ) {;} //break;
1966 //      cout << "Warning: ShapeFix_ComposeShell::CollectWires: Wrong patch indices" << endl;
1967 #endif
1968     Standard_Integer isshort = IsShortSegment ( seqw(i), myFace, myGrid, myLoc,
1969                                                 myUResolution, myVResolution );
1970     shorts.SetValue ( i, isshort );
1971     if ( isshort >0 && 
1972          ( seqw(i).Orientation() == TopAbs_EXTERNAL ||
1973            ( seqw(i).NbEdges() == 1 && //:abv 13.05.02: OCC320 - remove if degenerated 
1974              BRep_Tool::Degenerated ( seqw(i).Edge(1) ) ) ) ) {
1975 #ifdef DEB
1976       cout << "Info: ShapeFix_ComposeShell::CollectWires: Short segment ignored" << endl;
1977 #endif
1978       seqw(i).Orientation ( TopAbs_INTERNAL );
1979     }
1980   }
1981   
1982   Handle(ShapeExtend_WireData) sbwd;
1983   gp_Pnt2d endPnt, firstPnt;
1984   gp_Vec2d endTan, firstTan;
1985   TopoDS_Vertex firstV, endV;
1986   TopoDS_Edge firstEdge, lastEdge;
1987   Standard_Real tol = 0;
1988   Standard_Integer iumin, iumax, ivmin, ivmax;
1989   Standard_Real dsu=0., dsv=0.;
1990   Standard_Boolean canBeClosed = Standard_False;
1991   while ( 1 ) {
1992     Standard_Integer index = 0;
1993     Standard_Boolean misoriented = Standard_True, samepatch = Standard_False;
1994     Standard_Boolean reverse = Standard_False, connected = Standard_False;
1995     Standard_Real angle = -M_PI, mindist = RealLast();
1996     Standard_Integer weigth = 0;
1997     Standard_Real shiftu=0., shiftv=0.;
1998
1999     // find next segment to connect (or first if sbwd is NULL)
2000     for ( i = 1; i <= seqw.Length(); i++ ) {
2001       ShapeFix_WireSegment seg = seqw.Value(i);
2002       if(seg.IsVertex())
2003         continue;
2004       TopAbs_Orientation anOr = seg.Orientation();
2005       if ( anOr == TopAbs_INTERNAL ) continue;
2006
2007       // for first segment, take any
2008       if ( sbwd.IsNull() ) { 
2009         if ( shorts(i) >0 ) continue;
2010         if ( anOr == TopAbs_EXTERNAL ) continue;
2011         if ( anOr == TopAbs_FORWARD ) reverse = Standard_True;
2012         index = i;
2013         seg.GetPatchIndex ( 1, iumin, iumax, ivmin, ivmax );
2014         misoriented = Standard_False;
2015         dsu = dsv = 0.;
2016         break;
2017       }
2018
2019       // check whether current segment is on the same patch with previous
2020       Standard_Integer sp = ( myClosedMode || // no indexation in closed mode
2021                               IsSamePatch ( seg, myGrid->NbUPatches(), myGrid->NbVPatches(), 
2022                                             iumin, iumax, ivmin, ivmax ) );
2023
2024       // not same patch has lowest priority
2025       if ( ! sp && ( canBeClosed || ( index && samepatch ) ) ) continue;
2026       
2027       // try to connect, with the following priorities:
2028       // The name of property      Weigth:
2029       // sharing vertex            auto
2030       // samepatch = 1             16
2031       // ! sameedge                auto
2032       // misorientation = 0        8
2033       // connected in 2d           4
2034       // distance                  2
2035       // short                     auto
2036       // angle ->> PI              1
2037       Handle(ShapeExtend_WireData) wire = seg.WireData();
2038       for ( Standard_Integer j=0; j <2; j++ ) {
2039         if ( ! endV.IsSame ( j ? seg.LastVertex() : seg.FirstVertex() ) ) continue;
2040
2041         // check for misorientation only if nothing better is found
2042         Standard_Integer misor = ( anOr == ( j ? TopAbs_REVERSED : TopAbs_FORWARD ) );
2043 //      if ( misor ) continue; // temporarily, to be improved
2044
2045         // returning back by the same edge is lowest priority
2046         if ( lastEdge.IsSame ( wire->Edge ( j ? wire->NbEdges() : 1 ) ) ) {
2047           if ( ! index && ! canBeClosed ) { // || ( sp && ! samepatch ) ) { 
2048             index = i; 
2049             reverse = j; 
2050             connected = Standard_True; 
2051             misoriented = misor;
2052             samepatch = sp;
2053             weigth = ( sp ? 16 : 0 ) + ( connected ? 8 : 0 ) + (misor==0 ? 4 : 0);
2054             dsu = dsv = 0.;
2055           }
2056           continue;
2057         }
2058         
2059         // compute starting tangent
2060         gp_Pnt2d lPnt;
2061         gp_Vec2d lVec;
2062         Standard_Integer k;
2063         Standard_Real edgeTol = 0;
2064         for ( k=1; k <= wire->NbEdges(); k++ ) {
2065           TopoDS_Shape tmpE = wire->Edge(wire->NbEdges()-k+1).Reversed();
2066           TopoDS_Edge edge = ( j ? TopoDS::Edge ( tmpE ) : 
2067                                    wire->Edge(k) );
2068           edgeTol = BRep_Tool::Tolerance ( edge );
2069           //if ( sae.GetEndTangent2d ( edge, myFace, Standard_False, lPnt, lVec ) ) break;
2070           if ( sae.GetEndTangent2d ( edge, myFace, Standard_False, lPnt, lVec, 1.e-3 ) ) break;
2071         }
2072         if ( k > wire->NbEdges() ) myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
2073         
2074         if ( myClosedMode ) {
2075           if ( myUClosed ) {
2076             shiftu = ShapeAnalysis::AdjustByPeriod ( lPnt.X(), endPnt.X(), myUPeriod );
2077             lPnt.SetX ( lPnt.X() + shiftu );
2078           }
2079           if ( myVClosed ) {
2080             shiftv = ShapeAnalysis::AdjustByPeriod ( lPnt.Y(), endPnt.Y(), myVPeriod );
2081             lPnt.SetY ( lPnt.Y() + shiftv );
2082           }
2083         }
2084         
2085         // short segment is to be taken with highest priority by angle
2086         Standard_Real ang = ( shorts(i) >0 ? M_PI : endTan.Angle ( lVec ) );
2087         if ( myClosedMode && shorts(i) <=0 && M_PI-ang < ::Precision::Angular() )
2088           ang = 0.; // abv 21 Mar 00: trj3_s1-md-214.stp #2471: avoid going back
2089         // abv 05 Feb 02: face from Parasolid: use tolerance of edges for check
2090         // for coincidence (instead of vertex tolerance) in order 
2091         // this check to be in agreement with check for position of wire segments
2092         // thus avoiding bad effects on overlapping edges
2093         Standard_Real ctol = Max ( edgeTol, BRep_Tool::Tolerance(lastEdge) );
2094         Standard_Boolean conn = IsCoincided ( endPnt, lPnt, myUResolution, 
2095                                               myVResolution, ctol );
2096         Standard_Real dist = endPnt.SquareDistance ( lPnt );
2097         
2098         // check if case is better than last found
2099         
2100         Standard_Integer w1 = ( sp ? 16 : 0 ) + ( conn ? 4 : 0 ) + (misor==0 ? 8 : 0);
2101         Standard_Integer tail1 = ( !conn &&     (dist < mindist) ? 2 : 0) + (ang > angle ? 1 : 0);
2102         Standard_Integer tail2 = ( !connected &&(dist > mindist) ? 2 : 0) + (ang < angle ? 1 : 0);
2103         if(w1+tail1 <= weigth+tail2)
2104           continue;
2105                 
2106         index = i; 
2107         reverse = j; 
2108         angle = ang;
2109         mindist = dist;
2110         connected = conn;
2111         misoriented = misor;
2112         samepatch = sp;
2113         weigth = w1;
2114         dsu = shiftu;
2115         dsv = shiftv;
2116       }
2117     }
2118
2119     // if next segment found, connect it
2120     if ( index ) {
2121       if(misoriented) 
2122         myInvertEdgeStatus = Standard_True;
2123       ShapeFix_WireSegment seg = seqw.Value(index);
2124       if ( sbwd.IsNull() ) sbwd = new ShapeExtend_WireData;
2125       else if ( samepatch ) { // extend patch indices
2126             IsSamePatch ( seg, myGrid->NbUPatches(), myGrid->NbVPatches(), 
2127                       iumin, iumax, ivmin, ivmax, Standard_True );
2128       }
2129 //      TopAbs_Orientation or = seg.Orientation();
2130       if ( ! reverse ) sbwd->Add ( seg.WireData() );
2131       else {
2132         Handle(ShapeExtend_WireData) wire = new ShapeExtend_WireData;
2133         wire->ManifoldMode() = Standard_False;
2134             wire->Add ( seg.WireData() );
2135         wire->Reverse ( myFace );
2136         sbwd->Add ( wire );
2137       }
2138       if ( seg.Orientation() == TopAbs_EXTERNAL ) 
2139            seg.Orientation ( reverse ? TopAbs_REVERSED : TopAbs_FORWARD );
2140       else seg.Orientation ( TopAbs_INTERNAL );
2141       seqw.SetValue ( index, seg );
2142     }
2143     else if ( sbwd.IsNull() ) break; // stop when no free segments available
2144     // for first segment, remember start point
2145     if ( endV.IsNull() ) {
2146       firstEdge = sbwd->Edge(1);
2147       firstV = sae.FirstVertex ( firstEdge );
2148       //sae.GetEndTangent2d ( firstEdge, myFace, Standard_False, firstPnt, firstTan );
2149       sae.GetEndTangent2d ( firstEdge, myFace, Standard_False, firstPnt, firstTan, 1.e-3 );
2150     }
2151  
2152     // update last edge and vertex (only for not short segments)
2153     Standard_Boolean doupdate = ( index && ( shorts(index) <=0 || endV.IsNull() ) );
2154     if ( doupdate ) {
2155       lastEdge = sbwd->Edge ( sbwd->NbEdges() );
2156       endV = sae.LastVertex ( lastEdge );
2157       tol = BRep_Tool::Tolerance ( endV );
2158       // BUC60035 2053: iteration on edges is required
2159       Standard_Integer k; // svv #1
2160       for ( k=sbwd->NbEdges(); k >=1; k-- )
2161         //if ( sae.GetEndTangent2d ( sbwd->Edge ( k ), myFace, Standard_True, endPnt, endTan ) ) 
2162         if ( sae.GetEndTangent2d ( sbwd->Edge ( k ), myFace, Standard_True, endPnt, endTan, 1.e-3 ) ) 
2163           break;
2164       if ( k <1 ) myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
2165       if ( myUClosed ) endPnt.SetX ( endPnt.X() + dsu );
2166       if ( myVClosed ) endPnt.SetY ( endPnt.Y() + dsv );
2167     }
2168
2169     // if closed or no next segment found, add to wires
2170     canBeClosed = endV.IsSame ( firstV );
2171     if ( ! index || ( canBeClosed && 
2172                       ! lastEdge.IsSame ( firstEdge ) &&  // cylinder (seam) 
2173                       IsCoincided ( endPnt, firstPnt, myUResolution, myVResolution, 2.* tol ) ) ) {
2174       if ( ! endV.IsSame ( sae.FirstVertex ( firstEdge ) ) ) {
2175         myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL5 );
2176 #ifdef DEB
2177         cout << "Warning: ShapeFix_ComposeShell::CollectWires: can't close wire" << endl;
2178 #endif
2179       }
2180       ShapeFix_WireSegment s ( sbwd, TopAbs_FORWARD );
2181       s.DefineIUMin(1,iumin);
2182       s.DefineIUMax(1,iumax);
2183       s.DefineIVMin(1,ivmin);
2184       s.DefineIVMax(1,ivmax);
2185       wires.Append ( s );
2186       sbwd.Nullify();
2187       endV.Nullify();
2188       canBeClosed = Standard_False;
2189     }
2190   }
2191
2192   // Check if some wires are short in 3d (lie entirely inside one vertex), 
2193   // and if yes try to merge them with others
2194   //pdn The short seqments are stil plased in "in" sequence.
2195
2196   for ( i=1; i <= seqw.Length(); i++ ) {
2197     if ( shorts(i) != 1 || seqw(i).IsVertex() || seqw(i).Orientation() == TopAbs_INTERNAL ||
2198          seqw(i).Orientation() == TopAbs_EXTERNAL ) continue;
2199     
2200     // find any other wire containing the same vertex
2201     Handle(ShapeExtend_WireData) wd = seqw(i).WireData();
2202     TopoDS_Vertex V = seqw(i).FirstVertex();
2203     Standard_Integer minj=0, mink=0;
2204     gp_Pnt2d p2d;
2205     gp_Vec2d vec;
2206     Standard_Real mindist=0;
2207     Standard_Boolean samepatch = Standard_False;
2208 //    Standard_Integer iumin, iumax, ivmin, ivmax;
2209     seqw(i).GetPatchIndex ( 1, iumin, iumax, ivmin, ivmax );
2210     sae.GetEndTangent2d ( wd->Edge(1), myFace, Standard_False, p2d, vec );
2211     for ( Standard_Integer j=1; j <= wires.Length(); j++ ) {
2212 //      if ( j == i ) continue;
2213 //      Handle(ShapeExtend_WireData) 
2214       sbwd = wires(j).WireData();
2215       for ( Standard_Integer k=1; k <= sbwd->NbEdges(); k++ ) {
2216         if ( !V.IsSame ( sae.FirstVertex ( sbwd->Edge(k) ) ) ) continue; //pdn I suppose that short segment should be inserted into the SAME vertex.
2217         
2218         Standard_Integer sp = IsSamePatch ( wires(j), myGrid->NbUPatches(), myGrid->NbVPatches(), 
2219                                            iumin, iumax, ivmin, ivmax );
2220         if ( samepatch && !sp) continue;
2221         gp_Pnt2d pp;
2222         sae.GetEndTangent2d ( sbwd->Edge(k), myFace, Standard_False, pp, vec );
2223         Standard_Real dist = pp.SquareDistance ( p2d );
2224         if ( sp && ! samepatch ) { minj = j; mink = k; mindist = dist;samepatch=sp;}
2225         else
2226           if ( ! minj || mindist > dist ) { minj = j; mink = k; mindist = dist;samepatch=sp; }
2227       }
2228     }
2229     if ( ! minj ) {
2230       //pdn add into resulting sequence!
2231       ShapeFix_WireSegment s ( wd, TopAbs_FORWARD );
2232       wires.Append ( s );
2233 #ifdef DEB
2234       cout <<"Warning: Short segment processed as separate wire"<<endl;
2235 #endif
2236       continue;
2237     }
2238       
2239     // and if found, merge
2240 //    Handle(ShapeExtend_WireData) 
2241     sbwd = wires(minj).WireData();
2242     for ( Standard_Integer n=1; n <= wd->NbEdges(); n++ )
2243       sbwd->Add ( wd->Edge(n), mink++ );
2244     
2245 //    wires.Remove ( i );
2246 //    i--;
2247   }
2248   
2249 }
2250   
2251 //=======================================================================
2252 //function : DispatchWires
2253 //purpose  : 
2254 //=======================================================================
2255
2256 static gp_Pnt2d GetMiddlePoint (const ShapeFix_WireSegment wire,
2257                                 const TopoDS_Face face)
2258 {
2259   if(wire.IsVertex()) {
2260     TopoDS_Vertex aV = wire.GetVertex();
2261     gp_Pnt aP3D = BRep_Tool::Pnt(aV );
2262     Handle(Geom_Surface) surf = BRep_Tool::Surface(face);
2263     Handle(ShapeAnalysis_Surface) aSurfTool = new ShapeAnalysis_Surface(surf);
2264     return aSurfTool->ValueOfUV(aP3D,Precision::Confusion());
2265   }
2266   Bnd_Box2d box;
2267   ShapeAnalysis_Edge sae;
2268   ShapeAnalysis_Curve sac;
2269   Handle(ShapeExtend_WireData) wd = wire.WireData();
2270   for(Standard_Integer i = 1; i <= wd->NbEdges(); i++) {
2271     TopoDS_Edge E = wd->Edge (i);
2272     Standard_Real cf,cl;
2273     Handle(Geom2d_Curve) c2d;
2274     if(sae.PCurve (E,face,c2d,cf,cl,Standard_False)) {
2275       sac.FillBndBox ( c2d, cf, cl, 3, Standard_False, box );
2276 //      box.Add(c2d->Value(cf));
2277 //      box.Add(c2d->Value(cl));
2278 //      box.Add(c2d->Value((cl+cf)/2.));
2279     }
2280   }
2281   if ( box.IsVoid() ) return gp_Pnt2d(0.,0.);
2282   Standard_Real aXmin, aYmin, aXmax, aYmax;
2283   box.Get(aXmin, aYmin, aXmax, aYmax);
2284   return gp_Pnt2d ( 0.5 * ( aXmax + aXmin ), 0.5 * ( aYmax + aYmin ) );
2285 }
2286
2287 //=======================================================================
2288 //function : MakeFacesOnPatch
2289 //purpose  : 
2290 //=======================================================================
2291
2292 void ShapeFix_ComposeShell::MakeFacesOnPatch (TopTools_SequenceOfShape &faces,
2293                                               const Handle(Geom_Surface)& surf,
2294                                               TopTools_SequenceOfShape &loops) const
2295 {
2296   BRep_Builder B;
2297
2298   // Case of single loop: just add it to face
2299   if ( loops.Length() == 1 ) {
2300     TopoDS_Face newFace;
2301     B.MakeFace ( newFace, surf, myLoc, ::Precision::Confusion() );
2302     TopoDS_Shape aSH = loops.Value(1);
2303     if( aSH.ShapeType() != TopAbs_WIRE)
2304       return;
2305     TopoDS_Wire wire = TopoDS::Wire ( loops.Value(1) );
2306     
2307     B.Add ( newFace, wire );
2308     if(myInvertEdgeStatus) {
2309       Handle(ShapeFix_Face) sff = new ShapeFix_Face(newFace);
2310       sff->FixAddNaturalBoundMode() = Standard_False;
2311       TopTools_DataMapOfShapeListOfShape MapWires;
2312       MapWires.Clear();
2313       sff->FixOrientation(MapWires);
2314       newFace = sff->Face();
2315     }
2316       
2317     faces.Append ( newFace );
2318     return;
2319   }
2320
2321   // For several loops, first find roots
2322   // make pseudo-face,
2323   TopoDS_Face pf;
2324   B.MakeFace ( pf, surf, myLoc, ::Precision::Confusion() );
2325   Handle(Geom_Surface) atSurf = BRep_Tool::Surface(pf);
2326   
2327   Handle(ShapeAnalysis_Surface) aSurfTool = new ShapeAnalysis_Surface(atSurf);
2328   TopTools_SequenceOfShape roots;
2329   Standard_Integer i; // svv #1
2330   for ( i = 1; i <= loops.Length(); i++ ) {
2331     gp_Pnt2d unp;
2332     TopoDS_Wire wr;
2333     TopoDS_Shape aShape = loops(i);
2334     if(aShape.ShapeType() != TopAbs_WIRE || 
2335        (aShape.Orientation() != TopAbs_FORWARD && aShape.Orientation() != TopAbs_REVERSED))
2336       continue;
2337     
2338     wr = TopoDS::Wire ( loops(i) );
2339     TopoDS_Iterator ew (wr);
2340     if ( ! ew.More() ) continue;
2341     
2342     TopoDS_Edge ed = TopoDS::Edge ( ew.Value() );
2343     while(ed.Orientation() != TopAbs_FORWARD && 
2344           ed.Orientation() != TopAbs_REVERSED ) {
2345       ew.Next();
2346       if(ew.More())
2347         ed = TopoDS::Edge ( ew.Value() );
2348       else
2349         break;
2350     }
2351     if ( ! ew.More() ) continue;
2352     Standard_Real cf, cl;
2353     Handle(Geom2d_Curve) cw = BRep_Tool::CurveOnSurface ( ed, pf, cf, cl );
2354     if ( cw.IsNull() ) continue;
2355     unp = cw->Value ( 0.5 * ( cf + cl ) );
2356     
2357     Standard_Integer j; // svv #1
2358     for ( j = 1; j <= loops.Length(); j++ ) {
2359       if ( i == j ) continue;
2360       TopoDS_Shape aShape2 = loops(j);
2361       if(aShape2.ShapeType() != TopAbs_WIRE || 
2362        (aShape2.Orientation() != TopAbs_FORWARD && 
2363         aShape2.Orientation() != TopAbs_REVERSED))
2364         continue;
2365       TopoDS_Wire w1 = TopoDS::Wire (aShape2);
2366       TopoDS_Wire awtmp;
2367       B.MakeWire(awtmp);
2368       awtmp.Orientation(TopAbs_FORWARD);
2369       TopoDS_Iterator aIt(w1);
2370       Standard_Integer nbe =0;
2371       for( ; aIt.More() ; aIt.Next()) {
2372         if(aIt.Value().Orientation() == TopAbs_FORWARD ||
2373            aIt.Value().Orientation() == TopAbs_REVERSED) {
2374           B.Add(awtmp,aIt.Value());
2375           nbe++;
2376         }
2377         
2378       }
2379       if(!nbe)
2380         continue;
2381       TopoDS_Face fc;
2382       B.MakeFace ( fc, surf, myLoc, ::Precision::Confusion() );
2383       B.Add ( fc, awtmp );
2384       BRepTopAdaptor_FClass2d clas ( fc, ::Precision::PConfusion() );
2385       TopAbs_State stPoint = clas.Perform (unp,Standard_False);
2386       if(stPoint == TopAbs_ON || stPoint == TopAbs_UNKNOWN) {
2387
2388         TopoDS_Edge ed = TopoDS::Edge ( ew.Value() );
2389         Standard_Real cf, cl;
2390         Handle(Geom2d_Curve) cw = BRep_Tool::CurveOnSurface ( ed, pf, cf, cl );
2391         // handle tangential case (ON)
2392         while ( stPoint == TopAbs_ON || stPoint == TopAbs_UNKNOWN ) {
2393           stPoint = clas.Perform ( cw->Value(cl), Standard_False );
2394           if ( ! ew.More() ) break;
2395           ew.Next();
2396           if ( ! ew.More() ) break;
2397           TopoDS_Edge edge = TopoDS::Edge ( ew.Value() );
2398           if(edge.Orientation() !=TopAbs_FORWARD &&
2399              edge.Orientation() !=TopAbs_REVERSED)
2400             continue;
2401           Handle(Geom2d_Curve) c2d = BRep_Tool::CurveOnSurface ( edge, pf, cf, cl );
2402           if ( ! c2d.IsNull() ) cw = c2d;
2403         }
2404       }
2405       TopAbs_State stInfin = clas.PerformInfinitePoint();
2406       if ( stPoint != stInfin ) break;
2407     }
2408     if ( j > loops.Length()) {
2409       roots.Append ( wr );
2410       //      loops.Remove ( i-- );
2411     }
2412   }
2413   
2414   // And remove them from the list of loops
2415   for ( i = 1; i <= loops.Length(); i++ )
2416     for ( Standard_Integer j = 1; j <= roots.Length(); j++ ) 
2417       if ( loops(i).IsSame ( roots(j) ) ) { loops.Remove(i--); break; }
2418   
2419   // check for lost wires, and if they are, make them roots
2420   if ( roots.Length() <=0 && loops.Length() >0 ) {
2421 #ifdef DEB
2422     cout << "Error: ShapeFix_ComposeShell::MakeFacesOnPatch: can't dispatch wires" << endl;
2423 #endif
2424     for ( Standard_Integer j=1; j <= loops.Length(); j++ ) {
2425       roots.Append ( loops(j) );
2426     }
2427     loops.Clear();
2428   }
2429   
2430   // Then iterate on loops
2431   for ( i=1; i <= roots.Length(); i++ ) {
2432     Standard_Boolean reverse = Standard_False;
2433     TopoDS_Wire wire = TopoDS::Wire ( roots(i) );
2434     TopoDS_Face fc;
2435     B.MakeFace ( fc, surf, myLoc, ::Precision::Confusion() );
2436     B.Add ( fc, wire );
2437     BRepTopAdaptor_FClass2d clas ( fc, ::Precision::PConfusion() );
2438     if ( clas.PerformInfinitePoint() == TopAbs_IN ) {
2439       reverse = Standard_True;
2440 #ifdef DEB
2441       cout << "Warning: ShapeFix_ComposeShell::MakeFacesOnPatch: badly oriented wire" << endl;
2442 #endif
2443     }
2444     
2445     // find all holes for that loop
2446     TopTools_SequenceOfShape holes; // holes in holes not supported
2447     Standard_Integer j; // svv #1
2448     for ( j=1; j <= loops.Length(); j++ ) {
2449       gp_Pnt2d unp;
2450       if(loops(j).ShapeType() == TopAbs_WIRE) {
2451         TopoDS_Wire bw = TopoDS::Wire ( loops(j) );
2452         TopoDS_Iterator ew ( bw );
2453         if ( ! ew.More() ) continue;
2454         TopoDS_Edge ed = TopoDS::Edge ( ew.Value() );
2455         Standard_Real cf, cl;
2456         Handle(Geom2d_Curve) cw = BRep_Tool::CurveOnSurface ( ed, pf, cf, cl );
2457         if ( cw.IsNull() ) continue;
2458         unp = cw->Value ( 0.5 * ( cf + cl ) );
2459       }
2460       else if(loops(j).ShapeType() == TopAbs_VERTEX) {
2461         TopoDS_Vertex aV = TopoDS::Vertex(loops(j));
2462         gp_Pnt aP = BRep_Tool::Pnt(aV);
2463         unp = aSurfTool->ValueOfUV(aP,Precision::Confusion());
2464       }
2465       else
2466         continue;
2467       TopAbs_State state = clas.Perform (unp,Standard_False);
2468       if ( (Standard_Boolean) ( state == TopAbs_OUT ) == reverse ) {
2469         holes.Append ( loops(j) );
2470         loops.Remove ( j-- );
2471       }
2472     }
2473     
2474     // and add them to new face (no orienting is done)
2475     TopoDS_Face newFace;
2476     B.MakeFace ( newFace, surf, myLoc, ::Precision::Confusion() );
2477     B.Add ( newFace, wire );
2478     for ( j=1; j <= holes.Length(); j++ ) {
2479       TopoDS_Shape aSh = holes(j);
2480       if(aSh.ShapeType() == TopAbs_VERTEX) {
2481         TopoDS_Vertex aNewV = ShapeAnalysis_TransferParametersProj::CopyNMVertex(TopoDS::Vertex(aSh), newFace,myFace);
2482         Context()->Replace(aSh,aNewV);
2483         B.Add ( newFace,aNewV);
2484       }
2485       else
2486         B.Add ( newFace, holes(j) );
2487     }
2488     faces.Append ( newFace ); 
2489     
2490     // check for lost wires, and if they are, make them roots
2491     if ( i == roots.Length() && loops.Length() >0 ) {
2492 #ifdef DEB
2493       cout << "Error: ShapeFix_ComposeShell::MakeFacesOnPatch: can't dispatch wires" << endl;
2494 #endif
2495       for ( j=1; j <= loops.Length(); j++ ) {
2496         TopoDS_Shape aSh = loops(j);
2497         if(aSh.ShapeType() == TopAbs_WIRE && (aSh.Orientation() == TopAbs_FORWARD ||
2498                                               aSh.Orientation() == TopAbs_REVERSED))
2499           roots.Append ( loops(j) );
2500       }
2501       loops.Clear();
2502     }
2503   } 
2504 }
2505
2506 //=======================================================================
2507 //function : DispatchWires
2508 //purpose  : 
2509 //=======================================================================
2510
2511 void ShapeFix_ComposeShell::DispatchWires (TopTools_SequenceOfShape &faces,
2512                                            ShapeFix_SequenceOfWireSegment& wires) const
2513 {
2514   BRep_Builder B;
2515   
2516   // in closed mode, apply FixShifted to all wires before dispatching them
2517   if ( myClosedMode ) {
2518     ShapeFix_Wire sfw;
2519     sfw.SetFace ( myFace );
2520     sfw.SetPrecision ( Precision() );
2521     
2522     // pdn: shift pcurves in the seam to make OK shape w/o fixshifted
2523     Standard_Integer i;
2524     for ( i=1; i <= wires.Length(); i++ ) {
2525       if(wires(i).IsVertex())
2526         continue;
2527       Handle(ShapeExtend_WireData) sbwd = wires(i).WireData();
2528       
2529       for(Standard_Integer jL=1; jL <= sbwd->NbEdges(); jL++ ) {
2530         TopoDS_Edge E = sbwd->Edge(jL);
2531         if ( E.Orientation() == TopAbs_REVERSED && BRep_Tool::IsClosed(E,myFace) ) {
2532           Standard_Real f1,l1, f2, l2;
2533           Handle(Geom2d_Curve) c21 =  BRep_Tool::CurveOnSurface(E,myFace,f1,l1);
2534           TopoDS_Shape dummy = E.Reversed();
2535           Handle(Geom2d_Curve) c22 =  BRep_Tool::CurveOnSurface(TopoDS::Edge(dummy),myFace,f2,l2);
2536           Standard_Real dPreci = ::Precision::PConfusion()*Precision::PConfusion();
2537           gp_Pnt2d pf1 = c21->Value(f1);
2538           gp_Pnt2d pl1 = c21->Value(l1);
2539           gp_Pnt2d pf2 = c22->Value(f2);
2540           gp_Pnt2d pl2 = c22->Value(l2);
2541           if ( c21 == c22 || pf1.SquareDistance(pf2) < dPreci ||
2542               pl1.SquareDistance(pl2) < dPreci ) {
2543             gp_Vec2d shift(0.,0.);
2544             if ( myUClosed && Abs ( pf2.X() - pl2.X() ) < ::Precision::PConfusion() )
2545               shift.SetX(myUPeriod);
2546             if ( myVClosed && Abs ( pf2.Y() - pl2.Y() ) < ::Precision::PConfusion() )
2547               shift.SetY(myVPeriod);
2548             c22->Translate(shift);
2549           }
2550         }
2551       }
2552     }
2553     
2554     for ( i=1; i <= wires.Length(); i++ ) {
2555       if(wires(i).IsVertex())
2556         continue;
2557       Handle(ShapeExtend_WireData) sbwd = wires(i).WireData();
2558       
2559       //: abv 30.08.01: torHalf2.sat: if wire contains single degenerated
2560       // edge, skip that wire
2561       if ( sbwd->NbEdges() <=0 || 
2562           ( sbwd->NbEdges() ==1 && BRep_Tool::Degenerated(sbwd->Edge(1)) ) ) {
2563         wires.Remove(i--);
2564         continue;
2565       }
2566       
2567       sfw.Load ( sbwd );
2568       sfw.FixShifted();
2569       
2570       // force recomputation of degenerated edges (clear pcurves)
2571       ShapeBuild_Edge sbe;
2572       for (Standard_Integer jL=1; jL <= sbwd->NbEdges(); jL++ ) {
2573         if ( BRep_Tool::Degenerated(sbwd->Edge(jL)) ) 
2574           sbe.RemovePCurve(sbwd->Edge(jL),myFace);
2575         //        sfw.FixDegenerated(jL);
2576       }
2577       sfw.FixDegenerated();
2578     }
2579   }
2580   
2581   // Compute center points for wires
2582   TColgp_SequenceOfPnt2d mPnts;
2583   Standard_Integer nb = wires.Length();
2584   
2585   // pdn protection on empty sequence
2586   if(nb == 0)
2587     return;
2588   
2589   Standard_Integer i; //svv #1 
2590   for ( i = 1; i <= nb; i++ )
2591     mPnts.Append ( GetMiddlePoint ( wires(i), myFace ) );
2592   
2593   // Put each wire on its own surface patch (by reassigning pcurves)
2594   // and build 3d curve if necessary
2595   ShapeBuild_ReShape rs;
2596   ShapeBuild_Edge sbe;
2597   ShapeAnalysis_Edge sae;
2598   Handle(ShapeFix_Edge) sfe = new ShapeFix_Edge;
2599   
2600   Standard_Real U1,U2,V1,V2;
2601   myGrid->Bounds(U1,U2,V1,V2);
2602   for ( i = 1; i <= nb; i++ ) {
2603     
2604     gp_Pnt2d pnt = mPnts(i);
2605     Standard_Real ush =0., vsh=0.;
2606     if(myUClosed) {
2607       ush = ShapeAnalysis::AdjustToPeriod(pnt.X(),U1,U2);
2608       pnt.SetX(pnt.X()+ush);
2609     }
2610     if(myVClosed) {
2611       vsh = ShapeAnalysis::AdjustToPeriod(pnt.Y(),V1,V2);
2612       pnt.SetY(pnt.Y()+vsh);
2613     }
2614     mPnts(i) = pnt;
2615     Standard_Integer indU = myGrid->LocateUParameter ( pnt.X() );
2616     Standard_Integer indV = myGrid->LocateVParameter ( pnt.Y() );
2617     
2618     // compute parametric transformation
2619     gp_Trsf2d T;
2620     Standard_Real uFact=1.;
2621     Standard_Boolean needT = myGrid->GlobalToLocalTransformation ( indU, indV, uFact, T );
2622     if ( ush != 0. || vsh != 0. ) {
2623       gp_Trsf2d Sh;
2624       Sh.SetTranslation ( gp_Vec2d ( ush, vsh ) );
2625       T.Multiply ( Sh );
2626       needT = Standard_True;
2627     }
2628     if(wires(i).IsVertex()) 
2629       continue;
2630     Handle(Geom_Surface) surf = myGrid->Patch ( indU, indV );
2631     TopoDS_Face face;
2632     B.MakeFace ( face, surf, myLoc, ::Precision::Confusion() );
2633     Handle(ShapeExtend_WireData) sewd = wires(i).WireData();
2634     for ( Standard_Integer j = 1; j <= sewd->NbEdges(); j++ ) {
2635       //      Standard_Integer nsplit = ApplyContext ( sewd, j, context );
2636       //      if ( nsplit <1 ) { j--; continue; }
2637       
2638       TopoDS_Edge edge = sewd->Edge(j);
2639       
2640       // !! Accurately copy pcurves for SEAMS and SEAM-like edges !!
2641       
2642       // if edge is already copied, don`t copy any more
2643       TopoDS_Edge newEdge;
2644       TopoDS_Edge anInitEdge = edge;
2645       Standard_Boolean ismanifold = (edge.Orientation() == TopAbs_FORWARD ||
2646                                      edge.Orientation() == TopAbs_REVERSED);
2647       if ( rs.IsRecorded ( edge ) ) {
2648         //smh#8
2649         TopoDS_Shape tmpNE = rs.Value(edge);
2650         newEdge = TopoDS::Edge ( tmpNE );
2651       } 
2652       else {
2653         
2654         if(!ismanifold) 
2655           anInitEdge.Orientation(TopAbs_FORWARD);
2656         
2657         newEdge = sbe.Copy ( anInitEdge, Standard_False );
2658         if(!ismanifold)
2659           newEdge.Orientation(edge.Orientation());
2660         rs.Replace ( edge, newEdge );
2661         Context()->Replace ( edge, newEdge );
2662       }
2663       
2664       sbe.ReassignPCurve ( newEdge, myFace, face );
2665       
2666       // transform pcurve to parametric space of patch
2667       if ( needT ) {
2668         Standard_Real f, l;
2669         Handle(Geom2d_Curve) c2d;
2670         if ( sae.PCurve ( newEdge, face, c2d, f, l, Standard_False ) ) {
2671           Standard_Real newf = f, newl = l;
2672           Handle(Geom2d_Curve) c2dnew = sbe.TransformPCurve ( c2d, T, uFact, newf, newl );
2673           if ( BRep_Tool::IsClosed ( newEdge, face ) ) {
2674             Standard_Real cf, cl;
2675             Handle(Geom2d_Curve) c2d2;
2676             //smh#8
2677             TopoDS_Shape tmpE = newEdge.Reversed();
2678             TopoDS_Edge e2 = TopoDS::Edge (tmpE );
2679             if ( sae.PCurve ( e2, face, c2d2, cf, cl, Standard_False ) ) {
2680               if ( newEdge.Orientation() == TopAbs_FORWARD ) 
2681                 B.UpdateEdge ( newEdge, c2dnew, c2d2, face, 0. );
2682               else B.UpdateEdge ( newEdge, c2d2, c2dnew, face, 0. );
2683             }
2684             else B.UpdateEdge ( newEdge, c2dnew, face, 0. );
2685           }
2686           else B.UpdateEdge ( newEdge, c2dnew, face, 0. );
2687           B.Range ( newEdge, face, newf, newl );
2688           if ( (newf != f || newl != l) && !BRep_Tool::Degenerated(newEdge) ) 
2689             B.SameRange ( newEdge, Standard_False );
2690         }
2691       }
2692       
2693       if(!BRep_Tool::SameRange(newEdge)) {
2694         TopoDS_Edge etmp;
2695         if(!ismanifold) {
2696           TopoDS_Edge afe = TopoDS::Edge(newEdge.Oriented(TopAbs_FORWARD));
2697           etmp  = sbe.Copy (afe , Standard_False );
2698         }
2699         else
2700           etmp  = sbe.Copy ( newEdge, Standard_False );
2701         sfe->FixAddCurve3d ( etmp );
2702         Standard_Real cf, cl;
2703         Handle(Geom_Curve) c3d;
2704         if(sae.Curve3d(etmp,c3d,cf,cl,Standard_False)) {
2705           B.UpdateEdge ( newEdge, c3d, 0. );
2706           sbe.SetRange3d ( newEdge, cf, cl );
2707         }
2708       }
2709       else        
2710         sfe->FixAddCurve3d ( newEdge );
2711       sewd->Set ( newEdge, j );
2712     }
2713   }
2714   
2715   // Collect wires in packets lying on same surface and dispatch them
2716   TColStd_Array1OfBoolean used ( 1, nb );
2717   used.Init ( Standard_False );
2718   while ( 1 ) {
2719     TopTools_SequenceOfShape loops;
2720
2721     Handle(Geom_Surface) Surf;
2722     for ( i = 1; i <= nb; i++ ) {
2723       if ( used(i) ) continue;
2724       Handle(Geom_Surface) S = myGrid->Patch ( mPnts(i) );
2725       if ( Surf.IsNull() ) Surf = S;
2726       else if ( S != Surf ) continue;
2727       used(i) = Standard_True;
2728       ShapeFix_WireSegment aSeg = wires(i);
2729       if(aSeg.IsVertex()) {
2730         TopoDS_Vertex aVert = aSeg.GetVertex();
2731         if(aVert.Orientation() == TopAbs_INTERNAL)
2732           loops.Append(wires(i).GetVertex());
2733       }
2734       else {
2735         Handle(ShapeExtend_WireData) aWD = aSeg.WireData();
2736         if(!aWD.IsNull())
2737           loops.Append ( aWD->Wire() );
2738       }
2739     }
2740     if ( Surf.IsNull() ) break;
2741
2742     MakeFacesOnPatch ( faces, Surf, loops );
2743   } 
2744 }
2745
2746 //======================================================================
2747 //function : SetTransferParamTool
2748 //purpose  : 
2749 //=======================================================================
2750
2751 void ShapeFix_ComposeShell::SetTransferParamTool(const Handle(ShapeAnalysis_TransferParameters)& TransferParam) 
2752 {
2753   myTransferParamTool = TransferParam;
2754 }
2755
2756 //=======================================================================
2757 //function : GetTransferParamTool
2758 //purpose  : 
2759 //=======================================================================
2760
2761 Handle(ShapeAnalysis_TransferParameters) ShapeFix_ComposeShell::GetTransferParamTool() const
2762 {
2763   return myTransferParamTool;
2764 }
2765
2766 //=======================================================================
2767 //function : ClosedMode
2768 //purpose  : 
2769 //=======================================================================
2770
2771 Standard_Boolean &ShapeFix_ComposeShell::ClosedMode() 
2772 {
2773   return myClosedMode;
2774 }