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