diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index eb17c2ae6d..386166ef9e 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -7349,38 +7349,43 @@ bool SketchObject::insertBSplineKnot(int GeoId, double param, int multiplicity) Base::StateLocker lock(managedoperation, true); // handling unacceptable cases - if (GeoId < 0 || GeoId > getHighestCurveIndex()) + if (GeoId < 0 || GeoId > getHighestCurveIndex()) { THROWMT( Base::ValueError, QT_TRANSLATE_NOOP("Exceptions", "B-spline Geometry Index (GeoID) is out of bounds.")); + } - if (multiplicity == 0) + if (multiplicity == 0) { THROWMT(Base::ValueError, QT_TRANSLATE_NOOP("Exceptions", "Knot cannot have zero multiplicity.")); + } const Part::Geometry* geo = getGeometry(GeoId); - if (geo->getTypeId() != Part::GeomBSplineCurve::getClassTypeId()) + if (!geo->is()) { THROWMT(Base::TypeError, QT_TRANSLATE_NOOP("Exceptions", "The Geometry Index (GeoId) provided is not a B-spline.")); + } - const Part::GeomBSplineCurve* bsp = static_cast(geo); + const auto* bsp = static_cast(geo); int degree = bsp->getDegree(); double firstParam = bsp->getFirstParameter(); double lastParam = bsp->getLastParameter(); - if (multiplicity > degree) + if (multiplicity > degree) { THROWMT(Base::ValueError, QT_TRANSLATE_NOOP( "Exceptions", "Knot multiplicity cannot be higher than the degree of the B-spline.")); + } - if (param > lastParam || param < firstParam) + if (param > lastParam || param < firstParam) { THROWMT(Base::ValueError, QT_TRANSLATE_NOOP("Exceptions", "Knot cannot be inserted outside the B-spline parameter range.")); + } std::unique_ptr bspline; @@ -7400,89 +7405,64 @@ bool SketchObject::insertBSplineKnot(int GeoId, double param, int multiplicity) std::vector poles = bsp->getPoles(); std::vector newpoles = bspline->getPoles(); - std::vector prevpole(bsp->countPoles()); + std::vector poleIndexInNew(poles.size(), -1); - 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; - } - } + for (size_t j = 0; j < poles.size(); j++) { + const auto it = std::find(newpoles.begin(), newpoles.end(), poles[j]); + poleIndexInNew[j] = it - newpoles.begin(); } - // on fully removing a knot the knot geometry changes std::vector knots = bsp->getKnots(); std::vector newknots = bspline->getKnots(); - std::vector prevknot(bsp->countKnots()); + std::vector knotIndexInNew(knots.size(), -1); - for (int i = 0; i < int(knots.size()); i++) - prevknot[i] = -1; - - taken = 0; - for (int j = 0; j < int(knots.size()); j++) { - for (int i = taken; i < int(newknots.size()); i++) { - if (newknots[i] == knots[j]) { - prevknot[j] = i; - taken++; - break; - } - } + for (size_t j = 0; j < knots.size(); j++) { + const auto it = std::find(newknots.begin(), newknots.end(), knots[j]); + knotIndexInNew[j] = it - newknots.begin(); } const std::vector& cvals = Constraints.getValues(); std::vector newcVals(0); - // modify pole constraints - for (std::vector::const_iterator it = cvals.begin(); it != cvals.end(); - ++it) { - if ((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId) { - if ((*it)->AlignmentType == Sketcher::BSplineControlPoint) { - if (prevpole[(*it)->InternalAlignmentIndex] != -1) { - assert(prevpole[(*it)->InternalAlignmentIndex] < bspline->countPoles()); - Constraint* newConstr = (*it)->clone(); - newConstr->InternalAlignmentIndex = prevpole[(*it)->InternalAlignmentIndex]; - newcVals.push_back(newConstr); - } - else { - // it is an internal alignment geometry that is no longer valid => delete it and - // the pole circle - delGeoId.push_back((*it)->First); - } - } - else if ((*it)->AlignmentType == Sketcher::BSplineKnotPoint) { - if (prevknot[(*it)->InternalAlignmentIndex] != -1) { - assert(prevknot[(*it)->InternalAlignmentIndex] < bspline->countKnots()); - Constraint* newConstr = (*it)->clone(); - newConstr->InternalAlignmentIndex = prevknot[(*it)->InternalAlignmentIndex]; - newcVals.push_back(newConstr); - } - else { - // it is an internal alignment geometry that is no longer valid => delete it and - // the knot point - delGeoId.push_back((*it)->First); - } - } - else { - // it is a bspline geometry, but not a controlpoint or knot - newcVals.push_back(*it); - } + // modify pole and knot constraints + for (const auto& constr : cvals) { + if (!(constr->Type == Sketcher::InternalAlignment && constr->Second == GeoId)) { + newcVals.push_back(constr); + continue; + } + + std::vector* indexInNew = nullptr; + + if (constr->AlignmentType == Sketcher::BSplineControlPoint) { + indexInNew = &poleIndexInNew; + } + else if (constr->AlignmentType == Sketcher::BSplineKnotPoint) { + indexInNew = &knotIndexInNew; } else { - newcVals.push_back(*it); + // it is a bspline geometry, but not a controlpoint or knot + newcVals.push_back(constr); + continue; } + + if (indexInNew && indexInNew->at(constr->InternalAlignmentIndex) == -1) { + // it is an internal alignment geometry that is no longer valid + // => delete it and the pole circle + delGeoId.push_back(constr->First); + continue; + } + + Constraint* newConstr = constr->clone(); + newConstr->InternalAlignmentIndex = indexInNew->at(constr->InternalAlignmentIndex); + newcVals.push_back(newConstr); } const std::vector& vals = getInternalGeometry(); std::vector newVals(vals); + GeometryFacade::copyId(geo, bspline.get()); newVals[GeoId] = bspline.release(); // Block acceptGeometry in OnChanged to avoid unnecessary checks and updates @@ -7506,12 +7486,11 @@ bool SketchObject::insertBSplineKnot(int GeoId, double param, int multiplicity) // See 247a9f0876a00e08c25b07d1f8802479d8623e87 for suggestions. // Geometry.touch(); delGeometriesExclusiveList(delGeoId); - } - else { - Geometry.touch(); + return true; } - // handle this last return + Geometry.touch(); + return true; }