Sketcher: New Feature: Symmetric tool
===================================== Creates geometry symmetric to the selected one with respect to the last selected point or line. It does not support the following constraints: - Angle - Horiz/vertical distance - SnellLaw Horizontal and Vertical (directional) dimensions removed from the the copying process when created on a single edge (by picking one edge instead of two points), i.e. Constraint involving only one GeoId at "First".
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
# include <Precision.hxx>
|
||||
#endif
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include <App/Application.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/Document.h>
|
||||
@@ -971,6 +972,203 @@ bool CmdSketcherRestoreInternalAlignmentGeometry::isActive(void)
|
||||
return isSketcherAcceleratorActive( getActiveGuiDocument(), true );
|
||||
}
|
||||
|
||||
DEF_STD_CMD_A(CmdSketcherSymmetry);
|
||||
|
||||
CmdSketcherSymmetry::CmdSketcherSymmetry()
|
||||
:Command("Sketcher_Symmetry")
|
||||
{
|
||||
sAppModule = "Sketcher";
|
||||
sGroup = QT_TR_NOOP("Sketcher");
|
||||
sMenuText = QT_TR_NOOP("Symmetry");
|
||||
sToolTipText = QT_TR_NOOP("Creates symmetric geometry with respect to the last selected line or point");
|
||||
sWhatsThis = sToolTipText;
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Sketcher_Symmetry";
|
||||
sAccel = "";
|
||||
eType = ForEdit;
|
||||
}
|
||||
|
||||
void CmdSketcherSymmetry::activated(int iMsg)
|
||||
{
|
||||
// get the selection
|
||||
std::vector<Gui::SelectionObject> selection = getSelection().getSelectionEx();
|
||||
Sketcher::SketchObject* Obj = dynamic_cast<Sketcher::SketchObject*>(selection[0].getObject());
|
||||
|
||||
// only one sketch with its subelements are allowed to be selected
|
||||
if (selection.size() != 1) {
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
|
||||
QObject::tr("Select elements from a single sketch."));
|
||||
return;
|
||||
}
|
||||
|
||||
// get the needed lists and objects
|
||||
const std::vector<std::string> &SubNames = selection[0].getSubNames();
|
||||
const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues();
|
||||
|
||||
std::string doc_name = Obj->getDocument()->getName();
|
||||
std::string obj_name = Obj->getNameInDocument();
|
||||
std::stringstream ss;
|
||||
|
||||
getSelection().clearSelection();
|
||||
|
||||
int nelements = SubNames.size();
|
||||
|
||||
int LastGeoId;
|
||||
Sketcher::PointPos LastPointPos = Sketcher::none;
|
||||
const Part::Geometry *LastGeo;
|
||||
typedef enum { invalid = -1, line = 0, point = 1 } GeoType;
|
||||
|
||||
GeoType lastgeotype = invalid;
|
||||
|
||||
// create python command with list of elements
|
||||
std::stringstream stream;
|
||||
int geoids = 0;
|
||||
|
||||
for (std::vector<std::string>::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) {
|
||||
// only handle non-external edges
|
||||
if ((it->size() > 4 && it->substr(0,4) == "Edge") ||
|
||||
(it->size() > 12 && it->substr(0,12) == "ExternalEdge")) {
|
||||
|
||||
if(it->substr(0,4) == "Edge") {
|
||||
LastGeoId = std::atoi(it->substr(4,4000).c_str()) - 1;
|
||||
LastPointPos = Sketcher::none;
|
||||
}
|
||||
else {
|
||||
LastGeoId = -std::atoi(it->substr(12,4000).c_str()) - 2;
|
||||
LastPointPos = Sketcher::none;
|
||||
}
|
||||
|
||||
// reference can be external or non-external
|
||||
LastGeo = Obj->getGeometry(LastGeoId);
|
||||
// Only for supported types
|
||||
if(LastGeo->getTypeId() == Part::GeomLineSegment::getClassTypeId())
|
||||
lastgeotype = line;
|
||||
else
|
||||
lastgeotype = invalid;
|
||||
|
||||
// lines to make symmetric (only non-external)
|
||||
if(LastGeoId>=0) {
|
||||
geoids++;
|
||||
stream << LastGeoId << ",";
|
||||
}
|
||||
}
|
||||
else if(it->size() > 6 && it->substr(0,6) == "Vertex"){
|
||||
// only if it is a GeomPoint
|
||||
int VtId = std::atoi(it->substr(6,4000).c_str()) - 1;
|
||||
int GeoId;
|
||||
Sketcher::PointPos PosId;
|
||||
Obj->getGeoVertexIndex(VtId, GeoId, PosId);
|
||||
if (Obj->getGeometry(GeoId)->getTypeId() == Part::GeomPoint::getClassTypeId()) {
|
||||
LastGeoId = GeoId;
|
||||
LastPointPos = Sketcher::start;
|
||||
lastgeotype = point;
|
||||
|
||||
// points to make symmetric
|
||||
if(LastGeoId>=0) {
|
||||
geoids++;
|
||||
stream << LastGeoId << ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool lastvertexoraxis=false;
|
||||
// check if last selected element is a Vertex, not being a GeomPoint
|
||||
if(SubNames.rbegin()->size() > 6 && SubNames.rbegin()->substr(0,6) == "Vertex"){
|
||||
int VtId = std::atoi(SubNames.rbegin()->substr(6,4000).c_str()) - 1;
|
||||
int GeoId;
|
||||
Sketcher::PointPos PosId;
|
||||
Obj->getGeoVertexIndex(VtId, GeoId, PosId);
|
||||
if (Obj->getGeometry(GeoId)->getTypeId() != Part::GeomPoint::getClassTypeId()) {
|
||||
LastGeoId = GeoId;
|
||||
LastPointPos = PosId;
|
||||
lastgeotype = point;
|
||||
lastvertexoraxis=true;
|
||||
}
|
||||
}
|
||||
// check if last selected element is horizontal axis
|
||||
else if(SubNames.rbegin()->size() == 6 && SubNames.rbegin()->substr(0,6) == "H_Axis"){
|
||||
LastGeoId = -1;
|
||||
LastPointPos = Sketcher::none;
|
||||
lastgeotype = line;
|
||||
lastvertexoraxis=true;
|
||||
}
|
||||
// check if last selected element is vertical axis
|
||||
else if(SubNames.rbegin()->size() == 6 && SubNames.rbegin()->substr(0,6) == "V_Axis"){
|
||||
LastGeoId = -2;
|
||||
LastPointPos = Sketcher::none;
|
||||
lastgeotype = line;
|
||||
lastvertexoraxis=true;
|
||||
}
|
||||
// check if last selected element is the root point
|
||||
else if(SubNames.rbegin()->size() == 9 && SubNames.rbegin()->substr(0,9) == "RootPoint"){
|
||||
LastGeoId = -1;
|
||||
LastPointPos = Sketcher::start;
|
||||
lastgeotype = point;
|
||||
lastvertexoraxis=true;
|
||||
}
|
||||
|
||||
if ( geoids < 2 || (geoids<1 && LastGeoId<0) || (geoids<1 && lastvertexoraxis) ) {
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
|
||||
QObject::tr("A symmetric construction requires at least two geometric elements, the last geometric element being the reference for the symmetry construction."));
|
||||
return;
|
||||
}
|
||||
|
||||
if ( lastgeotype == invalid ) {
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
|
||||
QObject::tr("The last element must be a point or a line serving as reference for the symmetry construction."));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string geoIdList = stream.str();
|
||||
|
||||
// missing cases:
|
||||
// 1- Last element is an edge, and is V or H axis
|
||||
// 2- Last element is a point GeomPoint
|
||||
// 3- Last element is a point (Vertex)
|
||||
|
||||
if(LastGeoId>=0 && !lastvertexoraxis) {
|
||||
// if LastGeoId was added remove the last element
|
||||
int index = geoIdList.rfind(',');
|
||||
index = geoIdList.rfind(',',index-1);
|
||||
geoIdList.resize(index);
|
||||
}
|
||||
else {
|
||||
int index = geoIdList.rfind(',');
|
||||
geoIdList.resize(index);
|
||||
}
|
||||
|
||||
geoIdList.insert(0,1,'[');
|
||||
geoIdList.append(1,']');
|
||||
|
||||
Gui::Command::openCommand("Create Symmetric geometry");
|
||||
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher");
|
||||
bool autoRecompute = hGrp->GetBool("AutoRecompute",false);
|
||||
|
||||
try{
|
||||
Gui::Command::doCommand(
|
||||
Gui::Command::Doc, "App.ActiveDocument.%s.addSymmetric(%s,%d,%d)",
|
||||
Obj->getNameInDocument(), geoIdList.c_str(), LastGeoId, LastPointPos
|
||||
);
|
||||
|
||||
Gui::Command::commitCommand();
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
Base::Console().Error("%s\n", e.what());
|
||||
Gui::Command::abortCommand();
|
||||
}
|
||||
|
||||
if(autoRecompute)
|
||||
Gui::Command::updateActive();
|
||||
else
|
||||
Obj->solve();
|
||||
}
|
||||
|
||||
bool CmdSketcherSymmetry::isActive(void)
|
||||
{
|
||||
return isSketcherAcceleratorActive( getActiveGuiDocument(), true );
|
||||
}
|
||||
|
||||
void CreateSketcherCommandsConstraintAccel(void)
|
||||
{
|
||||
@@ -986,4 +1184,5 @@ void CreateSketcherCommandsConstraintAccel(void)
|
||||
rcCmdMgr.addCommand(new CmdSketcherSelectConflictingConstraints());
|
||||
rcCmdMgr.addCommand(new CmdSketcherSelectElementsAssociatedWithConstraints());
|
||||
rcCmdMgr.addCommand(new CmdSketcherRestoreInternalAlignmentGeometry());
|
||||
rcCmdMgr.addCommand(new CmdSketcherSymmetry());
|
||||
}
|
||||
|
||||
@@ -245,14 +245,16 @@ inline void SketcherAddWorkbenchTools<Gui::MenuItem>(Gui::MenuItem& consaccel){
|
||||
<< "Sketcher_SelectRedundantConstraints"
|
||||
<< "Sketcher_SelectConflictingConstraints"
|
||||
<< "Sketcher_SelectElementsAssociatedWithConstraints"
|
||||
<< "Sketcher_RestoreInternalAlignmentGeometry";
|
||||
<< "Sketcher_RestoreInternalAlignmentGeometry"
|
||||
<< "Sketcher_Symmetry";
|
||||
}
|
||||
template <>
|
||||
inline void SketcherAddWorkbenchTools<Gui::ToolBarItem>(Gui::ToolBarItem& consaccel){
|
||||
consaccel << "Sketcher_CloseShape"
|
||||
<< "Sketcher_ConnectLines"
|
||||
<< "Sketcher_SelectConstraints"
|
||||
<< "Sketcher_RestoreInternalAlignmentGeometry";
|
||||
<< "Sketcher_RestoreInternalAlignmentGeometry"
|
||||
<< "Sketcher_Symmetry";
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
Reference in New Issue
Block a user