diff --git a/src/BRepLib/BRepLib.cxx b/src/BRepLib/BRepLib.cxx index b956633f1c..a381c6c48c 100644 --- a/src/BRepLib/BRepLib.cxx +++ b/src/BRepLib/BRepLib.cxx @@ -1960,6 +1960,12 @@ public: return aDeriv.Transformed(mySurfaceTrsf); } + gp_Dir Normal() + { + gp_Dir aNormal = mySurfaceProps.Normal(); + return aNormal.Transformed(mySurfaceTrsf); + } + // Calculate principal curvatures, which consist of minimal and maximal normal curvatures and // the directions on the tangent plane (principal direction) where the extremums are reached void Curvature(gp_Dir& thePrincipalDir1, Standard_Real& theCurvature1, @@ -1998,32 +2004,63 @@ private: //purpose : check the angle at the border between two squares. // Two shares should have a shared front edge. //======================================================================= -static GeomAbs_Shape tgtfaces(const TopoDS_Edge& Ed, - const TopoDS_Face& F1, - const TopoDS_Face& F2, - const Standard_Real theAngleTol) +GeomAbs_Shape BRepLib::ContinuityOfFaces(const TopoDS_Edge& theEdge, + const TopoDS_Face& theFace1, + const TopoDS_Face& theFace2, + const Standard_Real theAngleTol) { - Standard_Boolean isSeam = F1.IsEqual(F2); + Standard_Boolean isSeam = theFace1.IsEqual(theFace2); - TopoDS_Edge E = Ed; + TopoDS_Edge anEdgeInFace1, anEdgeInFace2; + Handle(Geom2d_Curve) aCurve1, aCurve2; + + Standard_Real aFirst, aLast; + + if (!theFace1.IsSame (theFace2) && + BRep_Tool::IsClosed (theEdge, theFace1) && + BRep_Tool::IsClosed (theEdge, theFace2)) + { + //Find the edge in the face 1: this edge will have correct orientation + TopoDS_Face aFace1 = theFace1; + aFace1.Orientation (TopAbs_FORWARD); + TopExp_Explorer anExplo (aFace1, TopAbs_EDGE); + for (; anExplo.More(); anExplo.Next()) + { + const TopoDS_Edge& anEdge = TopoDS::Edge (anExplo.Current()); + if (anEdge.IsSame (theEdge)) + { + anEdgeInFace1 = anEdge; + break; + } + } + if (anEdgeInFace1.IsNull()) + return GeomAbs_C0; + + aCurve1 = BRep_Tool::CurveOnSurface (anEdgeInFace1, aFace1, aFirst, aLast); + TopoDS_Face aFace2 = theFace2; + aFace2.Orientation (TopAbs_FORWARD); + anEdgeInFace2 = anEdgeInFace1; + anEdgeInFace2.Reverse(); + aCurve2 = BRep_Tool::CurveOnSurface (anEdgeInFace2, aFace2, aFirst, aLast); + } + else + { + // Obtaining of pcurves of edge on two faces. + anEdgeInFace1 = anEdgeInFace2 = theEdge; + aCurve1 = BRep_Tool::CurveOnSurface (anEdgeInFace1, theFace1, aFirst, aLast); + //For the case of seam edge + if (theFace1.IsSame(theFace2)) + anEdgeInFace2.Reverse(); + aCurve2 = BRep_Tool::CurveOnSurface (anEdgeInFace2, theFace2, aFirst, aLast); + } - // Check if pcurves exist on both faces of edge - Standard_Real aFirst,aLast; - E.Orientation(TopAbs_FORWARD); - Handle(Geom2d_Curve) aCurve1 = BRep_Tool::CurveOnSurface(E, F1, aFirst, aLast); - if(aCurve1.IsNull()) - return GeomAbs_C0; - - if (isSeam) - E.Orientation(TopAbs_REVERSED); - Handle(Geom2d_Curve) aCurve2 = BRep_Tool::CurveOnSurface(E, F2, aFirst, aLast); - if(aCurve2.IsNull()) + if (aCurve1.IsNull() || aCurve2.IsNull()) return GeomAbs_C0; TopLoc_Location aLoc1, aLoc2; - Handle(Geom_Surface) aSurface1 = BRep_Tool::Surface(F1, aLoc1); + Handle(Geom_Surface) aSurface1 = BRep_Tool::Surface (theFace1, aLoc1); const gp_Trsf& aSurf1Trsf = aLoc1.Transformation(); - Handle(Geom_Surface) aSurface2 = BRep_Tool::Surface(F2, aLoc2); + Handle(Geom_Surface) aSurface2 = BRep_Tool::Surface (theFace2, aLoc2); const gp_Trsf& aSurf2Trsf = aLoc2.Transformation(); if (aSurface1->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) @@ -2040,11 +2077,11 @@ static GeomAbs_Shape tgtfaces(const TopoDS_Edge& Ed, return GeomAbs_CN; } - SurfaceProperties aSP1(aSurface1, aSurf1Trsf, aCurve1, F1.Orientation() == TopAbs_REVERSED); - SurfaceProperties aSP2(aSurface2, aSurf2Trsf, aCurve2, F2.Orientation() == TopAbs_REVERSED); + SurfaceProperties aSP1(aSurface1, aSurf1Trsf, aCurve1, theFace1.Orientation() == TopAbs_REVERSED); + SurfaceProperties aSP2(aSurface2, aSurf2Trsf, aCurve2, theFace2.Orientation() == TopAbs_REVERSED); Standard_Real f, l, eps; - BRep_Tool::Range(E,f,l); + BRep_Tool::Range (theEdge,f,l); Extrema_LocateExtPC ext; Handle(BRepAdaptor_Curve) aHC2; @@ -2055,7 +2092,6 @@ static GeomAbs_Shape tgtfaces(const TopoDS_Edge& Ed, const Standard_Real anAngleTol2 = theAngleTol * theAngleTol; gp_Vec aDer1, aDer2; - gp_Vec aNorm1; Standard_Real aSqLen1, aSqLen2; gp_Dir aCrvDir1[2], aCrvDir2[2]; Standard_Real aCrvLen1[2], aCrvLen2[2]; @@ -2083,13 +2119,26 @@ static GeomAbs_Shape tgtfaces(const TopoDS_Edge& Ed, aDer2 = aSP2.Derivative(); aSqLen2 = aDer2.SquareMagnitude(); Standard_Boolean isSmoothSuspect = (aDer1.CrossSquareMagnitude(aDer2) <= anAngleTol2 * aSqLen1 * aSqLen2); + if (isSmoothSuspect) + { + gp_Dir aNormal1 = aSP1.Normal(); + if (theFace1.Orientation() == TopAbs_REVERSED) + aNormal1.Reverse(); + gp_Dir aNormal2 = aSP2.Normal(); + if (theFace2.Orientation() == TopAbs_REVERSED) + aNormal2.Reverse(); + + if (aNormal1 * aNormal2 < 0.) + return GeomAbs_C0; + } + if (!isSmoothSuspect) { // Refine by projection if (aHC2.IsNull()) { // adaptor for pcurve on the second surface - aHC2 = new BRepAdaptor_Curve (E, F2); + aHC2 = new BRepAdaptor_Curve (anEdgeInFace2, theFace2); ext.Initialize(*aHC2, f, l, Precision::PConfusion()); } ext.Perform(aSP1.Value(), u); @@ -2285,9 +2334,8 @@ void BRepLib::EncodeRegularity(TopoDS_Edge& E, BRep_Builder B; if(BRep_Tool::Continuity(E,F1,F2)<=GeomAbs_C0){ try { - GeomAbs_Shape aCont = tgtfaces(E, F1, F2, TolAng); + GeomAbs_Shape aCont = ContinuityOfFaces(E, F1, F2, TolAng); B.Continuity(E,F1,F2,aCont); - } catch(Standard_Failure const&) { diff --git a/src/BRepLib/BRepLib.hxx b/src/BRepLib/BRepLib.hxx index 85d8c6d267..1acb765bfc 100644 --- a/src/BRepLib/BRepLib.hxx +++ b/src/BRepLib/BRepLib.hxx @@ -202,7 +202,14 @@ public: //! orientation to have matter in the solid. Returns //! False if the solid is unOrientable (open or incoherent) Standard_EXPORT static Standard_Boolean OrientClosedSolid (TopoDS_Solid& solid); - + + //! Returns the order of continuity between two faces + //! connected by an edge + Standard_EXPORT static GeomAbs_Shape ContinuityOfFaces(const TopoDS_Edge& theEdge, + const TopoDS_Face& theFace1, + const TopoDS_Face& theFace2, + const Standard_Real theAngleTol); + //! Encodes the Regularity of edges on a Shape. //! Warning: is an angular tolerance, expressed in Rad. //! Warning: If the edges's regularity are coded before, nothing diff --git a/src/ChFi3d/ChFi3d.cxx b/src/ChFi3d/ChFi3d.cxx index d9c03e4d9f..82d87ebd62 100644 --- a/src/ChFi3d/ChFi3d.cxx +++ b/src/ChFi3d/ChFi3d.cxx @@ -134,12 +134,12 @@ ChFiDS_TypeOfConcavity ChFi3d::DefineConnectType(const TopoDS_Edge& E, //function : IsTangentFaces //purpose : //======================================================================= -Standard_Boolean ChFi3d::IsTangentFaces(const TopoDS_Edge& theEdge, - const TopoDS_Face& theFace1, - const TopoDS_Face& theFace2, - const GeomAbs_Shape Order) +Standard_Boolean ChFi3d::IsTangentFaces(const TopoDS_Edge& theEdge, + const TopoDS_Face& theFace1, + const TopoDS_Face& theFace2, + const GeomAbs_Shape theOrder) { - if (Order == GeomAbs_G1 && BRep_Tool::Continuity(theEdge, theFace1, theFace2) != GeomAbs_C0) + if (theOrder == GeomAbs_G1 && BRep_Tool::Continuity(theEdge, theFace1, theFace2) != GeomAbs_C0) return Standard_True; Standard_Real TolC0 = Max(0.001, 1.5*BRep_Tool::Tolerance(theEdge)); @@ -147,15 +147,46 @@ Standard_Boolean ChFi3d::IsTangentFaces(const TopoDS_Edge& theEdge, Standard_Real aFirst; Standard_Real aLast; - // Obtaining of pcurves of edge on two faces. - const Handle(Geom2d_Curve) aC2d1 = BRep_Tool::CurveOnSurface - (theEdge, theFace1, aFirst, aLast); - //For the case of seam edge - TopoDS_Edge EE = theEdge; - if (theFace1.IsSame(theFace2)) - EE.Reverse(); - const Handle(Geom2d_Curve) aC2d2 = BRep_Tool::CurveOnSurface - (EE, theFace2, aFirst, aLast); + Handle(Geom2d_Curve) aC2d1, aC2d2; + + if (!theFace1.IsSame (theFace2) && + BRep_Tool::IsClosed (theEdge, theFace1) && + BRep_Tool::IsClosed (theEdge, theFace2)) + { + //Find the edge in the face 1: this edge will have correct orientation + TopoDS_Edge anEdgeInFace1; + TopoDS_Face aFace1 = theFace1; + aFace1.Orientation (TopAbs_FORWARD); + TopExp_Explorer anExplo (aFace1, TopAbs_EDGE); + for (; anExplo.More(); anExplo.Next()) + { + const TopoDS_Edge& anEdge = TopoDS::Edge (anExplo.Current()); + if (anEdge.IsSame (theEdge)) + { + anEdgeInFace1 = anEdge; + break; + } + } + if (anEdgeInFace1.IsNull()) + return Standard_False; + + aC2d1 = BRep_Tool::CurveOnSurface (anEdgeInFace1, aFace1, aFirst, aLast); + TopoDS_Face aFace2 = theFace2; + aFace2.Orientation (TopAbs_FORWARD); + anEdgeInFace1.Reverse(); + aC2d2 = BRep_Tool::CurveOnSurface (anEdgeInFace1, aFace2, aFirst, aLast); + } + else + { + // Obtaining of pcurves of edge on two faces. + aC2d1 = BRep_Tool::CurveOnSurface (theEdge, theFace1, aFirst, aLast); + //For the case of seam edge + TopoDS_Edge EE = theEdge; + if (theFace1.IsSame(theFace2)) + EE.Reverse(); + aC2d2 = BRep_Tool::CurveOnSurface (EE, theFace2, aFirst, aLast); + } + if (aC2d1.IsNull() || aC2d2.IsNull()) return Standard_False; @@ -186,15 +217,19 @@ Standard_Boolean ChFi3d::IsTangentFaces(const TopoDS_Edge& theEdge, if (i == aNbSamples) aPar = aLast; LocalAnalysis_SurfaceContinuity aCont(aC2d1, aC2d2, aPar, - aSurf1, aSurf2, Order, + aSurf1, aSurf2, theOrder, 0.001, TolC0, 0.1, 0.1, 0.1); if (!aCont.IsDone()) { + if (theOrder == GeomAbs_C2 && + aCont.StatusError() == LocalAnalysis_NullSecondDerivative) + continue; + nbNotDone++; continue; } - if (Order == GeomAbs_G1) + if (theOrder == GeomAbs_G1) { if (!aCont.IsG1()) return Standard_False; diff --git a/src/ShapeUpgrade/ShapeUpgrade_UnifySameDomain.cxx b/src/ShapeUpgrade/ShapeUpgrade_UnifySameDomain.cxx index f9185088b2..bd314351b5 100644 --- a/src/ShapeUpgrade/ShapeUpgrade_UnifySameDomain.cxx +++ b/src/ShapeUpgrade/ShapeUpgrade_UnifySameDomain.cxx @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -1212,7 +1213,31 @@ static Standard_Boolean GetNormalToSurface(const TopoDS_Face& theFace, { Standard_Real f, l; // get 2d curve to get point in 2d - const Handle(Geom2d_Curve)& aC2d = BRep_Tool::CurveOnSurface(theEdge, theFace, f, l); + Handle(Geom2d_Curve) aC2d; + if (BRep_Tool::IsClosed(theEdge, theFace)) + { + //Find the edge in the face: it will have correct orientation + TopoDS_Edge anEdgeInFace; + TopoDS_Face aFace = theFace; + aFace.Orientation (TopAbs_FORWARD); + TopExp_Explorer anExplo (aFace, TopAbs_EDGE); + for (; anExplo.More(); anExplo.Next()) + { + const TopoDS_Edge& anEdge = TopoDS::Edge (anExplo.Current()); + if (anEdge.IsSame (theEdge)) + { + anEdgeInFace = anEdge; + break; + } + } + if (anEdgeInFace.IsNull()) + return Standard_False; + + aC2d = BRep_Tool::CurveOnSurface (anEdgeInFace, aFace, f, l); + } + else + aC2d = BRep_Tool::CurveOnSurface(theEdge, theFace, f, l); + if (aC2d.IsNull()) { return Standard_False; } @@ -2965,29 +2990,107 @@ void ShapeUpgrade_UnifySameDomain::IntUnifyFaces(const TopoDS_Shape& theInpShape TopTools_IndexedDataMapOfShapeListOfShape VEmap; for (Standard_Integer ind = 1; ind <= edges.Length(); ind++) TopExp::MapShapesAndUniqueAncestors(edges(ind), TopAbs_VERTEX, TopAbs_EDGE, VEmap); + + //Try to find seam edge and an edge that is not seam but has 2 pcurves on the surface + Standard_Boolean SeamFound = Standard_False; + TopoDS_Edge EdgeWith2pcurves; + for (Standard_Integer ii = 1; ii <= faces.Length(); ii++) + { + const TopoDS_Face& face_ii = TopoDS::Face(faces(ii)); + TopoDS_Wire anOuterWire = BRepTools::OuterWire(face_ii); + TopoDS_Iterator itw(anOuterWire); + for (; itw.More(); itw.Next()) + { + const TopoDS_Edge& anEdge = TopoDS::Edge(itw.Value()); + if (BRep_Tool::IsClosed (anEdge, face_ii)) + { + if (BRepTools::IsReallyClosed(anEdge, face_ii)) + SeamFound = Standard_True; + else + EdgeWith2pcurves = anEdge; + } + } + } + + Standard_Boolean aIsEdgeWith2pcurvesSmooth = Standard_False; + if (myConcatBSplines && !EdgeWith2pcurves.IsNull() && !SeamFound) + { + const TopTools_ListOfShape& aFaceList = theGMapEdgeFaces.FindFromKey (EdgeWith2pcurves); + const TopoDS_Face& aFace1 = TopoDS::Face (aFaceList.First()); + const TopoDS_Face& aFace2 = TopoDS::Face (aFaceList.Last()); + GeomAbs_Shape anOrderOfCont = BRepLib::ContinuityOfFaces (EdgeWith2pcurves, + aFace1, aFace2, + myAngTol); + aIsEdgeWith2pcurvesSmooth = (anOrderOfCont >= GeomAbs_G1); + } + + if (aIsEdgeWith2pcurvesSmooth) + { + Handle(Geom2d_Curve) aPC1, aPC2; + Standard_Real aFirst, aLast; + aPC1 = BRep_Tool::CurveOnSurface (EdgeWith2pcurves, F_RefFace, aFirst, aLast); + EdgeWith2pcurves.Reverse(); + aPC2 = BRep_Tool::CurveOnSurface (EdgeWith2pcurves, F_RefFace, aFirst, aLast); + gp_Pnt2d aPnt1 = aPC1->Value (aFirst); + gp_Pnt2d aPnt2 = aPC2->Value (aFirst); + Standard_Boolean anIsUclosed = (Abs(aPnt1.X() - aPnt2.X()) > Abs(aPnt1.Y() - aPnt2.Y())); + Standard_Boolean aToMakeUPeriodic = Standard_False, aToMakeVPeriodic = Standard_False; + if (anIsUclosed && Uperiod == 0.) + aToMakeUPeriodic = Standard_True; + if (!anIsUclosed && Vperiod == 0.) + aToMakeVPeriodic = Standard_True; + + if (aToMakeUPeriodic || aToMakeVPeriodic) + { + Handle(Geom_BSplineSurface) aBSplineSurface = Handle(Geom_BSplineSurface)::DownCast(aBaseSurface); + if (aBSplineSurface.IsNull()) + { + Standard_Real aTol = 1.e-4; + GeomAbs_Shape aUCont = GeomAbs_C1, aVCont = GeomAbs_C1; + Standard_Integer degU = 14, degV = 14; + Standard_Integer nmax = 16; + Standard_Integer aPrec = 1; + GeomConvert_ApproxSurface Approximator(aBaseSurface,aTol,aUCont,aVCont,degU,degV,nmax,aPrec); + aBSplineSurface = Approximator.Surface(); + } + + if (aToMakeUPeriodic) + { + aBSplineSurface->SetUPeriodic(); + Uperiod = aBSplineSurface->UPeriod(); + } + if (aToMakeVPeriodic) + { + aBSplineSurface->SetVPeriodic(); + Vperiod = aBSplineSurface->VPeriod(); + } + + //Update ref face and pcurves if the surface changed + if (aBSplineSurface != aBaseSurface) + { + TopoDS_Face OldRefFace = RefFace; + Handle(Geom2d_Curve) NullPCurve; + RefFace.Nullify(); + BB.MakeFace(RefFace, aBSplineSurface, aBaseLocation, 0.); + for (Standard_Integer ii = 1; ii <= edges.Length(); ii++) + { + TopoDS_Edge anEdge = TopoDS::Edge(edges(ii)); + Handle(Geom2d_Curve) aPCurve = BRep_Tool::CurveOnSurface (anEdge, OldRefFace, aFirst, aLast); + if (MapEdgesWithTemporaryPCurves.Contains(anEdge)) + BB.UpdateEdge(anEdge, NullPCurve, OldRefFace, 0.); + BB.UpdateEdge(anEdge, aPCurve, RefFace, 0.); + } + F_RefFace = RefFace; + F_RefFace.Orientation(TopAbs_FORWARD); + } + } + } //if (myConcatBSplines && !EdgeWith2pcurves.IsNull() && !SeamFound) //Perform relocating to new U-origin //Define boundaries in 2d space of RefFace if (Uperiod != 0.) { - //try to find a real seam edge - if it exists, do nothing - Standard_Boolean SeamFound = Standard_False; - for (Standard_Integer ii = 1; ii <= faces.Length(); ii++) - { - const TopoDS_Face& face_ii = TopoDS::Face(faces(ii)); - TopoDS_Wire anOuterWire = BRepTools::OuterWire(face_ii); - TopoDS_Iterator itw(anOuterWire); - for (; itw.More(); itw.Next()) - { - const TopoDS_Edge& anEdge = TopoDS::Edge(itw.Value()); - if (BRepTools::IsReallyClosed(anEdge, face_ii)) - { - SeamFound = Standard_True; - break; - } - } - } - + //if seam edge exists, do nothing if (!SeamFound) { //try to find the origin of U in 2d space diff --git a/tests/bugs/heal/bug29382 b/tests/bugs/heal/bug29382_1 similarity index 100% rename from tests/bugs/heal/bug29382 rename to tests/bugs/heal/bug29382_1 diff --git a/tests/bugs/heal/bug29382_2 b/tests/bugs/heal/bug29382_2 new file mode 100644 index 0000000000..e9a6d47353 --- /dev/null +++ b/tests/bugs/heal/bug29382_2 @@ -0,0 +1,24 @@ +puts "================================================================================" +puts "OCC29382: ShapeUpgrade_UnifySameDomain algorithm incorrectly processes the shape" +puts "================================================================================" +puts "" + +restore [locate_data_file bug29382_Group_3.brep] a + +unifysamedom result a +b + +checkshape result +checkshape a + +checknbshapes result -solid 3 -shell 3 -face 16 -wire 16 -edge 30 -vertex 18 + +set tolres [checkmaxtol result] + +if { ${tolres} > 1.8066863810061599e-05} { + puts "Error: bad tolerance of result" +} + +explode result +checkprops result_1 -v 4.41996e-06 +checkprops result_2 -v 1.30453e-06 +checkprops result_3 -v 1.16532e-06 diff --git a/tests/bugs/heal/bug29382_3 b/tests/bugs/heal/bug29382_3 new file mode 100644 index 0000000000..6fcd5a6f57 --- /dev/null +++ b/tests/bugs/heal/bug29382_3 @@ -0,0 +1,24 @@ +puts "================================================================================" +puts "OCC29382: ShapeUpgrade_UnifySameDomain algorithm incorrectly processes the shape" +puts "================================================================================" +puts "" + +beziercurve a 5 0 0 0 1 0 0 2 2 0 0 0.5 0 0 0 0 +mkedge a a +wire a a +mkplane a a +prism a a 0 0 1 +box b -0.3 -0.2 0 1 0.4 1 +bcommon shape a b + +unifysamedom result shape +b + +checkshape result + +checknbshapes result -solid 1 -shell 1 -face 5 -wire 5 -edge 9 -vertex 5 + +set tolres [checkmaxtol result] + +if { ${tolres} > 6.e-6} { + puts "Error: bad tolerance of result" +}