1
/***************************************************************************
2
* Copyright (c) 2014 Abdullah Tahiri <abdullah.tahiri.yo@gmail.com> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
28
#include <QApplication>
32
#include <Inventor/SbString.h>
35
#include <App/Application.h>
36
#include <Base/Console.h>
37
#include <Base/Reader.h>
38
#include <Base/Writer.h>
39
#include <Gui/Action.h>
40
#include <Gui/Application.h>
41
#include <Gui/BitmapFactory.h>
42
#include <Gui/CommandT.h>
43
#include <Gui/Document.h>
44
#include <Gui/MainWindow.h>
45
#include <Gui/Notifications.h>
46
#include <Gui/Selection.h>
47
#include <Gui/SelectionObject.h>
48
#include <Mod/Sketcher/App/PythonConverter.h>
49
#include <Mod/Sketcher/App/SketchObject.h>
50
#include <Mod/Sketcher/App/SolverGeometryExtension.h>
52
#include "DrawSketchHandler.h"
53
#include "SketchRectangularArrayDialog.h"
55
#include "ViewProviderSketch.h"
57
#include "DrawSketchHandlerTranslate.h"
58
#include "DrawSketchHandlerOffset.h"
59
#include "DrawSketchHandlerRotate.h"
60
#include "DrawSketchHandlerScale.h"
61
#include "DrawSketchHandlerSymmetry.h"
63
// Hint: this is to prevent to re-format big parts of the file. Remove it later again.
66
using namespace SketcherGui;
67
using namespace Sketcher;
69
std::vector<int> getListOfSelectedGeoIds(bool forceInternalSelection)
71
std::vector<int> listOfGeoIds = {};
74
std::vector<Gui::SelectionObject> selection;
75
selection = Gui::Selection().getSelectionEx(0, Sketcher::SketchObject::getClassTypeId());
77
// only one sketch with its subelements are allowed to be selected
78
if (selection.size() != 1) {
79
QMessageBox::warning(Gui::getMainWindow(),
80
QObject::tr("Wrong selection"),
81
QObject::tr("Select elements from a single sketch."));
85
// get the needed lists and objects
86
auto* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject());
87
const std::vector<std::string>& subNames = selection[0].getSubNames();
88
if (!subNames.empty()) {
90
for (auto& name : subNames) {
91
// only handle non-external edges
92
if (name.size() > 4 && name.substr(0, 4) == "Edge") {
93
int geoId = std::atoi(name.substr(4, 4000).c_str()) - 1;
95
listOfGeoIds.push_back(geoId);
98
else if (name.size() > 6 && name.substr(0, 6) == "Vertex") {
99
// only if it is a GeomPoint
100
int VtId = std::atoi(name.substr(6, 4000).c_str()) - 1;
102
Sketcher::PointPos PosId;
103
Obj->getGeoVertexIndex(VtId, geoId, PosId);
104
if (isPoint(*Obj->getGeometry(geoId))) {
106
listOfGeoIds.push_back(geoId);
113
if (forceInternalSelection) {
114
size_t loopSize = listOfGeoIds.size();
115
for (size_t i = 0; i < loopSize; i++) {
116
const Part::Geometry* geo = Obj->getGeometry(listOfGeoIds[i]);
117
if (isEllipse(*geo) || isArcOfEllipse(*geo) || isArcOfHyperbola(*geo) || isArcOfParabola(*geo) || isBSplineCurve(*geo)) {
118
const std::vector<Sketcher::Constraint*>& constraints = Obj->Constraints.getValues();
119
for (auto constr : constraints) {
120
if (constr->Type == InternalAlignment && constr->Second == listOfGeoIds[i]) {
121
if (std::find(listOfGeoIds.begin(), listOfGeoIds.end(), constr->First) == listOfGeoIds.end()) {
122
// If the value is not found, add it to the vector
123
listOfGeoIds.push_back(constr->First);
131
if (listOfGeoIds.empty()) {
132
Gui::NotifyUserError(Obj,
133
QT_TRANSLATE_NOOP("Notifications", "Invalid selection"),
134
QT_TRANSLATE_NOOP("Notifications", "Selection has no valid geometries."));
140
Sketcher::SketchObject* getSketchObject()
142
Gui::Document* doc = Gui::Application::Instance->activeDocument();
144
auto* vp = static_cast<SketcherGui::ViewProviderSketch*>(doc->getInEdit());
145
return vp->getSketchObject();
148
// ================================================================================
152
bool copySelectionToClipboard(Sketcher::SketchObject* obj) {
153
std::vector<int> listOfGeoId = getListOfSelectedGeoIds(true);
154
if (listOfGeoId.empty()) { return false; }
155
sort(listOfGeoId.begin(), listOfGeoId.end());
157
//Export selected geometries as a formatted string.
158
std::vector<Part::Geometry*> shapeGeometry;
159
for (auto geoId : listOfGeoId) {
160
Part::Geometry* geoNew = obj->getGeometry(geoId)->copy();
161
shapeGeometry.push_back(geoNew);
163
std::string geosAsStr = Sketcher::PythonConverter::convert(
166
Sketcher::PythonConverter::Mode::OmitInternalGeometry);
168
// Export constraints of selected geos.
169
std::vector<Sketcher::Constraint*> shapeConstraints;
170
for (auto constr : obj->Constraints.getValues()) {
172
auto isSelectedGeoOrAxis = [](const std::vector<int>& vec, int value) {
173
return (std::find(vec.begin(), vec.end(), value) != vec.end())
174
|| value == GeoEnum::GeoUndef || value == GeoEnum::RtPnt
175
|| value == GeoEnum::VAxis || value == GeoEnum::HAxis;
178
if (!isSelectedGeoOrAxis(listOfGeoId, constr->First)
179
|| !isSelectedGeoOrAxis(listOfGeoId, constr->Second)
180
|| !isSelectedGeoOrAxis(listOfGeoId, constr->Third)) {
184
Constraint* temp = constr->copy();
185
for (size_t j = 0; j < listOfGeoId.size(); j++) {
186
if (temp->First == listOfGeoId[j]) {
189
if (temp->Second == listOfGeoId[j]) {
192
if (temp->Third == listOfGeoId[j]) {
196
shapeConstraints.push_back(temp);
198
std::string cstrAsStr = Sketcher::PythonConverter::convert("objectStr", shapeConstraints, Sketcher::PythonConverter::GeoIdMode::AddLastGeoIdToGeoIds);
200
std::string exportedData = "# Copied from sketcher. From:\n#objectStr = " + Gui::Command::getObjectCmd(obj) + "\n"
201
+ geosAsStr + "\n" + cstrAsStr;
203
if (!exportedData.empty()) {
204
QClipboard* clipboard = QGuiApplication::clipboard();
205
clipboard->setText(QString::fromStdString(exportedData));
211
DEF_STD_CMD_A(CmdSketcherCopyClipboard)
213
CmdSketcherCopyClipboard::CmdSketcherCopyClipboard()
214
: Command("Sketcher_CopyClipboard")
216
sAppModule = "Sketcher";
218
sMenuText = QT_TR_NOOP("C&opy in sketcher");
219
sToolTipText = QT_TR_NOOP("Copy selected geometries and constraints to the clipboard");
220
sWhatsThis = "Sketcher_CopyClipboard";
221
sStatusTip = sToolTipText;
222
sPixmap = "edit-copy";
223
sAccel = keySequenceToAccel(QKeySequence::Copy);
227
void CmdSketcherCopyClipboard::activated(int iMsg)
230
copySelectionToClipboard(getSketchObject());
233
bool CmdSketcherCopyClipboard::isActive()
235
return isCommandActive(getActiveGuiDocument(), true);
238
// ================================================================================
242
DEF_STD_CMD_A(CmdSketcherCut)
244
CmdSketcherCut::CmdSketcherCut()
245
: Command("Sketcher_Cut")
247
sAppModule = "Sketcher";
249
sMenuText = QT_TR_NOOP("C&ut in sketcher");
250
sToolTipText = QT_TR_NOOP("Cut selected geometries and constraints to the clipboard");
251
sWhatsThis = "Sketcher_Cut";
252
sStatusTip = sToolTipText;
253
sPixmap = "edit-cut";
254
sAccel = keySequenceToAccel(QKeySequence::Cut);
258
void CmdSketcherCut::activated(int iMsg)
261
if (copySelectionToClipboard(getSketchObject())) {
263
Gui::Document* doc = getActiveGuiDocument();
265
auto* vp = static_cast<SketcherGui::ViewProviderSketch*>(doc->getInEdit());
267
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Cut in Sketcher"));
268
vp->deleteSelected();
269
Gui::Command::commitCommand();
273
bool CmdSketcherCut::isActive()
275
return isCommandActive(getActiveGuiDocument(), true);
278
// ================================================================================
282
DEF_STD_CMD_A(CmdSketcherPaste)
284
CmdSketcherPaste::CmdSketcherPaste()
285
: Command("Sketcher_Paste")
287
sAppModule = "Sketcher";
289
sMenuText = QT_TR_NOOP("P&aste in sketcher");
290
sToolTipText = QT_TR_NOOP("Paste selected geometries and constraints from the clipboard");
291
sWhatsThis = "Sketcher_Paste";
292
sStatusTip = sToolTipText;
293
sPixmap = "edit-paste";
294
sAccel = keySequenceToAccel(QKeySequence::Paste);
298
void CmdSketcherPaste::activated(int iMsg)
301
Gui::Document* doc = getActiveGuiDocument();
303
auto* vp = static_cast<SketcherGui::ViewProviderSketch*>(doc->getInEdit());
304
Sketcher::SketchObject* obj = vp->getSketchObject();
306
std::string data = QGuiApplication::clipboard()->text().toStdString();
307
if (data.find("# Copied from sketcher.", 0) == std::string::npos) {
310
data = "objectStr = " + Gui::Command::getObjectCmd(obj) +"\n" + data;
312
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Paste in Sketcher"));
314
Gui::Command::doCommand(Gui::Command::Doc, data.c_str());
317
vp->draw(false, false);
319
Gui::Command::commitCommand();
322
bool CmdSketcherPaste::isActive()
324
return isCommandActive(getActiveGuiDocument(), false);
327
// ================================================================================
329
// Select Constraints of selected elements
330
DEF_STD_CMD_A(CmdSketcherSelectConstraints)
332
CmdSketcherSelectConstraints::CmdSketcherSelectConstraints()
333
: Command("Sketcher_SelectConstraints")
335
sAppModule = "Sketcher";
337
sMenuText = QT_TR_NOOP("Select associated constraints");
339
QT_TR_NOOP("Select the constraints associated with the selected geometrical elements");
340
sWhatsThis = "Sketcher_SelectConstraints";
341
sStatusTip = sToolTipText;
342
sPixmap = "Sketcher_SelectConstraints";
347
void CmdSketcherSelectConstraints::activated(int iMsg)
352
std::vector<Gui::SelectionObject> selection;
353
selection = getSelection().getSelectionEx(nullptr, Sketcher::SketchObject::getClassTypeId());
355
// Cancel any in-progress operation
356
Gui::Document* doc = Gui::Application::Instance->activeDocument();
357
SketcherGui::ReleaseHandler(doc);
359
// only one sketch with its subelements are allowed to be selected
360
if (selection.size() != 1) {
361
Gui::TranslatedUserWarning(doc->getDocument(),
362
QObject::tr("Wrong selection"),
363
QObject::tr("Select elements from a single sketch."));
368
// get the needed lists and objects
369
const std::vector<std::string>& SubNames = selection[0].getSubNames();
370
Sketcher::SketchObject* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject());
371
const std::vector<Sketcher::Constraint*>& vals = Obj->Constraints.getValues();
373
std::string doc_name = Obj->getDocument()->getName();
374
std::string obj_name = Obj->getNameInDocument();
376
getSelection().clearSelection();
378
std::vector<std::string> constraintSubNames;
379
// go through the selected subelements
380
for (std::vector<std::string>::const_iterator it = SubNames.begin(); it != SubNames.end();
383
if (it->size() > 4 && it->substr(0, 4) == "Edge") {
384
int GeoId = std::atoi(it->substr(4, 4000).c_str()) - 1;
386
// push all the constraints
388
for (std::vector<Sketcher::Constraint*>::const_iterator it = vals.begin();
391
if ((*it)->First == GeoId || (*it)->Second == GeoId || (*it)->Third == GeoId) {
392
constraintSubNames.push_back(
393
Sketcher::PropertyConstraintList::getConstraintName(i));
399
if (!constraintSubNames.empty())
400
Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames);
403
bool CmdSketcherSelectConstraints::isActive()
405
return isCommandActive(getActiveGuiDocument(), true);
408
// ================================================================================
411
DEF_STD_CMD_A(CmdSketcherSelectOrigin)
413
CmdSketcherSelectOrigin::CmdSketcherSelectOrigin()
414
: Command("Sketcher_SelectOrigin")
416
sAppModule = "Sketcher";
418
sMenuText = QT_TR_NOOP("Select origin");
419
sToolTipText = QT_TR_NOOP("Select the local origin point of the sketch");
420
sWhatsThis = "Sketcher_SelectOrigin";
421
sStatusTip = sToolTipText;
422
sPixmap = "Sketcher_SelectOrigin";
427
void CmdSketcherSelectOrigin::activated(int iMsg)
430
Sketcher::SketchObject * Obj = getSketchObject();
431
// ViewProviderSketch * vp = static_cast<ViewProviderSketch
432
// *>(Gui::Application::Instance->getViewProvider(docobj)); Sketcher::SketchObject* Obj =
433
// vp->getSketchObject();
435
std::string doc_name = Obj->getDocument()->getName();
436
std::string obj_name = Obj->getNameInDocument();
437
std::stringstream ss;
441
if (Gui::Selection().isSelected(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()))
442
Gui::Selection().rmvSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
444
Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
447
bool CmdSketcherSelectOrigin::isActive()
449
return isCommandActive(getActiveGuiDocument(), false);
452
// ================================================================================
454
// Select Vertical Axis
455
DEF_STD_CMD_A(CmdSketcherSelectVerticalAxis)
457
CmdSketcherSelectVerticalAxis::CmdSketcherSelectVerticalAxis()
458
: Command("Sketcher_SelectVerticalAxis")
460
sAppModule = "Sketcher";
462
sMenuText = QT_TR_NOOP("Select vertical axis");
463
sToolTipText = QT_TR_NOOP("Select the local vertical axis of the sketch");
464
sWhatsThis = "Sketcher_SelectVerticalAxis";
465
sStatusTip = sToolTipText;
466
sPixmap = "Sketcher_SelectVerticalAxis";
471
void CmdSketcherSelectVerticalAxis::activated(int iMsg)
474
Sketcher::SketchObject* Obj = getSketchObject();
476
std::string doc_name = Obj->getDocument()->getName();
477
std::string obj_name = Obj->getNameInDocument();
478
std::stringstream ss;
482
if (Gui::Selection().isSelected(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()))
483
Gui::Selection().rmvSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
485
Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
488
bool CmdSketcherSelectVerticalAxis::isActive()
490
return isCommandActive(getActiveGuiDocument(), false);
493
// ================================================================================
495
// Select Horizontal Axis
496
DEF_STD_CMD_A(CmdSketcherSelectHorizontalAxis)
498
CmdSketcherSelectHorizontalAxis::CmdSketcherSelectHorizontalAxis()
499
: Command("Sketcher_SelectHorizontalAxis")
501
sAppModule = "Sketcher";
503
sMenuText = QT_TR_NOOP("Select horizontal axis");
504
sToolTipText = QT_TR_NOOP("Select the local horizontal axis of the sketch");
505
sWhatsThis = "Sketcher_SelectHorizontalAxis";
506
sStatusTip = sToolTipText;
507
sPixmap = "Sketcher_SelectHorizontalAxis";
512
void CmdSketcherSelectHorizontalAxis::activated(int iMsg)
515
Sketcher::SketchObject* Obj = getSketchObject();
517
std::string doc_name = Obj->getDocument()->getName();
518
std::string obj_name = Obj->getNameInDocument();
519
std::stringstream ss;
523
if (Gui::Selection().isSelected(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()))
524
Gui::Selection().rmvSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
526
Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str());
529
bool CmdSketcherSelectHorizontalAxis::isActive()
531
return isCommandActive(getActiveGuiDocument(), false);
534
// ================================================================================
536
DEF_STD_CMD_A(CmdSketcherSelectRedundantConstraints)
538
CmdSketcherSelectRedundantConstraints::CmdSketcherSelectRedundantConstraints()
539
: Command("Sketcher_SelectRedundantConstraints")
541
sAppModule = "Sketcher";
543
sMenuText = QT_TR_NOOP("Select redundant constraints");
544
sToolTipText = QT_TR_NOOP("Select redundant constraints");
545
sWhatsThis = "Sketcher_SelectRedundantConstraints";
546
sStatusTip = sToolTipText;
547
sPixmap = "Sketcher_SelectRedundantConstraints";
552
void CmdSketcherSelectRedundantConstraints::activated(int iMsg)
555
Sketcher::SketchObject* Obj = getSketchObject();
557
std::string doc_name = Obj->getDocument()->getName();
558
std::string obj_name = Obj->getNameInDocument();
560
// get the needed lists and objects
561
const std::vector<int>& solverredundant = Obj->getLastRedundant();
562
const std::vector<Sketcher::Constraint*>& vals = Obj->Constraints.getValues();
564
getSelection().clearSelection();
566
// push the constraints
567
std::vector<std::string> constraintSubNames;
570
for (std::vector<Sketcher::Constraint*>::const_iterator it = vals.begin(); it != vals.end();
572
for (std::vector<int>::const_iterator itc = solverredundant.begin();
573
itc != solverredundant.end();
575
if ((*itc) - 1 == i) {
576
constraintSubNames.push_back(
577
Sketcher::PropertyConstraintList::getConstraintName(i));
583
if (!constraintSubNames.empty())
584
Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames);
587
bool CmdSketcherSelectRedundantConstraints::isActive()
589
return isCommandActive(getActiveGuiDocument(), false);
592
// ================================================================================
594
DEF_STD_CMD_A(CmdSketcherSelectMalformedConstraints)
596
CmdSketcherSelectMalformedConstraints::CmdSketcherSelectMalformedConstraints()
597
: Command("Sketcher_SelectMalformedConstraints")
599
sAppModule = "Sketcher";
601
sMenuText = QT_TR_NOOP("Select malformed constraints");
602
sToolTipText = QT_TR_NOOP("Select malformed constraints");
603
sWhatsThis = "Sketcher_SelectMalformedConstraints";
604
sStatusTip = sToolTipText;
608
void CmdSketcherSelectMalformedConstraints::activated(int iMsg)
611
Sketcher::SketchObject* Obj = getSketchObject();
613
std::string doc_name = Obj->getDocument()->getName();
614
std::string obj_name = Obj->getNameInDocument();
616
// get the needed lists and objects
617
const std::vector<int>& solvermalformed = Obj->getLastMalformedConstraints();
618
const std::vector<Sketcher::Constraint*>& vals = Obj->Constraints.getValues();
620
getSelection().clearSelection();
622
// push the constraints
623
std::vector<std::string> constraintSubNames;
625
for (std::vector<Sketcher::Constraint*>::const_iterator it = vals.begin(); it != vals.end();
627
for (std::vector<int>::const_iterator itc = solvermalformed.begin();
628
itc != solvermalformed.end();
630
if ((*itc) - 1 == i) {
631
constraintSubNames.push_back(
632
Sketcher::PropertyConstraintList::getConstraintName(i));
638
if (!constraintSubNames.empty())
639
Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames);
642
bool CmdSketcherSelectMalformedConstraints::isActive()
644
return isCommandActive(getActiveGuiDocument(), false);
647
// ================================================================================
649
DEF_STD_CMD_A(CmdSketcherSelectPartiallyRedundantConstraints)
651
CmdSketcherSelectPartiallyRedundantConstraints::CmdSketcherSelectPartiallyRedundantConstraints()
652
: Command("Sketcher_SelectPartiallyRedundantConstraints")
654
sAppModule = "Sketcher";
656
sMenuText = QT_TR_NOOP("Select partially redundant constraints");
657
sToolTipText = QT_TR_NOOP("Select partially redundant constraints");
658
sWhatsThis = "Sketcher_SelectPartiallyRedundantConstraints";
659
sStatusTip = sToolTipText;
663
void CmdSketcherSelectPartiallyRedundantConstraints::activated(int iMsg)
666
Sketcher::SketchObject* Obj = getSketchObject();
668
std::string doc_name = Obj->getDocument()->getName();
669
std::string obj_name = Obj->getNameInDocument();
671
// get the needed lists and objects
672
const std::vector<int>& solverpartiallyredundant =
673
Obj->getLastPartiallyRedundant();
674
const std::vector<Sketcher::Constraint*>& vals = Obj->Constraints.getValues();
676
getSelection().clearSelection();
678
// push the constraints
679
std::vector<std::string> constraintSubNames;
681
for (std::vector<Sketcher::Constraint*>::const_iterator it = vals.begin(); it != vals.end();
683
for (std::vector<int>::const_iterator itc = solverpartiallyredundant.begin();
684
itc != solverpartiallyredundant.end();
686
if ((*itc) - 1 == i) {
687
constraintSubNames.push_back(
688
Sketcher::PropertyConstraintList::getConstraintName(i));
694
if (!constraintSubNames.empty())
695
Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames);
698
bool CmdSketcherSelectPartiallyRedundantConstraints::isActive()
700
return isCommandActive(getActiveGuiDocument(), false);
703
// ================================================================================
705
DEF_STD_CMD_A(CmdSketcherSelectConflictingConstraints)
707
CmdSketcherSelectConflictingConstraints::CmdSketcherSelectConflictingConstraints()
708
: Command("Sketcher_SelectConflictingConstraints")
710
sAppModule = "Sketcher";
712
sMenuText = QT_TR_NOOP("Select conflicting constraints");
713
sToolTipText = QT_TR_NOOP("Select conflicting constraints");
714
sWhatsThis = "Sketcher_SelectConflictingConstraints";
715
sStatusTip = sToolTipText;
716
sPixmap = "Sketcher_SelectConflictingConstraints";
721
void CmdSketcherSelectConflictingConstraints::activated(int iMsg)
724
Sketcher::SketchObject* Obj = getSketchObject();
726
std::string doc_name = Obj->getDocument()->getName();
727
std::string obj_name = Obj->getNameInDocument();
729
// get the needed lists and objects
730
const std::vector<int>& solverconflicting = Obj->getLastConflicting();
731
const std::vector<Sketcher::Constraint*>& vals = Obj->Constraints.getValues();
733
getSelection().clearSelection();
735
// push the constraints
736
std::vector<std::string> constraintSubNames;
738
for (std::vector<Sketcher::Constraint*>::const_iterator it = vals.begin(); it != vals.end();
740
for (std::vector<int>::const_iterator itc = solverconflicting.begin();
741
itc != solverconflicting.end();
743
if ((*itc) - 1 == i) {
744
constraintSubNames.push_back(
745
Sketcher::PropertyConstraintList::getConstraintName(i));
751
if (!constraintSubNames.empty())
752
Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), constraintSubNames);
755
bool CmdSketcherSelectConflictingConstraints::isActive()
757
return isCommandActive(getActiveGuiDocument(), false);
760
// ================================================================================
762
DEF_STD_CMD_A(CmdSketcherSelectElementsAssociatedWithConstraints)
764
CmdSketcherSelectElementsAssociatedWithConstraints::
765
CmdSketcherSelectElementsAssociatedWithConstraints()
766
: Command("Sketcher_SelectElementsAssociatedWithConstraints")
768
sAppModule = "Sketcher";
770
sMenuText = QT_TR_NOOP("Select associated geometry");
772
QT_TR_NOOP("Select the geometrical elements associated with the selected constraints");
773
sWhatsThis = "Sketcher_SelectElementsAssociatedWithConstraints";
774
sStatusTip = sToolTipText;
775
sPixmap = "Sketcher_SelectElementsAssociatedWithConstraints";
780
void CmdSketcherSelectElementsAssociatedWithConstraints::activated(int iMsg)
783
std::vector<Gui::SelectionObject> selection = Gui::Selection().getSelectionEx();
784
Sketcher::SketchObject* Obj = getSketchObject();
786
const std::vector<std::string>& SubNames = selection[0].getSubNames();
787
const std::vector<Sketcher::Constraint*>& vals = Obj->Constraints.getValues();
789
getSelection().clearSelection();
791
std::string doc_name = Obj->getDocument()->getName();
792
std::string obj_name = Obj->getNameInDocument();
793
std::stringstream ss;
795
std::vector<std::string> elementSubNames;
796
// go through the selected subelements
797
for (std::vector<std::string>::const_iterator it = SubNames.begin(); it != SubNames.end();
799
// only handle constraints
800
if (it->size() > 10 && it->substr(0, 10) == "Constraint") {
801
int ConstrId = Sketcher::PropertyConstraintList::getIndexFromConstraintName(*it);
803
if (ConstrId < static_cast<int>(vals.size())) {
804
if (vals[ConstrId]->First != GeoEnum::GeoUndef) {
805
ss.str(std::string());
807
switch (vals[ConstrId]->FirstPos) {
808
case Sketcher::PointPos::none:
809
ss << "Edge" << vals[ConstrId]->First + 1;
811
case Sketcher::PointPos::start:
812
case Sketcher::PointPos::end:
813
case Sketcher::PointPos::mid:
814
int vertex = Obj->getVertexIndexGeoPos(vals[ConstrId]->First,
815
vals[ConstrId]->FirstPos);
817
ss << "Vertex" << vertex + 1;
820
elementSubNames.push_back(ss.str());
823
if (vals[ConstrId]->Second != GeoEnum::GeoUndef) {
824
ss.str(std::string());
826
switch (vals[ConstrId]->SecondPos) {
827
case Sketcher::PointPos::none:
828
ss << "Edge" << vals[ConstrId]->Second + 1;
830
case Sketcher::PointPos::start:
831
case Sketcher::PointPos::end:
832
case Sketcher::PointPos::mid:
833
int vertex = Obj->getVertexIndexGeoPos(vals[ConstrId]->Second,
834
vals[ConstrId]->SecondPos);
836
ss << "Vertex" << vertex + 1;
840
elementSubNames.push_back(ss.str());
843
if (vals[ConstrId]->Third != GeoEnum::GeoUndef) {
844
ss.str(std::string());
846
switch (vals[ConstrId]->ThirdPos) {
847
case Sketcher::PointPos::none:
848
ss << "Edge" << vals[ConstrId]->Third + 1;
850
case Sketcher::PointPos::start:
851
case Sketcher::PointPos::end:
852
case Sketcher::PointPos::mid:
853
int vertex = Obj->getVertexIndexGeoPos(vals[ConstrId]->Third,
854
vals[ConstrId]->ThirdPos);
856
ss << "Vertex" << vertex + 1;
860
elementSubNames.push_back(ss.str());
866
if (elementSubNames.empty()) {
867
Gui::TranslatedUserWarning(Obj,
868
QObject::tr("No constraint selected"),
869
QObject::tr("At least one constraint must be selected"));
872
Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), elementSubNames);
876
bool CmdSketcherSelectElementsAssociatedWithConstraints::isActive()
878
return isCommandActive(getActiveGuiDocument(), true);
881
// ================================================================================
883
DEF_STD_CMD_A(CmdSketcherSelectElementsWithDoFs)
885
CmdSketcherSelectElementsWithDoFs::CmdSketcherSelectElementsWithDoFs()
886
: Command("Sketcher_SelectElementsWithDoFs")
888
sAppModule = "Sketcher";
890
sMenuText = QT_TR_NOOP("Select under-constrained elements");
891
sToolTipText = QT_TR_NOOP("Select geometrical elements where the solver still detects "
892
"unconstrained degrees of freedom.");
893
sWhatsThis = "Sketcher_SelectElementsWithDoFs";
894
sStatusTip = sToolTipText;
895
sPixmap = "Sketcher_SelectElementsWithDoFs";
900
void CmdSketcherSelectElementsWithDoFs::activated(int iMsg)
903
getSelection().clearSelection();
904
Sketcher::SketchObject* Obj = getSketchObject();
906
std::string doc_name = Obj->getDocument()->getName();
907
std::string obj_name = Obj->getNameInDocument();
908
std::stringstream ss;
910
auto geos = Obj->getInternalGeometry();
912
std::vector<std::string> elementSubNames;
914
auto testselectvertex = [&Obj, &ss, &elementSubNames](int geoId, PointPos pos) {
915
ss.str(std::string());
917
int vertex = Obj->getVertexIndexGeoPos(geoId, pos);
919
ss << "Vertex" << vertex + 1;
921
elementSubNames.push_back(ss.str());
925
auto testselectedge = [&ss, &elementSubNames](int geoId) {
926
ss.str(std::string());
928
ss << "Edge" << geoId + 1;
929
elementSubNames.push_back(ss.str());
934
for (auto geo : geos) {
936
if (geo->hasExtension(Sketcher::SolverGeometryExtension::getClassTypeId())) {
938
auto solvext = std::static_pointer_cast<const Sketcher::SolverGeometryExtension>(
939
geo->getExtension(Sketcher::SolverGeometryExtension::getClassTypeId()).lock());
941
if (solvext->getGeometry()
942
== Sketcher::SolverGeometryExtension::NotFullyConstraint) {
943
// Coded for consistency with getGeometryWithDependentParameters, read the
944
// comments on that function
945
if (solvext->getEdge() == SolverGeometryExtension::Dependent)
946
testselectedge(geoid);
947
if (solvext->getStart() == SolverGeometryExtension::Dependent)
948
testselectvertex(geoid, Sketcher::PointPos::start);
949
if (solvext->getEnd() == SolverGeometryExtension::Dependent)
950
testselectvertex(geoid, Sketcher::PointPos::end);
951
if (solvext->getMid() == SolverGeometryExtension::Dependent)
952
testselectvertex(geoid, Sketcher::PointPos::mid);
960
if (!elementSubNames.empty()) {
961
Gui::Selection().addSelections(doc_name.c_str(), obj_name.c_str(), elementSubNames);
965
bool CmdSketcherSelectElementsWithDoFs::isActive()
967
return isCommandActive(getActiveGuiDocument(), false);
970
// ================================================================================
972
DEF_STD_CMD_A(CmdSketcherRestoreInternalAlignmentGeometry)
974
CmdSketcherRestoreInternalAlignmentGeometry::CmdSketcherRestoreInternalAlignmentGeometry()
975
: Command("Sketcher_RestoreInternalAlignmentGeometry")
977
sAppModule = "Sketcher";
979
sMenuText = QT_TR_NOOP("Show/hide internal geometry");
980
sToolTipText = QT_TR_NOOP("Show all internal geometry or hide unused internal geometry");
981
sWhatsThis = "Sketcher_RestoreInternalAlignmentGeometry";
982
sStatusTip = sToolTipText;
983
sPixmap = "Sketcher_Element_Ellipse_All";
988
void CmdSketcherRestoreInternalAlignmentGeometry::activated(int iMsg)
992
// Cancel any in-progress operation
993
Gui::Document* doc = Gui::Application::Instance->activeDocument();
994
SketcherGui::ReleaseHandler(doc);
997
std::vector<Gui::SelectionObject> selection;
998
selection = getSelection().getSelectionEx(nullptr, Sketcher::SketchObject::getClassTypeId());
1000
// only one sketch with its subelements are allowed to be selected
1001
if (selection.size() != 1) {
1002
Gui::TranslatedUserWarning(doc->getDocument(),
1003
QObject::tr("Wrong selection"),
1004
QObject::tr("Select elements from a single sketch."));
1009
// get the needed lists and objects
1010
const std::vector<std::string>& SubNames = selection[0].getSubNames();
1011
Sketcher::SketchObject* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject());
1013
getSelection().clearSelection();
1015
// Return GeoId of the SubName only if it is an edge
1016
auto getEdgeGeoId = [&Obj](const std::string& SubName) {
1018
Sketcher::PointPos PosId;
1019
getIdsFromName(SubName, Obj, GeoId, PosId);
1020
if (PosId == Sketcher::PointPos::none)
1023
return (int)GeoEnum::GeoUndef;
1026
// Tells if the geometry with given GeoId has internal geometry
1027
auto noInternalGeo = [&Obj](const auto& GeoId) {
1028
const Part::Geometry* geo = Obj->getGeometry(GeoId);
1029
bool hasInternalGeo = geo
1030
&& (geo->is<Part::GeomEllipse>()
1031
|| geo->is<Part::GeomArcOfEllipse>()
1032
|| geo->is<Part::GeomArcOfHyperbola>()
1033
|| geo->is<Part::GeomArcOfParabola>()
1034
|| geo->is<Part::GeomBSplineCurve>());
1035
return !hasInternalGeo;// so it's removed
1038
std::vector<int> SubGeoIds(SubNames.size());
1039
std::transform(SubNames.begin(), SubNames.end(), SubGeoIds.begin(), getEdgeGeoId);
1041
// Handle highest GeoIds first to minimize GeoIds changing
1042
// TODO: this might not completely resolve GeoIds changing
1043
std::sort(SubGeoIds.begin(), SubGeoIds.end(), std::greater<>());
1045
SubGeoIds.erase(std::unique(SubGeoIds.begin(), SubGeoIds.end()), SubGeoIds.end());
1047
// Only for supported types and keep unique
1048
SubGeoIds.erase(std::remove_if(SubGeoIds.begin(), SubGeoIds.end(), noInternalGeo),
1051
// go through the selected subelements
1052
for (const auto& GeoId : SubGeoIds) {
1053
int currentgeoid = Obj->getHighestCurveIndex();
1056
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Exposing Internal Geometry"));
1057
Gui::cmdAppObjectArgs(Obj, "exposeInternalGeometry(%d)", GeoId);
1059
int aftergeoid = Obj->getHighestCurveIndex();
1061
if (aftergeoid == currentgeoid) {// if we did not expose anything, deleteunused
1062
Gui::cmdAppObjectArgs(Obj, "deleteUnusedInternalGeometry(%d)", GeoId);
1065
catch (const Base::Exception& e) {
1066
Gui::NotifyUserError(
1067
Obj, QT_TRANSLATE_NOOP("Notifications", "Invalid Constraint"), e.what());
1068
Gui::Command::abortCommand();
1070
tryAutoRecomputeIfNotSolve(static_cast<Sketcher::SketchObject*>(Obj));
1075
Gui::Command::commitCommand();
1076
tryAutoRecomputeIfNotSolve(static_cast<Sketcher::SketchObject*>(Obj));
1080
bool CmdSketcherRestoreInternalAlignmentGeometry::isActive()
1082
return isCommandActive(getActiveGuiDocument(), true);
1085
// ================================================================================
1087
DEF_STD_CMD_A(CmdSketcherSymmetry)
1089
CmdSketcherSymmetry::CmdSketcherSymmetry()
1090
: Command("Sketcher_Symmetry")
1092
sAppModule = "Sketcher";
1093
sGroup = "Sketcher";
1094
sMenuText = QT_TR_NOOP("Symmetry");
1096
QT_TR_NOOP("Creates symmetric of selected geometry. After starting the tool select the reference line or point.");
1097
sWhatsThis = "Sketcher_Symmetry";
1098
sStatusTip = sToolTipText;
1099
sPixmap = "Sketcher_Symmetry";
1104
void CmdSketcherSymmetry::activated(int iMsg)
1107
std::vector<int> listOfGeoIds = getListOfSelectedGeoIds(true);
1109
if (!listOfGeoIds.empty()) {
1110
ActivateHandler(getActiveGuiDocument(), std::make_unique<DrawSketchHandlerSymmetry>(listOfGeoIds));
1112
getSelection().clearSelection();
1115
bool CmdSketcherSymmetry::isActive()
1117
return isCommandActive(getActiveGuiDocument(), true);
1120
// ================================================================================
1122
class SketcherCopy: public Gui::Command
1131
explicit SketcherCopy(const char* name);
1132
void activate(SketcherCopy::Op op);
1133
virtual void activate() = 0;
1136
// TODO: replace XPM cursor with SVG file
1137
static const char* cursor_createcopy[] = {"32 32 3 1",
1141
"................................",
1142
".......+........................",
1143
".......+........................",
1144
".......+........................",
1145
".......+........................",
1146
".......+........................",
1147
"................................",
1148
".+++++...+++++..................",
1149
"................................",
1150
".......+........................",
1151
".......+..............###.......",
1152
".......+..............###.......",
1153
".......+..............###.......",
1154
".......+..............###.......",
1155
"......................###.......",
1156
".....###..............###.......",
1157
".....###..............###.......",
1158
".....###..............###.......",
1159
".....###..............###.......",
1160
".....###..............###.......",
1161
".....###..............###.......",
1162
".....###..............###.......",
1163
".....###..............###.......",
1164
".....###..............###.......",
1165
".....###........................",
1166
".....###........................",
1167
".....###........................",
1168
".....###........................",
1169
"................................",
1170
"................................",
1171
"................................",
1172
"................................"};
1174
class DrawSketchHandlerCopy: public DrawSketchHandler
1177
DrawSketchHandlerCopy(string geoidlist, int origingeoid, Sketcher::PointPos originpos,
1178
int nelements, SketcherCopy::Op op)
1179
: Mode(STATUS_SEEK_First)
1180
, snapMode(SnapMode::Free)
1181
, geoIdList(geoidlist)
1183
, OriginGeoId(origingeoid)
1184
, OriginPos(originpos)
1185
, nElements(nelements)
1190
~DrawSketchHandlerCopy() override
1195
STATUS_SEEK_First, /**< enum value ----. */
1205
void mouseMove(Base::Vector2d onSketchPos) override
1207
if (Mode == STATUS_SEEK_First) {
1209
if (QApplication::keyboardModifiers() == Qt::ControlModifier)
1210
snapMode = SnapMode::Snap5Degree;
1212
snapMode = SnapMode::Free;
1214
float length = (onSketchPos - EditCurve[0]).Length();
1215
float angle = (onSketchPos - EditCurve[0]).Angle();
1217
Base::Vector2d endpoint = onSketchPos;
1219
if (snapMode == SnapMode::Snap5Degree) {
1220
angle = round(angle / (M_PI / 36)) * M_PI / 36;
1221
endpoint = EditCurve[0] + length * Base::Vector2d(cos(angle), sin(angle));
1224
if (showCursorCoords()) {
1226
std::string lengthString = lengthToDisplayFormat(length, 1);
1227
std::string angleString = angleToDisplayFormat(angle * 180.0 / M_PI, 1);
1228
text.sprintf(" (%s, %s)", lengthString.c_str(), angleString.c_str());
1229
setPositionText(endpoint, text);
1232
EditCurve[1] = endpoint;
1233
drawEdit(EditCurve);
1238
bool pressButton(Base::Vector2d) override
1240
if (Mode == STATUS_SEEK_First) {
1241
drawEdit(EditCurve);
1247
bool releaseButton(Base::Vector2d onSketchPos) override
1249
Q_UNUSED(onSketchPos);
1250
if (Mode == STATUS_End) {
1251
Base::Vector2d vector = EditCurve[1] - EditCurve[0];
1253
resetPositionText();
1255
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Copy/clone/move geometry"));
1258
if (Op != SketcherCopy::Move) {
1259
Gui::cmdAppObjectArgs(sketchgui->getObject(),
1260
"addCopy(%s, App.Vector(%f, %f, 0), %s)",
1264
(Op == SketcherCopy::Clone ? "True" : "False"));
1267
Gui::cmdAppObjectArgs(sketchgui->getObject(),
1268
"addMove(%s, App.Vector(%f, %f, 0))",
1273
Gui::Command::commitCommand();
1275
catch (const Base::Exception& e) {
1276
Gui::NotifyUserError(
1277
sketchgui->getObject(), QT_TRANSLATE_NOOP("Notifications", "Error"), e.what());
1278
Gui::Command::abortCommand();
1281
tryAutoRecomputeIfNotSolve(
1282
static_cast<Sketcher::SketchObject*>(sketchgui->getObject()));
1284
drawEdit(EditCurve);
1286
// no code after this line, Handler gets deleted in ViewProvider
1287
sketchgui->purgeHandler();
1293
void activated() override
1295
setCursor(QPixmap(cursor_createcopy), 7, 7);
1296
Origin = static_cast<Sketcher::SketchObject*>(sketchgui->getObject())
1297
->getPoint(OriginGeoId, OriginPos);
1298
EditCurve[0] = Base::Vector2d(Origin.x, Origin.y);
1305
Base::Vector3d Origin;
1307
Sketcher::PointPos OriginPos;
1309
SketcherCopy::Op Op;
1310
std::vector<Base::Vector2d> EditCurve;
1311
std::vector<AutoConstraint> sugConstr1;
1314
/*---- SketcherCopy definition ----*/
1315
SketcherCopy::SketcherCopy(const char* name)
1319
void SketcherCopy::activate(SketcherCopy::Op op)
1321
// get the selection
1322
std::vector<Gui::SelectionObject> selection = getSelection().getSelectionEx();
1324
// only one sketch with its subelements are allowed to be selected
1325
if (selection.size() != 1) {
1326
Gui::TranslatedUserWarning(getActiveGuiDocument()->getDocument(),
1327
QObject::tr("Wrong selection"),
1328
QObject::tr("Select elements from a single sketch."));
1333
// get the needed lists and objects
1334
const std::vector<std::string>& SubNames = selection[0].getSubNames();
1335
if (SubNames.empty()) {
1336
Gui::TranslatedUserWarning(getActiveGuiDocument()->getDocument(),
1337
QObject::tr("Wrong selection"),
1338
QObject::tr("Select elements from a single sketch."));
1343
Sketcher::SketchObject* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject());
1344
getSelection().clearSelection();
1347
Sketcher::PointPos LastPointPos = Sketcher::PointPos::none;
1348
const Part::Geometry* LastGeo = nullptr;
1350
// create python command with list of elements
1351
std::stringstream stream;
1353
for (std::vector<std::string>::const_iterator it = SubNames.begin(); it != SubNames.end();
1355
// only handle non-external edges
1356
if (it->size() > 4 && it->substr(0, 4) == "Edge") {
1357
LastGeoId = std::atoi(it->substr(4, 4000).c_str()) - 1;
1358
LastPointPos = Sketcher::PointPos::none;
1359
LastGeo = Obj->getGeometry(LastGeoId);
1361
if (LastGeoId >= 0) {
1363
stream << LastGeoId << ",";
1366
else if (it->size() > 6 && it->substr(0, 6) == "Vertex") {
1367
// only if it is a GeomPoint
1368
int VtId = std::atoi(it->substr(6, 4000).c_str()) - 1;
1370
Sketcher::PointPos PosId;
1371
Obj->getGeoVertexIndex(VtId, GeoId, PosId);
1372
if (Obj->getGeometry(GeoId)->is<Part::GeomPoint>()) {
1374
LastPointPos = Sketcher::PointPos::start;
1376
if (LastGeoId >= 0) {
1378
stream << LastGeoId << ",";
1384
// check if last selected element is a Vertex, not being a GeomPoint
1385
if (SubNames.rbegin()->size() > 6 && SubNames.rbegin()->substr(0, 6) == "Vertex") {
1386
int VtId = std::atoi(SubNames.rbegin()->substr(6, 4000).c_str()) - 1;
1388
Sketcher::PointPos PosId;
1389
Obj->getGeoVertexIndex(VtId, GeoId, PosId);
1390
if (!Obj->getGeometry(GeoId)->is<Part::GeomPoint>()) {
1392
LastPointPos = PosId;
1397
Gui::TranslatedUserWarning(
1399
QObject::tr("Wrong selection"),
1400
QObject::tr("A copy requires at least one selected non-external geometric element"));
1405
std::string geoIdList = stream.str();
1407
// remove the last added comma and brackets to make the python list
1408
int index = geoIdList.rfind(',');
1409
geoIdList.resize(index);
1410
geoIdList.insert(0, 1, '[');
1411
geoIdList.append(1, ']');
1413
// if the last element is not a point serving as a reference for the copy process
1414
// then make the start point of the last element the copy reference (if it exists, if not the
1416
if (LastPointPos == Sketcher::PointPos::none) {
1417
if (LastGeo->is<Part::GeomCircle>()
1418
|| LastGeo->is<Part::GeomEllipse>()) {
1419
LastPointPos = Sketcher::PointPos::mid;
1422
LastPointPos = Sketcher::PointPos::start;
1426
// Ask the user if they want to clone or to simple copy
1428
int ret = QMessageBox::question(Gui::getMainWindow(), QObject::tr("Dimensional/Geometric
1429
constraints"), QObject::tr("Do you want to clone the object, i.e. substitute dimensional
1430
constraints by geometric constraints?"), QMessageBox::Yes, QMessageBox::No,
1431
QMessageBox::Cancel);
1432
// use an equality constraint
1433
if (ret == QMessageBox::Yes) {
1436
else if (ret == QMessageBox::Cancel) {
1442
ActivateHandler(getActiveGuiDocument(),
1443
std::make_unique<DrawSketchHandlerCopy>(geoIdList, LastGeoId, LastPointPos, geoids, op));
1447
class CmdSketcherCopy: public SketcherCopy
1451
~CmdSketcherCopy() override
1453
const char* className() const override
1455
return "CmdSketcherCopy";
1457
void activate() override;
1460
void activated(int iMsg) override;
1461
bool isActive() override;
1464
CmdSketcherCopy::CmdSketcherCopy()
1465
: SketcherCopy("Sketcher_Copy")
1467
sAppModule = "Sketcher";
1468
sGroup = "Sketcher";
1469
sMenuText = QT_TR_NOOP("Copy");
1470
sToolTipText = QT_TR_NOOP(
1471
"Creates a simple copy of the geometry taking as reference the last selected point");
1472
sWhatsThis = "Sketcher_Copy";
1473
sStatusTip = sToolTipText;
1474
sPixmap = "Sketcher_Copy";
1479
void CmdSketcherCopy::activated(int iMsg)
1482
SketcherCopy::activate(SketcherCopy::Copy);
1486
void CmdSketcherCopy::activate()
1488
SketcherCopy::activate(SketcherCopy::Copy);
1491
bool CmdSketcherCopy::isActive()
1493
return isCommandActive(getActiveGuiDocument(), true);
1496
// ================================================================================
1498
class CmdSketcherClone: public SketcherCopy
1502
~CmdSketcherClone() override
1504
const char* className() const override
1506
return "CmdSketcherClone";
1508
void activate() override;
1511
void activated(int iMsg) override;
1512
bool isActive() override;
1515
CmdSketcherClone::CmdSketcherClone()
1516
: SketcherCopy("Sketcher_Clone")
1518
sAppModule = "Sketcher";
1519
sGroup = "Sketcher";
1520
sMenuText = QT_TR_NOOP("Clone");
1522
QT_TR_NOOP("Creates a clone of the geometry taking as reference the last selected point");
1523
sWhatsThis = "Sketcher_Clone";
1524
sStatusTip = sToolTipText;
1525
sPixmap = "Sketcher_Clone";
1530
void CmdSketcherClone::activated(int iMsg)
1533
SketcherCopy::activate(SketcherCopy::Clone);
1536
void CmdSketcherClone::activate()
1538
SketcherCopy::activate(SketcherCopy::Clone);
1541
bool CmdSketcherClone::isActive()
1543
return isCommandActive(getActiveGuiDocument(), true);
1546
class CmdSketcherMove: public SketcherCopy
1550
~CmdSketcherMove() override
1552
const char* className() const override
1554
return "CmdSketcherMove";
1556
void activate() override;
1559
void activated(int iMsg) override;
1560
bool isActive() override;
1563
CmdSketcherMove::CmdSketcherMove()
1564
: SketcherCopy("Sketcher_Move")
1566
sAppModule = "Sketcher";
1567
sGroup = "Sketcher";
1568
sMenuText = QT_TR_NOOP("Move");
1569
sToolTipText = QT_TR_NOOP("Moves the geometry taking as reference the last selected point");
1570
sWhatsThis = "Sketcher_Move";
1571
sStatusTip = sToolTipText;
1572
sPixmap = "Sketcher_Move";
1577
void CmdSketcherMove::activated(int iMsg)
1580
SketcherCopy::activate(SketcherCopy::Move);
1583
void CmdSketcherMove::activate()
1585
SketcherCopy::activate(SketcherCopy::Move);
1588
bool CmdSketcherMove::isActive()
1590
return isCommandActive(getActiveGuiDocument(), true);
1593
// ================================================================================
1595
DEF_STD_CMD_ACL(CmdSketcherCompCopy)
1597
CmdSketcherCompCopy::CmdSketcherCompCopy()
1598
: Command("Sketcher_CompCopy")
1600
sAppModule = "Sketcher";
1601
sGroup = "Sketcher";
1602
sMenuText = QT_TR_NOOP("Clone");
1604
QT_TR_NOOP("Creates a clone of the geometry taking as reference the last selected point");
1605
sWhatsThis = "Sketcher_CompCopy";
1606
sStatusTip = sToolTipText;
1611
void CmdSketcherCompCopy::activated(int iMsg)
1613
if (iMsg < 0 || iMsg > 2)
1616
// Since the default icon is reset when enabling/disabling the command we have
1617
// to explicitly set the icon of the used command.
1618
Gui::ActionGroup* pcAction = qobject_cast<Gui::ActionGroup*>(_pcAction);
1619
QList<QAction*> a = pcAction->actions();
1621
assert(iMsg < a.size());
1622
pcAction->setIcon(a[iMsg]->icon());
1625
CmdSketcherClone sc;
1627
pcAction->setShortcut(QString::fromLatin1(this->getAccel()));
1629
else if (iMsg == 1) {
1632
pcAction->setShortcut(QString::fromLatin1(this->getAccel()));
1634
else if (iMsg == 2) {
1637
pcAction->setShortcut(QString::fromLatin1(""));
1641
Gui::Action* CmdSketcherCompCopy::createAction()
1643
Gui::ActionGroup* pcAction = new Gui::ActionGroup(this, Gui::getMainWindow());
1644
pcAction->setDropDownMenu(true);
1645
applyCommandData(this->className(), pcAction);
1647
QAction* clone = pcAction->addAction(QString());
1648
clone->setIcon(Gui::BitmapFactory().iconFromTheme("Sketcher_Clone"));
1649
QAction* copy = pcAction->addAction(QString());
1650
copy->setIcon(Gui::BitmapFactory().iconFromTheme("Sketcher_Copy"));
1651
QAction* move = pcAction->addAction(QString());
1652
move->setIcon(Gui::BitmapFactory().iconFromTheme("Sketcher_Move"));
1654
_pcAction = pcAction;
1657
pcAction->setIcon(clone->icon());
1659
pcAction->setProperty("defaultAction", QVariant(defaultId));
1661
pcAction->setShortcut(QString::fromLatin1(getAccel()));
1666
void CmdSketcherCompCopy::languageChange()
1668
Command::languageChange();
1672
Gui::ActionGroup* pcAction = qobject_cast<Gui::ActionGroup*>(_pcAction);
1673
QList<QAction*> a = pcAction->actions();
1675
QAction* clone = a[0];
1676
clone->setText(QApplication::translate("Sketcher_CompCopy", "Clone"));
1677
clone->setToolTip(QApplication::translate(
1679
"Creates a clone of the geometry taking as reference the last selected point"));
1680
clone->setStatusTip(QApplication::translate(
1682
"Creates a clone of the geometry taking as reference the last selected point"));
1683
QAction* copy = a[1];
1684
copy->setText(QApplication::translate("Sketcher_CompCopy", "Copy"));
1685
copy->setToolTip(QApplication::translate(
1687
"Creates a simple copy of the geometry taking as reference the last selected point"));
1688
copy->setStatusTip(QApplication::translate(
1690
"Creates a simple copy of the geometry taking as reference the last selected point"));
1691
QAction* move = a[2];
1692
move->setText(QApplication::translate("Sketcher_CompCopy", "Move"));
1693
move->setToolTip(QApplication::translate(
1694
"Sketcher_Move", "Moves the geometry taking as reference the last selected point"));
1695
move->setStatusTip(QApplication::translate(
1696
"Sketcher_Move", "Moves the geometry taking as reference the last selected point"));
1699
bool CmdSketcherCompCopy::isActive()
1701
return isCommandActive(getActiveGuiDocument(), true);
1704
// ================================================================================
1706
// TODO: replace XPM cursor with SVG file
1708
static const char* cursor_createrectangulararray[] = {"32 32 3 1",
1712
"................................",
1713
".......+........................",
1714
".......+........................",
1715
".......+........................",
1716
".......+........................",
1717
".......+........................",
1718
"................................",
1719
".+++++...+++++..................",
1720
".......................###......",
1721
".......+...............###......",
1722
".......+...............###......",
1723
".......+...............###......",
1724
".......+......###......###......",
1725
".......+......###......###......",
1726
"..............###......###......",
1727
"..............###......###......",
1728
".....###......###......###......",
1729
".....###......###......###......",
1730
".....###......###......###......",
1731
".....###......###......###......",
1732
".....###......###......###......",
1733
".....###......###......###......",
1734
".....###......###...............",
1735
".....###......###...............",
1736
".....###......###...............",
1737
".....###......###...............",
1738
".....###........................",
1739
".....###........................",
1740
".....###........................",
1741
".....###........................",
1742
"................................",
1743
"................................"};
1745
class DrawSketchHandlerRectangularArray: public DrawSketchHandler
1748
DrawSketchHandlerRectangularArray(string geoidlist, int origingeoid,
1749
Sketcher::PointPos originpos, int nelements, bool clone,
1750
int rows, int cols, bool constraintSeparation,
1751
bool equalVerticalHorizontalSpacing)
1752
: Mode(STATUS_SEEK_First)
1753
, snapMode(SnapMode::Free)
1754
, geoIdList(geoidlist)
1755
, OriginGeoId(origingeoid)
1756
, OriginPos(originpos)
1757
, nElements(nelements)
1761
, ConstraintSeparation(constraintSeparation)
1762
, EqualVerticalHorizontalSpacing(equalVerticalHorizontalSpacing)
1766
~DrawSketchHandlerRectangularArray() override
1771
STATUS_SEEK_First, /**< enum value ----. */
1781
void mouseMove(Base::Vector2d onSketchPos) override
1783
if (Mode == STATUS_SEEK_First) {
1785
if (QApplication::keyboardModifiers() == Qt::ControlModifier)
1786
snapMode = SnapMode::Snap5Degree;
1788
snapMode = SnapMode::Free;
1790
float length = (onSketchPos - EditCurve[0]).Length();
1791
float angle = (onSketchPos - EditCurve[0]).Angle();
1793
Base::Vector2d endpoint = onSketchPos;
1795
if (snapMode == SnapMode::Snap5Degree) {
1796
angle = round(angle / (M_PI / 36)) * M_PI / 36;
1797
endpoint = EditCurve[0] + length * Base::Vector2d(cos(angle), sin(angle));
1800
if (showCursorCoords()) {
1802
std::string lengthString = lengthToDisplayFormat(length, 1);
1803
std::string angleString = angleToDisplayFormat(angle * 180.0 / M_PI, 1);
1804
text.sprintf(" (%s, %s)", lengthString.c_str(), angleString.c_str());
1805
setPositionText(endpoint, text);
1808
EditCurve[1] = endpoint;
1809
drawEdit(EditCurve);
1810
if (seekAutoConstraint(
1811
sugConstr1, endpoint, Base::Vector2d(0.0, 0.0), AutoConstraint::VERTEX)) {
1812
renderSuggestConstraintsCursor(sugConstr1);
1819
bool pressButton(Base::Vector2d) override
1821
if (Mode == STATUS_SEEK_First) {
1822
drawEdit(EditCurve);
1828
bool releaseButton(Base::Vector2d onSketchPos) override
1830
Q_UNUSED(onSketchPos);
1831
if (Mode == STATUS_End) {
1832
Base::Vector2d vector = EditCurve[1] - EditCurve[0];
1834
resetPositionText();
1836
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create copy of geometry"));
1839
Gui::cmdAppObjectArgs(
1840
sketchgui->getObject(),
1841
"addRectangularArray(%s, App.Vector(%f, %f, 0), %s, %d, %d, %s, %f)",
1845
(Clone ? "True" : "False"),
1848
(ConstraintSeparation ? "True" : "False"),
1849
(EqualVerticalHorizontalSpacing ? 1.0 : 0.5));
1850
Gui::Command::commitCommand();
1852
catch (const Base::Exception& e) {
1853
Gui::NotifyUserError(
1854
sketchgui, QT_TRANSLATE_NOOP("Notifications", "Error"), e.what());
1855
Gui::Command::abortCommand();
1858
// add auto constraints for the destination copy
1859
if (!sugConstr1.empty()) {
1860
createAutoConstraints(sugConstr1, OriginGeoId + nElements, OriginPos);
1863
tryAutoRecomputeIfNotSolve(
1864
static_cast<Sketcher::SketchObject*>(sketchgui->getObject()));
1867
drawEdit(EditCurve);
1869
// no code after this line, Handler is deleted in ViewProvider
1870
sketchgui->purgeHandler();
1876
void activated() override
1878
setCursor(QPixmap(cursor_createrectangulararray), 7, 7);
1879
Origin = static_cast<Sketcher::SketchObject*>(sketchgui->getObject())
1880
->getPoint(OriginGeoId, OriginPos);
1881
EditCurve[0] = Base::Vector2d(Origin.x, Origin.y);
1888
Base::Vector3d Origin;
1890
Sketcher::PointPos OriginPos;
1895
bool ConstraintSeparation;
1896
bool EqualVerticalHorizontalSpacing;
1897
std::vector<Base::Vector2d> EditCurve;
1898
std::vector<AutoConstraint> sugConstr1;
1901
DEF_STD_CMD_A(CmdSketcherRectangularArray)
1903
CmdSketcherRectangularArray::CmdSketcherRectangularArray()
1904
: Command("Sketcher_RectangularArray")
1906
sAppModule = "Sketcher";
1907
sGroup = "Sketcher";
1908
sMenuText = QT_TR_NOOP("Rectangular array");
1909
sToolTipText = QT_TR_NOOP("Creates a rectangular array pattern of the geometry taking as "
1910
"reference the last selected point");
1911
sWhatsThis = "Sketcher_RectangularArray";
1912
sStatusTip = sToolTipText;
1913
sPixmap = "Sketcher_RectangularArray";
1918
void CmdSketcherRectangularArray::activated(int iMsg)
1921
// get the selection
1922
std::vector<Gui::SelectionObject> selection;
1923
selection = getSelection().getSelectionEx(nullptr, Sketcher::SketchObject::getClassTypeId());
1925
// only one sketch with its subelements are allowed to be selected
1926
if (selection.size() != 1) {
1927
Gui::TranslatedUserWarning(getActiveGuiDocument()->getDocument(),
1928
QObject::tr("Wrong selection"),
1929
QObject::tr("Select elements from a single sketch."));
1934
// get the needed lists and objects
1935
const std::vector<std::string>& SubNames = selection[0].getSubNames();
1936
if (SubNames.empty()) {
1937
Gui::TranslatedUserWarning(getActiveGuiDocument()->getDocument(),
1938
QObject::tr("Wrong selection"),
1939
QObject::tr("Select elements from a single sketch."));
1943
Sketcher::SketchObject* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject());
1945
getSelection().clearSelection();
1948
Sketcher::PointPos LastPointPos = Sketcher::PointPos::none;
1949
const Part::Geometry* LastGeo = nullptr;
1951
// create python command with list of elements
1952
std::stringstream stream;
1955
for (std::vector<std::string>::const_iterator it = SubNames.begin(); it != SubNames.end();
1957
// only handle non-external edges
1958
if (it->size() > 4 && it->substr(0, 4) == "Edge") {
1959
LastGeoId = std::atoi(it->substr(4, 4000).c_str()) - 1;
1960
LastPointPos = Sketcher::PointPos::none;
1961
LastGeo = Obj->getGeometry(LastGeoId);
1964
if (LastGeoId >= 0) {
1966
stream << LastGeoId << ",";
1969
else if (it->size() > 6 && it->substr(0, 6) == "Vertex") {
1970
// only if it is a GeomPoint
1971
int VtId = std::atoi(it->substr(6, 4000).c_str()) - 1;
1973
Sketcher::PointPos PosId;
1974
Obj->getGeoVertexIndex(VtId, GeoId, PosId);
1975
if (Obj->getGeometry(GeoId)->is<Part::GeomPoint>()) {
1977
LastPointPos = Sketcher::PointPos::start;
1979
if (LastGeoId >= 0) {
1981
stream << LastGeoId << ",";
1987
// check if last selected element is a Vertex, not being a GeomPoint
1988
if (SubNames.rbegin()->size() > 6 && SubNames.rbegin()->substr(0, 6) == "Vertex") {
1989
int VtId = std::atoi(SubNames.rbegin()->substr(6, 4000).c_str()) - 1;
1991
Sketcher::PointPos PosId;
1992
Obj->getGeoVertexIndex(VtId, GeoId, PosId);
1993
if (!Obj->getGeometry(GeoId)->is<Part::GeomPoint>()) {
1995
LastPointPos = PosId;
2000
Gui::TranslatedUserWarning(
2002
QObject::tr("Wrong selection"),
2003
QObject::tr("A copy requires at least one selected non-external geometric element"));
2008
std::string geoIdList = stream.str();
2010
// remove the last added comma and brackets to make the python list
2011
int index = geoIdList.rfind(',');
2012
geoIdList.resize(index);
2013
geoIdList.insert(0, 1, '[');
2014
geoIdList.append(1, ']');
2016
// if the last element is not a point serving as a reference for the copy process
2017
// then make the start point of the last element the copy reference (if it exists, if not the
2019
if (LastPointPos == Sketcher::PointPos::none) {
2020
if (LastGeo->is<Part::GeomCircle>()
2021
|| LastGeo->is<Part::GeomEllipse>()) {
2022
LastPointPos = Sketcher::PointPos::mid;
2025
LastPointPos = Sketcher::PointPos::start;
2029
// Pop-up asking for values
2030
SketchRectangularArrayDialog slad;
2032
if (slad.exec() == QDialog::Accepted) {
2033
ActivateHandler(getActiveGuiDocument(),
2034
std::make_unique<DrawSketchHandlerRectangularArray>(geoIdList,
2041
slad.ConstraintSeparation,
2042
slad.EqualVerticalHorizontalSpacing));
2046
bool CmdSketcherRectangularArray::isActive()
2048
return isCommandActive(getActiveGuiDocument(), true);
2051
// ================================================================================
2053
DEF_STD_CMD_A(CmdSketcherDeleteAllGeometry)
2055
CmdSketcherDeleteAllGeometry::CmdSketcherDeleteAllGeometry()
2056
: Command("Sketcher_DeleteAllGeometry")
2058
sAppModule = "Sketcher";
2059
sGroup = "Sketcher";
2060
sMenuText = QT_TR_NOOP("Delete all geometry");
2061
sToolTipText = QT_TR_NOOP("Delete all geometry and constraints in the current sketch, "
2062
"with the exception of external geometry");
2063
sWhatsThis = "Sketcher_DeleteAllGeometry";
2064
sStatusTip = sToolTipText;
2065
sPixmap = "Sketcher_DeleteGeometry";
2070
void CmdSketcherDeleteAllGeometry::activated(int iMsg)
2074
int ret = QMessageBox::question(
2075
Gui::getMainWindow(),
2076
QObject::tr("Delete All Geometry"),
2077
QObject::tr("Are you really sure you want to delete all geometry and constraints?"),
2079
QMessageBox::Cancel);
2080
// use an equality constraint
2081
if (ret == QMessageBox::Yes) {
2082
getSelection().clearSelection();
2083
Sketcher::SketchObject* Obj = getSketchObject();
2086
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Delete all geometry"));
2087
Gui::cmdAppObjectArgs(Obj, "deleteAllGeometry()");
2088
Gui::Command::commitCommand();
2090
catch (const Base::Exception& e) {
2091
Gui::NotifyUserError(
2092
Obj, QT_TRANSLATE_NOOP("Notifications", "Failed to delete all geometry"), e.what());
2093
Gui::Command::abortCommand();
2096
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
2097
"User parameter:BaseApp/Preferences/Mod/Sketcher");
2098
bool autoRecompute = hGrp->GetBool("AutoRecompute", false);
2101
Gui::Command::updateActive();
2105
else if (ret == QMessageBox::Cancel) {
2111
bool CmdSketcherDeleteAllGeometry::isActive()
2113
return isCommandActive(getActiveGuiDocument(), false);
2116
// ================================================================================
2118
DEF_STD_CMD_A(CmdSketcherDeleteAllConstraints)
2120
CmdSketcherDeleteAllConstraints::CmdSketcherDeleteAllConstraints()
2121
: Command("Sketcher_DeleteAllConstraints")
2123
sAppModule = "Sketcher";
2124
sGroup = "Sketcher";
2125
sMenuText = QT_TR_NOOP("Delete all constraints");
2126
sToolTipText = QT_TR_NOOP("Delete all constraints in the sketch");
2127
sWhatsThis = "Sketcher_DeleteAllConstraints";
2128
sStatusTip = sToolTipText;
2129
sPixmap = "Sketcher_DeleteConstraints";
2134
void CmdSketcherDeleteAllConstraints::activated(int iMsg)
2138
int ret = QMessageBox::question(
2139
Gui::getMainWindow(),
2140
QObject::tr("Delete All Constraints"),
2141
QObject::tr("Are you really sure you want to delete all the constraints?"),
2143
QMessageBox::Cancel);
2145
if (ret == QMessageBox::Yes) {
2146
getSelection().clearSelection();
2147
Sketcher::SketchObject* Obj = getSketchObject();
2150
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Delete All Constraints"));
2151
Gui::cmdAppObjectArgs(Obj, "deleteAllConstraints()");
2152
Gui::Command::commitCommand();
2154
catch (const Base::Exception& e) {
2155
Gui::NotifyUserError(
2157
QT_TRANSLATE_NOOP("Notifications", "Failed to delete all constraints"),
2159
Gui::Command::abortCommand();
2162
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
2163
"User parameter:BaseApp/Preferences/Mod/Sketcher");
2164
bool autoRecompute = hGrp->GetBool("AutoRecompute", false);
2167
Gui::Command::updateActive();
2171
else if (ret == QMessageBox::Cancel) {
2177
bool CmdSketcherDeleteAllConstraints::isActive()
2179
return isCommandActive(getActiveGuiDocument(), false);
2182
// ================================================================================
2185
DEF_STD_CMD_A(CmdSketcherRemoveAxesAlignment)
2187
CmdSketcherRemoveAxesAlignment::CmdSketcherRemoveAxesAlignment()
2188
: Command("Sketcher_RemoveAxesAlignment")
2190
sAppModule = "Sketcher";
2191
sGroup = "Sketcher";
2192
sMenuText = QT_TR_NOOP("Remove axes alignment");
2193
sToolTipText = QT_TR_NOOP("Modifies constraints to remove axes alignment while trying to "
2194
"preserve the constraint relationship of the selection");
2195
sWhatsThis = "Sketcher_RemoveAxesAlignment";
2196
sStatusTip = sToolTipText;
2197
sPixmap = "Sketcher_RemoveAxesAlignment";
2202
void CmdSketcherRemoveAxesAlignment::activated(int iMsg)
2205
// get the selection
2206
std::vector<Gui::SelectionObject> selection;
2207
selection = getSelection().getSelectionEx(nullptr, Sketcher::SketchObject::getClassTypeId());
2209
// only one sketch with its subelements are allowed to be selected
2210
if (selection.size() != 1) {
2211
Gui::TranslatedUserWarning(getActiveGuiDocument()->getDocument(),
2212
QObject::tr("Wrong selection"),
2213
QObject::tr("Select elements from a single sketch."));
2218
// get the needed lists and objects
2219
const std::vector<std::string>& SubNames = selection[0].getSubNames();
2220
if (SubNames.empty()) {
2221
Gui::TranslatedUserWarning(getActiveGuiDocument()->getDocument(),
2222
QObject::tr("Wrong selection"),
2223
QObject::tr("Select elements from a single sketch."));
2227
Sketcher::SketchObject* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject());
2229
getSelection().clearSelection();
2233
// create python command with list of elements
2234
std::stringstream stream;
2237
for (std::vector<std::string>::const_iterator it = SubNames.begin(); it != SubNames.end();
2239
// only handle non-external edges
2240
if (it->size() > 4 && it->substr(0, 4) == "Edge") {
2241
LastGeoId = std::atoi(it->substr(4, 4000).c_str()) - 1;
2244
if (LastGeoId >= 0) {
2246
stream << LastGeoId << ",";
2249
else if (it->size() > 6 && it->substr(0, 6) == "Vertex") {
2250
// only if it is a GeomPoint
2251
int VtId = std::atoi(it->substr(6, 4000).c_str()) - 1;
2253
Sketcher::PointPos PosId;
2254
Obj->getGeoVertexIndex(VtId, GeoId, PosId);
2255
if (Obj->getGeometry(GeoId)->is<Part::GeomPoint>()) {
2258
if (LastGeoId >= 0) {
2260
stream << LastGeoId << ",";
2267
Gui::TranslatedUserWarning(
2269
QObject::tr("Wrong selection"),
2270
QObject::tr("Removal of axes alignment requires at least one selected "
2271
"non-external geometric element"));
2276
std::string geoIdList = stream.str();
2278
// remove the last added comma and brackets to make the python list
2279
int index = geoIdList.rfind(',');
2280
geoIdList.resize(index);
2281
geoIdList.insert(0, 1, '[');
2282
geoIdList.append(1, ']');
2284
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Remove Axes Alignment"));
2287
Gui::cmdAppObjectArgs(Obj, "removeAxesAlignment(%s)", geoIdList.c_str());
2288
Gui::Command::commitCommand();
2290
catch (const Base::Exception& e) {
2291
Gui::NotifyUserError(Obj, QT_TRANSLATE_NOOP("Notifications", "Error"), e.what());
2292
Gui::Command::abortCommand();
2295
tryAutoRecomputeIfNotSolve(static_cast<Sketcher::SketchObject*>(Obj));
2298
bool CmdSketcherRemoveAxesAlignment::isActive()
2300
return isCommandActive(getActiveGuiDocument(), true);
2304
// Offset tool =====================================================================
2305
DEF_STD_CMD_A(CmdSketcherOffset)
2307
CmdSketcherOffset::CmdSketcherOffset()
2308
: Command("Sketcher_Offset")
2310
sAppModule = "Sketcher";
2311
sGroup = "Sketcher";
2312
sMenuText = QT_TR_NOOP("Offset geometry");
2313
sToolTipText = QT_TR_NOOP("Offset selected geometries. A positive offset length makes the offset go outward, a negative length inward.");
2314
sWhatsThis = "Sketcher_Offset";
2315
sStatusTip = sToolTipText;
2316
sPixmap = "Sketcher_Offset";
2321
void CmdSketcherOffset::activated(int iMsg)
2324
std::vector<int> listOfGeoIds = {};
2326
// get the selection
2327
std::vector<Gui::SelectionObject> selection;
2328
selection = getSelection().getSelectionEx(0, Sketcher::SketchObject::getClassTypeId());
2330
// only one sketch with its subelements are allowed to be selected
2331
if (selection.size() != 1) {
2332
Gui::TranslatedUserWarning(
2333
getActiveGuiDocument(),
2334
QObject::tr("Wrong selection"),
2335
QObject::tr("Select elements from a single sketch."));
2339
// get the needed lists and objects
2340
auto* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject());
2341
const std::vector<std::string>& subNames = selection[0].getSubNames();
2342
if (!subNames.empty()) {
2343
for (auto& name : subNames) {
2344
// only handle non-external edges
2345
if (name.size() > 4 && name.substr(0, 4) == "Edge") {
2346
int geoId = std::atoi(name.substr(4, 4000).c_str()) - 1;
2348
const Part::Geometry* geo = Obj->getGeometry(geoId);
2350
&& !isBSplineCurve(*geo)
2352
&& !isArcOfEllipse(*geo)
2353
&& !isArcOfHyperbola(*geo)
2354
&& !isArcOfParabola(*geo)
2355
&& !GeometryFacade::isInternalAligned(geo)) {
2356
// Currently ellipse/parabola/hyperbola/bspline are not handled correctly.
2357
// Occ engine gives offset of those as set of lines and arcs and does not seem to work consistently.
2358
listOfGeoIds.push_back(geoId);
2365
if (listOfGeoIds.size() != 0) {
2366
ActivateHandler(getActiveGuiDocument(), std::make_unique<DrawSketchHandlerOffset>(listOfGeoIds));
2369
getSelection().clearSelection();
2370
Gui::NotifyUserError(Obj,
2371
QT_TRANSLATE_NOOP("Notifications", "Invalid selection"),
2372
QT_TRANSLATE_NOOP("Notifications", "Selection has no valid geometries. B-splines and points are not supported yet."));
2376
bool CmdSketcherOffset::isActive()
2378
return isCommandActive(getActiveGuiDocument(), true);
2381
// Rotate tool =====================================================================
2383
DEF_STD_CMD_A(CmdSketcherRotate)
2385
CmdSketcherRotate::CmdSketcherRotate()
2386
: Command("Sketcher_Rotate")
2388
sAppModule = "Sketcher";
2389
sGroup = "Sketcher";
2390
sMenuText = QT_TR_NOOP("Rotate / Polar transform");
2391
sToolTipText = QT_TR_NOOP("Rotate selected geometries, making n copies, enable creation of circular patterns.");
2392
sWhatsThis = "Sketcher_Rotate";
2393
sStatusTip = sToolTipText;
2394
sPixmap = "Sketcher_Rotate";
2399
void CmdSketcherRotate::activated(int iMsg)
2402
std::vector<int> listOfGeoIds = getListOfSelectedGeoIds(true);
2404
if (!listOfGeoIds.empty()) {
2405
ActivateHandler(getActiveGuiDocument(), std::make_unique<DrawSketchHandlerRotate>(listOfGeoIds));
2407
getSelection().clearSelection();
2410
bool CmdSketcherRotate::isActive()
2412
return isCommandActive(getActiveGuiDocument(), true);
2415
// Scale tool =====================================================================
2417
DEF_STD_CMD_A(CmdSketcherScale)
2419
CmdSketcherScale::CmdSketcherScale()
2420
: Command("Sketcher_Scale")
2422
sAppModule = "Sketcher";
2423
sGroup = "Sketcher";
2424
sMenuText = QT_TR_NOOP("Scale transform");
2425
sToolTipText = QT_TR_NOOP("Scale selected geometries. After selecting the center point you can either enter the scale factor, or select two reference points then scale factor = length(p2-center) / length(p1-center).");
2426
sWhatsThis = "Sketcher_Scale";
2427
sStatusTip = sToolTipText;
2428
sPixmap = "Sketcher_Scale";
2433
void CmdSketcherScale::activated(int iMsg)
2436
std::vector<int> listOfGeoIds = getListOfSelectedGeoIds(true);
2438
if (!listOfGeoIds.empty()) {
2439
ActivateHandler(getActiveGuiDocument(), std::make_unique<DrawSketchHandlerScale>(listOfGeoIds));
2441
getSelection().clearSelection();
2444
bool CmdSketcherScale::isActive()
2446
return isCommandActive(getActiveGuiDocument(), true);
2449
// Translate / rectangular pattern tool =======================================================
2451
DEF_STD_CMD_A(CmdSketcherTranslate)
2453
CmdSketcherTranslate::CmdSketcherTranslate()
2454
: Command("Sketcher_Translate")
2456
sAppModule = "Sketcher";
2457
sGroup = "Sketcher";
2458
sMenuText = QT_TR_NOOP("Move / Array transform");
2459
sToolTipText = QT_TR_NOOP("Translate selected geometries. Enable creation of i * j copies.");
2460
sWhatsThis = "Sketcher_Translate";
2461
sStatusTip = sToolTipText;
2462
sPixmap = "Sketcher_Translate";
2467
void CmdSketcherTranslate::activated(int iMsg)
2470
std::vector<int> listOfGeoIds = getListOfSelectedGeoIds(true);
2472
if (!listOfGeoIds.empty()) {
2473
ActivateHandler(getActiveGuiDocument(), std::make_unique<DrawSketchHandlerTranslate>(listOfGeoIds));
2475
getSelection().clearSelection();
2478
bool CmdSketcherTranslate::isActive()
2480
return isCommandActive(getActiveGuiDocument(), true);
2483
void CreateSketcherCommandsConstraintAccel()
2485
Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager();
2487
rcCmdMgr.addCommand(new CmdSketcherSelectConstraints());
2488
rcCmdMgr.addCommand(new CmdSketcherSelectOrigin());
2489
rcCmdMgr.addCommand(new CmdSketcherSelectVerticalAxis());
2490
rcCmdMgr.addCommand(new CmdSketcherSelectHorizontalAxis());
2491
rcCmdMgr.addCommand(new CmdSketcherSelectRedundantConstraints());
2492
rcCmdMgr.addCommand(new CmdSketcherSelectConflictingConstraints());
2493
rcCmdMgr.addCommand(new CmdSketcherSelectMalformedConstraints());
2494
rcCmdMgr.addCommand(new CmdSketcherSelectPartiallyRedundantConstraints());
2495
rcCmdMgr.addCommand(new CmdSketcherSelectElementsAssociatedWithConstraints());
2496
rcCmdMgr.addCommand(new CmdSketcherSelectElementsWithDoFs());
2497
rcCmdMgr.addCommand(new CmdSketcherRestoreInternalAlignmentGeometry());
2498
rcCmdMgr.addCommand(new CmdSketcherTranslate());
2499
rcCmdMgr.addCommand(new CmdSketcherOffset());
2500
rcCmdMgr.addCommand(new CmdSketcherRotate());
2501
rcCmdMgr.addCommand(new CmdSketcherScale());
2502
rcCmdMgr.addCommand(new CmdSketcherSymmetry());
2503
rcCmdMgr.addCommand(new CmdSketcherCopy());
2504
rcCmdMgr.addCommand(new CmdSketcherClone());
2505
rcCmdMgr.addCommand(new CmdSketcherMove());
2506
rcCmdMgr.addCommand(new CmdSketcherCompCopy());
2507
rcCmdMgr.addCommand(new CmdSketcherRectangularArray());
2508
rcCmdMgr.addCommand(new CmdSketcherDeleteAllGeometry());
2509
rcCmdMgr.addCommand(new CmdSketcherDeleteAllConstraints());
2510
rcCmdMgr.addCommand(new CmdSketcherRemoveAxesAlignment());
2511
rcCmdMgr.addCommand(new CmdSketcherCopyClipboard());
2512
rcCmdMgr.addCommand(new CmdSketcherCut());
2513
rcCmdMgr.addCommand(new CmdSketcherPaste());