From da7d5391af0bce35fee822d1fc598f0b813b0982 Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Fri, 14 Apr 2023 12:06:47 +0530 Subject: [PATCH] [Sketcher] Join curves with C1 continuity If endpoint-to-endpoint tangent constraint exists between the connecting points of the curves to be joined, also apply C1 continuity (i.e. a knot multiplicity of degree-1). --- src/Mod/Sketcher/App/SketchObject.cpp | 32 +++++++++++++++++-- src/Mod/Sketcher/App/SketchObject.h | 6 +++- src/Mod/Sketcher/App/SketchObjectPyImp.cpp | 6 ++-- .../Sketcher/Gui/CommandSketcherBSpline.cpp | 18 +++++++++-- 4 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index a9f985b851..2f0bf3934f 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -3840,7 +3840,7 @@ int SketchObject::split(int GeoId, const Base::Vector3d& point) return -1; } -int SketchObject::join(int geoId1, Sketcher::PointPos posId1, int geoId2, Sketcher::PointPos posId2) +int SketchObject::join(int geoId1, Sketcher::PointPos posId1, int geoId2, Sketcher::PointPos posId2, int continuity) { // No need to check input data validity as this is an sketchobject managed operation @@ -3901,7 +3901,25 @@ int SketchObject::join(int geoId1, Sketcher::PointPos posId1, int geoId2, Sketch else if (bsp2->getDegree() < bsp1->getDegree()) bsp2->increaseDegree(bsp1->getDegree()); - // TODO: set up vectors for new poles, knots, mults + // TODO: Check for tangent constraint here + bool makeC1Continuous = (continuity >= 1); + + // TODO: Rescale one or both sections to fulfill some purpose. + // This could include making param between [0,1], and/or making + // C1 continuity possible. + if (makeC1Continuous) { + // We assume here that there is already G1 continuity. + // Just scale parameters to get C1. + Base::Vector3d slope1 = bsp1->firstDerivativeAtParameter(bsp1->getLastParameter()); + Base::Vector3d slope2 = bsp2->firstDerivativeAtParameter(bsp2->getFirstParameter()); + // TODO: slope2 can technically be a zero vector + // But that seems not possible unless the spline is trivial. + // Prove or account for the possibility. + double scale = slope2.Length() / slope1.Length(); + bsp2->scaleKnotsToBounds(0, scale * (bsp2->getLastParameter() - bsp2->getFirstParameter())); + } + + // set up vectors for new poles, knots, mults std::vector poles1 = bsp1->getPoles(); std::vector weights1 = bsp1->getWeights(); std::vector knots1 = bsp1->getKnots(); @@ -3916,13 +3934,18 @@ int SketchObject::join(int geoId1, Sketcher::PointPos posId1, int geoId2, Sketch std::vector newKnots(std::move(knots1)); std::vector newMults(std::move(mults1)); + poles2.erase(poles2.begin()); + if (makeC1Continuous) + newPoles.erase(newPoles.end()-1); newPoles.insert(newPoles.end(), std::make_move_iterator(poles2.begin()), std::make_move_iterator(poles2.end())); // TODO: Weights might need to be scaled weights2.erase(weights2.begin()); + if (makeC1Continuous) + newWeights.erase(newWeights.end()-1); newWeights.insert(newWeights.end(), std::make_move_iterator(weights2.begin()), std::make_move_iterator(weights2.end())); @@ -3938,7 +3961,10 @@ int SketchObject::join(int geoId1, Sketcher::PointPos posId1, int geoId2, Sketch // end knots can have a multiplicity of (degree + 1) if (bsp1->getDegree() < newMults.back()) - newMults.back() = bsp1->getDegree(); + if (makeC1Continuous) + newMults.back() = bsp1->getDegree()-1; + else + newMults.back() = bsp1->getDegree(); mults2.erase(mults2.begin()); newMults.insert(newMults.end(), std::make_move_iterator(mults2.begin()), diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index 8a72250b67..d0f3b99ba1 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -354,7 +354,11 @@ public: \param geoId1, posId1, geoId2, posId2: the end points to join \retval - 0 on success, -1 on failure */ - int join(int geoId1, Sketcher::PointPos posId1, int geoId2, Sketcher::PointPos posId2); + int join(int geoId1, + Sketcher::PointPos posId1, + int geoId2, + Sketcher::PointPos posId2, + int continuity = 0); /// adds symmetric geometric elements with respect to the refGeoId (line or point) int addSymmetric(const std::vector& geoIdList, diff --git a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp index ee192870f5..631e90b8f8 100644 --- a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp +++ b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp @@ -1336,15 +1336,17 @@ PyObject* SketchObjectPy::join(PyObject* args) int GeoId1(Sketcher::GeoEnum::GeoUndef), GeoId2(Sketcher::GeoEnum::GeoUndef); int PosId1 = static_cast(Sketcher::PointPos::none), PosId2 = static_cast(Sketcher::PointPos::none); + int continuity = 0; - if (!PyArg_ParseTuple(args, "iiii", &GeoId1, &PosId1, &GeoId2, &PosId2)) { + if (!PyArg_ParseTuple(args, "iiii|i", &GeoId1, &PosId1, &GeoId2, &PosId2, &continuity)) { return nullptr; } if (this->getSketchObjectPtr()->join(GeoId1, (Sketcher::PointPos)PosId1, GeoId2, - (Sketcher::PointPos)PosId2)) { + (Sketcher::PointPos)PosId2, + continuity)) { std::stringstream str; str << "Not able to join the curves with end points: (" << GeoId1 << ", " << PosId1 << "), (" << GeoId2 << ", " << PosId2 << ")"; diff --git a/src/Mod/Sketcher/Gui/CommandSketcherBSpline.cpp b/src/Mod/Sketcher/Gui/CommandSketcherBSpline.cpp index 3fa34fcbed..0ff88432d7 100644 --- a/src/Mod/Sketcher/Gui/CommandSketcherBSpline.cpp +++ b/src/Mod/Sketcher/Gui/CommandSketcherBSpline.cpp @@ -1052,16 +1052,30 @@ void CmdSketcherJoinCurves::activated(int iMsg) } } + // TODO: Check for tangent constraints between these the two points. + // These need to be explicit: indirect tangency because poles are collinear will not work. + bool tangentConstraintExists = false; + for (const auto& constr : Obj->Constraints.getValues()) { + if (constr->Type == Sketcher::ConstraintType::Tangent + && ((constr->First == GeoIds[0] && constr->FirstPos == PosIds[0] + && constr->Second == GeoIds[1] && constr->SecondPos == PosIds[1]) + || (constr->First == GeoIds[1] && constr->FirstPos == PosIds[1] + && constr->Second == GeoIds[0] && constr->SecondPos == PosIds[0]))) { + tangentConstraintExists = true; + } + } + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Join Curves")); bool applied = false; try { Gui::cmdAppObjectArgs(selection[0].getObject(), - "join(%d, %d, %d, %d) ", + "join(%d, %d, %d, %d, %d) ", GeoIds[0], static_cast(PosIds[0]), GeoIds[1], - static_cast(PosIds[1])); + static_cast(PosIds[1]), + tangentConstraintExists ? 1 : 0); applied = true; // Warning: GeoId list will have changed