1 // Created on: 2000-01-21
2 // Created by: data exchange team
3 // Copyright (c) 2000-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <ShapeFix.hxx>
17 //:k2 abv 16.12.98: eliminating code duplication
18 //pdn 18.12.98: checking deviation for SP edges
19 //: abv 22.02.99: method FillFace() removed since PRO13123 is fixed
21 //szv#9:S4244:19Aug99: Added method FixWireGaps
22 //szv#10:S4244:23Aug99: Added method FixFaceGaps
24 #include <BRep_Builder.hxx>
25 #include <BRep_Tool.hxx>
27 #include <Geom2d_Curve.hxx>
28 #include <Geom_Curve.hxx>
30 #include <Precision.hxx>
32 #include <Standard_Failure.hxx>
34 #include <TopExp_Explorer.hxx>
35 #include <TopLoc_Location.hxx>
37 #include <TopoDS_Edge.hxx>
38 #include <TopoDS_Face.hxx>
39 #include <Geom_Surface.hxx>
43 #include <Geom_Plane.hxx>
44 #include <ShapeFix_Edge.hxx>
45 #include <Geom2dAdaptor_HCurve.hxx>
46 #include <Adaptor3d_CurveOnSurface.hxx>
47 #include <Geom_RectangularTrimmedSurface.hxx>
48 #include <ShapeAnalysis_Surface.hxx>
50 #include <ShapeFix_Edge.hxx>
51 #include <ShapeFix_Shape.hxx>
52 #include <ShapeFix_Wire.hxx>
53 #include <ShapeFix_Face.hxx>
54 #include <TopoDS_Iterator.hxx>
55 #include <GeomAdaptor_HSurface.hxx>
56 #include <TopTools_MapOfShape.hxx>
57 #include <BRepLib.hxx>
59 #include <ShapeAnalysis_Edge.hxx>
60 #include <ShapeBuild_Edge.hxx>
61 #include <TopoDS_Vertex.hxx>
62 #include <ShapeBuild_ReShape.hxx>
63 #include <TColgp_SequenceOfPnt.hxx>
64 #include <TopTools_ListOfShape.hxx>
65 #include <TopTools_ListIteratorOfListOfShape.hxx>
66 #include <TopTools_SequenceOfShape.hxx>
67 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
70 #include <Message_ProgressSentry.hxx>
71 #include <Message_Msg.hxx>
72 #include <ShapeExtend_BasicMsgRegistrator.hxx>
74 //=======================================================================
75 //function : SameParameter
77 //=======================================================================
79 Standard_Boolean ShapeFix::SameParameter(const TopoDS_Shape& shape,
80 const Standard_Boolean enforce,
81 const Standard_Real preci,
82 const Handle(Message_ProgressIndicator)& theProgress,
83 const Handle(ShapeExtend_BasicMsgRegistrator)& theMsgReg)
85 // Calculate number of edges
86 Standard_Integer aNbEdges = 0;
87 for ( TopExp_Explorer anEdgeExp(shape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next() )
90 // Calculate number of faces
91 Standard_Integer aNbFaces = 0;
92 for ( TopExp_Explorer anEdgeExp(shape, TopAbs_FACE); anEdgeExp.More(); anEdgeExp.Next() )
95 TopTools_IndexedDataMapOfShapeListOfShape aMapEF;
96 TopExp::MapShapesAndAncestors(shape, TopAbs_EDGE, TopAbs_FACE, aMapEF);
99 //Standard_Integer nbexcp = 0;
100 Standard_Integer nbfail = 0, numedge = 0;
101 Standard_Boolean status = Standard_True;
102 Standard_Real tol = preci;
103 Standard_Boolean iatol = (tol > 0);
104 Handle(ShapeFix_Edge) sfe = new ShapeFix_Edge;
105 TopExp_Explorer ex(shape,TopAbs_EDGE);
106 Message_Msg doneMsg("FixEdge.SameParameter.MSG0");
108 // Start progress scope (no need to check if progress exists -- it is safe)
109 Message_ProgressSentry aPSentryForSameParam(theProgress, "Fixing same parameter problem", 0, 2, 1);
112 // Start progress scope (no need to check if progress exists -- it is safe)
113 Message_ProgressSentry aPSentry(theProgress, "Fixing edge", 0, aNbEdges, 1);
118 while ( ex.More() && aPSentry.More() )
123 E = TopoDS::Edge (ex.Current());
127 tol = BRep_Tool::Tolerance (E);
130 B.SameRange (E,Standard_False);
131 B.SameParameter (E,Standard_False);
134 TopTools_ListOfShape aListOfFaces;
135 aMapEF.FindFromKey(E, aListOfFaces);
136 if (aListOfFaces.Extent() != 0)
138 TopTools_ListOfShape::Iterator aListOfFacesIt(aListOfFaces);
139 for ( ; aListOfFacesIt.More() ; aListOfFacesIt.Next())
141 TopoDS_Face aF = TopoDS::Face( aListOfFacesIt.Value() );
142 sfe->FixSameParameter (E, aF);
147 sfe->FixSameParameter (E); // K2-SEP97
150 if (!BRep_Tool::SameParameter (E)) { ierr = 1; nbfail ++; }
154 status = Standard_False;
155 B.SameRange (E,Standard_False);
156 B.SameParameter (E,Standard_False);
158 else if ( !theMsgReg.IsNull() && !sfe->Status( ShapeExtend_OK ) )
160 theMsgReg->Send( E, doneMsg, Message_Warning );
163 // Complete step in current progress scope
167 // Halt algorithm in case of user's abort
168 if ( !aPSentry.More() )
169 return Standard_False;
173 // Switch to "Update tolerances" step
174 aPSentryForSameParam.Next();
177 // Start progress scope (no need to check if progress exists -- it is safe)
178 Message_ProgressSentry aPSentry(theProgress, "Update tolerances", 0, aNbFaces, 1);
180 //:i2 abv 21 Aug 98: ProSTEP TR8 Motor.rle face 710:
181 // Update tolerance of edges on planes (no pcurves are stored)
182 for ( TopExp_Explorer exp ( shape, TopAbs_FACE ); exp.More() && aPSentry.More(); exp.Next(), aPSentry.Next() )
184 TopoDS_Face face = TopoDS::Face ( exp.Current() );
185 Handle(Geom_Surface) Surf = BRep_Tool::Surface ( face );
187 Handle(Geom_Plane) plane = Handle(Geom_Plane)::DownCast ( Surf );
188 if ( plane.IsNull() ) {
189 Handle(Geom_RectangularTrimmedSurface) GRTS =
190 Handle(Geom_RectangularTrimmedSurface)::DownCast ( Surf );
191 if ( ! GRTS.IsNull() )
192 plane = Handle(Geom_Plane)::DownCast ( GRTS->BasisSurface() );
193 if ( plane.IsNull() )
197 Handle(GeomAdaptor_HSurface) AS = new GeomAdaptor_HSurface ( plane );
198 for ( TopExp_Explorer ed ( face, TopAbs_EDGE ); ed.More(); ed.Next() ) {
199 TopoDS_Edge edge = TopoDS::Edge ( ed.Current() );
201 Handle(Geom_Curve) crv = BRep_Tool::Curve ( edge, f, l );
205 Handle(Geom2d_Curve) c2d = BRep_Tool::CurveOnSurface ( edge, face, f, l );;
206 if ( c2d.IsNull() ) continue;
207 Handle(Geom2dAdaptor_HCurve) GHPC = new Geom2dAdaptor_HCurve ( c2d, f, l );
208 Adaptor3d_CurveOnSurface ACS(GHPC,AS);
210 Standard_Real tol0 = BRep_Tool::Tolerance(edge);
212 Standard_Real tol2 = tol*tol;
213 Standard_Boolean isChanged = Standard_False;
214 const Standard_Integer NCONTROL = 23;
215 for ( Standard_Integer i = 0; i < NCONTROL; i++ )
217 Standard_Real par = ( f * ( NCONTROL - 1 - i ) + l * i ) / ( NCONTROL - 1 );
218 gp_Pnt pnt = crv->Value ( par );
219 gp_Pnt prj = ACS.Value( par );
220 Standard_Real dist = pnt.SquareDistance(prj);
224 isChanged = Standard_True;
229 tol = 1.00005 * sqrt(tol2); // coeff: see trj3_pm1-ct-203.stp #19681, edge 10
232 B.UpdateEdge ( edge, tol );
233 for ( TopoDS_Iterator itV(edge); itV.More(); itV.Next() )
235 TopoDS_Shape S = itV.Value();
236 B.UpdateVertex ( TopoDS::Vertex ( S ), tol );
242 // Halt algorithm in case of user's abort
243 if ( !aPSentry.More() )
244 return Standard_False;
250 cout<<"** SameParameter not complete. On "<<numedge<<" Edges:";
251 if (nbfail > 0) cout<<" "<<nbfail<<" Failed";
259 //=======================================================================
260 //function : EncodeRegularity
262 //=======================================================================
264 void ShapeFix::EncodeRegularity (const TopoDS_Shape& shape,
265 const Standard_Real tolang)
267 BRepLib::EncodeRegularity(shape, tolang);
271 //=======================================================================
272 //function : RemoveSmallEdges
274 //=======================================================================
276 TopoDS_Shape ShapeFix::RemoveSmallEdges (TopoDS_Shape& Shape,
277 const Standard_Real Tolerance,
278 Handle(ShapeBuild_ReShape)& context)
280 Handle(ShapeFix_Shape) sfs = new ShapeFix_Shape;
282 sfs->SetPrecision(Tolerance);
283 sfs->FixFaceTool()->FixMissingSeamMode() = Standard_False;
284 sfs->FixFaceTool()->FixOrientationMode() = Standard_False;
285 sfs->FixFaceTool()->FixSmallAreaWireMode() = Standard_False;
286 sfs->FixWireTool()->ModifyTopologyMode() = Standard_True;
287 //sfs.FixWireTool().FixReorderMode() = Standard_False;
288 sfs->FixWireTool()->FixConnectedMode() = Standard_False;
289 sfs->FixWireTool()->FixEdgeCurvesMode() = Standard_False;
290 sfs->FixWireTool()->FixDegeneratedMode() = Standard_False;
291 sfs->FixWireTool()->FixSelfIntersectionMode() = Standard_False;
292 sfs->FixWireTool()->FixLackingMode() = Standard_False;
293 sfs->FixWireTool()->FixSmallMode() = Standard_True;
295 TopoDS_Shape result = sfs->Shape();
296 context = sfs->Context();
301 //=======================================================================
302 //function : ReplaceVertex
303 //purpose : auxilary for FixVertexPosition
304 //=======================================================================
305 static TopoDS_Edge ReplaceVertex(const TopoDS_Edge& theEdge,
307 const Standard_Boolean theFwd)
309 TopoDS_Vertex aNewVertex;
311 aB.MakeVertex(aNewVertex,theP,Precision::Confusion());
312 TopoDS_Vertex aV1,aV2;
315 aV1.Orientation( TopAbs_FORWARD);
319 aV2.Orientation( TopAbs_REVERSED);
321 ShapeBuild_Edge aSbe;
322 TopoDS_Edge e1 = theEdge;
323 TopAbs_Orientation Ori = e1.Orientation();
324 e1.Orientation(TopAbs_FORWARD);
325 TopoDS_Edge aNewEdge = aSbe.CopyReplaceVertices(e1,aV1,aV2);
326 aNewEdge.Orientation(Ori);
331 //=======================================================================
332 //function : getNearPoint
333 //purpose : auxilary for FixVertexPosition
334 //=======================================================================
335 static Standard_Real getNearPoint(const TColgp_SequenceOfPnt& aSeq1,
336 const TColgp_SequenceOfPnt& aSeq2,
339 Standard_Integer i =1;
340 Standard_Integer ind1 =0,ind2 =0;
341 Standard_Real mindist =RealLast();
342 for( ; i <= aSeq1.Length(); i++) {
343 gp_Pnt p1 = aSeq1.Value(i);
344 Standard_Integer j=1;
345 for( ; j <= aSeq2.Length(); j++) {
346 gp_Pnt p2 = aSeq2.Value(j);
347 Standard_Real d = p1.Distance(p2);
348 if(fabs(d -mindist ) <= Precision::Confusion())
359 acent = (aSeq1.Value(ind1).XYZ() + aSeq2.Value(ind2).XYZ())/2.0;
364 //=======================================================================
365 //function : getNearestEdges
366 //purpose : auxilary for FixVertexPosition
367 //=======================================================================
368 static Standard_Boolean getNearestEdges(TopTools_ListOfShape& theLEdges,
369 const TopoDS_Vertex theVert,
370 TopTools_SequenceOfShape& theSuitEdges,
371 TopTools_SequenceOfShape& theRejectEdges,
372 const Standard_Real theTolerance,
373 gp_XYZ& thecentersuit,
374 gp_XYZ& thecenterreject)
376 if(theLEdges.IsEmpty())
377 return Standard_False;
378 TopTools_MapOfShape aMapEdges;
380 TopTools_ListOfShape atempList;
381 atempList= theLEdges;
382 TopTools_ListIteratorOfListOfShape alIter(atempList);
384 TopoDS_Edge aEdge1 = TopoDS::Edge(alIter.Value());
385 TopoDS_Vertex aVert11,aVert12;
386 TopExp::Vertices(aEdge1, aVert11,aVert12 );
387 aMapEdges.Add(aEdge1);
388 Standard_Real aFirst1,aLast1;
389 Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(aEdge1,aFirst1,aLast1);
392 Standard_Boolean isFirst1 = theVert.IsSame(aVert11);
393 Standard_Boolean isSame1 = aVert11.IsSame(aVert12);
394 if( !aCurve1.IsNull()) {
396 p11 = aCurve1->Value(aFirst1);
398 p11 = aCurve1->Value(aLast1);
400 p12 = aCurve1->Value(aLast1);
402 else return Standard_False;
404 TopTools_SequenceOfShape aseqreject;
405 TopTools_SequenceOfShape aseqsuit;
407 Standard_Integer anumLoop =0;
408 for( ; alIter.More(); ) {
409 TopoDS_Edge aEdge = TopoDS::Edge(alIter.Value());
410 if( aMapEdges.Contains(aEdge)) {
411 atempList.Remove(alIter);
415 TopoDS_Vertex aVert1,aVert2;
416 TopExp::Vertices(aEdge, aVert1,aVert2 );
417 Standard_Real isFirst = theVert.IsSame(aVert1);
418 Standard_Boolean isSame = aVert1.IsSame(aVert2);
420 Standard_Boolean isLoop = ((aVert1.IsSame(aVert11) && aVert2.IsSame(aVert12)) ||
421 (aVert1.IsSame(aVert12) && aVert2.IsSame(aVert11)));
422 if(isLoop /*&& !aseqsuit.Length()*/ && (atempList.Extent() >anumLoop)) {
423 atempList.Append(aEdge);
424 atempList.Remove(alIter);
428 aMapEdges.Add(aEdge);
429 Standard_Real aFirst,aLast;
430 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge,aFirst,aLast);
431 if( !aCurve.IsNull()) {
435 p1 = aCurve->Value(aFirst);
437 p1 = aCurve->Value(aLast);
439 p2 = aCurve->Value(aLast);
440 Standard_Real aMinDist = RealLast();
442 if(!isSame && ! isSame1) {
443 aMinDist = p1.Distance(p11);
444 acent = (p1.XYZ() + p11.XYZ())/2.0;
447 TColgp_SequenceOfPnt aSeq1;
448 TColgp_SequenceOfPnt aSeq2;
455 aMinDist = getNearPoint(aSeq1,aSeq2,acent);
458 if(aMinDist > theTolerance) {
459 if(!aseqreject.Length())
460 thecenterreject = acent;
461 aseqreject.Append(aEdge);
464 if(!aseqsuit.Length()) {
465 thecentersuit = acent;
466 aseqsuit.Append(aEdge);
469 aseqsuit.Append(aEdge);
470 else if((thecentersuit - acent).Modulus() < theTolerance)
471 aseqsuit.Append(aEdge);
473 aseqreject.Append(aEdge);
477 atempList.Remove(alIter);
480 Standard_Boolean isDone = (!aseqsuit.IsEmpty() || !aseqreject.IsEmpty());
482 if(aseqsuit.IsEmpty()) {
483 theRejectEdges.Append(aEdge1);
484 theLEdges.RemoveFirst();
486 getNearestEdges(theLEdges,theVert,theSuitEdges,theRejectEdges,
487 theTolerance,thecentersuit,thecenterreject);
490 theSuitEdges.Append(aEdge1);
491 theSuitEdges.Append(aseqsuit);
492 theRejectEdges.Append(aseqreject);
496 theRejectEdges.Append(aEdge1);
502 //=======================================================================
503 //function : FixVertexPosition
505 //=======================================================================
507 Standard_Boolean ShapeFix::FixVertexPosition(TopoDS_Shape& theshape,
508 const Standard_Real theTolerance,
509 const Handle(ShapeBuild_ReShape)& thecontext)
511 TopTools_IndexedDataMapOfShapeListOfShape aMapVertEdges;
512 TopExp_Explorer aExp1(theshape,TopAbs_EDGE);
513 for( ; aExp1.More(); aExp1.Next()) {
515 Standard_Integer nV =1;
516 TopoDS_Iterator aExp3(aExp1.Current());
517 for( ; aExp3.More(); aExp3.Next(),nV++) {
518 TopoDS_Shape aVert = aExp3.Value();
521 else if(aVert1.IsSame(aVert))
523 if(aMapVertEdges.Contains(aVert))
524 aMapVertEdges.ChangeFromKey(aVert).Append(aExp1.Current());
526 TopTools_ListOfShape alEdges;
527 alEdges.Append(aExp1.Current());
528 aMapVertEdges.Add(aVert,alEdges);
532 Standard_Boolean isDone = Standard_False;
533 Standard_Integer i=1;
534 for( ; i <= aMapVertEdges.Extent(); i++) {
535 TopoDS_Vertex aVert = TopoDS::Vertex(aMapVertEdges.FindKey(i));
536 Standard_Real aTolVert = BRep_Tool::Tolerance(aVert);
537 if(aTolVert <= theTolerance)
541 aB1.UpdateVertex(aVert,theTolerance);
542 gp_Pnt aPvert = BRep_Tool::Pnt(aVert);
543 gp_XYZ acenter(aPvert.XYZ()), acenterreject(aPvert.XYZ());
545 TopTools_SequenceOfShape aSuitEdges;
546 TopTools_SequenceOfShape aRejectEdges;
547 TopTools_ListOfShape aledges;
548 aledges= aMapVertEdges.FindFromIndex(i);
549 if(aledges.Extent() ==1)
551 //if tolerance of vertex is more than specified tolerance
552 // check distance between curves and vertex
554 if(!getNearestEdges(aledges,aVert,aSuitEdges,aRejectEdges,theTolerance,acenter,acenterreject))
557 //update vertex by nearest point
558 Standard_Boolean isAdd = Standard_False;
559 Standard_Integer k =1;
560 for( ; k <= aSuitEdges.Length(); k++) {
562 TopoDS_Edge aEdgeOld = TopoDS::Edge(aSuitEdges.Value(k));
563 TopoDS_Vertex aVert1,aVert2;
564 TopExp::Vertices(aEdgeOld, aVert1,aVert2 );
566 Standard_Boolean isFirst = (aVert1.IsSame(aVert));
567 Standard_Boolean isLast = (aVert2.IsSame(aVert));
568 if(!isFirst && !isLast)
570 Standard_Real aFirst,aLast;
571 Handle(Geom_Curve) aCurve;
572 TopoDS_Edge aEdge = TopoDS::Edge(thecontext->Apply(aEdgeOld));
574 TopoDS_Vertex aVert1n,aVert2n;
575 TopExp::Vertices(aEdge, aVert1n,aVert2n );
576 aCurve = BRep_Tool::Curve(aEdge,aFirst,aLast);
577 if( !aCurve.IsNull()) {
578 gp_Pnt p1 = aCurve->Value(aFirst);
579 gp_Pnt p2 = aCurve->Value(aLast);
581 //if distance between ends of curve more than specified tolerance
582 //but vertices are the same that one of the vertex will be replaced.
584 Standard_Boolean isReplace = (aVert1n.IsSame(aVert2n) && p1.Distance(p2) >theTolerance);
586 //Standard_Real dd1 = (acenter - p1.XYZ()).Modulus();
587 //Standard_Real dd2 = (acenter - p2.XYZ()).Modulus();
595 if(p1.Distance(acenter) < p2.Distance(acenter))
596 enew = ReplaceVertex(aEdge,p2,Standard_False);
598 enew = ReplaceVertex(aEdge,p1,Standard_True);
599 thecontext->Replace(aEdge,enew);
600 isDone = Standard_True;
610 if(p1.Distance(acenter) < p2.Distance(acenter))
611 enew = ReplaceVertex(aEdge,p2,Standard_False);
613 enew = ReplaceVertex(aEdge,p1,Standard_True);
614 thecontext->Replace(aEdge,enew);
615 isDone = Standard_True;
621 isAdd = Standard_True;
627 if(isAdd && aPvert.Distance(acenter) > theTolerance)
632 // aB.UpdateVertex(aVert,Precision::Confusion());
634 isDone = Standard_True;
635 TopoDS_Vertex aNewVertex;
636 aB.MakeVertex(aNewVertex,acenter,Precision::Confusion());
637 aNewVertex.Orientation(aVert.Orientation());
638 thecontext->Replace(aVert,aNewVertex);
642 for( k =1; k <= aRejectEdges.Length(); k++) {
643 TopoDS_Edge aEdgeOld = TopoDS::Edge( aRejectEdges.Value(k));
644 TopoDS_Vertex aVert1,aVert2;
645 TopExp::Vertices(aEdgeOld, aVert1,aVert2 );
647 Standard_Boolean isFirst = (aVert1.IsSame(aVert));
648 Standard_Boolean isLast = (aVert2.IsSame(aVert));
649 if(!isFirst && !isLast)
651 Standard_Boolean isSame = aVert1.IsSame(aVert2);
652 Handle(Geom_Curve) aCurve;
653 TopoDS_Edge aEdge = TopoDS::Edge(thecontext->Apply(aEdgeOld));
655 TopoDS_Vertex aVert1n,aVert2n;
656 TopExp::Vertices(aEdge, aVert1n,aVert2n );
658 Standard_Real aFirst,aLast;
659 aCurve = BRep_Tool::Curve(aEdge,aFirst,aLast);
660 if( !aCurve.IsNull()) {
661 gp_Pnt p1 = aCurve->Value(aFirst);
662 gp_Pnt p2 = aCurve->Value(aLast);
665 enew = ReplaceVertex(aEdge,p1,Standard_True);
667 enew = ReplaceVertex(enew,p2,Standard_False);
670 enew = ReplaceVertex(aEdge,p2,Standard_False);
672 enew = ReplaceVertex(enew ,p1,Standard_True);
675 thecontext->Replace(aEdge,enew);
676 isDone = Standard_True;
684 theshape = thecontext->Apply(theshape);
689 //=======================================================================
690 //function : LeastEdgeSize
692 //=======================================================================
694 Standard_Real ShapeFix::LeastEdgeSize(TopoDS_Shape& theShape)
696 Standard_Real aRes = RealLast();
697 for(TopExp_Explorer exp(theShape,TopAbs_EDGE); exp.More(); exp.Next()) {
698 TopoDS_Edge edge = TopoDS::Edge ( exp.Current() );
699 Standard_Real first,last;
700 Handle(Geom_Curve) c3d = BRep_Tool::Curve(edge, first, last);
703 bb.Add(c3d->Value(first));
704 bb.Add(c3d->Value(last));
705 bb.Add(c3d->Value((last+first)/2.));
706 Standard_Real x1,x2,y1,y2,z1,z2,size;
707 bb.Get(x1,y1,z1,x2,y2,z2);
708 size = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1);
709 if(size<aRes) aRes = size;