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