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