[Sketcher] Add methods and tools for joining curves

Algorithm to join b-splines:
The code simple concatenates the knots, poles, weights, and knot multiplicities
together, removing data on the connection point of the second curve. Some
further study is needed to see if/when it will give an exact/good connection.

Icon courtesy @bitacovir.
This commit is contained in:
Ajinkya Dahale
2022-03-04 00:27:22 -05:00
committed by abdullahtahiriyo
parent f79c66dc33
commit 01866dfbfc
8 changed files with 795 additions and 2 deletions

View File

@@ -3267,6 +3267,147 @@ int SketchObject::split(int GeoId, const Base::Vector3d &point)
return -1;
}
int SketchObject::join(int geoId1, Sketcher::PointPos posId1,
int geoId2, Sketcher::PointPos posId2)
{
// No need to check input data validity as this is an sketchobject managed operation
Base::StateLocker lock(managedoperation, true);
if (Sketcher::PointPos::start != posId1 && Sketcher::PointPos::end != posId1 &&
Sketcher::PointPos::start != posId2 && Sketcher::PointPos::end != posId2) {
THROWM(ValueError,"Invalid position(s): points must be start or end points of a curve.");
return -1;
}
if (geoId1 == geoId2) {
THROWM(ValueError,"Connecting the end points of the same curve is not yet supported.");
return -1;
}
if (geoId1 < 0 || geoId1 > getHighestCurveIndex() ||
geoId2 < 0 || geoId2 > getHighestCurveIndex()) {
return -1;
}
// get the old splines
auto* geo1 = getGeometry(geoId1);
auto* geo2 = getGeometry(geoId2);
if (GeometryFacade::getConstruction(geo1) != GeometryFacade::getConstruction(geo2)) {
THROWM(ValueError,"Cannot join construction and non-construction geometries.");
return -1;
}
// TODO: make both curves b-splines here itself
if (geo1->getTypeId() != Part::GeomBSplineCurve::getClassTypeId()) {
THROWM(ValueError,"Please convert both curves to NURBS before attempting to join them.");
return -1;
}
if (geo2->getTypeId() != Part::GeomBSplineCurve::getClassTypeId()) {
THROWM(ValueError,"Please convert both curves to NURBS before attempting to join them.");
return -1;
}
// TODO: is there a cleaner way to get our mutable bsp's?
// we need the splines to be mutable because we may reverse them
// and/or change their degree
auto* constbsp1 = static_cast<const Part::GeomBSplineCurve *>(geo1);
auto* constbsp2 = static_cast<const Part::GeomBSplineCurve *>(geo2);
const Handle(Geom_BSplineCurve) curve1 = Handle(Geom_BSplineCurve)::DownCast(constbsp1->handle());
const Handle(Geom_BSplineCurve) curve2 = Handle(Geom_BSplineCurve)::DownCast(constbsp2->handle());
std::unique_ptr<Part::GeomBSplineCurve> bsp1(new Part::GeomBSplineCurve(curve1));
std::unique_ptr<Part::GeomBSplineCurve> bsp2(new Part::GeomBSplineCurve(curve2));
if (bsp1->isPeriodic() || bsp2->isPeriodic()) {
THROWM(ValueError,"It is only possible to join non-periodic curves.");
return -1;
}
// reverse the splines if needed: join end of 1st to start of 2nd
if (Sketcher::PointPos::start == posId1)
bsp1->reverse();
if (Sketcher::PointPos::end == posId2)
bsp2->reverse();
// ensure the degrees of both curves are the same
if (bsp1->getDegree() < bsp2->getDegree())
bsp1->increaseDegree(bsp2->getDegree());
else if (bsp2->getDegree() < bsp1->getDegree())
bsp2->increaseDegree(bsp1->getDegree());
// TODO: 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();
std::vector<int> mults1 = bsp1->getMultiplicities();
std::vector<Base::Vector3d> poles2 = bsp2->getPoles();
std::vector<double> weights2 = bsp2->getWeights();
std::vector<double> knots2 = bsp2->getKnots();
std::vector<int> mults2 = bsp2->getMultiplicities();
std::vector<Base::Vector3d> newPoles(std::move(poles1));
std::vector<double> newWeights(std::move(weights1));
std::vector<double> newKnots(std::move(knots1));
std::vector<int> newMults(std::move(mults1));
poles2.erase(poles2.begin());
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());
newWeights.insert(newWeights.end(),
std::make_move_iterator(weights2.begin()),
std::make_move_iterator(weights2.end()));
// knots of the second spline come after all of the first
double offset = newKnots.back() - knots2.front();
knots2.erase(knots2.begin());
for (auto& knot : knots2)
knot += offset;
newKnots.insert(newKnots.end(),
std::make_move_iterator(knots2.begin()),
std::make_move_iterator(knots2.end()));
// end knots can have a multiplicity of (degree + 1)
if (bsp1->getDegree() < newMults.back())
newMults.back() = bsp1->getDegree();
mults2.erase(mults2.begin());
newMults.insert(newMults.end(),
std::make_move_iterator(mults2.begin()),
std::make_move_iterator(mults2.end()));
Part::GeomBSplineCurve* newSpline =
new Part::GeomBSplineCurve(newPoles, newWeights, newKnots, newMults,
bsp1->getDegree(), false, true);
int newGeoId = addGeometry(newSpline);
if (newGeoId < 0) {
THROWM(ValueError,"Failed to create joined curve.");
return -1;
}
else {
exposeInternalGeometry(newGeoId);
setConstruction(newGeoId, GeometryFacade::getConstruction(geo1));
// TODO: transfer constraints on the non-connected ends
auto otherPosId1 = (Sketcher::PointPos::start == posId1) ? Sketcher::PointPos::end : Sketcher::PointPos::start;
auto otherPosId2 = (Sketcher::PointPos::start == posId2) ? Sketcher::PointPos::end : Sketcher::PointPos::start;
transferConstraints(geoId1, otherPosId1, newGeoId, PointPos::start, true);
transferConstraints(geoId2, otherPosId2, newGeoId, PointPos::end, true);
delGeometries({geoId1, geoId2});
return 0;
}
return -1;
}
bool SketchObject::isExternalAllowed(App::Document *pDoc, App::DocumentObject *pObj, eReasonList* rsn) const
{
if (rsn)

View File

@@ -289,6 +289,14 @@ public:
int extend(int geoId, double increment, PointPos endPoint);
/// split a curve
int split(int geoId, const Base::Vector3d &point);
/*!
\brief Join one or two curves at the given end points
\details The combined curve will be a b-spline
\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);
/// adds symmetric geometric elements with respect to the refGeoId (line or point)
int addSymmetric(const std::vector<int> &geoIdList, int refGeoId, Sketcher::PointPos refPosId=Sketcher::PointPos::none);

View File

@@ -222,6 +222,11 @@ If there is no such constraint an exception is raised.
<UserDocu>split a curve with a given id at a given reference point</UserDocu>
</Documentation>
</Methode>
<Methode Name="join">
<Documentation>
<UserDocu>join two curves at the given end points</UserDocu>
</Documentation>
</Methode>
<Methode Name="addSymmetric">
<Documentation>
<UserDocu>add a symmetric geometric objects to the sketch with respect to a reference point or line</UserDocu>

View File

@@ -1169,6 +1169,28 @@ PyObject* SketchObjectPy::split(PyObject *args)
Py_Return;
}
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);
if (!PyArg_ParseTuple(args, "iiii", &GeoId1, &PosId1, &GeoId2, &PosId2))
return 0;
if (this->getSketchObjectPtr()->join(GeoId1, (Sketcher::PointPos) PosId1,
GeoId2, (Sketcher::PointPos) PosId2)) {
std::stringstream str;
str << "Not able to join the curves with end points: ("
<< GeoId1 << ", " << PosId1 << "), ("
<< GeoId2 << ", " << PosId2 << ")";
PyErr_SetString(PyExc_ValueError, str.str().c_str());
return 0;
}
Py_Return;
}
PyObject* SketchObjectPy::addSymmetric(PyObject *args)
{
PyObject *pcObj;

View File

@@ -1196,6 +1196,99 @@ bool CmdSketcherInsertKnot::isActive()
return isSketcherBSplineActive(getActiveGuiDocument(), true);
}
DEF_STD_CMD_A(CmdSketcherJoinCurves)
CmdSketcherJoinCurves::CmdSketcherJoinCurves()
: Command("Sketcher_JoinCurves")
{
sAppModule = "Sketcher";
sGroup = "Sketcher";
sMenuText = QT_TR_NOOP("Join curves");
sToolTipText = QT_TR_NOOP("Join two curves at selected end points");
sWhatsThis = "Sketcher_JoinCurves";
sStatusTip = sToolTipText;
sPixmap = "Sketcher_JoinCurves";
sAccel = "";
eType = ForEdit;
}
void CmdSketcherJoinCurves::activated(int iMsg)
{
Q_UNUSED(iMsg);
// TODO: confirm whether or not we need to check for OCC version
#if OCC_VERSION_HEX < 0x060900
QMessageBox::warning(Gui::getMainWindow(),
QObject::tr("Wrong OCE/OCC version"),
QObject::tr("This version of OCE/OCC "
"does not support knot operation. "
"You need 6.9.0 or higher"));
return;
#endif
// get the selection
std::vector<Gui::SelectionObject> selection;
selection = getSelection().getSelectionEx(0, Sketcher::SketchObject::getClassTypeId());
// only one sketch with its subelements are allowed to be selected
if (selection.size() != 1) {
return;
}
// get the needed lists and objects
const std::vector<std::string> &SubNames = selection[0].getSubNames();
if (SubNames.size() == 0) {
// Check that something is selected
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection is empty"),
QObject::tr("Nothing is selected. Please select end points of curves."));
return;
}
if (SubNames.size() != 2) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Two end points should be selected."));
return;
}
Sketcher::SketchObject* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject());
int GeoIds[2];
Sketcher::PointPos PosIds[2];
getIdsFromName(SubNames[0], Obj, GeoIds[0], PosIds[0]);
getIdsFromName(SubNames[1], Obj, GeoIds[1], PosIds[1]);
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Join Curves"));
bool applied = false;
try {
Gui::cmdAppObjectArgs(selection[0].getObject(), "join(%d, %d, %d, %d) ",
GeoIds[0], static_cast<int>(PosIds[0]),
GeoIds[1], static_cast<int>(PosIds[1]));
applied = true;
// Warning: GeoId list will have changed
}
catch (const Base::Exception& e) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Error"),
QObject::tr(getStrippedPythonExceptionString(e).c_str()));
getSelection().clearSelection();
}
if (applied)
Gui::Command::commitCommand();
else
Gui::Command::abortCommand();
tryAutoRecomputeIfNotSolve(Obj);
getSelection().clearSelection();
}
bool CmdSketcherJoinCurves::isActive(void)
{
return isSketcherBSplineActive(getActiveGuiDocument(), true);
}
void CreateSketcherCommandsBSpline()
{
Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager();
@@ -1213,4 +1306,5 @@ void CreateSketcherCommandsBSpline()
rcCmdMgr.addCommand(new CmdSketcherDecreaseKnotMultiplicity());
rcCmdMgr.addCommand(new CmdSketcherCompModifyKnotMultiplicity());
rcCmdMgr.addCommand(new CmdSketcherInsertKnot());
rcCmdMgr.addCommand(new CmdSketcherJoinCurves());
}

View File

@@ -216,6 +216,7 @@
<file>icons/splines/Sketcher_BSplineIncreaseDegree.svg</file>
<file>icons/splines/Sketcher_BSplineIncreaseKnotMultiplicity.svg</file>
<file>icons/splines/Sketcher_BSplineInsertKnot.svg</file>
<file>icons/splines/Sketcher_JoinCurves.svg</file>
<file>icons/splines/Sketcher_BSplineKnotMultiplicity.svg</file>
<file>icons/splines/Sketcher_BSplinePoleWeight.svg</file>
<file>icons/splines/Sketcher_BSplinePolygon.svg</file>

View File

@@ -0,0 +1,520 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
id="svg2918"
height="64px"
width="64px">
<title
id="title927">Sketcher_BSplineJoin</title>
<defs
id="defs2920">
<linearGradient
id="linearGradient3144">
<stop
id="stop3146"
offset="0"
style="stop-color:#ffffff;stop-opacity:1;" />
<stop
id="stop3148"
offset="1"
style="stop-color:#ffffff;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient3144-3">
<stop
id="stop3146-1"
offset="0"
style="stop-color:#ffffff;stop-opacity:1;" />
<stop
id="stop3148-5"
offset="1"
style="stop-color:#ffffff;stop-opacity:0;" />
</linearGradient>
<radialGradient
r="34.345188"
fy="672.79736"
fx="225.26402"
cy="672.79736"
cx="225.26402"
gradientTransform="matrix(1,0,0,0.6985294,0,202.82863)"
gradientUnits="userSpaceOnUse"
id="radialGradient3958"
xlink:href="#linearGradient3144" />
<radialGradient
r="34.345188"
fy="672.79736"
fx="225.26402"
cy="672.79736"
cx="225.26402"
gradientTransform="matrix(1,0,0,0.6985294,0,202.82863)"
gradientUnits="userSpaceOnUse"
id="radialGradient3960"
xlink:href="#linearGradient3144-3" />
<radialGradient
r="34.345188"
fy="672.79736"
fx="225.26402"
cy="672.79736"
cx="225.26402"
gradientTransform="matrix(1,0,0,0.6985294,0,202.82863)"
gradientUnits="userSpaceOnUse"
id="radialGradient3042"
xlink:href="#linearGradient3144" />
<radialGradient
r="34.345188"
fy="672.79736"
fx="225.26402"
cy="672.79736"
cx="225.26402"
gradientTransform="matrix(1,0,0,0.6985294,0,202.82863)"
gradientUnits="userSpaceOnUse"
id="radialGradient3068"
xlink:href="#linearGradient3144" />
<radialGradient
r="34.345188"
fy="672.79736"
fx="225.26402"
cy="672.79736"
cx="225.26402"
gradientTransform="matrix(1,0,0,0.6985294,0,202.82863)"
gradientUnits="userSpaceOnUse"
id="radialGradient3880"
xlink:href="#linearGradient3144" />
<radialGradient
r="34.345188"
fy="672.79736"
fx="225.26402"
cy="672.79736"
cx="225.26402"
gradientTransform="matrix(1,0,0,0.6985294,0,202.82863)"
gradientUnits="userSpaceOnUse"
id="radialGradient4654"
xlink:href="#linearGradient3144" />
<radialGradient
r="34.345188"
fy="672.79736"
fx="225.26402"
cy="672.79736"
cx="225.26402"
gradientTransform="matrix(1,0,0,0.6985294,0,202.82863)"
gradientUnits="userSpaceOnUse"
id="radialGradient4693"
xlink:href="#linearGradient3144" />
<linearGradient
xlink:href="#linearGradient3836-9-3-9"
id="linearGradient3131-2"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
id="linearGradient3836-9-3-9">
<stop
id="stop3838-8-5-1"
offset="0"
style="stop-color:#a40000;stop-opacity:1" />
<stop
id="stop3840-1-6-2"
offset="1"
style="stop-color:#ef2929;stop-opacity:1" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3836-9-3-6-0"
id="linearGradient3171-7"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
id="linearGradient3836-9-3-6-0">
<stop
id="stop3838-8-5-7-9"
offset="0"
style="stop-color:#a40000;stop-opacity:1" />
<stop
id="stop3840-1-6-5-3"
offset="1"
style="stop-color:#ef2929;stop-opacity:1" />
</linearGradient>
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3262"
xlink:href="#linearGradient3836-9-3" />
<linearGradient
id="linearGradient3836-9-3">
<stop
id="stop3838-8-5"
offset="0"
style="stop-color:#a40000;stop-opacity:1" />
<stop
id="stop3840-1-6"
offset="1"
style="stop-color:#ef2929;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient3836-9-3-6">
<stop
id="stop3838-8-5-7"
offset="0"
style="stop-color:#a40000;stop-opacity:1" />
<stop
id="stop3840-1-6-5"
offset="1"
style="stop-color:#ef2929;stop-opacity:1" />
</linearGradient>
<linearGradient
gradientTransform="matrix(0.93724177,0,0,0.93725692,-1.2227671,0.70650014)"
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3264-1"
xlink:href="#linearGradient3836-9-3-6-7" />
<linearGradient
id="linearGradient3836-9-3-6-7">
<stop
id="stop3838-8-5-7-4"
offset="0"
style="stop-color:#a40000;stop-opacity:1" />
<stop
id="stop3840-1-6-5-0"
offset="1"
style="stop-color:#ef2929;stop-opacity:1" />
</linearGradient>
<linearGradient
gradientTransform="matrix(0.93724177,0,0,0.93725692,-1.2227671,0.70650014)"
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3264-9"
xlink:href="#linearGradient3836-9-3-6-4" />
<linearGradient
id="linearGradient3836-9-3-6-4">
<stop
id="stop3838-8-5-7-8"
offset="0"
style="stop-color:#a40000;stop-opacity:1" />
<stop
id="stop3840-1-6-5-8"
offset="1"
style="stop-color:#ef2929;stop-opacity:1" />
</linearGradient>
<linearGradient
gradientTransform="matrix(0.93724177,0,0,0.93725692,-1.2227671,0.70650014)"
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3264-17"
xlink:href="#linearGradient3836-9-3-6-1" />
<linearGradient
id="linearGradient3836-9-3-6-1">
<stop
id="stop3838-8-5-7-1"
offset="0"
style="stop-color:#a40000;stop-opacity:1" />
<stop
id="stop3840-1-6-5-5"
offset="1"
style="stop-color:#ef2929;stop-opacity:1" />
</linearGradient>
<linearGradient
gradientTransform="matrix(0.93724177,0,0,0.93725692,-1.2227671,0.70650014)"
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3264-3"
xlink:href="#linearGradient3836-9-3-6-2" />
<linearGradient
id="linearGradient3836-9-3-6-2">
<stop
id="stop3838-8-5-7-2"
offset="0"
style="stop-color:#a40000;stop-opacity:1" />
<stop
id="stop3840-1-6-5-1"
offset="1"
style="stop-color:#ef2929;stop-opacity:1" />
</linearGradient>
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3262-5"
xlink:href="#linearGradient3836-9-3-3" />
<linearGradient
id="linearGradient3836-9-3-3">
<stop
id="stop3838-8-5-5"
offset="0"
style="stop-color:#a40000;stop-opacity:1" />
<stop
id="stop3840-1-6-6"
offset="1"
style="stop-color:#ef2929;stop-opacity:1" />
</linearGradient>
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3264"
xlink:href="#linearGradient3836-9-3-6-29" />
<linearGradient
id="linearGradient3836-9-3-6-29">
<stop
id="stop3838-8-5-7-12"
offset="0"
style="stop-color:#a40000;stop-opacity:1" />
<stop
id="stop3840-1-6-5-7"
offset="1"
style="stop-color:#ef2929;stop-opacity:1" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3836-9-3-9-9"
id="linearGradient3131-2-0"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
id="linearGradient3836-9-3-9-9">
<stop
id="stop3838-8-5-1-3"
offset="0"
style="stop-color:#a40000;stop-opacity:1" />
<stop
id="stop3840-1-6-2-6"
offset="1"
style="stop-color:#ef2929;stop-opacity:1" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3836-9-3-6-0-6"
id="linearGradient3171-7-0"
gradientUnits="userSpaceOnUse"
x1="-18"
y1="18"
x2="-22"
y2="5" />
<linearGradient
id="linearGradient3836-9-3-6-0-6">
<stop
id="stop3838-8-5-7-9-2"
offset="0"
style="stop-color:#a40000;stop-opacity:1" />
<stop
id="stop3840-1-6-5-3-6"
offset="1"
style="stop-color:#ef2929;stop-opacity:1" />
</linearGradient>
<linearGradient
gradientTransform="matrix(0.71441909,0,0,0.71408544,-5.531259,3.2604792)"
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientUnits="userSpaceOnUse"
id="linearGradient3931"
xlink:href="#linearGradient3836-9-3-6-29" />
<linearGradient
y2="5"
x2="-22"
y1="18"
x1="-18"
gradientTransform="matrix(0.71441909,0,0,0.71408544,-5.531259,3.2604792)"
gradientUnits="userSpaceOnUse"
id="linearGradient3937-1"
xlink:href="#linearGradient3836-9-3-6-29-8" />
<linearGradient
id="linearGradient3836-9-3-6-29-8">
<stop
id="stop3838-8-5-7-12-7"
offset="0"
style="stop-color:#a40000;stop-opacity:1" />
<stop
id="stop3840-1-6-5-7-9"
offset="1"
style="stop-color:#ef2929;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient3836-9-3-6-29-7">
<stop
id="stop3838-8-5-7-12-5"
offset="0"
style="stop-color:#a40000;stop-opacity:1" />
<stop
id="stop3840-1-6-5-7-92"
offset="1"
style="stop-color:#ef2929;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient3836-9-3-6-29-1">
<stop
id="stop3838-8-5-7-12-2"
offset="0"
style="stop-color:#a40000;stop-opacity:1" />
<stop
id="stop3840-1-6-5-7-93"
offset="1"
style="stop-color:#ef2929;stop-opacity:1" />
</linearGradient>
<linearGradient
gradientUnits="userSpaceOnUse"
y2="131.22015"
x2="154.4444"
y1="161.22015"
x1="164.4444"
id="linearGradient3850"
xlink:href="#linearGradient3836" />
<linearGradient
id="linearGradient3836">
<stop
id="stop3838"
offset="0"
style="stop-color:#3465a4;stop-opacity:1;" />
<stop
id="stop3840"
offset="1"
style="stop-color:#729fcf;stop-opacity:1;" />
</linearGradient>
<linearGradient
y2="131.22015"
x2="154.4444"
y1="161.22015"
x1="164.4444"
gradientTransform="translate(-188.44439,-101.22016)"
gradientUnits="userSpaceOnUse"
id="linearGradient3112"
xlink:href="#linearGradient3836" />
<linearGradient
id="linearGradient3895">
<stop
id="stop3897"
offset="0"
style="stop-color:#729fcf;stop-opacity:1;" />
<stop
id="stop3899"
offset="1"
style="stop-color:#204a87;stop-opacity:1;" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3895"
id="linearGradient989"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.52479408,0.00179447,0.00125537,-0.75015952,-9.0500601,39.653956)"
x1="51.973827"
y1="35.978416"
x2="25.988253"
y2="29.916241" />
<linearGradient
xlink:href="#linearGradient3895"
id="linearGradient1099"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.52479408,0.00179447,0.00125537,-0.75015952,-9.0500601,39.653956)"
x1="51.973827"
y1="35.978416"
x2="25.988253"
y2="29.916241" />
</defs>
<metadata
id="metadata2923">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Sketcher_BSplineJoin</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>[bitacovir]</dc:title>
</cc:Agent>
</dc:creator>
<dc:title>Sketcher_Create_Periodic_BSpline</dc:title>
<dc:date>06-03-2022</dc:date>
<dc:relation></dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier />
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<path
style="fill:none;stroke:#2e3436;stroke-width:12.5366;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
d="M 55.641578,8.1868685 C 57.288732,49.584802 17.403372,29.037685 8.2549696,55.500154"
id="path3266" />
<path
style="fill:none;stroke:#d3d7cf;stroke-width:6.2683;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
d="M 55.641578,8.1868685 C 57.999108,48.322001 17.200318,29.50549 8.2549696,55.500154"
id="path3266-9" />
<path
style="fill:none;stroke:#ffffff;stroke-width:3.13415;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
d="M 54.016393,8.1868685 C 57.606356,46.713599 15.172328,27.635191 6.6297851,55.651091"
id="path3266-9-2" />
<g
transform="matrix(-0.14137236,0.07774155,-0.01888492,-0.10633123,99.823869,75.569613)"
id="g3177" />
<g
transform="matrix(-0.14109247,0.07923086,-0.02087339,-0.10522619,77.138226,86.686164)"
id="g3185" />
<g
id="g1068">
<path
id="path3343-20"
d="m 13.547502,28.511064 v -7.501616 l -10.4959114,1e-6 V 10.507184 H 13.547502 V 3.005568 l 9.44632,12.752748 z"
style="fill:url(#linearGradient989);fill-opacity:1;fill-rule:evenodd;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="path3343-2-9"
d="m 15.03712,23.61475 -0.03666,-4.418275 -10.3125666,-0.08933 -0.036666,-6.608334 10.5325806,0.08933 -0.110007,-4.65436 5.722274,7.824535 z"
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<g
id="g1068-6"
transform="matrix(-1,0,0,1,45.987644,0)">
<path
style="fill:url(#linearGradient1099);fill-opacity:1;fill-rule:evenodd;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 13.547502,28.511064 v -7.501616 l -10.4959114,1e-6 V 10.507184 H 13.547502 V 3.005568 l 9.44632,12.752748 z"
id="path3343-20-4" />
<path
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 15.03712,23.61475 -0.03666,-4.418275 -10.3125666,-0.08933 -0.036666,-6.608334 10.5325806,0.08933 -0.110007,-4.65436 5.722274,7.824535 z"
id="path3343-2-9-3" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -423,7 +423,8 @@ inline void SketcherAddWorkbenchBSplines<Gui::MenuItem>(Gui::MenuItem& bspline)
<< "Sketcher_BSplineDecreaseDegree"
<< "Sketcher_BSplineIncreaseKnotMultiplicity"
<< "Sketcher_BSplineDecreaseKnotMultiplicity"
<< "Sketcher_BSplineInsertKnot";
<< "Sketcher_BSplineInsertKnot"
<< "Sketcher_JoinCurves";
}
template <>
@@ -434,7 +435,8 @@ inline void SketcherAddWorkbenchBSplines<Gui::ToolBarItem>(Gui::ToolBarItem& bsp
<< "Sketcher_BSplineIncreaseDegree"
<< "Sketcher_BSplineDecreaseDegree"
<< "Sketcher_CompModifyKnotMultiplicity"
<< "Sketcher_BSplineInsertKnot";
<< "Sketcher_BSplineInsertKnot"
<< "Sketcher_JoinCurves";
}
template <typename T>