+// Copyright (c) 1999-2012 OPEN CASCADE SAS
+//
+// The content of this file is subject to the Open CASCADE Technology Public
+// License Version 6.5 (the "License"). You may not use the content of this file
+// except in compliance with the License. Please obtain a copy of the License
+// at http://www.opencascade.org and read it completely before using this file.
+//
+// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
+// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
+//
+// The Original Code and all software distributed under the License is
+// distributed on an "AS IS" basis, without warranty of any kind, and the
+// Initial Developer hereby disclaims all such warranties, including without
+// limitation, any warranties of merchantability, fitness for a particular
+// purpose or non-infringement. Please see the License for the specific terms
+// and conditions governing the rights and limitations under the License.
+
// pdn 10.12.98: tr9_r0501-ug
// pdn 28.12.98: PRO10366 shifting pcurve between two singularities
//:k7 abv 5.01.99: USA60022.igs ent 243: FixMissingSeam() improved
#include <Geom2d_Curve.hxx>
#include <Geom2d_Line.hxx>
+#include <Geom2dAdaptor_Curve.hxx>
#include <Geom_Curve.hxx>
#include <Geom_BSplineSurface.hxx>
#include <GeomAdaptor_HSurface.hxx>
#include <BRep_Builder.hxx>
#include <BRepTopAdaptor_FClass2d.hxx>
#include <BRepTools.hxx>
+#include <BRepTools_WireExplorer.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
+#include <BRepBuilderAPI_MakeVertex.hxx>
+#include <BRepBuilderAPI_MakeWire.hxx>
#include <Message_Msg.hxx>
#include <ShapeBuild_ReShape.hxx>
#include <ShapeFix_Edge.hxx>
#include <ShapeAnalysis_Edge.hxx>
#include <Bnd_Box2d.hxx>
+#include <Geom_Circle.hxx>
#include <Geom_SphericalSurface.hxx>
#include <Geom_RectangularTrimmedSurface.hxx>
+#include <Geom_ConicalSurface.hxx>
#include <ShapeAnalysis_Wire.hxx>
#include <ShapeAnalysis_Surface.hxx>
void ShapeFix_Face::ClearModes()
{
- myFixWireMode = -1;
- myFixOrientationMode = -1;
- myFixAddNaturalBoundMode = -1;
- myFixMissingSeamMode = -1;
- myFixSmallAreaWireMode = -1;
+ myFixWireMode = -1;
+ myFixOrientationMode = -1;
+ myFixAddNaturalBoundMode = -1;
+ myFixMissingSeamMode = -1;
+ myFixSmallAreaWireMode = -1;
myFixIntersectingWiresMode = -1;
- myFixLoopWiresMode =-1;
- myFixSplitFaceMode =-1;
- myAutoCorrectPrecisionMode = 1;
+ myFixLoopWiresMode = -1;
+ myFixSplitFaceMode = -1;
+ myAutoCorrectPrecisionMode = 1;
+ myFixPeriodicDegenerated = -1;
}
//=======================================================================
//purpose : auxilary - try to split wire (it is needed if some segments
// were removed in ShapeFix_Wire::FixSelfIntersection()
//=======================================================================
-static Standard_Boolean SplitWire(const TopoDS_Wire& wire,
+static Standard_Boolean SplitWire(const TopoDS_Face &face, const TopoDS_Wire& wire,
TopTools_SequenceOfShape& aResWires)
{
TColStd_MapOfInteger UsedEdges;
sewd1->Add(E1);
Standard_Boolean IsConnectedEdge = Standard_True;
for(j=2; j<=sewd->NbEdges() && IsConnectedEdge; j++) {
+ TopoDS_Edge E2;
for(k=2; k<=sewd->NbEdges(); k++) {
if(UsedEdges.Contains(k)) continue;
- TopoDS_Edge E2 = sewd->Edge(k);
+ E2 = sewd->Edge(k);
TopoDS_Vertex V21 = sae.FirstVertex(E2);
TopoDS_Vertex V22 = sae.LastVertex(E2);
if( sae.FirstVertex(E2).IsSame(V1) ) {
break;
}
}
- if(V1.IsSame(V0)) {
- // new wire is closed, put it into sequence
- aResWires.Append(sewd1->Wire());
- break;
- }
if(k>sewd->NbEdges()) {
IsConnectedEdge = Standard_False;
break;
}
+ if(V1.IsSame(V0)) {
+ //check that V0 and V1 are same in 2d too
+ Standard_Real a1,b1,a2,b2;
+ Handle (Geom2d_Curve) curve1 = BRep_Tool::CurveOnSurface(E1,face,a1,b1);
+ Handle (Geom2d_Curve) curve2 = BRep_Tool::CurveOnSurface(E2,face,a2,b2);
+ gp_Pnt2d v0,v1;
+ if (E1.Orientation() == TopAbs_REVERSED)
+ a1 = b1;
+ if (E2.Orientation() == TopAbs_REVERSED)
+ b2 = a2;
+ curve1->D0(a1,v0);
+ curve2->D0(b2,v1);
+ GeomAdaptor_Surface anAdaptor(BRep_Tool::Surface(face));
+ Standard_Real tol = Max(BRep_Tool::Tolerance(V0),BRep_Tool::Tolerance(V1));
+ Standard_Real maxResolution = 2 * Max ( anAdaptor.UResolution(tol), anAdaptor.VResolution(tol) );
+ if (v0.SquareDistance(v1) < maxResolution) {
+ // new wire is closed, put it into sequence
+ aResWires.Append(sewd1->Wire());
+ break;
+ }
+ }
}
if(!IsConnectedEdge) {
// create new notclosed wire
if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace );
//myFace = tmpFace;
isReplaced = Standard_True;
- myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
-
}
- if(fixed || isfixReorder)
+ if(fixed || isfixReorder) {
myFace = tmpFace;
+ if (!theAdvFixWire->StatusReorder(ShapeExtend_DONE5)) {
+ myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
+ }
+ }
}
myResult = myFace;
TopoDS_Shape savShape = myFace; //gka BUG 6555
+
+ // Specific case for conic surfaces
+ if ( NeedFix(myFixPeriodicDegenerated) )
+ this->FixPeriodicDegenerated();
+
// fix missing seam
if ( NeedFix ( myFixMissingSeamMode ) ) {
if ( FixMissingSeam() ) {
B.Add (tmpFace,iter.Value());
continue;
}
- if(iter.Value().Orientation() != TopAbs_FORWARD ||
+ if(iter.Value().Orientation() != TopAbs_FORWARD &&
iter.Value().Orientation() != TopAbs_REVERSED) {
B.Add (tmpFace,TopoDS::Wire(iter.Value()));
continue;
}
nbw++;
TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
- SplitWire(wire,aWires);
+ SplitWire(tmpFace,wire,aWires);
}
if(nbw<aWires.Length()) {
for(Standard_Integer iw=1; iw<=aWires.Length(); iw++)
if ( ::Precision::IsInfinite ( SUF ) || ::Precision::IsInfinite ( SUL ) ) {
if ( ::Precision::IsInfinite ( SUF ) ) SUF = fU1;
if ( ::Precision::IsInfinite ( SUL ) ) SUL = fU2;
- if(Abs(SUL-SUF) < ::Precision::PConfusion())
+ if(Abs(SUL-SUF) < ::Precision::PConfusion()) {
if ( ::Precision::IsInfinite ( SUF ) ) SUF-=1000.;
else SUL+=1000.;
+ }
}
if ( ::Precision::IsInfinite ( SVF ) || ::Precision::IsInfinite ( SVL ) ) {
if ( ::Precision::IsInfinite ( SVF ) ) SVF = fV1;
if ( ::Precision::IsInfinite ( SVL ) ) SVL = fV2;
- if(Abs(SVL-SVF) < ::Precision::PConfusion())
+ if(Abs(SVL-SVF) < ::Precision::PConfusion()) {
if ( ::Precision::IsInfinite ( SVF ) ) SVF-=1000.;
else SVL+=1000.;
+ }
}
URange = Abs ( SUL - SUF );
vf = pos1.Y();
}
}
- if ( skipU && skipV )
+ if ( skipU && skipV ) {
if ( i1 <= nb1 ) continue;
else break;
+ }
// or yet better - if it is end of some edges on both wires
for ( Standard_Integer i2 = 1; i1 <= nb1 && i2 <= nb2; i2++ ) {
TopoDS_Edge edge2 = wd2->Edge ( i2 );
Standard_Real prec = ::Precision::PConfusion()*100;
for (TopoDS_Iterator wi (myFace, Standard_False); wi.More(); wi.Next()) {
if(wi.Value().ShapeType() != TopAbs_WIRE &&
- (wi.Value().Orientation() != TopAbs_FORWARD || wi.Value().Orientation() != TopAbs_REVERSED))
+ (wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED))
continue;
TopoDS_Wire wire = TopoDS::Wire ( wi.Value() );
Handle(ShapeAnalysis_Wire) saw = new ShapeAnalysis_Wire(wire,myFace,prec);
return isDone;
}
-
-//=======================================================================
-//function : GetPointOnEdge
-//purpose : auxiliary
-//:h0 abv 29 May 98: PRO10105 1949: like in BRepCheck, point is to be taken
-// from 3d curve (but only if edge is SameParameter)
-//=======================================================================
-static gp_Pnt GetPointOnEdge ( const TopoDS_Edge &edge,
- const Handle(ShapeAnalysis_Surface) &surf,
- const Handle(Geom2d_Curve) &Crv2d,
- const Standard_Real param )
-{
- if ( BRep_Tool::SameParameter ( edge ) ) {
- Standard_Real f,l;
- TopLoc_Location L;
- const Handle(Geom_Curve) ConS = BRep_Tool::Curve ( edge, L, f, l );
- if ( ! ConS.IsNull() )
- return ConS->Value ( param ).Transformed ( L.Transformation() );
- }
- return surf->Value ( Crv2d->Value ( param ) );
-}
-
-
//=======================================================================
//function : SplitEdge
//purpose :
TopoDS_Shape S = myFace;
if ( ! Context().IsNull() )
S = Context()->Apply ( myFace );
- Standard_Integer NbWires=0, NbWiresNew=0;
+ Standard_Integer NbWires=0, NbWiresNew=0, NbEdges;
for(TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
- if(iter.Value().ShapeType() != TopAbs_WIRE ||
- (iter.Value().Orientation() != TopAbs_FORWARD && iter.Value().Orientation() != TopAbs_REVERSED))
+ const TopoDS_Shape& aShape = iter.Value();
+ if(aShape.ShapeType() != TopAbs_WIRE ||
+ (aShape.Orientation() != TopAbs_FORWARD && aShape.Orientation() != TopAbs_REVERSED))
continue;
- TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
+ TopoDS_Wire wire = TopoDS::Wire ( aShape );
NbWires++;
if(MapWires.IsBound(wire)) {
// if wire not closed --> stop split and return false
Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire);
+ NbEdges = sewd->NbEdges();
+ if (NbEdges == 0) {
+ continue;
+ }
+ //
TopoDS_Edge E1 = sewd->Edge(1);
- TopoDS_Edge E2 = sewd->Edge(sewd->NbEdges());
+ TopoDS_Edge E2 = sewd->Edge(NbEdges);
TopoDS_Vertex V1,V2;
ShapeAnalysis_Edge sae;
V1=sae.FirstVertex(E1);
return Standard_False;
}
+
+//=======================================================================
+//function : IsPeriodicConicalLoop
+//purpose : Checks whether the passed wire makes up a periodic loop on
+// passed conical surface
+//=======================================================================
+
+static Standard_Boolean IsPeriodicConicalLoop(const Handle(Geom_ConicalSurface)& theSurf,
+ const TopoDS_Wire& theWire,
+ const Standard_Real theTolerance,
+ Standard_Real& theMinU,
+ Standard_Real& theMaxU,
+ Standard_Real& theMinV,
+ Standard_Real& theMaxV,
+ Standard_Boolean& isUDecrease)
+{
+ if ( theSurf.IsNull() )
+ return Standard_False;
+
+ ShapeAnalysis_Edge aSAE;
+ TopLoc_Location aLoc;
+
+ Standard_Real aCumulDeltaU = 0.0, aCumulDeltaUAbs = 0.0;
+ Standard_Real aMinU = RealLast();
+ Standard_Real aMinV = aMinU;
+ Standard_Real aMaxU = -aMinU;
+ Standard_Real aMaxV = aMaxU;
+
+ // Iterate over the edges to check whether the wire is periodic on conical surface
+ BRepTools_WireExplorer aWireExp(theWire);
+ for ( ; aWireExp.More(); aWireExp.Next() )
+ {
+ const TopoDS_Edge& aCurrentEdge = aWireExp.Current();
+ Handle(Geom2d_Curve) aC2d;
+ Standard_Real aPFirst, aPLast;
+
+ aSAE.PCurve(aCurrentEdge, theSurf, aLoc, aC2d, aPFirst, aPLast, Standard_True);
+
+ if ( aC2d.IsNull() )
+ return Standard_False;
+
+ gp_Pnt2d aUVFirst = aC2d->Value(aPFirst),
+ aUVLast = aC2d->Value(aPLast);
+
+ Standard_Real aUFirst = aUVFirst.X(), aULast = aUVLast.X();
+ Standard_Real aVFirst = aUVFirst.Y(), aVLast = aUVLast.Y();
+
+ Standard_Real aCurMaxU = Max(aUFirst, aULast),
+ aCurMinU = Min(aUFirst, aULast);
+ Standard_Real aCurMaxV = Max(aVFirst, aVLast),
+ aCurMinV = Min(aVFirst, aVLast);
+
+ if ( aCurMinU < aMinU )
+ aMinU = aCurMinU;
+ if ( aCurMaxU > aMaxU )
+ aMaxU = aCurMaxU;
+ if ( aCurMinV < aMinV )
+ aMinV = aCurMinV;
+ if ( aCurMaxV > aMaxV )
+ aMaxV = aCurMaxV;
+
+ Standard_Real aDeltaU = aULast - aUFirst;
+
+ aCumulDeltaU += aDeltaU;
+ aCumulDeltaUAbs += Abs(aDeltaU);
+ }
+
+ theMinU = aMinU;
+ theMaxU = aMaxU;
+ theMinV = aMinV;
+ theMaxV = aMaxV;
+ isUDecrease = (aCumulDeltaU < 0 ? Standard_True : Standard_False);
+
+ Standard_Boolean is2PIDelta = Abs(aCumulDeltaUAbs - 2*M_PI) <= theTolerance;
+ Standard_Boolean isAroundApex = Abs(theMaxU - theMinU) > 2*M_PI - theTolerance;
+
+ return is2PIDelta && isAroundApex;
+}
+
+//=======================================================================
+//function : FixPeriodicDegenerated
+//purpose :
+//=======================================================================
+
+Standard_Boolean ShapeFix_Face::FixPeriodicDegenerated()
+{
+ /* =====================
+ * Prepare fix routine
+ * ===================== */
+
+ if ( !Context().IsNull() )
+ {
+ TopoDS_Shape aSh = Context()->Apply(myFace);
+ myFace = TopoDS::Face(aSh);
+ }
+
+ /* ================================================
+ * Check if fix can be applied on the passed face
+ * ================================================ */
+
+ // Collect all wires owned by the face
+ TopTools_SequenceOfShape aWireSeq;
+ for ( TopoDS_Iterator aWireIt(myFace, Standard_False); aWireIt.More(); aWireIt.Next() )
+ {
+ const TopoDS_Shape& aSubSh = aWireIt.Value();
+ if ( aSubSh.ShapeType() != TopAbs_WIRE || ( aSubSh.Orientation() != TopAbs_FORWARD &&
+ aSubSh.Orientation() != TopAbs_REVERSED ) )
+ continue;
+
+ aWireSeq.Append( aWireIt.Value() );
+ }
+
+ // Get number of wires and surface
+ Standard_Integer aNbWires = aWireSeq.Length();
+ Handle(Geom_Surface) aSurface = BRep_Tool::Surface(myFace);
+
+ // Only single wires on conical surfaces are checked
+ if ( aNbWires != 1 || aSurface.IsNull() ||
+ aSurface->DynamicType() != STANDARD_TYPE(Geom_ConicalSurface) )
+ return Standard_False;
+
+ // Get the single wire
+ TopoDS_Wire aSoleWire = TopoDS::Wire( aWireSeq.Value(1) );
+
+ // Check whether this wire is belting the conical surface by period
+ Handle(Geom_ConicalSurface) aConeSurf = Handle(Geom_ConicalSurface)::DownCast(aSurface);
+ Standard_Real aMinLoopU = 0.0, aMaxLoopU = 0.0, aMinLoopV = 0.0, aMaxLoopV = 0.0;
+ Standard_Boolean isUDecrease = Standard_False;
+
+ Standard_Boolean isConicLoop = IsPeriodicConicalLoop(aConeSurf, aSoleWire, Precision(),
+ aMinLoopU, aMaxLoopU,
+ aMinLoopV, aMaxLoopV,
+ isUDecrease);
+
+ if ( !isConicLoop )
+ return Standard_False;
+
+ /* ===============
+ * Retrieve apex
+ * =============== */
+
+ // Get base circle of the conical surface (the circle it was built from)
+ Handle(Geom_Curve) aConeBaseCrv = aConeSurf->VIso(0.0);
+ Handle(Geom_Circle) aConeBaseCirc = Handle(Geom_Circle)::DownCast(aConeBaseCrv);
+
+ // Retrieve conical props
+ Standard_Real aConeBaseR = aConeBaseCirc->Radius();
+ Standard_Real aSemiAngle = aConeSurf->SemiAngle();
+
+ if ( fabs(aSemiAngle) <= Precision::Confusion() )
+ return Standard_False; // Bad surface
+
+ // Find the V parameter of the apex
+ Standard_Real aConeBaseH = aConeBaseR / Sin(aSemiAngle);
+ Standard_Real anApexV = -aConeBaseH;
+
+ // Get apex vertex
+ TopoDS_Vertex anApex = BRepBuilderAPI_MakeVertex( aConeSurf->Apex() );
+
+ // ====================================
+ // Build degenerated edge in the apex
+ // ====================================
+
+ TopoDS_Edge anApexEdge;
+ BRep_Builder aBuilder;
+ aBuilder.MakeEdge(anApexEdge);
+
+ // Check if positional relationship between the initial wire and apex
+ // line in 2D is going to be consistent
+ if ( fabs(anApexV - aMinLoopV) <= Precision() ||
+ fabs(anApexV - aMaxLoopV) <= Precision() ||
+ ( anApexV < aMaxLoopV && anApexV > aMinLoopV ) )
+ return Standard_False;
+
+ Handle(Geom2d_Line) anApexCurve2d;
+
+ // Apex curve below the wire
+ if ( anApexV < aMinLoopV )
+ {
+ anApexCurve2d = new Geom2d_Line( gp_Pnt2d(aMinLoopU, anApexV), gp_Dir2d(1, 0) );
+ if ( !isUDecrease )
+ aSoleWire.Reverse();
+ }
+
+ // Apex curve above the wire
+ if ( anApexV > aMaxLoopV )
+ {
+ anApexCurve2d = new Geom2d_Line( gp_Pnt2d(aMaxLoopU, anApexV), gp_Dir2d(-1, 0) );
+ if ( isUDecrease )
+ aSoleWire.Reverse();
+ }
+
+ // Create degenerated edge & wire for apex
+ aBuilder.UpdateEdge( anApexEdge, anApexCurve2d, myFace, Precision() );
+ aBuilder.Add( anApexEdge, anApex );
+ aBuilder.Add( anApexEdge, anApex.Reversed() );
+ aBuilder.Degenerated(anApexEdge, Standard_True);
+ aBuilder.Range( anApexEdge, 0, fabs(aMaxLoopU - aMinLoopU) );
+ TopoDS_Wire anApexWire = BRepBuilderAPI_MakeWire(anApexEdge);
+
+ // ===============================================================
+ // Finalize the fix building new face and setting up the results
+ // ===============================================================
+
+ // Collect the resulting set of wires
+ TopTools_SequenceOfShape aNewWireSeq;
+ aNewWireSeq.Append(aSoleWire);
+ aNewWireSeq.Append(anApexWire);
+
+ // Assemble new face
+ TopoDS_Face aNewFace = TopoDS::Face( myFace.EmptyCopied() );
+ aNewFace.Orientation(TopAbs_FORWARD);
+ BRep_Builder aFaceBuilder;
+ for ( Standard_Integer i = 1; i <= aNewWireSeq.Length(); i++ )
+ {
+ TopoDS_Wire aNewWire = TopoDS::Wire( aNewWireSeq.Value(i) );
+ aFaceBuilder.Add(aNewFace, aNewWire);
+ }
+ aNewFace.Orientation( myFace.Orientation() );
+
+ // Adjust the resulting state of the healing tool
+ myResult = aNewFace;
+ Context()->Replace(myFace, myResult);
+
+ return Standard_True;
+}