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