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