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