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