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