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