[Sketcher] Use tangent at B-spline knot constraint

Also squashes:

[Sketcher] Make tangent-at-knot with just knot and line

[Sketcher] Disallow tangent at C0 knot

If passed on to planegcs can cause segmentation fault.

[Sketcher] (Re-)Support tangent at B-spline end-knots

New code had introduced problems for non-periodic spline end-points, and
periodic spline "end-points" were not supported anyway.

(here end-points mean star/end points)
This commit is contained in:
Ajinkya Dahale
2022-09-21 20:26:56 +05:30
committed by Chris Hennes
parent 4c71957a97
commit 75f2a1d69a
4 changed files with 94 additions and 8 deletions

View File

@@ -2454,6 +2454,48 @@ int Sketch::addAngleAtPointConstraint(
if(avp)
geoId3 = checkGeoId(geoId3);
if ((Geoms[geoId1].type == BSpline && Geoms[geoId2].type == Line) ||
(Geoms[geoId1].type == Line && Geoms[geoId2].type == BSpline)) {
if (cTyp == Tangent) {
if (Geoms[geoId1].type == Line && Geoms[geoId2].type == BSpline) {
std::swap(geoId1, geoId2);
std::swap(pos1, pos2);
}
GCS::BSpline &b = BSplines[Geoms[geoId1].index];
GCS::Line &l = Lines[Geoms[geoId2].index];
size_t knotindex = b.knots.size();
if (avp) {
auto knotIt = std::find(b.knotpointGeoids.begin(),
b.knotpointGeoids.end(), geoId3);
knotindex =
std::distance(b.knotpointGeoids.begin(), knotIt);
}
else {
knotindex = (pos1 == PointPos::start) ? 0 : (b.knots.size() - 1);
}
if (knotindex >= b.knots.size())
return -1;
if (b.mult[knotindex] >= b.degree) {
// Leave handling of start/end of non-periodic B-splines to legacy code
if (b.periodic ||
(pos1 != PointPos::start && pos1 != PointPos::end)) {
Base::Console().Error("addAngleAtPointConstraint: cannot set constraint when B-spline slope is discontinuous at knot!\n");
return -1;
}
}
else {
int tag;
if(e2c)
tag = Sketch::addPointOnObjectConstraint(geoId1, pos1, geoId2, driving);//increases ConstraintsCounter
else
tag = ++ConstraintsCounter;
GCSsys.addConstraintTangentAtBSplineKnot(b, l, knotindex, tag, driving);
return ConstraintsCounter;
}
}
}
if (Geoms[geoId1].type == Point ||
Geoms[geoId2].type == Point){
Base::Console().Error("addAngleAtPointConstraint: one of the curves is a point!\n");

View File

@@ -8492,7 +8492,7 @@ int SketchObject::port_reversedExternalArcs(bool justAnalyze)
/// false - fail (this indicates an error, or that a constraint locking isn't supported).
bool SketchObject::AutoLockTangencyAndPerpty(Constraint *cstr, bool bForce, bool bLock)
{
try{
try {
//assert ( cstr->Type == Tangent || cstr->Type == Perpendicular);
if(cstr->getValue() != 0.0 && ! bForce) /*tangency type already set. If not bForce - don't touch.*/
return true;
@@ -8536,7 +8536,8 @@ bool SketchObject::AutoLockTangencyAndPerpty(Constraint *cstr, bool bForce, bool
cstr->setValue(angleDesire + angleOffset); //external tangency. The angle stored is offset by Pi/2 so that a value of 0.0 is invalid and treated as "undecided".
}
}
} catch (Base::Exception& e){
}
catch (Base::Exception& e){
//failure to determine tangency type is not a big deal, so a warning.
Base::Console().Warning("Error in AutoLockTangency. %s \n", e.what());
return false;

View File

@@ -4198,7 +4198,8 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
};
strError = QObject::tr("With 3 objects, there must be 2 curves and 1 point.", "tangent constraint");
} else if (SubNames.size() == 2) {
}
else if (SubNames.size() == 2) {
if (isVertex(GeoId1,PosId1) && isVertex(GeoId2,PosId2)) { // endpoint-to-endpoint tangency
@@ -4218,16 +4219,44 @@ void CmdSketcherConstrainTangent::activated(int iMsg)
return;
}
else if ((isVertex(GeoId1,PosId1) && isEdge(GeoId2,PosId2)) ||
(isEdge(GeoId1,PosId1) && isVertex(GeoId2,PosId2))) { // endpoint-to-curve tangency
(isEdge(GeoId1,PosId1) && isVertex(GeoId2,PosId2))) { // endpoint-to-curve/knot-to-curve tangency
if (isVertex(GeoId2,PosId2)) {
std::swap(GeoId1,GeoId2);
std::swap(PosId1,PosId2);
}
if (isSimpleVertex(Obj, GeoId1, PosId1)) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Cannot add a tangency constraint at an unconnected point!"));
return;
if (isBsplineKnot(Obj, GeoId1)) {
// find the B-spline and treat as TangentViaPoint
openCommand(QT_TRANSLATE_NOOP("Command", "Add tangent constraint"));
const std::vector<Constraint *> &constraints = Obj->Constraints.getValues();
for (const auto& constraint: constraints) {
// TODO: wrap around with try-catch
if (constraint->Type == Sketcher::ConstraintType::InternalAlignment &&
constraint->First == GeoId1 &&
constraint->AlignmentType == Sketcher::InternalAlignmentType::BSplineKnotPoint) {
int GeoId3 = constraint->Second;
// TODO: ensure C1 continuity at point
if(! IsPointAlreadyOnCurve(GeoId2, GeoId1, PosId1, Obj)){
Gui::cmdAppObjectArgs(selection[0].getObject(), "addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
GeoId1,static_cast<int>(PosId1),GeoId2);
}
Gui::cmdAppObjectArgs(selection[0].getObject(), "addConstraint(Sketcher.Constraint('TangentViaPoint',%d,%d,%d,%d)) ",
GeoId3,GeoId2,GeoId1,static_cast<int>(PosId1));
commitCommand();
tryAutoRecompute(Obj);
getSelection().clearSelection();
return;
}
}
}
else {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Cannot add a tangency constraint at an unconnected point!"));
return;
}
}
const Part::Geometry *geom2 = Obj->getGeometry(GeoId2);

View File

@@ -226,8 +226,22 @@ bool SketcherGui::IsPointAlreadyOnCurve(int GeoIdCurve, int GeoIdPoint, Sketcher
//Simple geometric test seems to be the best, because a point can be
// constrained to a curve in a number of ways (e.g. it is an endpoint of an
// arc, or is coincident to endpoint of an arc, or it is an endpoint of an
// ellipse's majopr diameter line). Testing all those possibilities is way
// ellipse's major diameter line). Testing all those possibilities is way
// too much trouble, IMO(DeepSOIC).
// One exception: check for knots on their B-splines, at least until point on B-spline is implemented. (Ajinkya)
if (isBsplineKnot(Obj, GeoIdPoint)) {
const Part::Geometry *geoCurve = Obj->getGeometry(GeoIdCurve);
if (geoCurve->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) {
const std::vector<Constraint *> &constraints = Obj->Constraints.getValues();
for (const auto& constraint: constraints) {
if (constraint->Type == Sketcher::ConstraintType::InternalAlignment &&
constraint->First == GeoIdPoint &&
constraint->Second == GeoIdCurve)
return true;
}
}
}
Base::Vector3d p = Obj->getPoint(GeoIdPoint, PosIdPoint);
return Obj->isPointOnCurve(GeoIdCurve, p.x, p.y);
}