Sketcher: Snap: initial implementation: - creation of SnapManager class. - Move grid snap to this new class. - Add snap to object. - Add snap at angle.
This commit is contained in:
@@ -144,6 +144,8 @@ SET(SketcherGui_SRCS
|
||||
SketchRectangularArrayDialog.cpp
|
||||
SketcherRegularPolygonDialog.h
|
||||
SketcherRegularPolygonDialog.cpp
|
||||
SnapManager.cpp
|
||||
SnapManager.h
|
||||
TaskDlgEditSketch.cpp
|
||||
TaskDlgEditSketch.h
|
||||
ViewProviderPython.cpp
|
||||
|
||||
@@ -995,7 +995,7 @@ public:
|
||||
updateCheckBox(checkbox, propvalue);
|
||||
};
|
||||
|
||||
updateCheckBox(gridSnap, sketchView->getSnapMode() == SnapMode::SnapToGrid);
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
|
||||
|
||||
updateCheckBoxFromProperty(gridAutoSpacing, sketchView->GridAuto);
|
||||
|
||||
@@ -1005,10 +1005,6 @@ public:
|
||||
|
||||
void languageChange()
|
||||
{
|
||||
gridSnap->setText(tr("Grid Snap"));
|
||||
gridSnap->setToolTip(tr("New points will snap to the nearest grid line.\nPoints must be set closer than a fifth of the grid spacing to a grid line to snap."));
|
||||
gridSnap->setStatusTip(gridSnap->toolTip());
|
||||
|
||||
gridAutoSpacing->setText(tr("Grid Auto Spacing"));
|
||||
gridAutoSpacing->setToolTip(tr("Resize grid automatically depending on zoom."));
|
||||
gridAutoSpacing->setStatusTip(gridAutoSpacing->toolTip());
|
||||
@@ -1020,8 +1016,6 @@ public:
|
||||
protected:
|
||||
QWidget* createWidget(QWidget* parent) override
|
||||
{
|
||||
gridSnap = new QCheckBox();
|
||||
|
||||
gridAutoSpacing = new QCheckBox();
|
||||
|
||||
sizeLabel = new QLabel();
|
||||
@@ -1034,27 +1028,12 @@ protected:
|
||||
|
||||
QWidget* gridSizeW = new QWidget(parent);
|
||||
auto* layout = new QGridLayout(gridSizeW);
|
||||
layout->addWidget(gridSnap, 0, 0);
|
||||
layout->addWidget(gridAutoSpacing, 1, 0);
|
||||
layout->addWidget(sizeLabel, 2, 0);
|
||||
layout->addWidget(gridSizeBox, 2, 1);
|
||||
layout->addWidget(gridAutoSpacing, 0, 0, 1, 2);
|
||||
layout->addWidget(sizeLabel, 1, 0);
|
||||
layout->addWidget(gridSizeBox, 1, 1);
|
||||
|
||||
languageChange();
|
||||
|
||||
QObject::connect(gridSnap, &QCheckBox::stateChanged, [this](int state) {
|
||||
auto* sketchView = getView();
|
||||
|
||||
if(sketchView) {
|
||||
if(state == Qt::Checked) {
|
||||
sketchView->setSnapMode(SnapMode::SnapToGrid);
|
||||
}
|
||||
else {
|
||||
sketchView->setSnapMode(SnapMode::None);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
QObject::connect(gridAutoSpacing, &QCheckBox::stateChanged, [this](int state) {
|
||||
auto* sketchView = getView();
|
||||
|
||||
@@ -1086,7 +1065,6 @@ private:
|
||||
}
|
||||
|
||||
private:
|
||||
QCheckBox * gridSnap;
|
||||
QCheckBox * gridAutoSpacing;
|
||||
QLabel * sizeLabel;
|
||||
Gui::QuantitySpinBox * gridSizeBox;
|
||||
@@ -1213,6 +1191,250 @@ bool CmdSketcherGrid::isActive()
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Snap tool */
|
||||
class SnapSpaceAction : public QWidgetAction
|
||||
{
|
||||
public:
|
||||
SnapSpaceAction(QObject* parent) : QWidgetAction(parent) {
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
void updateWidget() {
|
||||
|
||||
auto* sketchView = getView();
|
||||
|
||||
if (sketchView) {
|
||||
|
||||
auto updateCheckBox = [](QCheckBox* checkbox, bool value) {
|
||||
auto checked = checkbox->checkState() == Qt::Checked;
|
||||
|
||||
if (value != checked) {
|
||||
const QSignalBlocker blocker(checkbox);
|
||||
checkbox->setChecked(value);
|
||||
}
|
||||
};
|
||||
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
|
||||
|
||||
updateCheckBox(snapToObjects, hGrp->GetBool("SnapToObjects", true));
|
||||
|
||||
updateCheckBox(snapToGrid, hGrp->GetBool("SnapToGrid", false));
|
||||
|
||||
snapAngle->setValue(hGrp->GetFloat("SnapAngle", 5.0));
|
||||
|
||||
bool snapActivated = hGrp->GetBool("Snap", true);
|
||||
snapToObjects->setEnabled(snapActivated);
|
||||
snapToGrid->setEnabled(snapActivated);
|
||||
angleLabel->setEnabled(snapActivated);
|
||||
snapAngle->setEnabled(snapActivated);
|
||||
}
|
||||
}
|
||||
|
||||
void languageChange()
|
||||
{
|
||||
|
||||
snapToObjects->setText(tr("Snap to objects"));
|
||||
snapToObjects->setToolTip(tr("New points will snap to the currently preselected object. It will also snap to the middle of lines and arcs."));
|
||||
snapToObjects->setStatusTip(snapToObjects->toolTip());
|
||||
|
||||
snapToGrid->setText(tr("Snap to Grid"));
|
||||
snapToGrid->setToolTip(tr("New points will snap to the nearest grid line.\nPoints must be set closer than a fifth of the grid spacing to a grid line to snap."));
|
||||
snapToGrid->setStatusTip(snapToGrid->toolTip());
|
||||
|
||||
angleLabel->setText(tr("Snap angle"));
|
||||
snapAngle->setToolTip(tr("Angular step for tools that use 'Snap at Angle' (line for instance). Hold CTRL to enable 'Snap at Angle'. The angle start from the East axis (horizontal right)"));
|
||||
}
|
||||
|
||||
protected:
|
||||
QWidget* createWidget(QWidget* parent) override
|
||||
{
|
||||
snapToObjects = new QCheckBox();
|
||||
|
||||
snapToGrid = new QCheckBox();
|
||||
|
||||
angleLabel = new QLabel();
|
||||
|
||||
snapAngle = new Gui::QuantitySpinBox();
|
||||
snapAngle->setProperty("unit", QVariant(QStringLiteral("deg")));
|
||||
snapAngle->setObjectName(QStringLiteral("snapAngle"));
|
||||
snapAngle->setMaximum(99999999.0);
|
||||
snapAngle->setMinimum(0);
|
||||
|
||||
QWidget* snapW = new QWidget(parent);
|
||||
auto* layout = new QGridLayout(snapW);
|
||||
layout->addWidget(snapToGrid, 0, 0, 1, 2);
|
||||
layout->addWidget(snapToObjects, 1, 0, 1, 2);
|
||||
layout->addWidget(angleLabel, 2, 0);
|
||||
layout->addWidget(snapAngle, 2, 1);
|
||||
|
||||
languageChange();
|
||||
|
||||
QObject::connect(snapToObjects, &QCheckBox::stateChanged, [this](int state) {
|
||||
auto* sketchView = getView();
|
||||
|
||||
if (sketchView) {
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
|
||||
hGrp->SetBool("SnapToObjects", state == Qt::Checked);
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(snapToGrid, &QCheckBox::stateChanged, [this](int state) {
|
||||
auto* sketchView = getView();
|
||||
if (sketchView) {
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
|
||||
hGrp->SetBool("SnapToGrid", state == Qt::Checked);
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(snapAngle, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), [this](double val) {
|
||||
auto* sketchView = getView();
|
||||
|
||||
if (sketchView) {
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
|
||||
hGrp->SetFloat("SnapAngle", val);
|
||||
}
|
||||
});
|
||||
|
||||
return snapW;
|
||||
}
|
||||
|
||||
private:
|
||||
ViewProviderSketch* getView() {
|
||||
Gui::Document* doc = Gui::Application::Instance->activeDocument();
|
||||
|
||||
if (doc) {
|
||||
return dynamic_cast<SketcherGui::ViewProviderSketch*>(doc->getInEdit());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
QCheckBox* snapToObjects;
|
||||
QCheckBox* snapToGrid;
|
||||
QLabel* angleLabel;
|
||||
Gui::QuantitySpinBox* snapAngle;
|
||||
};
|
||||
|
||||
class CmdSketcherSnap : public Gui::Command
|
||||
{
|
||||
public:
|
||||
CmdSketcherSnap();
|
||||
virtual ~CmdSketcherSnap() {}
|
||||
virtual const char* className() const
|
||||
{
|
||||
return "CmdSketcherSnap";
|
||||
}
|
||||
virtual void languageChange();
|
||||
protected:
|
||||
virtual void activated(int iMsg);
|
||||
virtual bool isActive(void);
|
||||
virtual Gui::Action* createAction(void);
|
||||
private:
|
||||
void updateIcon(bool value);
|
||||
|
||||
CmdSketcherSnap(const CmdSketcherSnap&) = delete;
|
||||
CmdSketcherSnap(CmdSketcherSnap&&) = delete;
|
||||
CmdSketcherSnap& operator= (const CmdSketcherSnap&) = delete;
|
||||
CmdSketcherSnap& operator= (CmdSketcherSnap&&) = delete;
|
||||
};
|
||||
|
||||
CmdSketcherSnap::CmdSketcherSnap()
|
||||
: Command("Sketcher_Snap")
|
||||
{
|
||||
sAppModule = "Sketcher";
|
||||
sGroup = "Sketcher";
|
||||
sMenuText = QT_TR_NOOP("Toggle Snap");
|
||||
sToolTipText = QT_TR_NOOP("Toggle all snapping functionalities. In the menu you can toggle individually 'Snap to Grid', 'Snap to Objects' and further snap settings");
|
||||
sWhatsThis = "Sketcher_Snap";
|
||||
sStatusTip = sToolTipText;
|
||||
eType = 0;
|
||||
}
|
||||
|
||||
void CmdSketcherSnap::updateIcon(bool value)
|
||||
{
|
||||
static QIcon active = Gui::BitmapFactory().iconFromTheme("Sketcher_Snap");
|
||||
static QIcon inactive = Gui::BitmapFactory().iconFromTheme("Sketcher_Snap_Deactivated");
|
||||
|
||||
auto* pcAction = qobject_cast<Gui::ActionGroup*>(getAction());
|
||||
pcAction->setIcon(value ? active : inactive);
|
||||
}
|
||||
|
||||
void CmdSketcherSnap::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
|
||||
bool value = !hGrp->GetBool("Snap", true);
|
||||
|
||||
hGrp->SetBool("Snap", value);
|
||||
|
||||
updateIcon(value);
|
||||
|
||||
//Update the widget :
|
||||
if (!_pcAction)
|
||||
return;
|
||||
|
||||
Gui::ActionGroup* pcAction = qobject_cast<Gui::ActionGroup*>(_pcAction);
|
||||
QList<QAction*> a = pcAction->actions();
|
||||
|
||||
auto* ssa = static_cast<SnapSpaceAction*>(a[0]);
|
||||
ssa->updateWidget();
|
||||
}
|
||||
|
||||
Gui::Action* CmdSketcherSnap::createAction()
|
||||
{
|
||||
auto* pcAction = new Gui::ActionGroup(this, Gui::getMainWindow());
|
||||
pcAction->setDropDownMenu(true);
|
||||
pcAction->setExclusive(false);
|
||||
applyCommandData(this->className(), pcAction);
|
||||
|
||||
SnapSpaceAction* ssa = new SnapSpaceAction(pcAction);
|
||||
pcAction->addAction(ssa);
|
||||
|
||||
_pcAction = pcAction;
|
||||
|
||||
QObject::connect(pcAction, &Gui::ActionGroup::aboutToShow, [ssa](QMenu* menu) {
|
||||
Q_UNUSED(menu)
|
||||
ssa->updateWidget();
|
||||
});
|
||||
|
||||
// set the right pixmap
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
|
||||
updateIcon(hGrp->GetBool("Snap", true));
|
||||
|
||||
return pcAction;
|
||||
}
|
||||
|
||||
void CmdSketcherSnap::languageChange()
|
||||
{
|
||||
Command::languageChange();
|
||||
|
||||
if (!_pcAction)
|
||||
return;
|
||||
|
||||
Gui::ActionGroup* pcAction = qobject_cast<Gui::ActionGroup*>(_pcAction);
|
||||
QList<QAction*> a = pcAction->actions();
|
||||
|
||||
auto* ssa = static_cast<SnapSpaceAction*>(a[0]);
|
||||
ssa->languageChange();
|
||||
}
|
||||
|
||||
bool CmdSketcherSnap::isActive()
|
||||
{
|
||||
auto* vp = getInactiveHandlerEditModeSketchViewProvider();
|
||||
|
||||
if (vp) {
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
|
||||
bool value = hGrp->GetBool("Snap", true);
|
||||
|
||||
updateIcon(value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CreateSketcherCommands()
|
||||
{
|
||||
@@ -1230,4 +1452,5 @@ void CreateSketcherCommands()
|
||||
rcCmdMgr.addCommand(new CmdSketcherMergeSketches());
|
||||
rcCmdMgr.addCommand(new CmdSketcherViewSection());
|
||||
rcCmdMgr.addCommand(new CmdSketcherGrid());
|
||||
rcCmdMgr.addCommand(new CmdSketcherSnap());
|
||||
}
|
||||
|
||||
@@ -106,6 +106,8 @@
|
||||
<file>icons/general/Sketcher_ViewSketch.svg</file>
|
||||
<file>icons/general/Sketcher_GridToggle.svg</file>
|
||||
<file>icons/general/Sketcher_GridToggle_Deactivated.svg</file>
|
||||
<file>icons/general/Sketcher_Snap.svg</file>
|
||||
<file>icons/general/Sketcher_Snap_Deactivated.svg</file>
|
||||
</qresource>
|
||||
<qresource>
|
||||
<file>icons/geometry/Sketcher_AlterFillet.svg</file>
|
||||
|
||||
386
src/Mod/Sketcher/Gui/Resources/icons/general/Sketcher_Snap.svg
Normal file
386
src/Mod/Sketcher/Gui/Resources/icons/general/Sketcher_Snap.svg
Normal file
@@ -0,0 +1,386 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg3364"
|
||||
version="1.1"
|
||||
sodipodi:docname="Sketcher_Snap.svg"
|
||||
inkscape:version="1.1-beta1 (77e7b44db3, 2021-03-28)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<sodipodi:namedview
|
||||
id="namedview55"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
objecttolerance="10.0"
|
||||
gridtolerance="10.0"
|
||||
guidetolerance="10.0"
|
||||
inkscape:pageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="11.765625"
|
||||
inkscape:cx="39.861886"
|
||||
inkscape:cy="27.580345"
|
||||
inkscape:window-width="1725"
|
||||
inkscape:window-height="1013"
|
||||
inkscape:window-x="1213"
|
||||
inkscape:window-y="293"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg3364" />
|
||||
<defs
|
||||
id="defs3366">
|
||||
<linearGradient
|
||||
id="linearGradient3864">
|
||||
<stop
|
||||
id="stop3866"
|
||||
offset="0"
|
||||
style="stop-color:#71b2f8;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop3868"
|
||||
offset="1"
|
||||
style="stop-color:#002795;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient2571"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="342.58258"
|
||||
cy="27.256668"
|
||||
fx="342.58258"
|
||||
fy="27.256668"
|
||||
r="19.571428"
|
||||
gradientTransform="matrix(1.6258409,0.5434973,-8.8819886e-2,0.2656996,-215.02413,-170.90186)" />
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient3593"
|
||||
id="radialGradient3352"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="345.28433"
|
||||
cy="15.560534"
|
||||
fx="345.28433"
|
||||
fy="15.560534"
|
||||
r="19.571428"
|
||||
gradientTransform="translate(-0.1767767,-2.6516504)" />
|
||||
<linearGradient
|
||||
id="linearGradient3593">
|
||||
<stop
|
||||
style="stop-color:#c8e0f9;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3595" />
|
||||
<stop
|
||||
style="stop-color:#637dca;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3597" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient3593"
|
||||
id="radialGradient3354"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="330.63791"
|
||||
cy="39.962704"
|
||||
fx="330.63791"
|
||||
fy="39.962704"
|
||||
r="19.571428"
|
||||
gradientTransform="translate(-0.1767767,-2.6516504)" />
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient3369"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.6258409,0.5434973,-8.8819886e-2,0.2656996,-461.81066,-173.06271)"
|
||||
cx="342.58258"
|
||||
cy="27.256668"
|
||||
fx="342.58258"
|
||||
fy="27.256668"
|
||||
r="19.571428" />
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient3593"
|
||||
id="radialGradient3372"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.0012324,0,0,0.9421773,-327.50313,-4.3316646)"
|
||||
cx="345.28433"
|
||||
cy="15.560534"
|
||||
fx="345.28433"
|
||||
fy="15.560534"
|
||||
r="19.571428" />
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient3593"
|
||||
id="radialGradient3375"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.0012324,0,0,0.9421773,-287.81791,-28.143054)"
|
||||
cx="330.63791"
|
||||
cy="39.962704"
|
||||
fx="330.63791"
|
||||
fy="39.962704"
|
||||
r="19.571428" />
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient3380"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.9829174,1.3240854,-1.2330051,0.8105158,-131.04134,-483.74563)"
|
||||
cx="320.44025"
|
||||
cy="113.23357"
|
||||
fx="320.44025"
|
||||
fy="113.23357"
|
||||
r="19.571428" />
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient3864"
|
||||
id="linearGradient3914"
|
||||
x1="6.94525"
|
||||
y1="36.838673"
|
||||
x2="48.691113"
|
||||
y2="36.838673"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.0012324,0,0,0.9421773,-4.8699606,-2.3863162)" />
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient3794"
|
||||
id="radialGradient3800"
|
||||
cx="1"
|
||||
cy="45"
|
||||
fx="1"
|
||||
fy="45"
|
||||
r="41"
|
||||
gradientTransform="matrix(0.93348213,-2.2905276e-8,0,0.28687573,0.06651751,32.090592)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3794">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3796" />
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:0"
|
||||
offset="1"
|
||||
id="stop3798" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="translate(0,-9)"
|
||||
xlink:href="#linearGradient3777"
|
||||
id="linearGradient3783"
|
||||
x1="53.896763"
|
||||
y1="51.179787"
|
||||
x2="48"
|
||||
y2="32"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3777">
|
||||
<stop
|
||||
style="stop-color:#204a87;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3779" />
|
||||
<stop
|
||||
style="stop-color:#3465a4;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3781" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="translate(22,-17)"
|
||||
xlink:href="#linearGradient3767"
|
||||
id="linearGradient3773"
|
||||
x1="22.116516"
|
||||
y1="55.717518"
|
||||
x2="19"
|
||||
y2="33"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3767">
|
||||
<stop
|
||||
style="stop-color:#3465a4;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3769" />
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3771" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="translate(-2,-11)"
|
||||
xlink:href="#linearGradient3777-6"
|
||||
id="linearGradient3783-3"
|
||||
x1="53.896763"
|
||||
y1="51.179787"
|
||||
x2="48"
|
||||
y2="32"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3777-6">
|
||||
<stop
|
||||
style="stop-color:#204a87;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3779-7" />
|
||||
<stop
|
||||
style="stop-color:#3465a4;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3781-5" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="32"
|
||||
x2="48"
|
||||
y1="51.179787"
|
||||
x1="53.896763"
|
||||
gradientTransform="translate(-24,-13)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3066"
|
||||
xlink:href="#linearGradient3777-6" />
|
||||
<linearGradient
|
||||
y2="5"
|
||||
x2="-22"
|
||||
y1="18"
|
||||
x1="-18"
|
||||
gradientTransform="matrix(0.53559025,0,0,0.53556875,-6.4812797,2.8041108)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3323-4"
|
||||
xlink:href="#linearGradient3836-9-3-7-2-7-7-2-6" />
|
||||
<linearGradient
|
||||
id="linearGradient3836-9-3-7-2-7-7-2-6">
|
||||
<stop
|
||||
style="stop-color:#a40000;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3838-8-5-4-4-6-4-4-61" />
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3840-1-6-0-5-1-0-5-8" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3836-9-3-7-2-7-7-2-6"
|
||||
id="linearGradient898"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.53559025,0,0,0.53556875,-6.4812797,2.8041108)"
|
||||
x1="-18"
|
||||
y1="18"
|
||||
x2="-22"
|
||||
y2="5" />
|
||||
<linearGradient
|
||||
y2="5"
|
||||
x2="-22"
|
||||
y1="18"
|
||||
x1="-18"
|
||||
gradientTransform="matrix(0.53559025,0,0,0.53556875,-6.4812797,2.8041108)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3323-3"
|
||||
xlink:href="#linearGradient3836-9-3-7-2-7-7-2-6" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata3369">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[wmayer]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:date>2011-10-10</dc:date>
|
||||
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Part/Gui/Resources/icons/Part_Section.svg</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>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<path
|
||||
style="fill:none;stroke:#363636;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:6, 3;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 2.3798139,32.218121 H 61.620186"
|
||||
id="path985-9" />
|
||||
<path
|
||||
style="fill:none;stroke:#363636;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:6, 3;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 2.2324867,51.127858 H 61.472858"
|
||||
id="path985-6" />
|
||||
<path
|
||||
style="fill:none;stroke:#4ce642;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:6, 3;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 12.221742,61.620185 V 2.3798148"
|
||||
id="path985-92" />
|
||||
<path
|
||||
style="fill:none;stroke:#363636;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:6, 3;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 31.131479,61.620186 V 2.3798143"
|
||||
id="path985-9-8" />
|
||||
<path
|
||||
style="fill:none;stroke:#363636;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:6, 3;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 50.041216,61.620185 V 2.3798148"
|
||||
id="path985-6-2" />
|
||||
<path
|
||||
style="fill:none;stroke:#4ce642;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:6, 3;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 2.2324859,13.308385 H 61.472857"
|
||||
id="path985" />
|
||||
<g
|
||||
transform="rotate(63.326802,46.528624,-2.5779449)"
|
||||
id="g3529-7">
|
||||
<path
|
||||
id="path3491-7"
|
||||
d="M 56,8 V 32"
|
||||
style="fill:none;stroke:#172a04;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path3491-4-7"
|
||||
d="M 56,8 V 32"
|
||||
style="fill:none;stroke:#73d216;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path3491-4-1-3"
|
||||
d="M 55,8 V 32"
|
||||
style="fill:none;stroke:#8ae234;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke-width:6.44377;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
transform="matrix(0.35922387,0.71507028,-0.71505986,0.35921864,53.759702,19.45672)"
|
||||
id="g3797-7-2-9-5-4-9-5-96">
|
||||
<path
|
||||
style="fill:#ef2929;stroke:#280000;stroke-width:2.4993;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4250-6-9-4-1-2-4-1-3"
|
||||
d="m -21.570202,4.8706993 a 6.2460052,6.2456584 0.01677682 1 1 9.488239,8.1250407 6.2460052,6.2456584 0.01677682 1 1 -9.488239,-8.1250407 z" />
|
||||
<path
|
||||
style="fill:url(#linearGradient898);fill-opacity:1;stroke:#ef2929;stroke-width:2.4993;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4250-7-0-1-8-7-3-8-7-7"
|
||||
d="m -19.674789,6.4961011 a 3.7491316,3.7489813 0 1 1 5.695246,4.8771099 3.7491316,3.7489813 0 0 1 -5.695246,-4.8771099 z" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke-width:6.44377;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
transform="matrix(0.35922387,0.71507028,-0.71505986,0.35921864,32.313746,30.230346)"
|
||||
id="g3797-7-2-9-5-4-9-5-96-5">
|
||||
<path
|
||||
style="fill:#ef2929;stroke:#280000;stroke-width:2.4993;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4250-6-9-4-1-2-4-1-3-7"
|
||||
d="m -21.570202,4.8706993 a 6.2460052,6.2456584 0.01677682 1 1 9.488239,8.1250407 6.2460052,6.2456584 0.01677682 1 1 -9.488239,-8.1250407 z" />
|
||||
<path
|
||||
style="fill:url(#linearGradient3323-4);fill-opacity:1;stroke:#ef2929;stroke-width:2.4993;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4250-7-0-1-8-7-3-8-7-7-5"
|
||||
d="m -19.674789,6.4961011 a 3.7491316,3.7489813 0 1 1 5.695246,4.8771099 3.7491316,3.7489813 0 0 1 -5.695246,-4.8771099 z" />
|
||||
</g>
|
||||
<g
|
||||
id="g4273"
|
||||
transform="translate(-89.528258,0.54055521)">
|
||||
<path
|
||||
style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 108.96148,19.97344 c 4.28933,11.161025 8.9416,20.384136 14.87384,32.552457 l 5.94954,-11.134131 12.749,12.154051 c 3.39402,0.638464 5.31688,-1.489816 4.75963,-4.504649 l -13.00398,-11.814076 8.49933,-6.629483 z"
|
||||
id="path1052"
|
||||
sodipodi:nodetypes="cccccccc" />
|
||||
<path
|
||||
style="fill:#d3d7cf;fill-opacity:1;stroke:#ffffff;stroke-width:1.285;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 112.59215,23.233162 c 3.72959,10.062766 6.25342,13.924184 11.41153,24.895126 l 5.26419,-9.586262 13.8638,13.109482 c 1.42608,0.530564 2.84842,-0.286358 2.07091,-2.088013 l -13.80942,-12.277572 7.29489,-5.92068 z"
|
||||
id="path1052-8"
|
||||
sodipodi:nodetypes="cccccccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,377 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg3364"
|
||||
version="1.1"
|
||||
sodipodi:docname="Sketcher_Snap_Deactivated.svg"
|
||||
inkscape:version="1.1-beta1 (77e7b44db3, 2021-03-28)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<sodipodi:namedview
|
||||
id="namedview55"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
objecttolerance="10.0"
|
||||
gridtolerance="10.0"
|
||||
guidetolerance="10.0"
|
||||
inkscape:pageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="5.8828125"
|
||||
inkscape:cx="56.180611"
|
||||
inkscape:cy="32.63745"
|
||||
inkscape:window-width="1720"
|
||||
inkscape:window-height="1112"
|
||||
inkscape:window-x="743"
|
||||
inkscape:window-y="334"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg3364" />
|
||||
<defs
|
||||
id="defs3366">
|
||||
<linearGradient
|
||||
id="linearGradient3864">
|
||||
<stop
|
||||
id="stop3866"
|
||||
offset="0"
|
||||
style="stop-color:#71b2f8;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop3868"
|
||||
offset="1"
|
||||
style="stop-color:#002795;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient2571"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="342.58258"
|
||||
cy="27.256668"
|
||||
fx="342.58258"
|
||||
fy="27.256668"
|
||||
r="19.571428"
|
||||
gradientTransform="matrix(1.6258409,0.5434973,-8.8819886e-2,0.2656996,-215.02413,-170.90186)" />
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient3593"
|
||||
id="radialGradient3352"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="345.28433"
|
||||
cy="15.560534"
|
||||
fx="345.28433"
|
||||
fy="15.560534"
|
||||
r="19.571428"
|
||||
gradientTransform="translate(-0.1767767,-2.6516504)" />
|
||||
<linearGradient
|
||||
id="linearGradient3593">
|
||||
<stop
|
||||
style="stop-color:#c8e0f9;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3595" />
|
||||
<stop
|
||||
style="stop-color:#637dca;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3597" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient3593"
|
||||
id="radialGradient3354"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="330.63791"
|
||||
cy="39.962704"
|
||||
fx="330.63791"
|
||||
fy="39.962704"
|
||||
r="19.571428"
|
||||
gradientTransform="translate(-0.1767767,-2.6516504)" />
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient3369"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.6258409,0.5434973,-8.8819886e-2,0.2656996,-461.81066,-173.06271)"
|
||||
cx="342.58258"
|
||||
cy="27.256668"
|
||||
fx="342.58258"
|
||||
fy="27.256668"
|
||||
r="19.571428" />
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient3593"
|
||||
id="radialGradient3372"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.0012324,0,0,0.9421773,-327.50313,-4.3316646)"
|
||||
cx="345.28433"
|
||||
cy="15.560534"
|
||||
fx="345.28433"
|
||||
fy="15.560534"
|
||||
r="19.571428" />
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient3593"
|
||||
id="radialGradient3375"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.0012324,0,0,0.9421773,-287.81791,-28.143054)"
|
||||
cx="330.63791"
|
||||
cy="39.962704"
|
||||
fx="330.63791"
|
||||
fy="39.962704"
|
||||
r="19.571428" />
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient3380"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.9829174,1.3240854,-1.2330051,0.8105158,-131.04134,-483.74563)"
|
||||
cx="320.44025"
|
||||
cy="113.23357"
|
||||
fx="320.44025"
|
||||
fy="113.23357"
|
||||
r="19.571428" />
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient3864"
|
||||
id="linearGradient3914"
|
||||
x1="6.94525"
|
||||
y1="36.838673"
|
||||
x2="48.691113"
|
||||
y2="36.838673"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.0012324,0,0,0.9421773,-4.8699606,-2.3863162)" />
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient3794"
|
||||
id="radialGradient3800"
|
||||
cx="1"
|
||||
cy="45"
|
||||
fx="1"
|
||||
fy="45"
|
||||
r="41"
|
||||
gradientTransform="matrix(0.93348213,-2.2905276e-8,0,0.28687573,0.06651751,32.090592)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3794">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3796" />
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:0"
|
||||
offset="1"
|
||||
id="stop3798" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="translate(0,-9)"
|
||||
xlink:href="#linearGradient3777"
|
||||
id="linearGradient3783"
|
||||
x1="53.896763"
|
||||
y1="51.179787"
|
||||
x2="48"
|
||||
y2="32"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3777">
|
||||
<stop
|
||||
style="stop-color:#204a87;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3779" />
|
||||
<stop
|
||||
style="stop-color:#3465a4;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3781" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="translate(22,-17)"
|
||||
xlink:href="#linearGradient3767"
|
||||
id="linearGradient3773"
|
||||
x1="22.116516"
|
||||
y1="55.717518"
|
||||
x2="19"
|
||||
y2="33"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3767">
|
||||
<stop
|
||||
style="stop-color:#3465a4;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3769" />
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3771" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="translate(-2,-11)"
|
||||
xlink:href="#linearGradient3777-6"
|
||||
id="linearGradient3783-3"
|
||||
x1="53.896763"
|
||||
y1="51.179787"
|
||||
x2="48"
|
||||
y2="32"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3777-6">
|
||||
<stop
|
||||
style="stop-color:#204a87;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3779-7" />
|
||||
<stop
|
||||
style="stop-color:#3465a4;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3781-5" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="32"
|
||||
x2="48"
|
||||
y1="51.179787"
|
||||
x1="53.896763"
|
||||
gradientTransform="translate(-24,-13)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3066"
|
||||
xlink:href="#linearGradient3777-6" />
|
||||
<linearGradient
|
||||
y2="5"
|
||||
x2="-22"
|
||||
y1="18"
|
||||
x1="-18"
|
||||
gradientTransform="matrix(0.53559025,0,0,0.53556875,-6.4812797,2.8041108)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3323-3"
|
||||
xlink:href="#linearGradient3836-9-3-7-2-7-7-2-13" />
|
||||
<linearGradient
|
||||
id="linearGradient3836-9-3-7-2-7-7-2-13">
|
||||
<stop
|
||||
style="stop-color:#a40000;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3838-8-5-4-4-6-4-4-8" />
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3840-1-6-0-5-1-0-5-9" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3836-9-3-7-2-7-7-2-13"
|
||||
id="linearGradient1092"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.53559025,0,0,0.53556875,-6.4812797,2.8041108)"
|
||||
x1="-18"
|
||||
y1="18"
|
||||
x2="-22"
|
||||
y2="5" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata3369">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[wmayer]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:date>2011-10-10</dc:date>
|
||||
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Part/Gui/Resources/icons/Part_Section.svg</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>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<path
|
||||
style="fill:none;stroke:#363636;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:6, 3;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 2.3798139,32.218121 H 61.620186"
|
||||
id="path985-9" />
|
||||
<path
|
||||
style="fill:none;stroke:#363636;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:6, 3;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 2.2324867,51.127858 H 61.472858"
|
||||
id="path985-6" />
|
||||
<path
|
||||
style="fill:none;stroke:#363636;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:6, 3;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 12.221742,61.620185 V 2.3798148"
|
||||
id="path985-92" />
|
||||
<path
|
||||
style="fill:none;stroke:#363636;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:6, 3;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 31.131479,61.620186 V 2.3798143"
|
||||
id="path985-9-8" />
|
||||
<path
|
||||
style="fill:none;stroke:#363636;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:6, 3;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 50.041216,61.620185 V 2.3798148"
|
||||
id="path985-6-2" />
|
||||
<path
|
||||
style="fill:none;stroke:#363636;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:6, 3;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 2.2324859,13.308385 H 61.472857"
|
||||
id="path985" />
|
||||
<g
|
||||
id="g4273"
|
||||
transform="translate(-85.253531,6.1052318)">
|
||||
<path
|
||||
style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 108.96148,19.97344 c 4.28933,11.161025 8.9416,20.384136 14.87384,32.552457 l 5.94954,-11.134131 12.749,12.154051 c 3.39402,0.638464 5.31688,-1.489816 4.75963,-4.504649 l -13.00398,-11.814076 8.49933,-6.629483 z"
|
||||
id="path1052"
|
||||
sodipodi:nodetypes="cccccccc" />
|
||||
<path
|
||||
style="fill:#d3d7cf;fill-opacity:1;stroke:#ffffff;stroke-width:1.285;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 112.59215,23.233162 c 3.72959,10.062766 6.25342,13.924184 11.41153,24.895126 l 5.26419,-9.586262 13.8638,13.109482 c 1.42608,0.530564 2.84842,-0.286358 2.07091,-2.088013 l -13.80942,-12.277572 7.29489,-5.92068 z"
|
||||
id="path1052-8"
|
||||
sodipodi:nodetypes="cccccccc" />
|
||||
</g>
|
||||
<g
|
||||
transform="rotate(63.436651,45.794909,-8.4224816)"
|
||||
id="g3529-4">
|
||||
<path
|
||||
id="path3491-6"
|
||||
d="M 56,8 V 32"
|
||||
style="fill:none;stroke:#2e3436;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path3491-4-07"
|
||||
d="M 56,8 V 32"
|
||||
style="fill:none;stroke:#d3d7cf;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path3491-4-1-17"
|
||||
d="M 55,8 V 32"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke-width:6.44377;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
transform="matrix(0.35785226,0.71575769,-0.71574725,0.35784704,48.084512,16.896405)"
|
||||
id="g3797-7-2-9-5-4-9-5-4">
|
||||
<path
|
||||
style="fill:#ef2929;stroke:#280000;stroke-width:2.4993;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4250-6-9-4-1-2-4-1-4"
|
||||
d="m -21.570202,4.8706993 a 6.2460052,6.2456584 0.01677682 1 1 9.488239,8.1250407 6.2460052,6.2456584 0.01677682 1 1 -9.488239,-8.1250407 z" />
|
||||
<path
|
||||
style="fill:url(#linearGradient1092);fill-opacity:1;stroke:#ef2929;stroke-width:2.4993;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4250-7-0-1-8-7-3-8-7-6"
|
||||
d="m -19.674789,6.4961011 a 3.7491316,3.7489813 0 1 1 5.695246,4.8771099 3.7491316,3.7489813 0 0 1 -5.695246,-4.8771099 z" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke-width:6.44377;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
transform="matrix(0.35785226,0.71575769,-0.71574725,0.35784704,26.61794,27.628894)"
|
||||
id="g3797-7-2-9-5-4-9-5-4-0">
|
||||
<path
|
||||
style="fill:#ef2929;stroke:#280000;stroke-width:2.4993;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4250-6-9-4-1-2-4-1-4-1"
|
||||
d="m -21.570202,4.8706993 a 6.2460052,6.2456584 0.01677682 1 1 9.488239,8.1250407 6.2460052,6.2456584 0.01677682 1 1 -9.488239,-8.1250407 z" />
|
||||
<path
|
||||
style="fill:url(#linearGradient3323-3);fill-opacity:1;stroke:#ef2929;stroke-width:2.4993;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4250-7-0-1-8-7-3-8-7-6-6"
|
||||
d="m -19.674789,6.4961011 a 3.7491316,3.7489813 0 1 1 5.695246,4.8771099 3.7491316,3.7489813 0 0 1 -5.695246,-4.8771099 z" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
364
src/Mod/Sketcher/Gui/SnapManager.cpp
Normal file
364
src/Mod/Sketcher/Gui/SnapManager.cpp
Normal file
@@ -0,0 +1,364 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 Pierre-Louis Boyer <pierrelouis.boyer@gmail.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <QApplication>
|
||||
#endif // #ifndef _PreComp_
|
||||
|
||||
#include <Mod/Sketcher/App/SketchObject.h>
|
||||
|
||||
#include "SnapManager.h"
|
||||
#include "ViewProviderSketch.h"
|
||||
|
||||
|
||||
using namespace SketcherGui;
|
||||
using namespace Sketcher;
|
||||
|
||||
/************************************ Attorney *******************************************/
|
||||
|
||||
inline int ViewProviderSketchSnapAttorney::getPreselectPoint(const ViewProviderSketch& vp)
|
||||
{
|
||||
return vp.getPreselectPoint();
|
||||
}
|
||||
|
||||
inline int ViewProviderSketchSnapAttorney::getPreselectCross(const ViewProviderSketch& vp)
|
||||
{
|
||||
return vp.getPreselectCross();
|
||||
}
|
||||
|
||||
inline int ViewProviderSketchSnapAttorney::getPreselectCurve(const ViewProviderSketch& vp)
|
||||
{
|
||||
return vp.getPreselectCurve();
|
||||
}
|
||||
|
||||
/**************************** ParameterObserver nested class *****************************/
|
||||
SnapManager::ParameterObserver::ParameterObserver(SnapManager& client) : client(client)
|
||||
{
|
||||
initParameters();
|
||||
subscribeToParameters();
|
||||
}
|
||||
|
||||
SnapManager::ParameterObserver::~ParameterObserver()
|
||||
{
|
||||
unsubscribeToParameters();
|
||||
}
|
||||
|
||||
void SnapManager::ParameterObserver::initParameters()
|
||||
{
|
||||
// static map to avoid substantial if/else branching
|
||||
//
|
||||
// key->first => String of parameter,
|
||||
// key->second => Update function to be called for the parameter,
|
||||
str2updatefunction = {
|
||||
{"Snap",
|
||||
[this](const std::string& param) {updateSnapParameter(param); }},
|
||||
{"SnapToObjects",
|
||||
[this](const std::string& param) {updateSnapToObjectParameter(param); }},
|
||||
{"SnapToGrid",
|
||||
[this](const std::string& param) {updateSnapToGridParameter(param); }},
|
||||
{"SnapAngle",
|
||||
[this](const std::string& param) {updateSnapAngleParameter(param); }},
|
||||
};
|
||||
|
||||
for (auto& val : str2updatefunction) {
|
||||
auto string = val.first;
|
||||
auto function = val.second;
|
||||
|
||||
function(string);
|
||||
}
|
||||
}
|
||||
|
||||
void SnapManager::ParameterObserver::updateSnapParameter(const std::string& parametername)
|
||||
{
|
||||
ParameterGrp::handle hGrp = getParameterGrpHandle();
|
||||
|
||||
client.snapRequested = hGrp->GetBool(parametername.c_str(), true);
|
||||
}
|
||||
|
||||
void SnapManager::ParameterObserver::updateSnapToObjectParameter(const std::string& parametername)
|
||||
{
|
||||
ParameterGrp::handle hGrp = getParameterGrpHandle();
|
||||
|
||||
client.snapToObjectsRequested = hGrp->GetBool(parametername.c_str(), true);
|
||||
}
|
||||
|
||||
void SnapManager::ParameterObserver::updateSnapToGridParameter(const std::string& parametername)
|
||||
{
|
||||
ParameterGrp::handle hGrp = getParameterGrpHandle();
|
||||
|
||||
client.snapToGridRequested = hGrp->GetBool(parametername.c_str(), false);
|
||||
}
|
||||
|
||||
void SnapManager::ParameterObserver::updateSnapAngleParameter(const std::string& parametername)
|
||||
{
|
||||
ParameterGrp::handle hGrp = getParameterGrpHandle();
|
||||
|
||||
client.snapAngle = fmod(hGrp->GetFloat(parametername.c_str(), 5.) * M_PI / 180, 2 * M_PI);
|
||||
}
|
||||
|
||||
void SnapManager::ParameterObserver::subscribeToParameters()
|
||||
{
|
||||
try {
|
||||
ParameterGrp::handle hGrp = getParameterGrpHandle();
|
||||
hGrp->Attach(this);
|
||||
}
|
||||
catch (const Base::ValueError& e) { // ensure that if parameter strings are not well-formed, the exception is not propagated
|
||||
Base::Console().Error("SnapManager: Malformed parameter string: %s\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void SnapManager::ParameterObserver::unsubscribeToParameters()
|
||||
{
|
||||
try {
|
||||
ParameterGrp::handle hGrp = getParameterGrpHandle();
|
||||
hGrp->Detach(this);
|
||||
}
|
||||
catch (const Base::ValueError& e) {// ensure that if parameter strings are not well-formed, the program is not terminated when calling the noexcept destructor.
|
||||
Base::Console().Error("SnapManager: Malformed parameter string: %s\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void SnapManager::ParameterObserver::OnChange(Base::Subject<const char*>& rCaller, const char* sReason)
|
||||
{
|
||||
(void)rCaller;
|
||||
|
||||
auto key = str2updatefunction.find(sReason);
|
||||
if (key != str2updatefunction.end()) {
|
||||
auto string = key->first;
|
||||
auto function = key->second;
|
||||
|
||||
function(string);
|
||||
}
|
||||
}
|
||||
|
||||
ParameterGrp::handle SnapManager::ParameterObserver::getParameterGrpHandle()
|
||||
{
|
||||
return App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General");
|
||||
}
|
||||
|
||||
//**************************** SnapManager class ******************************
|
||||
|
||||
SnapManager::SnapManager(ViewProviderSketch &vp):viewProvider(vp), angleSnapEnabled(false), referencePoint(Base::Vector2d(0.,0.)), lastMouseAngle(0.0)
|
||||
{
|
||||
// Create parameter observer and initialise watched parameters
|
||||
pObserver = std::make_unique<SnapManager::ParameterObserver>(*this);
|
||||
}
|
||||
|
||||
SnapManager::~SnapManager() {}
|
||||
|
||||
bool SnapManager::snap(double& x, double& y)
|
||||
{
|
||||
if (!snapRequested)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//In order of priority :
|
||||
|
||||
// 1 - Snap at an angle
|
||||
if (angleSnapEnabled && QApplication::keyboardModifiers() == Qt::ControlModifier) {
|
||||
return snapAtAngle(x, y);
|
||||
}
|
||||
else {
|
||||
lastMouseAngle = 0.0;
|
||||
}
|
||||
|
||||
// 2 - Snap to objects
|
||||
if (snapToObjectsRequested
|
||||
&& snapToObject(x, y)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 3 - Snap to grid
|
||||
if (snapToGridRequested /*&& viewProvider.ShowGrid.getValue() */ ) { //Snap to grid is enabled even if the grid is not visible.
|
||||
return snapToGrid(x, y);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SnapManager::snapAtAngle(double& x, double& y)
|
||||
{
|
||||
Base::Vector2d pointToOverride(x, y);
|
||||
double length = (pointToOverride - referencePoint).Length();
|
||||
|
||||
double angle1 = (pointToOverride - referencePoint).Angle();
|
||||
double angle2 = angle1 + (angle1 < 0. ? 2 : -2) * M_PI;
|
||||
lastMouseAngle = abs(angle1 - lastMouseAngle) < abs(angle2 - lastMouseAngle) ? angle1 : angle2;
|
||||
|
||||
double angle = round(lastMouseAngle / snapAngle) * snapAngle;
|
||||
pointToOverride = referencePoint + length * Base::Vector2d(cos(angle), sin(angle));
|
||||
x = pointToOverride.x;
|
||||
y = pointToOverride.y;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SnapManager::snapToObject(double& x, double& y)
|
||||
{
|
||||
Sketcher::SketchObject* Obj = viewProvider.getSketchObject();
|
||||
int geoId = GeoEnum::GeoUndef;
|
||||
Sketcher::PointPos posId = Sketcher::PointPos::none;
|
||||
|
||||
int VtId = ViewProviderSketchSnapAttorney::getPreselectPoint(viewProvider);
|
||||
int CrsId = ViewProviderSketchSnapAttorney::getPreselectCross(viewProvider);
|
||||
int CrvId = ViewProviderSketchSnapAttorney::getPreselectCurve(viewProvider);
|
||||
|
||||
if (CrsId == 0 || VtId >= 0) {
|
||||
if (CrsId == 0) {
|
||||
geoId = Sketcher::GeoEnum::RtPnt;
|
||||
posId = Sketcher::PointPos::start;
|
||||
}
|
||||
else if (VtId >= 0) {
|
||||
Obj->getGeoVertexIndex(VtId, geoId, posId);
|
||||
}
|
||||
|
||||
x = Obj->getPoint(geoId, posId).x;
|
||||
y = Obj->getPoint(geoId, posId).y;
|
||||
return true;
|
||||
}
|
||||
else if (CrsId == 1) { //H_Axis
|
||||
y = 0;
|
||||
return true;
|
||||
}
|
||||
else if (CrsId == 2) { //V_Axis
|
||||
x = 0;
|
||||
return true;
|
||||
}
|
||||
else if (CrvId >= 0 || CrvId <= Sketcher::GeoEnum::RefExt) { //Curves
|
||||
|
||||
const Part::Geometry* geo = Obj->getGeometry(CrvId);
|
||||
|
||||
Base::Vector3d pointToOverride(x, y, 0.);
|
||||
|
||||
double pointParam = 0.0;
|
||||
auto curve = dynamic_cast<const Part::GeomCurve*>(geo);
|
||||
if (curve) {
|
||||
try {
|
||||
curve->closestParameter(pointToOverride, pointParam);
|
||||
pointToOverride = curve->pointAtParameter(pointParam);
|
||||
}
|
||||
catch (Base::CADKernelError& e) {
|
||||
e.ReportException();
|
||||
return false;
|
||||
}
|
||||
|
||||
//If it is a line, then we check if we need to snap to the middle.
|
||||
if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
|
||||
const Part::GeomLineSegment* line = static_cast<const Part::GeomLineSegment*>(geo);
|
||||
snapToLineMiddle(pointToOverride, line);
|
||||
}
|
||||
|
||||
//If it is an arc, then we check if we need to snap to the middle (not the center).
|
||||
if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
|
||||
const Part::GeomArcOfCircle* arc = static_cast<const Part::GeomArcOfCircle*>(geo);
|
||||
snapToArcMiddle(pointToOverride, arc);
|
||||
}
|
||||
|
||||
x = pointToOverride.x;
|
||||
y = pointToOverride.y;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SnapManager::snapToGrid(double& x, double& y)
|
||||
{
|
||||
// Snap Tolerance in pixels
|
||||
const double snapTol = viewProvider.getGridSize() / 5;
|
||||
|
||||
double tmpX = x, tmpY = y;
|
||||
|
||||
viewProvider.getClosestGridPoint(tmpX, tmpY);
|
||||
|
||||
bool snapped = false;
|
||||
|
||||
// Check if x within snap tolerance
|
||||
if (x < tmpX + snapTol && x > tmpX - snapTol) {
|
||||
x = tmpX; // Snap X Mouse Position
|
||||
snapped = true;
|
||||
}
|
||||
|
||||
// Check if y within snap tolerance
|
||||
if (y < tmpY + snapTol && y > tmpY - snapTol) {
|
||||
y = tmpY; // Snap Y Mouse Position
|
||||
snapped = true;
|
||||
}
|
||||
|
||||
return snapped;
|
||||
}
|
||||
|
||||
bool SnapManager::snapToLineMiddle(Base::Vector3d& pointToOverride, const Part::GeomLineSegment* line)
|
||||
{
|
||||
Base::Vector3d startPoint = line->getStartPoint();
|
||||
Base::Vector3d endPoint = line->getEndPoint();
|
||||
Base::Vector3d midPoint = (startPoint + endPoint) / 2;
|
||||
|
||||
//Check if we are at middle of the line and if so snap to it.
|
||||
if ((pointToOverride - midPoint).Length() < (endPoint - startPoint).Length() * 0.05) {
|
||||
pointToOverride = midPoint;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SnapManager::snapToArcMiddle(Base::Vector3d& pointToOverride, const Part::GeomArcOfCircle* arc)
|
||||
{
|
||||
Base::Vector3d centerPoint = arc->getCenter();
|
||||
Base::Vector3d startVec = (arc->getStartPoint() - centerPoint);
|
||||
Base::Vector3d middleVec = startVec + (arc->getEndPoint() - centerPoint);
|
||||
|
||||
/* Handle the case of arc angle = 180 */
|
||||
if (middleVec.Length() < Precision::Confusion()) {
|
||||
middleVec.x = startVec.y;
|
||||
middleVec.y = -startVec.x;
|
||||
}
|
||||
else {
|
||||
middleVec = middleVec / middleVec.Length() * arc->getRadius();
|
||||
}
|
||||
|
||||
Base::Vector2d mVec = Base::Vector2d(middleVec.x, middleVec.y);
|
||||
Base::Vector3d pointVec = pointToOverride - centerPoint;
|
||||
Base::Vector2d pVec = Base::Vector2d(pointVec.x, pointVec.y);
|
||||
|
||||
double u, v;
|
||||
arc->getRange(u, v, true);
|
||||
if (v < u)
|
||||
v += 2 * M_PI;
|
||||
double angle = v - u;
|
||||
int revert = angle < M_PI ? 1 : -1;
|
||||
|
||||
/*To know if we are close to the middle of the arc, we are going to compare the angle of the
|
||||
* (mouse cursor - center) to the angle of the middle of the arc. If it's less than 10% of the arc angle, then we snap.
|
||||
*/
|
||||
if (fabs(pVec.Angle() - (revert * mVec).Angle()) < 0.10 * angle) {
|
||||
pointToOverride = centerPoint + middleVec * revert;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
125
src/Mod/Sketcher/Gui/SnapManager.h
Normal file
125
src/Mod/Sketcher/Gui/SnapManager.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 Pierre-Louis Boyer <pierrelouis.boyer@gmail.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
* SnapManager initially funded by the Open Toolchain Foundation *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef SKETCHERGUI_SnapManager_H
|
||||
#define SKETCHERGUI_SnapManager_H
|
||||
|
||||
|
||||
#include <App/Application.h>
|
||||
|
||||
|
||||
namespace SketcherGui {
|
||||
|
||||
class ViewProviderSketch;
|
||||
|
||||
|
||||
class ViewProviderSketchSnapAttorney {
|
||||
private:
|
||||
|
||||
static inline int getPreselectPoint(const ViewProviderSketch& vp);
|
||||
static inline int getPreselectCross(const ViewProviderSketch& vp);
|
||||
static inline int getPreselectCurve(const ViewProviderSketch& vp);
|
||||
|
||||
friend class SnapManager;
|
||||
};
|
||||
|
||||
/* This class is used to manage the overriding of mouse pointer coordinates in Sketcher
|
||||
* (in Edit-Mode) depending on the situation. Those situations are in priority order :
|
||||
* 1 - Snap at angle: For tools like Slot, Arc, Line, Ellipse, this enables to constrain the angle at steps of 5° (or customized angle).
|
||||
* This is useful to make features at a certain angle (45° for example)
|
||||
* 2 - Snap to object: This snaps the mouse pointer onto objects.
|
||||
* 3 - Snap to grid: This snaps the mouse pointer on the grid.
|
||||
*/
|
||||
class SnapManager
|
||||
{
|
||||
|
||||
/** @brief Class for monitoring changes in parameters affecting Snapping
|
||||
* @details
|
||||
*
|
||||
* This nested class is a helper responsible for attaching to the parameters relevant for
|
||||
* SnapManager, initialising the SnapManager to the current configuration
|
||||
* and handle in real time any change to their values.
|
||||
*/
|
||||
class ParameterObserver : public ParameterGrp::ObserverType
|
||||
{
|
||||
public:
|
||||
explicit ParameterObserver(SnapManager& client);
|
||||
~ParameterObserver() override;
|
||||
|
||||
void subscribeToParameters();
|
||||
|
||||
void unsubscribeToParameters();
|
||||
|
||||
/** Observer for parameter group. */
|
||||
void OnChange(Base::Subject<const char*>& rCaller, const char* sReason) override;
|
||||
|
||||
private:
|
||||
void initParameters();
|
||||
void updateSnapParameter(const std::string& parametername);
|
||||
void updateSnapToObjectParameter(const std::string& parametername);
|
||||
void updateSnapToGridParameter(const std::string& parametername);
|
||||
void updateSnapAngleParameter(const std::string& parametername);
|
||||
|
||||
static ParameterGrp::handle getParameterGrpHandle();
|
||||
|
||||
private:
|
||||
std::map<std::string, std::function<void(const std::string&)>> str2updatefunction;
|
||||
SnapManager& client;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit SnapManager(ViewProviderSketch &vp);
|
||||
~SnapManager();
|
||||
|
||||
bool snap(double& x, double& y);
|
||||
bool snapAtAngle(double& x, double& y);
|
||||
bool snapToObject(double& x, double& y);
|
||||
bool snapToGrid(double& x, double& y);
|
||||
|
||||
bool snapToLineMiddle(Base::Vector3d& pointToOverride, const Part::GeomLineSegment* line);
|
||||
bool snapToArcMiddle(Base::Vector3d& pointToOverride, const Part::GeomArcOfCircle* arc);
|
||||
|
||||
bool angleSnapEnabled;
|
||||
Base::Vector2d referencePoint;
|
||||
|
||||
private:
|
||||
double snapAngle;
|
||||
double lastMouseAngle;
|
||||
|
||||
bool snapRequested;
|
||||
bool snapToObjectsRequested;
|
||||
bool snapToGridRequested;
|
||||
|
||||
/// Reference to ViewProviderSketch in order to access the public and the Attorney Interface
|
||||
ViewProviderSketch & viewProvider;
|
||||
|
||||
/// Observer to track all the needed parameters.
|
||||
std::unique_ptr<SnapManager::ParameterObserver> pObserver;
|
||||
};
|
||||
|
||||
|
||||
} // namespace SketcherGui
|
||||
|
||||
|
||||
#endif // SKETCHERGUI_SnapManager_H
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
#include "DrawSketchHandler.h"
|
||||
#include "EditDatumDialog.h"
|
||||
#include "EditModeCoinManager.h"
|
||||
#include "SnapManager.h"
|
||||
#include "TaskDlgEditSketch.h"
|
||||
#include "TaskSketcherValidation.h"
|
||||
#include "Utils.h"
|
||||
@@ -304,6 +305,7 @@ ViewProviderSketch::ViewProviderSketch()
|
||||
Mode(STATUS_NONE),
|
||||
listener(nullptr),
|
||||
editCoinManager(nullptr),
|
||||
snapManager(nullptr),
|
||||
pObserver(std::make_unique<ViewProviderSketch::ParameterObserver>(*this)),
|
||||
sketchHandler(nullptr),
|
||||
viewOrientationFactor(1)
|
||||
@@ -551,36 +553,11 @@ bool ViewProviderSketch::keyPressed(bool pressed, int key)
|
||||
return true; // handle all other key events
|
||||
}
|
||||
|
||||
void ViewProviderSketch::setSnapMode(SnapMode mode)
|
||||
void ViewProviderSketch::setAngleSnapping(bool enable, Base::Vector2d referencePoint)
|
||||
{
|
||||
snapMode = mode; // to be redirected to SnapManager
|
||||
}
|
||||
|
||||
SnapMode ViewProviderSketch::getSnapMode() const
|
||||
{
|
||||
return snapMode; // to be redirected to SnapManager
|
||||
}
|
||||
|
||||
void ViewProviderSketch::snapToGrid(double &x, double &y) // Paddle, when resolving this conflict, make sure to use the function in ViewProviderGridExtension
|
||||
{
|
||||
if (snapMode == SnapMode::SnapToGrid && ShowGrid.getValue()) {
|
||||
// Snap Tolerance in pixels
|
||||
const double snapTol = getGridSize() / 5;
|
||||
|
||||
double tmpX = x, tmpY = y;
|
||||
|
||||
getClosestGridPoint(tmpX, tmpY);
|
||||
|
||||
// Check if x within snap tolerance
|
||||
if (x < tmpX + snapTol && x > tmpX - snapTol) {
|
||||
x = tmpX; // Snap X Mouse Position
|
||||
}
|
||||
|
||||
// Check if y within snap tolerance
|
||||
if (y < tmpY + snapTol && y > tmpY - snapTol) {
|
||||
y = tmpY; // Snap Y Mouse Position
|
||||
}
|
||||
}
|
||||
assert(snapManager);
|
||||
snapManager->angleSnapEnabled = enable;
|
||||
snapManager->referencePoint = referencePoint;
|
||||
}
|
||||
|
||||
void ViewProviderSketch::getProjectingLine(const SbVec2s& pnt, const Gui::View3DInventorViewer *viewer, SbLine& line) const
|
||||
@@ -679,7 +656,7 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe
|
||||
|
||||
try {
|
||||
getCoordsOnSketchPlane(pos,normal,x,y);
|
||||
snapToGrid(x, y);
|
||||
snapManager->snap(x, y);
|
||||
}
|
||||
catch (const Base::ZeroDivisionError&) {
|
||||
return false;
|
||||
@@ -1148,7 +1125,7 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor
|
||||
double x,y;
|
||||
try {
|
||||
getCoordsOnSketchPlane(line.getPosition(),line.getDirection(),x,y);
|
||||
snapToGrid(x, y);
|
||||
snapManager->snap(x, y);
|
||||
}
|
||||
catch (const Base::ZeroDivisionError&) {
|
||||
return false;
|
||||
@@ -1275,7 +1252,7 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor
|
||||
SbLine line2;
|
||||
getProjectingLine(DoubleClick::prvCursorPos, viewer, line2);
|
||||
getCoordsOnSketchPlane(line2.getPosition(),line2.getDirection(),drag.xInit,drag.yInit);
|
||||
snapToGrid(drag.xInit, drag.yInit);
|
||||
snapManager->snap(drag.xInit, drag.yInit);
|
||||
} else {
|
||||
drag.resetVector();
|
||||
}
|
||||
@@ -2877,6 +2854,7 @@ bool ViewProviderSketch::setEdit(int ModNum)
|
||||
preselection.reset();
|
||||
selection.reset();
|
||||
editCoinManager = std::make_unique<EditModeCoinManager>(*this);
|
||||
snapManager = std::make_unique<SnapManager>(*this);
|
||||
|
||||
auto editDoc = Gui::Application::Instance->editDocument();
|
||||
App::DocumentObject *editObj = getSketchObject();
|
||||
@@ -3123,6 +3101,7 @@ void ViewProviderSketch::unsetEdit(int ModNum)
|
||||
deactivateHandler();
|
||||
|
||||
editCoinManager = nullptr;
|
||||
snapManager = nullptr;
|
||||
preselection.reset();
|
||||
selection.reset();
|
||||
this->detachSelection();
|
||||
|
||||
@@ -85,15 +85,9 @@ namespace Sketcher {
|
||||
namespace SketcherGui {
|
||||
|
||||
class EditModeCoinManager;
|
||||
class SnapManager;
|
||||
class DrawSketchHandler;
|
||||
|
||||
enum class SnapMode { // to be moved to SnapManager
|
||||
None,
|
||||
SnapToObject,
|
||||
SnapToAngle,
|
||||
SnapToGrid,
|
||||
};
|
||||
|
||||
using GeoList = Sketcher::GeoList;
|
||||
using GeoListFacade = Sketcher::GeoListFacade;
|
||||
|
||||
@@ -484,8 +478,10 @@ public:
|
||||
void onSelectionChanged(const Gui::SelectionChanges& msg) override;
|
||||
//@}
|
||||
|
||||
void setSnapMode(SnapMode mode);
|
||||
SnapMode getSnapMode() const;
|
||||
/** @name Toggle angle snapping and set the reference point */
|
||||
//@{
|
||||
/// Toggle angle snapping and set the reference point
|
||||
void setAngleSnapping(bool enable, Base::Vector2d referencePoint = Base::Vector2d(0., 0.));
|
||||
|
||||
/** @name Access to Sketch and Solver objects */
|
||||
//@{
|
||||
@@ -566,6 +562,7 @@ public:
|
||||
//@{
|
||||
friend class ViewProviderSketchDrawSketchHandlerAttorney;
|
||||
friend class ViewProviderSketchCoinAttorney;
|
||||
friend class ViewProviderSketchSnapAttorney;
|
||||
friend class ViewProviderSketchShortcutListenerAttorney;
|
||||
//@}
|
||||
protected:
|
||||
@@ -660,9 +657,6 @@ private:
|
||||
|
||||
/** @name miscelanea utilities */
|
||||
//@{
|
||||
/// snap points x,y (mouse coordinates) onto grid if enabled
|
||||
void snapToGrid(double &x, double &y);
|
||||
|
||||
/// moves a selected constraint
|
||||
void moveConstraint(int constNum, const Base::Vector2d &toPos);
|
||||
|
||||
@@ -784,6 +778,8 @@ private:
|
||||
|
||||
std::unique_ptr<EditModeCoinManager> editCoinManager;
|
||||
|
||||
std::unique_ptr<SnapManager> snapManager;
|
||||
|
||||
std::unique_ptr<ViewProviderSketch::ParameterObserver> pObserver;
|
||||
|
||||
std::unique_ptr<DrawSketchHandler> sketchHandler;
|
||||
@@ -792,8 +788,6 @@ private:
|
||||
|
||||
SoNodeSensor cameraSensor;
|
||||
int viewOrientationFactor; // stores if sketch viewed from front or back
|
||||
|
||||
SnapMode snapMode = SnapMode::None; // temporary - to be moved to SnapManager
|
||||
};
|
||||
|
||||
} // namespace PartGui
|
||||
|
||||
@@ -188,7 +188,8 @@ inline void SketcherAddWorkbenchSketchEditModeActions(Gui::ToolBarItem& sketch)
|
||||
sketch << "Sketcher_LeaveSketch"
|
||||
<< "Sketcher_ViewSketch"
|
||||
<< "Sketcher_ViewSection"
|
||||
<< "Sketcher_Grid";
|
||||
<< "Sketcher_Grid"
|
||||
<< "Sketcher_Snap";
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
Reference in New Issue
Block a user