From 982152c332480663c0b1e0ecdf56fd9dc5d69191 Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Mon, 16 Jan 2023 22:51:20 +0530 Subject: [PATCH] [Sketcher] Add line tangent at knot through endpoint --- src/Mod/Sketcher/App/Sketch.cpp | 77 +++++++++++++++++++-- src/Mod/Sketcher/App/Sketch.h | 1 + src/Mod/Sketcher/Gui/CommandConstraints.cpp | 21 +++++- 3 files changed, 89 insertions(+), 10 deletions(-) diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index f079501703..70c251d173 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -1715,15 +1715,18 @@ int Sketch::addConstraint(const Constraint *constraint) c.value, constraint->Type, c.driving); } break; - case Tangent: + case Tangent: { + bool isSpecialCase = false; + if (constraint->FirstPos == PointPos::none && constraint->SecondPos == PointPos::none && constraint->Third == GeoEnum::GeoUndef){ //simple tangency rtn = addTangentConstraint(constraint->First,constraint->Second); + + isSpecialCase = true; } else if (constraint->FirstPos == PointPos::start && - constraint->SecondPos == PointPos::none && constraint->Third == GeoEnum::GeoUndef) { // check for B-Spline Knot to curve tangency auto knotgeoId = checkGeoId(constraint->First); @@ -1737,13 +1740,25 @@ int Sketch::addConstraint(const Constraint *constraint) auto linegeoid = checkGeoId(constraint->Second); - if (Geoms[linegeoid].type == Line) - rtn = addTangentLineAtBSplineKnotConstraint( - linegeoid, bsplinegeoid, knotgeoId); + if (Geoms[linegeoid].type == Line) { + if (constraint->SecondPos == PointPos::none) { + rtn = addTangentLineAtBSplineKnotConstraint( + linegeoid, bsplinegeoid, knotgeoId); + + isSpecialCase = true; + } + else if (constraint->SecondPos == PointPos::start || + constraint->SecondPos == PointPos::end) { + rtn = addTangentLineEndpointAtBSplineKnotConstraint( + linegeoid, constraint->SecondPos, bsplinegeoid, knotgeoId); + + isSpecialCase = true; + } + } } } } - else { + if (!isSpecialCase) { //any other point-wise tangency (endpoint-to-curve, endpoint-to-endpoint, tangent-via-point) c.value = new double(constraint->getValue()); if(c.driving) @@ -1760,6 +1775,7 @@ int Sketch::addConstraint(const Constraint *constraint) c.value, constraint->Type, c.driving); } break; + } case Distance: if (constraint->SecondPos != PointPos::none){ // point to point distance c.value = new double(constraint->getValue()); @@ -2497,6 +2513,53 @@ int Sketch::addTangentLineAtBSplineKnotConstraint(int checkedlinegeoId, int chec } } +int Sketch::addTangentLineEndpointAtBSplineKnotConstraint(int checkedlinegeoId, PointPos endpointPos, int checkedbsplinegeoId, int checkedknotgeoid) +{ + GCS::BSpline &b = BSplines[Geoms[checkedbsplinegeoId].index]; + GCS::Line &l = Lines[Geoms[checkedlinegeoId].index]; + auto pointId = getPointId(checkedlinegeoId, endpointPos); + auto pointIdKnot = getPointId(checkedknotgeoid, PointPos::start); + GCS::Point &p = Points[pointId]; + GCS::Point &pk = Points[pointIdKnot]; + + size_t knotindex = b.knots.size(); + + auto knotIt = std::find(b.knotpointGeoids.begin(), + b.knotpointGeoids.end(), checkedknotgeoid); + + knotindex = std::distance(b.knotpointGeoids.begin(), knotIt); + + if (knotindex >= b.knots.size()){ + Base::Console().Error("addConstraint: Knot index out-of-range!\n"); + return -1; + } + + if (b.mult[knotindex] >= b.degree) { + if (b.periodic || (knotindex > 0 && knotindex < (b.knots.size()-1))) { + Base::Console().Error("addTangentLineEndpointAtBSplineKnotConstraint: cannot set constraint when B-spline slope is discontinuous at knot!\n"); + return -1; + } + else { + // TODO: Let angle-at-point do the work. Requires a `double * value` + // return addAngleAtPointConstraint( + // linegeoid, endpointPos, + // bsplinegeoid, PointPos::none, + // knotgeoId, PointPos::start, + // nullptr, Tangent, true); + + // For now we just throw an error. + Base::Console().Error("addTangentLineEndpointAtBSplineKnotConstraint: This method cannot set tangent constraint at end knots of a B-spline. Please constrain the start/end points instead.\n"); + return -1; + } + } + else { + int tag = ++ConstraintsCounter; + GCSsys.addConstraintP2PCoincident(p, pk, tag); + GCSsys.addConstraintTangentAtBSplineKnot(b, l, knotindex, tag); + return ConstraintsCounter; + } +} + //This function handles any type of tangent, perpendicular and angle // constraint that involves a point. // i.e. endpoint-to-curve, endpoint-to-endpoint and tangent-via-point @@ -3032,7 +3095,7 @@ int Sketch::addSnellsLawConstraint(int geoIdRay1, PointPos posRay1, GCS::Point &p1 = Points[pointId1]; // add the parameters (refractive indexes) - // n1 uses the place hold by n2divn1, so that is retrivable in updateNonDrivingConstraints + // n1 uses the place hold by n2divn1, so that is retrievable in updateNonDrivingConstraints double *n1 = value; double *n2 = secondvalue; diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h index 3d33f93e67..b161fa676a 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -283,6 +283,7 @@ public: /// add a tangency constraint between two geometries int addTangentConstraint(int geoId1, int geoId2); int addTangentLineAtBSplineKnotConstraint(int checkedlinegeoId, int checkedbsplinegeoId, int checkedknotgeoid); + int addTangentLineEndpointAtBSplineKnotConstraint(int checkedlinegeoId, PointPos endpointPos, int checkedbsplinegeoId, int checkedknotgeoid); int addAngleAtPointConstraint( int geoId1, PointPos pos1, int geoId2, PointPos pos2, diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 20e7cca390..ffde840d65 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -4203,11 +4203,26 @@ void CmdSketcherConstrainTangent::activated(int iMsg) if (isVertex(GeoId1,PosId1) && isVertex(GeoId2,PosId2)) { // endpoint-to-endpoint tangency + if (isBsplineKnot(Obj, GeoId2)) { + std::swap(GeoId1,GeoId2); + std::swap(PosId1,PosId2); + } + if (isSimpleVertex(Obj, GeoId1, PosId1) || isSimpleVertex(Obj, GeoId2, PosId2)) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Cannot add a tangency constraint at an unconnected point!")); - return; + if (isBsplineKnot(Obj, GeoId1)) { + const Part::Geometry *geom2 = Obj->getGeometry(GeoId2); + if (!geom2 || geom2->getTypeId() !=Part::GeomLineSegment::getClassTypeId()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Tangent constraint at B-spline knot is only supported with lines!")); + return; + } + } + else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Cannot add a tangency constraint at an unconnected point!")); + return; + } } openCommand(QT_TRANSLATE_NOOP("Command", "Add tangent constraint"));