/*************************************************************************** * Copyright (c) 2014 Abdullah Tahiri # include # include # include #endif # include #include #include #include #include #include #include #include #include #include #include #include "ViewProviderSketch.h" #include "DrawSketchHandler.h" #include #include #include "ViewProviderSketch.h" #include "SketchRectangularArrayDialog.h" using namespace std; using namespace SketcherGui; using namespace Sketcher; bool isSketcherAcceleratorActive(Gui::Document *doc, bool actsOnSelection ) { if (doc) { // checks if a Sketch Viewprovider is in Edit and is in no special mode if (doc->getInEdit() && doc->getInEdit()->isDerivedFrom(SketcherGui::ViewProviderSketch::getClassTypeId())) { if (static_cast(doc->getInEdit()) ->getSketchMode() == ViewProviderSketch::STATUS_NONE) { if (!actsOnSelection) return true; else if (Gui::Selection().countObjectsOfType(Sketcher::SketchObject::getClassTypeId()) > 0) return true; } } } return false; } void ActivateAcceleratorHandler(Gui::Document *doc,DrawSketchHandler *handler) { if (doc) { if (doc->getInEdit() && doc->getInEdit()->isDerivedFrom (SketcherGui::ViewProviderSketch::getClassTypeId())) { SketcherGui::ViewProviderSketch* vp = static_cast (doc->getInEdit()); vp->purgeHandler(); vp->activateHandler(handler); } } } // Close Shape Command DEF_STD_CMD_A(CmdSketcherCloseShape); CmdSketcherCloseShape::CmdSketcherCloseShape() :Command("Sketcher_CloseShape") { sAppModule = "Sketcher"; sGroup = QT_TR_NOOP("Sketcher"); sMenuText = QT_TR_NOOP("Close Shape"); sToolTipText = QT_TR_NOOP("Produce closed shape by Link end point of element with next elements' starting point"); sWhatsThis = "Sketcher_CloseShape"; sStatusTip = sToolTipText; sPixmap = "Sketcher_CloseShape"; sAccel = "CTRL+SHIFT+S"; eType = ForEdit; } void CmdSketcherCloseShape::activated(int iMsg) { Q_UNUSED(iMsg); // get the selection std::vector selection = getSelection().getSelectionEx(); // 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 at least two edges from the sketch.")); return; } // get the needed lists and objects const std::vector &SubNames = selection[0].getSubNames(); if (SubNames.size() < 2) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select at least two edges from the sketch.")); return; } Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); int GeoIdFirst=-1; int GeoIdLast=-1; // undo command open openCommand("add coincident constraint"); // go through the selected subelements for (unsigned int i=0; i<(SubNames.size()-1); i++ ) { // only handle edges if (SubNames[i].size() > 4 && SubNames[i].substr(0,4) == "Edge" && SubNames[i+1].size() > 4 && SubNames[i+1].substr(0,4) == "Edge" ) { int GeoId1 = std::atoi(SubNames[i].substr(4,4000).c_str()) - 1; int GeoId2 = std::atoi(SubNames[i+1].substr(4,4000).c_str()) - 1; if(GeoIdFirst==-1) GeoIdFirst=GeoId1; GeoIdLast=GeoId2; const Part::Geometry *geo1 = Obj->getGeometry(GeoId1); const Part::Geometry *geo2 = Obj->getGeometry(GeoId2); if ((geo1->getTypeId() != Part::GeomLineSegment::getClassTypeId() && geo1->getTypeId() != Part::GeomArcOfCircle::getClassTypeId() ) || (geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId() && geo2->getTypeId() != Part::GeomArcOfCircle::getClassTypeId()) ) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Impossible constraint"), QObject::tr("One selected edge is not connectable")); abortCommand(); return; } // Check for the special case of closing a shape with two lines to avoid overlap if (SubNames.size() == 2 && geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId() && geo2->getTypeId() == Part::GeomLineSegment::getClassTypeId() ) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Closing a shape formed by exactly two lines makes no sense.")); abortCommand(); return; } Gui::Command::doCommand( Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Coincident',%d,%d,%d,%d)) ", selection[0].getFeatName(),GeoId1,Sketcher::end,GeoId2,Sketcher::start); } } // Close Last Edge with First Edge Gui::Command::doCommand( Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Coincident',%d,%d,%d,%d)) ", selection[0].getFeatName(),GeoIdLast,Sketcher::end,GeoIdFirst,Sketcher::start); // finish the transaction and update commitCommand(); ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); bool autoRecompute = hGrp->GetBool("AutoRecompute",false); if(autoRecompute) Gui::Command::updateActive(); // clear the selection (convenience) getSelection().clearSelection(); } bool CmdSketcherCloseShape::isActive(void) { return isSketcherAcceleratorActive( getActiveGuiDocument(), true ); } // Connect Edges Command DEF_STD_CMD_A(CmdSketcherConnect); CmdSketcherConnect::CmdSketcherConnect() :Command("Sketcher_ConnectLines") { sAppModule = "Sketcher"; sGroup = QT_TR_NOOP("Sketcher"); sMenuText = QT_TR_NOOP("Connect Edges"); sToolTipText = QT_TR_NOOP("Link end point of element with next elements' starting point"); sWhatsThis = "Sketcher_ConnectLines"; sStatusTip = sToolTipText; sPixmap = "Sketcher_ConnectLines"; sAccel = "CTRL+SHIFT+K"; eType = ForEdit; } void CmdSketcherConnect::activated(int iMsg) { Q_UNUSED(iMsg); // get the selection std::vector selection = getSelection().getSelectionEx(); // 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 at least two edges from the sketch.")); return; } // get the needed lists and objects const std::vector &SubNames = selection[0].getSubNames(); if (SubNames.size() < 2) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select at least two edges from the sketch.")); return; } Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); // undo command open openCommand("add coincident constraint"); // go through the selected subelements for (unsigned int i=0; i<(SubNames.size()-1); i++ ) { // only handle edges if (SubNames[i].size() > 4 && SubNames[i].substr(0,4) == "Edge" && SubNames[i+1].size() > 4 && SubNames[i+1].substr(0,4) == "Edge" ) { int GeoId1 = std::atoi(SubNames[i].substr(4,4000).c_str()) - 1; int GeoId2 = std::atoi(SubNames[i+1].substr(4,4000).c_str()) - 1; const Part::Geometry *geo1 = Obj->getGeometry(GeoId1); const Part::Geometry *geo2 = Obj->getGeometry(GeoId2); if ((geo1->getTypeId() != Part::GeomLineSegment::getClassTypeId() && geo1->getTypeId() != Part::GeomArcOfCircle::getClassTypeId()) || (geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId() && geo2->getTypeId() != Part::GeomArcOfCircle::getClassTypeId())) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Impossible constraint"), QObject::tr("One selected edge is not connectable")); abortCommand(); return; } Gui::Command::doCommand( Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Coincident',%d,%d,%d,%d)) ", selection[0].getFeatName(),GeoId1,Sketcher::end,GeoId2,Sketcher::start); } } // finish the transaction and update commitCommand(); ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); bool autoRecompute = hGrp->GetBool("AutoRecompute",false); if(autoRecompute) Gui::Command::updateActive(); // clear the selection (convenience) getSelection().clearSelection(); } bool CmdSketcherConnect::isActive(void) { return isSketcherAcceleratorActive( getActiveGuiDocument(), true ); } // Select Constraints of selected elements DEF_STD_CMD_A(CmdSketcherSelectConstraints); CmdSketcherSelectConstraints::CmdSketcherSelectConstraints() :Command("Sketcher_SelectConstraints") { sAppModule = "Sketcher"; sGroup = QT_TR_NOOP("Sketcher"); sMenuText = QT_TR_NOOP("Select Constraints"); sToolTipText = QT_TR_NOOP("Select the constraints associated to the selected elements"); sWhatsThis = "Sketcher_SelectConstraints"; sStatusTip = sToolTipText; sPixmap = "Sketcher_SelectConstraints"; sAccel = "CTRL+SHIFT+C"; eType = ForEdit; } void CmdSketcherSelectConstraints::activated(int iMsg) { Q_UNUSED(iMsg); // get the selection std::vector selection = getSelection().getSelectionEx(); // 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 &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues(); std::string doc_name = Obj->getDocument()->getName(); std::string obj_name = Obj->getNameInDocument(); getSelection().clearSelection(); // go through the selected subelements for (std::vector::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) { // only handle edges if (it->size() > 4 && it->substr(0,4) == "Edge") { int GeoId = std::atoi(it->substr(4,4000).c_str()) - 1; // push all the constraints int i = 0; for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); it != vals.end(); ++it,++i) { if ( (*it)->First == GeoId || (*it)->Second == GeoId || (*it)->Third == GeoId){ Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), Sketcher::PropertyConstraintList::getConstraintName(i).c_str()); } } } } } bool CmdSketcherSelectConstraints::isActive(void) { return isSketcherAcceleratorActive( getActiveGuiDocument(), true ); } // Select Origin DEF_STD_CMD_A(CmdSketcherSelectOrigin); CmdSketcherSelectOrigin::CmdSketcherSelectOrigin() :Command("Sketcher_SelectOrigin") { sAppModule = "Sketcher"; sGroup = QT_TR_NOOP("Sketcher"); sMenuText = QT_TR_NOOP("Select Origin"); sToolTipText = QT_TR_NOOP("Select the origin point"); sWhatsThis = "Sketcher_SelectOrigin"; sStatusTip = sToolTipText; sPixmap = "Sketcher_SelectOrigin"; sAccel = "CTRL+SHIFT+O"; eType = ForEdit; } void CmdSketcherSelectOrigin::activated(int iMsg) { Q_UNUSED(iMsg); Gui::Document * doc= getActiveGuiDocument(); SketcherGui::ViewProviderSketch* vp = static_cast(doc->getInEdit()); Sketcher::SketchObject* Obj= vp->getSketchObject(); // ViewProviderSketch * vp = static_cast(Gui::Application::Instance->getViewProvider(docobj)); // Sketcher::SketchObject* Obj = vp->getSketchObject(); std::string doc_name = Obj->getDocument()->getName(); std::string obj_name = Obj->getNameInDocument(); std::stringstream ss; ss << "RootPoint"; if(Gui::Selection().isSelected(doc_name.c_str(), obj_name.c_str(), ss.str().c_str())) Gui::Selection().rmvSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); else Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); } bool CmdSketcherSelectOrigin::isActive(void) { return isSketcherAcceleratorActive( getActiveGuiDocument(), false ); } // Select Vertical Axis DEF_STD_CMD_A(CmdSketcherSelectVerticalAxis); CmdSketcherSelectVerticalAxis::CmdSketcherSelectVerticalAxis() :Command("Sketcher_SelectVerticalAxis") { sAppModule = "Sketcher"; sGroup = QT_TR_NOOP("Sketcher"); sMenuText = QT_TR_NOOP("Select Vertical Axis"); sToolTipText = QT_TR_NOOP("Select the vertical axis"); sWhatsThis = "Sketcher_SelectVerticalAxis"; sStatusTip = sToolTipText; sPixmap = "Sketcher_SelectVerticalAxis"; sAccel = "CTRL+SHIFT+V"; eType = ForEdit; } void CmdSketcherSelectVerticalAxis::activated(int iMsg) { Q_UNUSED(iMsg); Gui::Document * doc= getActiveGuiDocument(); SketcherGui::ViewProviderSketch* vp = static_cast(doc->getInEdit()); Sketcher::SketchObject* Obj= vp->getSketchObject(); std::string doc_name = Obj->getDocument()->getName(); std::string obj_name = Obj->getNameInDocument(); std::stringstream ss; ss << "V_Axis"; if(Gui::Selection().isSelected(doc_name.c_str(), obj_name.c_str(), ss.str().c_str())) Gui::Selection().rmvSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); else Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); } bool CmdSketcherSelectVerticalAxis::isActive(void) { return isSketcherAcceleratorActive( getActiveGuiDocument(), false ); } // Select Horizontal Axis DEF_STD_CMD_A(CmdSketcherSelectHorizontalAxis); CmdSketcherSelectHorizontalAxis::CmdSketcherSelectHorizontalAxis() :Command("Sketcher_SelectHorizontalAxis") { sAppModule = "Sketcher"; sGroup = QT_TR_NOOP("Sketcher"); sMenuText = QT_TR_NOOP("Select Horizontal Axis"); sToolTipText = QT_TR_NOOP("Select the horizontal axis"); sWhatsThis = "Sketcher_SelectHorizontalAxis"; sStatusTip = sToolTipText; sPixmap = "Sketcher_SelectHorizontalAxis"; sAccel = "CTRL+SHIFT+H"; eType = ForEdit; } void CmdSketcherSelectHorizontalAxis::activated(int iMsg) { Q_UNUSED(iMsg); Gui::Document * doc= getActiveGuiDocument(); SketcherGui::ViewProviderSketch* vp = static_cast(doc->getInEdit()); Sketcher::SketchObject* Obj= vp->getSketchObject(); std::string doc_name = Obj->getDocument()->getName(); std::string obj_name = Obj->getNameInDocument(); std::stringstream ss; ss << "H_Axis"; if(Gui::Selection().isSelected(doc_name.c_str(), obj_name.c_str(), ss.str().c_str())) Gui::Selection().rmvSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); else Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); } bool CmdSketcherSelectHorizontalAxis::isActive(void) { return isSketcherAcceleratorActive( getActiveGuiDocument(), false ); } DEF_STD_CMD_A(CmdSketcherSelectRedundantConstraints); CmdSketcherSelectRedundantConstraints::CmdSketcherSelectRedundantConstraints() :Command("Sketcher_SelectRedundantConstraints") { sAppModule = "Sketcher"; sGroup = QT_TR_NOOP("Sketcher"); sMenuText = QT_TR_NOOP("Select Redundant Constraints"); sToolTipText = QT_TR_NOOP("Select Redundant Constraints"); sWhatsThis = "Sketcher_SelectRedundantConstraints"; sStatusTip = sToolTipText; sPixmap = "Sketcher_SelectRedundantConstraints"; sAccel = "CTRL+SHIFT+R"; eType = ForEdit; } void CmdSketcherSelectRedundantConstraints::activated(int iMsg) { Q_UNUSED(iMsg); Gui::Document * doc= getActiveGuiDocument(); SketcherGui::ViewProviderSketch* vp = static_cast(doc->getInEdit()); Sketcher::SketchObject* Obj= vp->getSketchObject(); std::string doc_name = Obj->getDocument()->getName(); std::string obj_name = Obj->getNameInDocument(); // get the needed lists and objects const std::vector< int > &solverredundant = vp->getSketchObject()->getLastRedundant(); const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues(); getSelection().clearSelection(); // push the constraints int i = 0; for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it != vals.end(); ++it,++i) { for(std::vector< int >::const_iterator itc= solverredundant.begin();itc != solverredundant.end(); ++itc) { if ( (*itc) - 1 == i){ Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), Sketcher::PropertyConstraintList::getConstraintName(i).c_str()); break; } } } } bool CmdSketcherSelectRedundantConstraints::isActive(void) { return isSketcherAcceleratorActive( getActiveGuiDocument(), false ); } DEF_STD_CMD_A(CmdSketcherSelectConflictingConstraints); CmdSketcherSelectConflictingConstraints::CmdSketcherSelectConflictingConstraints() :Command("Sketcher_SelectConflictingConstraints") { sAppModule = "Sketcher"; sGroup = QT_TR_NOOP("Sketcher"); sMenuText = QT_TR_NOOP("Select Conflicting Constraints"); sToolTipText = QT_TR_NOOP("Select Conflicting Constraints"); sWhatsThis = "Sketcher_SelectConflictingConstraints"; sStatusTip = sToolTipText; sPixmap = "Sketcher_SelectConflictingConstraints"; sAccel = "CTRL+SHIFT+E"; eType = ForEdit; } void CmdSketcherSelectConflictingConstraints::activated(int iMsg) { Q_UNUSED(iMsg); Gui::Document * doc= getActiveGuiDocument(); SketcherGui::ViewProviderSketch* vp = static_cast(doc->getInEdit()); Sketcher::SketchObject* Obj= vp->getSketchObject(); std::string doc_name = Obj->getDocument()->getName(); std::string obj_name = Obj->getNameInDocument(); // get the needed lists and objects const std::vector< int > &solverconflicting = vp->getSketchObject()->getLastConflicting(); const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues(); getSelection().clearSelection(); // push the constraints int i = 0; for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it != vals.end(); ++it,++i) { for(std::vector< int >::const_iterator itc= solverconflicting.begin();itc != solverconflicting.end(); ++itc) { if ( (*itc) - 1 == i){ Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), Sketcher::PropertyConstraintList::getConstraintName(i).c_str()); break; } } } } bool CmdSketcherSelectConflictingConstraints::isActive(void) { return isSketcherAcceleratorActive( getActiveGuiDocument(), false ); } DEF_STD_CMD_A(CmdSketcherSelectElementsAssociatedWithConstraints); CmdSketcherSelectElementsAssociatedWithConstraints::CmdSketcherSelectElementsAssociatedWithConstraints() :Command("Sketcher_SelectElementsAssociatedWithConstraints") { sAppModule = "Sketcher"; sGroup = QT_TR_NOOP("Sketcher"); sMenuText = QT_TR_NOOP("Select Elements associated with constraints"); sToolTipText = QT_TR_NOOP("Select Elements associated with constraints"); sWhatsThis = "Sketcher_SelectElementsAssociatedWithConstraints"; sStatusTip = sToolTipText; sPixmap = "Sketcher_SelectElementsAssociatedWithConstraints"; sAccel = "CTRL+SHIFT+E"; eType = ForEdit; } void CmdSketcherSelectElementsAssociatedWithConstraints::activated(int iMsg) { Q_UNUSED(iMsg); std::vector selection = Gui::Selection().getSelectionEx(); Gui::Document * doc= getActiveGuiDocument(); SketcherGui::ViewProviderSketch* vp = static_cast(doc->getInEdit()); Sketcher::SketchObject* Obj= vp->getSketchObject(); const std::vector &SubNames = selection[0].getSubNames(); const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues(); getSelection().clearSelection(); std::string doc_name = Obj->getDocument()->getName(); std::string obj_name = Obj->getNameInDocument(); std::stringstream ss; int selected=0; // go through the selected subelements for (std::vector::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) { // only handle constraints if (it->size() > 10 && it->substr(0,10) == "Constraint") { int ConstrId = Sketcher::PropertyConstraintList::getIndexFromConstraintName(*it); if(ConstrId < static_cast(vals.size())){ if(vals[ConstrId]->First!=Constraint::GeoUndef){ ss.str(std::string()); switch(vals[ConstrId]->FirstPos) { case Sketcher::none: ss << "Edge" << vals[ConstrId]->First + 1; break; case Sketcher::start: case Sketcher::end: case Sketcher::mid: int vertex = Obj->getVertexIndexGeoPos(vals[ConstrId]->First,vals[ConstrId]->FirstPos); if(vertex>-1) ss << "Vertex" << vertex + 1; break; } Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); selected++; } if(vals[ConstrId]->Second!=Constraint::GeoUndef){ ss.str(std::string()); switch(vals[ConstrId]->SecondPos) { case Sketcher::none: ss << "Edge" << vals[ConstrId]->Second + 1; break; case Sketcher::start: case Sketcher::end: case Sketcher::mid: int vertex = Obj->getVertexIndexGeoPos(vals[ConstrId]->Second,vals[ConstrId]->SecondPos); if(vertex>-1) ss << "Vertex" << vertex + 1; break; } Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); selected++; } if(vals[ConstrId]->Third!=Constraint::GeoUndef){ ss.str(std::string()); switch(vals[ConstrId]->ThirdPos) { case Sketcher::none: ss << "Edge" << vals[ConstrId]->Third + 1; break; case Sketcher::start: case Sketcher::end: case Sketcher::mid: int vertex = Obj->getVertexIndexGeoPos(vals[ConstrId]->Third,vals[ConstrId]->ThirdPos); if(vertex>-1) ss << "Vertex" << vertex + 1; break; } Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); selected++; } } } } if ( selected == 0 ) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No constraint selected"), QObject::tr("At least one constraint must be selected")); } } bool CmdSketcherSelectElementsAssociatedWithConstraints::isActive(void) { return isSketcherAcceleratorActive( getActiveGuiDocument(), true ); } DEF_STD_CMD_A(CmdSketcherRestoreInternalAlignmentGeometry); CmdSketcherRestoreInternalAlignmentGeometry::CmdSketcherRestoreInternalAlignmentGeometry() :Command("Sketcher_RestoreInternalAlignmentGeometry") { sAppModule = "Sketcher"; sGroup = QT_TR_NOOP("Sketcher"); sMenuText = QT_TR_NOOP("Show/hide internal geometry"); sToolTipText = QT_TR_NOOP("Show all internal geometry / hide unused internal geometry"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; sPixmap = "Sketcher_Element_Ellipse_All"; sAccel = "CTRL+SHIFT+E"; eType = ForEdit; } void CmdSketcherRestoreInternalAlignmentGeometry::activated(int iMsg) { Q_UNUSED(iMsg); // get the selection std::vector selection = getSelection().getSelectionEx(); // 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 &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); std::string doc_name = Obj->getDocument()->getName(); std::string obj_name = Obj->getNameInDocument(); std::stringstream ss; getSelection().clearSelection(); // go through the selected subelements for (std::vector::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) { // only handle edges if ( (it->size() > 4 && it->substr(0,4) == "Edge") || (it->size() > 12 && it->substr(0,12) == "ExternalEdge")) { int GeoId; if(it->substr(0,4) == "Edge") GeoId = std::atoi(it->substr(4,4000).c_str()) - 1; else GeoId = -std::atoi(it->substr(12,4000).c_str()) - 2; const Part::Geometry *geo = Obj->getGeometry(GeoId); // Only for supported types if( geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() ) { int currentgeoid = Obj->getHighestCurveIndex(); try { Gui::Command::openCommand("Exposing Internal Geometry"); Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.ExposeInternalGeometry(%d)", Obj->getNameInDocument(), GeoId); int aftergeoid = Obj->getHighestCurveIndex(); if(aftergeoid == currentgeoid) { // if we did not expose anything, deleteunused Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.DeleteUnusedInternalGeometry(%d)", Obj->getNameInDocument(), GeoId); } } catch (const Base::Exception& e) { Base::Console().Error("%s\n", e.what()); Gui::Command::abortCommand(); ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); bool autoRecompute = hGrp->GetBool("AutoRecompute",false); if(autoRecompute) Gui::Command::updateActive(); else static_cast(Obj)->solve(); return; } Gui::Command::commitCommand(); ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); bool autoRecompute = hGrp->GetBool("AutoRecompute",false); if(autoRecompute) Gui::Command::updateActive(); else static_cast(Obj)->solve(); } } } } 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) { Q_UNUSED(iMsg); // get the selection std::vector selection = getSelection().getSelectionEx(); // 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 &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); getSelection().clearSelection(); int LastGeoId = 0; 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::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 = Sketcher::GeoEnum::HAxis; 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 = Sketcher::GeoEnum::VAxis; 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 = Sketcher::GeoEnum::RtPnt; LastPointPos = Sketcher::start; lastgeotype = point; lastvertexoraxis=true; } if ( geoids == 0 || (geoids == 1 && LastGeoId>=0 && !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 ); } static const char *cursor_createcopy[]={ "32 32 3 1", "+ c white", "# c red", ". c None", "................................", "................................", "................................", "................................", "................................", "................................", "................................", "......................###.......", "......................###.......", "......................###.......", "......................###.......", "......................###.......", ".....###..............###.......", ".....###..............###.......", ".....###..............###.......", ".....###..............###.......", ".....###..............###.......", ".....###..............###.......", ".....###..............###.......", ".....###..............###.......", ".....###..............###.......", ".....###........................", ".....###........................", ".....###........................", ".....###........................", "................................", "................................", "................................", "................................", "................................", "................................", "................................"}; class DrawSketchHandlerCopy: public DrawSketchHandler { public: DrawSketchHandlerCopy(string geoidlist, int origingeoid, Sketcher::PointPos originpos, int nelements, bool clone) : Mode(STATUS_SEEK_First) , geoIdList(geoidlist) , Origin() , OriginGeoId(origingeoid) , OriginPos(originpos) , nElements(nelements) , Clone(clone) , EditCurve(2) { } virtual ~DrawSketchHandlerCopy(){} /// mode table enum SelectMode { STATUS_SEEK_First, /**< enum value ----. */ STATUS_End }; virtual void activated(ViewProviderSketch *sketchgui) { setCursor(QPixmap(cursor_createcopy),7,7); Origin = static_cast(sketchgui->getObject())->getPoint(OriginGeoId, OriginPos); EditCurve[0] = Base::Vector2d(Origin.x,Origin.y); } virtual void mouseMove(Base::Vector2d onSketchPos) { if (Mode==STATUS_SEEK_First) { float length = (onSketchPos - EditCurve[0]).Length(); float angle = (onSketchPos - EditCurve[0]).GetAngle(Base::Vector2d(1.f,0.f)); SbString text; text.sprintf(" (%.1f,%.1fdeg)", length, angle * 180 / M_PI); setPositionText(onSketchPos, text); EditCurve[1] = onSketchPos; sketchgui->drawEdit(EditCurve); if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2d(0.0,0.0),AutoConstraint::VERTEX)) { renderSuggestConstraintsCursor(sugConstr1); return; } } applyCursor(); } virtual bool pressButton(Base::Vector2d onSketchPos) { if (Mode==STATUS_SEEK_First){ EditCurve[1] = onSketchPos; sketchgui->drawEdit(EditCurve); Mode = STATUS_End; } return true; } virtual bool releaseButton(Base::Vector2d onSketchPos) { Q_UNUSED(onSketchPos); if (Mode==STATUS_End){ Base::Vector2d vector = EditCurve[1]-EditCurve[0]; unsetCursor(); resetPositionText(); Gui::Command::openCommand("Create copy of 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.addCopy(%s,App.Vector(%f,%f,0),%s)", sketchgui->getObject()->getNameInDocument(), geoIdList.c_str(), vector.x, vector.y, (Clone?"True":"False")); Gui::Command::commitCommand(); } catch (const Base::Exception& e) { Base::Console().Error("%s\n", e.what()); Gui::Command::abortCommand(); } // add auto constraints for the destination copy if (sugConstr1.size() > 0) { createAutoConstraints(sugConstr1, OriginGeoId+nElements, OriginPos); sugConstr1.clear(); } if(autoRecompute) Gui::Command::updateActive(); else static_cast(sketchgui->getObject())->solve(); EditCurve.clear(); sketchgui->drawEdit(EditCurve); sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider } return true; } protected: SelectMode Mode; string geoIdList; Base::Vector3d Origin; int OriginGeoId; Sketcher::PointPos OriginPos; int nElements; bool Clone; std::vector EditCurve; std::vector sugConstr1; }; class SketcherCopy : public Gui::Command { public: SketcherCopy(const char* name); void activate(bool clone); }; SketcherCopy::SketcherCopy(const char* name): Command(name) {} void SketcherCopy::activate(bool clone) { // get the selection std::vector selection = getSelection().getSelectionEx(); // 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 &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); getSelection().clearSelection(); int LastGeoId = 0; Sketcher::PointPos LastPointPos = Sketcher::none; const Part::Geometry *LastGeo = 0; // create python command with list of elements std::stringstream stream; int geoids = 0; for (std::vector::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) { // only handle non-external edges if (it->size() > 4 && it->substr(0,4) == "Edge") { LastGeoId = std::atoi(it->substr(4,4000).c_str()) - 1; LastPointPos = Sketcher::none; LastGeo = Obj->getGeometry(LastGeoId); // lines to copy 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; // points to copy if (LastGeoId>=0) { geoids++; stream << LastGeoId << ","; } } } } // 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; } } if (geoids < 1) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("A copy requires at least one selected non-external geometric element")); return; } std::string geoIdList = stream.str(); // remove the last added comma and brackets to make the python list int index = geoIdList.rfind(','); geoIdList.resize(index); geoIdList.insert(0,1,'['); geoIdList.append(1,']'); // if the last element is not a point serving as a reference for the copy process // then make the start point of the last element the copy reference (if it exists, if not the center point) if (LastPointPos == Sketcher::none) { if (LastGeo->getTypeId() == Part::GeomCircle::getClassTypeId() || LastGeo->getTypeId() == Part::GeomEllipse::getClassTypeId()) { LastPointPos = Sketcher::mid; } else { LastPointPos = Sketcher::start; } } // Ask the user if he wants to clone or to simple copy /*int ret = QMessageBox::question(Gui::getMainWindow(), QObject::tr("Dimensional/Geometric constraints"), QObject::tr("Do you want to clone the object, i.e. substitute dimensional constraints by geometric constraints?"), QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel); // use an equality constraint if (ret == QMessageBox::Yes) { clone = true; } else if (ret == QMessageBox::Cancel) { // do nothing return; }*/ ActivateAcceleratorHandler(getActiveGuiDocument(),new DrawSketchHandlerCopy(geoIdList, LastGeoId, LastPointPos, geoids, clone)); } class CmdSketcherCopy : public SketcherCopy { public: CmdSketcherCopy(); virtual ~CmdSketcherCopy(){} virtual const char* className() const { return "CmdSketcherCopy"; } protected: virtual void activated(int iMsg); virtual bool isActive(void); }; CmdSketcherCopy::CmdSketcherCopy() :SketcherCopy("Sketcher_Copy") { sAppModule = "Sketcher"; sGroup = QT_TR_NOOP("Sketcher"); sMenuText = QT_TR_NOOP("Copy"); sToolTipText = QT_TR_NOOP("Creates a simple copy of the geometry taking as reference the last selected point"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; sPixmap = "Sketcher_Copy"; sAccel = ""; eType = ForEdit; } void CmdSketcherCopy::activated(int iMsg) { Q_UNUSED(iMsg); activate(false); } bool CmdSketcherCopy::isActive(void) { return isSketcherAcceleratorActive( getActiveGuiDocument(), true ); } class CmdSketcherClone : public SketcherCopy { public: CmdSketcherClone(); virtual ~CmdSketcherClone(){} virtual const char* className() const { return "CmdSketcherClone"; } protected: virtual void activated(int iMsg); virtual bool isActive(void); }; CmdSketcherClone::CmdSketcherClone() :SketcherCopy("Sketcher_Clone") { sAppModule = "Sketcher"; sGroup = QT_TR_NOOP("Sketcher"); sMenuText = QT_TR_NOOP("Clone"); sToolTipText = QT_TR_NOOP("Creates a clone of the geometry taking as reference the last selected point"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; sPixmap = "Sketcher_Clone"; sAccel = ""; eType = ForEdit; } void CmdSketcherClone::activated(int iMsg) { Q_UNUSED(iMsg); activate(true); } bool CmdSketcherClone::isActive(void) { return isSketcherAcceleratorActive( getActiveGuiDocument(), true ); } DEF_STD_CMD_ACL(CmdSketcherCompCopy); CmdSketcherCompCopy::CmdSketcherCompCopy() : Command("Sketcher_CompCopy") { sAppModule = "Sketcher"; sGroup = QT_TR_NOOP("Sketcher"); sMenuText = QT_TR_NOOP("Copy"); sToolTipText = QT_TR_NOOP("Creates a clone of the geometry taking as reference the last selected point"); sWhatsThis = "Sketcher_CompCopy"; sStatusTip = sToolTipText; sAccel = "CTRL+C"; eType = ForEdit; } void CmdSketcherCompCopy::activated(int iMsg) { if (iMsg==0){ CmdSketcherClone sc; sc.activate(true); } else if (iMsg==1) { CmdSketcherCopy sc; sc.activate(false); } else return; // Since the default icon is reset when enabing/disabling the command we have // to explicitly set the icon of the used command. Gui::ActionGroup* pcAction = qobject_cast(_pcAction); QList a = pcAction->actions(); assert(iMsg < a.size()); pcAction->setIcon(a[iMsg]->icon()); pcAction->setShortcut(QString::fromLatin1(this->sAccel)); } Gui::Action * CmdSketcherCompCopy::createAction(void) { Gui::ActionGroup* pcAction = new Gui::ActionGroup(this, Gui::getMainWindow()); pcAction->setDropDownMenu(true); applyCommandData(this->className(), pcAction); QAction* clone = pcAction->addAction(QString()); clone->setIcon(Gui::BitmapFactory().pixmap("Sketcher_Clone")); QAction* copy = pcAction->addAction(QString()); copy->setIcon(Gui::BitmapFactory().pixmap("Sketcher_Copy")); _pcAction = pcAction; languageChange(); pcAction->setIcon(clone->icon()); int defaultId = 0; pcAction->setProperty("defaultAction", QVariant(defaultId)); pcAction->setShortcut(QString::fromLatin1(sAccel)); return pcAction; } void CmdSketcherCompCopy::languageChange() { Command::languageChange(); if (!_pcAction) return; Gui::ActionGroup* pcAction = qobject_cast(_pcAction); QList a = pcAction->actions(); QAction* clone = a[0]; clone->setText(QApplication::translate("Sketcher_CompCopy","Clone")); clone->setToolTip(QApplication::translate("Sketcher_Clone","Creates a clone of the geometry taking as reference the last selected point")); clone->setStatusTip(QApplication::translate("Sketcher_Clone","Creates a clone of the geometry taking as reference the last selected point")); QAction* copy = a[1]; copy->setText(QApplication::translate("Sketcher_CompCopy","Copy")); copy->setToolTip(QApplication::translate("Sketcher_Copy","Creates a simple copy of the geometry taking as reference the last selected point")); copy->setStatusTip(QApplication::translate("Sketcher_Copy","Creates a simple copy of the geometry taking as reference the last selected point")); } bool CmdSketcherCompCopy::isActive(void) { return isSketcherAcceleratorActive( getActiveGuiDocument(), true ); } /* XPM */ static const char *cursor_createrectangulararray[]={ "32 32 3 1", "+ c white", "# c red", ". c None", "................................", "................................", "................................", "................................", "................................", ".......................###......", ".......................###......", ".......................###......", ".......................###......", "..............###......###......", "..............###......###......", "..............###......###......", "..............###......###......", ".....###......###......###......", ".....###......###......###......", ".....###......###......###......", ".....###......###......###......", ".....###......###......###......", ".....###......###......###......", ".....###......###...............", ".....###......###...............", ".....###......###...............", ".....###......###...............", ".....###........................", ".....###........................", ".....###........................", ".....###........................", "................................", "................................", "................................", "................................", "................................"}; class DrawSketchHandlerRectangularArray: public DrawSketchHandler { public: DrawSketchHandlerRectangularArray(string geoidlist, int origingeoid, Sketcher::PointPos originpos, int nelements, bool clone, int rows, int cols, bool constraintSeparation, bool equalVerticalHorizontalSpacing ) : Mode(STATUS_SEEK_First) , geoIdList(geoidlist) , OriginGeoId(origingeoid) , OriginPos(originpos) , nElements(nelements) , Clone(clone) , Rows(rows) , Cols(cols) , ConstraintSeparation(constraintSeparation) , EqualVerticalHorizontalSpacing(equalVerticalHorizontalSpacing) , EditCurve(2) { } virtual ~DrawSketchHandlerRectangularArray(){} /// mode table enum SelectMode { STATUS_SEEK_First, /**< enum value ----. */ STATUS_End }; virtual void activated(ViewProviderSketch *sketchgui) { setCursor(QPixmap(cursor_createrectangulararray),7,7); Origin = static_cast(sketchgui->getObject())->getPoint(OriginGeoId, OriginPos); EditCurve[0] = Base::Vector2d(Origin.x,Origin.y); } virtual void mouseMove(Base::Vector2d onSketchPos) { if (Mode==STATUS_SEEK_First) { float length = (onSketchPos - EditCurve[0]).Length(); float angle = (onSketchPos - EditCurve[0]).GetAngle(Base::Vector2d(1.f,0.f)); SbString text; text.sprintf(" (%.1f,%.1fdeg)", length, angle * 180 / M_PI); setPositionText(onSketchPos, text); EditCurve[1] = onSketchPos; sketchgui->drawEdit(EditCurve); if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2d(0.0,0.0),AutoConstraint::VERTEX)) { renderSuggestConstraintsCursor(sugConstr1); return; } } applyCursor(); } virtual bool pressButton(Base::Vector2d onSketchPos) { if (Mode==STATUS_SEEK_First){ EditCurve[1] = onSketchPos; sketchgui->drawEdit(EditCurve); Mode = STATUS_End; } return true; } virtual bool releaseButton(Base::Vector2d onSketchPos) { Q_UNUSED(onSketchPos); if (Mode==STATUS_End){ Base::Vector2d vector = EditCurve[1]-EditCurve[0]; unsetCursor(); resetPositionText(); Gui::Command::openCommand("Create copy of 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.addRectangularArray(%s, App.Vector(%f,%f,0),%s,%d,%d,%s,%f)", sketchgui->getObject()->getNameInDocument(), geoIdList.c_str(), vector.x, vector.y, (Clone?"True":"False"), Cols, Rows, (ConstraintSeparation?"True":"False"), (EqualVerticalHorizontalSpacing?1.0:0.5)); Gui::Command::commitCommand(); } catch (const Base::Exception& e) { Base::Console().Error("%s\n", e.what()); Gui::Command::abortCommand(); } // add auto constraints for the destination copy if (sugConstr1.size() > 0) { createAutoConstraints(sugConstr1, OriginGeoId+nElements, OriginPos); sugConstr1.clear(); } if(autoRecompute) Gui::Command::updateActive(); else static_cast(sketchgui->getObject())->solve(); EditCurve.clear(); sketchgui->drawEdit(EditCurve); sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider } return true; } protected: SelectMode Mode; string geoIdList; Base::Vector3d Origin; int OriginGeoId; Sketcher::PointPos OriginPos; int nElements; bool Clone; int Rows; int Cols; bool ConstraintSeparation; bool EqualVerticalHorizontalSpacing; std::vector EditCurve; std::vector sugConstr1; }; DEF_STD_CMD_A(CmdSketcherRectangularArray); CmdSketcherRectangularArray::CmdSketcherRectangularArray() :Command("Sketcher_RectangularArray") { sAppModule = "Sketcher"; sGroup = QT_TR_NOOP("Sketcher"); sMenuText = QT_TR_NOOP("Rectangular Array"); sToolTipText = QT_TR_NOOP("Creates an rectangular array pattern of the geometry taking as reference the last selected point"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; sPixmap = "Sketcher_RectangularArray"; sAccel = ""; eType = ForEdit; } void CmdSketcherRectangularArray::activated(int iMsg) { Q_UNUSED(iMsg); // get the selection std::vector selection = getSelection().getSelectionEx(); // 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 &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); getSelection().clearSelection(); int LastGeoId = 0; Sketcher::PointPos LastPointPos = Sketcher::none; const Part::Geometry *LastGeo = 0; // create python command with list of elements std::stringstream stream; int geoids = 0; for (std::vector::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) { // only handle non-external edges if (it->size() > 4 && it->substr(0,4) == "Edge") { LastGeoId = std::atoi(it->substr(4,4000).c_str()) - 1; LastPointPos = Sketcher::none; LastGeo = Obj->getGeometry(LastGeoId); // lines to copy 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; // points to copy if(LastGeoId>=0) { geoids++; stream << LastGeoId << ","; } } } } // 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; } } if ( geoids < 1 ) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("A copy requires at least one selected non-external geometric element")); return; } std::string geoIdList = stream.str(); // remove the last added comma and brackets to make the python list int index = geoIdList.rfind(','); geoIdList.resize(index); geoIdList.insert(0,1,'['); geoIdList.append(1,']'); // if the last element is not a point serving as a reference for the copy process // then make the start point of the last element the copy reference (if it exists, if not the center point) if (LastPointPos == Sketcher::none) { if (LastGeo->getTypeId() == Part::GeomCircle::getClassTypeId() || LastGeo->getTypeId() == Part::GeomEllipse::getClassTypeId()) { LastPointPos = Sketcher::mid; } else { LastPointPos = Sketcher::start; } } // Pop-up asking for values SketchRectangularArrayDialog * slad = new SketchRectangularArrayDialog(); if (slad->exec() == QDialog::Accepted) { ActivateAcceleratorHandler(getActiveGuiDocument(), new DrawSketchHandlerRectangularArray(geoIdList, LastGeoId, LastPointPos, geoids, slad->Clone, slad->Rows, slad->Cols, slad->ConstraintSeparation, slad->EqualVerticalHorizontalSpacing)); } delete slad; } bool CmdSketcherRectangularArray::isActive(void) { return isSketcherAcceleratorActive( getActiveGuiDocument(), true ); } void CreateSketcherCommandsConstraintAccel(void) { Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); rcCmdMgr.addCommand(new CmdSketcherCloseShape()); rcCmdMgr.addCommand(new CmdSketcherConnect()); rcCmdMgr.addCommand(new CmdSketcherSelectConstraints()); rcCmdMgr.addCommand(new CmdSketcherSelectOrigin()); rcCmdMgr.addCommand(new CmdSketcherSelectVerticalAxis()); rcCmdMgr.addCommand(new CmdSketcherSelectHorizontalAxis()); rcCmdMgr.addCommand(new CmdSketcherSelectRedundantConstraints()); rcCmdMgr.addCommand(new CmdSketcherSelectConflictingConstraints()); rcCmdMgr.addCommand(new CmdSketcherSelectElementsAssociatedWithConstraints()); rcCmdMgr.addCommand(new CmdSketcherRestoreInternalAlignmentGeometry()); rcCmdMgr.addCommand(new CmdSketcherSymmetry()); rcCmdMgr.addCommand(new CmdSketcherCopy()); rcCmdMgr.addCommand(new CmdSketcherClone()); rcCmdMgr.addCommand(new CmdSketcherCompCopy()); rcCmdMgr.addCommand(new CmdSketcherRectangularArray()); }