0026788: Compiler warnings when OCCT_DEBUG is enabled
[occt.git] / src / ShapeFix / ShapeFix_Face.cxx
CommitLineData
973c2be1 1// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 2//
973c2be1 3// This file is part of Open CASCADE Technology software library.
b311480e 4//
d5f74e42 5// This library is free software; you can redistribute it and/or modify it under
6// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 7// by the Free Software Foundation, with special exception defined in the file
8// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9// distribution for complete text of the license and disclaimer of any warranty.
b311480e 10//
973c2be1 11// Alternatively, this file may be used under the terms of Open CASCADE
12// commercial license or contractual agreement.
b311480e 13
7fd59977 14// pdn 10.12.98: tr9_r0501-ug
15// pdn 28.12.98: PRO10366 shifting pcurve between two singularities
16//:k7 abv 5.01.99: USA60022.igs ent 243: FixMissingSeam() improved
17//:l2 abv 10.01.99: USA60022 7289: corrections for reversed face
18//gka 11.01.99 file PRO7755.stp #2018: work-around error in BRepLib_MakeFace
19//:p4 abv, pdn 23.02.99: PRO9234 #15720: call BRepTools::Update() for faces
20// rln 03.03.99 S4135: transmission of parameter precision to SA_Surface::NbSingularities
21//:q5 abv 19.03.99 code improvement
22//%14 pdn 15.03.99 adding function for fixing null area wires
23//%15 pdn 20.03.99 code improvement
24// abv 09.04.99 S4136: improve tolerance management; remove unused flag Closed
25//#4 szv S4163: optimization
26// smh 31.01.01 BUC60810 : Case of small wire on face in solid
27// sln 25.09.2001 checking order of 3d and 2d representation curves
28// abv 19.10.2001 FixAddNaturalBound improved and extracted as separate fix
29// skl,pdn 14.05.2002 OCC55 (correction precision for small faces)
30
42cf5bc1 31#include <Bnd_Box.hxx>
32#include <Bnd_Box2d.hxx>
33#include <BndLib_Add2dCurve.hxx>
34#include <BRep_Builder.hxx>
35#include <BRep_Tool.hxx>
36#include <BRepBuilderAPI_MakeFace.hxx>
37#include <BRepBuilderAPI_MakeVertex.hxx>
38#include <BRepBuilderAPI_MakeWire.hxx>
39#include <BRepGProp.hxx>
40#include <BRepTools.hxx>
41#include <BRepTopAdaptor_FClass2d.hxx>
42#include <Geom2d_BSplineCurve.hxx>
7fd59977 43#include <Geom2d_Curve.hxx>
44#include <Geom2d_Line.hxx>
fdabc211 45#include <Geom2dAdaptor_Curve.hxx>
42cf5bc1 46#include <Geom2dInt_GInter.hxx>
7fd59977 47#include <Geom_BSplineSurface.hxx>
42cf5bc1 48#include <Geom_Circle.hxx>
49#include <Geom_ConicalSurface.hxx>
50#include <Geom_Curve.hxx>
51#include <Geom_RectangularTrimmedSurface.hxx>
52#include <Geom_SphericalSurface.hxx>
53#include <Geom_Surface.hxx>
7fd59977 54#include <GeomAdaptor_HSurface.hxx>
56a9db93 55#include <GProp_GProps.hxx>
42cf5bc1 56#include <IntRes2d_Domain.hxx>
57#include <IntRes2d_IntersectionPoint.hxx>
58#include <IntRes2d_IntersectionSegment.hxx>
59#include <IntRes2d_Transition.hxx>
60#include <Message_Msg.hxx>
61#include <NCollection_Array1.hxx>
62#include <Precision.hxx>
7fd59977 63#include <ShapeAnalysis.hxx>
7fd59977 64#include <ShapeAnalysis_Edge.hxx>
7fd59977 65#include <ShapeAnalysis_Surface.hxx>
42cf5bc1 66#include <ShapeAnalysis_Wire.hxx>
67#include <ShapeBuild_Edge.hxx>
68#include <ShapeBuild_ReShape.hxx>
69#include <ShapeExtend_BasicMsgRegistrator.hxx>
7fd59977 70#include <ShapeExtend_CompositeSurface.hxx>
42cf5bc1 71#include <ShapeExtend_WireData.hxx>
72#include <ShapeFix.hxx>
7fd59977 73#include <ShapeFix_ComposeShell.hxx>
42cf5bc1 74#include <ShapeFix_DataMapOfShapeBox2d.hxx>
75#include <ShapeFix_Edge.hxx>
76#include <ShapeFix_Face.hxx>
77#include <ShapeFix_IntersectionTool.hxx>
78#include <ShapeFix_SplitTool.hxx>
79#include <ShapeFix_Wire.hxx>
80#include <Standard_ErrorHandler.hxx>
81#include <Standard_Failure.hxx>
82#include <Standard_Type.hxx>
7fd59977 83#include <TColGeom_HArray2OfSurface.hxx>
7fd59977 84#include <TColgp_SequenceOfPnt2d.hxx>
42cf5bc1 85#include <TColStd_MapOfInteger.hxx>
86#include <TopExp.hxx>
87#include <TopExp_Explorer.hxx>
88#include <TopoDS.hxx>
89#include <TopoDS_Compound.hxx>
90#include <TopoDS_Edge.hxx>
91#include <TopoDS_Face.hxx>
92#include <TopoDS_Iterator.hxx>
93#include <TopoDS_Shell.hxx>
94#include <TopoDS_Vertex.hxx>
95#include <TopoDS_Wire.hxx>
96#include <TopTools_DataMapOfShapeInteger.hxx>
7fd59977 97#include <TopTools_DataMapOfShapeListOfShape.hxx>
42cf5bc1 98#include <TopTools_DataMapOfShapeShape.hxx>
99#include <TopTools_IndexedMapOfShape.hxx>
7fd59977 100#include <TopTools_ListIteratorOfListOfShape.hxx>
101#include <TopTools_MapOfShape.hxx>
7fd59977 102#include <TopTools_SequenceOfShape.hxx>
7fd59977 103
0797d9d3 104#ifdef OCCT_DEBUG
7fd59977 105#define DEBUG
106#endif
107
46aed280 108static Standard_Boolean IsSurfaceUVInfinite(const Handle(Geom_Surface)& theSurf)
109{
110 Standard_Real UMin,UMax,VMin,VMax;
111 theSurf->Bounds(UMin,UMax,VMin,VMax);
112
113 return (Precision::IsInfinite(UMin) ||
114 Precision::IsInfinite(UMax) ||
115 Precision::IsInfinite(VMin) ||
116 Precision::IsInfinite(VMax) );
117}
118
119static Standard_Boolean IsSurfaceUVPeriodic(const Handle(Geom_Surface)& theSurf)
120{
121 return theSurf->IsUPeriodic() && theSurf->IsVPeriodic();
122}
123
7fd59977 124//=======================================================================
125//function : ShapeFix_Face
126//purpose :
127//=======================================================================
128
129ShapeFix_Face::ShapeFix_Face()
130{
131 myFwd = Standard_True;
132 myStatus = 0;
133 myFixWire = new ShapeFix_Wire;
134 ClearModes();
135}
136
137//=======================================================================
138//function : ShapeFix_Face
139//purpose :
140//=======================================================================
141
142ShapeFix_Face::ShapeFix_Face(const TopoDS_Face &face)
143{
144 myFwd = Standard_True;
145 myStatus = 0;
146 myFixWire = new ShapeFix_Wire;
147 ClearModes();
148 Init( face );
149}
150
151//=======================================================================
152//function : ClearModes
153//purpose :
154//=======================================================================
155
156void ShapeFix_Face::ClearModes()
157{
84dc990a
S
158 myFixWireMode = -1;
159 myFixOrientationMode = -1;
160 myFixAddNaturalBoundMode = -1;
161 myFixMissingSeamMode = -1;
162 myFixSmallAreaWireMode = -1;
9d1b116f 163 myRemoveSmallAreaFaceMode = -1;
7fd59977 164 myFixIntersectingWiresMode = -1;
84dc990a
S
165 myFixLoopWiresMode = -1;
166 myFixSplitFaceMode = -1;
167 myAutoCorrectPrecisionMode = 1;
168 myFixPeriodicDegenerated = -1;
7fd59977 169}
170
171//=======================================================================
172//function : SetMsgRegistrator
173//purpose :
174//=======================================================================
175
176void ShapeFix_Face::SetMsgRegistrator(const Handle(ShapeExtend_BasicMsgRegistrator)& msgreg)
177{
178 ShapeFix_Root::SetMsgRegistrator ( msgreg );
179 myFixWire->SetMsgRegistrator ( msgreg );
180}
181
182//=======================================================================
183//function : SetPrecision
184//purpose :
185//=======================================================================
186
187void ShapeFix_Face::SetPrecision (const Standard_Real preci)
188{
189 ShapeFix_Root::SetPrecision ( preci );
190 myFixWire->SetPrecision ( preci );
191}
192
193//=======================================================================
194//function : SetMinTolerance
195//purpose :
196//=======================================================================
197
198void ShapeFix_Face::SetMinTolerance (const Standard_Real mintol)
199{
200 ShapeFix_Root::SetMinTolerance ( mintol );
201 myFixWire->SetMinTolerance ( mintol );
202}
203
204//=======================================================================
205//function : SetMaxTolerance
206//purpose :
207//=======================================================================
208
209void ShapeFix_Face::SetMaxTolerance (const Standard_Real maxtol)
210{
211 ShapeFix_Root::SetMaxTolerance ( maxtol );
212 myFixWire->SetMaxTolerance ( maxtol );
213}
214
215//=======================================================================
216//function : Init
217//purpose :
218//=======================================================================
219
220void ShapeFix_Face::Init (const Handle(Geom_Surface)& surf,
221 const Standard_Real preci, const Standard_Boolean fwd)
222{
223 myStatus = 0;
224 Handle(ShapeAnalysis_Surface) sas = new ShapeAnalysis_Surface ( surf );
225 Init ( sas, preci, fwd );
226}
227
228//=======================================================================
229//function : Init
230//purpose :
231//=======================================================================
232
233void ShapeFix_Face::Init (const Handle(ShapeAnalysis_Surface)& surf,
234 const Standard_Real preci, const Standard_Boolean fwd)
235{
236 myStatus = 0;
237 mySurf = surf;
238 SetPrecision ( preci );
239 BRep_Builder B;
240 B.MakeFace ( myFace, mySurf->Surface(), ::Precision::Confusion() );
241 myShape = myFace;
242 myFwd = fwd;
243 if ( !fwd ) myFace.Orientation(TopAbs_REVERSED);
244}
245
246//=======================================================================
247//function : Init
248//purpose :
249//=======================================================================
250
251void ShapeFix_Face::Init (const TopoDS_Face& face)
252{
253 myStatus = 0;
254 mySurf = new ShapeAnalysis_Surface ( BRep_Tool::Surface (face) );
255 myFwd = ( face.Orientation() != TopAbs_REVERSED );
256 myFace = face;
257 myShape = myFace;
258// myFace = TopoDS::Face(face.EmptyCopied());
259// for (TopoDS_Iterator ws (face,Standard_False); ws.More(); ws.Next())
260// Add (TopoDS::Wire (ws.Value()) );
261}
262
263//=======================================================================
264//function : Add
265//purpose :
266//=======================================================================
267
268void ShapeFix_Face::Add (const TopoDS_Wire& wire)
269{
270 if ( wire.IsNull() ) return;
271 BRep_Builder B;
272 //szv#4:S4163:12Mar99 SGI warns
273 TopoDS_Shape fc = myFace.Oriented(TopAbs_FORWARD); //:l2 abv 10 Jan 99: Oriented()
274 B.Add ( fc, wire );
275}
276
277
278//=======================================================================
279//function : SplitWire
280//purpose : auxilary - try to split wire (it is needed if some segments
281// were removed in ShapeFix_Wire::FixSelfIntersection()
282//=======================================================================
fdabc211 283static Standard_Boolean SplitWire(const TopoDS_Face &face, const TopoDS_Wire& wire,
7fd59977 284 TopTools_SequenceOfShape& aResWires)
285{
286 TColStd_MapOfInteger UsedEdges;
287 Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire);
288 Standard_Integer i,j,k;
289 ShapeAnalysis_Edge sae;
290 for(i=1; i<=sewd->NbEdges(); i++) {
291 if(UsedEdges.Contains(i)) continue;
292 TopoDS_Edge E1 = sewd->Edge(i);
293 UsedEdges.Add(i);
294 TopoDS_Vertex V0,V1,V2;
295 V0 = sae.FirstVertex(E1);
296 V1 = sae.LastVertex(E1);
297 Handle(ShapeExtend_WireData) sewd1 = new ShapeExtend_WireData;
298 sewd1->Add(E1);
299 Standard_Boolean IsConnectedEdge = Standard_True;
300 for(j=2; j<=sewd->NbEdges() && IsConnectedEdge; j++) {
fdabc211 301 TopoDS_Edge E2;
7fd59977 302 for(k=2; k<=sewd->NbEdges(); k++) {
303 if(UsedEdges.Contains(k)) continue;
fdabc211 304 E2 = sewd->Edge(k);
7fd59977 305 TopoDS_Vertex V21 = sae.FirstVertex(E2);
306 TopoDS_Vertex V22 = sae.LastVertex(E2);
307 if( sae.FirstVertex(E2).IsSame(V1) ) {
308 sewd1->Add(E2);
309 UsedEdges.Add(k);
310 V1 = sae.LastVertex(E2);
311 break;
312 }
313 }
7fd59977 314 if(k>sewd->NbEdges()) {
315 IsConnectedEdge = Standard_False;
316 break;
317 }
fdabc211 318 if(V1.IsSame(V0)) {
319 //check that V0 and V1 are same in 2d too
320 Standard_Real a1,b1,a2,b2;
321 Handle (Geom2d_Curve) curve1 = BRep_Tool::CurveOnSurface(E1,face,a1,b1);
322 Handle (Geom2d_Curve) curve2 = BRep_Tool::CurveOnSurface(E2,face,a2,b2);
323 gp_Pnt2d v0,v1;
324 if (E1.Orientation() == TopAbs_REVERSED)
325 a1 = b1;
326 if (E2.Orientation() == TopAbs_REVERSED)
327 b2 = a2;
328 curve1->D0(a1,v0);
329 curve2->D0(b2,v1);
330 GeomAdaptor_Surface anAdaptor(BRep_Tool::Surface(face));
331 Standard_Real tol = Max(BRep_Tool::Tolerance(V0),BRep_Tool::Tolerance(V1));
332 Standard_Real maxResolution = 2 * Max ( anAdaptor.UResolution(tol), anAdaptor.VResolution(tol) );
333 if (v0.SquareDistance(v1) < maxResolution) {
334 // new wire is closed, put it into sequence
335 aResWires.Append(sewd1->Wire());
336 break;
337 }
338 }
7fd59977 339 }
340 if(!IsConnectedEdge) {
341 // create new notclosed wire
342 aResWires.Append(sewd1->Wire());
343 }
344 if(UsedEdges.Extent()==sewd->NbEdges()) break;
345 }
346
347 if(aResWires.Length()>1) {
0797d9d3 348#ifdef OCCT_DEBUG
7fd59977 349 cout<<"Wire was splitted on "<<aResWires.Length()<<" wires"<< endl;
350#endif
351 }
352
353 return Standard_True;
354}
355
356
357//=======================================================================
358//function : Perform
359//purpose :
360//=======================================================================
361
362Standard_Boolean ShapeFix_Face::Perform()
363{
364 myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
365 myFixWire->SetContext ( Context() );
366 Handle(ShapeFix_Wire) theAdvFixWire = Handle(ShapeFix_Wire)::DownCast(myFixWire);
367 if (theAdvFixWire.IsNull()) return Standard_False;
368
369 BRep_Builder B;
370 TopoDS_Shape aInitFace = myFace;
371 // perform first part of fixes on wires
372 Standard_Boolean isfixReorder = Standard_False;
373 Standard_Boolean isReplaced = Standard_False;
374
375 //gka fix in order to avoid lost messages (following OCC21771)
376 TopTools_DataMapOfShapeShape aMapReorderedWires;
377
378 Standard_Real aSavPreci = Precision();
379 if ( NeedFix ( myFixWireMode ) ) {
380 theAdvFixWire->SetFace ( myFace );
381
382 Standard_Integer usFixLackingMode = theAdvFixWire->FixLackingMode();
0d4e3501 383 //Standard_Integer usFixNotchedEdgesMode = theAdvFixWire->FixNotchedEdgesMode(); // CR0024983
7fd59977 384 Standard_Integer usFixSelfIntersectionMode = theAdvFixWire->FixSelfIntersectionMode();
385 theAdvFixWire->FixLackingMode() = Standard_False;
0d4e3501 386 //theAdvFixWire->FixNotchedEdgesMode() = Standard_False; // CR0024983
7fd59977 387 theAdvFixWire->FixSelfIntersectionMode() = Standard_False;
388
389 Standard_Boolean fixed = Standard_False;
390 TopoDS_Shape S = myFace;
391 if ( ! Context().IsNull() )
392 S = Context()->Apply ( myFace );
393 TopoDS_Shape emptyCopied = S.EmptyCopied();
394 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
395 tmpFace.Orientation ( TopAbs_FORWARD );
396
397 /*
398 // skl 14.05.2002 OCC55 + corrected 03.03.2004
399 Standard_Real dPreci = aSavPreci*aSavPreci;
400 dPreci*=4;
401 Standard_Real newpreci=dPreci;
402 for(TopExp_Explorer exp(S,TopAbs_EDGE); exp.More(); exp.Next()) {
403 TopoDS_Edge edge = TopoDS::Edge ( exp.Current() );
404 Standard_Real first,last;
405 Handle(Geom_Curve) c3d = BRep_Tool::Curve(edge, first, last);
406 if(!c3d.IsNull()) {
407 Bnd_Box bb;
408 bb.Add(c3d->Value(first));
409 bb.Add(c3d->Value(last));
410 bb.Add(c3d->Value((last+first)/2.));
411 Standard_Real x1,x2,y1,y2,z1,z2,size;
412 bb.Get(x1,y1,z1,x2,y2,z2);
413 size = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1);
414 if(size<newpreci) newpreci=size;
415 }
416 }
417 newpreci=sqrt(newpreci)/2.*1.00001;
418 if( aSavPreci > newpreci && newpreci > Precision::Confusion()) {
419 SetPrecision(newpreci);
420 theAdvFixWire->SetPrecision(newpreci);
421 }
422 // end skl 14.05.2002
423 */
424
425 // skl 29.03.2010 (OCC21623)
426 if( myAutoCorrectPrecisionMode ) {
427 Standard_Real size = ShapeFix::LeastEdgeSize(S);
428 Standard_Real newpreci = Min(aSavPreci,size/2.);
429 newpreci = newpreci*1.00001;
430 if( aSavPreci > newpreci && newpreci > Precision::Confusion()) {
431 SetPrecision(newpreci);
432 theAdvFixWire->SetPrecision(newpreci);
433 }
434 }
46aed280 435
7fd59977 436 isfixReorder = Standard_False;
437 for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
438 if(iter.Value().ShapeType() != TopAbs_WIRE) {
439 B.Add ( tmpFace, iter.Value() );
440 continue;
441 }
442 TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
443 theAdvFixWire->Load ( wire );
444 if(theAdvFixWire->NbEdges() == 0) {
445 if(theAdvFixWire->WireData()->NbNonManifoldEdges())
446 B.Add ( tmpFace, wire );
447 else {
448 fixed = Standard_True;
449 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
450 }
451 continue;
452 }
453 if ( theAdvFixWire->Perform() ) {
454 //fixed = Standard_True;
d3c5411b 455 isfixReorder = (theAdvFixWire->StatusReorder(ShapeExtend_DONE) || isfixReorder);
7fd59977 456 fixed = (theAdvFixWire->StatusSmall(ShapeExtend_DONE) ||
457 theAdvFixWire->StatusConnected(ShapeExtend_DONE) ||
458 theAdvFixWire->StatusEdgeCurves(ShapeExtend_DONE) ||
0d4e3501 459 theAdvFixWire->StatusNotches(ShapeExtend_DONE) || // CR0024983
fbf3becf 460 theAdvFixWire->StatusFixTails(ShapeExtend_DONE) ||
7fd59977 461 theAdvFixWire->StatusDegenerated(ShapeExtend_DONE) ||
462 theAdvFixWire->StatusClosed(ShapeExtend_DONE));
463 TopoDS_Wire w = theAdvFixWire->Wire();
464 if(fixed) {
465 if ( ! Context().IsNull() ) Context()->Replace ( wire, w );
466 if(theAdvFixWire->NbEdges() == 0) {
467 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
468 continue;
469 }
470 }
471 else if(!wire.IsSame(w))
472 aMapReorderedWires.Bind(wire,w);
473
474 wire = w;
475 }
476 B.Add ( tmpFace, wire );
477 // if ( theAdvFixWire->Status ( ShapeExtend_FAIL ) )
478 // myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
479 }
480
481 theAdvFixWire->FixLackingMode() = usFixLackingMode;
0d4e3501 482 //theAdvFixWire->FixNotchedEdgesMode() = usFixNotchedEdgesMode; // CR0024983
7fd59977 483 theAdvFixWire->FixSelfIntersectionMode() = usFixSelfIntersectionMode;
484 if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED );
485
486 if ( fixed ) {
487 //if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED );
488 if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace );
489 //myFace = tmpFace;
490 isReplaced = Standard_True;
7fd59977 491 }
673693f1 492 if(fixed || isfixReorder) {
7fd59977 493 myFace = tmpFace;
d3c5411b 494 if (!theAdvFixWire->StatusReorder(ShapeExtend_DONE5)) {
495 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
496 }
673693f1 497 }
7fd59977 498 }
499
500 myResult = myFace;
501 TopoDS_Shape savShape = myFace; //gka BUG 6555
84dc990a
S
502
503 // Specific case for conic surfaces
504 if ( NeedFix(myFixPeriodicDegenerated) )
505 this->FixPeriodicDegenerated();
506
7fd59977 507 // fix missing seam
508 if ( NeedFix ( myFixMissingSeamMode ) ) {
509 if ( FixMissingSeam() ) {
510 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
511 }
512 }
513
514 // cycle by all possible faces coming from FixMissingSeam
46aed280 515 // each face is processed as if it was single
7fd59977 516 TopExp_Explorer exp(myResult,TopAbs_FACE);
517 for ( ; exp.More(); exp.Next() ) {
518 myFace = TopoDS::Face ( exp.Current() );
519 Standard_Boolean NeedCheckSplitWire = Standard_False;
520
521 // perform second part of fixes on wires
522 if ( NeedFix ( myFixWireMode ) ) {
523 theAdvFixWire->SetFace ( myFace );
524
525 Standard_Integer usFixSmallMode = theAdvFixWire->FixSmallMode();
526 Standard_Integer usFixConnectedMode = theAdvFixWire->FixConnectedMode();
527 Standard_Integer usFixEdgeCurvesMode =theAdvFixWire->FixEdgeCurvesMode();
528 Standard_Integer usFixDegeneratedMode = theAdvFixWire->FixDegeneratedMode();
529 theAdvFixWire->FixSmallMode() = Standard_False;
530 theAdvFixWire->FixConnectedMode() = Standard_False;
531 theAdvFixWire->FixEdgeCurvesMode() = Standard_False;
532 theAdvFixWire->FixDegeneratedMode() = Standard_False;
533
534 Standard_Boolean fixed = Standard_False;
535 TopoDS_Shape S = myFace;
536 if ( ! Context().IsNull() )
537 S = Context()->Apply ( myFace );
538 TopoDS_Shape emptyCopied = S.EmptyCopied();
539 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
540 tmpFace.Orientation ( TopAbs_FORWARD );
541 for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
542 if(iter.Value().ShapeType() != TopAbs_WIRE) {
543 B.Add ( tmpFace,iter.Value());
544 continue;
545 }
546
547 TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
548 theAdvFixWire->Load ( wire );
549 if(theAdvFixWire->NbEdges() == 0) {
550 if(theAdvFixWire->WireData()->NbNonManifoldEdges())
551 B.Add ( tmpFace, wire );
552 else {
553 fixed = Standard_True;
554 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
555 }
556 continue;
557 }
558 if ( theAdvFixWire->Perform() ) {
559 isfixReorder = theAdvFixWire->StatusReorder(ShapeExtend_DONE);
fbf3becf 560 fixed = (theAdvFixWire->StatusLacking(ShapeExtend_DONE) ||
561 theAdvFixWire->StatusSelfIntersection(ShapeExtend_DONE) ||
562 theAdvFixWire->StatusNotches(ShapeExtend_DONE) ||
563 theAdvFixWire->StatusFixTails(ShapeExtend_DONE));
7fd59977 564 TopoDS_Wire w = theAdvFixWire->Wire();
565 if(fixed) {
566 if ( ! Context().IsNull() ) Context()->Replace ( wire, w );
567
568 }
569 else if(!wire.IsSame(w))
570 aMapReorderedWires.Bind(wire,w);
571
572 wire = w;
573 }
574 if(theAdvFixWire->StatusRemovedSegment())
575 NeedCheckSplitWire = Standard_True;
576
577 //fix for loop of wire
578 TopTools_SequenceOfShape aLoopWires;
579 if(NeedFix ( myFixLoopWiresMode) && FixLoopWire(aLoopWires)) {
999d2599
D
580 if (aLoopWires.Length() > 1)
581 SendWarning ( wire, Message_Msg ( "FixAdvFace.FixLoopWire.MSG0" ) );// Wire was splitted on several wires
7fd59977 582 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
583 fixed = Standard_True;
584 Standard_Integer k=1;
585 for( ; k <= aLoopWires.Length(); k++)
586 B.Add (tmpFace,aLoopWires.Value(k));
587 }
588 else
589 B.Add ( tmpFace, wire );
590 }
591
592 theAdvFixWire->FixSmallMode() = usFixSmallMode;
593 theAdvFixWire->FixConnectedMode() = usFixConnectedMode;
594 theAdvFixWire->FixEdgeCurvesMode() = usFixEdgeCurvesMode;
595 theAdvFixWire->FixDegeneratedMode() = usFixDegeneratedMode;
596
597 if ( fixed ) {
598 if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED );
599 if(!isReplaced && !aInitFace.IsSame(myResult) && ! Context().IsNull()) //gka 06.09.04 BUG 6555
600 Context()->Replace(aInitFace,savShape);
601 if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace );
602 myFace = tmpFace;
603 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
604 }
605 }
606
607 if(NeedCheckSplitWire) {
608 // try to split wire - it is needed if some segments were removed
609 // in ShapeFix_Wire::FixSelfIntersection()
610 TopoDS_Shape S = myFace;
611 if ( ! Context().IsNull() )
612 S = Context()->Apply ( myFace );
613 TopoDS_Shape emptyCopied = S.EmptyCopied();
614 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
615 tmpFace.Orientation ( TopAbs_FORWARD );
616 TopTools_SequenceOfShape aWires;
617 Standard_Integer nbw=0;
618 for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
619 if(iter.Value().ShapeType() != TopAbs_WIRE) {
620 B.Add (tmpFace,iter.Value());
621 continue;
622 }
56084216 623 if(iter.Value().Orientation() != TopAbs_FORWARD &&
7fd59977 624 iter.Value().Orientation() != TopAbs_REVERSED) {
625 B.Add (tmpFace,TopoDS::Wire(iter.Value()));
626 continue;
627 }
628 nbw++;
629 TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
fdabc211 630 SplitWire(tmpFace,wire,aWires);
7fd59977 631 }
632 if(nbw<aWires.Length()) {
633 for(Standard_Integer iw=1; iw<=aWires.Length(); iw++)
634 B.Add (tmpFace,aWires.Value(iw));
635 if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace );
636 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 );
637 myFace = tmpFace;
638 }
639 }
640
641 // fix intersecting wires
642 if(FixWiresTwoCoincEdges())
643 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
644 if ( NeedFix ( myFixIntersectingWiresMode ) ) {
645 if ( FixIntersectingWires() ) {
646 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE6 );
647 }
648 }
649
650 // fix orientation
651 TopTools_DataMapOfShapeListOfShape MapWires;
652 MapWires.Clear();
653 if ( NeedFix ( myFixOrientationMode ) ) {
654 if ( FixOrientation(MapWires) )
655 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
656 }
657
658 BRepTools::Update(myFace);
659
660 // fix natural bounds
661 Standard_Boolean NeedSplit = Standard_True;
662 if ( NeedFix ( myFixAddNaturalBoundMode ) ) {
663 if ( FixAddNaturalBound() ) {
664 NeedSplit = Standard_False;
665 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
666 }
667 }
668
669 // split face
670 if ( NeedFix ( myFixSplitFaceMode ) && NeedSplit && MapWires.Extent()>1 ) {
671 if ( FixSplitFace(MapWires) )
672 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 );
673 }
674
675 }
676
677 //return the original preci
678 SetPrecision(aSavPreci);
46aed280 679 theAdvFixWire->SetPrecision(aSavPreci);
7fd59977 680
681 // cycle by all possible faces coming from FixAddNaturalBound
682 // each face is processed as if it was single
683 for ( exp.Init(myResult,TopAbs_FACE); exp.More(); exp.Next() ) {
684 myFace = TopoDS::Face ( exp.Current() );
685
686 // fix small-area wires
56a9db93 687 if ( NeedFix ( myFixSmallAreaWireMode, Standard_False ) )
688 {
689 const Standard_Boolean isRemoveFace = NeedFix( myRemoveSmallAreaFaceMode, Standard_False );
690 if ( FixSmallAreaWire( isRemoveFace ) )
691 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE4 );
7fd59977 692 }
693 }
56a9db93 694
7fd59977 695 if ( ! Context().IsNull() ) {
696 if(Status ( ShapeExtend_DONE ) && !isReplaced && !aInitFace.IsSame(savShape))
697 {
698 //gka fix in order to avoid lost messages (following OCC21771)
699 if(aMapReorderedWires.Extent())
700 {
701 TopoDS_Iterator aItW(aInitFace,Standard_False);
702 for( ; aItW.More() ; aItW.Next())
703 {
704 TopoDS_Shape aCurW = aItW.Value();
705 while(aMapReorderedWires.IsBound(aCurW))
706 {
707 TopoDS_Shape aFixW = aMapReorderedWires.Find(aCurW);
708 Context()->Replace(aCurW, aFixW);
709 aCurW = aFixW;
710 }
711 }
712
713 }
714 Context()->Replace(aInitFace, savShape);
715 }
716 myResult = Context()->Apply ( aInitFace ); //gka 06.09.04
717 }
718 else if(!Status ( ShapeExtend_DONE ))
719 myResult = aInitFace;
720
721 return Status ( ShapeExtend_DONE );
722}
723
724//=======================================================================
725//function : Auxiliary functions
726//purpose :
727//=======================================================================
728
729// Shift all pcurves of edges in the given wire on the given face
730// to vector <vec>
731static void Shift2dWire(const TopoDS_Wire w, const TopoDS_Face f,
732 const gp_Vec2d vec,
733 const Handle(ShapeAnalysis_Surface)& mySurf,
734 Standard_Boolean recompute3d = Standard_False)
735{
736 gp_Trsf2d tr2d;
737 tr2d.SetTranslation(vec.XY());
738 ShapeAnalysis_Edge sae;
739 ShapeBuild_Edge sbe;
740 BRep_Builder B;
741 for (TopoDS_Iterator ei (w,Standard_False); ei.More(); ei.Next()){
742 TopoDS_Edge edge = TopoDS::Edge(ei.Value());
743 Handle (Geom2d_Curve) C2d;
744 Standard_Real cf, cl;
745 if ( ! sae.PCurve(edge, f, C2d, cf, cl, Standard_True) ) continue;
746 C2d->Transform(tr2d);
747 if ( recompute3d ) {
748 // recompute 3d curve and vertex
749 sbe.RemoveCurve3d ( edge );
750 sbe.BuildCurve3d ( edge );
751 B.UpdateVertex ( sae.FirstVertex(edge), mySurf->Value(C2d->Value(cf)), 0. );
752 }
753 }
754}
755
756// Cut interval from the sequence of intervals
757static Standard_Boolean CutInterval (TColgp_SequenceOfPnt2d &intervals,
758 const gp_Pnt2d &toAddI,
759 const Standard_Real period)
760{
761 if ( intervals.Length() <=0 ) return Standard_False;
762 for ( Standard_Integer j=0; j <2; j++ ) { // try twice, align to bottom and to top
763 for ( Standard_Integer i=1; i <= intervals.Length(); i++ ) {
764 gp_Pnt2d interval = intervals(i);
765 // ACIS907, OCC921 a054a.sat (face 124)
766 Standard_Real shift = ShapeAnalysis::AdjustByPeriod ( ( j ? toAddI.X() : toAddI.Y() ),
767 0.5*( interval.X() + interval.Y() ),period);
768 gp_Pnt2d toAdd ( toAddI.X() + shift, toAddI.Y() + shift );
769 if ( toAdd.Y() <= interval.X() || toAdd.X() >= interval.Y() ) continue;
770 if ( toAdd.X() > interval.X() ) {
771 if ( toAdd.Y() < interval.Y() ) {
772 intervals.InsertBefore ( i, interval );
773 intervals.ChangeValue(i+1).SetX ( toAdd.Y() ); // i++...
774 }
775 intervals.ChangeValue(i).SetY ( toAdd.X() );
776 }
777 else if ( toAdd.Y() < interval.Y() ) {
778 intervals.ChangeValue(i).SetX ( toAdd.Y() );
779 }
780 else intervals.Remove ( i-- );
781 }
782 }
783 return Standard_True;
784}
785
786// Find middle of the biggest interval
787static Standard_Real FindBestInterval (TColgp_SequenceOfPnt2d &intervals)
788{
789 Standard_Real shift = 0., max = -1.;
790 for ( Standard_Integer i=1; i <= intervals.Length(); i++ ) {
791 gp_Pnt2d interval = intervals(i);
792 if ( interval.Y() - interval.X() <= max ) continue;
793 max = interval.Y() - interval.X();
794 shift = interval.X() + 0.5 * max;
795 }
796 return shift;
797}
798
799//=======================================================================
800//function : FixAddNaturalBound
801//purpose :
802//=======================================================================
803// Detect missing natural bounary on spherical surfaces and add it if
804// necessary
805//pdn 981202: add natural bounds if missing (on sphere only)
806//:abv 28.08.01: rewritten and extended for toruses
807
808Standard_Boolean ShapeFix_Face::FixAddNaturalBound()
809{
810 if ( ! Context().IsNull() ) {
811 TopoDS_Shape S = Context()->Apply ( myFace );
812 myFace = TopoDS::Face ( S );
813 }
814
815 // collect wires in sequence
816 TopTools_SequenceOfShape ws;
817 TopTools_SequenceOfShape vs;
818 TopoDS_Iterator wi (myFace,Standard_False);
819 for ( ; wi.More(); wi.Next()) {
820 if(wi.Value().ShapeType() == TopAbs_WIRE &&
821 (wi.Value().Orientation() == TopAbs_FORWARD || wi.Value().Orientation() == TopAbs_REVERSED))
822 ws.Append (wi.Value());
823 else
824 vs.Append(wi.Value());
825 }
826
46aed280 827 // deal with the case of an empty face: just create a new face by a standard tool
828 if (ws.IsEmpty() && !IsSurfaceUVInfinite (mySurf->Surface()))
829 {
830 BRepBuilderAPI_MakeFace aFaceBuilder (mySurf->Surface(), Precision::Confusion());
831
832 TopoDS_Face aNewFace = aFaceBuilder.Face();
833 aNewFace.Orientation (myFace.Orientation());
834
835 if ( ! Context().IsNull() )
836 Context()->Replace (myFace, aNewFace);
837
838 // taking into account orientation
839 myFace = aNewFace;
7fd59977 840
841 //gka 11.01.99 file PRO7755.stp entity #2018 surface #1895: error BRepLib_MakeFace func IsDegenerated
842 Handle(ShapeFix_Edge) sfe = myFixWire->FixEdgeTool();
843 for (TopExp_Explorer Eed (myFace, TopAbs_EDGE); Eed.More(); Eed.Next()) {
844 TopoDS_Edge edg = TopoDS::Edge (Eed.Current());
845 sfe->FixVertexTolerance(edg);
846 }
847
848// B.UpdateFace (myFace,myPrecision);
999d2599 849 SendWarning ( myFace, Message_Msg ( "FixAdvFace.FixOrientation.MSG0" ) );// Face created with natural bounds
7fd59977 850 BRepTools::Update(myFace);
46aed280 851 myResult = myFace;
7fd59977 852 return Standard_True;
853 }
46aed280 854
855 // check if surface is double-closed and fix is needed
856 if ( !IsSurfaceUVPeriodic (mySurf->Surface()) || ShapeAnalysis::IsOuterBound (myFace) )
7fd59977 857 return Standard_False;
858
859 // Collect informations on free intervals in U and V
860 TColgp_SequenceOfPnt2d intU, intV, centers;
861 Standard_Real SUF, SUL, SVF, SVL;
862 mySurf->Bounds(SUF, SUL, SVF, SVL);
863 intU.Append ( gp_Pnt2d(SUF, SUL) );
864 intV.Append ( gp_Pnt2d(SVF, SVL) );
865 Standard_Integer nb = ws.Length();
866 Standard_Integer i;
867 for ( i=1; i <= nb; i ++) {
868 Standard_Real Umin, Vmin, Umax, Vmax;
869// Bnd_Box2d B;
870 TopoDS_Wire aw = TopoDS::Wire (ws.Value(i));
871 // PTV 01.11.2002 ACIS907, OCC921 begin
872// BRepTools::AddUVBounds(myFace,aw,B);
873// B.Get(Umin, Vmin, Umax, Vmax);
874 TopoDS_Face aWireFace = TopoDS::Face( myFace.EmptyCopied() );
875 BRep_Builder aB;
876 aB.Add( aWireFace, aw );
877 ShapeAnalysis::GetFaceUVBounds(aWireFace, Umin, Umax, Vmin, Vmax);
878 // PTV 01.11.2002 ACIS907, OCC921 end
879 if ( mySurf->IsUClosed() ) CutInterval ( intU, gp_Pnt2d(Umin,Umax), SUL-SUF );
880 if ( mySurf->IsVClosed() ) CutInterval ( intV, gp_Pnt2d(Vmin,Vmax), SVL-SVF );
881 centers.Append ( gp_Pnt2d ( 0.5*(Umin+Umax), 0.5*(Vmin+Vmax) ) );
882 }
883
884 // find best interval and thus compute shift
885 gp_Pnt2d shift(0.,0.);
886 if ( mySurf->IsUClosed() ) shift.SetX ( FindBestInterval ( intU ) );
887 if ( mySurf->IsVClosed() ) shift.SetY ( FindBestInterval ( intV ) );
888
889 // Adjust all other wires to be inside outer one
890 gp_Pnt2d center ( shift.X() + 0.5*(SUL-SUF), shift.Y() + 0.5*(SVL-SVF) );
891 for ( i=1; i <= nb; i++ ) {
892 TopoDS_Wire wire = TopoDS::Wire (ws.Value(i));
893 gp_Pnt2d sh(0.,0.);
894 if ( mySurf->IsUClosed() )
895 sh.SetX ( ShapeAnalysis::AdjustByPeriod ( centers(i).X(), center.X(), SUL-SUF ) );
896 if ( mySurf->IsVClosed() )
897 sh.SetY ( ShapeAnalysis::AdjustByPeriod ( centers(i).Y(), center.Y(), SVL-SVF ) );
898 Shift2dWire ( wire, myFace, sh.XY(), mySurf );
899 }
900
901 // Create naturally bounded surface and add that wire to sequence
902/* variant 1
903 // Create fictive grid and call ComposeShell
904 Handle(Geom_RectangularTrimmedSurface) RTS =
905 new Geom_RectangularTrimmedSurface ( mySurf->Surface(), SUF+shift.X(), SUL+shift.X(),
906 SVF+shift.Y(), SVL+shift.Y() );
907 Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 );
908 grid->SetValue ( 1, 1, RTS );
909 Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid );
910 TopLoc_Location L;
911
912 ShapeFix_ComposeShell CompShell;
913 CompShell.Init ( G, L, myFace, ::Precision::Confusion() );
914 CompShell.ClosedMode() = Standard_True;
915 CompShell.NaturalBoundMode() = Standard_True;
916 CompShell.SetContext( Context() );
917 CompShell.SetMaxTolerance(MaxTolerance());
918 CompShell.Perform();
919 TopoDS_Shape res = CompShell.Result();
920
921 Context()->Replace ( myFace, res );
922 for (TopExp_Explorer exp ( res, TopAbs_FACE ); exp.More(); exp.Next() ) {
923 myFace = TopoDS::Face ( exp.Current() );
924 BRepTools::Update(myFace); //:p4
925 }
926 myResult = Context()->Apply ( myResult );
927*/
928/* variant 2 */
929 TopLoc_Location L;
930 Handle(Geom_Surface) surf = BRep_Tool::Surface ( myFace, L );
1c72dff6 931 BRepBuilderAPI_MakeFace mf (surf, Precision::Confusion());
7fd59977 932 TopoDS_Face ftmp = mf.Face();
933 ftmp.Location ( L );
934 for (wi.Initialize (ftmp,Standard_False); wi.More(); wi.Next()) {
935 if(wi.Value().ShapeType() != TopAbs_WIRE)
936 continue;
937 TopoDS_Wire wire = TopoDS::Wire ( wi.Value() );
938 ws.Append ( wire );
939 if ( shift.XY().Modulus() < ::Precision::PConfusion() ) continue;
940 Shift2dWire ( wire, myFace, shift.XY(), mySurf, Standard_True );
941 }
942
943 // Fix possible case on sphere when gap contains degenerated edge
944 // and thus has a common part with natural boundary
945 // Such hole should be merged with boundary
946 if ( mySurf->Adaptor3d()->GetType() == GeomAbs_Sphere &&
947 ws.Length() == nb+1 ) {
948 Handle(ShapeExtend_WireData) bnd =
949 new ShapeExtend_WireData ( TopoDS::Wire ( ws.Last() ) );
950 // code to become separate method FixTouchingWires()
951 for ( i=1; i <= nb; i++ ) {
952 Handle(ShapeExtend_WireData) sbwd =
953 new ShapeExtend_WireData ( TopoDS::Wire ( ws.Value(i) ) );
954 for (Standard_Integer j=1; j <= sbwd->NbEdges(); j++ ) {
955 if ( ! BRep_Tool::Degenerated ( sbwd->Edge(j) ) ) continue;
956 // find corresponding place in boundary
957 ShapeAnalysis_Edge sae;
958 TopoDS_Vertex V = sae.FirstVertex ( sbwd->Edge(j) );
959 Standard_Integer k;
960 for ( k=1; k <= bnd->NbEdges(); k++ ) {
961 if ( ! BRep_Tool::Degenerated ( bnd->Edge(k) ) ) continue;
962 if ( BRepTools::Compare ( V, sae.FirstVertex ( bnd->Edge(k) ) ) ) break;
963 }
964 if ( k > bnd->NbEdges() ) continue;
965 // and insert hole to that place
966 BRep_Builder B;
967 B.Degenerated ( sbwd->Edge(j), Standard_False );
968 B.Degenerated ( bnd->Edge(k), Standard_False );
969 sbwd->SetLast ( j );
970 bnd->Add ( sbwd, k+1 );
971 ws.Remove ( i-- );
972 nb--;
973 myFixWire->SetFace ( myFace );
974 myFixWire->Load ( bnd );
975 myFixWire->FixConnected();
976 myFixWire->FixDegenerated();
977 ws.SetValue ( ws.Length(), bnd->Wire() );
978 break;
979 }
980 }
981 }
982
983 // Create resulting face
984 BRep_Builder B;
985 TopoDS_Shape S = myFace.EmptyCopied();
986 S.Orientation ( TopAbs_FORWARD );
987 for ( i = 1; i <= ws.Length(); i++ ) B.Add ( S, ws.Value(i) );
988 for ( i = 1; i <= vs.Length(); i++ ) B.Add ( S, vs.Value(i) );
989 if ( ! myFwd ) S.Orientation (TopAbs_REVERSED);
990 if ( ! Context().IsNull() ) Context()->Replace ( myFace, S );
991 myFace = TopoDS::Face ( S );
992 BRepTools::Update(myFace);
993
994/**/
0797d9d3 995#ifdef OCCT_DEBUG
7fd59977 996 cout<<"Natural bound on sphere or torus with holes added"<<endl; // mise au point !
997#endif
999d2599 998 SendWarning ( myFace, Message_Msg ( "FixAdvFace.FixOrientation.MSG0" ) );// Face created with natural bounds
7fd59977 999 return Standard_True;
1000}
1001
1002
1003//=======================================================================
1004//function : FixOrientation
1005//purpose :
1006//=======================================================================
1007
1008Standard_Boolean ShapeFix_Face::FixOrientation()
1009{
1010 TopTools_DataMapOfShapeListOfShape MapWires;
1011 MapWires.Clear();
1012 return FixOrientation(MapWires);
1013}
1014
1015
1016//=======================================================================
1017//function : FixOrientation
1018//purpose :
1019//=======================================================================
1020
1021Standard_Boolean ShapeFix_Face::FixOrientation(TopTools_DataMapOfShapeListOfShape &MapWires)
1022{
1023 Standard_Boolean done = Standard_False;
1024
1025 if ( ! Context().IsNull() ) {
1026 TopoDS_Shape S = Context()->Apply ( myFace );
1027 myFace = TopoDS::Face ( S );
1028 }
1029 TopTools_SequenceOfShape ws;
1030 TopTools_SequenceOfShape allSubShapes;
1031 // smh: BUC60810 : protection against very small wires (one-edge, null-length)
1032 TopTools_SequenceOfShape VerySmallWires;
1033 for ( TopoDS_Iterator wi (myFace,Standard_False); wi.More(); wi.Next()) {
1034 if(wi.Value().ShapeType() == TopAbs_VERTEX ||
1035 (wi.Value().Orientation() != TopAbs_FORWARD &&
1036 wi.Value().Orientation() != TopAbs_REVERSED)) {
1037 allSubShapes.Append (wi.Value());
1038 //ws.Append (wi.Value());
1039 continue;
1040 }
1041
46aed280 1042 TopoDS_Iterator ei (wi.Value(),Standard_False);
7fd59977 1043 TopoDS_Edge anEdge;
1044 Standard_Real length = RealLast();
1045 if ( ei.More() ) {
1046 anEdge = TopoDS::Edge(ei.Value());
1047 ei.Next();
1048 if ( ! ei.More() ) {
1049 length = 0;
1050 Standard_Real First, Last;
1051 Handle(Geom_Curve) c3d;
1052 ShapeAnalysis_Edge sae;
1053 if ( sae.Curve3d(anEdge,c3d,First,Last) ) {
1054 gp_Pnt pntIni = c3d->Value(First);
1055 gp_XYZ prev;
1056 prev = pntIni.XYZ();
1057 Standard_Integer NbControl = 10;
1058 for ( Standard_Integer j = 1; j < NbControl; j++) {
1059 Standard_Real prm = ((NbControl-1-j)*First + j*Last)/(NbControl-1);
1060 gp_Pnt pntCurr = c3d->Value(prm);
1061 gp_XYZ curr = pntCurr.XYZ();
1062 gp_XYZ delta = curr - prev;
1063 length += delta.Modulus();
1064 prev = curr;
1065 }
1066 }
1067 }
1068 }
1069 else length = 0;
1070 if (length > ::Precision::Confusion()) {
1071 ws.Append (wi.Value());
1072 allSubShapes.Append (wi.Value());
1073 }
1074 else VerySmallWires.Append (wi.Value());
1075 }
1076 if ( VerySmallWires.Length() >0 ) done = Standard_True;
1077
1078 Standard_Integer nb = ws.Length();
1079 Standard_Integer nbAll = allSubShapes.Length();
1080 BRep_Builder B;
1081
1082 // if no wires, just do nothing
1083 if ( nb <= 0) return Standard_False;
1084 Standard_Integer nbInternal=0;
1085 Standard_Boolean isAddNaturalBounds = (NeedFix (myFixAddNaturalBoundMode) &&
46aed280 1086 IsSurfaceUVPeriodic (mySurf->Surface()));
7fd59977 1087 TColStd_SequenceOfInteger aSeqReversed;
1088 // if wire is only one, check its orientation
1089 if ( nb == 1 ) {
1090 // skl 12.04.2002 for cases with nbwires>1 (VerySmallWires>1)
1091 // make face with only one wire (ws.Value(1))
1092 TopoDS_Shape dummy = myFace.EmptyCopied();
1093 TopoDS_Face af = TopoDS::Face ( dummy );
1094 af.Orientation ( TopAbs_FORWARD );
1095 B.Add (af,ws.Value(1));
46aed280 1096 if ((myFixAddNaturalBoundMode != Standard_True || //: abv 29.08.01: Spatial_firex_lofting.sat
1097 !IsSurfaceUVPeriodic (mySurf->Surface()) ) &&
1098 !ShapeAnalysis::IsOuterBound (af) )
1099 {
7fd59977 1100 Handle(ShapeExtend_WireData) sbdw =
1101 new ShapeExtend_WireData (TopoDS::Wire(ws.Value(1)));
1102 sbdw->Reverse ( myFace );
1103 ws.SetValue ( 1, sbdw->Wire() );
999d2599 1104 SendWarning ( sbdw->Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
7fd59977 1105 done = Standard_True;
0797d9d3 1106#ifdef OCCT_DEBUG
7fd59977 1107 cout<<"Wire reversed"<<endl; // mise au point !
1108#endif
1109 }
1110 }
1111 // in case of several wires, perform complex analysis
1112// ATTENTION ESSAI
1113// Plusieurs wires : orientations relatives
1114// Chaque wire doit "contenir" tous les autres
1115// Evidemment, en cas de peau de leopard, il peut y avoir probleme
1116 else {
1117// On prend chaque wire (NB: pcurves presentes !)
1118// En principe on devrait rejeter les wires non fermes (cf couture manque ?)
1119// On le classe par rapport aux autres, qui doivent tous etre, soit IN soit
1120// OUT. Sinon il y a imbrication -> SDB. Si IN, OK, si OUT on inverse
1121// (nb : ici pas myClos donc pas de pb de couture)
1122// Si au moins une inversion, il faut refaire la face (cf myRebil)
1123
1124 //:94 abv 30 Jan 98: calculate parametric precision
1125
1126// GeomAdaptor_Surface& Ads = mySurf->Adaptor3d()->ChangeSurface();
1127// Standard_Real toluv = Min ( Ads.UResolution(Precision()), Ads.VResolution(Precision()) );
1128 Standard_Boolean uclosed = mySurf->IsUClosed();
1129 Standard_Boolean vclosed = mySurf->IsVClosed();
1130 Standard_Real SUF, SUL, SVF, SVL;
1131 mySurf->Bounds(SUF, SUL, SVF, SVL);
1ee621b6 1132 Standard_Real uRange = SUL - SUF;
1133 Standard_Real vRange = SVL - SVF;
7fd59977 1134
1135 TopTools_DataMapOfShapeListOfShape MW;
1136 TopTools_DataMapOfShapeInteger SI;
1137 TopTools_MapOfShape MapIntWires;
1138 MW.Clear();
1139 SI.Clear();
1140 MapIntWires.Clear();
1141 Standard_Integer NbOuts=0;
1142 Standard_Integer i;
1ee621b6 1143
1144 NCollection_Array1<Bnd_Box2d> aWireBoxes(1, nb);
1145 Standard_Real uMiddle = 0, vMiddle = 0;
1146 Standard_Boolean isFirst = Standard_True;
1147 //create Bounding boxes for each wire
1148 for ( i = 1; i <= nb; i ++) {
1149 TopoDS_Shape aShape = ws.Value(i);
1150 TopoDS_Wire aWire = TopoDS::Wire (aShape);
1151 Bnd_Box2d aBox;
1152 Standard_Real cf,cl;
1153 TopoDS_Iterator ew (aWire);
1154 for(;ew.More(); ew.Next()) {
1155 TopoDS_Edge ed = TopoDS::Edge (ew.Value());
1156 Handle(Geom2d_Curve) cw = BRep_Tool::CurveOnSurface (ed,myFace,cf,cl);
1157 Geom2dAdaptor_Curve gac;
1158 Standard_Real aFirst = cw->FirstParameter();
1159 Standard_Real aLast = cw->LastParameter();
1160 if(cw->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve)) && (cf < aFirst || cl > aLast)) {
1161 //avoiding problems with segment in Bnd_Box
1162 gac.Load(cw);
1163 }
1164 else
1165 gac.Load(cw,cf,cl);
1166 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),aBox);
1167 }
1168
1169 Standard_Real aXMin, aXMax, aYMin, aYMax;
1170 aBox.Get(aXMin, aYMin, aXMax, aYMax);
1171 if (isFirst) {
1172 isFirst = Standard_False;
1173 uMiddle = (aXMin + aXMax) * 0.5;
1174 vMiddle = (aYMin + aYMax) * 0.5;
1175 }
1176 else {
1177 Standard_Real xShift = 0, yShift = 0;
1178 if ( mySurf->IsUClosed() )
1179 xShift = ShapeAnalysis::AdjustByPeriod ( 0.5*(aXMin + aXMax), uMiddle, uRange );
1180 if ( mySurf->IsVClosed() )
1181 yShift = ShapeAnalysis::AdjustByPeriod ( 0.5*(aYMin + aYMax), vMiddle, vRange ) ;
1182 aBox.Update(aXMin + xShift, aYMin + yShift, aXMax + xShift, aYMax + yShift);
1183 }
1184 aWireBoxes.ChangeValue(i) = aBox;
1185 }
7fd59977 1186
1187 for ( i = 1; i <= nb; i ++) {
1188 TopoDS_Shape asw = ws.Value(i);
1189 TopoDS_Wire aw = TopoDS::Wire (asw);
1ee621b6 1190 Bnd_Box2d aBox1 = aWireBoxes.Value(i);
7fd59977 1191 TopoDS_Shape dummy = myFace.EmptyCopied();
1192 TopoDS_Face af = TopoDS::Face ( dummy );
1193// B.MakeFace (af,mySurf->Surface(),::Precision::Confusion());
1194 af.Orientation ( TopAbs_FORWARD );
1195 B.Add (af,aw);
1196 // PTV OCC945 06.11.2002 files ie_exhaust-A.stp (entities 3782, 3787)
1197 // tolerance is too big. It is seems that to identify placement of 2d point
1198 // it is enough Precision::PConfusion(), cause wea re know that 2d point in TopAbs_ON
1199 // BRepTopAdaptor_FClass2d clas (af,toluv);
1200 Standard_Boolean CheckShift = Standard_True;
1201 BRepTopAdaptor_FClass2d clas (af,::Precision::PConfusion());
1202 TopAbs_State sta = TopAbs_OUT;
1203 TopAbs_State staout = clas.PerformInfinitePoint();
1204 TopTools_ListOfShape IntWires;
1ee621b6 1205 Standard_Integer aWireIt = 0;
7fd59977 1206 for ( Standard_Integer j = 1; j <= nbAll; j ++) {
1ee621b6 1207 aWireIt++;
7fd59977 1208 //if(i==j) continue;
1209 TopoDS_Shape aSh2 = allSubShapes.Value(j);
1210 if(aw == aSh2)
1211 continue;
1212 TopAbs_State stb = TopAbs_UNKNOWN;
1213 if(aSh2.ShapeType() == TopAbs_VERTEX) {
1ee621b6 1214 aWireIt--;
7fd59977 1215 gp_Pnt aP = BRep_Tool::Pnt(TopoDS::Vertex(aSh2));
1216 gp_Pnt2d p2d = mySurf->ValueOfUV(aP,Precision::Confusion());
1217 stb = clas.Perform (p2d,Standard_False);
1218 if(stb == staout && (uclosed || vclosed)) {
1219 gp_Pnt2d p2d1;
1220 if(uclosed) {
1ee621b6 1221 p2d1.SetCoord(p2d.X()+uRange, p2d.Y());
7fd59977 1222 stb = clas.Perform (p2d1,Standard_False);
1223
1224 }
1225 if(stb == staout && vclosed) {
1ee621b6 1226 p2d1.SetCoord(p2d.X(), p2d.Y()+ vRange);
7fd59977 1227 stb = clas.Perform (p2d1,Standard_False);
1228 }
1229 }
1230 }
1231 else if (aSh2.ShapeType() == TopAbs_WIRE) {
1232 CheckShift = Standard_True;
1233 TopoDS_Wire bw = TopoDS::Wire (aSh2);
1ee621b6 1234 //Standard_Integer numin =0;
1235 Bnd_Box2d aBox2 = aWireBoxes.Value(aWireIt);
1236 if (aBox2.IsOut(aBox1))
1237 continue;
1238
7fd59977 1239 TopoDS_Iterator ew (bw);
1240 for(;ew.More(); ew.Next()) {
1241 TopoDS_Edge ed = TopoDS::Edge (ew.Value());
1242 Standard_Real cf,cl;
1243 Handle(Geom2d_Curve) cw = BRep_Tool::CurveOnSurface (ed,myFace,cf,cl);
1244 if (cw.IsNull()) continue;
1245 gp_Pnt2d unp = cw->Value ((cf+cl)/2.);
1246 TopAbs_State ste = clas.Perform (unp,Standard_False);
1247 if( ste==TopAbs_OUT || ste==TopAbs_IN ) {
1248 if(stb==TopAbs_UNKNOWN) {
1249 stb = ste;
1250 }
1251 else {
1252 if(!(stb==ste)) {
1253 sta = TopAbs_UNKNOWN;
1254 SI.Bind(aw,0);
1255 j=nb;
1256 break;
1257 }
1258 }
1259 }
1260
1261 Standard_Boolean found = Standard_False;
1262 gp_Pnt2d unp1;
1263 if( stb == staout && CheckShift ) {
1264 CheckShift = Standard_False;
1265 if(uclosed) {
1ee621b6 1266 unp1.SetCoord(unp.X()+uRange, unp.Y());
7fd59977 1267 found = (staout != clas.Perform (unp1,Standard_False));
1268 if(!found) {
1ee621b6 1269 unp1.SetX(unp.X()-uRange);
7fd59977 1270 found = (staout != clas.Perform (unp1,Standard_False));
1271 }
1272 }
1273 if(vclosed&&!found) {
1ee621b6 1274 unp1.SetCoord(unp.X(), unp.Y()+vRange);
7fd59977 1275 found = (staout != clas.Perform (unp1,Standard_False));
1276 if(!found) {
1ee621b6 1277 unp1.SetY(unp.Y()-vRange);
7fd59977 1278 found = (staout != clas.Perform (unp1,Standard_False));
1279 }
1280 }
94f71cad 1281 // Additional check of diagonal steps for toroidal surfaces
1282 if (!found && uclosed && vclosed)
1283 {
1284 for (Standard_Real dX = -1.0; dX <= 1.0 && !found; dX += 2.0)
1285 for (Standard_Real dY = -1.0; dY <= 1.0 && !found; dY += 2.0)
1286 {
1287 unp1.SetCoord(unp.X() + uRange * dX, unp.Y() + vRange * dY);
1288 found = (staout != clas.Perform(unp1, Standard_False));
1289 }
1290 }
7fd59977 1291 }
1292 if(found) {
1293 if(stb==TopAbs_IN) stb = TopAbs_OUT;
1294 else stb = TopAbs_IN;
1295 Shift2dWire(bw,myFace,unp1.XY()-unp.XY(), mySurf);
1296 }
1297 }
1298 }
1299 if(stb==staout) {
1300 sta = TopAbs_IN;
1301 }
1302 else {
1303 IntWires.Append(aSh2);
1304 MapIntWires.Add(aSh2);
1305 }
1306 }
1307
1308 if (sta == TopAbs_UNKNOWN) { // ERREUR
999d2599 1309 SendWarning ( aw, Message_Msg ( "FixAdvFace.FixOrientation.MSG11" ) );// Cannot orient wire
7fd59977 1310 }
1311 else {
1312 MW.Bind(aw,IntWires);
1313 if(sta==TopAbs_OUT) {
1314 NbOuts++;
1315 if(staout==TopAbs_IN) {
1316 // wire is OUT but InfinitePoint is IN => need to reverse
1317 ShapeExtend_WireData sewd (aw);
1318 sewd.Reverse(myFace);
1319 ws.SetValue (i,sewd.Wire());
999d2599 1320 SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
7fd59977 1321 aSeqReversed.Append(i);
1322 done = Standard_True;
1323 SI.Bind(ws.Value(i),1);
1324 MapWires.Bind(ws.Value(i),IntWires);
1325 }
1326 else {
1327 SI.Bind(aw,1);
1328 MapWires.Bind(aw,IntWires);
1329 }
1330 }
1331 else {
1332 if(staout==TopAbs_OUT) SI.Bind(aw,2);
1333 else SI.Bind(aw,3);
1334 }
1335 }
1336
1337 }
1338
1339 for(i=1; i<=nb; i++) {
1340 TopoDS_Wire aw = TopoDS::Wire (ws.Value(i));
1341 Standard_Integer tmpi = SI.Find(aw);
1342 if(tmpi>1) {
1343 if(!MapIntWires.Contains(aw)) {
1344 NbOuts++;
1345 const TopTools_ListOfShape& IW = MW.Find(aw);
1346 if(tmpi==3) {
1347 // wire is OUT but InfinitePoint is IN => need to reverse
1348 ShapeExtend_WireData sewd (aw);
1349 sewd.Reverse(myFace);
1350 ws.SetValue (i,sewd.Wire());
999d2599 1351 SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
7fd59977 1352 aSeqReversed.Append(i);
1353 done = Standard_True;
1354 MapWires.Bind(ws.Value(i),IW);
1355 }
1356 else MapWires.Bind(aw,IW);
1357 }
1358 else {
1359 if(tmpi==2) {
1360 // wire is IN but InfinitePoint is OUT => need to reverse
1361 ShapeExtend_WireData sewd (aw);
1362 sewd.Reverse(myFace);
1363 ws.SetValue (i,sewd.Wire());
999d2599 1364 SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
7fd59977 1365 aSeqReversed.Append(i);
1366 done = Standard_True;
1367 }
1368 }
1369 }
1370 }
1371
1372 }
1373
1374 //done = (done && (nb ==1 || (isAddNaturalBounds || (!isAddNaturalBounds && nbInternal <nb))));
1375 if(isAddNaturalBounds && nb == aSeqReversed.Length())
1376 done = Standard_False;
1377 else
1378 done = (done && (nb ==1 || (isAddNaturalBounds || (!isAddNaturalBounds && nbInternal <nb))));
1379 // Faut-il reconstruire ? si myRebil est mis
1380 if ( done ) {
1381 TopoDS_Shape S = myFace.EmptyCopied();
1382 S.Orientation ( TopAbs_FORWARD );
1383 Standard_Integer i = 1;
1384 for ( ; i <= nb; i++ )
1385 B.Add ( S, ws.Value(i) );
1386
1387 if(nb < nbAll) {
1388 for( i =1; i <= nbAll;i++) {
1389 TopoDS_Shape aS2 = allSubShapes.Value(i);
1390 if(aS2.ShapeType() != TopAbs_WIRE ||
1391 (aS2.Orientation() != TopAbs_FORWARD && aS2.Orientation() != TopAbs_REVERSED))
1392 B.Add ( S,aS2);
1393 }
1394 }
1395
1396 if ( ! myFwd ) S.Orientation (TopAbs_REVERSED);
1397 if ( ! Context().IsNull() ) Context()->Replace ( myFace, S );
1398 myFace = TopoDS::Face ( S );
1399 BRepTools::Update(myFace);
1400 Standard_Integer k =1;
999d2599
D
1401 for( ; k <= aSeqReversed.Length(); k++ )
1402 {
0797d9d3 1403#ifdef OCCT_DEBUG
999d2599 1404 cout<<"Wire no "<<aSeqReversed.Value(k)<<" of "<<nb<<" reversed"<<endl; // mise au point !
7fd59977 1405#endif
1406 }
1407
1408 }
1409 return done;
1410}
1411
1412
1413//=======================================================================
1414//function : CheckWire
1415//purpose : auxilary for FixMissingSeam
1416//=======================================================================
1417//:i7 abv 18 Sep 98: ProSTEP TR9 r0501-ug.stp: algorithm of fixing missing seam changed
1418// test whether the wire is opened on period of periodical surface
1419static Standard_Boolean CheckWire (const TopoDS_Wire &wire,
1420 const TopoDS_Face &face,
1421 const Standard_Real dU,
1422 const Standard_Real dV,
1423 Standard_Integer &isuopen,
1424 Standard_Integer &isvopen,
1425 Standard_Boolean &isDeg)
1426{
1427 gp_XY vec;
1428 vec.SetX(0);
1429 vec.SetY(0);
1430 ShapeAnalysis_Edge sae;
59495dbe 1431
1432 isuopen = isvopen = 0;
7fd59977 1433 isDeg = Standard_True;
1434 for ( TopoDS_Iterator ed(wire); ed.More(); ed.Next() ) {
1435 TopoDS_Edge edge = TopoDS::Edge ( ed.Value() );
1436 if ( ! BRep_Tool::Degenerated ( edge ) ) isDeg = Standard_False;
1437 Handle(Geom2d_Curve) c2d;
1438 Standard_Real f, l;
1439 if ( ! sae.PCurve ( edge, face, c2d, f, l, Standard_True ) )
1440 return Standard_False;
1441 vec += c2d->Value(l).XY() - c2d->Value(f).XY();
1442 }
59495dbe 1443
1444 Standard_Real aDelta = Abs(vec.X())-dU;
1445 if(Abs(aDelta) < 0.1*dU)
1446 {
1447 if(vec.X() > 0.0)
1448 {
1449 isuopen = 1;
1450 }
1451 else
1452 {
1453 isuopen = -1;
1454 }
1455 }
1456 else
1457 {
1458 isuopen = 0;
1459 }
1460
1461 aDelta = Abs(vec.Y())-dV;
1462 if(Abs(aDelta) < 0.1*dV)
1463 {
1464 if(vec.Y() > 0.0)
1465 {
1466 isvopen = 1;
1467 }
1468 else
1469 {
1470 isvopen = -1;
1471 }
1472 }
1473 else
1474 {
1475 isvopen = 0;
1476 }
1477
7fd59977 1478 return isuopen || isvopen;
1479}
1480
7fd59977 1481//=======================================================================
1482//function : FixMissingSeam
1483//purpose :
1484//=======================================================================
7fd59977 1485Standard_Boolean ShapeFix_Face::FixMissingSeam()
1486{
1487 Standard_Boolean uclosed = mySurf->IsUClosed();
1488 Standard_Boolean vclosed = mySurf->IsVClosed();
1489
1490 if ( ! uclosed && ! vclosed ) return Standard_False;
1491
1492 if ( ! Context().IsNull() ) {
1493 TopoDS_Shape S = Context()->Apply ( myFace );
1494 myFace = TopoDS::Face ( S );
1495 }
1496
1497 //%pdn: surface should be made periodic before (see ShapeCustom_Surface)!
1498 if (mySurf->Surface()->IsKind(STANDARD_TYPE (Geom_BSplineSurface))) {
1499 Handle (Geom_BSplineSurface) BSpl = Handle (Geom_BSplineSurface)::DownCast (mySurf->Surface());
1500 if (!BSpl->IsUPeriodic() && !BSpl->IsVPeriodic())
1501 return Standard_False;
1502 }
1503
1504 Standard_Real URange, VRange, SUF, SUL, SVF, SVL;
1505 mySurf->Bounds ( SUF, SUL, SVF, SVL );
1506 Standard_Real fU1,fU2,fV1,fV2;
1507 BRepTools::UVBounds(myFace,fU1,fU2,fV1,fV2);
1508
1509 //pdn OCC55 fix to faces without the wires to avoid identical first and last parameters
1510 if ( ::Precision::IsInfinite ( SUF ) || ::Precision::IsInfinite ( SUL ) ) {
1511 if ( ::Precision::IsInfinite ( SUF ) ) SUF = fU1;
1512 if ( ::Precision::IsInfinite ( SUL ) ) SUL = fU2;
eafb234b 1513 if(Abs(SUL-SUF) < ::Precision::PConfusion()) {
7fd59977 1514 if ( ::Precision::IsInfinite ( SUF ) ) SUF-=1000.;
1515 else SUL+=1000.;
eafb234b 1516 }
7fd59977 1517 }
1518 if ( ::Precision::IsInfinite ( SVF ) || ::Precision::IsInfinite ( SVL ) ) {
1519 if ( ::Precision::IsInfinite ( SVF ) ) SVF = fV1;
1520 if ( ::Precision::IsInfinite ( SVL ) ) SVL = fV2;
eafb234b 1521 if(Abs(SVL-SVF) < ::Precision::PConfusion()) {
7fd59977 1522 if ( ::Precision::IsInfinite ( SVF ) ) SVF-=1000.;
1523 else SVL+=1000.;
eafb234b 1524 }
7fd59977 1525 }
1526
59495dbe 1527 URange = Min(Abs (SUL - SUF), Precision::Infinite());
1528 VRange = Min(Abs(SVL - SVF), Precision::Infinite());
7fd59977 1529// Standard_Real UTol = 0.2 * URange, VTol = 0.2 * VRange;
1530 Standard_Integer ismodeu = 0, ismodev = 0; //szv#4:S4163:12Mar99 was Boolean
1531 Standard_Integer isdeg1=0, isdeg2=0;
1532
1533 TopTools_SequenceOfShape ws;
1534 TopTools_SequenceOfShape aSeqNonManif;
1535 for ( TopoDS_Iterator wi(myFace,Standard_False); wi.More(); wi.Next() ) {
1536 if(wi.Value().ShapeType() != TopAbs_WIRE ||
1537 (wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED)) {
1538 aSeqNonManif.Append(wi.Value());
1539 continue;
1540 }
1541 ws.Append ( wi.Value() );
1542 }
1543
1544 TopoDS_Wire w1, w2;
1545 Standard_Integer i;
1546 for ( i=1; i <= ws.Length(); i++ ) {
1547 TopoDS_Wire wire = TopoDS::Wire ( ws.Value(i) );
1548 Standard_Integer isuopen, isvopen;
1549 Standard_Boolean isdeg;
1550 if ( ! CheckWire ( wire, myFace, URange, VRange, isuopen, isvopen, isdeg ) )
1551 continue;
1552 if ( w1.IsNull() ) { w1 = wire; ismodeu = isuopen; ismodev = isvopen; isdeg1 = isdeg ? i : 0; }
1553 else if ( w2.IsNull() ) {
1554 if ( ismodeu == -isuopen && ismodev == -isvopen ) { w2 = wire; isdeg2 = isdeg ? i : 0; }
1555 else if ( ismodeu == isuopen && ismodev == isvopen ) {
1556 w2 = wire;
1557 isdeg2 = isdeg;
1558 //:abv 29.08.01: If wires are contraversal, reverse one of them
1559 // If first one is single degenerated edge, reverse it; else second
1560 if ( isdeg1 ) {
1561 w1.Reverse();
1562 ismodeu = -ismodeu;
1563 ismodev = -ismodev;
1564 }
1565 else {
1566 w2.Reverse();
0797d9d3 1567#ifdef OCCT_DEBUG
7fd59977 1568 if ( ! isdeg2 ) cout << "Warning: ShapeFix_Face::FixMissingSeam(): wire reversed" << endl;
1569#endif
1570 }
1571 }
0797d9d3 1572#ifdef OCCT_DEBUG
7fd59977 1573 else cout << "Warning: ShapeFix_Face::FixMissingSeam(): incompatible open wires" << endl;
1574#endif
1575 }
1576// else return Standard_False; // abort
1577 else {
0797d9d3 1578#ifdef OCCT_DEBUG
7fd59977 1579 cout << "Warning: ShapeFix_Face::FixMissingSeam(): more than two open wires detected!" << endl;
1580#endif
1581 //:abv 30.08.09: if more than one open wires and more than two of them are
1582 // completely degenerated, remove any of them
1583 if ( isdeg || isdeg1 || isdeg2 ) {
1584 ws.Remove ( isdeg ? i : isdeg2 ? isdeg2 : isdeg1 );
1585 w1.Nullify();
1586 w2.Nullify();
1587 i = 0;
0797d9d3 1588#ifdef OCCT_DEBUG
7fd59977 1589 cout << "Warning: ShapeFix_Face::FixMissingSeam(): open degenerated wire removed" << endl;
1590#endif
1591 continue;
1592 }
1593 }
1594 }
1595
1596 BRep_Builder B;
1597 if ( w1.IsNull() ) return Standard_False;
16c7b642 1598 else if ( w2.IsNull()) {
1599 // For spheres and BSpline cone-like surfaces(bug 24055):
1600 // If only one of wires limiting face on surface is open in 2d,
1601 // this may means that degenerated edge should be added, and
7fd59977 1602 // then usual procedure applied
16c7b642 1603 gp_Pnt2d p;
1604 gp_Dir2d d;
1605 Standard_Real aRange;
1606
7fd59977 1607 if ( ismodeu && mySurf->Surface()->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) ) {
16c7b642 1608 p.SetCoord ( ( ismodeu < 0 ? 0. : 2.*M_PI ), ismodeu * 0.5 * M_PI );
1609 Standard_Real aXCoord = -ismodeu;
1610 d.SetCoord ( aXCoord, 0.);
1611 aRange = 2.*M_PI;
1612 }
1613 else if ( ismodev && mySurf->Surface()->IsKind(STANDARD_TYPE(Geom_BSplineSurface))) {
1614 Standard_Real uCoord;
1615 if (mySurf->Value(SUF, SVF).Distance(mySurf->Value(SUF, (SVF + SVL) / 2)) < ::Precision::Confusion())
1616 uCoord = SUF;
1617 else if (mySurf->Value(SUL, SVF).Distance(mySurf->Value(SUL, (SVF + SVL) / 2)) < ::Precision::Confusion())
1618 uCoord = SUL;
1619 else return Standard_False;
1620
1621 p.SetCoord ( uCoord, ( ismodev < 0 ? 0. : VRange ) );
1622 d.SetCoord ( 0., -ismodev);
1623 aRange = VRange;
1624 }
1625 else if ( ismodeu && mySurf->Surface()->IsKind(STANDARD_TYPE(Geom_BSplineSurface))) {
1626 Standard_Real vCoord;
1627 if (mySurf->Value(SUF, SVF).Distance(mySurf->Value((SUF + SUL) / 2, SVF)) < ::Precision::Confusion())
1628 vCoord = SVF;
1629 else if (mySurf->Value(SUL, SVL).Distance(mySurf->Value((SUF + SUL) / 2, SVL)) < ::Precision::Confusion())
1630 vCoord = SVL;
1631 else return Standard_False;
1632
1633 p.SetCoord ( ( ismodeu < 0 ? 0. : URange ), vCoord );
1634 Standard_Real aXCoord = -ismodeu;
1635 d.SetCoord ( aXCoord, 0.);
1636 aRange = URange;
7fd59977 1637 }
1638 else return Standard_False;
16c7b642 1639
1640 Handle(Geom2d_Line) line = new Geom2d_Line ( p, d );
1641 TopoDS_Edge edge;
1642 B.MakeEdge ( edge );
1643 B.Degenerated ( edge, Standard_True );
1644 B.UpdateEdge ( edge, line, myFace, ::Precision::Confusion() );
1645 B.Range ( edge, myFace, 0., aRange );
1646 TopoDS_Vertex V;
1647 B.MakeVertex ( V, mySurf->Value ( p.X(), p.Y() ), ::Precision::Confusion() );
1648 V.Orientation(TopAbs_FORWARD);
1649 B.Add(edge,V);
1650 V.Orientation(TopAbs_REVERSED);
1651 B.Add(edge,V);
1652 B.MakeWire ( w2 );
1653 B.Add ( w2, edge );
1654 ws.Append ( w2 );
7fd59977 1655 }
1656
0d3d226e 1657 // Check consistency of orientations of the two wires that need to be connected by a seam
1658 Standard_Real uf=SUF, vf=SVF;
1659 Standard_Integer coord = ( ismodeu ? 1 : 0 );
1660 Standard_Integer isneg = ( ismodeu ? ismodeu : -ismodev );
1661 Standard_Real period = ( ismodeu ? URange : VRange );
1662 TopoDS_Shape S;
1663 Standard_Real m1[2][2], m2[2][2];
1664 S = myFace.EmptyCopied();
1665 B.Add ( S, w1 );
1666 ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m1[0][0], m1[0][1], m1[1][0], m1[1][1]);
1667 S = myFace.EmptyCopied();
1668 B.Add ( S, w2 );
1669 ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m2[0][0], m2[0][1], m2[1][0], m2[1][1]);
1670
1671 // For the case when surface is closed only in one direction it is necesary to check
1672 // validity of orientation of the open wires in parametric space.
1673 // In case of U closed surface wire with minimal V coordinate should be directed in positive direction by U
1674 // In case of V closed surface wire with minimal U coordinate should be directed in negative direction by V
1675 if (!vclosed || !uclosed)
1676 {
1677 Standard_Real deltaOther = 0.5 * (m2[coord][0] + m2[coord][1]) - 0.5 * (m1[coord][0] + m1[coord][1]);
1678 if (deltaOther * isneg < 0)
1679 {
1680 w1.Reverse();
1681 w2.Reverse();
1682 }
1683 }
1684
7fd59977 1685 // sort original wires
1686 Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
1687 sfw->SetFace ( myFace );
1688 sfw->SetPrecision ( Precision() );
7fd59977 1689 Handle(ShapeExtend_WireData) wd1 = new ShapeExtend_WireData ( w1 );
1690 Handle(ShapeExtend_WireData) wd2 = new ShapeExtend_WireData ( w2 );
0d3d226e 1691 sfw->Load ( wd1 );
1692 sfw->FixReorder();
7fd59977 1693 sfw->Load ( wd2 );
1694 sfw->FixReorder();
0d3d226e 1695 TopoDS_Wire w11 = wd1->Wire();
1696 TopoDS_Wire w21 = wd2->Wire();
1697
7fd59977 1698 //:abv 29.08.01: reconstruct face taking into account reversing
1699 TopoDS_Shape dummy = myFace.EmptyCopied();
1700 TopoDS_Face tmpF = TopoDS::Face ( dummy );
1701 tmpF.Orientation ( TopAbs_FORWARD );
1702 for ( i=1; i <= ws.Length(); i++ ) {
1703 TopoDS_Wire wire = TopoDS::Wire ( ws.Value(i) );
0d3d226e 1704 if ( wire.IsSame ( w1 ) ) wire = w11;
1705 else if ( wire.IsSame ( w2 ) ) wire = w21;
1706 else
1707 {
1708 // other wires (not boundary) are considered as holes; make sure to have them oriented accordingly
1709 TopoDS_Shape curface = tmpF.EmptyCopied();
1710 B.Add(curface,wire);
1711 curface.Orientation ( myFace.Orientation() );
1712 if( ShapeAnalysis::IsOuterBound(TopoDS::Face(curface)))
1713 wire.Reverse();
1714 }
7fd59977 1715 B.Add ( tmpF, wire );
1716 }
0d3d226e 1717
7fd59977 1718 tmpF.Orientation ( myFace.Orientation() );
0d3d226e 1719
7fd59977 1720 // A special kind of FixShifted is necessary for torus-like
1721 // surfaces to adjust wires by period ALONG the missing SEAM direction
1722 // tr9_r0501-ug.stp #187640
1723 if ( uclosed && vclosed ) {
7fd59977 1724 Standard_Real shiftw2 =
1725 ShapeAnalysis::AdjustByPeriod ( 0.5 * ( m2[coord][0] + m2[coord][1] ),
1726 0.5 * ( m1[coord][0] + m1[coord][1] +
1727 isneg * ( period + ::Precision::PConfusion() ) ),
1728 period );
1729 m1[coord][0] = Min ( m1[coord][0], m2[coord][0] + shiftw2 );
1730 m1[coord][1] = Max ( m1[coord][1], m2[coord][1] + shiftw2 );
1731 for ( TopoDS_Iterator it(tmpF,Standard_False); it.More(); it.Next() ) {
1732 if(it.Value().ShapeType() != TopAbs_WIRE)
1733 continue;
1734 TopoDS_Wire w = TopoDS::Wire ( it.Value() );
0d3d226e 1735 if ( w == w11 ) continue;
7fd59977 1736 Standard_Real shift;
0d3d226e 1737 if ( w == w21 ) shift = shiftw2;
1738
7fd59977 1739 else {
1740 S = tmpF.EmptyCopied();
1741 B.Add ( S, w );
1742 ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m2[0][0], m2[0][1], m2[1][0], m2[1][1]);
1743 shift = ShapeAnalysis::AdjustByPeriod ( 0.5 * ( m2[coord][0] + m2[coord][1] ),
1744 0.5 * ( m1[coord][0] + m1[coord][1] ), period );
1745 }
1746 if ( shift != 0. ) {
1747 gp_Vec2d V(0.,0.);
1748 V.SetCoord ( coord+1, shift );
1749 ShapeAnalysis_Edge sae;
1750 for ( TopoDS_Iterator iw(w); iw.More(); iw.Next() ) {
1751 TopoDS_Edge E = TopoDS::Edge ( iw.Value() );
1752 Handle(Geom2d_Curve) C;
1753 Standard_Real a, b;
1754 if ( ! sae.PCurve ( E, tmpF, C, a, b ) ) continue;
1755 C->Translate ( V );
1756 }
1757 }
1758 }
1759 // abv 05 Feb 02: OCC34
1760 // by the way, select proper split place by V to avoid extra intersections
1761 if ( m1[coord][1] - m1[coord][0] <= period ) {
1762 Standard_Real other = 0.5 * ( m1[coord][0] + m1[coord][1] - period );
1763 if ( ismodeu ) vf = other;
1764 else uf = other;
1765 }
1766 }
1767
1768 // find the best place by u and v to insert a seam
1769 // (so as to minimize splitting edges as possible)
1770 ShapeAnalysis_Edge sae;
1771 Standard_Integer foundU=0, foundV=0;
1772 Standard_Integer nb1 = wd1->NbEdges();
1773 Standard_Integer nb2 = wd2->NbEdges();
1774 for ( Standard_Integer i1 = 1; i1 <= nb1 + nb2; i1++ ) {
1775 TopoDS_Edge edge1 = ( i1 <= nb1 ? wd1->Edge ( i1 ) : wd2->Edge ( i1-nb1 ) );
1776 Handle(Geom2d_Curve) c2d;
1777 Standard_Real f, l;
1778 if ( ! sae.PCurve ( edge1, tmpF, c2d, f, l, Standard_True ) ) return Standard_False;
1779 gp_Pnt2d pos1 = c2d->Value(l).XY();
1780 // the best place is end of edge which is nearest to 0
1781 Standard_Boolean skipU = ! uclosed;
1782 if ( uclosed && ismodeu ) {
1783 pos1.SetX ( pos1.X() + ShapeAnalysis::AdjustByPeriod ( pos1.X(), SUF, URange ) );
1784 if ( foundU ==2 && Abs ( pos1.X() ) > Abs(uf) ) skipU = Standard_True;
1785 else if ( ! foundU || ( foundU ==1 && Abs ( pos1.X() ) < Abs(uf) ) ) {
1786 foundU = 1;
1787 uf = pos1.X();
1788 }
1789 }
1790 Standard_Boolean skipV = ! vclosed;
1791 if ( vclosed && ! ismodeu ) {
16c7b642 1792 pos1.SetY ( pos1.Y() + ShapeAnalysis::AdjustByPeriod ( pos1.Y(), SVF, VRange ) );
7fd59977 1793 if ( foundV ==2 && Abs ( pos1.Y() ) > Abs(vf) ) skipV = Standard_True;
1794 else if ( ! foundV || ( foundV ==1 && Abs ( pos1.Y() ) < Abs(vf) ) ) {
1795 foundV = 1;
1796 vf = pos1.Y();
1797 }
1798 }
eafb234b 1799 if ( skipU && skipV ) {
7fd59977 1800 if ( i1 <= nb1 ) continue;
1801 else break;
eafb234b 1802 }
7fd59977 1803 // or yet better - if it is end of some edges on both wires
1804 for ( Standard_Integer i2 = 1; i1 <= nb1 && i2 <= nb2; i2++ ) {
1805 TopoDS_Edge edge2 = wd2->Edge ( i2 );
1806 if ( ! sae.PCurve ( edge2, tmpF, c2d, f, l, Standard_True ) ) return Standard_False;
1807 gp_Pnt2d pos2 = c2d->Value(f).XY();
1808 if ( uclosed && ismodeu ) {
1809 pos2.SetX ( pos2.X() + ShapeAnalysis::AdjustByPeriod ( pos2.X(), pos1.X(), URange ) );
1810 if ( Abs ( pos2.X() - pos1.X() ) < ::Precision::PConfusion() &&
1811 ( foundU != 2 || Abs ( pos1.X() ) < Abs ( uf ) ) ) {
1812 foundU = 2;
1813 uf = pos1.X();
1814 }
1815 }
1816 if ( vclosed && ! ismodeu ) {
1817 pos2.SetY ( pos2.Y() + ShapeAnalysis::AdjustByPeriod ( pos2.Y(), pos1.Y(), VRange ) );
1818 if ( Abs ( pos2.Y() - pos1.Y() ) < ::Precision::PConfusion() &&
1819 ( foundV != 2 || Abs ( pos1.Y() ) < Abs ( vf ) ) ) {
1820 foundV = 2;
1821 vf = pos1.Y();
1822 }
1823 }
1824 }
1825 }
1826
1827 //pdn fixing RTS on offsets
1828 if ( uf < SUF || uf > SUL )
1829 uf+=ShapeAnalysis::AdjustToPeriod(uf,SUF,SUF+URange);
1830 if ( vf < SVF || vf > SVL )
1831 vf+=ShapeAnalysis::AdjustToPeriod(vf,SVF,SVF+VRange);
1832
1833 // Create fictive grid and call ComposeShell to insert a seam
1834 Handle(Geom_RectangularTrimmedSurface) RTS =
1835 new Geom_RectangularTrimmedSurface ( mySurf->Surface(), uf, uf+URange, vf, vf+VRange );
1836 Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 );
1837 grid->SetValue ( 1, 1, RTS ); //mySurf->Surface() );
1838 Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid );
1839 TopLoc_Location L;
1840
1841 //addition non-manifold topology
1842 Standard_Integer j=1;
1843 for( ; j <= aSeqNonManif.Length(); j++)
1844 B.Add(tmpF,aSeqNonManif.Value(j));
1845
1846 ShapeFix_ComposeShell CompShell;
1847// TopoDS_Face tmpF = myFace;
1848// tmpF.Orientation(TopAbs_FORWARD);
1849 CompShell.Init ( G, L, tmpF, ::Precision::Confusion() );//myPrecision
1850 if ( Context().IsNull() ) SetContext ( new ShapeBuild_ReShape );
1851 CompShell.ClosedMode() = Standard_True;
1852 CompShell.SetContext( Context() );
1853 CompShell.SetMaxTolerance(MaxTolerance());
1854 CompShell.Perform();
1855
1856 // abv 03.07.00: CAX-IF TRJ4: trj4_k1_goe-tu-214.stp: #785: reset mySurf
1857 mySurf = new ShapeAnalysis_Surface ( RTS );
1858
1859 myResult = CompShell.Result();
1860// if ( myFace.Orientation() == TopAbs_REVERSED ) res.Reverse();
1861 Context()->Replace ( myFace, myResult );
1862 for (TopExp_Explorer exp ( myResult, TopAbs_FACE ); exp.More(); exp.Next() ) {
1863 myFace = TopoDS::Face ( exp.Current() );
1864 BRepTools::Update(myFace); //:p4
1865 }
1866
999d2599 1867 SendWarning ( Message_Msg ( "FixAdvFace.FixMissingSeam.MSG0" ) );// Missing seam-edge added
7fd59977 1868 return Standard_True;
1869}
1870
1871//=======================================================================
1872//function : FixSmallAreaWire
1873//purpose :
1874//=======================================================================
7fd59977 1875//%14 pdn 24.02.99 PRO10109, USA60293 fix wire on face with small area.
56a9db93 1876Standard_Boolean ShapeFix_Face::FixSmallAreaWire(const Standard_Boolean theIsRemoveSmallFace)
7fd59977 1877{
56a9db93 1878 if ( !Context().IsNull() )
1879 {
1880 TopoDS_Shape aShape = Context()->Apply(myFace);
1881 myFace = TopoDS::Face(aShape);
7fd59977 1882 }
56a9db93 1883
1884 BRep_Builder aBuilder;
7fd59977 1885 Standard_Integer nbRemoved = 0, nbWires = 0;
56a9db93 1886
1887 TopoDS_Shape anEmptyCopy = myFace.EmptyCopied();
1888 TopoDS_Face aFace = TopoDS::Face(anEmptyCopy);
1889
1890 const TopoDS_Wire anOuterWire = BRepTools::OuterWire(myFace);
1891 const Standard_Real aTolerance3d = ShapeFix_Root::Precision();
1892 for (TopoDS_Iterator aWIt(myFace, Standard_False); aWIt.More(); aWIt.Next())
1893 {
1894 const TopoDS_Shape& aShape = aWIt.Value();
1895 if ( aShape.ShapeType() != TopAbs_WIRE &&
1896 aShape.Orientation() != TopAbs_FORWARD &&
1897 aShape.Orientation() != TopAbs_REVERSED )
999d2599 1898 {
56a9db93 1899 continue;
1900 }
1901
1902 const TopoDS_Wire& aWire = TopoDS::Wire(aShape);
1903 const Standard_Boolean isOuterWire = anOuterWire.IsEqual(aWire);
1904 Handle(ShapeAnalysis_Wire) anAnalyzer = new ShapeAnalysis_Wire(aWire, myFace, aTolerance3d);
1905 if ( anAnalyzer->CheckSmallArea(aWire, isOuterWire) )
1906 {
1907 // Null area wire detected, wire skipped
1908 SendWarning(aWire, Message_Msg("FixAdvFace.FixSmallAreaWire.MSG0"));
1909 ++nbRemoved;
999d2599
D
1910 }
1911 else
1912 {
56a9db93 1913 aBuilder.Add(aFace, aWire);
1914 ++nbWires;
7fd59977 1915 }
1916 }
56a9db93 1917
1918 if ( nbRemoved <= 0 )
1919 return Standard_False;
1920
1921 if ( nbWires <= 0 )
1922 {
0797d9d3 1923#ifdef OCCT_DEBUG
7fd59977 1924 cout << "Warning: ShapeFix_Face: All wires on a face have small area; left untouched" << endl;
1925#endif
56a9db93 1926 if ( theIsRemoveSmallFace && !Context().IsNull() )
1927 Context()->Remove(myFace);
1928
7fd59977 1929 return Standard_False;
1930 }
0797d9d3 1931#ifdef OCCT_DEBUG
7fd59977 1932 cout << "Warning: ShapeFix_Face: " << nbRemoved << " small area wire(s) removed" << endl;
1933#endif
56a9db93 1934 if ( !Context().IsNull() )
1935 Context()->Replace(myFace, aFace);
1936
1937 myFace = aFace;
7fd59977 1938 return Standard_True;
1939}
1940//=======================================================================
1941//function : FixLoopWire
1942//purpose :
1943//=======================================================================
1944static void FindNext(const TopoDS_Shape& aVert,
1945 const TopoDS_Shape& ainitEdge,
1946 TopTools_IndexedMapOfShape& aMapVertices,
1947 TopTools_DataMapOfShapeListOfShape& aMapVertexEdges,
1948 const TopTools_MapOfShape& aMapSmallEdges,
1949 const TopTools_MapOfShape& aMapSeemEdges,
1950 TopTools_MapOfShape& aMapEdges,
1951 Handle(ShapeExtend_WireData)& aWireData)
1952{
1953 TopoDS_Iterator aItV(ainitEdge);
1954 TopoDS_Shape anextVert = aVert;
1955 Standard_Boolean isFind = Standard_False;
1956 for( ; aItV.More() && !isFind; aItV.Next())
1957 {
1958 if(!aItV.Value().IsSame(aVert) ) {
1959 isFind = Standard_True;
1960 anextVert = aItV.Value();
1961
1962 }
1963 }
1964
1965 if(!isFind && !aMapSmallEdges.Contains(ainitEdge))
1966 return;
1967 if(isFind && aMapVertices.Contains(anextVert))
1968 return;
1969
1970 const TopTools_ListOfShape& aledges = aMapVertexEdges.Find(anextVert);
1971 TopTools_ListIteratorOfListOfShape liter(aledges);
1972 isFind = Standard_False;
1973 TopoDS_Shape anextEdge;
1974 for( ; liter.More() && !isFind; liter.Next())
1975 {
1976 if(!aMapEdges.Contains(liter.Value()) && !liter.Value().IsSame(ainitEdge)) {
1977 anextEdge = liter.Value();
1978 aWireData->Add(anextEdge);
1979 if(aMapSeemEdges.Contains(anextEdge))
1980 aWireData->Add(anextEdge.Reversed());
1981 isFind = Standard_True;
1982 aMapEdges.Add(anextEdge);
1983 FindNext(anextVert,anextEdge,aMapVertices,aMapVertexEdges,aMapSmallEdges,aMapSeemEdges,aMapEdges,aWireData);
1984 }
1985 }
1986 return;
1987}
1988
1989static Standard_Boolean isClosed2D(const TopoDS_Face& aFace,const TopoDS_Wire& aWire)
1990{
1991 Standard_Boolean isClosed = Standard_True;
1992 Handle(ShapeAnalysis_Wire) asaw = new ShapeAnalysis_Wire(aWire,aFace,Precision::Confusion());
1993 for (Standard_Integer i = 1; i <= asaw->NbEdges() && isClosed; i++) {
1994 TopoDS_Edge edge1 = asaw->WireData()->Edge(i);
1995 //checking that wire is closed in 2D space with tolerance of vertex.
1996 ShapeAnalysis_Edge sae;
1997 TopoDS_Vertex v1 = sae.FirstVertex(edge1);
1998 asaw->SetPrecision(BRep_Tool::Tolerance(v1));
1999 asaw->CheckGap2d(i);
2000 isClosed = (asaw->LastCheckStatus(ShapeExtend_OK));
2001
2002 }
2003 return isClosed;
2004}
2005
2006//=======================================================================
2007//function : FixLoopWire
2008//purpose :
2009//=======================================================================
2010
2011Standard_Boolean ShapeFix_Face::FixLoopWire(TopTools_SequenceOfShape& aResWires)
2012{
2013 TopTools_IndexedMapOfShape aMapVertices;
2014 TopTools_DataMapOfShapeListOfShape aMapVertexEdges;
2015 TopTools_MapOfShape aMapSmallEdges;
2016 TopTools_MapOfShape aMapSeemEdges;
2017 if(!FixWireTool()->Analyzer()->CheckLoop(aMapVertices, aMapVertexEdges,aMapSmallEdges,aMapSeemEdges))
2018 return Standard_False;
2019
2020
2021 TopTools_MapOfShape aMapEdges;
2022 TopTools_SequenceOfShape aSeqWires;
2023
2024 //collecting wires from common vertex belonging more than 2 edges
2025 Standard_Integer i =1;
2026 for( ; i <= aMapVertices.Extent(); i++) {
2027 TopoDS_Shape aVert = aMapVertices.FindKey(i);
2028 const TopTools_ListOfShape& aledges = aMapVertexEdges.Find(aVert);
2029 TopTools_ListIteratorOfListOfShape liter(aledges);
2030 for( ; liter.More(); liter.Next())
2031 {
2032 TopoDS_Edge Edge = TopoDS::Edge(liter.Value());
2033 if(aMapEdges.Contains(Edge))
2034 continue;
2035
2036 Handle(ShapeExtend_WireData) aWireData = new ShapeExtend_WireData;
2037 aWireData->Add(Edge);
2038 if(aMapSeemEdges.Contains(Edge))
2039 aWireData->Add(Edge.Reversed());
2040 aMapEdges.Add(Edge);
2041 FindNext(aVert,Edge,aMapVertices,aMapVertexEdges,aMapSmallEdges,aMapSeemEdges,aMapEdges,aWireData);
2042 if(aWireData->NbEdges() ==1 && aMapSmallEdges.Contains(aWireData->Edge(1)))
2043 continue;
2044 TopoDS_Vertex aV1,aV2;
2045 TopoDS_Wire aWire = aWireData->Wire();
2046 TopExp::Vertices(aWire,aV1,aV2);
2047
2048 if(aV1.IsSame(aV2)) {
2049 Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire);
2050 Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire;
2051 asfw->Load(asewd);
2052 asfw->FixReorder();
2053 TopoDS_Wire awire2 = asfw->Wire();
2054 aResWires.Append(awire2);
2055
2056 }
2057 else aSeqWires.Append(aWireData->Wire());
2058 }
2059 }
2060
2061
2062 if(aSeqWires.Length() ==1) {
2063 aResWires.Append(aSeqWires.Value(1));
2064 }
2065 else {
2066 //collecting whole wire from two not closed wires having two common vertices.
2067 for( i =1; i <= aSeqWires.Length(); i++) {
2068 TopoDS_Vertex aV1,aV2;
2069 TopoDS_Wire aWire = TopoDS::Wire(aSeqWires.Value(i));
2070 TopExp::Vertices(aWire,aV1,aV2);
2071 Standard_Integer j = i+1;
2072 for( ; j <= aSeqWires.Length(); j++)
2073 {
2074 TopoDS_Vertex aV21,aV22;
2075 TopoDS_Wire aWire2 = TopoDS::Wire(aSeqWires.Value(j));
2076 TopExp::Vertices(aWire2,aV21,aV22);
2077 if((aV1.IsSame(aV21) || aV1.IsSame(aV22)) && (aV2.IsSame(aV21) || aV2.IsSame(aV22)))
2078 {
2079 Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire);
2080 asewd->Add(aWire2);
2081 Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire;
2082 asfw->Load(asewd);
2083 asfw->FixReorder();
2084 aResWires.Append(asfw->Wire());
2085 aSeqWires.Remove(j--);
2086 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
2087 break;
2088 }
2089
2090 }
2091 if(j <= aSeqWires.Length())
2092 aSeqWires.Remove(i--);
2093
2094 }
2095 if(aSeqWires.Length()<3) {
2096 for( i =1; i <= aSeqWires.Length(); i++)
2097 aResWires.Append(aSeqWires.Value(i));
2098
2099 }
2100 else {
2101 //collecting wires having one common vertex
2102 for( i =1; i <= aSeqWires.Length(); i++) {
2103 TopoDS_Vertex aV1,aV2;
2104 TopoDS_Wire aWire = TopoDS::Wire(aSeqWires.Value(i));
2105 TopExp::Vertices(aWire,aV1,aV2);
2106 Standard_Integer j =i+1;
2107 for( ; j <= aSeqWires.Length(); j++)
2108 {
2109 TopoDS_Vertex aV21,aV22;
2110 TopoDS_Wire aWire2 = TopoDS::Wire(aSeqWires.Value(j));
2111 TopExp::Vertices(aWire2,aV21,aV22);
2112 if((aV1.IsSame(aV21) || aV1.IsSame(aV22)) || (aV2.IsSame(aV21) || aV2.IsSame(aV22)))
2113 {
2114 Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire);
2115 asewd->Add(aWire2);
2116 Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire;
2117 asfw->Load(asewd);
2118 asfw->FixReorder();
2119 aWire = asfw->Wire();
2120 TopExp::Vertices(aWire,aV1,aV2);
2121 aSeqWires.Remove(j--);
2122 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
2123 }
2124 }
2125 aResWires.Append(aWire);
2126
2127 }
2128 }
2129 }
2130 Standard_Boolean isClosed = Standard_True;
2131
2132 //checking that obtained wires is closed in 2D space
2133 if (mySurf->Adaptor3d()->GetType() != GeomAbs_Plane) {
2134
2135 TopoDS_Shape emptyCopied = myFace.EmptyCopied();
2136 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
2137 tmpFace.Orientation ( TopAbs_FORWARD );
2138
2139 for(i =1; i <= aResWires.Length() && isClosed; i++) {
2140 TopoDS_Wire awire = TopoDS::Wire(aResWires.Value(i));
2141 isClosed = isClosed2D(tmpFace,awire);
2142 }
2143 }
2144
2145 Standard_Boolean isDone =(aResWires.Length() && isClosed);
999d2599
D
2146 if(isDone && aResWires.Length() >1)
2147 {
0797d9d3 2148#ifdef OCCT_DEBUG
999d2599 2149 cout<<"Wire was splitted on "<<aResWires.Length()<<" wires"<< endl;
7fd59977 2150#endif
2151 }
2152
2153 return isDone;
2154}
2155
7fd59977 2156//=======================================================================
2157//function : SplitEdge
2158//purpose :
2159//=======================================================================
2160
2161Standard_Boolean ShapeFix_Face::SplitEdge(const Handle(ShapeExtend_WireData)& sewd,
2162 const Standard_Integer num,
2163 const Standard_Real param,
2164 const TopoDS_Vertex& vert,
2165 const Standard_Real preci,
2166 ShapeFix_DataMapOfShapeBox2d& boxes)
2167{
2168 TopoDS_Edge edge = sewd->Edge(num);
2169 TopoDS_Edge newE1, newE2;
2170 ShapeFix_SplitTool aTool;
2171 if(aTool.SplitEdge(edge,param,vert,myFace,newE1,newE2,preci,0.01*preci)) {
2172 // change context
2173 Handle(ShapeExtend_WireData) wd = new ShapeExtend_WireData;
2174 wd->Add(newE1);
2175 wd->Add(newE2);
2176 if(!Context().IsNull()) Context()->Replace( edge, wd->Wire() );
2177 for (TopExp_Explorer exp ( wd->Wire(), TopAbs_EDGE ); exp.More(); exp.Next() ) {
2178 TopoDS_Edge E = TopoDS::Edge ( exp.Current() );
2179 BRepTools::Update(E);
2180 }
2181
2182// for ( Standard_Integer i=1; i <= sewd->NbEdges(); i++ ) {
2183// TopoDS_Edge E = sewd->Edge(i);
2184// TopoDS_Shape S = Context()->Apply ( E );
2185// if ( S == E ) continue;
2186// for ( TopExp_Explorer exp(S,TopAbs_EDGE); exp.More(); exp.Next() )
2187// sewd->Add ( exp.Current(), i++ );
2188// sewd->Remove ( i-- );
2189// }
2190
2191 // change sewd and boxes
2192 sewd->Set(newE1,num);
2193 if(num==sewd->NbEdges())
2194 sewd->Add(newE2);
2195 else
2196 sewd->Add(newE2,num+1);
2197
2198 boxes.UnBind(edge);
2199 TopLoc_Location L;
2200 const Handle(Geom_Surface)& S = BRep_Tool::Surface(myFace,L);
2201 Handle(Geom2d_Curve) c2d;
2202 Standard_Real cf,cl;
2203 ShapeAnalysis_Edge sae;
2204 if(sae.PCurve(newE1,S,L,c2d,cf,cl,Standard_False)) {
2205 Bnd_Box2d box;
2206 Geom2dAdaptor_Curve gac;
2207 Standard_Real aFirst = c2d->FirstParameter();
2208 Standard_Real aLast = c2d->LastParameter();
2209 if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2210 && (cf < aFirst || cl > aLast)) {
2211 //pdn avoiding problems with segment in Bnd_Box
2212 gac.Load(c2d);
2213 }
2214 else
2215 gac.Load(c2d,cf,cl);
2216 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2217 boxes.Bind(newE1,box);
2218 }
2219 if(sae.PCurve(newE2,S,L,c2d,cf,cl,Standard_False)) {
2220 Bnd_Box2d box;
2221 Geom2dAdaptor_Curve gac;
2222 Standard_Real aFirst = c2d->FirstParameter();
2223 Standard_Real aLast = c2d->LastParameter();
2224 if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2225 && (cf < aFirst || cl > aLast)) {
2226 //pdn avoiding problems with segment in Bnd_Box
2227 gac.Load(c2d);
2228 }
2229 else
2230 gac.Load(c2d,cf,cl);
2231 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2232 boxes.Bind(newE2,box);
2233 }
2234 return Standard_True;
2235 }
2236 return Standard_False;
2237}
2238
2239
2240//=======================================================================
2241//function : SplitEdge
2242//purpose :
2243//=======================================================================
2244
2245Standard_Boolean ShapeFix_Face::SplitEdge(const Handle(ShapeExtend_WireData)& sewd,
2246 const Standard_Integer num,
2247 const Standard_Real param1,
2248 const Standard_Real param2,
2249 const TopoDS_Vertex& vert,
2250 const Standard_Real preci,
2251 ShapeFix_DataMapOfShapeBox2d& boxes)
2252{
2253 TopoDS_Edge edge = sewd->Edge(num);
2254 TopoDS_Edge newE1, newE2;
2255 ShapeFix_SplitTool aTool;
2256 if(aTool.SplitEdge(edge,param1,param2,vert,myFace,newE1,newE2,preci,0.01*preci)) {
2257 // change context
2258 Handle(ShapeExtend_WireData) wd = new ShapeExtend_WireData;
2259 wd->Add(newE1);
2260 wd->Add(newE2);
2261 if(!Context().IsNull()) Context()->Replace( edge, wd->Wire() );
2262 for (TopExp_Explorer exp ( wd->Wire(), TopAbs_EDGE ); exp.More(); exp.Next() ) {
2263 TopoDS_Edge E = TopoDS::Edge ( exp.Current() );
2264 BRepTools::Update(E);
2265 }
2266
2267 // change sewd and boxes
2268 sewd->Set(newE1,num);
2269 if(num==sewd->NbEdges())
2270 sewd->Add(newE2);
2271 else
2272 sewd->Add(newE2,num+1);
2273
2274 boxes.UnBind(edge);
2275 TopLoc_Location L;
2276 const Handle(Geom_Surface)& S = BRep_Tool::Surface(myFace,L);
2277 Handle(Geom2d_Curve) c2d;
2278 Standard_Real cf,cl;
2279 ShapeAnalysis_Edge sae;
2280 if(sae.PCurve(newE1,S,L,c2d,cf,cl,Standard_False)) {
2281 Bnd_Box2d box;
2282 Geom2dAdaptor_Curve gac;
2283 Standard_Real aFirst = c2d->FirstParameter();
2284 Standard_Real aLast = c2d->LastParameter();
2285 if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2286 && (cf < aFirst || cl > aLast)) {
2287 //pdn avoiding problems with segment in Bnd_Box
2288 gac.Load(c2d);
2289 }
2290 else
2291 gac.Load(c2d,cf,cl);
2292 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2293 boxes.Bind(newE1,box);
2294 }
2295 if(sae.PCurve(newE2,S,L,c2d,cf,cl,Standard_False)) {
2296 Bnd_Box2d box;
2297 Geom2dAdaptor_Curve gac;
2298 Standard_Real aFirst = c2d->FirstParameter();
2299 Standard_Real aLast = c2d->LastParameter();
2300 if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2301 && (cf < aFirst || cl > aLast)) {
2302 //pdn avoiding problems with segment in Bnd_Box
2303 gac.Load(c2d);
2304 }
2305 else
2306 gac.Load(c2d,cf,cl);
2307 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2308 boxes.Bind(newE2,box);
2309 }
2310 return Standard_True;
2311 }
2312 return Standard_False;
2313}
2314
2315
2316//=======================================================================
2317//function : FixIntersectingWires
2318//purpose :
2319//=======================================================================
2320
2321Standard_Boolean ShapeFix_Face::FixIntersectingWires()
2322{
2323 ShapeFix_IntersectionTool ITool(Context(),Precision(),MaxTolerance());
2324 return ITool.FixIntersectingWires(myFace);
2325}
2326
2327
2328//=======================================================================
2329//function : FixWiresTwoCoincEdges
2330//purpose :
2331//=======================================================================
2332
2333Standard_Boolean ShapeFix_Face::FixWiresTwoCoincEdges()
2334{
2335 if ( ! Context().IsNull() ) {
2336 TopoDS_Shape S = Context()->Apply ( myFace );
2337 myFace = TopoDS::Face ( S );
2338 }
2339
2340 TopAbs_Orientation ori = myFace.Orientation();
2341 TopoDS_Shape emptyCopied = myFace.EmptyCopied();
2342 TopoDS_Face face = TopoDS::Face (emptyCopied);
2343 face.Orientation(TopAbs_FORWARD);
2344 Standard_Integer nbWires = 0;
2345 BRep_Builder B;
2346
2347 for (TopoDS_Iterator it (myFace, Standard_False); it.More(); it.Next()) {
2348 if(it.Value().ShapeType() != TopAbs_WIRE ||
2349 (it.Value().Orientation() != TopAbs_FORWARD && it.Value().Orientation() != TopAbs_REVERSED)) {
2350 continue;
2351 }
2352 nbWires++;
2353 }
2354 if(nbWires<2) return Standard_False;
2355 Standard_Boolean isFixed = Standard_False;
2356 for (TopoDS_Iterator wi (myFace, Standard_False); wi.More(); wi.Next()) {
2357 if(wi.Value().ShapeType() != TopAbs_WIRE ||
2358 (wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED)) {
2359 B.Add(face,wi.Value());
2360 continue;
2361 }
2362 TopoDS_Wire wire = TopoDS::Wire ( wi.Value() );
2363 Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire);
2364 if(sewd->NbEdges()==2) {
2365 TopoDS_Edge E1 = sewd->Edge(1);
2366 TopoDS_Edge E2 = sewd->Edge(2);
2367 E1.Orientation(TopAbs_FORWARD);
2368 E2.Orientation(TopAbs_FORWARD);
2369 if( !(E1==E2) ) {
2370 B.Add(face,wire);
2371 }
2372 else isFixed = Standard_True;
2373 }
2374 else {
2375 B.Add(face,wire);
2376 }
2377 }
2378 if(isFixed) {
2379 face.Orientation(ori);
2380 if ( ! Context().IsNull() ) Context()->Replace ( myFace, face );
2381 myFace = face;
2382 }
2383
2384 return isFixed;
2385}
2386
2387
2388//=======================================================================
2389//function : FixSplitFace
2390//purpose :
2391//=======================================================================
2392
2393Standard_Boolean ShapeFix_Face::FixSplitFace(const TopTools_DataMapOfShapeListOfShape &MapWires)
2394{
2395 BRep_Builder B;
2396 TopTools_SequenceOfShape faces;
2397 TopoDS_Shape S = myFace;
2398 if ( ! Context().IsNull() )
2399 S = Context()->Apply ( myFace );
0f180c0c 2400 Standard_Integer NbWires=0, NbWiresNew=0, NbEdges;
7fd59977 2401 for(TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
0f180c0c 2402 const TopoDS_Shape& aShape = iter.Value();
2403 if(aShape.ShapeType() != TopAbs_WIRE ||
2404 (aShape.Orientation() != TopAbs_FORWARD && aShape.Orientation() != TopAbs_REVERSED))
7fd59977 2405 continue;
0f180c0c 2406 TopoDS_Wire wire = TopoDS::Wire ( aShape );
7fd59977 2407 NbWires++;
2408 if(MapWires.IsBound(wire)) {
2409 // if wire not closed --> stop split and return false
2410 Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire);
0f180c0c 2411 NbEdges = sewd->NbEdges();
2412 if (NbEdges == 0) {
2413 continue;
2414 }
2415 //
7fd59977 2416 TopoDS_Edge E1 = sewd->Edge(1);
0f180c0c 2417 TopoDS_Edge E2 = sewd->Edge(NbEdges);
7fd59977 2418 TopoDS_Vertex V1,V2;
2419 ShapeAnalysis_Edge sae;
2420 V1=sae.FirstVertex(E1);
2421 V2=sae.LastVertex(E2);
2422 if(!V1.IsSame(V2)) {
0797d9d3 2423#ifdef OCCT_DEBUG
7fd59977 2424 cout<<"wire not closed --> stop split"<<endl;
aefdc31b 2425#endif
7fd59977 2426 return Standard_False;
2427 }
2428 // create face
2429 TopoDS_Shape emptyCopied = S.EmptyCopied();
2430 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
2431 tmpFace.Orientation ( TopAbs_FORWARD );
2432 B.Add(tmpFace,wire);
2433 NbWiresNew++;
2434 const TopTools_ListOfShape& IntWires = MapWires.Find(wire);
2435 TopTools_ListIteratorOfListOfShape liter(IntWires);
2436 for( ; liter.More(); liter.Next()) {
51740958 2437 TopoDS_Shape aShapeEmptyCopied = tmpFace.EmptyCopied();
2438 TopoDS_Face aFace = TopoDS::Face ( aShapeEmptyCopied);
77193183 2439 aFace.Orientation ( TopAbs_FORWARD );
2440 B.Add (aFace,liter.Value());
2441 BRepTopAdaptor_FClass2d clas (aFace,::Precision::PConfusion());
2442 TopAbs_State staout = clas.PerformInfinitePoint();
2443 if (staout == TopAbs_IN)
2444 B.Add(tmpFace,liter.Value());
2445 else
2446 B.Add(tmpFace,liter.Value().Reversed());
7fd59977 2447 NbWiresNew++;
2448 }
2449 if(!myFwd) tmpFace.Orientation(TopAbs_REVERSED);
2450 faces.Append(tmpFace);
2451 }
2452 }
2453
2454 if(NbWires!=NbWiresNew) return Standard_False;
2455
2456 if(faces.Length()>1) {
2457 TopoDS_Compound Comp;
2458 B.MakeCompound(Comp);
2459 for(Standard_Integer i=1; i<=faces.Length(); i++ )
2460 B.Add(Comp,faces(i));
2461 myResult = Comp;
2462 Context()->Replace ( myFace, myResult );
2463 for (TopExp_Explorer exp ( myResult, TopAbs_FACE ); exp.More(); exp.Next() ) {
2464 myFace = TopoDS::Face ( exp.Current() );
2465 BRepTools::Update(myFace);
2466 }
2467 return Standard_True;
2468 }
2469
2470 return Standard_False;
2471}
84dc990a
S
2472
2473//=======================================================================
2474//function : IsPeriodicConicalLoop
2475//purpose : Checks whether the passed wire makes up a periodic loop on
2476// passed conical surface
2477//=======================================================================
2478
2479static Standard_Boolean IsPeriodicConicalLoop(const Handle(Geom_ConicalSurface)& theSurf,
2480 const TopoDS_Wire& theWire,
2481 const Standard_Real theTolerance,
2482 Standard_Real& theMinU,
2483 Standard_Real& theMaxU,
2484 Standard_Real& theMinV,
2485 Standard_Real& theMaxV,
2486 Standard_Boolean& isUDecrease)
2487{
2488 if ( theSurf.IsNull() )
fdbc4fe7 2489 return Standard_False;
84dc990a
S
2490
2491 ShapeAnalysis_Edge aSAE;
2492 TopLoc_Location aLoc;
2493
2494 Standard_Real aCumulDeltaU = 0.0, aCumulDeltaUAbs = 0.0;
2495 Standard_Real aMinU = RealLast();
2496 Standard_Real aMinV = aMinU;
2497 Standard_Real aMaxU = -aMinU;
2498 Standard_Real aMaxV = aMaxU;
2499
2500 // Iterate over the edges to check whether the wire is periodic on conical surface
46aed280 2501 TopoDS_Iterator aWireIter(theWire, Standard_False);
2502 for ( ; aWireIter.More(); aWireIter.Next() )
84dc990a 2503 {
46aed280 2504 const TopoDS_Edge& aCurrentEdge = TopoDS::Edge(aWireIter.Value());
84dc990a
S
2505 Handle(Geom2d_Curve) aC2d;
2506 Standard_Real aPFirst, aPLast;
2507
2508 aSAE.PCurve(aCurrentEdge, theSurf, aLoc, aC2d, aPFirst, aPLast, Standard_True);
2509
2510 if ( aC2d.IsNull() )
2511 return Standard_False;
2512
2513 gp_Pnt2d aUVFirst = aC2d->Value(aPFirst),
2514 aUVLast = aC2d->Value(aPLast);
2515
2516 Standard_Real aUFirst = aUVFirst.X(), aULast = aUVLast.X();
2517 Standard_Real aVFirst = aUVFirst.Y(), aVLast = aUVLast.Y();
2518
2519 Standard_Real aCurMaxU = Max(aUFirst, aULast),
2520 aCurMinU = Min(aUFirst, aULast);
2521 Standard_Real aCurMaxV = Max(aVFirst, aVLast),
2522 aCurMinV = Min(aVFirst, aVLast);
2523
2524 if ( aCurMinU < aMinU )
2525 aMinU = aCurMinU;
2526 if ( aCurMaxU > aMaxU )
2527 aMaxU = aCurMaxU;
2528 if ( aCurMinV < aMinV )
2529 aMinV = aCurMinV;
2530 if ( aCurMaxV > aMaxV )
2531 aMaxV = aCurMaxV;
2532
2533 Standard_Real aDeltaU = aULast - aUFirst;
2534
2535 aCumulDeltaU += aDeltaU;
2536 aCumulDeltaUAbs += Abs(aDeltaU);
2537 }
2538
2539 theMinU = aMinU;
2540 theMaxU = aMaxU;
2541 theMinV = aMinV;
2542 theMaxV = aMaxV;
2543 isUDecrease = (aCumulDeltaU < 0 ? Standard_True : Standard_False);
2544
2545 Standard_Boolean is2PIDelta = Abs(aCumulDeltaUAbs - 2*M_PI) <= theTolerance;
2546 Standard_Boolean isAroundApex = Abs(theMaxU - theMinU) > 2*M_PI - theTolerance;
2547
2548 return is2PIDelta && isAroundApex;
2549}
2550
2551//=======================================================================
2552//function : FixPeriodicDegenerated
2553//purpose :
2554//=======================================================================
2555
2556Standard_Boolean ShapeFix_Face::FixPeriodicDegenerated()
2557{
2558 /* =====================
2559 * Prepare fix routine
2560 * ===================== */
2561
2562 if ( !Context().IsNull() )
2563 {
2564 TopoDS_Shape aSh = Context()->Apply(myFace);
2565 myFace = TopoDS::Face(aSh);
2566 }
2567
2568 /* ================================================
2569 * Check if fix can be applied on the passed face
2570 * ================================================ */
2571
2572 // Collect all wires owned by the face
2573 TopTools_SequenceOfShape aWireSeq;
2574 for ( TopoDS_Iterator aWireIt(myFace, Standard_False); aWireIt.More(); aWireIt.Next() )
2575 {
2576 const TopoDS_Shape& aSubSh = aWireIt.Value();
2577 if ( aSubSh.ShapeType() != TopAbs_WIRE || ( aSubSh.Orientation() != TopAbs_FORWARD &&
2578 aSubSh.Orientation() != TopAbs_REVERSED ) )
2579 continue;
2580
2581 aWireSeq.Append( aWireIt.Value() );
2582 }
2583
2584 // Get number of wires and surface
2585 Standard_Integer aNbWires = aWireSeq.Length();
2586 Handle(Geom_Surface) aSurface = BRep_Tool::Surface(myFace);
2587
2588 // Only single wires on conical surfaces are checked
2589 if ( aNbWires != 1 || aSurface.IsNull() ||
2590 aSurface->DynamicType() != STANDARD_TYPE(Geom_ConicalSurface) )
2591 return Standard_False;
2592
2593 // Get the single wire
2594 TopoDS_Wire aSoleWire = TopoDS::Wire( aWireSeq.Value(1) );
2595
2596 // Check whether this wire is belting the conical surface by period
2597 Handle(Geom_ConicalSurface) aConeSurf = Handle(Geom_ConicalSurface)::DownCast(aSurface);
2598 Standard_Real aMinLoopU = 0.0, aMaxLoopU = 0.0, aMinLoopV = 0.0, aMaxLoopV = 0.0;
2599 Standard_Boolean isUDecrease = Standard_False;
2600
2601 Standard_Boolean isConicLoop = IsPeriodicConicalLoop(aConeSurf, aSoleWire, Precision(),
2602 aMinLoopU, aMaxLoopU,
2603 aMinLoopV, aMaxLoopV,
2604 isUDecrease);
2605
2606 if ( !isConicLoop )
2607 return Standard_False;
2608
2609 /* ===============
2610 * Retrieve apex
2611 * =============== */
2612
2613 // Get base circle of the conical surface (the circle it was built from)
2614 Handle(Geom_Curve) aConeBaseCrv = aConeSurf->VIso(0.0);
2615 Handle(Geom_Circle) aConeBaseCirc = Handle(Geom_Circle)::DownCast(aConeBaseCrv);
2616
2617 // Retrieve conical props
2618 Standard_Real aConeBaseR = aConeBaseCirc->Radius();
2619 Standard_Real aSemiAngle = aConeSurf->SemiAngle();
2620
2621 if ( fabs(aSemiAngle) <= Precision::Confusion() )
2622 return Standard_False; // Bad surface
2623
2624 // Find the V parameter of the apex
2625 Standard_Real aConeBaseH = aConeBaseR / Sin(aSemiAngle);
2626 Standard_Real anApexV = -aConeBaseH;
2627
2628 // Get apex vertex
2629 TopoDS_Vertex anApex = BRepBuilderAPI_MakeVertex( aConeSurf->Apex() );
2630
2631 // ====================================
2632 // Build degenerated edge in the apex
2633 // ====================================
2634
2635 TopoDS_Edge anApexEdge;
2636 BRep_Builder aBuilder;
2637 aBuilder.MakeEdge(anApexEdge);
2638
2639 // Check if positional relationship between the initial wire and apex
2640 // line in 2D is going to be consistent
2641 if ( fabs(anApexV - aMinLoopV) <= Precision() ||
2642 fabs(anApexV - aMaxLoopV) <= Precision() ||
2643 ( anApexV < aMaxLoopV && anApexV > aMinLoopV ) )
2644 return Standard_False;
2645
2646 Handle(Geom2d_Line) anApexCurve2d;
2647
2648 // Apex curve below the wire
2649 if ( anApexV < aMinLoopV )
2650 {
2651 anApexCurve2d = new Geom2d_Line( gp_Pnt2d(aMinLoopU, anApexV), gp_Dir2d(1, 0) );
2652 if ( !isUDecrease )
2653 aSoleWire.Reverse();
2654 }
2655
2656 // Apex curve above the wire
2657 if ( anApexV > aMaxLoopV )
2658 {
2659 anApexCurve2d = new Geom2d_Line( gp_Pnt2d(aMaxLoopU, anApexV), gp_Dir2d(-1, 0) );
2660 if ( isUDecrease )
2661 aSoleWire.Reverse();
2662 }
2663
2664 // Create degenerated edge & wire for apex
2665 aBuilder.UpdateEdge( anApexEdge, anApexCurve2d, myFace, Precision() );
2666 aBuilder.Add( anApexEdge, anApex );
2667 aBuilder.Add( anApexEdge, anApex.Reversed() );
2668 aBuilder.Degenerated(anApexEdge, Standard_True);
2669 aBuilder.Range( anApexEdge, 0, fabs(aMaxLoopU - aMinLoopU) );
2670 TopoDS_Wire anApexWire = BRepBuilderAPI_MakeWire(anApexEdge);
2671
2672 // ===============================================================
2673 // Finalize the fix building new face and setting up the results
2674 // ===============================================================
2675
2676 // Collect the resulting set of wires
2677 TopTools_SequenceOfShape aNewWireSeq;
2678 aNewWireSeq.Append(aSoleWire);
2679 aNewWireSeq.Append(anApexWire);
2680
2681 // Assemble new face
2682 TopoDS_Face aNewFace = TopoDS::Face( myFace.EmptyCopied() );
2683 aNewFace.Orientation(TopAbs_FORWARD);
2684 BRep_Builder aFaceBuilder;
2685 for ( Standard_Integer i = 1; i <= aNewWireSeq.Length(); i++ )
2686 {
2687 TopoDS_Wire aNewWire = TopoDS::Wire( aNewWireSeq.Value(i) );
2688 aFaceBuilder.Add(aNewFace, aNewWire);
2689 }
2690 aNewFace.Orientation( myFace.Orientation() );
2691
2692 // Adjust the resulting state of the healing tool
2693 myResult = aNewFace;
2694 Context()->Replace(myFace, myResult);
2695
2696 return Standard_True;
2697}