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