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