From: msv Date: Tue, 24 Oct 2017 12:01:49 +0000 (+0300) Subject: 0029257: GeomPlate generates surface in unexpected place X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=07045ddcf578c83701477d7d166ab5f2dd95f3fb;p=occt-copy.git 0029257: GeomPlate generates surface in unexpected place Treatment of the parameter EnlargeCoeff in the constructor of GeomPlate_MakeApprox has been corrected. Now the bounds of the result surface are correctly enlarged. The new draw command 'pullupface' has been implemented to check behavior of GeomPlate. --- diff --git a/src/BRepTest/BRepTest_FillingCommands.cxx b/src/BRepTest/BRepTest_FillingCommands.cxx index 7bead0b63e..74bc9d5836 100644 --- a/src/BRepTest/BRepTest_FillingCommands.cxx +++ b/src/BRepTest/BRepTest_FillingCommands.cxx @@ -42,6 +42,8 @@ #include #include #include +#include +#include #include #include #include @@ -64,12 +66,15 @@ #include #include #include +#include +#include #include #include #include #include #include +#include #include #include @@ -92,6 +97,7 @@ #include #include #include +#include #include #include #include @@ -694,7 +700,311 @@ static Standard_Integer fillingparam( Draw_Interpretor & di, Standard_Integer n, } +//======================================================================= +//function : addPointsOnCurveOnSurfaceConstraints +//purpose : +//======================================================================= +static void addPointsOnCurveOnSurfaceConstraints(GeomPlate_BuildPlateSurface& thePlate, + const TopoDS_Edge &theEdge, + const TopoDS_Face &theFace, + const TopoDS_Shape& theAvoidEdges, + const Standard_Real theAvoidRadius, + const Standard_Real theStep, + const Standard_Real theTol3d, + const Standard_Real theTolAng, + const Standard_Integer theOrder, + TopoDS_Compound& thePoints) +{ + BRepAdaptor_Curve2d anAC2d(theEdge, theFace); + BRepAdaptor_Curve anAC(theEdge, theFace); + Handle(Geom_Surface) aSurf = BRep_Tool::Surface(theFace); + + // discretize the curve + Standard_Real aLen = GCPnts_AbscissaPoint::Length(anAC); + Standard_Integer npt = Max(2, (Standard_Integer)(aLen / theStep)); + GCPnts_QuasiUniformAbscissa aDiscr(anAC, npt); + if (!aDiscr.IsDone()) + Standard_Failure::Raise("Failure discretization of an edge"); + + // do not take last point to avoid confusion with first point of the next edge + Standard_Integer aBegin = 1, anEnd = aDiscr.NbPoints(); + if (theEdge.Orientation() == TopAbs_FORWARD) + anEnd--; + else + aBegin++; + for (Standard_Integer i = aBegin; i <= anEnd; i++) + { + Standard_Real aCPar = aDiscr.Parameter(i); + gp_Pnt2d aP2d = anAC2d.Value(aCPar); + + // evaluate distance to avoid vertices + gp_Pnt aPnt = aSurf->Value(aP2d.X(), aP2d.Y()); + TopoDS_Vertex aVert = BRepBuilderAPI_MakeVertex(aPnt); + Standard_Real aDist = RealLast(); + if (!theAvoidEdges.IsNull()) + { + BRepExtrema_DistShapeShape aDistSS(theAvoidEdges, aVert); + if (!aDistSS.IsDone()) + Standard_Failure::Raise("Failure computation of distance between edges and vertex"); + aDist = aDistSS.Value(); + } + if (aDist > theAvoidRadius) + { + if (theOrder > 0) + thePlate.Add(new GeomPlate_PointConstraint + (aP2d.X(), aP2d.Y(), aSurf, theOrder, theTol3d, theTolAng)); + else + thePlate.Add(new GeomPlate_PointConstraint(aPnt, 0, theTol3d)); + BRep_Builder().Add(thePoints, aVert); + } + } +} + +//======================================================================= +//function : addPointsOnCurveOnSurfaceConstraints +//purpose : +//======================================================================= +static void addPointsOnSurfaceConstraints(GeomPlate_BuildPlateSurface& thePlate, + const TopoDS_Face& theFace, + const TopoDS_Shape& theAvoidEdges, + const Standard_Real theAvoidRadius, + const Standard_Real theStep, + const Standard_Real theTol3d, + TopoDS_Compound& thePoints) +{ + // make adapted surface with UV bounds + BRepAdaptor_Surface anASurf(theFace, Standard_True); + Standard_Real aU1 = anASurf.FirstUParameter(); + Standard_Real aU2 = anASurf.LastUParameter(); + Standard_Real aV1 = anASurf.FirstVParameter(); + Standard_Real aV2 = anASurf.LastVParameter(); + + // get middle iso lines + Standard_Real aMidU = (aU1 + aU2) * 0.5; + Standard_Real aMidV = (aV1 + aV2) * 0.5; + Handle(Geom_Curve) aUIso = anASurf.Surface().Surface()->UIso(aMidU); + Handle(Geom_Curve) aVIso = anASurf.Surface().Surface()->VIso(aMidV); + + // compute their length to decide which one to discretize + Standard_Real aUIsoLen = GCPnts_AbscissaPoint::Length(GeomAdaptor_Curve(aUIso, aV1, aV2)); + Standard_Real aVIsoLen = GCPnts_AbscissaPoint::Length(GeomAdaptor_Curve(aVIso, aU1, aU2)); + Standard_Boolean isUDiscr = aUIsoLen > aVIsoLen; + + // discretize the longest iso line + Standard_Real aLongPar1 = aV1, aLongPar2 = aV2, anOrtPar1 = aU1, anOrtPar2 = aU2; + if (!isUDiscr) + { + aLongPar1 = aU1; + aLongPar2 = aU2; + anOrtPar1 = aV1; + anOrtPar2 = aV2; + } + GeomAdaptor_Curve anACLongIso(isUDiscr ? aUIso : aVIso); + Standard_Real aLongLen = (isUDiscr ? aUIsoLen : aVIsoLen); + Standard_Integer aLongNpt = Max(3, (Standard_Integer)(aLongLen / theStep)); + GCPnts_QuasiUniformAbscissa aDiscr(anACLongIso, aLongNpt, aLongPar1, aLongPar2); + if (!aDiscr.IsDone()) + Standard_Failure::Raise("Failure discretization of an iso line"); + + // do not take first and last points to avoid confusion with boundary + for (Standard_Integer i = 2; i <= aDiscr.NbPoints() - 1; i++) + { + Standard_Real anIsoPar = aDiscr.Parameter(i); + // get orthogonal iso line at this parameter + Handle(Geom_Curve) anOrtIso = (isUDiscr ? anASurf.Surface().Surface()->VIso(anIsoPar) + : anASurf.Surface().Surface()->UIso(anIsoPar)); + // discretize the ort iso line + GeomAdaptor_Curve anACOrtIso(anOrtIso, anOrtPar1, anOrtPar2); + Standard_Real anOrtLen = GCPnts_AbscissaPoint::Length(anACOrtIso); + Standard_Integer anOrtNpt = Max(3, (Standard_Integer)(anOrtLen / theStep)); + GCPnts_QuasiUniformAbscissa aDiscrOrt(anACOrtIso, anOrtNpt); + if (!aDiscrOrt.IsDone()) + Standard_Failure::Raise("Failure discretization of an iso line"); + + // do not take first and last points to avoid confusion with boundary + for (Standard_Integer j = 2; j <= aDiscrOrt.NbPoints() - 1; j++) + { + Standard_Real anOrtPar = aDiscrOrt.Parameter(j); + gp_Pnt aPnt = anACOrtIso.Value(anOrtPar); + + // evaluate distance between the point and avoid edges + TopoDS_Vertex aVert = BRepBuilderAPI_MakeVertex(aPnt); + BRepExtrema_DistShapeShape aDistSS(theAvoidEdges, aVert); + if (!aDistSS.IsDone()) + Standard_Failure::Raise("Failure computation of distance between edges and vertex"); + Standard_Real aDist = aDistSS.Value(); + if (aDist > theAvoidRadius) + { + thePlate.Add(new GeomPlate_PointConstraint(aPnt, 0, theTol3d)); + BRep_Builder().Add(thePoints, aVert); + } + } + } +} + +//======================================================================= +//function : pullupface +//purpose : +//======================================================================= +static Standard_Integer pullupface(Draw_Interpretor& theDI, + Standard_Integer theArgc, + const char** theArgv) +{ + if (theArgc < 6) + { + cout << "incorrect usage, see help" << endl; + return 1; + } + TopoDS_Face aFace = TopoDS::Face(DBRep::Get(theArgv[2], TopAbs_FACE)); + if (aFace.IsNull()) + { + cout << "no such face " << theArgv[2] << endl; + return 1; + } + TopoDS_Shape anOldEdges = DBRep::Get(theArgv[3]); + if (anOldEdges.IsNull()) + { + cout << "no such shape " << theArgv[3] << endl; + return 1; + } + TopoDS_Shape aNewEdges = DBRep::Get(theArgv[4]); + if (aNewEdges.IsNull()) + { + cout << "no such shape " << theArgv[4] << endl; + return 1; + } + TopoDS_Face anOtherFace = TopoDS::Face(DBRep::Get(theArgv[5], TopAbs_FACE)); + if (anOtherFace.IsNull()) + { + cout << "no such face " << theArgv[5] << endl; + return 1; + } + + Standard_Real aModifRadius = 0.1; + Standard_Integer anOrder = 1, aDegree = 3; + Standard_Real aTol2d = 0.00001, aTol3d = 0.0001, aTolAng = 0.01; + Standard_Real aStep = 0.1, anEnlargeCoeff = 1.01; + Standard_Integer anAppDegree = 8, anAppSegments = 9; + Standard_Boolean bAddInner = Standard_False, bAddBnd = Standard_False; + Standard_Boolean isOutputPnts = Standard_False; + for (Standard_Integer i = 6; i < theArgc; i++) + { + if (strcmp(theArgv[i], "-mr") == 0) + aModifRadius = Draw::Atof(theArgv[++i]); + else if (strcmp(theArgv[i], "-order") == 0) + anOrder = Draw::Atoi(theArgv[++i]); + else if (strcmp(theArgv[i], "-deg") == 0) + aDegree = Draw::Atoi(theArgv[++i]); + else if (strcmp(theArgv[i], "-step") == 0) + aStep = Draw::Atof(theArgv[++i]); + else if (strcmp(theArgv[i], "-tol2d") == 0) + aTol2d = Draw::Atof(theArgv[++i]); + else if (strcmp(theArgv[i], "-tol3d") == 0) + aTol3d = Draw::Atof(theArgv[++i]); + else if (strcmp(theArgv[i], "-tolang") == 0) + aTolAng = Draw::Atof(theArgv[++i]); + else if (strcmp(theArgv[i], "-appdeg") == 0) + anAppDegree = Draw::Atoi(theArgv[++i]); + else if (strcmp(theArgv[i], "-appsegs") == 0) + anAppSegments = Draw::Atoi(theArgv[++i]); + else if (strcmp(theArgv[i], "-enlarge") == 0) + anEnlargeCoeff = Draw::Atof(theArgv[++i]); + else if (strcmp(theArgv[i], "-inner") == 0) + bAddInner = Standard_True; + else if (strcmp(theArgv[i], "-bnd") == 0) + bAddBnd = Standard_True; + else if (strcmp(theArgv[i], "-pnts") == 0) + isOutputPnts = Standard_True; + else + { + cout << "invalid option " << theArgv[i] << endl; + return 1; + } + } + + // Init plate builder + Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace); + Standard_Real aU1, aU2, aV1, aV2; + BRepTools::UVBounds(aFace, aU1, aU2, aV1, aV2); + aSurf = new Geom_RectangularTrimmedSurface(aSurf, aU1, aU2, aV1, aV2); + Standard_Integer aNbIter = 1, aNbPtsOnCur = 10; + GeomPlate_BuildPlateSurface aPlate(aDegree, aNbPtsOnCur, aNbIter, aTol2d, aTol3d, aTolAng); + aPlate.LoadInitSurface(aSurf); + + TopTools_IndexedMapOfShape anOldEMap; + TopExp::MapShapes(anOldEdges, TopAbs_EDGE, anOldEMap); + + TopoDS_Compound aPoints; + BRep_Builder().MakeCompound(aPoints); + + if (bAddBnd) + { + // Add face boundary constraints + for (TopExp_Explorer ex(aFace, TopAbs_EDGE); ex.More(); ex.Next()) + { + TopoDS_Edge aE = TopoDS::Edge(ex.Current()); + if (anOldEMap.Contains(aE)) + { + // edge to be replaced, skip it + continue; + } + TopoDS_Vertex aV1, aV2; + TopExp::Vertices(aE, aV1, aV2); + addPointsOnCurveOnSurfaceConstraints(aPlate, aE, aFace, anOldEdges, aModifRadius, + aStep, aTol3d, aTolAng, anOrder, aPoints); + } + } + + // add constraints of the replaced edges + for (TopExp_Explorer ex(aNewEdges, TopAbs_EDGE); ex.More(); ex.Next()) + { + TopoDS_Edge aE = TopoDS::Edge(ex.Current()); + //addPointsOnCurveConstraints(aPlate, aE, aStep, aTol3d, aPoints); + addPointsOnCurveOnSurfaceConstraints(aPlate, aE, anOtherFace, TopoDS_Shape(), 0., + aStep, aTol3d, aTolAng, anOrder, aPoints); + } + + if (bAddInner) + { + // add face inner constraints + addPointsOnSurfaceConstraints(aPlate, aFace, anOldEdges, aModifRadius, aStep, aTol3d, aPoints); + } + + if (isOutputPnts) + { + DBRep::Set("pnts", aPoints); + theDI << "compound pnts is drawn\n"; + } + + // perform plate + aPlate.Perform(); + if (!aPlate.IsDone()) + { + theDI << "plate is not done"; + return 0; + } + + // build plate surface + Handle(GeomPlate_Surface) aPlateSurf = aPlate.Surface(); + Standard_Real aDMax = Max(aTol3d, 10. * aPlate.G0Error()); + TColgp_SequenceOfXY aS2d; + TColgp_SequenceOfXYZ aS3d; + aPlate.Disc2dContour(4, aS2d); + aPlate.Disc3dContour(4, 0, aS3d); + GeomPlate_PlateG0Criterion aCriterion(aS2d, aS3d, aDMax); + GeomPlate_MakeApprox anApprox(aPlateSurf, aCriterion, aTol3d, + anAppSegments, anAppDegree, GeomAbs_C1, anEnlargeCoeff); + Handle(Geom_BSplineSurface) aNewSurf = anApprox.Surface(); + + // make new face + BRepBuilderAPI_MakeFace aFMaker(aNewSurf, Precision::Confusion()); + TopoDS_Face aNewFace = aFMaker.Face(); + + DBRep::Set(theArgv[1], aNewFace); + theDI << "Done"; + return 0; +} void BRepTest::FillingCommands(Draw_Interpretor& theCommands) { @@ -738,4 +1048,21 @@ void BRepTest::FillingCommands(Draw_Interpretor& theCommands) fillingparam, g) ; + theCommands.Add("pullupface", + "result face old_edges new_edges modif_face [options]\n" + "\t\tPull up the surface to new replacement edges. Options:\n" + "\t\t-mr val Modification radius [default 0.1]\n" + "\t\t-bnd Use face boundary constraints\n" + "\t\t-inner Use face inner points constraints\n" + "\t\t-step val Step of discretization [0.1]\n" + "\t\t-order val Order of continuity of point constraints (0/1) [1]\n" + "\t\t-deg val Degree of resolution for Plate (>=2) [3]\n" + "\t\t-pnts Output point constraints in the compound of vertices pnts\n" + "\t\t-tol2d val Tolerance to compare points in space of initial surface [1e-5]\n" + "\t\t-tol3d val Tolerance to compare points in 3d space [1e-4]\n" + "\t\t-tolang val Tolerance to compare normals of two points [1e-2]\n" + "\t\t-appdeg val Maximal degree for approximation of the surface [8]\n" + "\t\t-appsegs val Maximal number of bezier pieces in output surface [9]" + "\t\t-enlarge val Enlarge coefficient to extend boundaries of result surface [1.01]", + __FILE__, pullupface, g); } diff --git a/src/GeomPlate/GeomPlate_MakeApprox.cxx b/src/GeomPlate/GeomPlate_MakeApprox.cxx index dc53d80cf4..92404a74ac 100644 --- a/src/GeomPlate/GeomPlate_MakeApprox.cxx +++ b/src/GeomPlate/GeomPlate_MakeApprox.cxx @@ -257,10 +257,12 @@ GeomPlate_MakeApprox::GeomPlate_MakeApprox(const Handle(GeomPlate_Surface)& Surf Standard_Real U0=0., U1=0., V0=0., V1=0.; myPlate->RealBounds(U0, U1, V0, V1); - U0 = EnlargeCoeff * U0; - U1 = EnlargeCoeff * U1; - V0 = EnlargeCoeff * V0; - V1 = EnlargeCoeff * V1; + Standard_Real aDU = (U1 - U0) * (EnlargeCoeff - 1); + Standard_Real aDV = (V1 - V0) * (EnlargeCoeff - 1); + U0 = U0 - aDU; + U1 = U1 + aDU; + V0 = V0 - aDV; + V1 = V1 + aDV; Standard_Integer nb1 = 0, nb2 = 0, nb3 = 1; Handle(TColStd_HArray1OfReal) nul1 = @@ -351,10 +353,12 @@ GeomPlate_MakeApprox::GeomPlate_MakeApprox(const Handle(GeomPlate_Surface)& Surf Standard_Real U0=0., U1=0., V0=0., V1=0.; myPlate->RealBounds(U0, U1, V0, V1); - U0 = EnlargeCoeff * U0; - U1 = EnlargeCoeff * U1; - V0 = EnlargeCoeff * V0; - V1 = EnlargeCoeff * V1; + Standard_Real aDU = (U1 - U0) * (EnlargeCoeff - 1); + Standard_Real aDV = (V1 - V0) * (EnlargeCoeff - 1); + U0 = U0 - aDU; + U1 = U1 + aDU; + V0 = V0 - aDV; + V1 = V1 + aDV; Standard_Real seuil = Tol3d; if (CritOrder==0&&Tol3d<10*dmax) { diff --git a/tests/bugs/modalg_7/bug29257_1 b/tests/bugs/modalg_7/bug29257_1 new file mode 100644 index 0000000000..58b77b0ebf --- /dev/null +++ b/tests/bugs/modalg_7/bug29257_1 @@ -0,0 +1,61 @@ +puts "========" +puts "OCC29257" +puts "========" +puts "" +################################################# +# GeomPlate generates surface in unexpected place +################################################# + +set MaxDist 0.05 + +restore [locate_data_file bug29257_plate_26_307.brep] a +explode a + +# numbers of edges in a_1 to be replaced +set old_edges_num {3} + +# get modified surface from a_2 +mksurface su a_2 + +# create compounds of old edges and their replacements new edges +shape old_edges C +shape new_edges C + +foreach i $old_edges_num { + # get old edge and its curve 3d + subshape a_1 e $i + mkcurve c a_1_$i + + # project it on modified surface, result is curve 2d + project cp c su -t 1e-2 + + # create 3d curve of projection + approxcurveonsurf ca cp su + + # make new edge with pcurve + mkedge e ca + addpcurve e cp a_2 + + add a_1_$i old_edges + add e new_edges +} +don a_1 new_edges + +# compute plate surface +pullupface r a_1 old_edges new_edges a_2 -bnd -order 1 -mr 0.4 -step 0.4 -deg 3 -enlarge 1.1 + +checkprops r -s 341.201 + +# check distance from vertices of the initial face to the new face +foreach v [explode a_1 v] { + distmini d $v r + set dist [dval d_val] + if {$dist > $MaxDist} { + puts "Error: distance from vertex $v to the result is $dist, which is > $MaxDist" + } +} + +smallview +don r a_1 +fit +checkview -screenshot -2d -path ${imagedir}/${test_image}_1.png diff --git a/tests/bugs/modalg_7/bug29257_2 b/tests/bugs/modalg_7/bug29257_2 new file mode 100644 index 0000000000..0dd46e8ae6 --- /dev/null +++ b/tests/bugs/modalg_7/bug29257_2 @@ -0,0 +1,61 @@ +puts "========" +puts "OCC29257" +puts "========" +puts "" +################################################# +# GeomPlate generates surface in unexpected place +################################################# + +set MaxDist 0.1 + +restore [locate_data_file bug29257_plate_8_3.brep] a +explode a + +# numbers of edges in a_1 to be replaced +set old_edges_num {2} + +# get modified surface from a_2 +mksurface su a_2 + +# create compounds of old edges and their replacements new edges +shape old_edges C +shape new_edges C + +foreach i $old_edges_num { + # get old edge and its curve 3d + subshape a_1 e $i + mkcurve c a_1_$i + + # project it on modified surface, result is curve 2d + project cp c su -t 1e-2 + + # create 3d curve of projection + approxcurveonsurf ca cp su + + # make new edge with pcurve + mkedge e ca + addpcurve e cp a_2 + + add a_1_$i old_edges + add e new_edges +} +don a_1 new_edges + +# compute plate surface +pullupface r a_1 old_edges new_edges a_2 -bnd -order 1 -mr 0.4 -step 0.2 -deg 3 -enlarge 1.1 + +checkprops r -s 10.5986 + +# check distance from vertices of the initial face to the new face +foreach v [explode a_1 v] { + distmini d $v r + set dist [dval d_val] + if {$dist > $MaxDist} { + puts "Error: distance from vertex $v to the result is $dist, which is > $MaxDist" + } +} + +smallview +don r a_1 +fit +checkview -screenshot -2d -path ${imagedir}/${test_image}_1.png