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