[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:
@@ -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, ¶m1, ¶m2);
|
||||
}
|
||||
|
||||
Base::Vector3d Sketch::calculateNormalAtPoint(int geoIdCurve, double px, double py) const
|
||||
{
|
||||
geoIdCurve = checkGeoId(geoIdCurve);
|
||||
|
||||
@@ -488,6 +488,8 @@ public:
|
||||
// value as the point approaches intersection of curves).
|
||||
double calculateAngleViaPoint(int geoId1, int geoId2, double px, double py);
|
||||
|
||||
double calculateAngleViaParams(int geoId1, int geoId2, double param1, double param2);
|
||||
|
||||
// This is to be used for rendering of angle-via-point constraint.
|
||||
Base::Vector3d calculateNormalAtPoint(int geoIdCurve, double px, double py) const;
|
||||
|
||||
|
||||
@@ -8578,13 +8578,24 @@ double SketchObject::calculateAngleViaPoint(int GeoId1, int GeoId2, double px, d
|
||||
// Temporary sketch based calculation. Slow, but guaranteed consistency with constraints.
|
||||
Sketcher::Sketch sk;
|
||||
|
||||
const Part::Geometry* p1 = this->getGeometry(GeoId1);
|
||||
const Part::Geometry* p2 = this->getGeometry(GeoId2);
|
||||
const Part::GeomCurve* p1 = dynamic_cast<const Part::GeomCurve*>(this->getGeometry(GeoId1));
|
||||
const Part::GeomCurve* p2 = dynamic_cast<const Part::GeomCurve*>(this->getGeometry(GeoId2));
|
||||
|
||||
if (p1 && p2) {
|
||||
// TODO: Check if any of these are B-splines
|
||||
int i1 = sk.addGeometry(this->getGeometry(GeoId1));
|
||||
int i2 = sk.addGeometry(this->getGeometry(GeoId2));
|
||||
|
||||
if (p1->is<Part::GeomBSplineCurve>() ||
|
||||
p2->is<Part::GeomBSplineCurve>()) {
|
||||
double p1ClosestParam, p2ClosestParam;
|
||||
Base::Vector3d pt(px, py, 0);
|
||||
p1->closestParameter(pt, p1ClosestParam);
|
||||
p2->closestParameter(pt, p2ClosestParam);
|
||||
|
||||
return sk.calculateAngleViaParams(i1, i2, p1ClosestParam, p2ClosestParam);
|
||||
}
|
||||
|
||||
return sk.calculateAngleViaPoint(i1, i2, px, py);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -774,6 +774,36 @@ int System::addConstraintAngleViaPoint(Curve& crv1,
|
||||
return addConstraint(constr);
|
||||
}
|
||||
|
||||
int System::addConstraintAngleViaPointAndParam(Curve& crv1,
|
||||
Curve& crv2,
|
||||
Point& p,
|
||||
double* cparam,
|
||||
double* angle,
|
||||
int tagId,
|
||||
bool driving)
|
||||
{
|
||||
Constraint* constr = new ConstraintAngleViaPointAndParam(crv1, crv2, p, cparam, angle);
|
||||
constr->setTag(tagId);
|
||||
constr->setDriving(driving);
|
||||
return addConstraint(constr);
|
||||
}
|
||||
|
||||
int System::addConstraintAngleViaPointAndTwoParams(Curve& crv1,
|
||||
Curve& crv2,
|
||||
Point& p,
|
||||
double* cparam1,
|
||||
double* cparam2,
|
||||
double* angle,
|
||||
int tagId,
|
||||
bool driving)
|
||||
{
|
||||
Constraint* constr =
|
||||
new ConstraintAngleViaPointAndTwoParams(crv1, crv2, p, cparam1, cparam2, angle);
|
||||
constr->setTag(tagId);
|
||||
constr->setDriving(driving);
|
||||
return addConstraint(constr);
|
||||
}
|
||||
|
||||
int System::addConstraintMidpointOnLine(Line& l1, Line& l2, int tagId, bool driving)
|
||||
{
|
||||
Constraint* constr = new ConstraintMidpointOnLine(l1, l2);
|
||||
|
||||
@@ -317,6 +317,21 @@ public:
|
||||
double* angle,
|
||||
int tagId = 0,
|
||||
bool driving = true);
|
||||
int addConstraintAngleViaPointAndParam(Curve& crv1,
|
||||
Curve& crv2,
|
||||
Point& p,
|
||||
double* cparam,
|
||||
double* angle,
|
||||
int tagId = 0,
|
||||
bool driving = true);
|
||||
int addConstraintAngleViaPointAndTwoParams(Curve& crv1,
|
||||
Curve& crv2,
|
||||
Point& p,
|
||||
double* cparam1,
|
||||
double* cparam2,
|
||||
double* angle,
|
||||
int tagId = 0,
|
||||
bool driving = true);
|
||||
int addConstraintMidpointOnLine(Line& l1, Line& l2, int tagId = 0, bool driving = true);
|
||||
int addConstraintMidpointOnLine(Point& l1p1,
|
||||
Point& l1p2,
|
||||
|
||||
@@ -777,31 +777,43 @@ DeriVector2 BSpline::CalculateNormal(const double* param, const double* derivpar
|
||||
{
|
||||
// TODO: is there any advantage in making this a `static`?
|
||||
size_t startpole = 0;
|
||||
for (size_t j = 1; j < mult.size() && *(knots[j]) <= *param; ++j)
|
||||
for (size_t j = 1; j < mult.size() && *(knots[j]) <= *param; ++j) {
|
||||
startpole += mult[j];
|
||||
if (!periodic && startpole >= poles.size())
|
||||
}
|
||||
if (!periodic && startpole >= poles.size()) {
|
||||
startpole = poles.size() - degree - 1;
|
||||
}
|
||||
|
||||
// double xsum = 0., xslopesum = 0.;
|
||||
// double ysum = 0., yslopesum = 0.;
|
||||
// double wsum = 0., wslopesum = 0.;
|
||||
|
||||
auto polexat = [&](size_t i) { return poles[(startpole + i) % poles.size()].x; };
|
||||
auto poleyat = [&](size_t i) { return poles[(startpole + i) % poles.size()].y; };
|
||||
auto weightat = [&](size_t i) { return weights[(startpole + i) % weights.size()]; };
|
||||
auto polexat = [&](size_t i) {
|
||||
return poles[(startpole + i) % poles.size()].x;
|
||||
};
|
||||
auto poleyat = [&](size_t i) {
|
||||
return poles[(startpole + i) % poles.size()].y;
|
||||
};
|
||||
auto weightat = [&](size_t i) {
|
||||
return weights[(startpole + i) % weights.size()];
|
||||
};
|
||||
|
||||
size_t numpoints = degree + 1;
|
||||
// Tangent vector
|
||||
// This should in principle be identical to error gradient wrt curve parameter in point-on-object
|
||||
// This should in principle be identical to error gradient wrt curve parameter in
|
||||
// point-on-object
|
||||
VEC_D d(numpoints);
|
||||
for (size_t i = 0; i < numpoints; ++i)
|
||||
for (size_t i = 0; i < numpoints; ++i) {
|
||||
d[i] = *polexat(i) * *weightat(i);
|
||||
}
|
||||
double xsum = BSpline::splineValue(*param, startpole + degree, degree, d, flattenedknots);
|
||||
for (size_t i = 0; i < numpoints; ++i)
|
||||
for (size_t i = 0; i < numpoints; ++i) {
|
||||
d[i] = *poleyat(i) * *weightat(i);
|
||||
}
|
||||
double ysum = BSpline::splineValue(*param, startpole + degree, degree, d, flattenedknots);
|
||||
for (size_t i = 0; i < numpoints; ++i)
|
||||
for (size_t i = 0; i < numpoints; ++i) {
|
||||
d[i] = *weightat(i);
|
||||
}
|
||||
double wsum = BSpline::splineValue(*param, startpole + degree, degree, d, flattenedknots);
|
||||
|
||||
d.resize(numpoints - 1);
|
||||
@@ -809,22 +821,22 @@ DeriVector2 BSpline::CalculateNormal(const double* param, const double* derivpar
|
||||
d[i - 1] = (*polexat(i) * *weightat(i) - *polexat(i - 1) * *weightat(i - 1))
|
||||
/ (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]);
|
||||
}
|
||||
double xslopesum = degree * BSpline::splineValue(
|
||||
*param, startpole + degree, degree - 1, d, flattenedknots);
|
||||
double xslopesum =
|
||||
degree * BSpline::splineValue(*param, startpole + degree, degree - 1, d, flattenedknots);
|
||||
for (size_t i = 1; i < numpoints; ++i) {
|
||||
d[i - 1] = (*poleyat(i) * *weightat(i) - *poleyat(i - 1) * *weightat(i - 1))
|
||||
/ (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]);
|
||||
}
|
||||
double yslopesum = degree * BSpline::splineValue(
|
||||
*param, startpole + degree, degree - 1, d, flattenedknots);
|
||||
double yslopesum =
|
||||
degree * BSpline::splineValue(*param, startpole + degree, degree - 1, d, flattenedknots);
|
||||
for (size_t i = 1; i < numpoints; ++i) {
|
||||
d[i - 1] = (*weightat(i) - *weightat(i - 1))
|
||||
/ (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]);
|
||||
}
|
||||
double wslopesum = degree * BSpline::splineValue(
|
||||
*param, startpole + degree, degree - 1, d, flattenedknots);
|
||||
double wslopesum =
|
||||
degree * BSpline::splineValue(*param, startpole + degree, degree - 1, d, flattenedknots);
|
||||
|
||||
DeriVector2 result(wsum*xslopesum - wslopesum*xsum, wsum*yslopesum - wslopesum*ysum);
|
||||
DeriVector2 result(wsum * xslopesum - wslopesum * xsum, wsum * yslopesum - wslopesum * ysum);
|
||||
|
||||
// get dx, dy of the normal as well
|
||||
bool dpfound = false;
|
||||
@@ -832,95 +844,113 @@ DeriVector2 BSpline::CalculateNormal(const double* param, const double* derivpar
|
||||
if (derivparam == polexat(i)) {
|
||||
VEC_D d(numpoints);
|
||||
d[i] = 1;
|
||||
double factor = BSpline::splineValue(*param, startpole + degree, degree, d, flattenedknots);
|
||||
VEC_D sd(numpoints-1);
|
||||
if (i > 0)
|
||||
sd[i-1] = 1.0 / (flattenedknots[startpole+i+degree] - flattenedknots[startpole+i]);
|
||||
if (i < numpoints - 1)
|
||||
sd[i] = -1.0 / (flattenedknots[startpole+i+1+degree] - flattenedknots[startpole+i+1]);
|
||||
double slopefactor = BSpline::splineValue(*param, startpole + degree, degree-1, sd, flattenedknots);
|
||||
result.dx = *weightat(i) * (wsum*slopefactor - wslopesum*factor);
|
||||
double factor =
|
||||
BSpline::splineValue(*param, startpole + degree, degree, d, flattenedknots);
|
||||
VEC_D sd(numpoints - 1);
|
||||
if (i > 0) {
|
||||
sd[i - 1] =
|
||||
1.0 / (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]);
|
||||
}
|
||||
if (i < numpoints - 1) {
|
||||
sd[i] = -1.0
|
||||
/ (flattenedknots[startpole + i + 1 + degree]
|
||||
- flattenedknots[startpole + i + 1]);
|
||||
}
|
||||
double slopefactor =
|
||||
BSpline::splineValue(*param, startpole + degree, degree - 1, sd, flattenedknots);
|
||||
result.dx = *weightat(i) * (wsum * slopefactor - wslopesum * factor);
|
||||
dpfound = true;
|
||||
break;
|
||||
}
|
||||
if (derivparam == poleyat(i)) {
|
||||
VEC_D d(numpoints);
|
||||
d[i] = 1;
|
||||
double factor = BSpline::splineValue(*param, startpole + degree, degree, d, flattenedknots);
|
||||
VEC_D sd(numpoints-1);
|
||||
if (i > 0)
|
||||
sd[i-1] = 1.0 / (flattenedknots[startpole+i+degree] - flattenedknots[startpole+i]);
|
||||
if (i < numpoints - 1)
|
||||
sd[i] = -1.0 / (flattenedknots[startpole+i+1+degree] - flattenedknots[startpole+i+1]);
|
||||
double slopefactor = BSpline::splineValue(*param, startpole + degree, degree-1, sd, flattenedknots);
|
||||
result.dy = *weightat(i) * (wsum*slopefactor - wslopesum*factor);
|
||||
double factor =
|
||||
BSpline::splineValue(*param, startpole + degree, degree, d, flattenedknots);
|
||||
VEC_D sd(numpoints - 1);
|
||||
if (i > 0) {
|
||||
sd[i - 1] =
|
||||
1.0 / (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]);
|
||||
}
|
||||
if (i < numpoints - 1) {
|
||||
sd[i] = -1.0
|
||||
/ (flattenedknots[startpole + i + 1 + degree]
|
||||
- flattenedknots[startpole + i + 1]);
|
||||
}
|
||||
double slopefactor =
|
||||
BSpline::splineValue(*param, startpole + degree, degree - 1, sd, flattenedknots);
|
||||
result.dy = *weightat(i) * (wsum * slopefactor - wslopesum * factor);
|
||||
dpfound = true;
|
||||
break;
|
||||
}
|
||||
if (derivparam == weightat(i)) {
|
||||
VEC_D d(numpoints);
|
||||
d[i] = 1;
|
||||
double factor = BSpline::splineValue(*param, startpole + degree, degree, d, flattenedknots);
|
||||
VEC_D sd(numpoints-1);
|
||||
if (i > 0)
|
||||
sd[i-1] = 1.0 / (flattenedknots[startpole+i+degree] - flattenedknots[startpole+i]);
|
||||
if (i < numpoints - 1)
|
||||
sd[i] = -1.0 / (flattenedknots[startpole+i+1+degree] - flattenedknots[startpole+i+1]);
|
||||
double slopefactor = BSpline::splineValue(*param, startpole + degree, degree-1, sd, flattenedknots);
|
||||
result.dx = degree *
|
||||
(factor * (xslopesum - wslopesum*(*polexat(i))) - slopefactor * (xsum - wsum*(*polexat(i))));
|
||||
result.dy = degree *
|
||||
(factor * (yslopesum - wslopesum*(*poleyat(i))) - slopefactor * (ysum - wsum*(*poleyat(i))));
|
||||
double factor =
|
||||
BSpline::splineValue(*param, startpole + degree, degree, d, flattenedknots);
|
||||
VEC_D sd(numpoints - 1);
|
||||
if (i > 0) {
|
||||
sd[i - 1] =
|
||||
1.0 / (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]);
|
||||
}
|
||||
if (i < numpoints - 1) {
|
||||
sd[i] = -1.0
|
||||
/ (flattenedknots[startpole + i + 1 + degree]
|
||||
- flattenedknots[startpole + i + 1]);
|
||||
}
|
||||
double slopefactor =
|
||||
BSpline::splineValue(*param, startpole + degree, degree - 1, sd, flattenedknots);
|
||||
result.dx = degree
|
||||
* (factor * (xslopesum - wslopesum * (*polexat(i)))
|
||||
- slopefactor * (xsum - wsum * (*polexat(i))));
|
||||
result.dy = degree
|
||||
* (factor * (yslopesum - wslopesum * (*poleyat(i)))
|
||||
- slopefactor * (ysum - wsum * (*poleyat(i))));
|
||||
dpfound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// the curve parameter being used by the constraint is not known to the geometry (there can be
|
||||
// many tangent constraints on the same curve after all). Assume that this is the param provided.
|
||||
// many tangent constraints on the same curve after all). Assume that this is the param
|
||||
// provided.
|
||||
if (derivparam == param) {
|
||||
VEC_D sd(numpoints-1), ssd(numpoints-2);
|
||||
VEC_D sd(numpoints - 1), ssd(numpoints - 2);
|
||||
for (size_t i = 1; i < numpoints; ++i) {
|
||||
sd[i-1] =
|
||||
(*weightat(i) - *weightat(i-1)) /
|
||||
(flattenedknots[startpole+i+degree] - flattenedknots[startpole+i]);
|
||||
sd[i - 1] = (*weightat(i) - *weightat(i - 1))
|
||||
/ (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]);
|
||||
}
|
||||
for (size_t i = 1; i < numpoints-1; ++i) {
|
||||
ssd[i-1] =
|
||||
(sd[i] - sd[i-1]) /
|
||||
(flattenedknots[startpole+i+degree] - flattenedknots[startpole+i]);
|
||||
for (size_t i = 1; i < numpoints - 1; ++i) {
|
||||
ssd[i - 1] = (sd[i] - sd[i - 1])
|
||||
/ (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]);
|
||||
}
|
||||
double wslopeslopesum = degree * (degree - 1) *
|
||||
BSpline::splineValue(*param, startpole + degree, degree-2, ssd, flattenedknots);
|
||||
double wslopeslopesum = degree * (degree - 1)
|
||||
* BSpline::splineValue(*param, startpole + degree, degree - 2, ssd, flattenedknots);
|
||||
|
||||
for (size_t i = 1; i < numpoints; ++i) {
|
||||
sd[i-1] =
|
||||
(*polexat(i) * *weightat(i) - *polexat(i-1) * *weightat(i-1)) /
|
||||
(flattenedknots[startpole+i+degree] - flattenedknots[startpole+i]);
|
||||
sd[i - 1] = (*polexat(i) * *weightat(i) - *polexat(i - 1) * *weightat(i - 1))
|
||||
/ (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]);
|
||||
}
|
||||
for (size_t i = 1; i < numpoints-1; ++i) {
|
||||
ssd[i-1] =
|
||||
(sd[i] - sd[i-1]) /
|
||||
(flattenedknots[startpole+i+degree] - flattenedknots[startpole+i]);
|
||||
for (size_t i = 1; i < numpoints - 1; ++i) {
|
||||
ssd[i - 1] = (sd[i] - sd[i - 1])
|
||||
/ (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]);
|
||||
}
|
||||
double xslopeslopesum = degree * (degree - 1) *
|
||||
BSpline::splineValue(*param, startpole + degree, degree-2, ssd, flattenedknots);
|
||||
double xslopeslopesum = degree * (degree - 1)
|
||||
* BSpline::splineValue(*param, startpole + degree, degree - 2, ssd, flattenedknots);
|
||||
|
||||
for (size_t i = 1; i < numpoints; ++i) {
|
||||
sd[i-1] =
|
||||
(*poleyat(i) * *weightat(i) - *poleyat(i-1) * *weightat(i-1)) /
|
||||
(flattenedknots[startpole+i+degree] - flattenedknots[startpole+i]);
|
||||
sd[i - 1] = (*poleyat(i) * *weightat(i) - *poleyat(i - 1) * *weightat(i - 1))
|
||||
/ (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]);
|
||||
}
|
||||
for (size_t i = 1; i < numpoints-1; ++i) {
|
||||
ssd[i-1] =
|
||||
(sd[i] - sd[i-1]) /
|
||||
(flattenedknots[startpole+i+degree] - flattenedknots[startpole+i]);
|
||||
for (size_t i = 1; i < numpoints - 1; ++i) {
|
||||
ssd[i - 1] = (sd[i] - sd[i - 1])
|
||||
/ (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]);
|
||||
}
|
||||
double yslopeslopesum = degree * (degree - 1) *
|
||||
BSpline::splineValue(*param, startpole + degree, degree-2, ssd, flattenedknots);
|
||||
double yslopeslopesum = degree * (degree - 1)
|
||||
* BSpline::splineValue(*param, startpole + degree, degree - 2, ssd, flattenedknots);
|
||||
|
||||
result.dx = wsum*xslopeslopesum - wslopeslopesum*xsum;
|
||||
result.dy = wsum*yslopeslopesum - wslopeslopesum*ysum;
|
||||
result.dx = wsum * xslopeslopesum - wslopeslopesum * xsum;
|
||||
result.dy = wsum * yslopeslopesum - wslopeslopesum * ysum;
|
||||
}
|
||||
|
||||
return result.rotate90ccw();
|
||||
|
||||
@@ -187,6 +187,54 @@ bool isGeoConcentricCompatible(const Part::Geometry* geo)
|
||||
return (isEllipse(*geo) || isArcOfEllipse(*geo) || isCircle(*geo) || isArcOfCircle(*geo));
|
||||
}
|
||||
|
||||
// Removes point-on-object constraints made redundant with certain constraints
|
||||
// under certain conditions. Currently, that happens only when the constraint is on
|
||||
// a B-spline, for 3-selection tangent, perpendicular, and angle constraints.
|
||||
// Returns true if constraints were removed.
|
||||
// GeoId3 HAS to be the point, and the other two are the curves.
|
||||
bool removeRedundantPointOnObject(SketchObject* Obj, int GeoId1, int GeoId2, int GeoId3)
|
||||
{
|
||||
const std::vector<Constraint*>& cvals = Obj->Constraints.getValues();
|
||||
|
||||
std::vector<int> cidsToBeRemoved;
|
||||
|
||||
int cid = 0;
|
||||
for (auto it = cvals.begin(); it != cvals.end(); ++it, ++cid) {
|
||||
if ((*it)->Type == Sketcher::PointOnObject &&
|
||||
(((*it)->First == GeoId3 && (*it)->Second == GeoId1) ||
|
||||
((*it)->First == GeoId3 && (*it)->Second == GeoId2))) {
|
||||
|
||||
// ONLY do this if it is a B-spline (or any other where point
|
||||
// on object is implied).
|
||||
const Part::Geometry* geom = Obj->getGeometry((*it)->Second);
|
||||
if (isBSplineCurve(*geom))
|
||||
cidsToBeRemoved.push_back(cid);
|
||||
}
|
||||
}
|
||||
|
||||
if (!cidsToBeRemoved.empty()) {
|
||||
for (auto it = cidsToBeRemoved.rbegin(); it != cidsToBeRemoved.rend(); ++it) {
|
||||
Gui::cmdAppObjectArgs(Obj,
|
||||
"delConstraint(%d)",
|
||||
*it);// remove the preexisting point on object constraint.
|
||||
}
|
||||
|
||||
// A substitution requires a solve() so that the autoremove redundants works when
|
||||
// Autorecompute not active. However, delConstraint includes such solve() internally. So
|
||||
// at this point it is already solved.
|
||||
tryAutoRecomputeIfNotSolve(Obj);
|
||||
|
||||
notifyConstraintSubstitutions(QObject::tr("One or two point on object constraint(s) was/were deleted, "
|
||||
"since the latest constraint being applied internally applies point-on-object as well."));
|
||||
|
||||
// TODO: find way to get selection here, or clear elsewhere
|
||||
// getSelection().clearSelection();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Makes an angle constraint between 2 lines
|
||||
void SketcherGui::makeAngleBetweenTwoLines(Sketcher::SketchObject* Obj,
|
||||
Gui::Command* cmd,
|
||||
@@ -232,8 +280,6 @@ void SketcherGui::makeAngleBetweenTwoLines(Sketcher::SketchObject* Obj,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool SketcherGui::calculateAngle(Sketcher::SketchObject* Obj, int& GeoId1, int& GeoId2, Sketcher::PointPos& PosId1, Sketcher::PointPos& PosId2, double& ActAngle)
|
||||
{
|
||||
const Part::Geometry* geom1 = Obj->getGeometry(GeoId1);
|
||||
@@ -312,7 +358,6 @@ bool SketcherGui::calculateAngle(Sketcher::SketchObject* Obj, int& GeoId1, int&
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// Makes a simple tangency constraint using extra point + tangent via point
|
||||
/// ellipse => an ellipse
|
||||
/// geom2 => any of an ellipse, an arc of ellipse, a circle, or an arc (of circle)
|
||||
@@ -5699,11 +5744,11 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg)
|
||||
if (isVertex(GeoId1, PosId1)) {
|
||||
std::swap(GeoId1, GeoId2);
|
||||
std::swap(PosId1, PosId2);
|
||||
};
|
||||
}
|
||||
if (isVertex(GeoId2, PosId2)) {
|
||||
std::swap(GeoId2, GeoId3);
|
||||
std::swap(PosId2, PosId3);
|
||||
};
|
||||
}
|
||||
|
||||
if (isEdge(GeoId1, PosId1) && isEdge(GeoId2, PosId2) && isVertex(GeoId3, PosId3)) {
|
||||
|
||||
@@ -5720,35 +5765,45 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg)
|
||||
bool safe = addConstraintSafely(Obj, [&]() {
|
||||
// add missing point-on-object constraints
|
||||
if (!IsPointAlreadyOnCurve(GeoId1, GeoId3, PosId3, Obj)) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
};
|
||||
const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
|
||||
if (!(geom1 && isBSplineCurve(*geom1))) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsPointAlreadyOnCurve(GeoId2, GeoId3, PosId3, Obj)) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId2);
|
||||
};
|
||||
const Part::Geometry *geom2 = Obj->getGeometry(GeoId2);
|
||||
if (!(geom2 && isBSplineCurve(*geom2))) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId2);
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsPointAlreadyOnCurve(
|
||||
GeoId1,
|
||||
GeoId3,
|
||||
PosId3,
|
||||
Obj)) {// FIXME: it's a good idea to add a check if the sketch is solved
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
};
|
||||
Obj)) {
|
||||
// FIXME: it's a good idea to add a check if the sketch is solved
|
||||
const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
|
||||
if (!(geom1 && isBSplineCurve(*geom1))) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
}
|
||||
}
|
||||
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
@@ -5757,6 +5812,8 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg)
|
||||
GeoId2,
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3));
|
||||
|
||||
removeRedundantPointOnObject(Obj, GeoId1, GeoId2, GeoId3);
|
||||
});
|
||||
|
||||
if (!safe) {
|
||||
@@ -5770,7 +5827,7 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg)
|
||||
getSelection().clearSelection();
|
||||
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
Gui::TranslatedUserWarning(
|
||||
Obj,
|
||||
@@ -5833,15 +5890,6 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg)
|
||||
|
||||
const Part::Geometry* geom2 = Obj->getGeometry(GeoId2);
|
||||
|
||||
if (geom2 && isBSplineCurve(*geom2)) {
|
||||
// unsupported until normal to B-spline at any point implemented.
|
||||
Gui::TranslatedUserWarning(
|
||||
Obj,
|
||||
QObject::tr("Wrong selection"),
|
||||
QObject::tr("Perpendicular to B-spline edge currently unsupported."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isBsplinePole(geom2)) {
|
||||
Gui::TranslatedUserWarning(
|
||||
Obj,
|
||||
@@ -5879,14 +5927,14 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg)
|
||||
return;
|
||||
}
|
||||
|
||||
if (isBSplineCurve(*geo1) || isBSplineCurve(*geo2)) {
|
||||
// unsupported until tangent to B-spline at any point implemented.
|
||||
Gui::TranslatedUserWarning(
|
||||
Obj,
|
||||
QObject::tr("Wrong selection"),
|
||||
QObject::tr("Perpendicular to B-spline edge currently unsupported."));
|
||||
return;
|
||||
}
|
||||
// if (isBSplineCurve(*geo1) || isBSplineCurve(*geo2)) {
|
||||
// // unsupported until tangent to B-spline at any point implemented.
|
||||
// Gui::TranslatedUserWarning(
|
||||
// Obj,
|
||||
// QObject::tr("Wrong selection"),
|
||||
// QObject::tr("Perpendicular to B-spline edge currently unsupported."));
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (isLineSegment(*geo1)) {
|
||||
std::swap(GeoId1, GeoId2);
|
||||
@@ -6080,14 +6128,14 @@ void CmdSketcherConstrainPerpendicular::applyConstraint(std::vector<SelIdPair>&
|
||||
return;
|
||||
}
|
||||
|
||||
if (isBSplineCurve(*geo1) || isBSplineCurve(*geo2)) {
|
||||
// unsupported until tangent to B-spline at any point implemented.
|
||||
Gui::TranslatedUserWarning(
|
||||
Obj,
|
||||
QObject::tr("Wrong selection"),
|
||||
QObject::tr("Perpendicular to B-spline edge currently unsupported."));
|
||||
return;
|
||||
}
|
||||
// if (isBSplineCurve(*geo1) || isBSplineCurve(*geo2)) {
|
||||
// // unsupported until tangent to B-spline at any point implemented.
|
||||
// Gui::TranslatedUserWarning(
|
||||
// Obj,
|
||||
// QObject::tr("Wrong selection"),
|
||||
// QObject::tr("Perpendicular to B-spline edge currently unsupported."));
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (isLineSegment(*geo1)) {
|
||||
std::swap(GeoId1, GeoId2);
|
||||
@@ -6285,35 +6333,41 @@ void CmdSketcherConstrainPerpendicular::applyConstraint(std::vector<SelIdPair>&
|
||||
bool safe = addConstraintSafely(Obj, [&]() {
|
||||
// add missing point-on-object constraints
|
||||
if (!IsPointAlreadyOnCurve(GeoId1, GeoId3, PosId3, Obj)) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
};
|
||||
const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
|
||||
if (!(geom1 && isBSplineCurve(*geom1))) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsPointAlreadyOnCurve(GeoId2, GeoId3, PosId3, Obj)) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId2);
|
||||
};
|
||||
const Part::Geometry *geom2 = Obj->getGeometry(GeoId2);
|
||||
if (!(geom2 && isBSplineCurve(*geom2))) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId2);
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsPointAlreadyOnCurve(
|
||||
GeoId1,
|
||||
GeoId3,
|
||||
PosId3,
|
||||
Obj)) {// FIXME: it's a good idea to add a check if the sketch is solved
|
||||
Gui::cmdAppObjectArgs(
|
||||
Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
};
|
||||
if (!IsPointAlreadyOnCurve(GeoId1, GeoId3, PosId3, Obj)) {
|
||||
// FIXME: it's a good idea to add a check if the sketch is solved
|
||||
const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
|
||||
if (!(geom1 && isBSplineCurve(*geom1))) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
}
|
||||
}
|
||||
|
||||
Gui::cmdAppObjectArgs(
|
||||
Obj,
|
||||
@@ -6322,6 +6376,8 @@ void CmdSketcherConstrainPerpendicular::applyConstraint(std::vector<SelIdPair>&
|
||||
GeoId2,
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3));
|
||||
|
||||
removeRedundantPointOnObject(Obj, GeoId1, GeoId2, GeoId3);
|
||||
});
|
||||
|
||||
if (!safe) {
|
||||
@@ -6335,7 +6391,7 @@ void CmdSketcherConstrainPerpendicular::applyConstraint(std::vector<SelIdPair>&
|
||||
getSelection().clearSelection();
|
||||
|
||||
return;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================================================
|
||||
@@ -6519,11 +6575,11 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
|
||||
if (isVertex(GeoId1, PosId1)) {
|
||||
std::swap(GeoId1, GeoId2);
|
||||
std::swap(PosId1, PosId2);
|
||||
};
|
||||
}
|
||||
if (isVertex(GeoId2, PosId2)) {
|
||||
std::swap(GeoId2, GeoId3);
|
||||
std::swap(PosId2, PosId3);
|
||||
};
|
||||
}
|
||||
|
||||
if (isEdge(GeoId1, PosId1) && isEdge(GeoId2, PosId2) && isVertex(GeoId3, PosId3)) {
|
||||
|
||||
@@ -6540,35 +6596,41 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
|
||||
bool safe = addConstraintSafely(Obj, [&]() {
|
||||
// add missing point-on-object constraints
|
||||
if (!IsPointAlreadyOnCurve(GeoId1, GeoId3, PosId3, Obj)) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
};
|
||||
const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
|
||||
if (!(geom1 && isBSplineCurve(*geom1))) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsPointAlreadyOnCurve(GeoId2, GeoId3, PosId3, Obj)) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId2);
|
||||
};
|
||||
const Part::Geometry *geom2 = Obj->getGeometry(GeoId2);
|
||||
if (!(geom2 && isBSplineCurve(*geom2))) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId2);
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsPointAlreadyOnCurve(
|
||||
GeoId1,
|
||||
GeoId3,
|
||||
PosId3,
|
||||
Obj)) {// FIXME: it's a good idea to add a check if the sketch is solved
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
};
|
||||
if (!IsPointAlreadyOnCurve(GeoId1, GeoId3, PosId3, Obj)) {
|
||||
// FIXME: it's a good idea to add a check if the sketch is solved
|
||||
const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
|
||||
if (!(geom1 && isBSplineCurve(*geom1))) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
}
|
||||
}
|
||||
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
@@ -6577,6 +6639,8 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
|
||||
GeoId2,
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3));
|
||||
|
||||
removeRedundantPointOnObject(Obj, GeoId1, GeoId2, GeoId3);
|
||||
});
|
||||
|
||||
if (!safe) {
|
||||
@@ -6590,7 +6654,7 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
|
||||
getSelection().clearSelection();
|
||||
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
Gui::TranslatedUserWarning(
|
||||
Obj,
|
||||
@@ -6669,15 +6733,6 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
|
||||
|
||||
const Part::Geometry* geom2 = Obj->getGeometry(GeoId2);
|
||||
|
||||
if (geom2 && isBSplineCurve(*geom2)) {
|
||||
// unsupported until tangent to B-spline at any point implemented.
|
||||
Gui::TranslatedUserWarning(
|
||||
Obj,
|
||||
QObject::tr("Wrong selection"),
|
||||
QObject::tr("Tangency to B-spline edge currently unsupported."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isBsplinePole(geom2)) {
|
||||
Gui::TranslatedUserWarning(
|
||||
Obj,
|
||||
@@ -6686,16 +6741,18 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
|
||||
return;
|
||||
}
|
||||
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Add tangent constraint"));
|
||||
Gui::cmdAppObjectArgs(selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('Tangent',%d,%d,%d))",
|
||||
GeoId1,
|
||||
static_cast<int>(PosId1),
|
||||
GeoId2);
|
||||
commitCommand();
|
||||
tryAutoRecompute(Obj);
|
||||
if (!substituteConstraintCombinations(Obj, GeoId1, GeoId2)) {
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Add tangent constraint"));
|
||||
Gui::cmdAppObjectArgs(selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('Tangent',%d,%d,%d))",
|
||||
GeoId1,
|
||||
static_cast<int>(PosId1),
|
||||
GeoId2);
|
||||
commitCommand();
|
||||
tryAutoRecompute(Obj);
|
||||
|
||||
getSelection().clearSelection();
|
||||
getSelection().clearSelection();
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (isEdge(GeoId1, PosId1)
|
||||
@@ -6704,15 +6761,6 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
|
||||
const Part::Geometry* geom1 = Obj->getGeometry(GeoId1);
|
||||
const Part::Geometry* geom2 = Obj->getGeometry(GeoId2);
|
||||
|
||||
if (geom1 && geom2 && (isBSplineCurve(*geom1) || isBSplineCurve(*geom2))) {
|
||||
// unsupported until tangent to B-spline at any point implemented.
|
||||
Gui::TranslatedUserWarning(
|
||||
Obj,
|
||||
QObject::tr("Wrong selection"),
|
||||
QObject::tr("Tangency to B-spline edge currently unsupported."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isBsplinePole(geom1) || isBsplinePole(geom2)) {
|
||||
Gui::TranslatedUserWarning(
|
||||
Obj,
|
||||
@@ -6872,6 +6920,14 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (geom1 && geom2 && (isBSplineCurve(*geom1) || isBSplineCurve(*geom2))) {
|
||||
Gui::TranslatedUserWarning(
|
||||
Obj,
|
||||
QObject::tr("Wrong selection"),
|
||||
QObject::tr("Only tangent-via-point is supported with a B-spline."));
|
||||
getSelection().clearSelection();
|
||||
return;
|
||||
}
|
||||
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Add tangent constraint"));
|
||||
Gui::cmdAppObjectArgs(selection[0].getObject(),
|
||||
@@ -6917,15 +6973,6 @@ void CmdSketcherConstrainTangent::applyConstraint(std::vector<SelIdPair>& selSeq
|
||||
const Part::Geometry* geom1 = Obj->getGeometry(GeoId1);
|
||||
const Part::Geometry* geom2 = Obj->getGeometry(GeoId2);
|
||||
|
||||
if (geom1 && geom2 && (isBSplineCurve(*geom1) || isBSplineCurve(*geom2))) {
|
||||
// unsupported until tangent to B-spline at any point implemented.
|
||||
Gui::TranslatedUserWarning(
|
||||
Obj,
|
||||
QObject::tr("Wrong selection"),
|
||||
QObject::tr("Tangency to B-spline edge currently unsupported."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isBsplinePole(geom1) || isBsplinePole(geom2)) {
|
||||
Gui::TranslatedUserWarning(
|
||||
Obj,
|
||||
@@ -7158,35 +7205,41 @@ void CmdSketcherConstrainTangent::applyConstraint(std::vector<SelIdPair>& selSeq
|
||||
bool safe = addConstraintSafely(Obj, [&]() {
|
||||
// add missing point-on-object constraints
|
||||
if (!IsPointAlreadyOnCurve(GeoId1, GeoId3, PosId3, Obj)) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
};
|
||||
const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
|
||||
if (!(geom1 && isBSplineCurve(*geom1))) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsPointAlreadyOnCurve(GeoId2, GeoId3, PosId3, Obj)) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId2);
|
||||
};
|
||||
const Part::Geometry *geom2 = Obj->getGeometry(GeoId2);
|
||||
if (!(geom2 && isBSplineCurve(*geom2))) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId2);
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsPointAlreadyOnCurve(
|
||||
GeoId1,
|
||||
GeoId3,
|
||||
PosId3,
|
||||
Obj)) {// FIXME: it's a good idea to add a check if the sketch is solved
|
||||
Gui::cmdAppObjectArgs(
|
||||
Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
};
|
||||
if (!IsPointAlreadyOnCurve(GeoId1, GeoId3, PosId3, Obj)) {
|
||||
// FIXME: it's a good idea to add a check if the sketch is solved
|
||||
const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
|
||||
if (!(geom1 && isBSplineCurve(*geom1))) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
}
|
||||
}
|
||||
|
||||
Gui::cmdAppObjectArgs(
|
||||
Obj,
|
||||
@@ -7195,6 +7248,8 @@ void CmdSketcherConstrainTangent::applyConstraint(std::vector<SelIdPair>& selSeq
|
||||
GeoId2,
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3));
|
||||
|
||||
removeRedundantPointOnObject(Obj, GeoId1, GeoId2, GeoId3);
|
||||
});
|
||||
|
||||
if (!safe) {
|
||||
@@ -7208,7 +7263,7 @@ void CmdSketcherConstrainTangent::applyConstraint(std::vector<SelIdPair>& selSeq
|
||||
getSelection().clearSelection();
|
||||
|
||||
return;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================================================
|
||||
@@ -8530,11 +8585,11 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
|
||||
if (isVertex(GeoId1, PosId1)) {
|
||||
std::swap(GeoId1, GeoId2);
|
||||
std::swap(PosId1, PosId2);
|
||||
};
|
||||
}
|
||||
if (isVertex(GeoId2, PosId2)) {
|
||||
std::swap(GeoId2, GeoId3);
|
||||
std::swap(PosId2, PosId3);
|
||||
};
|
||||
}
|
||||
|
||||
bool bothexternal = areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2);
|
||||
|
||||
@@ -8554,32 +8609,38 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
|
||||
|
||||
// add missing point-on-object constraints
|
||||
if (!IsPointAlreadyOnCurve(GeoId1, GeoId3, PosId3, Obj)) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
|
||||
if (!(geom1 && isBSplineCurve(*geom1))) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
}
|
||||
}
|
||||
if (!IsPointAlreadyOnCurve(GeoId2, GeoId3, PosId3, Obj)) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId2);
|
||||
const Part::Geometry *geom2 = Obj->getGeometry(GeoId2);
|
||||
if (!(geom2 && isBSplineCurve(*geom2))) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId2);
|
||||
}
|
||||
}
|
||||
if (!IsPointAlreadyOnCurve(
|
||||
GeoId1,
|
||||
GeoId3,
|
||||
PosId3,
|
||||
Obj)) {// FIXME: it's a good idea to add a check if the sketch is solved
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
if (!IsPointAlreadyOnCurve(GeoId1, GeoId3, PosId3, Obj)) {
|
||||
// FIXME: it's a good idea to add a check if the sketch is solved
|
||||
const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
|
||||
if (!(geom1 && isBSplineCurve(*geom1))) {
|
||||
Gui::cmdAppObjectArgs(
|
||||
selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
}
|
||||
}
|
||||
|
||||
// assuming point-on-curves have been solved, calculate the angle.
|
||||
@@ -8604,6 +8665,8 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
|
||||
static_cast<int>(PosId3),
|
||||
ActAngle);
|
||||
|
||||
removeRedundantPointOnObject(Obj, GeoId1, GeoId2, GeoId3);
|
||||
|
||||
if (bothexternal
|
||||
|| constraintCreationMode
|
||||
== Reference) {// it is a constraint on a external line, make it non-driving
|
||||
@@ -8620,7 +8683,7 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
}
|
||||
}
|
||||
else if (SubNames.size() < 3) {
|
||||
|
||||
@@ -8707,7 +8770,7 @@ void CmdSketcherConstrainAngle::activated(int iMsg)
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Gui::TranslatedUserWarning(
|
||||
Obj,
|
||||
@@ -8783,26 +8846,35 @@ void CmdSketcherConstrainAngle::applyConstraint(std::vector<SelIdPair>& selSeq,
|
||||
|
||||
// add missing point-on-object constraints
|
||||
if (!IsPointAlreadyOnCurve(GeoId1, GeoId3, PosId3, Obj)) {
|
||||
Gui::cmdAppObjectArgs(Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
|
||||
if (!(geom1 && isBSplineCurve(*geom1))) {
|
||||
Gui::cmdAppObjectArgs(Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
}
|
||||
}
|
||||
if (!IsPointAlreadyOnCurve(GeoId2, GeoId3, PosId3, Obj)) {
|
||||
Gui::cmdAppObjectArgs(Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId2);
|
||||
const Part::Geometry *geom2 = Obj->getGeometry(GeoId2);
|
||||
if (!(geom2 && isBSplineCurve(*geom2))) {
|
||||
Gui::cmdAppObjectArgs(Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId2);
|
||||
}
|
||||
}
|
||||
if (!IsPointAlreadyOnCurve(GeoId1, GeoId3, PosId3, Obj)) {
|
||||
// FIXME: it's a good idea to add a check if the sketch is solved
|
||||
Gui::cmdAppObjectArgs(Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
const Part::Geometry *geom1 = Obj->getGeometry(GeoId1);
|
||||
if (!(geom1 && isBSplineCurve(*geom1))) {
|
||||
Gui::cmdAppObjectArgs(Obj,
|
||||
"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d))",
|
||||
GeoId3,
|
||||
static_cast<int>(PosId3),
|
||||
GeoId1);
|
||||
}
|
||||
}
|
||||
|
||||
// assuming point-on-curves have been solved, calculate the angle.
|
||||
@@ -8826,6 +8898,8 @@ void CmdSketcherConstrainAngle::applyConstraint(std::vector<SelIdPair>& selSeq,
|
||||
static_cast<int>(PosId3),
|
||||
ActAngle);
|
||||
|
||||
removeRedundantPointOnObject(Obj, GeoId1, GeoId2, GeoId3);
|
||||
|
||||
if (bothexternal || constraintCreationMode == Reference) {
|
||||
// it is a constraint on a external line, make it non-driving
|
||||
const std::vector<Sketcher::Constraint*>& ConStr = Obj->Constraints.getValues();
|
||||
@@ -8838,7 +8912,7 @@ void CmdSketcherConstrainAngle::applyConstraint(std::vector<SelIdPair>& selSeq,
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void CmdSketcherConstrainAngle::updateAction(int mode)
|
||||
@@ -9566,18 +9640,18 @@ void CmdSketcherConstrainSnellsLaw::activated(int iMsg)
|
||||
QObject::tr("Wrong selection"),
|
||||
QObject::tr("Incompatible geometry is selected."));
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
const Part::Geometry* geo = Obj->getGeometry(GeoId3);
|
||||
|
||||
if (geo && isBSplineCurve(*geo)) {
|
||||
// unsupported until normal to B-spline at any point implemented.
|
||||
Gui::TranslatedUserWarning(
|
||||
Obj,
|
||||
QObject::tr("Wrong selection"),
|
||||
QObject::tr("SnellsLaw on B-spline edge is currently unsupported."));
|
||||
return;
|
||||
}
|
||||
// if (geo && isBSplineCurve(*geo)) {
|
||||
// // unsupported until normal to B-spline at any point implemented.
|
||||
// Gui::TranslatedUserWarning(
|
||||
// Obj,
|
||||
// QObject::tr("Wrong selection"),
|
||||
// QObject::tr("SnellsLaw on B-spline edge is currently unsupported."));
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (isBsplinePole(geo)) {
|
||||
Gui::TranslatedUserWarning(Obj,
|
||||
|
||||
Reference in New Issue
Block a user