[Sketcher] Constrain B-spline knots as linear combination of poles

Also squashes:

[Sketcher] Create center of gravity constraint in planegcs

[Sketcher] typo

[Sketcher] Use accurate "weights" for knots

By weights we mean the linear combination factor B_i(x) such that
spline(x) = sum(pole_i * B_i(x)) for _non-rational_ splines.

[Sketcher] Use more appropriate weights for knots

These are relevant for knots _away_ from any ends (and possibly other high
multiplicity knots).

[Sketcher] Make COG constraint weights user-definable

[Sketcher] Make `flattenedknots` for periodic B-Splines

[Sketcher] Fix incorrect setup of `flattenedknots`

Without ensuring enough space, iterators become invalid. These iterators are
needed because for periodic B-splines we need to pad flattenedknots with offset
values within flattenedknots.

Apparently there is still some iterator issues even after the reserve. Just use
fresh vectors instead.

[Sketcher] Apply knot constraints by parameter

Hopefully this will allow directly applying constraints on knots.

[Sketcher] Disable some knot updating

[Sketcher] Use center of gravity constraint on knots

[Sketcher] Fix knot COG constraint for periodic splines

[Sketcher] Add start/end point of periodic spline to solver

This removes the trouble of transferring constraints to the underlying knot.

[Sketcher] Support knot constraints on rational B-splines

[Sketcher] Remove virtual from overridden methods in planegcs

Follow 0penbrain's comments

[Sketcher][planegcs] Use `unsigned int` in signatures

Also `size_t` at places

Suggestions by @abdullahtahiriyo
This commit is contained in:
Ajinkya Dahale
2022-07-12 13:24:04 +05:30
committed by abdullahtahiriyo
parent 027504ce16
commit 7cd2cbd29c
7 changed files with 346 additions and 66 deletions

View File

@@ -1326,13 +1326,63 @@ int System::addConstraintInternalAlignmentParabolaFocus(Parabola &e, Point &p1,
return addConstraintEqual(e.focus1.y, p1.y, tagId, driving, Constraint::Alignment::InternalAlignment);
}
int System::addConstraintInternalAlignmentBSplineControlPoint(BSpline &b, Circle &c, int poleindex, int tagId, bool driving)
int System::addConstraintInternalAlignmentBSplineControlPoint(BSpline &b, Circle &c, unsigned int poleindex, int tagId, bool driving)
{
addConstraintEqual(b.poles[poleindex].x, c.center.x, tagId, driving, Constraint::Alignment::InternalAlignment);
addConstraintEqual(b.poles[poleindex].y, c.center.y, tagId, driving, Constraint::Alignment::InternalAlignment);
return addConstraintEqual(b.weights[poleindex], c.rad, tagId, driving, Constraint::Alignment::InternalAlignment);
}
int System::addConstraintInternalAlignmentKnotPoint(BSpline &b, Point &p, unsigned int knotindex, int tagId, bool driving)
{
if (b.periodic && knotindex == 0) {
// This is done here since knotpoints themselves aren't stored
addConstraintP2PCoincident(p, b.start, tagId, driving);
addConstraintP2PCoincident(p, b.end, tagId, driving);
}
size_t numpoles = b.degree - b.mult[knotindex] + 1;
if (numpoles == 0)
numpoles = 1;
size_t startpole = 0;
std::vector<double *> pvec;
pvec.push_back(p.x);
std::vector<double> weights(numpoles, 1.0 / numpoles);
// TODO: Adjust for periodic knot
for (size_t j = 1; j <= knotindex; ++j)
startpole += b.mult[j];
if (!b.periodic && startpole >= b.poles.size())
startpole = b.poles.size() - 1;
for (size_t i = 0; i < numpoles; ++i) {
pvec.push_back(b.poles[(startpole + i) % b.poles.size()].x);
// FIXME: `getLinCombFactor` seg-faults for the last knot so this safeguard exists
if (numpoles > 2)
weights[i] = b.getLinCombFactor(*(b.knots[knotindex]), startpole + b.degree, startpole + i);
}
for (size_t i = 0; i < numpoles; ++i)
pvec.push_back(b.weights[(startpole + i) % b.poles.size()]);
Constraint *constr = new ConstraintWeightedLinearCombination(numpoles, pvec, weights);
constr->setTag(tagId);
constr->setDriving(driving);
addConstraint(constr);
pvec.clear();
pvec.push_back(p.y);
for (size_t i = 0; i < numpoles; ++i)
pvec.push_back(b.poles[(startpole + i) % b.poles.size()].y);
for (size_t i = 0; i < numpoles; ++i)
pvec.push_back(b.weights[(startpole + i) % b.poles.size()]);
constr = new ConstraintWeightedLinearCombination(numpoles, pvec, weights);
constr->setTag(tagId);
constr->setDriving(driving);
return addConstraint(constr);
}
//calculates angle between two curves at point of their intersection p. If two
//points are supplied, p is used for first curve and p2 for second, yielding a
//remote angle computation (this is useful when the endpoints haven't) been