diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 723e84cc4a..aba5d2a329 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -3953,6 +3953,130 @@ bool SketchObject::increaseBSplineDegree(int GeoId, int degreeincrement /*= 1*/) return true; } +bool SketchObject::modifyBSplineKnotMultiplicity(int GeoId, int knotIndex, int multiplicityincr) +{ + if (GeoId < 0 || GeoId > getHighestCurveIndex()) + return false; + + if (multiplicityincr == 0) // no change in multiplicity + return true; + + const Part::Geometry *geo = getGeometry(GeoId); + + if(geo->getTypeId() != Part::GeomBSplineCurve::getClassTypeId()) + return false; + + const Part::GeomBSplineCurve *bsp = static_cast(geo); + + int degree = bsp->getDegree(); + + if( knotIndex > bsp->countKnots() || knotIndex < 1 ) // knotindex in OCC 1 -> countKnots + return false; + + Part::GeomBSplineCurve *bspline; + + try { + int curmult = bsp->getMultiplicity(knotIndex); + + if ( (curmult + multiplicityincr) > degree || (curmult + multiplicityincr) < 0) // zero is removing the knot, degree is just positional continuity + return false; + + const Handle_Geom_BSplineCurve curve = Handle_Geom_BSplineCurve::DownCast(bsp->handle()); + + bspline = new Part::GeomBSplineCurve(curve); + + if(multiplicityincr > 0) { // increase multiplicity + bspline->increaseMultiplicity(knotIndex, curmult + multiplicityincr); + } + else { // decrease multiplicity + bool result = bspline->removeKnot(knotIndex, curmult + multiplicityincr); + + if(!result) + return false; + } + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + return false; + } + + // we succeeded with the multiplicity modification, so aligment geometry may be invalid/inconsistent for the new bspline + // If multiplicity is increased, the number of poles is increased. An increase of 1 degree generates one pole extra + + if(multiplicityincr > 0) { + + std::vector poles = bsp->getPoles(); + std::vector newpoles = bspline->getPoles(); + std::vector prevpole(bsp->countPoles()); + + for(int i = 0; i < int(poles.size()); i++) + prevpole[i] = -1; + + int taken = 0; + for(int j = 0; j < int(poles.size()); j++){ + for(int i = taken; i < int(newpoles.size()); i++){ + if( newpoles[i] == poles[j] ) { + prevpole[j] = i; + taken++; + break; + } + } + } + + const std::vector< Sketcher::Constraint * > &cvals = Constraints.getValues(); + + std::vector< Constraint * > newcVals(cvals); + + // modify pole constraints + for (std::vector< Sketcher::Constraint * >::iterator it= newcVals.begin(); it != newcVals.end(); ++it) { + if((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId) + { + if((*it)->AlignmentType == Sketcher::BSplineControlPoint && prevpole[(*it)->InternalAlignmentIndex]!=-1) { + (*it)->InternalAlignmentIndex = prevpole[(*it)->InternalAlignmentIndex]; + } + } + } + + this->Constraints.setValues(newcVals); + } + else { + return false; + } + + // * DOCUMENTING OCC ISSUE + // When bspline is assigned below in newVals[GeoId] = bspline, when sketch.cpp updateGeometry executes this: + // + // point->setPoint(bsp->pointAtParameter(knots[index])); + // + // A segmentation fault is generated: + //Program received signal SIGSEGV, Segmentation fault. + //#0 /lib/x86_64-linux-gnu/libc.so.6(+0x36cb0) [0x7f4b933bbcb0] + //#1 0x7f4b0300ea14 in BSplCLib::BuildCache(double, double, bool, int, TColStd_Array1OfReal const&, TColgp_Array1OfPnt const&, TColStd_Array1OfReal const&, TColgp_Array1OfPnt&, TColStd_Array1OfReal&) from /usr/lib/x86_64-linux-gnu/libTKMath.so.10+0x484 + //#2 0x7f4b033f9582 in Geom_BSplineCurve::ValidateCache(double) from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0x202 + //#3 0x7f4b033f2a7e in Geom_BSplineCurve::D0(double, gp_Pnt&) const from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0xde + //#4 0x7f4b033de1b5 in Geom_Curve::Value(double) const from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0x25 + //#5 0x7f4b03423d73 in GeomLProp_CurveTool::Value(Handle_Geom_Curve const&, double, gp_Pnt&) from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0x13 + //#6 0x7f4b03427175 in GeomLProp_CLProps::SetParameter(double) from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0x75 + //#7 0x7f4b0342727d in GeomLProp_CLProps::GeomLProp_CLProps(Handle_Geom_Curve const&, double, int, double) from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0xcd + //#8 0x7f4b11924b53 in Part::GeomCurve::pointAtParameter(double) const from /home/abdullah/github/freecad-build/Mod/Part/Part.so+0xa7 + + Part::GeomBSplineCurve * tbspline = new Part::GeomBSplineCurve( bspline->getPoles(), bspline->getWeights(), bspline->getKnots(), bspline->getMultiplicities(), + bspline->getDegree(), bspline->isPeriodic()); + + const std::vector< Part::Geometry * > &vals = getInternalGeometry(); + + std::vector< Part::Geometry * > newVals(vals); + + newVals[GeoId] = tbspline; + + Geometry.setValues(newVals); + Constraints.acceptGeometry(getCompleteGeometry()); + rebuildVertexIndex(); + + return true; + +} + int SketchObject::addExternal(App::DocumentObject *Obj, const char* SubName) { // so far only externals to the support of the sketch and datum features diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index 9a8e5f961b..81d076d111 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -211,6 +211,15 @@ public: \retval bool - returns true if the increase in degree succeeded, or false if it did not succeed. */ bool increaseBSplineDegree(int GeoId, int degreeincrement = 1); + + /*! + \ brief Increases or Decreases the multiplicity of a BSpline knot by the multiplicityincr param, which defaults to 1, if the result is multiplicity zero, the knot is removed + \param GeoId - the geometry of type bspline to increase the degree + \param knotIndex - the index of the knot to modify (note that index is OCC consistent, so 1<=knotindex<=knots) + \param multiplicityincr - the increment (positive value) or decrement (negative value) of multiplicity of the knot + \retval bool - returns true if the operation succeeded, or false if it did not succeed. + */ + bool modifyBSplineKnotMultiplicity(int GeoId, int knotIndex, int multiplicityincr = 1); /// retrieves for a Vertex number the corresponding GeoId and PosId void getGeoVertexIndex(int VertexId, int &GeoId, PointPos &PosId) const;