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