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