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