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
6 // This file is part of Open CASCADE Technology software library.
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.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
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
21 #include <Bnd_Box2d.hxx>
22 #include <BRep_Builder.hxx>
23 #include <BRep_Tool.hxx>
24 #include <BRepTools.hxx>
25 #include <BRepTopAdaptor_FClass2d.hxx>
26 #include <Extrema_ExtPC2d.hxx>
27 #include <Geom2d_Curve.hxx>
28 #include <Geom2d_Line.hxx>
29 #include <Geom2dAdaptor_Curve.hxx>
30 #include <Geom2dInt_GInter.hxx>
31 #include <Geom_Curve.hxx>
32 #include <Geom_ElementarySurface.hxx>
33 #include <gp_Dir2d.hxx>
34 #include <gp_Lin2d.hxx>
36 #include <gp_Pnt2d.hxx>
37 #include <IntRes2d_Domain.hxx>
38 #include <IntRes2d_IntersectionPoint.hxx>
39 #include <IntRes2d_IntersectionSegment.hxx>
40 #include <Precision.hxx>
41 #include <ShapeAnalysis.hxx>
42 #include <ShapeAnalysis_Curve.hxx>
43 #include <ShapeAnalysis_Edge.hxx>
44 #include <ShapeAnalysis_Surface.hxx>
45 #include <ShapeAnalysis_TransferParametersProj.hxx>
46 #include <ShapeAnalysis_WireOrder.hxx>
47 #include <ShapeBuild_Edge.hxx>
48 #include <ShapeBuild_ReShape.hxx>
49 #include <ShapeBuild_Vertex.hxx>
50 #include <ShapeExtend_CompositeSurface.hxx>
51 #include <ShapeFix_ComposeShell.hxx>
52 #include <ShapeFix_Edge.hxx>
53 #include <ShapeFix_Face.hxx>
54 #include <ShapeFix_Wire.hxx>
55 #include <ShapeFix_WireSegment.hxx>
56 #include <Standard_Type.hxx>
57 #include <TColgp_SequenceOfPnt2d.hxx>
58 #include <TColStd_Array1OfBoolean.hxx>
59 #include <TColStd_Array1OfInteger.hxx>
60 #include <TColStd_Array1OfReal.hxx>
61 #include <TColStd_HArray1OfReal.hxx>
62 #include <TColStd_SequenceOfReal.hxx>
63 #include <TopLoc_Location.hxx>
65 #include <TopoDS_Edge.hxx>
66 #include <TopoDS_Face.hxx>
67 #include <TopoDS_Iterator.hxx>
68 #include <TopoDS_Shape.hxx>
69 #include <TopoDS_Shell.hxx>
70 #include <TopoDS_Vertex.hxx>
71 #include <TopoDS_Wire.hxx>
72 #include <TopTools_DataMapOfShapeListOfShape.hxx>
73 #include <TopTools_MapOfShape.hxx>
75 IMPLEMENT_STANDARD_RTTIEXT(ShapeFix_ComposeShell,ShapeFix_Root)
77 //=======================================================================
78 //function : ShapeFix_ComposeShell
80 //=======================================================================
81 ShapeFix_ComposeShell::ShapeFix_ComposeShell () :
82 myOrient(TopAbs_FORWARD),
84 myUResolution(RealLast()),
85 myVResolution(RealLast()),
86 myInvertEdgeStatus(Standard_True),
87 myClosedMode(Standard_False),
88 myUClosed(Standard_False),
89 myVClosed(Standard_False),
93 myTransferParamTool = new ShapeAnalysis_TransferParametersProj;
97 //=======================================================================
100 //=======================================================================
102 void ShapeFix_ComposeShell::Init (const Handle(ShapeExtend_CompositeSurface) &Grid,
103 const TopLoc_Location& L,
104 const TopoDS_Face &Face,
105 const Standard_Real Prec)
108 myUClosed = myGrid->IsUClosed();
109 myVClosed = myGrid->IsVClosed();
110 myUPeriod = myGrid->UJointValue(myGrid->NbUPatches()+1) - myGrid->UJointValue(1);
111 myVPeriod = myGrid->VJointValue(myGrid->NbVPatches()+1) - myGrid->VJointValue(1);
113 // DTK-CKY 100531 : protection against very thin face
114 // Test "isclosed" should be filtered on the overall (non trimmed) surface, must be closed
115 Handle(Geom_Surface) theSurface = BRep_Tool::Surface(Face,myLoc);
116 // avoid false detection of 'Closed' on very thin faces
117 if (theSurface->IsKind(STANDARD_TYPE(Geom_ElementarySurface))) {
118 myUClosed = myUClosed && theSurface->IsUClosed();
119 myVClosed = myVClosed && theSurface->IsVClosed();
121 Standard_Real U0,U1,V0,V1,GU0 = 0.,GU1 = 0.,GV0 = 0.,GV1 = 0.;
122 theSurface->Bounds(U0,U1,V0,V1);
123 if (::Precision::IsInfinite (U0) || ::Precision::IsInfinite (U1) ||
124 ::Precision::IsInfinite (V0) || ::Precision::IsInfinite (V1))
125 BRepTools::UVBounds(Face, GU0, GU1, GV0, GV1);
127 if (::Precision::IsInfinite (V0)) V0 = GV0;
128 if (::Precision::IsInfinite (V1)) V1 = GV1;
129 gp_Pnt P0 = theSurface->Value(U0,(V0+V1)/2.);
130 gp_Pnt P1 = theSurface->Value(U1,(V0+V1)/2.);
131 if (P0.Distance(P1) > Precision::Confusion()*10)
132 myUClosed = Standard_False;
135 if (::Precision::IsInfinite (U0)) U0 = GU0;
136 if (::Precision::IsInfinite (U1)) U1 = GU1;
137 gp_Pnt P0 = theSurface->Value((U0+U1)/2.,V0);
138 gp_Pnt P1 = theSurface->Value((U0+U1)/2.,V1);
139 if (P0.Distance(P1) > Precision::Confusion()*10)
140 myVClosed = Standard_False;
143 // DTK-CKY 100531 end
147 TopoDS_Shape tmpF = Face.Oriented ( TopAbs_FORWARD );
148 myFace = TopoDS::Face ( tmpF ); // for correct dealing with seams
149 myOrient = Face.Orientation();
151 myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
153 // Compute resolution (checking in 2d is necessary for splitting
154 // degenerated edges and avoiding NotClosed)
155 myUResolution = myVResolution = RealLast();
156 for ( Standard_Integer i=1; i <= myGrid->NbUPatches(); i++ ) {
157 Standard_Real uRange = myGrid->UJointValue(i+1)-myGrid->UJointValue(i);
158 for ( Standard_Integer j=1; j <= myGrid->NbVPatches(); j++ ) {
159 Standard_Real vRange = myGrid->VJointValue(j+1)-myGrid->VJointValue(j);
160 Standard_Real u1,u2,v1,v2;
161 myGrid->Patch(i,j)->Bounds(u1,u2,v1,v2);
162 GeomAdaptor_Surface GAS ( myGrid->Patch(i,j) );
163 Standard_Real ures = GAS.UResolution ( 1. )*uRange/(u2-u1);
164 Standard_Real vres = GAS.VResolution ( 1. )*vRange/(v2-v1);
165 if ( ures >0. && myUResolution > ures ) myUResolution = ures;
166 if ( vres >0. && myVResolution > vres ) myVResolution = vres;
169 if ( myUResolution == RealLast() ) myUResolution = ::Precision::Parametric ( 1. );
170 if ( myVResolution == RealLast() ) myVResolution = ::Precision::Parametric ( 1. );
173 //=======================================================================
176 //=======================================================================
178 Standard_Boolean ShapeFix_ComposeShell::Perform ()
180 myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
181 myInvertEdgeStatus = Standard_False;
183 ShapeFix_SequenceOfWireSegment seqw; // working data: wire segments
185 // Init seqw by initial set of wires (with corresponding orientation)
187 if(seqw.Length() == 0) {
188 myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_FAIL6 );
189 return Standard_False;
192 // Split edges in the wires by grid and add internal segments of grid (parts of cutting lines)
193 SplitByGrid ( seqw );
195 // Split all the wires into segments by common vertices (intersections)
198 // Then, collect resulting wires
199 ShapeFix_SequenceOfWireSegment wires; // resulting wires
200 CollectWires ( wires, seqw );
202 // And construct resulting faces
203 TopTools_SequenceOfShape faces;
204 DispatchWires ( faces, wires );
206 // Finally, construct resulting shell
207 if ( faces.Length() !=1 ) {
211 for ( Standard_Integer i=1; i <= faces.Length(); i++ )
212 B.Add ( S, faces(i) );
215 else myResult = faces(1);
216 myResult.Orientation ( myOrient );
218 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
219 return Standard_True;
222 //=======================================================================
223 //function : SplitEdges
225 //=======================================================================
227 void ShapeFix_ComposeShell::SplitEdges ()
229 myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
231 ShapeFix_SequenceOfWireSegment seqw; // working data: wire segments
233 // Init seqw by initial set of wires (with corresponding orientation)
236 // Split edges in the wires by grid and add internal segments of grid (parts of cutting lines)
237 SplitByGrid ( seqw );
240 //=======================================================================
243 //=======================================================================
245 const TopoDS_Shape& ShapeFix_ComposeShell::Result () const
250 //=======================================================================
253 //=======================================================================
255 Standard_Boolean ShapeFix_ComposeShell::Status (const ShapeExtend_Status status) const
257 return ShapeExtend::DecodeStatus ( myStatus, status );
260 //=======================================================================
261 // PRIVATE (working) METHODS
262 //=======================================================================
264 #define TOLINT 1.e-10 // precision for intersection
266 // Local definitions: characteristics of intersection point
268 #define IOR_UNDEF 0 // undefined side
269 #define IOR_LEFT 1 // to left side of cutting line
270 #define IOR_RIGHT 2 // to right side of cutting line
271 #define IOR_BOTH 3 // crossing
272 #define IOR_POS 4 // in case of cycle on full period, whether first point is right
274 #define ITP_INTER 8 // crossing
275 #define ITP_BEGSEG 16 // start of tangential segment
276 #define ITP_ENDSEG 32 // stop of tangential segment
277 #define ITP_TANG 64 // tangential point
279 //=======================================================================
280 //function : PointLineDeviation
281 //purpose : auxiliary
282 //=======================================================================
283 // Return (signed) deviation of point from line
284 static Standard_Real PointLineDeviation (const gp_Pnt2d &p, const gp_Lin2d &line)
286 gp_Dir2d dir = line.Direction();
287 gp_Dir2d n ( -dir.Y(), dir.X() );
288 return n.XY() * ( p.XY() - line.Location().XY() );
291 //=======================================================================
292 //function : PointLinePosition
293 //purpose : auxiliary
294 //=======================================================================
295 // Define position of point relative to line
296 static Standard_Integer PointLinePosition (const gp_Pnt2d &p, const gp_Lin2d &line,
299 dev = PointLineDeviation ( p, line );
300 return ( dev > TOLINT ? IOR_LEFT : ( dev < -TOLINT ? IOR_RIGHT : IOR_UNDEF ) );
303 //=======================================================================
304 //function : PointLinePosition
305 //purpose : auxiliary
306 //=======================================================================
307 // Define position of point relative to line
308 static Standard_Integer PointLinePosition (const gp_Pnt2d &p, const gp_Lin2d &line)
311 return PointLinePosition ( p, line, dev );
314 //=======================================================================
315 //function : ParamPointsOnLine
316 //purpose : auxiliary
317 //=======================================================================
318 // Compute parameter of point on line
319 static inline Standard_Real ParamPointOnLine (const gp_Pnt2d &p, const gp_Lin2d &line)
321 return line.Direction().XY() * ( p.XY() - line.Location().XY() );
324 //=======================================================================
325 //function : ParamPointsOnLine
326 //purpose : auxiliary
327 //=======================================================================
328 // Compute parameter of two points on line (as intersection of segment)
329 static Standard_Real ParamPointsOnLine (const gp_Pnt2d &p1, const gp_Pnt2d &p2,
330 const gp_Lin2d &line)
332 Standard_Real dist1 = PointLineDeviation ( p1, line );
333 Standard_Real dist2 = PointLineDeviation ( p2, line );
334 // in most cases, one of points is on line
335 if ( Abs ( dist1 ) < ::Precision::PConfusion() ) {
336 if ( Abs ( dist2 ) < ::Precision::PConfusion() )
337 return 0.5 * ( ParamPointOnLine ( p1, line ) + ParamPointOnLine ( p2, line ) );
338 return ParamPointOnLine ( p1, line );
340 if ( Abs ( dist2 ) < ::Precision::PConfusion() )
341 return ParamPointOnLine ( p2, line );
343 if ( dist2 * dist1 >0 )
344 return 0.5 * ( ParamPointOnLine ( p1, line ) + ParamPointOnLine ( p2, line ) );
345 // else compute intersection
346 return ( ParamPointOnLine ( p1, line ) * dist2 -
347 ParamPointOnLine ( p2, line ) * dist1 ) / ( dist2 - dist1 );
350 //=======================================================================
351 //function : ProjectPointOnLine
352 //purpose : auxiliary
353 //=======================================================================
354 // Compute projection of point on line
355 static inline gp_Pnt2d ProjectPointOnLine (const gp_Pnt2d &p, const gp_Lin2d &line)
357 return line.Location().XY() + line.Direction().XY() * ParamPointOnLine ( p, line );
360 //=======================================================================
361 //function : ApplyContext
362 //purpose : auxiliary
363 //=======================================================================
364 // Apply context to one edge in the wire and put result into this wire
365 static Standard_Integer ApplyContext (ShapeFix_WireSegment &wire,
366 const Standard_Integer iedge,
367 const Handle(ShapeBuild_ReShape) &context)
369 TopoDS_Edge edge = wire.Edge ( iedge );
370 TopoDS_Shape res = context->Apply ( edge );
372 if ( res.IsSame ( edge ) ) return 1;
374 if ( res.ShapeType() == TopAbs_EDGE ) {
375 wire.SetEdge ( iedge, TopoDS::Edge ( res ) );
379 Standard_Integer index = iedge;
381 Handle(ShapeExtend_WireData) segw = new ShapeExtend_WireData;
382 segw->ManifoldMode() = Standard_False;
383 for ( TopoDS_Iterator it(res); it.More(); it.Next() ) {
384 TopoDS_Edge E = TopoDS::Edge ( it.Value() );
385 if ( ! E.IsNull() ) segw->Add ( E );
387 else std::cout << "Error: ShapeFix_ComposeShell, ApplyContext: wrong mapping of edge" << std::endl;
391 // add edges into the wire in correct order
392 if ( segw->NbEdges() >0 ) {
393 Standard_Integer ind, iumin, iumax, ivmin, ivmax;
394 wire.GetPatchIndex ( iedge, iumin, iumax, ivmin, ivmax );
395 Standard_Integer nbEdges = segw->NbEdges();
396 for ( Standard_Integer i=1; i <= nbEdges; i++, index++ ) {
397 ind = ( edge.Orientation() == TopAbs_FORWARD || edge.Orientation() == TopAbs_INTERNAL ? i : segw->NbEdges()-i+1 );
398 TopoDS_Edge aE = segw->Edge ( ind );
399 if ( i==1 ) wire.SetEdge ( index, aE );
400 else wire.AddEdge ( index, aE, iumin, iumax, ivmin, ivmax );
404 else std::cout << "Warning: ShapeFix_ComposeShell, ApplyContext: edge is to remove - not implemented" << std::endl;
407 return index - iedge;
411 //=======================================================================
412 //function : IsCoincided
413 //purpose : auxiliary
414 //=======================================================================
415 // check points coincidence
416 static inline Standard_Boolean IsCoincided (const gp_Pnt2d &p1, const gp_Pnt2d &p2,
417 const Standard_Real UResolution,
418 const Standard_Real VResolution,
419 const Standard_Real tol)
421 //pdn Maximal accuracy is working precision of intersector.
422 Standard_Real UTolerance = UResolution * tol;
423 Standard_Real VTolerance = VResolution * tol;
424 return Abs ( p1.X() - p2.X() ) <= Max(TOLINT,UTolerance) &&
425 Abs ( p1.Y() - p2.Y() ) <= Max(TOLINT,VTolerance);
429 //=======================================================================
430 //function : GetPatchIndex
431 //purpose : auxiliary
432 //=======================================================================
434 // computes index for the patch by given parameter Param
435 static Standard_Integer GetPatchIndex (const Standard_Real Param,
436 const Handle(TColStd_HArray1OfReal) &Params,
437 const Standard_Boolean isClosed)
439 Standard_Integer NP = Params->Upper();
440 Standard_Real period = Params->Value(NP) - Params->Value(1);
441 Standard_Real shift = 0;
443 shift = ShapeAnalysis::AdjustToPeriod ( Param, Params->Value(1), Params->Value(NP) );
444 Standard_Real p = Param + shift;
446 // locate patch: the same algo as in SE_CS::LocateParameter()
447 Standard_Integer i; // svv #1
448 for ( i = 2; i < NP; i++ ) {
449 // Standard_Real par = Params->Value(i);
450 if ( p < Params->Value(i) ) break;
454 Standard_Real ish = shift / period;
455 Standard_Integer ishift = (Standard_Integer)( ish <0 ? ish - 0.5 : ish + 0.5 );
456 return i - ishift * ( NP - 1 );
459 //=======================================================================
460 //function : LoadWires
462 //=======================================================================
464 void ShapeFix_ComposeShell::LoadWires (ShapeFix_SequenceOfWireSegment &seqw) const
468 // Init seqw by initial set of wires (with corresponding orientation)
469 for ( TopoDS_Iterator iw(myFace,Standard_False); iw.More(); iw.Next() )
471 TopoDS_Shape tmpW = Context()->Apply ( iw.Value() ) ;
472 if(tmpW.ShapeType() != TopAbs_WIRE)
474 if(tmpW.ShapeType() == TopAbs_VERTEX)
476 ShapeFix_WireSegment seg; //(( isOuter ? TopAbs_REVERSED : TopAbs_FORWARD ) );
477 seg.SetVertex(TopoDS::Vertex(tmpW));
478 seg.Orientation(tmpW.Orientation());
485 TopoDS_Wire wire = TopoDS::Wire ( tmpW );
487 Standard_Boolean isNonManifold = ( wire.Orientation() != TopAbs_REVERSED &&
488 wire.Orientation() != TopAbs_FORWARD );
490 // protect against INTERNAL/EXTERNAL wires
491 // if ( wire.Orientation() != TopAbs_REVERSED &&
492 // wire.Orientation() != TopAbs_FORWARD ) continue;
494 // determine orientation of the wire
495 // TopoDS_Face face = TopoDS::Face ( myFace.EmptyCopied() );
496 // B.Add ( face, wire );
497 // Standard_Boolean isOuter = ShapeAnalysis::IsOuterBound ( face );
501 Handle(ShapeExtend_WireData) sbwd = new ShapeExtend_WireData ( wire ,Standard_True,Standard_False);
502 //pdn protection against wires w/o edges
503 Standard_Integer nbEdges = sbwd->NbEdges();
506 //wire segments for non-manifold topology should have INTERNAL orientation
507 ShapeFix_WireSegment seg ( sbwd, TopAbs_INTERNAL);
513 //splitting wires containing manifold and non-manifold parts on a separate
515 Handle(ShapeExtend_WireData) sbwdM = new ShapeExtend_WireData();
516 Handle(ShapeExtend_WireData) sbwdNM = new ShapeExtend_WireData();
517 sbwdNM->ManifoldMode() = Standard_False;
518 TopoDS_Iterator aIt(wire);
519 for( ; aIt.More(); aIt.Next())
521 TopoDS_Edge E = TopoDS::Edge ( aIt.Value() );
522 if(E.Orientation() == TopAbs_FORWARD || E.Orientation() == TopAbs_REVERSED)
528 Standard_Integer nbMEdges = sbwdM->NbEdges();
529 Standard_Integer nbNMEdges = sbwdNM->NbEdges();
533 ShapeFix_WireSegment seg ( sbwdNM, TopAbs_INTERNAL); //(( isOuter ? TopAbs_REVERSED : TopAbs_FORWARD ) );
538 // Orientation is set so as to allow the segment to be traversed in only one direction
540 Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
542 Standard_Integer stat=0;
543 Handle(Geom_Surface) gs = BRep_Tool::Surface(myFace);
544 if( gs->IsUPeriodic() && gs->IsVPeriodic() )
546 // For torus-like shapes, first reorder in 2d since reorder is indifferent in 3d
547 ShapeAnalysis_WireOrder sawo(Standard_False, 0);
548 ShapeAnalysis_Edge sae;
549 for(Standard_Integer i = 1; i <= nbMEdges; i++) {
551 Handle(Geom2d_Curve) c2d;
553 TopoDS_Shape tmpF = myFace.Oriented(TopAbs_FORWARD);
554 if(!sae.PCurve(sbwdM->Edge(i),TopoDS::Face(tmpF),c2d,f,l))
556 sawo.Add(c2d->Value(f).XY(),c2d->Value(l).XY());
560 stat = (sawo.Status() < 0 ? -1 : 1);
561 sfw->FixReorder(sawo);
565 if (sfw->StatusReorder(ShapeExtend_DONE3))
571 TopoDS_Shape dummy = myFace.EmptyCopied();
572 TopoDS_Face face = TopoDS::Face ( dummy );
573 B.Add ( face, wire );
574 Standard_Boolean isOuter = ShapeAnalysis::IsOuterBound ( face );
575 TopoDS_Wire w = sbwdM->Wire();
576 dummy = myFace.EmptyCopied();
577 face = TopoDS::Face ( dummy );
579 Standard_Boolean isOuterAfter = ShapeAnalysis::IsOuterBound ( face );
580 if(isOuter!=isOuterAfter)
581 sbwdM->Reverse(face);
584 ShapeFix_WireSegment seg ( sbwdM, TopAbs_REVERSED ); //(( isOuter ? TopAbs_REVERSED : TopAbs_FORWARD ) );
591 //=======================================================================
592 //function : ComputeCode
593 //purpose : compute code for wire segment between two intersections (by deviation)
594 //=======================================================================
596 Standard_Integer ShapeFix_ComposeShell::ComputeCode (const Handle(ShapeExtend_WireData) &wire,
597 const gp_Lin2d &line,
598 const Standard_Integer begInd,
599 const Standard_Integer endInd,
600 const Standard_Real begPar,
601 const Standard_Real endPar,
602 const Standard_Boolean isInternal)
604 Standard_Integer code = IOR_UNDEF;
606 ShapeAnalysis_Edge sae;
607 const Standard_Integer NPOINTS = 5; // number of points for measuring deviation
609 // track special closed case: segment starts at end of edge and ends at its beginning
610 Standard_Integer special = ( begInd == endInd &&
611 ( wire->Edge(begInd).Orientation() == TopAbs_FORWARD ||
612 wire->Edge(begInd).Orientation() == TopAbs_INTERNAL) ==
613 ( begPar > endPar ) ? 1 : 0);
614 if ( ! special && begInd == endInd && begPar == endPar && (myClosedMode || isInternal))
617 // for tracking cases in closed mode
618 Standard_Boolean begin=Standard_True;
619 Standard_Real shift=0;
622 // check if segment is tangency
623 // Segment is considered as tangency if deviation of pcurve from line
624 // (in 2d) measured by NPOINTS points is less than tolerance of edge
625 // (recomputed to 2d using Resolution).
627 Standard_Integer nb = wire->NbEdges();
629 Standard_Integer i; // svv #1
630 for ( i=begInd; ; i++ ) {
632 TopoDS_Edge edge = wire->Edge ( i );
634 Handle(Geom2d_Curve) c2d;
636 if ( ! sae.PCurve ( edge, myFace, c2d, f, l, Standard_False ) ) {
637 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL3 );
640 Standard_Real tol = LimitTolerance(BRep_Tool::Tolerance ( edge ));
641 Standard_Boolean isreversed = ( edge.Orientation() == TopAbs_REVERSED );
643 Standard_Real par1 = ( i == begInd && special >=0 ? begPar : ( isreversed ? l : f ) );
644 Standard_Real par2 = ( i == endInd && special <=0 ? endPar : ( isreversed ? f : l ) );
645 Standard_Real dpar = ( par2 - par1 ) / ( NPOINTS - 1 );
646 Standard_Integer np = ( Abs ( dpar ) < ::Precision::PConfusion() ? 1 : NPOINTS );
647 Standard_Integer j; // svv #1
648 for ( j=0; j < np; j++ ) {
649 Standard_Real par = par1 + dpar * j;
650 gp_Pnt2d p2d = c2d->Value ( par );
651 if ( myClosedMode ) {
652 if ( myUClosed && Abs ( line.Direction().X() ) < ::Precision::PConfusion() ) {
653 if ( begin ) shift = ShapeAnalysis::AdjustByPeriod ( p2d.X(), line.Location().X(), myUPeriod );
654 else if ( ! j ) shift = ShapeAnalysis::AdjustByPeriod ( p2d.X()-p2d0.X(), 0., myUPeriod );
655 p2d.SetX ( p2d.X() + shift );
657 if ( myVClosed && Abs ( line.Direction().Y() ) < ::Precision::PConfusion() ) {
658 if ( begin ) shift = ShapeAnalysis::AdjustByPeriod ( p2d.Y(), line.Location().Y(), myVPeriod );
659 else if ( ! j ) shift = ShapeAnalysis::AdjustByPeriod ( p2d.Y()-p2d0.Y(), 0., myVPeriod );
660 p2d.SetY ( p2d.Y() + shift );
662 begin = Standard_False;
665 Standard_Integer pos = PointLinePosition ( p2d, line );
666 if ( pos == IOR_UNDEF ) continue;
668 // analyse the deviation
669 gp_Pnt2d p2dl = ProjectPointOnLine ( p2d, line );
670 if(!IsCoincided ( p2d, p2dl, myUResolution, myVResolution, tol )) {
671 if(!myClosedMode) { code = pos; break; }
677 if ( j < np ) { i = 0; break; } // not tangency
679 if ( special <=0 ) break;
683 if ( myClosedMode ) {
684 if ( code != IOR_UNDEF && ! begin ) {
685 // in closed mode, if segment is of 2*pi length, it is BOTH
686 Standard_Real dev = PointLineDeviation ( p2d0, line );
687 if ( myUClosed && Abs ( line.Direction().X() ) < ::Precision::PConfusion() ) {
688 if ( Abs ( Abs ( dev ) - myUPeriod ) < 0.1 * myUPeriod ) {
690 if ( dev >0 ) code |= IOR_POS;
692 else if(code==IOR_BOTH)
695 if ( myVClosed && Abs ( line.Direction().Y() ) < ::Precision::PConfusion() ) {
696 if ( Abs ( Abs ( dev ) - myVPeriod ) < 0.1 * myVPeriod ) {
698 if ( dev >0 ) code |= IOR_POS;
700 else if(code==IOR_BOTH)
706 if ( i ) code = IOR_UNDEF; // tangency
707 else if ( code == IOR_BOTH ) { // parity error in intersector
709 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
711 std::cout << "Warning: ShapeFix_ComposeShell::ComputeCode: lost intersection point" << std::endl;
717 //=======================================================================
718 //function : DistributeSplitPoints
719 //purpose : auxiliary
720 //=======================================================================
721 // After applying context to (seam) edge, distribute its indices on new edges,
722 // according to their parameters on that edge
723 static void DistributeSplitPoints (const Handle(ShapeExtend_WireData) &sbwd,
724 const TopoDS_Face myFace,
725 const Standard_Integer index,
726 const Standard_Integer nsplit,
727 TColStd_SequenceOfInteger& indexes,
728 const TColStd_SequenceOfReal& values)
730 Standard_Boolean isreversed = ( nsplit >0 && sbwd->Edge(index).Orientation() == TopAbs_REVERSED );
732 TColStd_Array1OfReal params(0,nsplit);
733 Standard_Integer i; // svv #1
734 for ( i=0; i < nsplit; i++ ) {
736 BRep_Tool::Range ( sbwd->Edge(index+i), myFace, f, l );
737 params.SetValue ( i, ( isreversed ? l : f ) );
740 for ( i=1; i <= indexes.Length() && indexes(i) < index; i++ );
741 for ( Standard_Integer shift = 1; i <= indexes.Length() && indexes(i) == index; i++ ) {
742 while ( shift < nsplit && isreversed != (values(i) > params(shift)) ) shift++;
743 indexes.SetValue ( i, index + shift - 1 );
745 for ( ; i <= indexes.Length(); i++ )
746 indexes.SetValue ( i, indexes(i) + nsplit - 1 );
749 //=======================================================================
750 //function : CheckByCurve3d
751 //purpose : auxiliary
752 //=======================================================================
753 static Standard_Integer CheckByCurve3d (const gp_Pnt &pos,
754 const Handle(Geom_Curve) &c3d,
755 const Standard_Real param,
757 const Standard_Real tol)
759 if ( c3d.IsNull() ) return Standard_True;
760 gp_Pnt p = c3d->Value(param);
761 if ( T.Form() != gp_Identity ) p.Transform ( T );
762 return pos.SquareDistance ( p ) <= tol * tol;
765 //=======================================================================
766 //function : DefinePatch
767 //purpose : auxiliary
768 //=======================================================================
769 static void DefinePatch (ShapeFix_WireSegment &wire, const Standard_Integer code,
770 const Standard_Boolean isCutByU, const Standard_Integer cutIndex,
771 const Standard_Integer number = -1)
773 Standard_Integer nb = (number > 0 ? number : wire.NbEdges());
775 if ( ! ( code & IOR_LEFT ) ) wire.DefineIUMin ( nb, cutIndex );
776 if ( ! ( code & IOR_RIGHT ) ) wire.DefineIUMax ( nb, cutIndex );
779 if ( ! ( code & IOR_RIGHT ) ) wire.DefineIVMin ( nb, cutIndex );
780 if ( ! ( code & IOR_LEFT ) ) wire.DefineIVMax ( nb, cutIndex );
784 //=======================================================================
785 //function : GetGridResolution
786 //purpose : auxiliary
787 //=======================================================================
788 static Standard_Real GetGridResolution(const Handle(TColStd_HArray1OfReal) SplitValues,
789 const Standard_Integer cutIndex)
791 Standard_Integer nb = SplitValues->Length();
792 Standard_Real leftLen = (cutIndex > 1 ? SplitValues->Value(cutIndex) - SplitValues->Value(cutIndex-1) :
793 SplitValues->Value(nb) -SplitValues->Value(nb-1));
794 Standard_Real rigthLen =(cutIndex < nb ? SplitValues->Value(cutIndex+1)-SplitValues->Value(cutIndex) :
795 SplitValues->Value(2) - SplitValues->Value(1));
796 return Min(leftLen,rigthLen)/3.;
799 //=======================================================================
800 //function : SplitWire
802 //=======================================================================
804 ShapeFix_WireSegment ShapeFix_ComposeShell::SplitWire (ShapeFix_WireSegment &wire,
805 TColStd_SequenceOfInteger& indexes,
806 const TColStd_SequenceOfReal& values,
807 TopTools_SequenceOfShape& vertices,
808 const TColStd_SequenceOfInteger &SegmentCodes,
809 const Standard_Boolean isCutByU,
810 const Standard_Integer cutIndex)
813 ShapeFix_WireSegment result;
814 Handle(ShapeAnalysis_Surface) aSurfTool =
815 new ShapeAnalysis_Surface ( BRep_Tool::Surface (myFace) );
816 Standard_Integer nbSplits = indexes.Length();
817 ShapeAnalysis_Edge sae;
818 Standard_Integer start = 1;
819 TopAbs_Orientation anWireOrient = wire.Orientation();
821 if ( ! myLoc.IsIdentity() ) T = myLoc.Inverted().Transformation();
823 // Processing edge by edge (assuming that split points are sorted along the wire)
824 for ( Standard_Integer i = 1; i <= wire.NbEdges(); i++ ) {
826 // for already split seam edge, redistribute its splitting points
827 Standard_Integer nsplit = ApplyContext ( wire, i, Context() );
829 DistributeSplitPoints ( wire.WireData(), myFace, i, nsplit, indexes, values );
832 std::cout << "Error: ShapeFix_ComposeShell::SplitWire: edge dismissed" << std::endl;
838 TopoDS_Edge edge = wire.Edge(i);
840 Standard_Integer iumin, iumax, ivmin, ivmax;
841 wire.GetPatchIndex ( i, iumin, iumax, ivmin, ivmax );
843 // Position code for first segment of edge
844 Standard_Integer code = SegmentCodes ( start >1 ? start-1 : SegmentCodes.Length() );
846 // Defining split parameters on edge
847 Standard_Integer stop = start;
848 while ( stop <= nbSplits && indexes(stop) == i ) stop++;
849 if ( stop == start ) {
850 result.AddEdge ( 0, edge, iumin, iumax, ivmin, ivmax );
851 if(code!=0 || wire.Orientation()!=TopAbs_EXTERNAL) // pdn 0 code handling for extertnal wires
852 DefinePatch ( result, code, isCutByU, cutIndex );
855 //find non-manifold vertices on edge
856 TopTools_SequenceOfShape aNMVertices;
857 TopoDS_Iterator aIt(edge,Standard_False);
858 for( ; aIt.More(); aIt.Next()) {
859 if(aIt.Value().Orientation() != TopAbs_FORWARD &&
860 aIt.Value().Orientation() != TopAbs_REVERSED)
861 aNMVertices.Append(aIt.Value());
864 // Collect data on edge
865 Standard_Real tolEdge = BRep_Tool::Tolerance(edge);
866 TopoDS_Vertex prevV = sae.FirstVertex(edge);
867 TopoDS_Vertex lastV = sae.LastVertex(edge);
868 Standard_Real prevVTol = LimitTolerance( BRep_Tool::Tolerance(prevV) );
869 Standard_Real lastVTol = LimitTolerance( BRep_Tool::Tolerance(lastV) );
870 gp_Pnt prevVPnt = BRep_Tool::Pnt(prevV);
871 gp_Pnt lastVPnt = BRep_Tool::Pnt(lastV);
872 if ( T.Form() != gp_Identity ) {
873 prevVPnt.Transform ( T );
874 lastVPnt.Transform ( T );
877 Handle(Geom_Curve) c3d;
878 Standard_Real f3d, l3d;
879 if ( ! sae.Curve3d ( edge, c3d, f3d, l3d ) ) { // not a crime
884 Standard_Real firstPar, lastPar;
885 Handle(Geom2d_Curve) C2d;
886 if ( ! sae.PCurve ( edge, myFace, C2d, firstPar, lastPar ) ) {
887 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
889 //finding sequence of non-manifold parameters
890 Standard_Integer nbNMVert = aNMVertices.Length();
891 TColStd_SequenceOfReal aNMVertParams;
893 Geom2dAdaptor_Curve adc(C2d);
894 Standard_Integer n =1;
895 for( ; n<= nbNMVert; n++) {
896 gp_Pnt apV = BRep_Tool::Pnt(TopoDS::Vertex(aNMVertices.Value(n)));
897 Standard_Real apar =firstPar;
898 Standard_Real adist2 =RealLast();
901 ShapeAnalysis_Curve asae;
902 adist2 = asae.Project(c3d,apV,Precision::Confusion(),aPproj,apar);
906 gp_Pnt2d aP2d = aSurfTool->ValueOfUV(apV,Precision::Confusion());
907 Extrema_ExtPC2d aExtr(aP2d,adc);
908 if(aExtr.IsDone() && aExtr.NbExt()) {
909 adist2 = aExtr.SquareDistance(1);
910 Standard_Integer index =1;
911 Standard_Integer k =2;
912 for( ; k <= aExtr.NbExt();k++) {
913 Standard_Real ad2 = aExtr.SquareDistance(k);
919 apar = aExtr.Point(index).Parameter();
922 aNMVertParams.Append(apar);
926 //pdn Claculating parametric shift
927 Standard_Boolean sp = (f3d == firstPar && l3d == lastPar);
928 Standard_Real span2d = lastPar - firstPar;
929 // Standard_Real ln2d = lastPar-prevPar;
930 // Standard_Real ln3d = l3d - f3d;
931 // Standard_Real fact = ln2d/ln3d;
932 // Standard_Real shift = prevPar - f3d*fact;
933 Standard_Real prevPar = firstPar;
934 gp_Pnt2d prevPnt2d = C2d->Value(prevPar);
935 gp_Pnt2d lastPnt2d = C2d->Value(lastPar);
936 gp_Pnt prevPnt = myGrid->Value ( prevPnt2d );
937 gp_Pnt lastPnt = myGrid->Value ( lastPnt2d );
938 Standard_Boolean isPeriodic = C2d->IsPeriodic();
939 Standard_Real aPeriod = (isPeriodic ? C2d->Period() :0.);
942 Standard_Integer NbEdgesStart = result.NbEdges();
943 Standard_Boolean splitted = Standard_False;
944 Standard_Real currPar=lastPar; //SK
945 for ( Standard_Integer j = start; j <= stop; prevPar = currPar, j++ ) {
946 if ( ! splitted && j >= stop ) {// no splitting at all
947 // code = SegmentCodes ( j >1 ? j-1 : SegmentCodes.Length() ); // classification code
950 currPar = ( j < stop ? values.Value(j) : lastPar );
951 //fix for case when pcurve is periodic and first parameter of edge is more than 2P
952 //method ShapeBuild_Edge::CopyRanges shift pcurve to range 0-2P and parameters of cutting
953 //should be shifted too. gka SAMTECH 28.07.06
955 if (currPar > (Max(lastPar,firstPar) +Precision::PConfusion()) ||
956 currPar < (Min(firstPar,lastPar)- Precision::PConfusion())) {
957 Standard_Real aShift = ShapeAnalysis::AdjustByPeriod(currPar, (firstPar+lastPar)*0.5,aPeriod);
965 // Try to adjust current splitting point to previous or end of edge
966 Standard_Boolean doCut = Standard_True;
968 if ( Abs ( currPar - lastPar ) < ::Precision::PConfusion() ) {
970 doCut = Standard_False;
972 else if ( Abs ( currPar - prevPar ) < ::Precision::PConfusion() ) {
973 vertices.Append ( prevV );
974 code = SegmentCodes ( j ); // classification code - update for next segment
975 continue; // no splitting at this point, go to next one
978 currPnt2d = C2d->Value(currPar);
979 currPnt = myGrid->Value ( currPnt2d );
980 if ( currPnt.Distance ( lastVPnt ) <= lastVTol &&
981 // Tolerance is increased to prevent degenerated cuts in cases where all vertex
982 // tolerance is covered by distance of the edge curve from vertex point.
983 // Doubled to prevent edge being fully covered by its vertices tolerance (invalid edge).
984 CheckByCurve3d ( lastVPnt, c3d, f3d+(currPar-firstPar)*(l3d-f3d)/span2d,
985 T, lastVTol + 2 * Precision::Confusion() ) &&
986 lastPnt.Distance (myGrid->Value (C2d->Value(0.5*(currPar+lastPar)))) <= lastVTol) {
988 Standard_Real uRes = myUResolution;
989 Standard_Real vRes = myVResolution;
991 Standard_Real gridRes = GetGridResolution(myGrid->UJointValues(), cutIndex) / lastVTol;
992 uRes = Min(myUResolution,gridRes);
995 Standard_Real gridRes = GetGridResolution(myGrid->VJointValues(), cutIndex) / lastVTol;
996 vRes = Min(myVResolution,gridRes);
998 if (IsCoincided(lastPnt2d, currPnt2d, uRes, vRes, lastVTol) &&
999 IsCoincided(lastPnt2d, C2d->Value(0.5*(currPar + lastPar)), uRes, vRes, lastVTol))
1000 doCut = Standard_False;
1002 else if ( currPnt.Distance ( prevVPnt ) <= prevVTol &&
1003 // Tolerance is increased to prevent degenerated cuts in cases where all vertex
1004 // tolerance is covered by distance of the edge curve from vertex point.
1005 // Doubled to prevent edge being fully covered by its vertices tolerance (invalid edge).
1006 CheckByCurve3d ( prevVPnt, c3d, f3d+(currPar-firstPar)*(l3d-f3d)/span2d,
1007 T, prevVTol + 2 * Precision::Confusion()) &&
1008 prevPnt.Distance (myGrid->Value (C2d->Value(0.5*(currPar+prevPar)))) <= prevVTol) {
1010 Standard_Real uRes = myUResolution;
1011 Standard_Real vRes = myVResolution;
1013 Standard_Real gridRes = GetGridResolution(myGrid->UJointValues(), cutIndex) / prevVTol;
1014 uRes = Min(myUResolution,gridRes);
1017 Standard_Real gridRes = GetGridResolution(myGrid->VJointValues(), cutIndex) / prevVTol;
1018 vRes = Min(myVResolution,gridRes);
1020 if (IsCoincided(prevPnt2d, currPnt2d, uRes, vRes, prevVTol) &&
1021 IsCoincided(prevPnt2d, C2d->Value(0.5*(currPar + prevPar)), uRes, vRes, prevVTol)) {
1023 vertices.Append ( prevV );
1024 code = SegmentCodes ( j ); // classification code - update for next segment
1025 continue; // no splitting at this point, go to next one
1028 //:abv 28.05.02: OCC320 Sample_2: if maxtol = 1e-7, the vertex tolerance
1029 // is actually ignored - protect against new vertex on degenerated edge
1030 else if ( BRep_Tool::Degenerated(edge) && prevV.IsSame(lastV) ) {
1034 // classification code for current segment
1035 if ( j > start ) code = SegmentCodes ( j >1 ? j-1 : SegmentCodes.Length() );
1037 // if not adjusted, make new vertex
1039 B.MakeVertex ( V, currPnt.Transformed(myLoc.Transformation()), tolEdge );
1040 vertices.Append ( V );
1042 // else adjusted to end, fill all resting vertices
1043 else if ( ! doCut ) {
1044 for ( ; j < stop; j++ ) vertices.Append ( lastV );
1045 if ( ! splitted ) break; // no splitting at all
1048 else vertices.Append ( V );
1050 // When edge is about to be split, copy end vertices to protect
1051 // original shape from increasing tolerance after fixing SameParameter
1054 TopoDS_Shape emptyCopiedfV = prevV.EmptyCopied();
1055 TopoDS_Vertex fV = TopoDS::Vertex (emptyCopiedfV );
1056 Context()->Replace ( prevV, fV );
1058 if ( prevV.IsSame ( lastV ) ) {
1060 TopoDS_Shape tmpV = fV.Oriented ( lastV.Orientation() ) ;
1061 lV = TopoDS::Vertex (tmpV);
1065 TopoDS_Shape emptyCopied = lastV.EmptyCopied();
1066 lV = TopoDS::Vertex (emptyCopied);
1067 Context()->Replace ( lastV, lV );
1069 if ( V.IsSame ( lastV ) ) V = lV;
1070 else if ( V.IsSame ( prevV ) ) V = fV;
1075 // Splitting of the edge
1076 splitted = Standard_True;
1077 prevV.Orientation ( TopAbs_FORWARD );
1078 V.Orientation ( TopAbs_REVERSED );
1079 ShapeBuild_Edge sbe;
1080 TopoDS_Edge anInitEdge = edge;
1081 Standard_Boolean ismanifold = (edge.Orientation() == TopAbs_FORWARD ||
1082 edge.Orientation() == TopAbs_REVERSED);
1084 anInitEdge.Orientation(TopAbs_FORWARD);
1085 TopoDS_Edge newEdge = sbe.CopyReplaceVertices (anInitEdge, prevV, V );
1087 //addition internal vertices if they exists on edge
1088 Standard_Integer n =1;
1089 for( ; n <= aNMVertParams.Length(); n++) {
1090 Standard_Real apar = aNMVertParams.Value(n);
1091 TopoDS_Vertex aNMVert =TopoDS::Vertex(aNMVertices.Value(n));
1092 TopoDS_Vertex atmpV = TopoDS::Vertex(Context()->Apply(aNMVert));
1093 if(fabs(apar - prevPar) <= Precision::PConfusion()) {
1094 Context()->Replace(atmpV,prevV);
1095 aNMVertParams.Remove(n);
1096 aNMVertices.Remove(n);
1099 else if(fabs(apar - currPar) <= Precision::PConfusion()) {
1100 Context()->Replace(atmpV,V);
1101 aNMVertParams.Remove(n);
1102 aNMVertices.Remove(n);
1105 if(apar > prevPar && apar < currPar) {
1106 B.Add(newEdge,atmpV);
1107 aNMVertParams.Remove(n);
1108 aNMVertices.Remove(n);
1113 sbe.CopyPCurves ( newEdge, anInitEdge );
1115 Handle(ShapeAnalysis_TransferParameters) theTransferParamtool = GetTransferParamTool();
1116 theTransferParamtool->SetMaxTolerance(MaxTolerance());
1117 theTransferParamtool->Init(anInitEdge,myFace);
1118 theTransferParamtool->TransferRange(newEdge,prevPar,currPar,Standard_True);
1121 if(code == IOR_UNDEF) //tangential segment
1122 newEdge.Orientation(TopAbs_EXTERNAL);
1124 newEdge.Orientation(edge.Orientation());
1127 if(!sp && !BRep_Tool::Degenerated(newEdge))
1128 B.SameRange(newEdge, Standard_False);
1129 //pdn take into account 0 codes (if ext)
1130 if(code == 0 && wire.Orientation()==TopAbs_EXTERNAL){
1131 code = ( ( isCutByU == (j == 1) ) ? 1 : 2 );
1134 result.AddEdge ( 0, newEdge, iumin, iumax, ivmin, ivmax );
1135 DefinePatch ( result, code, isCutByU, cutIndex );
1137 // Changing prev parameters
1139 prevVTol = LimitTolerance( BRep_Tool::Tolerance ( V ) );
1140 prevVPnt = BRep_Tool::Pnt ( V );
1142 prevPnt2d = currPnt2d;
1147 // record replacement in context
1148 // NOTE: order of edges in the replacing wire corresponds to FORWARD orientation of the edge
1149 TopoDS_Wire resWire;
1150 B.MakeWire ( resWire );
1151 for ( Standard_Integer k=NbEdgesStart; k < result.NbEdges(); k++ ) {
1152 if ( edge.Orientation() == TopAbs_FORWARD || edge.Orientation() == TopAbs_INTERNAL)
1153 B.Add ( resWire, result.Edge(k+1) );
1154 else B.Add ( resWire, result.Edge(result.NbEdges()-k+NbEdgesStart) );
1156 Context()->Replace ( edge, resWire );
1159 if(anWireOrient == TopAbs_INTERNAL && code ==0) {
1160 ShapeBuild_Edge sbe;
1161 if(edge.Orientation() == TopAbs_INTERNAL)
1162 edge.Orientation(TopAbs_FORWARD);
1163 TopoDS_Edge e1 = sbe.Copy(edge,Standard_False);
1164 Handle(Geom2d_Curve) C2d2 = Handle(Geom2d_Curve)::DownCast(C2d->Copy());
1165 B.UpdateEdge(e1,C2d,C2d2,myFace,0.);
1166 e1.Orientation(TopAbs_EXTERNAL);
1167 Context()->Replace ( edge,e1);
1168 result.AddEdge ( 0,e1 , iumin, iumax, ivmin, ivmax );
1171 result.AddEdge ( 0, edge, iumin, iumax, ivmin, ivmax );
1172 if(code == 0 && wire.Orientation()==TopAbs_EXTERNAL){
1173 //pdn defining code for intersection of two isos
1174 code = ( ( isCutByU == ( Abs(firstPar-currPar) < Abs(lastPar-currPar) ) ) ? 2 : 1 );
1176 DefinePatch ( result, code, isCutByU, cutIndex );
1179 result.Orientation ( anWireOrient );
1183 //=======================================================================
1184 //function : SplitByLine
1186 //=======================================================================
1188 Standard_Boolean ShapeFix_ComposeShell::SplitByLine (ShapeFix_WireSegment &wire,
1189 const gp_Lin2d &line,
1190 const Standard_Boolean isCutByU,
1191 const Standard_Integer cutIndex,
1192 TColStd_SequenceOfReal &SplitLinePar,
1193 TColStd_SequenceOfInteger &SplitLineCode,
1194 TopTools_SequenceOfShape &SplitLineVertex)
1196 ShapeAnalysis_Edge sae;
1197 // prepare data on cutting line
1198 Handle(Geom2d_Line) jC2d = new Geom2d_Line ( line );
1199 Geom2dAdaptor_Curve jGAC(jC2d);
1201 TColStd_SequenceOfInteger IntEdgeInd; // index of intersecting edge
1202 TColStd_SequenceOfReal IntEdgePar; // parameter of intersection point on edge
1203 TColStd_SequenceOfReal IntLinePar; // parameter of intersection point on line
1205 Standard_Boolean isnonmanifold = (wire.Orientation() == TopAbs_INTERNAL);
1206 //gka correction for non-manifold vertices SAMTECH
1207 if(wire.IsVertex()) {
1208 Handle(ShapeAnalysis_Surface) aSurfTool = new ShapeAnalysis_Surface ( BRep_Tool::Surface (myFace) );
1209 TopoDS_Vertex aVert = wire.GetVertex();
1210 gp_Pnt aP3d = BRep_Tool::Pnt(aVert);
1211 gp_Pnt2d aP2d = aSurfTool->ValueOfUV(aP3d,Precision::Confusion());
1212 Standard_Real dev =0.;
1213 Standard_Integer code = PointLinePosition(aP2d,line,dev);
1214 if(code != IOR_UNDEF)
1215 return Standard_False;
1216 Standard_Real par = ParamPointOnLine (aP2d,line);
1217 SplitLinePar.Append ( par );
1218 //splitting codes for non-manifold topology should be tangential
1219 SplitLineCode.Append (ITP_TANG); //ITP_INTER);
1220 TopoDS_Vertex aVertNew;
1222 aB.MakeVertex(aVertNew,aP3d,BRep_Tool::Tolerance(aVert));
1223 aVertNew.Orientation(TopAbs_FORWARD);
1224 Context()->Replace(aVert,aVertNew);
1225 SplitLineVertex.Append (aVertNew);
1226 wire.SetVertex(aVertNew);
1227 return Standard_True;
1229 const Handle(ShapeExtend_WireData) sewd = wire.WireData();
1231 Standard_Integer nbe = sewd->NbEdges();
1233 //:abv 31.10.01: for closed mode
1234 Standard_Integer closedDir = 0;
1235 if ( myClosedMode ) {
1236 if ( myUClosed && Abs ( line.Direction().X() ) < ::Precision::PConfusion() )
1238 else if ( myVClosed && Abs ( line.Direction().Y() ) < ::Precision::PConfusion() )
1241 Standard_Real halfPeriod = 0.5 * ( closedDir ? closedDir <0 ? myUPeriod : myVPeriod : 0. );
1243 //============================================
1244 // make intersections and collect all data on intersection points
1245 Standard_Integer firstCode=0, prevCode=0;
1246 gp_Pnt2d firstPos, prevPos;
1247 Standard_Real firstDev=0., prevDev=0.;
1248 for (Standard_Integer iedge = 1; iedge <= nbe; iedge++) {
1249 TopoDS_Edge E= sewd->Edge ( iedge );
1250 Standard_Boolean isreversed = ( E.Orientation() == TopAbs_REVERSED );
1253 Handle(Geom2d_Curve) c2d;
1254 if ( ! sae.PCurve ( E, myFace, c2d, f, l, Standard_False ) ) continue;
1255 Handle(Geom2d_Curve) c2d_sav = c2d;
1258 gp_Pnt2d posf = c2d->Value(f), posl = c2d->Value(l);
1259 gp_XY pppf = posf.XY(), pppl = posl.XY();
1261 // In case of ClosedMode, adjust curve and end points to period on closed surface
1262 //:abv 16.10.01: Ziegler_CADDY01.sat -18: if pcurve is longer than period,
1263 // ensure processing of all intersections
1264 Standard_Integer nbIter = 1;
1265 gp_Vec2d shiftNext(0.,0.);
1266 if ( myClosedMode ) {
1267 // get bounding box of pcurve
1268 ShapeAnalysis_Curve sac;
1270 const Standard_Integer aNbPoints = 41;
1271 sac.FillBndBox ( c2d, f, l, aNbPoints, Standard_True, box );
1272 Standard_Real umin, vmin, umax, vmax;
1273 box.Get ( umin, vmin, umax, vmax );
1275 // compute shifts and adjust points adjust
1276 if ( closedDir < 0 ) {
1277 Standard_Real x = line.Location().X();
1278 Standard_Real shift = ShapeAnalysis::AdjustToPeriod ( umin, x-myUPeriod, x );
1279 if ( shift != 0. ) {
1280 c2d = Handle(Geom2d_Curve)::DownCast ( c2d->Copy() );
1281 gp_Vec2d V ( shift, 0. );
1282 c2d->Translate ( V );
1283 pppf.SetX ( pppf.X() + shift );
1284 pppl.SetX ( pppl.X() + shift );
1286 Standard_Real dUmax = umax + shift - x;
1287 shiftNext.SetX (dUmax > 0 ? -myUPeriod : myUPeriod);
1288 nbIter = (Standard_Integer)(1 + Abs (dUmax) / myUPeriod);
1289 shift = ShapeAnalysis::AdjustByPeriod ( posf.X(), x, myUPeriod );
1290 posf.SetX ( posf.X() + shift );
1291 shift = ShapeAnalysis::AdjustByPeriod ( posl.X(), x, myUPeriod );
1292 posl.SetX ( posl.X() + shift );
1294 else if ( closedDir > 0 ) {
1295 Standard_Real y = line.Location().Y();
1296 Standard_Real shift = ShapeAnalysis::AdjustToPeriod ( vmin, y-myVPeriod, y );
1297 if ( shift != 0. ) {
1298 c2d = Handle(Geom2d_Curve)::DownCast ( c2d->Copy() );
1299 gp_Vec2d V ( 0., shift );
1300 c2d->Translate ( V );
1301 pppf.SetY ( pppf.Y() + shift );
1302 pppl.SetY ( pppl.Y() + shift );
1304 Standard_Real dVmax = vmax + shift - y;
1305 shiftNext.SetY (dVmax > 0 ? -myVPeriod : myVPeriod);
1306 nbIter = (Standard_Integer)(1 + Abs (dVmax) / myVPeriod);
1307 shift = ShapeAnalysis::AdjustByPeriod ( posf.Y(), y, myVPeriod );
1308 posf.SetY ( posf.Y() + shift );
1309 shift = ShapeAnalysis::AdjustByPeriod ( posl.Y(), y, myVPeriod );
1310 posl.SetY ( posl.Y() + shift );
1314 // detect intersections at junction of two edges
1315 gp_Pnt2d pos = ( isreversed ? posl : posf );
1317 Standard_Integer code = PointLinePosition ( pos, line, dev );
1318 if ( iedge ==1 ) { firstCode = code; firstPos = pos; firstDev = dev; }
1319 else if ( code == IOR_UNDEF || code != prevCode ) {
1320 if ( ! closedDir || Abs ( dev - prevDev ) < halfPeriod ) {
1321 IntLinePar.Append ( ParamPointsOnLine ( pos, prevPos, line ) ); // !! - maybe compute exactly ?
1322 IntEdgePar.Append ( isreversed ? l : f );
1323 IntEdgeInd.Append ( iedge );
1327 // fill data on end point (for next edge)
1328 pos = ( isreversed ? posf : posl );
1329 prevCode = PointLinePosition ( pos, line, prevDev );
1332 // cycle with shift in order to track all possible intersections
1333 for ( Standard_Integer iter=1; iter <= nbIter; iter++ ) {
1334 // data for intersection
1335 IntRes2d_Domain iDom ( pppf, f, TOLINT, pppl, l, TOLINT );
1336 Geom2dAdaptor_Curve iGAC(c2d);
1339 Geom2dInt_GInter Inter;
1340 Inter.Perform ( jGAC, /*jDom,*/ iGAC, iDom, TOLINT, TOLINT );
1342 // Fill arrays with new intersection points
1343 if ( Inter.IsDone() ) {
1345 for ( i = 1; i <= Inter.NbPoints(); i++ ) {
1346 IntRes2d_IntersectionPoint IP = Inter.Point (i);
1347 if (IP.TransitionOfSecond().PositionOnCurve() == IntRes2d_Middle || (code != IOR_UNDEF && prevCode != IOR_UNDEF) )
1349 IntLinePar.Append (IP.ParamOnFirst());
1350 IntEdgePar.Append (IP.ParamOnSecond());
1353 for ( i = 1; i <= Inter.NbSegments(); i++ ) {
1354 IntRes2d_IntersectionSegment IS = Inter.Segment (i);
1355 if ( IS.HasFirstPoint() ) {
1356 IntRes2d_IntersectionPoint IP = IS.FirstPoint();
1357 IntLinePar.Append ( IP.ParamOnFirst() );
1358 IntEdgePar.Append ( IP.ParamOnSecond() );
1360 if ( IS.HasLastPoint() ) {
1361 IntRes2d_IntersectionPoint IP = IS.LastPoint();
1362 IntLinePar.Append ( IP.ParamOnFirst() );
1363 IntEdgePar.Append ( IP.ParamOnSecond() );
1367 if ( iter < nbIter ) {
1368 if ( iter == 1 ) c2d = Handle(Geom2d_Curve)::DownCast ( c2d->Copy() );
1369 pppf += shiftNext.XY();
1370 pppl += shiftNext.XY();
1371 c2d->Translate ( shiftNext );
1375 Standard_Integer start = IntEdgeInd.Length() + 1; // first of the new points
1377 // Move all points into range [f,l] (intersector sometimes gives params out of range)
1379 for ( i = start; i <= IntEdgePar.Length(); i++ ) {
1380 if ( IntEdgePar(i) < f ) IntEdgePar.SetValue ( i, f );
1381 else if ( IntEdgePar(i) > l ) IntEdgePar.SetValue ( i, l );
1384 // Sort by parameter on edge
1385 for ( i = IntEdgePar.Length(); i > start; i-- )
1386 for ( Standard_Integer j = start; j < i; j++ ) {
1387 if ( isreversed == ( IntEdgePar(j+1) < IntEdgePar(j) ) ) continue;
1388 IntLinePar.Exchange ( j, j+1 );
1389 IntEdgePar.Exchange ( j, j+1 );
1393 for ( i = start; i <= IntEdgePar.Length(); i++ )
1394 IntEdgeInd.Append ( iedge );
1396 // Detect intersection at closing point
1397 // Only wires which are not EXTERNAL are considered (as closed)
1398 if ( iedge == nbe && wire.Orientation() != TopAbs_EXTERNAL &&
1399 wire.Orientation() != TopAbs_INTERNAL &&
1400 ( prevCode == IOR_UNDEF || prevCode != firstCode ) ) {
1401 if ( ! closedDir || Abs ( firstDev - prevDev ) < halfPeriod ) {
1402 IntLinePar.Append ( ParamPointsOnLine ( pos, firstPos, line ) );
1403 IntEdgePar.Append ( isreversed ? f : l );
1404 IntEdgeInd.Append ( iedge );
1409 if ( IntEdgePar.Length() <1 ) {
1410 //pdn Defining position of wire. There is no intersection, so by any point.
1411 //DefinePatchForWire ( wire, firstCode, isCutByU, cutIndex );
1412 return Standard_False; //pdn ??
1415 //======================================
1416 // Fill sequence of transition codes for intersection points
1417 TColStd_SequenceOfInteger IntCode; // parameter of intersection point on line
1418 TColStd_SequenceOfInteger SegmentCodes; // classification codes for segments of wire
1420 // remove duplicated points to ensure correct results of ComputeCode
1421 Standard_Integer i, j = IntEdgePar.Length();
1422 if ( myClosedMode && j >1 ) {
1423 for ( i = 1; i <= IntEdgePar.Length(); ) {
1424 if ( i == j ) break;
1425 if ( IntEdgeInd(i) == IntEdgeInd(j) &&
1426 Abs ( IntEdgePar(i) - IntEdgePar(j) ) < ::Precision::PConfusion() ) {
1427 IntLinePar.Remove(i);
1428 IntEdgePar.Remove(i);
1429 IntEdgeInd.Remove(i);
1433 else if ( nbe ==1 || IntEdgeInd(i) == (IntEdgeInd(j)%nbe)+1 ) {
1434 TopoDS_Edge E1 = sewd->Edge ( IntEdgeInd(j) );
1435 TopoDS_Edge E2 = sewd->Edge ( IntEdgeInd(i) );
1436 Standard_Real a1, b1, a2, b2;
1437 BRep_Tool::Range ( E1, myFace, a1, b1 );
1438 BRep_Tool::Range ( E2, myFace, a2, b2 );
1439 if ( Abs ( IntEdgePar(j) - ( E1.Orientation() == TopAbs_FORWARD ? b1 : a1 ) ) < ::Precision::PConfusion() &&
1440 Abs ( IntEdgePar(i) - ( E2.Orientation() == TopAbs_FORWARD ? a2 : b2 ) ) < ::Precision::PConfusion() ) {
1441 IntLinePar.Remove(i);
1442 IntEdgePar.Remove(i);
1443 IntEdgeInd.Remove(i);
1451 //sequence of real codes for each segment
1452 TColStd_SequenceOfInteger aNewSegCodes;
1453 // Compute segment codes (left side of line, right or tangential)
1454 for ( i=1; i <= IntEdgePar.Length(); i++ ) {
1455 j = ( i < IntEdgePar.Length() ? i + 1 : 1 );
1456 Standard_Integer code = ComputeCode ( sewd, line, IntEdgeInd(i), IntEdgeInd(j),
1457 IntEdgePar(i), IntEdgePar(j),isnonmanifold );
1458 SegmentCodes.Append ( code );
1461 // for EXTERNAL wire, i.e. another joint line, every point is double intersection
1462 if ( wire.Orientation() == TopAbs_EXTERNAL ) {
1463 for ( i=1; i <= IntEdgePar.Length(); i++ )
1465 IntCode.Append ( ITP_TANG | IOR_BOTH );
1466 aNewSegCodes.Append(SegmentCodes(i));
1469 // For real (closed) wire, analyze tangencies
1471 if(wire.Orientation() != TopAbs_INTERNAL) {
1472 // Two consecutive tangential segments are considered as one, merge them.
1473 for ( i=1; i <= IntEdgePar.Length(); i++ ) {
1474 j = ( i > 1 ? i-1 : IntEdgePar.Length() );
1476 int k = ( i < IntEdgePar.Length() ? i + 1 : 1 ); // [ACIS22539]
1478 if ( SegmentCodes(j) == IOR_UNDEF &&
1479 SegmentCodes(i) == IOR_UNDEF ) {
1481 // Very specific case when the constructed seam edge
1482 // overlaps with spur edge [ACIS22539]
1483 if (myClosedMode && (IntLinePar(i) - IntLinePar(j)) * (IntLinePar(k) - IntLinePar(i)) <= 0. )
1486 IntEdgeInd.Remove(i);
1487 IntEdgePar.Remove(i);
1488 IntLinePar.Remove(i);
1489 SegmentCodes.Remove(i);
1494 //pdn exit if all split points removed
1495 if ( IntEdgePar.Length() <1 ) {
1496 return Standard_False; //pdn ??
1499 // Analyze type of intersection point and encode it
1500 // Three kinds of points (ITP): clear intersection, tangency in-point,
1501 // beginning and end of tangential segment.
1502 // Orientation (IOR) tells on which side of line edge crosses it
1503 j = IntEdgePar.Length();
1505 for ( i=1; i <= IntEdgePar.Length(); j = i++ ) {
1506 Standard_Integer codej = SegmentCodes(j);
1507 Standard_Integer codei = SegmentCodes(i);
1508 if ( myClosedMode ) {
1509 if ( ( codej & IOR_BOTH ) == IOR_BOTH ) //IOR_LEFT : IOR_RIGHT
1510 codej = ( codej & IOR_POS ? IOR_RIGHT : IOR_LEFT );
1511 if ( ( codei & IOR_BOTH ) == IOR_BOTH ) //IOR_RIGHT : IOR_LEFT
1512 codei = ( codei & IOR_POS ? IOR_LEFT : IOR_RIGHT );
1513 aNewSegCodes.Append ( codei );
1514 if(IntEdgeInd(i) == IntEdgeInd(j))
1515 aNewSegCodes.Append ( codej );
1519 aNewSegCodes.Append ( codei );
1520 Standard_Integer ipcode = ( codej | codei );
1521 if ( codej == IOR_UNDEF ) { // previous segment was tangency
1522 if ( IntLinePar(i) > IntLinePar (j) )
1523 ipcode |= ITP_ENDSEG; // end of segment
1524 else ipcode |= ITP_BEGSEG; // beginning of segment
1526 else if ( codei == IOR_UNDEF ) { // current segment is tangency
1527 if ( IntLinePar ( i < IntLinePar.Length() ? i+1 : 1 ) > IntLinePar(i) )
1528 ipcode |= ITP_BEGSEG; // beginning of segment
1529 else ipcode |= ITP_ENDSEG; // end of segment
1531 //internal wire can be only tangent
1532 else if ( i == j ) ipcode |= ( ( ipcode & IOR_BOTH ) == IOR_BOTH && !isnonmanifold ? ITP_INTER : ITP_TANG );
1533 else if ( codei == codej || isnonmanifold) ipcode |= ITP_TANG; // tangency in-point
1534 else ipcode |= ITP_INTER; // standard crossing
1535 IntCode.Append ( ipcode );
1539 //=======================================
1540 // Split edges in the wire by intersection points and fill vertices array
1541 TopTools_SequenceOfShape IntVertices;
1542 wire = SplitWire ( wire, IntEdgeInd, IntEdgePar, IntVertices,
1543 aNewSegCodes, isCutByU, cutIndex );
1545 // add all data to input arrays
1546 for ( i=1; i <= IntLinePar.Length(); i++ ) {
1547 SplitLinePar.Append ( IntLinePar(i) );
1548 SplitLineCode.Append ( IntCode(i) );
1549 SplitLineVertex.Append ( IntVertices(i) );
1552 return Standard_True;
1555 //=======================================================================
1556 //function : SplitByLine
1558 //=======================================================================
1560 void ShapeFix_ComposeShell::SplitByLine (ShapeFix_SequenceOfWireSegment &wires,
1561 const gp_Lin2d &line,
1562 const Standard_Boolean isCutByU,
1563 const Standard_Integer cutIndex)
1565 TColStd_SequenceOfReal SplitLinePar;
1566 TColStd_SequenceOfInteger SplitLineCode;
1567 TopTools_SequenceOfShape SplitLineVertex;
1569 // split wires one by one, collecting data on intersection points
1570 Standard_Integer i; // svv #1
1571 for ( i=1; i <= wires.Length(); i++ ) {
1572 SplitByLine ( wires(i), line, isCutByU, cutIndex,
1573 SplitLinePar, SplitLineCode, SplitLineVertex );
1576 // sort intersection points along parameter on cutting line
1577 for ( i = SplitLinePar.Length(); i >1; i-- )
1578 for ( Standard_Integer j=1; j < i; j++ ) {
1579 if ( SplitLinePar(j) > SplitLinePar(j+1) ) {
1580 SplitLinePar.Exchange ( j, j+1 );
1581 SplitLineCode.Exchange ( j, j+1 );
1582 SplitLineVertex.Exchange ( j, j+1 );
1586 // merge null-length tangential segments into one-point tangencies or intersections
1587 for ( i = 1; i < SplitLinePar.Length(); i++ ) {
1588 if ( Abs ( SplitLinePar(i+1) - SplitLinePar(i) ) > ::Precision::PConfusion() && !SplitLineVertex(i).IsSame(SplitLineVertex(i+1)) ) continue;
1589 if ( ( SplitLineCode(i) & ITP_ENDSEG &&
1590 SplitLineCode(i+1) & ITP_BEGSEG ) ||
1591 ( SplitLineCode(i) & ITP_BEGSEG &&
1592 SplitLineCode(i+1) & ITP_ENDSEG ) ) {
1593 Standard_Integer code = ( SplitLineCode(i) | SplitLineCode(i+1) ) & IOR_BOTH;
1594 SplitLineCode.SetValue ( i, code | ( code == IOR_BOTH ? ITP_INTER : ITP_TANG ) );
1595 SplitLinePar.Remove(i+1);
1596 SplitLineCode.Remove(i+1);
1597 SplitLineVertex.Remove(i+1);
1601 // go along line, split it by intersection points and create edges
1602 // (only for internal parts, in particular not for tangential segments)
1604 Standard_Integer parity = 0; // 0 - out, 1 - in
1605 Standard_Integer halfparity = 0; // left/right for tangential segments
1606 Standard_Integer tanglevel = 0; // tangency nesting level
1607 for ( i = 1; i <= SplitLinePar.Length(); i++ ) {
1608 Standard_Integer code = SplitLineCode(i);
1609 Standard_Boolean interior = ( !tanglevel && parity % 2 ); // create an edge
1610 if ( code & ITP_INTER ) { // crossing
1613 else if ( code & ITP_BEGSEG ) { // beginning of tangential segment
1615 if ( ! halfparity ) halfparity = ( code & IOR_BOTH );
1616 else if ( halfparity != ( code & IOR_BOTH ) ) parity++;
1618 else if ( code & ITP_ENDSEG ) { // end of tangential segment
1620 if ( ! halfparity ) halfparity = ( code & IOR_BOTH );
1621 else if ( halfparity != ( code & IOR_BOTH ) ) parity++;
1623 if ( tanglevel <0 ) {
1624 // myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL4 );
1626 std::cout << "Warning: ShapeFix_ComposeShell::SplitByLine: tangency level <0 !" << std::endl;
1629 if ( ! interior ) continue;
1631 // apply context to vertices (to perform replacing/merging vertices)
1633 TopoDS_Shape tmpV1 = Context()->Apply ( SplitLineVertex(i-1) );
1634 TopoDS_Shape tmpV2 = Context()->Apply ( SplitLineVertex(i) );
1635 TopoDS_Vertex V1 = TopoDS::Vertex ( tmpV1 );
1636 TopoDS_Vertex V2 = TopoDS::Vertex ( tmpV2 );
1637 // protection against creating null-length edges or edges lying inside tolerance of vertices
1638 //first and last vertices for split line can not be merged to each other
1639 Standard_Boolean canbeMerged = ( /*myClosedMode &&*/ (i -1 > 1 || i < SplitLinePar.Length()));
1640 Standard_Real aMaxTol = MaxTolerance();
1641 //case when max tolerance is not defined tolerance of vertices will be used as is
1642 if( aMaxTol <= 2. *Precision::Confusion() )
1643 aMaxTol = Precision::Infinite();
1644 Standard_Real aTol1 = Min(BRep_Tool::Tolerance(V1), aMaxTol);
1645 Standard_Real aTol2 = Min(BRep_Tool::Tolerance(V2), aMaxTol);
1646 gp_Pnt aP1 = BRep_Tool::Pnt(V1);
1647 gp_Pnt aP2 = BRep_Tool::Pnt(V2);
1648 Standard_Real aD = aP1.SquareDistance(aP2);
1649 if (SplitLinePar(i) - SplitLinePar(i-1) < ::Precision::PConfusion() || ( canbeMerged && ( aD <= (aTol1 * aTol1) || aD <= (aTol2 * aTol2)))) {// BRepTools::Compare(V1, V2)) ) {
1652 std::cout << "Info: ShapeFix_ComposeShell::SplitByLine: Short segment ignored" << std::endl;
1654 if ( ! V1.IsSame ( V2 ) ) { // merge coincident vertices
1655 ShapeBuild_Vertex sbv;
1656 TopoDS_Vertex V = sbv.CombineVertex ( V1, V2 );
1657 Context()->Replace ( V1, V.Oriented ( V1.Orientation() ) );
1658 Context()->Replace ( V2, V.Oriented ( V2.Orientation() ) );
1661 std::cout << "Info: ShapeFix_ComposeShell::SplitByLine: Coincided vertices merged" << std::endl;
1667 // create an edge (without 3d curve), put it in wire segment and add to sequence
1668 // NOTE: i here is always >1
1670 B.MakeEdge ( edge );
1671 V1.Orientation ( TopAbs_FORWARD );
1672 V2.Orientation ( TopAbs_REVERSED );
1675 Handle(Geom2d_Line) Lin1 = new Geom2d_Line ( line );
1676 Handle(Geom2d_Line) Lin2 = new Geom2d_Line ( line );
1677 B.UpdateEdge ( edge, Lin1, Lin2, myFace, ::Precision::Confusion() );
1678 B.Range ( edge, myFace, SplitLinePar(i-1), SplitLinePar(i) );
1680 Handle(ShapeExtend_WireData) sbwd = new ShapeExtend_WireData;
1682 ShapeFix_WireSegment seg ( sbwd, TopAbs_EXTERNAL );
1684 // set patch indices
1685 DefinePatch ( seg, IOR_UNDEF, isCutByU, cutIndex );
1687 Standard_Real shiftU =
1688 (myClosedMode && myUClosed ? ShapeAnalysis::AdjustToPeriod(SplitLinePar(i-1) -TOLINT, myGrid->UJointValue(1), myGrid->UJointValue(2)) : 0.);
1689 Standard_Real aPar = SplitLinePar(i-1) + shiftU;
1691 seg.DefineIUMin ( 1, GetPatchIndex ( aPar+::Precision::PConfusion(), myGrid->UJointValues(), myUClosed ) );
1692 seg.DefineIUMax ( 1, GetPatchIndex ( aPar-::Precision::PConfusion(), myGrid->UJointValues(), myUClosed ) + 1 );
1695 Standard_Real shiftV = (myClosedMode && myVClosed ? ShapeAnalysis::AdjustToPeriod(SplitLinePar(i-1) -TOLINT, myGrid->VJointValue(1), myGrid->VJointValue(2)) : 0.);
1696 Standard_Real aPar = SplitLinePar(i-1) + shiftV;
1697 seg.DefineIVMin ( 1, GetPatchIndex ( aPar+::Precision::PConfusion(), myGrid->VJointValues(), myVClosed ) );
1698 seg.DefineIVMax ( 1, GetPatchIndex ( aPar-::Precision::PConfusion(), myGrid->VJointValues(), myVClosed ) + 1 );
1700 wires.Append ( seg );
1703 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL4 );
1705 std::cout << "Error: ShapeFix_ComposeShell::SplitByLine: parity error" << std::endl;
1709 // Apply context to all wires to perform all recorded replacements/merging
1710 for ( i=1; i <= wires.Length(); i++ ) {
1711 for ( Standard_Integer j=1; j <= wires(i).NbEdges(); )
1712 j += ApplyContext ( wires(i), j, Context() );
1716 //=======================================================================
1717 //function : SplitByGrid
1719 //=======================================================================
1721 void ShapeFix_ComposeShell::SplitByGrid (ShapeFix_SequenceOfWireSegment &seqw)
1723 // process splitting by U- anv V-seams (i.e. U=const and V=const curves)
1724 // closed composite surface is processed as periodic
1725 Standard_Real Uf,Ul,Vf,Vl;
1726 BRepTools::UVBounds(myFace,Uf,Ul,Vf,Vl);
1727 Standard_Real Umin,Umax,Vmin,Vmax;
1728 myGrid->Bounds(Umin,Umax,Vmin,Vmax);
1730 //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)
1731 Standard_Real pprec = TOLINT;//::Precision::PConfusion();
1732 Standard_Integer i = 1;
1735 //for closed mode when only one patch exist and location of the splitting line is coincident with first joint value
1736 //Therefore in this case it is necessary to move all wire segments in the range of the patch between first and last joint
1737 //values. Then all wire segments are lie between -period and period in order to have valid split ranges after splitting.
1738 //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).
1739 for ( i=1; i <= seqw.Length(); i++ )
1741 ShapeFix_WireSegment &wire = seqw(i);
1743 TopoDS_Shape atmpF = myFace.EmptyCopied();
1745 atmpF.Orientation(TopAbs_FORWARD);
1746 aB.Add(atmpF, wire.WireData()->Wire());
1747 Standard_Real Uf1,Ul1,Vf1,Vl1;
1748 ShapeAnalysis::GetFaceUVBounds(TopoDS::Face(atmpF),Uf1,Ul1,Vf1,Vl1);
1750 //for closed mode it is necessary to move wire segment in the interval defined by first and last grid UV values
1751 Standard_Real shiftU = (myClosedMode && myUClosed ? ShapeAnalysis::AdjustToPeriod(Ul1 -pprec, myGrid->UJointValue(1), myGrid->UJointValue(2)) : 0.);
1752 Standard_Real shiftV = (myClosedMode && myVClosed ? ShapeAnalysis::AdjustToPeriod(Vl1 -pprec, myGrid->VJointValue(1), myGrid->VJointValue(2)) : 0.);
1757 // limit patch indices to be in range of grid (extended for periodic) (0, 2)
1758 //in same cases for example trj4_pm2-ug-203.stp (entity #8024) wire in 2D space has length greater then period
1759 Standard_Integer iumin = Max(0,GetPatchIndex ( Uf1+pprec, myGrid->UJointValues(), myUClosed ));
1760 Standard_Integer iumax = GetPatchIndex ( Ul1-pprec, myGrid->UJointValues(), myUClosed ) + 1;
1762 for ( Standard_Integer j=1; j <= wire.NbEdges(); j++ ) {
1763 wire.DefineIUMin ( j, iumin );
1764 wire.DefineIUMax ( j, iumax );
1767 Standard_Integer ivmin = Max(0,GetPatchIndex ( Vf1+pprec, myGrid->VJointValues(), myVClosed ));
1768 Standard_Integer ivmax = GetPatchIndex ( Vl1-pprec, myGrid->VJointValues(), myVClosed ) + 1;
1770 for ( Standard_Integer j=1; j <= wire.NbEdges(); j++ ) {
1771 wire.DefineIVMin ( j, ivmin );
1772 wire.DefineIVMax ( j, ivmax );
1778 // limit patch indices to be in range of grid (extended for periodic)
1779 Standard_Integer iumin = GetPatchIndex ( Uf+pprec, myGrid->UJointValues(), myUClosed );
1780 Standard_Integer iumax = GetPatchIndex ( Ul-pprec, myGrid->UJointValues(), myUClosed ) + 1;
1781 for ( i=1; i <= seqw.Length(); i++ ) {
1782 ShapeFix_WireSegment &wire = seqw(i);
1783 for ( Standard_Integer j=1; j <= wire.NbEdges(); j++ ) {
1784 wire.DefineIUMin ( j, iumin );
1785 wire.DefineIUMax ( j, iumax );
1788 Standard_Integer ivmin = GetPatchIndex ( Vf+pprec, myGrid->VJointValues(), myVClosed );
1789 Standard_Integer ivmax = GetPatchIndex ( Vl-pprec, myGrid->VJointValues(), myVClosed ) + 1;
1790 for ( i=1; i <= seqw.Length(); i++ ) {
1791 ShapeFix_WireSegment &wire = seqw(i);
1792 for ( Standard_Integer j=1; j <= wire.NbEdges(); j++ ) {
1793 wire.DefineIVMin ( j, ivmin );
1794 wire.DefineIVMax ( j, ivmax );
1800 for ( i = ( myUClosed ? 1 : 2 ); i <= myGrid->NbUPatches(); i++ ) {
1801 gp_Pnt2d pos ( myGrid->UJointValue(i), 0. ); // 0. - for infinite ranges: myGrid->VJointValue(1) ;
1802 gp_Lin2d line ( pos, gp_Dir2d ( 0., 1. ) );
1803 if ( ! myClosedMode && myUClosed ) {
1804 Standard_Real period = Umax - Umin;
1805 Standard_Real X = pos.X();
1806 Standard_Real sh = ShapeAnalysis::AdjustToPeriod(X,Uf, Uf+period);
1807 for( ; X+sh <= Ul+pprec; sh += period ) {
1808 gp_Lin2d ln = line.Translated(gp_Vec2d(sh,0));
1809 Standard_Integer cutIndex = GetPatchIndex ( X+sh+pprec, myGrid->UJointValues(), myUClosed );
1810 SplitByLine ( seqw, ln, Standard_True, cutIndex );
1814 SplitByLine ( seqw, line, Standard_True, i );
1818 for ( i = ( myVClosed ? 1 : 2 ); i <= myGrid->NbVPatches(); i++ ) {
1819 gp_Pnt2d pos ( 0., myGrid->VJointValue(i) );
1820 gp_Lin2d line ( pos, gp_Dir2d ( 1., 0. ) );
1821 if ( ! myClosedMode && myVClosed ) {
1822 Standard_Real period = Vmax - Vmin;
1823 Standard_Real Y = pos.Y();
1824 Standard_Real sh = ShapeAnalysis::AdjustToPeriod(Y,Vf, Vf+period);
1825 for( ; Y+sh <= Vl+pprec; sh += period) {
1826 gp_Lin2d ln = line.Translated(gp_Vec2d(0,sh));
1827 Standard_Integer cutIndex = GetPatchIndex ( Y+sh+pprec, myGrid->VJointValues(), myVClosed );
1828 SplitByLine ( seqw, ln, Standard_False, cutIndex );
1832 SplitByLine ( seqw, line, Standard_False, i );
1836 //=======================================================================
1837 //function : BreakWires
1839 //=======================================================================
1841 void ShapeFix_ComposeShell::BreakWires (ShapeFix_SequenceOfWireSegment &seqw)
1843 // split all the wires by vertices
1844 TopTools_MapOfShape splitVertices;
1845 ShapeAnalysis_Edge sae;
1847 // first collect splitting vertices
1848 Standard_Integer i; // svv #1
1849 for ( i=1; i <= seqw.Length(); i++ ) {
1850 TopAbs_Orientation ori_wire = seqw(i).Orientation();
1851 if ( ori_wire != TopAbs_EXTERNAL &&
1852 ori_wire != TopAbs_INTERNAL) continue;
1854 Handle(ShapeExtend_WireData) sbwd = seqw(i).WireData();
1855 for ( Standard_Integer j=1; j <= sbwd->NbEdges(); j++ ) {
1856 TopoDS_Edge edge = sbwd->Edge ( j );
1857 TopAbs_Orientation ori_edge = (ori_wire == TopAbs_EXTERNAL ? ori_wire : edge.Orientation());
1858 if(ori_edge == TopAbs_EXTERNAL) {
1859 splitVertices.Add ( sae.FirstVertex ( edge ) );
1860 splitVertices.Add ( sae.LastVertex ( edge ) );
1865 // and then split each vire
1866 // Here each wire is supposed to be connected (while probably not closed)
1867 for ( i=1; i <= seqw.Length(); i++ ) {
1868 TopAbs_Orientation ori = seqw(i).Orientation();
1869 ShapeFix_WireSegment wire = seqw(i);
1872 Handle(ShapeExtend_WireData) sbwd = wire.WireData();
1874 // find first vertex for split
1875 Standard_Integer j; // svv #1
1876 for ( j=1; j <= sbwd->NbEdges(); j++ ) {
1877 TopoDS_Vertex V = sae.FirstVertex ( sbwd->Edge(j) );
1878 if ( splitVertices.Contains ( V ) ) break;
1880 if ( j > sbwd->NbEdges() ) continue; // splitting not needed
1882 // if first split of closed edge is not its start, make permutation
1883 Standard_Integer shift = 0;
1884 if ( j >1 && ! myClosedMode && wire.IsClosed() ) {
1885 TopoDS_Vertex V = sae.FirstVertex ( sbwd->Edge(1) );
1886 if ( ! splitVertices.Contains ( V ) )
1888 // wire.SetLast ( j-1 );
1891 // perform splitting
1892 Standard_Integer nbnew = 0;
1893 ShapeFix_WireSegment newwire;
1894 TopAbs_Orientation curOri = ori;
1895 for ( Standard_Integer ind=1; ind <= sbwd->NbEdges(); ind++ ) {
1896 j = 1 + ( ind - 1 + shift ) % sbwd->NbEdges();
1897 TopoDS_Edge edge = sbwd->Edge(j);
1898 TopoDS_Vertex V = sae.FirstVertex ( edge );
1899 if ( ind==1 || splitVertices.Contains ( V ) ) {
1900 if ( newwire.NbEdges() ) {
1901 newwire.Orientation ( curOri );
1902 // ShapeFix_WireSegment seg ( newwire, ori );
1903 seqw.InsertBefore ( i++, newwire );
1909 Standard_Integer iumin, iumax, ivmin, ivmax;
1910 wire.GetPatchIndex ( j, iumin, iumax, ivmin, ivmax );
1911 if(ori == TopAbs_INTERNAL && edge.Orientation() == TopAbs_EXTERNAL ) {
1912 curOri = TopAbs_EXTERNAL;
1913 edge.Orientation(TopAbs_FORWARD);
1916 newwire.AddEdge ( 0, edge, iumin, iumax, ivmin, ivmax );
1919 newwire.Orientation ( curOri );
1920 // ShapeFix_WireSegment seg ( newwire, ori );
1921 seqw.SetValue ( i, newwire );
1926 //=======================================================================
1927 //function : IsShortSegment
1928 //purpose : auxiliary
1929 //=======================================================================
1930 // BUC60035 2053: check if wire segment is very short (in order not to skip it)
1932 // 1 - short even in 2d (to be taken always)
1933 // -1 - short in 3d but not in 2d (to be checked after algo and atteching to
1934 // another wire if alone)
1935 static Standard_Integer IsShortSegment (const ShapeFix_WireSegment &seg,
1936 const TopoDS_Face myFace,
1937 const Handle(Geom_Surface)& myGrid,
1938 const TopLoc_Location &myLoc,
1939 const Standard_Real UResolution,
1940 const Standard_Real VResolution)
1942 TopoDS_Vertex Vf = seg.FirstVertex();
1943 if ( ! Vf.IsSame ( seg.LastVertex() ) ) return 0;
1945 gp_Pnt pnt = BRep_Tool::Pnt(Vf);
1946 Standard_Real tol = BRep_Tool::Tolerance(Vf);
1947 Standard_Real tol2 = tol*tol;
1949 Standard_Integer code = 1;
1950 ShapeAnalysis_Edge sae;
1951 Handle(ShapeExtend_WireData) sbwd = seg.WireData();
1952 for ( Standard_Integer i=1; i <= sbwd->NbEdges(); i++ ) {
1953 TopoDS_Edge edge = sbwd->Edge ( i );
1954 if ( ! Vf.IsSame ( sae.LastVertex ( edge ) ) ) return 0;
1955 Handle(Geom2d_Curve) c2d;
1957 if ( ! sae.PCurve ( edge, myFace, c2d, f, l ) ) continue;
1960 gp_Pnt2d endPnt = c2d->Value(l);
1961 gp_Pnt2d midPnt = c2d->Value((f+l)/2);
1962 if ( ! IsCoincided ( endPnt, midPnt, UResolution, VResolution, tol ) ) code = -1;
1965 gp_Pnt midPnt3d = myGrid->Value(midPnt.X(),midPnt.Y());
1966 if ( ! myLoc.IsIdentity() ) midPnt3d.Transform ( myLoc.Transformation() );
1967 if ( midPnt3d.SquareDistance(pnt) > tol2) return 0;
1972 //=======================================================================
1973 //function : IsSamePatch
1974 //purpose : auxiliary
1975 //=======================================================================
1976 static Standard_Boolean IsSamePatch (const ShapeFix_WireSegment& wire,
1977 const Standard_Integer NU,
1978 const Standard_Integer NV,
1979 Standard_Integer& iumin,
1980 Standard_Integer& iumax,
1981 Standard_Integer& ivmin,
1982 Standard_Integer& ivmax,
1983 const Standard_Boolean extend=Standard_False)
1985 // get patch indices for current segment
1986 Standard_Integer jumin, jumax, jvmin, jvmax;
1987 wire.GetPatchIndex ( 1, jumin, jumax, jvmin, jvmax );
1989 // shift to the same period
1990 Standard_Integer du=0, dv=0;
1991 if ( jumin - iumin > NU ) du =-( jumin - iumin ) / NU;
1992 else if ( iumin - jumin > NU ) du = ( iumin - jumin ) / NU;
1993 if ( jvmin - ivmin > NV ) dv =-( jvmin - ivmin ) / NV;
1994 else if ( ivmin - jvmin > NV ) dv = ( ivmin - jvmin ) / NV;
1995 if ( du ) { jumin += du * NU; jumax += du * NU; }
1996 if ( dv ) { jvmin += dv * NV; jvmax += dv * NV; }
1998 // compute common (extended) indices
1999 Standard_Integer iun = Min ( iumin, jumin );
2000 Standard_Integer iux = Max ( iumax, jumax );
2001 Standard_Integer ivn = Min ( ivmin, jvmin );
2002 Standard_Integer ivx = Max ( ivmax, jvmax );
2003 Standard_Boolean ok = ( iun == iux || iun+1 == iux ) &&
2004 ( ivn == ivx || ivn+1 == ivx );
2005 if ( ok && extend ) { iumin = iun; iumax = iux; ivmin = ivn; ivmax = ivx; }
2009 //=======================================================================
2010 //function : CollectWires
2012 //=======================================================================
2014 void ShapeFix_ComposeShell::CollectWires (ShapeFix_SequenceOfWireSegment &wires,
2015 ShapeFix_SequenceOfWireSegment &seqw)
2017 ShapeAnalysis_Edge sae;
2018 Standard_Integer i; // svv #1
2019 // Collect information on short closed segments
2020 TColStd_Array1OfInteger shorts(1,seqw.Length());
2021 for ( i=1; i <= seqw.Length(); i++ ) {
2022 if(seqw(i).IsVertex() || seqw(i).Orientation() == TopAbs_INTERNAL) {
2023 wires.Append(seqw(i));
2029 for ( Standard_Integer k=1; ! myClosedMode && k <= seqw(i).NbEdges(); k++ )
2030 if ( ! seqw(i).CheckPatchIndex ( k ) ) {
2031 std::cout << "Warning: ShapeFix_ComposeShell::CollectWires: Wrong patch indices" << std::endl;
2035 Standard_Integer isshort = IsShortSegment ( seqw(i), myFace, myGrid, myLoc,
2036 myUResolution, myVResolution );
2037 shorts.SetValue ( i, isshort );
2039 ( seqw(i).Orientation() == TopAbs_EXTERNAL ||
2040 ( seqw(i).NbEdges() == 1 && //:abv 13.05.02: OCC320 - remove if degenerated
2041 BRep_Tool::Degenerated ( seqw(i).Edge(1) ) ) ) ) {
2043 std::cout << "Info: ShapeFix_ComposeShell::CollectWires: Short segment ignored" << std::endl;
2045 seqw(i).Orientation ( TopAbs_INTERNAL );
2049 Handle(ShapeExtend_WireData) sbwd;
2050 gp_Pnt2d endPnt, firstPnt;
2051 gp_Vec2d endTan, firstTan;
2052 TopoDS_Vertex firstV, endV;
2053 TopoDS_Edge firstEdge, lastEdge;
2054 Standard_Real tol = 0;
2055 Standard_Integer iumin = 0, iumax = 0, ivmin = 0, ivmax = 0;
2056 Standard_Real dsu=0., dsv=0.;
2057 Standard_Boolean canBeClosed = Standard_False;
2059 Standard_Integer index = 0;
2060 Standard_Boolean misoriented = Standard_True, samepatch = Standard_False;
2061 Standard_Boolean reverse = Standard_False, connected = Standard_False;
2062 Standard_Real angle = -M_PI, mindist = RealLast();
2063 Standard_Integer weigth = 0;
2064 Standard_Real shiftu=0., shiftv=0.;
2066 // find next segment to connect (or first if sbwd is NULL)
2067 for ( i = 1; i <= seqw.Length(); i++ ) {
2068 ShapeFix_WireSegment seg = seqw.Value(i);
2071 TopAbs_Orientation anOr = seg.Orientation();
2072 if ( anOr == TopAbs_INTERNAL ) continue;
2074 // for first segment, take any
2075 if ( sbwd.IsNull() ) {
2076 if ( shorts(i) >0 ) continue;
2077 if ( anOr == TopAbs_EXTERNAL ) continue;
2078 if ( anOr == TopAbs_FORWARD ) reverse = Standard_True;
2080 seg.GetPatchIndex ( 1, iumin, iumax, ivmin, ivmax );
2082 misoriented = Standard_False;
2087 // check whether current segment is on the same patch with previous
2088 Standard_Boolean sp = IsSamePatch ( seg, myGrid->NbUPatches(), myGrid->NbVPatches(),
2089 iumin, iumax, ivmin, ivmax );
2091 // not same patch has lowest priority
2092 if ( ! sp && ( canBeClosed || ( index && samepatch ) ) ) continue;
2094 // try to connect, with the following priorities:
2095 // The name of property Weigth:
2096 // sharing vertex auto
2099 // misorientation = 0 8
2100 // connected in 2d 4
2104 Handle(ShapeExtend_WireData) wire = seg.WireData();
2105 for ( Standard_Integer j=0; j <2; j++ ) {
2106 if ( ! endV.IsSame ( j ? seg.LastVertex() : seg.FirstVertex() ) ) continue;
2108 // check for misorientation only if nothing better is found
2109 Standard_Boolean misor = ( anOr == ( j ? TopAbs_REVERSED : TopAbs_FORWARD ) );
2110 // if ( misor ) continue; // temporarily, to be improved
2112 // returning back by the same edge is lowest priority
2113 if ( lastEdge.IsSame ( wire->Edge ( j ? wire->NbEdges() : 1 ) ) ) {
2114 if ( ! index && ! canBeClosed ) { // || ( sp && ! samepatch ) ) {
2117 connected = Standard_True;
2118 misoriented = misor;
2120 weigth = ( sp ? 16 : 0 ) + ( connected ? 8 : 0 ) + (misor==0 ? 4 : 0);
2126 // compute starting tangent
2130 Standard_Real edgeTol = 0;
2131 for ( k=1; k <= wire->NbEdges(); k++ ) {
2132 TopoDS_Shape tmpE = wire->Edge(wire->NbEdges()-k+1).Reversed();
2133 TopoDS_Edge edge = ( j ? TopoDS::Edge ( tmpE ) :
2135 edgeTol = BRep_Tool::Tolerance ( edge );
2136 //if ( sae.GetEndTangent2d ( edge, myFace, Standard_False, lPnt, lVec ) ) break;
2137 if ( sae.GetEndTangent2d ( edge, myFace, Standard_False, lPnt, lVec, 1.e-3 ) ) break;
2139 if ( k > wire->NbEdges() ) myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
2141 if ( myClosedMode ) {
2143 shiftu = ShapeAnalysis::AdjustByPeriod ( lPnt.X(), endPnt.X(), myUPeriod );
2144 lPnt.SetX ( lPnt.X() + shiftu );
2147 shiftv = ShapeAnalysis::AdjustByPeriod ( lPnt.Y(), endPnt.Y(), myVPeriod );
2148 lPnt.SetY ( lPnt.Y() + shiftv );
2152 // short segment is to be taken with highest priority by angle
2153 Standard_Real ang = ( shorts(i) >0 ? M_PI : endTan.Angle ( lVec ) );
2154 if ( myClosedMode && shorts(i) <=0 && M_PI-ang < ::Precision::Angular() )
2155 ang = 0.; // abv 21 Mar 00: trj3_s1-md-214.stp #2471: avoid going back
2157 // abv 05 Feb 02: face from Parasolid: use tolerance of edges for check
2158 // for coincidence (instead of vertex tolerance) in order
2159 // this check to be in agreement with check for position of wire segments
2160 // thus avoiding bad effects on overlapping edges
2161 Standard_Real ctol = Max (edgeTol, BRep_Tool::Tolerance(endV/*lastEdge*/));
2162 Standard_Boolean conn = IsCoincided ( endPnt, lPnt, myUResolution, myVResolution, ctol );
2163 Standard_Real dist = endPnt.SquareDistance ( lPnt );
2165 // check if case is better than last found
2166 Standard_Integer w1 = ( sp ? 16 : 0 ) + ( conn ? 4 : 0 ) + (misor==0 ? 8 : 0);
2167 Standard_Integer tail1 = ( !conn && (dist < mindist) ? 2 : 0) + (ang > angle ? 1 : 0);
2168 Standard_Integer tail2 = ( !connected &&(dist > mindist) ? 2 : 0) + (ang < angle ? 1 : 0);
2169 if(w1+tail1 <= weigth+tail2)
2177 misoriented = misor;
2185 // if next segment found, connect it
2188 myInvertEdgeStatus = Standard_True;
2189 ShapeFix_WireSegment seg = seqw.Value(index);
2190 if ( sbwd.IsNull() ) sbwd = new ShapeExtend_WireData;
2191 else if ( samepatch ) { // extend patch indices
2192 IsSamePatch ( seg, myGrid->NbUPatches(), myGrid->NbVPatches(),
2193 iumin, iumax, ivmin, ivmax, Standard_True );
2196 //for closed mode in case if current segment is seam segment it is necessary to detect crossing seam edge
2197 //in order to have possibility to take candidate from other patch
2199 seg.GetPatchIndex ( 1, iumin, iumax, ivmin, ivmax );
2201 // TopAbs_Orientation or = seg.Orientation();
2202 if ( ! reverse ) sbwd->Add ( seg.WireData() );
2204 Handle(ShapeExtend_WireData) wire = new ShapeExtend_WireData;
2205 wire->ManifoldMode() = Standard_False;
2206 wire->Add ( seg.WireData() );
2207 wire->Reverse ( myFace );
2210 if ( seg.Orientation() == TopAbs_EXTERNAL )
2211 seg.Orientation ( reverse ? TopAbs_REVERSED : TopAbs_FORWARD );
2213 seg.Orientation ( TopAbs_INTERNAL );
2214 seqw.SetValue ( index, seg );
2216 else if ( sbwd.IsNull() ) break; // stop when no free segments available
2217 // for first segment, remember start point
2218 if ( endV.IsNull() ) {
2219 firstEdge = sbwd->Edge(1);
2220 firstV = sae.FirstVertex ( firstEdge );
2221 //sae.GetEndTangent2d ( firstEdge, myFace, Standard_False, firstPnt, firstTan );
2222 sae.GetEndTangent2d ( firstEdge, myFace, Standard_False, firstPnt, firstTan, 1.e-3 );
2225 // update last edge and vertex (only for not short segments)
2226 Standard_Boolean doupdate = ( index && ( shorts(index) <=0 || endV.IsNull() ) );
2228 lastEdge = sbwd->Edge ( sbwd->NbEdges() );
2229 endV = sae.LastVertex ( lastEdge );
2230 tol = BRep_Tool::Tolerance ( endV );
2231 // BUC60035 2053: iteration on edges is required
2232 Standard_Integer k; // svv #1
2233 for ( k=sbwd->NbEdges(); k >=1; k-- )
2234 //if ( sae.GetEndTangent2d ( sbwd->Edge ( k ), myFace, Standard_True, endPnt, endTan ) )
2235 if ( sae.GetEndTangent2d ( sbwd->Edge ( k ), myFace, Standard_True, endPnt, endTan, 1.e-3 ) )
2237 if ( k <1 ) myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL2 );
2238 if ( myUClosed ) endPnt.SetX ( endPnt.X() + dsu );
2239 if ( myVClosed ) endPnt.SetY ( endPnt.Y() + dsv );
2242 // if closed or no next segment found, add to wires
2243 canBeClosed = endV.IsSame ( firstV );
2244 if ( ! index || ( canBeClosed &&
2245 ! lastEdge.IsSame ( firstEdge ) && // cylinder (seam)
2246 IsCoincided ( endPnt, firstPnt, myUResolution, myVResolution, 2.* tol ) ) ) {
2247 if ( ! endV.IsSame ( sae.FirstVertex ( firstEdge ) ) ) {
2248 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL5 );
2250 std::cout << "Warning: ShapeFix_ComposeShell::CollectWires: can't close wire" << std::endl;
2253 ShapeFix_WireSegment s ( sbwd, TopAbs_FORWARD );
2254 s.DefineIUMin(1,iumin);
2255 s.DefineIUMax(1,iumax);
2256 s.DefineIVMin(1,ivmin);
2257 s.DefineIVMax(1,ivmax);
2261 canBeClosed = Standard_False;
2265 // Check if some wires are short in 3d (lie entirely inside one vertex),
2266 // and if yes try to merge them with others
2267 //pdn The short seqments are still placed in "in" sequence.
2269 for ( i=1; i <= seqw.Length(); i++ ) {
2270 if ( shorts(i) != 1 ||
2271 seqw(i).IsVertex() ||
2272 seqw(i).Orientation() == TopAbs_INTERNAL ||
2273 seqw(i).Orientation() == TopAbs_EXTERNAL )
2276 // find any other wire containing the same vertex
2277 Handle(ShapeExtend_WireData) wd = seqw(i).WireData();
2278 TopoDS_Vertex V = seqw(i).FirstVertex();
2279 Standard_Integer minj=0, mink=0;
2282 Standard_Real mindist=0;
2283 Standard_Boolean samepatch = Standard_False;
2284 // Standard_Integer iumin, iumax, ivmin, ivmax;
2285 seqw(i).GetPatchIndex ( 1, iumin, iumax, ivmin, ivmax );
2286 sae.GetEndTangent2d ( wd->Edge(1), myFace, Standard_False, p2d, vec );
2287 for ( Standard_Integer j=1; j <= wires.Length(); j++ ) {
2288 // if ( j == i ) continue;
2289 // Handle(ShapeExtend_WireData)
2290 sbwd = wires(j).WireData();
2291 for ( Standard_Integer k=1; k <= sbwd->NbEdges(); k++ ) {
2292 if ( !V.IsSame ( sae.FirstVertex ( sbwd->Edge(k) ) ) ) continue; //pdn I suppose that short segment should be inserted into the SAME vertex.
2294 Standard_Boolean sp = IsSamePatch ( wires(j), myGrid->NbUPatches(), myGrid->NbVPatches(),
2295 iumin, iumax, ivmin, ivmax );
2296 if ( samepatch && !sp) continue;
2298 sae.GetEndTangent2d ( sbwd->Edge(k), myFace, Standard_False, pp, vec );
2299 Standard_Real dist = pp.SquareDistance ( p2d );
2300 if ( sp && ! samepatch ) { minj = j; mink = k; mindist = dist;samepatch=sp;}
2302 if ( ! minj || mindist > dist ) { minj = j; mink = k; mindist = dist;samepatch=sp; }
2306 //pdn add into resulting sequence!
2307 ShapeFix_WireSegment s ( wd, TopAbs_FORWARD );
2310 std::cout <<"Warning: Short segment processed as separate wire"<<std::endl;
2315 // and if found, merge
2316 // Handle(ShapeExtend_WireData)
2317 sbwd = wires(minj).WireData();
2318 for ( Standard_Integer n=1; n <= wd->NbEdges(); n++ )
2319 sbwd->Add ( wd->Edge(n), mink++ );
2321 // wires.Remove ( i );
2326 //=======================================================================
2327 //function : DispatchWires
2329 //=======================================================================
2331 static gp_Pnt2d GetMiddlePoint (const ShapeFix_WireSegment& wire,
2332 const TopoDS_Face& face)
2334 if(wire.IsVertex()) {
2335 TopoDS_Vertex aV = wire.GetVertex();
2336 gp_Pnt aP3D = BRep_Tool::Pnt(aV );
2337 Handle(Geom_Surface) surf = BRep_Tool::Surface(face);
2338 Handle(ShapeAnalysis_Surface) aSurfTool = new ShapeAnalysis_Surface(surf);
2339 return aSurfTool->ValueOfUV(aP3D,Precision::Confusion());
2342 ShapeAnalysis_Edge sae;
2343 ShapeAnalysis_Curve sac;
2344 Handle(ShapeExtend_WireData) wd = wire.WireData();
2345 for(Standard_Integer i = 1; i <= wd->NbEdges(); i++) {
2346 TopoDS_Edge E = wd->Edge (i);
2347 Standard_Real cf,cl;
2348 Handle(Geom2d_Curve) c2d;
2349 if(sae.PCurve (E,face,c2d,cf,cl,Standard_False)) {
2350 sac.FillBndBox ( c2d, cf, cl, 3, Standard_False, box );
2351 // box.Add(c2d->Value(cf));
2352 // box.Add(c2d->Value(cl));
2353 // box.Add(c2d->Value((cl+cf)/2.));
2356 if ( box.IsVoid() ) return gp_Pnt2d(0.,0.);
2357 Standard_Real aXmin, aYmin, aXmax, aYmax;
2358 box.Get(aXmin, aYmin, aXmax, aYmax);
2359 return gp_Pnt2d ( 0.5 * ( aXmax + aXmin ), 0.5 * ( aYmax + aYmin ) );
2362 //=======================================================================
2363 //function : MakeFacesOnPatch
2365 //=======================================================================
2367 void ShapeFix_ComposeShell::MakeFacesOnPatch (TopTools_SequenceOfShape &faces,
2368 const Handle(Geom_Surface)& surf,
2369 TopTools_SequenceOfShape &loops) const
2373 // Case of single loop: just add it to face
2374 if ( loops.Length() == 1 ) {
2375 TopoDS_Face newFace;
2376 B.MakeFace ( newFace, surf, myLoc, ::Precision::Confusion() );
2377 TopoDS_Shape aSH = loops.Value(1);
2378 if( aSH.ShapeType() != TopAbs_WIRE)
2380 TopoDS_Wire wire = TopoDS::Wire ( loops.Value(1) );
2382 B.Add ( newFace, wire );
2383 if(myInvertEdgeStatus) {
2384 Handle(ShapeFix_Face) sff = new ShapeFix_Face(newFace);
2385 sff->FixAddNaturalBoundMode() = Standard_False;
2386 TopTools_DataMapOfShapeListOfShape MapWires;
2388 sff->FixOrientation(MapWires);
2389 newFace = sff->Face();
2392 faces.Append ( newFace );
2396 // For several loops, first find roots
2397 // make pseudo-face,
2399 B.MakeFace ( pf, surf, myLoc, ::Precision::Confusion() );
2400 Handle(Geom_Surface) atSurf = BRep_Tool::Surface(pf);
2402 Handle(ShapeAnalysis_Surface) aSurfTool = new ShapeAnalysis_Surface(atSurf);
2403 TopTools_SequenceOfShape roots;
2404 Standard_Integer i; // svv #1
2405 for ( i = 1; i <= loops.Length(); i++ ) {
2408 TopoDS_Shape aShape = loops(i);
2409 if(aShape.ShapeType() != TopAbs_WIRE ||
2410 (aShape.Orientation() != TopAbs_FORWARD && aShape.Orientation() != TopAbs_REVERSED))
2413 wr = TopoDS::Wire ( loops(i) );
2414 TopoDS_Iterator ew (wr);
2415 if ( ! ew.More() ) continue;
2417 TopoDS_Edge ed = TopoDS::Edge ( ew.Value() );
2418 while(ed.Orientation() != TopAbs_FORWARD &&
2419 ed.Orientation() != TopAbs_REVERSED ) {
2422 ed = TopoDS::Edge ( ew.Value() );
2426 if ( ! ew.More() ) continue;
2427 Standard_Real cf, cl;
2428 Handle(Geom2d_Curve) cw = BRep_Tool::CurveOnSurface ( ed, pf, cf, cl );
2429 if ( cw.IsNull() ) continue;
2430 unp = cw->Value ( 0.5 * ( cf + cl ) );
2432 Standard_Integer j; // svv #1
2433 for ( j = 1; j <= loops.Length(); j++ ) {
2434 if ( i == j ) continue;
2435 TopoDS_Shape aShape2 = loops(j);
2436 if(aShape2.ShapeType() != TopAbs_WIRE ||
2437 (aShape2.Orientation() != TopAbs_FORWARD &&
2438 aShape2.Orientation() != TopAbs_REVERSED))
2440 TopoDS_Wire w1 = TopoDS::Wire (aShape2);
2443 awtmp.Orientation(TopAbs_FORWARD);
2444 TopoDS_Iterator aIt(w1);
2445 Standard_Integer nbe =0;
2446 for( ; aIt.More() ; aIt.Next()) {
2447 if(aIt.Value().Orientation() == TopAbs_FORWARD ||
2448 aIt.Value().Orientation() == TopAbs_REVERSED) {
2449 B.Add(awtmp,aIt.Value());
2456 B.MakeFace ( fc, surf, myLoc, ::Precision::Confusion() );
2457 B.Add ( fc, awtmp );
2458 BRepTopAdaptor_FClass2d clas ( fc, ::Precision::PConfusion() );
2459 TopAbs_State stPoint = clas.Perform (unp,Standard_False);
2460 if(stPoint == TopAbs_ON || stPoint == TopAbs_UNKNOWN) {
2462 TopoDS_Edge anEdge = TopoDS::Edge ( ew.Value() );
2463 Standard_Real aCF, aCL;
2464 Handle(Geom2d_Curve) aCW = BRep_Tool::CurveOnSurface ( anEdge, pf, aCF, aCL);
2465 // handle tangential case (ON)
2466 while ( stPoint == TopAbs_ON || stPoint == TopAbs_UNKNOWN ) {
2467 stPoint = clas.Perform (aCW->Value(aCL), Standard_False );
2468 if ( ! ew.More() ) break;
2470 if ( ! ew.More() ) break;
2471 TopoDS_Edge edge = TopoDS::Edge ( ew.Value() );
2472 if(edge.Orientation() !=TopAbs_FORWARD &&
2473 edge.Orientation() !=TopAbs_REVERSED)
2475 Handle(Geom2d_Curve) c2d = BRep_Tool::CurveOnSurface ( edge, pf, aCF, aCL );
2476 if ( ! c2d.IsNull() ) aCW = c2d;
2479 TopAbs_State stInfin = clas.PerformInfinitePoint();
2480 if ( stPoint != stInfin ) break;
2482 if ( j > loops.Length()) {
2483 roots.Append ( wr );
2484 // loops.Remove ( i-- );
2488 // And remove them from the list of loops
2489 for ( i = 1; i <= loops.Length(); i++ )
2490 for ( Standard_Integer j = 1; j <= roots.Length(); j++ )
2491 if ( loops(i).IsSame ( roots(j) ) ) { loops.Remove(i--); break; }
2493 // check for lost wires, and if they are, make them roots
2494 if ( roots.Length() <=0 && loops.Length() >0 ) {
2496 std::cout << "Error: ShapeFix_ComposeShell::MakeFacesOnPatch: can't dispatch wires" << std::endl;
2498 for ( Standard_Integer j=1; j <= loops.Length(); j++ ) {
2499 roots.Append ( loops(j) );
2504 // Then iterate on loops
2505 for ( i=1; i <= roots.Length(); i++ ) {
2506 Standard_Boolean reverse = Standard_False;
2507 TopoDS_Wire wire = TopoDS::Wire ( roots(i) );
2509 B.MakeFace ( fc, surf, myLoc, ::Precision::Confusion() );
2511 BRepTopAdaptor_FClass2d clas ( fc, ::Precision::PConfusion() );
2512 if ( clas.PerformInfinitePoint() == TopAbs_IN ) {
2513 reverse = Standard_True;
2515 std::cout << "Warning: ShapeFix_ComposeShell::MakeFacesOnPatch: badly oriented wire" << std::endl;
2519 // find all holes for that loop
2520 TopTools_SequenceOfShape holes; // holes in holes not supported
2521 Standard_Integer j; // svv #1
2522 for ( j=1; j <= loops.Length(); j++ ) {
2524 if(loops(j).ShapeType() == TopAbs_WIRE) {
2525 TopoDS_Wire bw = TopoDS::Wire ( loops(j) );
2526 TopoDS_Iterator ew ( bw );
2527 if ( ! ew.More() ) continue;
2528 TopoDS_Edge ed = TopoDS::Edge ( ew.Value() );
2529 Standard_Real cf, cl;
2530 Handle(Geom2d_Curve) cw = BRep_Tool::CurveOnSurface ( ed, pf, cf, cl );
2531 if ( cw.IsNull() ) continue;
2532 unp = cw->Value ( 0.5 * ( cf + cl ) );
2534 else if(loops(j).ShapeType() == TopAbs_VERTEX) {
2535 TopoDS_Vertex aV = TopoDS::Vertex(loops(j));
2536 gp_Pnt aP = BRep_Tool::Pnt(aV);
2537 unp = aSurfTool->ValueOfUV(aP,Precision::Confusion());
2541 TopAbs_State state = clas.Perform (unp,Standard_False);
2542 if ((state == TopAbs_OUT) == reverse) {
2543 holes.Append ( loops(j) );
2544 loops.Remove ( j-- );
2548 // and add them to new face (no orienting is done)
2549 TopoDS_Face newFace;
2550 B.MakeFace ( newFace, surf, myLoc, ::Precision::Confusion() );
2551 B.Add ( newFace, wire );
2552 for ( j=1; j <= holes.Length(); j++ ) {
2553 TopoDS_Shape aSh = holes(j);
2554 if(aSh.ShapeType() == TopAbs_VERTEX) {
2555 TopoDS_Vertex aNewV = ShapeAnalysis_TransferParametersProj::CopyNMVertex(TopoDS::Vertex(aSh), newFace,myFace);
2556 Context()->Replace(aSh,aNewV);
2557 B.Add ( newFace,aNewV);
2560 B.Add ( newFace, holes(j) );
2562 faces.Append ( newFace );
2564 // check for lost wires, and if they are, make them roots
2565 if ( i == roots.Length() && loops.Length() >0 ) {
2567 std::cout << "Error: ShapeFix_ComposeShell::MakeFacesOnPatch: can't dispatch wires" << std::endl;
2569 for ( j=1; j <= loops.Length(); j++ ) {
2570 TopoDS_Shape aSh = loops(j);
2571 if(aSh.ShapeType() == TopAbs_WIRE && (aSh.Orientation() == TopAbs_FORWARD ||
2572 aSh.Orientation() == TopAbs_REVERSED))
2573 roots.Append ( loops(j) );
2580 //=======================================================================
2581 //function : DispatchWires
2583 //=======================================================================
2585 void ShapeFix_ComposeShell::DispatchWires (TopTools_SequenceOfShape &faces,
2586 ShapeFix_SequenceOfWireSegment& wires) const
2590 // in closed mode, apply FixShifted to all wires before dispatching them
2591 if ( myClosedMode ) {
2593 sfw.SetFace ( myFace );
2594 sfw.SetPrecision ( Precision() );
2596 // pdn: shift pcurves in the seam to make OK shape w/o fixshifted
2598 for ( i=1; i <= wires.Length(); i++ ) {
2599 if(wires(i).IsVertex())
2601 Handle(ShapeExtend_WireData) sbwd = wires(i).WireData();
2603 for(Standard_Integer jL=1; jL <= sbwd->NbEdges(); jL++ ) {
2604 TopoDS_Edge E = sbwd->Edge(jL);
2605 if ( E.Orientation() == TopAbs_REVERSED && BRep_Tool::IsClosed(E,myFace) ) {
2606 Standard_Real f1,l1, f2, l2;
2607 Handle(Geom2d_Curve) c21 = BRep_Tool::CurveOnSurface(E,myFace,f1,l1);
2608 TopoDS_Shape dummy = E.Reversed();
2609 Handle(Geom2d_Curve) c22 = BRep_Tool::CurveOnSurface(TopoDS::Edge(dummy),myFace,f2,l2);
2610 Standard_Real dPreci = ::Precision::PConfusion()*Precision::PConfusion();
2611 gp_Pnt2d pf1 = c21->Value(f1);
2612 gp_Pnt2d pl1 = c21->Value(l1);
2613 gp_Pnt2d pf2 = c22->Value(f2);
2614 gp_Pnt2d pl2 = c22->Value(l2);
2615 if ( c21 == c22 || pf1.SquareDistance(pf2) < dPreci ||
2616 pl1.SquareDistance(pl2) < dPreci ) {
2617 gp_Vec2d shift(0.,0.);
2618 if ( myUClosed && Abs ( pf2.X() - pl2.X() ) < ::Precision::PConfusion() )
2619 shift.SetX(myUPeriod);
2620 if ( myVClosed && Abs ( pf2.Y() - pl2.Y() ) < ::Precision::PConfusion() )
2621 shift.SetY(myVPeriod);
2622 c22->Translate(shift);
2628 for ( i=1; i <= wires.Length(); i++ ) {
2629 if(wires(i).IsVertex())
2631 Handle(ShapeExtend_WireData) sbwd = wires(i).WireData();
2633 //: abv 30.08.01: torHalf2.sat: if wire contains single degenerated
2634 // edge, skip that wire
2635 if ( sbwd->NbEdges() <=0 ||
2636 ( sbwd->NbEdges() ==1 && BRep_Tool::Degenerated(sbwd->Edge(1)) ) ) {
2644 // force recomputation of degenerated edges (clear pcurves)
2645 ShapeBuild_Edge sbe;
2646 for (Standard_Integer jL=1; jL <= sbwd->NbEdges(); jL++ ) {
2647 if ( BRep_Tool::Degenerated(sbwd->Edge(jL)) )
2648 sbe.RemovePCurve(sbwd->Edge(jL),myFace);
2649 // sfw.FixDegenerated(jL);
2651 sfw.FixDegenerated();
2655 // Compute center points for wires
2656 TColgp_SequenceOfPnt2d mPnts;
2657 Standard_Integer nb = wires.Length();
2659 // pdn protection on empty sequence
2663 Standard_Integer i; //svv #1
2664 for ( i = 1; i <= nb; i++ )
2665 mPnts.Append ( GetMiddlePoint ( wires(i), myFace ) );
2667 // Put each wire on its own surface patch (by reassigning pcurves)
2668 // and build 3d curve if necessary
2669 ShapeBuild_ReShape rs;
2670 ShapeBuild_Edge sbe;
2671 ShapeAnalysis_Edge sae;
2672 Handle(ShapeFix_Edge) sfe = new ShapeFix_Edge;
2674 Standard_Real U1,U2,V1,V2;
2675 myGrid->Bounds(U1,U2,V1,V2);
2676 for ( i = 1; i <= nb; i++ ) {
2677 gp_Pnt2d pnt = mPnts(i);
2678 Standard_Real ush =0., vsh=0.;
2680 ush = ShapeAnalysis::AdjustToPeriod(pnt.X(),U1,U2);
2681 pnt.SetX(pnt.X()+ush);
2684 vsh = ShapeAnalysis::AdjustToPeriod(pnt.Y(),V1,V2);
2685 pnt.SetY(pnt.Y()+vsh);
2688 Standard_Integer indU = myGrid->LocateUParameter ( pnt.X() );
2689 Standard_Integer indV = myGrid->LocateVParameter ( pnt.Y() );
2691 // compute parametric transformation
2693 Standard_Real uFact=1.;
2694 Standard_Boolean needT = myGrid->GlobalToLocalTransformation ( indU, indV, uFact, T );
2695 if ( ush != 0. || vsh != 0. ) {
2697 Sh.SetTranslation ( gp_Vec2d ( ush, vsh ) );
2699 needT = Standard_True;
2701 if(wires(i).IsVertex())
2703 Handle(Geom_Surface) surf = myGrid->Patch ( indU, indV );
2705 B.MakeFace ( face, surf, myLoc, ::Precision::Confusion() );
2706 Handle(ShapeExtend_WireData) sewd = wires(i).WireData();
2707 for ( Standard_Integer j = 1; j <= sewd->NbEdges(); j++ ) {
2708 // Standard_Integer nsplit = ApplyContext ( sewd, j, context );
2709 // if ( nsplit <1 ) { j--; continue; }
2711 TopoDS_Edge edge = sewd->Edge(j);
2713 // !! Accurately copy pcurves for SEAMS and SEAM-like edges !!
2715 // if edge is already copied, don`t copy any more
2716 TopoDS_Edge newEdge;
2717 TopoDS_Edge anInitEdge = edge;
2718 Standard_Boolean ismanifold = (edge.Orientation() == TopAbs_FORWARD ||
2719 edge.Orientation() == TopAbs_REVERSED);
2720 if ( rs.IsRecorded ( edge ) ) {
2722 TopoDS_Shape tmpNE = rs.Value(edge);
2723 newEdge = TopoDS::Edge ( tmpNE );
2727 anInitEdge.Orientation(TopAbs_FORWARD);
2729 newEdge = sbe.Copy ( anInitEdge, Standard_False );
2731 newEdge.Orientation(edge.Orientation());
2732 rs.Replace ( edge, newEdge );
2733 Context()->Replace ( edge, newEdge );
2736 sbe.ReassignPCurve ( newEdge, myFace, face );
2738 // transform pcurve to parametric space of patch
2741 Handle(Geom2d_Curve) c2d;
2742 if ( sae.PCurve ( newEdge, face, c2d, f, l, Standard_False ) ) {
2743 Standard_Real newf = f, newl = l;
2744 Handle(Geom2d_Curve) c2dnew = sbe.TransformPCurve ( c2d, T, uFact, newf, newl );
2745 if ( BRep_Tool::IsClosed ( newEdge, face ) ) {
2746 Standard_Real cf, cl;
2747 Handle(Geom2d_Curve) c2d2;
2749 TopoDS_Shape tmpE = newEdge.Reversed();
2750 TopoDS_Edge e2 = TopoDS::Edge (tmpE );
2751 if ( sae.PCurve ( e2, face, c2d2, cf, cl, Standard_False ) ) {
2752 if ( newEdge.Orientation() == TopAbs_FORWARD )
2753 B.UpdateEdge ( newEdge, c2dnew, c2d2, face, 0. );
2754 else B.UpdateEdge ( newEdge, c2d2, c2dnew, face, 0. );
2756 else B.UpdateEdge ( newEdge, c2dnew, face, 0. );
2758 else B.UpdateEdge ( newEdge, c2dnew, face, 0. );
2759 B.Range ( newEdge, face, newf, newl );
2760 if ( (newf != f || newl != l) && !BRep_Tool::Degenerated(newEdge) )
2761 B.SameRange ( newEdge, Standard_False );
2765 if(!BRep_Tool::SameRange(newEdge)) {
2768 TopoDS_Edge afe = TopoDS::Edge(newEdge.Oriented(TopAbs_FORWARD));
2769 etmp = sbe.Copy (afe , Standard_False );
2772 etmp = sbe.Copy ( newEdge, Standard_False );
2773 sfe->FixAddCurve3d ( etmp );
2774 Standard_Real cf, cl;
2775 Handle(Geom_Curve) c3d;
2776 if(sae.Curve3d(etmp,c3d,cf,cl,Standard_False)) {
2777 B.UpdateEdge ( newEdge, c3d, 0. );
2778 sbe.SetRange3d ( newEdge, cf, cl );
2782 sfe->FixAddCurve3d ( newEdge );
2783 sewd->Set ( newEdge, j );
2787 // Collect wires in packets lying on same surface and dispatch them
2788 TColStd_Array1OfBoolean used ( 1, nb );
2789 used.Init ( Standard_False );
2791 TopTools_SequenceOfShape loops;
2793 Handle(Geom_Surface) Surf;
2794 for ( i = 1; i <= nb; i++ ) {
2795 if ( used(i) ) continue;
2796 Handle(Geom_Surface) S = myGrid->Patch ( mPnts(i) );
2797 if ( Surf.IsNull() ) Surf = S;
2798 else if ( S != Surf ) continue;
2799 used(i) = Standard_True;
2800 ShapeFix_WireSegment aSeg = wires(i);
2801 if(aSeg.IsVertex()) {
2802 TopoDS_Vertex aVert = aSeg.GetVertex();
2803 if(aVert.Orientation() == TopAbs_INTERNAL)
2804 loops.Append(wires(i).GetVertex());
2807 Handle(ShapeExtend_WireData) aWD = aSeg.WireData();
2809 loops.Append ( aWD->Wire() );
2812 if ( Surf.IsNull() ) break;
2814 MakeFacesOnPatch ( faces, Surf, loops );
2818 //======================================================================
2819 //function : SetTransferParamTool
2821 //=======================================================================
2823 void ShapeFix_ComposeShell::SetTransferParamTool(const Handle(ShapeAnalysis_TransferParameters)& TransferParam)
2825 myTransferParamTool = TransferParam;
2828 //=======================================================================
2829 //function : GetTransferParamTool
2831 //=======================================================================
2833 Handle(ShapeAnalysis_TransferParameters) ShapeFix_ComposeShell::GetTransferParamTool() const
2835 return myTransferParamTool;
2838 //=======================================================================
2839 //function : ClosedMode
2841 //=======================================================================
2843 Standard_Boolean &ShapeFix_ComposeShell::ClosedMode()
2845 return myClosedMode;