[Sketcher] Refactor SketchObject::insertBSplineKnot()

This commit is contained in:
Ajinkya Dahale
2024-06-29 13:50:57 +05:30
parent 10f4fb866e
commit da71365ff3

View File

@@ -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<Part::GeomBSplineCurve>()) {
THROWMT(Base::TypeError,
QT_TRANSLATE_NOOP("Exceptions",
"The Geometry Index (GeoId) provided is not a B-spline."));
}
const Part::GeomBSplineCurve* bsp = static_cast<const Part::GeomBSplineCurve*>(geo);
const auto* bsp = static_cast<const Part::GeomBSplineCurve*>(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<Part::GeomBSplineCurve> bspline;
@@ -7400,89 +7405,64 @@ bool SketchObject::insertBSplineKnot(int GeoId, double param, int multiplicity)
std::vector<Base::Vector3d> poles = bsp->getPoles();
std::vector<Base::Vector3d> newpoles = bspline->getPoles();
std::vector<int> prevpole(bsp->countPoles());
std::vector<int> 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<double> knots = bsp->getKnots();
std::vector<double> newknots = bspline->getKnots();
std::vector<int> prevknot(bsp->countKnots());
std::vector<int> 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<Sketcher::Constraint*>& cvals = Constraints.getValues();
std::vector<Constraint*> newcVals(0);
// modify pole constraints
for (std::vector<Sketcher::Constraint*>::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<int>* 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<Part::Geometry*>& vals = getInternalGeometry();
std::vector<Part::Geometry*> 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;
}