From 6d0c845208785182bee7a72439d8e2728bee9f84 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Thu, 18 Feb 2021 16:09:07 +0100 Subject: [PATCH] Part: Geometry - BSpline - fix weight assignment ================================================ If during assignment of weights (during the for loop iteratively setting the poles) all weights become (temporarily) equal even though weights does not have equal values OCCT will convert all the weights (the already assigned and those not yet assigned) to 1.0 (nonrational b-splines have 1.0 weights). This may lead to the assignment of wrong of weight values. The work-around is to temporarily set the last weight to be assigned to a value different from the current value and the to-be-assigned value for the weight at position last-to-be-assign but one. Fixes: https://forum.freecadweb.org/viewtopic.php?p=478701#p478702 --- src/Mod/Part/App/Geometry.cpp | 27 +++++++++++++++++++++++++-- src/Mod/Part/App/Geometry.h | 10 ++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp index 43087c5b7e..2f86b87185 100644 --- a/src/Mod/Part/App/Geometry.cpp +++ b/src/Mod/Part/App/Geometry.cpp @@ -1186,15 +1186,36 @@ void GeomBSplineCurve::setPole(int index, const Base::Vector3d& pole, double wei } } +void GeomBSplineCurve::workAroundOCCTBug(const std::vector& weights) +{ + // If during assignment of weights (during the for loop below) all weights + // become (temporarily) equal even though weights does not have equal values + // OCCT will convert all the weights (the already assigned and those not yet assigned) + // to 1.0 (nonrational b-splines have 1.0 weights). This may lead to the assignment of wrong + // of weight values. + // + // Little hack is to set the last weight to a value different from last but one current and to-be-assigned + + if (weights.size() < 2) // at least two poles/weights + return; + + auto lastindex = myCurve->NbPoles(); // OCCT is base-1 + auto lastbutonevalue = myCurve->Weight(lastindex-1); + double fakelastvalue = lastbutonevalue + weights[weights.size()-2]; + myCurve->SetWeight(weights.size(),fakelastvalue); +} + void GeomBSplineCurve::setPoles(const std::vector& poles, const std::vector& weights) { if (poles.size() != weights.size()) throw Base::ValueError("poles and weights mismatch"); + workAroundOCCTBug(weights); + Standard_Integer index=1; - for (std::size_t it = 0; it < poles.size(); it++, index++) { - setPole(index, poles[it], weights[it]); + for (std::size_t i = 0; i < poles.size(); i++, index++) { + setPole(index, poles[i], weights[i]); } } @@ -1237,6 +1258,8 @@ std::vector GeomBSplineCurve::getWeights() const void GeomBSplineCurve::setWeights(const std::vector& weights) { + workAroundOCCTBug(weights); + try { Standard_Integer index=1; diff --git a/src/Mod/Part/App/Geometry.h b/src/Mod/Part/App/Geometry.h index d52d09fa40..b1f9568298 100644 --- a/src/Mod/Part/App/Geometry.h +++ b/src/Mod/Part/App/Geometry.h @@ -324,6 +324,16 @@ private: bool calculateBiArcPoints(const gp_Pnt& p0, gp_Vec v_start, const gp_Pnt& p4, gp_Vec v_end, gp_Pnt& p1, gp_Pnt& p2, gp_Pnt& p3) const; + + // If during assignment of weights (during the for loop iteratively setting the poles) all weights + // become (temporarily) equal even though weights does not have equal values + // OCCT will convert all the weights (the already assigned and those not yet assigned) + // to 1.0 (nonrational b-splines have 1.0 weights). This may lead to the assignment of wrong + // of weight values. + // + // The work-around is to temporarily set the last weight to be assigned to a value different from + // the current value and the to-be-assigned value for the weight at position last-to-be-assign but one. + void workAroundOCCTBug(const std::vector& weights); private: Handle(Geom_BSplineCurve) myCurve; };