[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 bad4406387
commit ba4f2bf128
7 changed files with 346 additions and 66 deletions

View File

@@ -617,12 +617,7 @@ int Sketch::addGeometry(const Part::Geometry *geo, bool fixed)
const GeomPoint *point = static_cast<const GeomPoint*>(geo);
auto pointf = GeometryFacade::getFacade(point);
// create the definition struct for that geom
if( pointf->getInternalType() == InternalType::BSplineKnotPoint ) {
return addPoint(*point, true);
}
else {
return addPoint(*point, fixed);
}
return addPoint(*point, fixed);
}
else if (geo->getTypeId() == GeomLineSegment::getClassTypeId()) { // add a line
const GeomLineSegment *lineSeg = static_cast<const GeomLineSegment*>(geo);
@@ -1257,12 +1252,10 @@ int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed)
double * p1x = new double(startPnt.x);
double * p1y = new double(startPnt.y);
// if periodic, startpoint and endpoint do not play a role in the solver, this removes unnecessary DoF of determining where in the curve
// the start and the stop should be
if(!periodic) {
params.push_back(p1x);
params.push_back(p1y);
}
// If periodic, startpoint and endpoint do not play a role in the solver, this can remove unnecessary DoF of determining where in the curve
// the start and the stop should be. However, since start and end points are placed above knots, removing them leads to that knot being unusable.
params.push_back(p1x);
params.push_back(p1y);
p1.x = p1x;
p1.y = p1y;
@@ -1270,12 +1263,11 @@ int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed)
double * p2x = new double(endPnt.x);
double * p2y = new double(endPnt.y);
// if periodic, startpoint and endpoint do not play a role in the solver, this removes unnecessary DoF of determining where in the curve
// the start and the stop should be
if(!periodic) {
params.push_back(p2x);
params.push_back(p2y);
}
// If periodic, startpoint and endpoint do not play a role in the solver, this can remove unnecessary DoF of determining where in the curve
// the start and the stop should be. However, since start and end points are placed above knots, removing them leads to that knot being unusable.
params.push_back(p2x);
params.push_back(p2y);
p2.x = p2x;
p2.y = p2y;
@@ -3311,16 +3303,14 @@ int Sketch::addInternalAlignmentKnotPoint(int geoId1, int geoId2, int knotindex)
int pointId1 = getPointId(geoId2, PointPos::start);
if (pointId1 >= 0 && pointId1 < int(Points.size())) {
// GCS::Point &p = Points[pointId1];
GCS::Point &p = Points[pointId1];
GCS::BSpline &b = BSplines[Geoms[geoId1].index];
// no constraint is actually added, as knots are fixed geometry in this implementation
// indexing is added here.
// However, we need to advance the tag, so that the index after a knot constraint is accurate
ConstraintsCounter++;
assert(knotindex < static_cast<int>(b.knots.size()) && knotindex >= 0);
b.knotpointGeoids[knotindex] = geoId2;
int tag = ++ConstraintsCounter;
GCSsys.addConstraintInternalAlignmentKnotPoint(b, p, knotindex, tag);
return ConstraintsCounter;
}
@@ -3374,12 +3364,9 @@ bool Sketch::updateGeometry()
GeomPoint *point = static_cast<GeomPoint*>(it->geo);
auto pointf = GeometryFacade::getFacade(point);
if(!(pointf->getInternalType() == InternalType::BSplineKnotPoint)) {
point->setPoint(Vector3d(*Points[it->startPointId].x,
point->setPoint(Vector3d(*Points[it->startPointId].x,
*Points[it->startPointId].y,
0.0)
);
}
0.0));
}
else if (it->type == Line) {
GeomLineSegment *lineSeg = static_cast<GeomLineSegment*>(it->geo);
@@ -3527,38 +3514,6 @@ bool Sketch::updateGeometry()
}
bsp->setKnots(knots,mult);*/
// This is the code that needs to be here to take advantage of the current OCCT reliant implementation
// The current B-Spline implementation relies on OCCT for pole calculation, so the knots are set by the OCCT calculated values
auto occtknots = bsp->getKnots();
for(auto it3 = occtknots.begin() ; it3 != occtknots.end(); ++it3)
knots.push_back(*it3);
int index = 0;
for(std::vector<int>::const_iterator it5 = mybsp.knotpointGeoids.begin(); it5 != mybsp.knotpointGeoids.end(); ++it5, index++) {
if( *it5 != GeoEnum::GeoUndef) {
if (Geoms[*it5].type == Point) {
GeomPoint *point = static_cast<GeomPoint*>(Geoms[*it5].geo);
auto pointf = GeometryFacade::getFacade(point);
if(pointf->getInternalType() == InternalType::BSplineKnotPoint) {
auto pointcoords = bsp->pointAtParameter(knots[index]);
point->setPoint(pointcoords); // update the geompoint of the knot (geometry update)
// Now we update the position of the points in the solver, so that any call to solve()
// calculates constraints and positions based on the actual position of the knots.
auto pointindex = getPointId(*it5, PointPos::start);
if(pointindex >= 0) {
auto solverpoint = Points[pointindex];
*(solverpoint.x) = pointcoords.x;
*(solverpoint.y) = pointcoords.y;
}
}
}
}
}
}
} catch (Base::Exception &e) {
Base::Console().Error("Updating geometry: Error build geometry(%d): %s\n",