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