From eccff10d90f06fc9c0e23e8dfe4b407d705344e9 Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Mon, 29 Jun 2015 19:33:01 +0300 Subject: [PATCH] PartDesign: fix refuse to pad When something was depending on a sketch (another sketch, for example), padding (revolving, pocketing, etc) it was impossible. This is fixed. Also, padding or revolving a single sketch twice was allowed (with a warning msg displayed). --- src/Mod/PartDesign/Gui/Command.cpp | 39 +- src/Mod/PartDesign/Gui/Command.cpp.orig | 601 ++++++++++++++++++------ 2 files changed, 495 insertions(+), 145 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index ae3b99c59..fc0fcb76e 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -992,7 +992,9 @@ void finishFeature(const Gui::Command* cmd, const std::string& FeatName, const b while (o != inList.end()) { //Base::Console().Error("Inlist: %s\n", (*o)->getNameInDocument()); if ((*o)->getTypeId().isDerivedFrom(PartDesign::Body::getClassTypeId())) - o = inList.erase(o); + o = inList.erase(o); //ignore bodies + else if (!( (*o)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId()) )) + o = inList.erase(o); //ignore non-partDesign else ++o; } @@ -1043,21 +1045,25 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, PartDesign::Body *pcActiveBody = PartDesignGui::getBody(/*messageIfNot = */true); if (!pcActiveBody) return; + bool bNoSketchWasSelected = false; // Get a valid sketch from the user // First check selections + std::vector sketches = cmd->getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); + if (sketches.size() == 0) {//no sketches were selected. Let user pick an object from valid ones available in document + sketches = cmd->getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); + bNoSketchWasSelected = true; + } std::vector status; std::vector::iterator firstValidSketch; - std::vector sketches = cmd->getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); - // Next let the user choose from a list of all eligible objects unsigned validSketches = validateSketches(sketches, status, firstValidSketch); if (validSketches == 0) { - status.clear(); - sketches = cmd->getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); - validSketches = validateSketches(sketches, status, firstValidSketch); - if (validSketches == 0) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), - QObject::tr("Please create a sketch or 2D object first.")); + if (bNoSketchWasSelected) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No sketch to work on"), + QObject::tr("No sketch was selected. None of the sketches in the document is free.")); return; + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches selected"), + QObject::tr("Attention: none of selected sketches/2D objects is free.")); } } @@ -1088,8 +1094,10 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, }; // If there is more than one selection/possibility, show dialog and let user pick sketch - if (validSketches > 1) { - + if (bNoSketchWasSelected && validSketches > 1 + || + !bNoSketchWasSelected && sketches.size() > 1) { + Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); PartDesignGui::TaskDlgFeaturePick *pickDlg = qobject_cast(dlg); if (dlg && !pickDlg) { @@ -1112,7 +1120,14 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, Gui::Control().showDialog(new PartDesignGui::TaskDlgFeaturePick(sketches, status, accepter, worker)); } else { - worker(sketches); + std::vector theSketch; + theSketch.reserve(1); + if (bNoSketchWasSelected && validSketches == 1){ + theSketch.push_back(*firstValidSketch); + } else if(!bNoSketchWasSelected && sketches.size() == 1) { + theSketch = sketches; + } + worker(theSketch); } } diff --git a/src/Mod/PartDesign/Gui/Command.cpp.orig b/src/Mod/PartDesign/Gui/Command.cpp.orig index a71c325d3..2d5ef772b 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp.orig +++ b/src/Mod/PartDesign/Gui/Command.cpp.orig @@ -81,6 +81,44 @@ using namespace std; #include "TaskFeaturePick.h" #include "ReferenceSelection.h" + +//=========================================================================== +// PartDesign_Part +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignPart); + +CmdPartDesignPart::CmdPartDesignPart() + : Command("PartDesign_Part") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Create part"); + sToolTipText = QT_TR_NOOP("Create a new part feature"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Tree_Annotation"; +} + +void CmdPartDesignPart::activated(int iMsg) +{ + openCommand("Add a body feature"); + std::string FeatName = getUniqueObjectName("Part"); + + std::string PartName; + PartName = getUniqueObjectName("Part"); + doCommand(Doc,"App.activeDocument().Tip = App.activeDocument().addObject('App::Part','%s')",PartName.c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr(PartName.c_str()).toStdString().c_str()); + PartDesignGui::Workbench::setUpPart(dynamic_cast(getDocument()->getObject(PartName.c_str()))); + doCommand(Gui::Command::Gui, "Gui.activeView().setActiveObject('%s', App.activeDocument().%s)", PARTKEY, PartName.c_str()); + + updateActive(); +} + +bool CmdPartDesignPart::isActive(void) +{ + return hasActiveDocument(); +} + //=========================================================================== // PartDesign_Body //=========================================================================== @@ -106,7 +144,7 @@ void CmdPartDesignBody::activated(int iMsg) // first check if Part is already created: App::Part *actPart = getDocument()->Tip.getValue(); std::string PartName; - + if(!actPart){ // if not, creating a part and set it up by calling the appropiated function in Workbench //if we create a new part we automaticly get a new body, there is no need to create a second one @@ -114,6 +152,8 @@ void CmdPartDesignBody::activated(int iMsg) doCommand(Doc,"App.activeDocument().Tip = App.activeDocument().addObject('App::Part','%s')",PartName.c_str()); doCommand(Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr(PartName.c_str()).toStdString().c_str()); PartDesignGui::Workbench::setUpPart(dynamic_cast(getDocument()->getObject(PartName.c_str()))); + doCommand(Gui::Command::Gui, "Gui.activeView().setActiveObject('%s', App.activeDocument().%s)", PARTKEY, PartName.c_str()); + } else { PartName = actPart->getNameInDocument(); // add the Body feature itself, and make it active @@ -122,6 +162,7 @@ void CmdPartDesignBody::activated(int iMsg) //doCommand(Doc,"App.activeDocument().%s.Tip = None",FeatName.c_str()); addModule(Gui,"PartDesignGui"); // import the Gui module only once a session doCommand(Gui::Command::Gui, "Gui.activeView().setActiveObject('%s', App.activeDocument().%s)", PDBODYKEY, FeatName.c_str()); + // Make the "Create sketch" prompt appear in the task panel doCommand(Gui,"Gui.Selection.clearSelection()"); doCommand(Gui,"Gui.Selection.addSelection(App.ActiveDocument.%s)", FeatName.c_str()); @@ -257,6 +298,8 @@ void CmdPartDesignDuplicateSelection::activated(int iMsg) // Find the features that were added std::vector afterFeatures = getDocument()->getObjects(); std::vector newFeatures; + std::sort(beforeFeatures.begin(), beforeFeatures.end()); + std::sort(afterFeatures.begin(), afterFeatures.end()); std::set_difference(afterFeatures.begin(), afterFeatures.end(), beforeFeatures.begin(), beforeFeatures.end(), std::back_inserter(newFeatures)); @@ -331,12 +374,17 @@ void CmdPartDesignMoveFeature::activated(int iMsg) for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { // Find body of this feature Part::BodyBase* source = PartDesign::Body::findBodyOf(*f); - if (source == target) continue; - bool featureIsTip = (source->Tip.getValue() == *f); + bool featureIsTip = false; - // Remove from source body - doCommand(Doc,"App.activeDocument().%s.removeFeature(App.activeDocument().%s)", + if (source == target) continue; + + // Remove from the source body if the feature belonged to a body + if (source) { + featureIsTip = (source->Tip.getValue() == *f); + doCommand(Doc,"App.activeDocument().%s.removeFeature(App.activeDocument().%s)", source->getNameInDocument(), (*f)->getNameInDocument()); + } + // Add to target body (always at the Tip) doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", target->getNameInDocument(), (*f)->getNameInDocument()); @@ -348,13 +396,24 @@ void CmdPartDesignMoveFeature::activated(int iMsg) // If we removed the tip of the source body, make the new tip visible if (featureIsTip) { App::DocumentObject* prevSolidFeature = source->getPrevSolidFeature(); - doCommand(Gui,"Gui.activeDocument().show(\"%s\")", prevSolidFeature->getNameInDocument()); + if (prevSolidFeature) { + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", prevSolidFeature->getNameInDocument()); + } } // Hide old tip and show new tip (the moved feature) of the target body App::DocumentObject* prevSolidFeature = target->getPrevSolidFeature(); doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); doCommand(Gui,"Gui.activeDocument().show(\"%s\")", (*f)->getNameInDocument()); + } else if ((*f)->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) { + Sketcher::SketchObject *sketch = static_cast(*f); + try { + PartDesignGui::Workbench::fixSketchSupport(sketch); + } catch (Base::Exception &) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Sketch plane cannot be migrated"), + QObject::tr("Please edit '%1' and redefine it to use a Base or Datum plane as the sketch plane."). + arg(QString::fromAscii(sketch->getNameInDocument()) ) ); + } } } } @@ -407,13 +466,6 @@ void CmdPartDesignMoveFeatureInTree::activated(int iMsg) openCommand("Move an object inside tree"); - // Set insert point at the selected feature - App::DocumentObject* oldTip = pcActiveBody->Tip.getValue(); - Gui::Selection().clearSelection(); - if (target != NULL) - Gui::Selection().addSelection(target->getDocument()->getName(), target->getNameInDocument()); - Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); - for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { if (*f == target) continue; @@ -422,17 +474,13 @@ void CmdPartDesignMoveFeatureInTree::activated(int iMsg) // feature as before! doCommand(Doc,"App.activeDocument().%s.removeFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), (*f)->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", - pcActiveBody->getNameInDocument(), (*f)->getNameInDocument()); + doCommand(Doc, + "App.activeDocument().%s.insertFeature(App.activeDocument().%s, App.activeDocument().%s, True)", + pcActiveBody->getNameInDocument(), (*f)->getNameInDocument(), target->getNameInDocument()); } // Recompute to update the shape doCommand(Gui,"App.activeDocument().recompute()"); - // Set insert point where it was before - Gui::Selection().clearSelection(); - Gui::Selection().addSelection(oldTip->getDocument()->getName(), oldTip->getNameInDocument()); - Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); - Gui::Selection().clearSelection(); } bool CmdPartDesignMoveFeatureInTree::isActive(void) @@ -517,9 +565,9 @@ const QString getReferenceString(Gui::Command* cmd) QString::fromAscii(",'')]"); } } - - //datum features task can start without reference, as every needed one can be set from - //withing the task. + + //datum features task can start without reference, as every needed one can be set from + //withing the task. return QString::fromAscii(""); } @@ -695,10 +743,16 @@ void CmdPartDesignNewSketch::activated(int iMsg) else if (FaceFilter.match() || PlaneFilter.match()) { // get the selected object std::string supportString; - Part::Feature* feat; + App::DocumentObject* obj; if (FaceFilter.match()) { - feat = static_cast(FaceFilter.Result[0][0].getObject()); + obj = FaceFilter.Result[0][0].getObject(); + + if(!obj->isDerivedFrom(Part::Feature::getClassTypeId())) + return; + + Part::Feature* feat = static_cast(obj); + // FIXME: Reject or warn about feature that is outside of active body, and feature // that comes after the current insert point (Tip) const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); @@ -728,17 +782,20 @@ void CmdPartDesignNewSketch::activated(int iMsg) supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); } else { - feat = static_cast(PlaneFilter.Result[0][0].getObject()); + obj = static_cast(PlaneFilter.Result[0][0].getObject()); // TODO: Find out whether the user picked front or back of this plane - supportString = std::string("(App.activeDocument().") + feat->getNameInDocument() + ", ['front'])"; + supportString = std::string("(App.activeDocument().") + obj->getNameInDocument() + ", ['front'])"; } - if (!pcActiveBody->hasFeature(feat)) { + if (!pcActiveBody->hasFeature(obj)) { bool isBasePlane = false; - for (unsigned i = 0; i < 3; i++) { - if (strcmp(App::Part::BaseplaneTypes[i], feat->getNameInDocument()) == 0) { - isBasePlane = true; - break; + if(obj->isDerivedFrom(App::Plane::getClassTypeId())) { + App::Plane* pfeat = static_cast(obj); + for (unsigned i = 0; i < 3; i++) { + if (strcmp(App::Part::BaseplaneTypes[i], pfeat->PlaneType.getValue()) == 0) { + isBasePlane = true; + break; + } } } if (!isBasePlane) { @@ -746,7 +803,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) QObject::tr("You have to select a face or plane from the active body!")); return; } - } else if (pcActiveBody->isAfterTip(feat)) { + } else if (pcActiveBody->isAfterTip(obj)) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection from inactive feature"), QObject::tr("You have to select a face or plane before the current insert point, or move the insert point")); return; @@ -756,7 +813,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) std::string FeatName = getUniqueObjectName("Sketch"); openCommand("Create a Sketch on Face"); - doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); @@ -777,14 +834,17 @@ void CmdPartDesignNewSketch::activated(int iMsg) for (std::vector::iterator p = planes.begin(); p != planes.end(); p++) { // Check whether this plane is a base plane bool base = false; - for (unsigned i = 0; i < 3; i++) { - if (strcmp(App::Part::BaseplaneTypes[i], (*p)->getNameInDocument()) == 0) { - status.push_back(PartDesignGui::TaskFeaturePick::basePlane); - if (firstValidPlane == planes.end()) - firstValidPlane = p; - validPlanes++; - base = true; - break; + if((*p)->isDerivedFrom(App::Plane::getClassTypeId())) { + App::Plane* pfeat = static_cast(*p); + for (unsigned i = 0; i < 3; i++) { + if (strcmp(App::Part::BaseplaneTypes[i], pfeat->PlaneType.getValue()) == 0) { + status.push_back(PartDesignGui::TaskFeaturePick::basePlane); + if (firstValidPlane == planes.end()) + firstValidPlane = p; + validPlanes++; + base = true; + break; + } } } if (base) continue; @@ -814,15 +874,15 @@ void CmdPartDesignNewSketch::activated(int iMsg) } auto accepter = [=](const std::vector& features) -> bool { - + if(features.empty()) return false; - + return true; }; - + auto worker = [=](const std::vector& features) { - App::Plane* plane = static_cast(features.front()); + App::Plane* plane = static_cast(features.front()); std::string FeatName = getUniqueObjectName("Sketch"); std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + ", ['" + (false ? "back" : "front") + "'])"; @@ -836,11 +896,11 @@ void CmdPartDesignNewSketch::activated(int iMsg) //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); Gui::Command::doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); }; - + // If there is more than one possibility, show dialog and let user pick plane bool reversed = false; if (validPlanes > 1) { - + Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); PartDesignGui::TaskDlgFeaturePick *pickDlg = qobject_cast(dlg); if (dlg && !pickDlg) { @@ -855,7 +915,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) else return; } - + if(dlg) Gui::Control().closeDialog(); @@ -889,7 +949,7 @@ void finishFeature(const Gui::Command* cmd, const std::string& FeatName, const b cmd->doCommand(cmd->Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); - if (cmd->isActiveObjectValid() && (pcActiveBody != NULL)) { + if (pcActiveBody != NULL) { App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(NULL, false); if (hidePrevSolid && (prevSolidFeature != NULL)) cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); @@ -917,7 +977,7 @@ void finishFeature(const Gui::Command* cmd, const std::string& FeatName, const b const unsigned validateSketches(std::vector& sketches, std::vector& status, std::vector::iterator& firstValidSketch) -{ +{ // TODO: If the user previously opted to allow multiple use of sketches or use of sketches from other bodies, // then count these as valid sketches! unsigned validSketches = 0; @@ -932,7 +992,9 @@ void finishFeature(const Gui::Command* cmd, const std::string& FeatName, const b while (o != inList.end()) { //Base::Console().Error("Inlist: %s\n", (*o)->getNameInDocument()); if ((*o)->getTypeId().isDerivedFrom(PartDesign::Body::getClassTypeId())) - o = inList.erase(o); + o = inList.erase(o); //ignore bodies + else if (!( (*o)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId()) )) + o = inList.erase(o); //ignore non-partDesign else ++o; } @@ -977,40 +1039,53 @@ void finishFeature(const Gui::Command* cmd, const std::string& FeatName, const b return validSketches; } -void prepareSketchBased(Gui::Command* cmd, const std::string& which, +void prepareSketchBased(Gui::Command* cmd, const std::string& which, boost::function func) { PartDesign::Body *pcActiveBody = PartDesignGui::getBody(/*messageIfNot = */true); if (!pcActiveBody) return; + bool bNoSketchWasSelected = false; // Get a valid sketch from the user // First check selections + std::vector sketches = cmd->getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); + if (sketches.size() == 0) {//no sketches were selected. Let user pick an object from valid ones available in document + sketches = cmd->getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); + bNoSketchWasSelected = true; + } std::vector status; std::vector::iterator firstValidSketch; - std::vector sketches = cmd->getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); - // Next let the user choose from a list of all eligible objects unsigned validSketches = validateSketches(sketches, status, firstValidSketch); if (validSketches == 0) { +<<<<<<< 4b045c35fe095e70e0ac1a04afade8f6685fecdb status.clear(); sketches = cmd->getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); validSketches = validateSketches(sketches, status, firstValidSketch); if (validSketches == 0) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), QObject::tr("Please create a sketch or 2D object first.")); +======= + if (bNoSketchWasSelected) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No sketch to work on"), + QObject::tr("No sketch was selected. None of the sketches in the document is free.")); +>>>>>>> PartDesign: fix refuse to pad return; + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches selected"), + QObject::tr("Attention: none of selected sketches/2D objects is free.")); } } - + auto accepter = [=](const std::vector& features) -> bool { - + if(features.empty()) return false; - + return true; }; - + auto worker = [which, cmd, func](std::vector features) { - + auto firstValidSketch = features.begin(); Part::Part2DObject* sketch = static_cast(*firstValidSketch); @@ -1026,9 +1101,11 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, func(sketch, FeatName); }; - + // If there is more than one selection/possibility, show dialog and let user pick sketch - if (validSketches > 1) { + if (bNoSketchWasSelected && validSketches > 1 + || + !bNoSketchWasSelected && sketches.size() > 1) { Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); PartDesignGui::TaskDlgFeaturePick *pickDlg = qobject_cast(dlg); @@ -1044,7 +1121,7 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, else return; } - + if(dlg) Gui::Control().closeDialog(); @@ -1052,16 +1129,21 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, Gui::Control().showDialog(new PartDesignGui::TaskDlgFeaturePick(sketches, status, accepter, worker)); } else { - worker(sketches); + std::vector theSketch; + theSketch.reserve(1); + if (bNoSketchWasSelected && validSketches == 1){ + theSketch.push_back(*firstValidSketch); + } else if(!bNoSketchWasSelected && sketches.size() == 1) { + theSketch = sketches; + } + worker(theSketch); } - + } void finishSketchBased(const Gui::Command* cmd, const Part::Part2DObject* sketch, const std::string& FeatName) { - if (cmd->isActiveObjectValid()) - cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", sketch->getNameInDocument()); - + cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", sketch->getNameInDocument()); finishFeature(cmd, FeatName); } @@ -1083,12 +1165,12 @@ CmdPartDesignPad::CmdPartDesignPad() } void CmdPartDesignPad::activated(int iMsg) -{ +{ Gui::Command* cmd = this; auto worker = [cmd](Part::Part2DObject* sketch, std::string FeatName) { - + if (FeatName.empty()) return; - + // specific parameters for Pad Gui::Command::doCommand(Doc,"App.activeDocument().%s.Length = 10.0",FeatName.c_str()); App::DocumentObjectGroup* grp = sketch->getGroup(); @@ -1101,9 +1183,9 @@ void CmdPartDesignPad::activated(int iMsg) Gui::Command::updateActive(); finishSketchBased(cmd, sketch, FeatName); - //adjustCameraPosition(); + cmd->adjustCameraPosition(); }; - + prepareSketchBased(this, "Pad", worker); } @@ -1133,14 +1215,14 @@ void CmdPartDesignPocket::activated(int iMsg) { Gui::Command* cmd = this; auto worker = [cmd](Part::Part2DObject* sketch, std::string FeatName) { - + if (FeatName.empty()) return; - + Gui::Command::doCommand(Doc,"App.activeDocument().%s.Length = 5.0",FeatName.c_str()); finishSketchBased(cmd, sketch, FeatName); - //adjustCameraPosition(); + cmd->adjustCameraPosition(); }; - + prepareSketchBased(this, "Pocket", worker); } @@ -1170,7 +1252,7 @@ void CmdPartDesignRevolution::activated(int iMsg) { Gui::Command* cmd = this; auto worker = [cmd](Part::Part2DObject* sketch, std::string FeatName) { - + if (FeatName.empty()) return; Gui::Command::doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", @@ -1179,11 +1261,11 @@ void CmdPartDesignRevolution::activated(int iMsg) PartDesign::Revolution* pcRevolution = static_cast(cmd->getDocument()->getObject(FeatName.c_str())); if (pcRevolution && pcRevolution->suggestReversed()) Gui::Command::doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); - + finishSketchBased(cmd, sketch, FeatName); - //adjustCameraPosition(); + cmd->adjustCameraPosition(); }; - + prepareSketchBased(this, "Revolution", worker); } @@ -1210,10 +1292,10 @@ CmdPartDesignGroove::CmdPartDesignGroove() } void CmdPartDesignGroove::activated(int iMsg) -{ +{ Gui::Command* cmd = this; auto worker = [cmd](Part::Part2DObject* sketch, std::string FeatName) { - + if (FeatName.empty()) return; Gui::Command::doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", @@ -1224,7 +1306,7 @@ void CmdPartDesignGroove::activated(int iMsg) Gui::Command::doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); finishSketchBased(cmd, sketch, FeatName); - //adjustCameraPosition(); + cmd->adjustCameraPosition(); }; prepareSketchBased(this, "Groove", worker); @@ -1235,6 +1317,165 @@ bool CmdPartDesignGroove::isActive(void) return hasActiveDocument(); } +//=========================================================================== +// PartDesign_Additive_Pipe +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignAdditivePipe); + +CmdPartDesignAdditivePipe::CmdPartDesignAdditivePipe() + : Command("PartDesign_AdditivePipe") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Additive pipe"); + sToolTipText = QT_TR_NOOP("Sweep a selected sketch along a path or to other profiles"); + sWhatsThis = "PartDesign_Additive_Pipe"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Additive_Pipe"; +} + +void CmdPartDesignAdditivePipe::activated(int iMsg) +{ + Gui::Command* cmd = this; + auto worker = [cmd](Part::Part2DObject* sketch, std::string FeatName) { + + if (FeatName.empty()) return; + + // specific parameters for pipe + Gui::Command::updateActive(); + + finishSketchBased(cmd, sketch, FeatName); + cmd->adjustCameraPosition(); + }; + + prepareSketchBased(this, "AdditivePipe", worker); +} + +bool CmdPartDesignAdditivePipe::isActive(void) +{ + return hasActiveDocument(); +} + + +//=========================================================================== +// PartDesign_Subtractive_Pipe +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignSubtractivePipe); + +CmdPartDesignSubtractivePipe::CmdPartDesignSubtractivePipe() + : Command("PartDesign_SubtractivePipe") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Subtractive pipe"); + sToolTipText = QT_TR_NOOP("Sweep a selected sketch along a path or to other profiles and remove it from the body"); + sWhatsThis = "PartDesign_Subtractive_Pipe"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Subtractive_Pipe"; +} + +void CmdPartDesignSubtractivePipe::activated(int iMsg) +{ + Gui::Command* cmd = this; + auto worker = [cmd](Part::Part2DObject* sketch, std::string FeatName) { + + if (FeatName.empty()) return; + + // specific parameters for pipe + Gui::Command::updateActive(); + + finishSketchBased(cmd, sketch, FeatName); + cmd->adjustCameraPosition(); + }; + + prepareSketchBased(this, "SubtractivePipe", worker); +} + +bool CmdPartDesignSubtractivePipe::isActive(void) +{ + return hasActiveDocument(); +} + + +//=========================================================================== +// PartDesign_Additive_Loft +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignAdditiveLoft); + +CmdPartDesignAdditiveLoft::CmdPartDesignAdditiveLoft() + : Command("PartDesign_AdditiveLoft") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Additive pipe"); + sToolTipText = QT_TR_NOOP("Sweep a selected sketch along a path or to other profiles"); + sWhatsThis = "PartDesign_Additive_Loft"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Additive_Loft"; +} + +void CmdPartDesignAdditiveLoft::activated(int iMsg) +{ + Gui::Command* cmd = this; + auto worker = [cmd](Part::Part2DObject* sketch, std::string FeatName) { + + if (FeatName.empty()) return; + + // specific parameters for pipe + Gui::Command::updateActive(); + + finishSketchBased(cmd, sketch, FeatName); + cmd->adjustCameraPosition(); + }; + + prepareSketchBased(this, "AdditiveLoft", worker); +} + +bool CmdPartDesignAdditiveLoft::isActive(void) +{ + return hasActiveDocument(); +} + + +//=========================================================================== +// PartDesign_Subtractive_Loft +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignSubtractiveLoft); + +CmdPartDesignSubtractiveLoft::CmdPartDesignSubtractiveLoft() + : Command("PartDesign_SubtractiveLoft") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Subtractive pipe"); + sToolTipText = QT_TR_NOOP("Sweep a selected sketch along a path or to other profiles and remove it from the body"); + sWhatsThis = "PartDesign_Subtractive_Loft"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Subtractive_Loft"; +} + +void CmdPartDesignSubtractiveLoft::activated(int iMsg) +{ + Gui::Command* cmd = this; + auto worker = [cmd](Part::Part2DObject* sketch, std::string FeatName) { + + if (FeatName.empty()) return; + + // specific parameters for pipe + Gui::Command::updateActive(); + + finishSketchBased(cmd, sketch, FeatName); + cmd->adjustCameraPosition(); + }; + + prepareSketchBased(this, "SubtractiveLoft", worker); +} + +bool CmdPartDesignSubtractiveLoft::isActive(void) +{ + return hasActiveDocument(); +} + //=========================================================================== // Common utility functions for Dressup features //=========================================================================== @@ -1252,7 +1493,7 @@ void makeChamferOrFillet(Gui::Command* cmd, const std::string& which) QObject::tr("Select an edge, face or body. Only one body is allowed.")); return; } - + Gui::Selection().clearSelection(); if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ @@ -1269,21 +1510,6 @@ void makeChamferOrFillet(Gui::Command* cmd, const std::string& which) return; } -<<<<<<< 2c7cc8276bd6dd4ccc4aa28daa809a688bd493c5 - const Part::TopoShape& TopShape = base->Shape.getShape(); - if (TopShape._Shape.IsNull()){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Shape of selected part is empty.")); - return; - } - - TopTools_IndexedMapOfShape mapOfEdges; - TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; - TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); - TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); - -======= ->>>>>>> allow to add faces to fillet and chamfer std::vector SubNames = std::vector(selection[0].getSubNames()); if (SubNames.size() == 0) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), @@ -1483,23 +1709,125 @@ bool CmdPartDesignDraft::isActive(void) return hasActiveDocument(); } + +//=========================================================================== +// PartDesign_Thickness +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignThickness); + +CmdPartDesignThickness::CmdPartDesignThickness() + :Command("PartDesign_Thickness") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Thickness"); + sToolTipText = QT_TR_NOOP("Make a thick solid"); + sWhatsThis = "PartDesign_Thickness"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Thickness"; +} + +void CmdPartDesignThickness::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(/*messageIfNot = */true); + if (!pcActiveBody) return; + + std::vector selection = getSelection().getSelectionEx(); + + if (selection.size() < 1) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select one or more faces.")); + return; + } + + if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), + QObject::tr("Thickness works only on parts")); + return; + } + + Part::Feature *base = static_cast(selection[0].getObject()); + + if (base != pcActiveBody->getPrevSolidFeature(NULL, true)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong base feature"), + QObject::tr("Only the current Tip of the active Body can be selected as the base feature")); + return; + } + + const Part::TopoShape& TopShape = base->Shape.getShape(); + if (TopShape._Shape.IsNull()){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Shape of selected Part is empty")); + return; + } + + std::vector SubNames = std::vector(selection[0].getSubNames()); + unsigned int i = 0; + + while(i < SubNames.size()) + { + std::string aSubName = static_cast(SubNames.at(i)); + + if(aSubName.size() > 4 && aSubName.substr(0,4) != "Face") { + // empty name or any other sub-element + SubNames.erase(SubNames.begin()+i); + } + i++; + } + + if (SubNames.size() == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("No thickness possible with selected faces")); + return; + } + + std::string SelString; + SelString += "(App."; + SelString += "ActiveDocument"; + SelString += "."; + SelString += selection[0].getFeatName(); + SelString += ",["; + for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ + SelString += "\""; + SelString += *it; + SelString += "\""; + if(it != --SubNames.end()) + SelString += ","; + } + SelString += "])"; + + std::string FeatName = getUniqueObjectName("Thickness"); + + openCommand("Make Thickness"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Thickness\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); + doCommand(Doc,"App.activeDocument().%s.Value = %f",FeatName.c_str(), 1.); + + finishFeature(this, FeatName); +} + +bool CmdPartDesignThickness::isActive(void) +{ + return hasActiveDocument(); +} + //=========================================================================== // Common functions for all Transformed features //=========================================================================== -void prepareTransformed(Gui::Command* cmd, const std::string& which, +void prepareTransformed(Gui::Command* cmd, const std::string& which, boost::function)> func) { std::string FeatName = cmd->getUniqueObjectName(which.c_str()); auto accepter = [=](std::vector features) -> bool{ - + if(features.empty()) return false; - + return true; }; - + auto worker = [=](std::vector features) { std::stringstream str; str << "App.activeDocument()." << FeatName << ".Originals = ["; @@ -1514,10 +1842,10 @@ void prepareTransformed(Gui::Command* cmd, const std::string& which, // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' Gui::Command::updateActive(); // Helps to ensure that the object already exists when the next command comes up Gui::Command::doCommand(Gui::Command::Doc, str.str().c_str()); - + func(FeatName, features); }; - + // Get a valid original from the user // First check selections std::vector features = cmd->getSelection().getObjectsOfType(PartDesign::FeatureAddSub::getClassTypeId()); @@ -1529,7 +1857,7 @@ void prepareTransformed(Gui::Command* cmd, const std::string& which, std::vector status; for (unsigned i = 0; i < features.size(); i++) status.push_back(PartDesignGui::TaskFeaturePick::validFeature); - + Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); PartDesignGui::TaskDlgFeaturePick *pickDlg = qobject_cast(dlg); if (dlg && !pickDlg) { @@ -1544,7 +1872,7 @@ void prepareTransformed(Gui::Command* cmd, const std::string& which, else return; } - + if(dlg) Gui::Control().closeDialog(); @@ -1587,10 +1915,10 @@ void CmdPartDesignMirrored::activated(int iMsg) { Gui::Command* cmd = this; auto worker = [cmd](std::string FeatName, std::vector features) { - + if (features.empty()) return; - + if(features.front()->isDerivedFrom(PartDesign::SketchBased::getClassTypeId())) { Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); if (sketch) @@ -1604,8 +1932,8 @@ void CmdPartDesignMirrored::activated(int iMsg) finishTransformed(cmd, FeatName); }; - - prepareTransformed(this, "Mirrored", worker); + + prepareTransformed(this, "Mirrored", worker); } bool CmdPartDesignMirrored::isActive(void) @@ -1634,7 +1962,7 @@ void CmdPartDesignLinearPattern::activated(int iMsg) { Gui::Command* cmd = this; auto worker = [cmd](std::string FeatName, std::vector features) { - + if (features.empty()) return; @@ -1653,7 +1981,8 @@ void CmdPartDesignLinearPattern::activated(int iMsg) finishTransformed(cmd, FeatName); }; - prepareTransformed(this, "LinearPattern", worker); + + prepareTransformed(this, "LinearPattern", worker); } bool CmdPartDesignLinearPattern::isActive(void) @@ -1679,13 +2008,13 @@ CmdPartDesignPolarPattern::CmdPartDesignPolarPattern() } void CmdPartDesignPolarPattern::activated(int iMsg) -{ +{ Gui::Command* cmd = this; auto worker = [cmd](std::string FeatName, std::vector features) { - + if (features.empty()) return; - + if(features.front()->isDerivedFrom(PartDesign::SketchBased::getClassTypeId())) { Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); if (sketch) @@ -1696,14 +2025,14 @@ void CmdPartDesignPolarPattern::activated(int iMsg) doCommand(Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"\"])", FeatName.c_str(), App::Part::BaselineTypes[0]); } - + doCommand(Doc,"App.activeDocument().%s.Angle = 360", FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); finishTransformed(cmd, FeatName); }; - - prepareTransformed(this, "PolarPattern", worker); + + prepareTransformed(this, "PolarPattern", worker); } bool CmdPartDesignPolarPattern::isActive(void) @@ -1729,20 +2058,20 @@ CmdPartDesignScaled::CmdPartDesignScaled() } void CmdPartDesignScaled::activated(int iMsg) -{ +{ Gui::Command* cmd = this; auto worker = [cmd](std::string FeatName, std::vector features) { - + if (features.empty()) return; - + doCommand(Doc,"App.activeDocument().%s.Factor = 2", FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); finishTransformed(cmd, FeatName); }; - - prepareTransformed(this, "Scaled", worker); + + prepareTransformed(this, "Scaled", worker); } bool CmdPartDesignScaled::isActive(void) @@ -1820,10 +2149,10 @@ void CmdPartDesignMultiTransform::activated(int iMsg) Gui::Selection().clearSelection(); } // otherwise the insert point remains at the new MultiTransform, which is fine } else { - + Gui::Command* cmd = this; auto worker = [cmd, pcActiveBody](std::string FeatName, std::vector features) { - + if (features.empty()) return; @@ -1836,8 +2165,8 @@ void CmdPartDesignMultiTransform::activated(int iMsg) } finishFeature(cmd, FeatName); }; - - prepareTransformed(this, "MultiTransform", worker); + + prepareTransformed(this, "MultiTransform", worker); } } @@ -1859,7 +2188,7 @@ CmdPartDesignBoolean::CmdPartDesignBoolean() sAppModule = "PartDesign"; sGroup = QT_TR_NOOP("PartDesign"); sMenuText = QT_TR_NOOP("Boolean operation"); - sToolTipText = QT_TR_NOOP("Boolean operation with two or more boies"); + sToolTipText = QT_TR_NOOP("Boolean operation with two or more bodies"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; sPixmap = "PartDesign_Boolean"; @@ -1891,9 +2220,9 @@ void CmdPartDesignBoolean::activated(int iMsg) openCommand("Create Boolean"); - PartDesign::Body* activeBody = Gui::Application::Instance->activeView()->getActiveObject(PDBODYKEY); + PartDesign::Body* activeBody = Gui::Application::Instance->activeView()->getActiveObject(PDBODYKEY); // Make sure we are working on the selected body - if (body != activeBody) { + if (body != activeBody) { Gui::Selection().clearSelection(); Gui::Selection().addSelection(body->getDocument()->getName(), body->Tip.getValue()->getNameInDocument()); Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); @@ -1924,6 +2253,7 @@ void CreatePartDesignCommands(void) { Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); + rcCmdMgr.addCommand(new CmdPartDesignPart()); rcCmdMgr.addCommand(new CmdPartDesignBody()); rcCmdMgr.addCommand(new CmdPartDesignMoveTip()); @@ -1941,10 +2271,15 @@ void CreatePartDesignCommands(void) rcCmdMgr.addCommand(new CmdPartDesignPocket()); rcCmdMgr.addCommand(new CmdPartDesignRevolution()); rcCmdMgr.addCommand(new CmdPartDesignGroove()); + rcCmdMgr.addCommand(new CmdPartDesignAdditivePipe); + rcCmdMgr.addCommand(new CmdPartDesignSubtractivePipe); + rcCmdMgr.addCommand(new CmdPartDesignAdditiveLoft); + rcCmdMgr.addCommand(new CmdPartDesignSubtractiveLoft); rcCmdMgr.addCommand(new CmdPartDesignFillet()); - rcCmdMgr.addCommand(new CmdPartDesignDraft()); + rcCmdMgr.addCommand(new CmdPartDesignDraft()); rcCmdMgr.addCommand(new CmdPartDesignChamfer()); + rcCmdMgr.addCommand(new CmdPartDesignThickness()); rcCmdMgr.addCommand(new CmdPartDesignMirrored()); rcCmdMgr.addCommand(new CmdPartDesignLinearPattern());