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