[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:
committed by
Chris Hennes
parent
4c71957a97
commit
75f2a1d69a
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user