[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).
This commit is contained in:
Ajinkya Dahale
2023-04-14 12:06:47 +05:30
committed by Chris Hennes
parent f8f159c4d3
commit da7d5391af
4 changed files with 54 additions and 8 deletions

View File

@@ -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<Base::Vector3d> poles1 = bsp1->getPoles();
std::vector<double> weights1 = bsp1->getWeights();
std::vector<double> knots1 = bsp1->getKnots();
@@ -3916,13 +3934,18 @@ int SketchObject::join(int geoId1, Sketcher::PointPos posId1, int geoId2, Sketch
std::vector<double> newKnots(std::move(knots1));
std::vector<int> 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()),

View File

@@ -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<int>& geoIdList,

View File

@@ -1336,15 +1336,17 @@ PyObject* SketchObjectPy::join(PyObject* args)
int GeoId1(Sketcher::GeoEnum::GeoUndef), GeoId2(Sketcher::GeoEnum::GeoUndef);
int PosId1 = static_cast<int>(Sketcher::PointPos::none),
PosId2 = static_cast<int>(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 << ")";

View File

@@ -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<int>(PosIds[0]),
GeoIds[1],
static_cast<int>(PosIds[1]));
static_cast<int>(PosIds[1]),
tangentConstraintExists ? 1 : 0);
applied = true;
// Warning: GeoId list will have changed