[Sketcher] Expose general tangency with B-splines to Sketcher

The following commits were squashed into this

[Sketcher] Handle some corner cases in AngleViaPoint

[Sketcher] Avoid redundant constraints with B-splines...

When involving tangent, perpendicular and angle constraints.

[Sketcher] Add pre-commit changes

[Sketcher] Do not allow 2-selection tangent with B-spline

Also...

[Sketcher] Report error when using direct tangency with B-splines

[Sketcher] Fix malformed constraint when B-spline is selected second

To clarify, this means the second curve selected. The position of the point in
selection order does not matter in angle-via-point.

[Sketcher] Fix wrong number for B-Spline tangent on redundancy

[Sketcher] Remove existing point-on-object in some redundant cases

Particularly when point constrained on a B-spline is being used for
tangent, perpendicular or angle via point with the same B-spline.

[Sketcher] Fix direction issue with B-spline tangents.

Without these changes the solver might try to "twist" the B-spline to make the
angle between curves be 0 instead of PI (which may be closer to the initial shape).
This commit is contained in:
Ajinkya Dahale
2023-04-05 23:11:28 +05:30
parent 0dd55072dc
commit cf3e0c1b4a
7 changed files with 611 additions and 304 deletions

View File

@@ -2868,6 +2868,11 @@ int Sketch::addTangentConstraint(int geoId1, int geoId2)
GCSsys.addConstraintTangent(l, a, tag);
return ConstraintsCounter;
}
else if (Geoms[geoId2].type == BSpline) {
Base::Console().Error("Direct tangency constraint between line and B-spline is not "
"supported. Use tangent-via-point instead.");
return -1;
}
}
else if (Geoms[geoId1].type == Circle) {
GCS::Circle& c = Circles[Geoms[geoId1].index];
@@ -2888,6 +2893,11 @@ int Sketch::addTangentConstraint(int geoId1, int geoId2)
GCSsys.addConstraintTangent(c, a, tag);
return ConstraintsCounter;
}
else if (Geoms[geoId2].type == BSpline) {
Base::Console().Error("Direct tangency constraint between circle and B-spline is not "
"supported. Use tangent-via-point instead.");
return -1;
}
}
else if (Geoms[geoId1].type == Ellipse) {
if (Geoms[geoId2].type == Circle) {
@@ -2900,6 +2910,11 @@ int Sketch::addTangentConstraint(int geoId1, int geoId2)
"supported. Use tangent-via-point instead.");
return -1;
}
else if (Geoms[geoId2].type == BSpline) {
Base::Console().Error("Direct tangency constraint between ellipse and B-spline is not "
"supported. Use tangent-via-point instead.");
return -1;
}
}
else if (Geoms[geoId1].type == Arc) {
GCS::Arc& a = Arcs[Geoms[geoId1].index];
@@ -2920,6 +2935,16 @@ int Sketch::addTangentConstraint(int geoId1, int geoId2)
GCSsys.addConstraintTangent(a, a2, tag);
return ConstraintsCounter;
}
else if (Geoms[geoId2].type == BSpline) {
Base::Console().Error("Direct tangency constraint between arc and B-spline is not "
"supported. Use tangent-via-point instead.");
return -1;
}
}
else if (Geoms[geoId1].type == BSpline) {
Base::Console().Error("Direct tangency constraint including B-splines is not "
"supported. Use tangent-via-point instead.");
return -1;
}
return -1;
@@ -3041,7 +3066,6 @@ int Sketch::addAngleAtPointConstraint(int geoId1,
ConstraintType cTyp,
bool driving)
{
if (!(cTyp == Angle || cTyp == Tangent || cTyp == Perpendicular)) {
// assert(0);//none of the three types. Why are we here??
return -1;
@@ -3146,19 +3170,116 @@ int Sketch::addAngleAtPointConstraint(int geoId1,
}
int tag = -1;
// FIXME: Perform construction of any parameters where this method is called instead of here
if (e2c) {
// increases ConstraintsCounter
tag = Sketch::addPointOnObjectConstraint(geoId1, pos1, geoId2, driving);
if (Geoms[geoId2].type == BSpline) {
GCS::Point& p1 = Points[getPointId(geoId1, pos1)];
auto* partBsp = static_cast<GeomBSplineCurve*>(Geoms[geoId2].geo);
double uNear;
partBsp->closestParameter(Base::Vector3d(*p1.x, *p1.y, 0.0), uNear);
double* pointparam = new double(uNear);
Parameters.push_back(pointparam);
--ConstraintsCounter; // Do this just before point-on-object because ConstraintsCounter
// is increased again before being used
tag = addPointOnObjectConstraint(geoId1,
pos1,
geoId2,
pointparam,
driving); // increases ConstraintsCounter
GCSsys.addConstraintAngleViaPointAndParam(*crv2,
*crv1,
p,
pointparam,
angle,
tag,
driving);
}
else {
// increases ConstraintsCounter
tag = Sketch::addPointOnObjectConstraint(geoId1,
pos1,
geoId2,
driving); // increases ConstraintsCounter
GCSsys.addConstraintAngleViaPoint(*crv1, *crv2, p, angle, tag, driving);
}
}
if (e2e) {
tag = ++ConstraintsCounter;
GCSsys.addConstraintP2PCoincident(p, *p2, tag, driving);
GCSsys.addConstraintAngleViaPoint(*crv1, *crv2, p, angle, tag, driving);
}
if (avp) {
tag = ++ConstraintsCounter;
if (Geoms[geoId1].type == BSpline || Geoms[geoId2].type == BSpline) {
if (Geoms[geoId1].type == BSpline && Geoms[geoId2].type == BSpline) {
GCS::Point& p3 = Points[getPointId(geoId3, pos3)];
auto* partBsp = static_cast<GeomBSplineCurve*>(Geoms[geoId1].geo);
double uNear;
partBsp->closestParameter(Base::Vector3d(*p3.x, *p3.y, 0.0), uNear);
double* pointparam1 = new double(uNear);
Parameters.push_back(pointparam1);
--ConstraintsCounter; // Do this just before point-on-object because
// ConstraintsCounter is increased again before being used
addPointOnObjectConstraint(geoId3,
pos3,
geoId1,
pointparam1,
driving); // increases ConstraintsCounter
partBsp = static_cast<GeomBSplineCurve*>(Geoms[geoId2].geo);
partBsp->closestParameter(Base::Vector3d(*p3.x, *p3.y, 0.0), uNear);
double* pointparam2 = new double(uNear);
--ConstraintsCounter; // Do this just before point-on-object because
// ConstraintsCounter is increased again before being used
addPointOnObjectConstraint(geoId3,
pos3,
geoId2,
pointparam2,
driving); // increases ConstraintsCounter
Parameters.push_back(pointparam2);
GCSsys.addConstraintAngleViaPointAndTwoParams(*crv1,
*crv2,
p,
pointparam1,
pointparam2,
angle,
tag,
driving);
}
else {
if (Geoms[geoId1].type != BSpline) {
std::swap(geoId1, geoId2);
std::swap(crv1, crv2);
std::swap(pos1, pos2);
// FIXME: Confirm whether or not this is needed
// *angle = -*angle;
}
GCS::Point& p3 = Points[getPointId(geoId3, pos3)];
auto* partBsp = static_cast<GeomBSplineCurve*>(Geoms[geoId1].geo);
double uNear;
partBsp->closestParameter(Base::Vector3d(*p3.x, *p3.y, 0.0), uNear);
double* pointparam = new double(uNear);
Parameters.push_back(pointparam);
--ConstraintsCounter; // Do this just before point-on-object because
// ConstraintsCounter is increased again before being used
addPointOnObjectConstraint(geoId3,
pos3,
geoId1,
pointparam,
driving); // increases ConstraintsCounter
GCSsys.addConstraintAngleViaPointAndParam(*crv1,
*crv2,
p,
pointparam,
angle,
tag,
driving);
}
}
else {
GCSsys.addConstraintAngleViaPoint(*crv1, *crv2, p, angle, tag, driving);
}
}
GCSsys.addConstraintAngleViaPoint(*crv1, *crv2, p, angle, tag, driving);
return ConstraintsCounter;
}
@@ -4139,6 +4260,30 @@ double Sketch::calculateAngleViaPoint(int geoId1, int geoId2, double px, double
return GCSsys.calculateAngleViaPoint(*crv1, *crv2, p);
}
double Sketch::calculateAngleViaParams(int geoId1, int geoId2, double param1, double param2)
{
geoId1 = checkGeoId(geoId1);
geoId2 = checkGeoId(geoId2);
// check pointers
GCS::Curve* crv1 = getGCSCurveByGeoId(geoId1);
GCS::Curve* crv2 = getGCSCurveByGeoId(geoId2);
if (!crv1 || !crv2) {
throw Base::ValueError("calculateAngleViaPoint: getGCSCurveByGeoId returned NULL!");
}
// FIXME: This should probably not be needed
auto* crv1AsBSpline = dynamic_cast<GCS::BSpline*>(crv1);
if (crv1AsBSpline && crv1AsBSpline->flattenedknots.empty()) {
crv1AsBSpline->setupFlattenedKnots();
}
auto* crv2AsBSpline = dynamic_cast<GCS::BSpline*>(crv2);
if (crv2AsBSpline && crv2AsBSpline->flattenedknots.empty()) {
crv2AsBSpline->setupFlattenedKnots();
}
return GCSsys.calculateAngleViaParams(*crv1, *crv2, &param1, &param2);
}
Base::Vector3d Sketch::calculateNormalAtPoint(int geoIdCurve, double px, double py) const
{
geoIdCurve = checkGeoId(geoIdCurve);