| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <TopoDS.hxx> |
| | #include <TopoDS_Face.hxx> |
| | #include <boost/signals2.hpp> |
| | #include <map> |
| | #include <string> |
| | #include <vector> |
| | #include <QMessageBox> |
| |
|
| |
|
| | #include "SketchWorkflow.h" |
| | #include "DlgActiveBody.h" |
| | #include "TaskFeaturePick.h" |
| | #include "Utils.h" |
| | #include "ViewProviderBody.h" |
| | #include "WorkflowManager.h" |
| | #include "ui_DlgReference.h" |
| | #include <Mod/PartDesign/App/Body.h> |
| | #include <Mod/PartDesign/App/DatumPlane.h> |
| | #include <Mod/PartDesign/App/ShapeBinder.h> |
| | #include <Mod/Part/App/Attacher.h> |
| | #include <Mod/Part/App/TopoShape.h> |
| | #include <Mod/Sketcher/Gui/ViewProviderSketch.h> |
| |
|
| | #include <App/Document.h> |
| | #include <App/Link.h> |
| | #include <App/Origin.h> |
| | #include <App/Datums.h> |
| | #include <App/Part.h> |
| | #include <Gui/Application.h> |
| | #include <Gui/Command.h> |
| | #include <Gui/Control.h> |
| | #include <Gui/Document.h> |
| | #include <Gui/MainWindow.h> |
| | #include <Gui/ViewParams.h> |
| | #include <Gui/ViewProviderPlane.h> |
| | #include <Gui/Selection/SelectionFilter.h> |
| |
|
| | using namespace PartDesignGui; |
| |
|
| | namespace |
| | { |
| | struct RejectException |
| | { |
| | }; |
| |
|
| | struct WrongSelectionException |
| | { |
| | }; |
| |
|
| | struct WrongSupportException |
| | { |
| | }; |
| |
|
| | struct SupportNotPlanarException |
| | { |
| | }; |
| |
|
| | struct MissingPlanesException |
| | { |
| | }; |
| |
|
| | class SupportFaceValidator |
| | { |
| | public: |
| | explicit SupportFaceValidator(Gui::SelectionObject faceSelection) |
| | : faceSelection(faceSelection) |
| | {} |
| |
|
| | void handleSelectedBody(PartDesign::Body* activeBody) |
| | { |
| | App::DocumentObject* object = faceSelection.getObject(); |
| | std::vector<std::string> elements = faceSelection.getSubNames(); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | if (object == activeBody) { |
| | App::DocumentObject* tip = activeBody->Tip.getValue(); |
| | if (tip && tip->isDerivedFrom<Part::Feature>() && elements.size() == 1) { |
| | Gui::SelectionChanges msg; |
| | msg.pDocName = faceSelection.getDocName(); |
| | msg.pObjectName = tip->getNameInDocument(); |
| | msg.pSubName = elements[0].c_str(); |
| | msg.pTypeName = tip->getTypeId().getName(); |
| |
|
| | faceSelection = Gui::SelectionObject {msg}; |
| |
|
| | |
| | setThroughModeOfBody(activeBody); |
| | } |
| | } |
| | } |
| |
|
| | void throwIfInvalid() |
| | { |
| | App::DocumentObject* object = faceSelection.getObject(); |
| | std::vector<std::string> elements = faceSelection.getSubNames(); |
| |
|
| | Part::Feature* partobject = dynamic_cast<Part::Feature*>(object); |
| | if (!partobject) { |
| | throw WrongSelectionException(); |
| | } |
| |
|
| | if (elements.size() != 1) { |
| | throw WrongSelectionException(); |
| | } |
| |
|
| | |
| | const Part::TopoShape& shape = partobject->Shape.getValue(); |
| | Part::TopoShape subshape(shape.getSubShape(elements[0].c_str())); |
| | if (subshape.isNull()) { |
| | throw WrongSupportException(); |
| | } |
| |
|
| | if (!subshape.isPlanar(Attacher::AttachEnginePlane::planarPrecision())) { |
| | throw SupportNotPlanarException(); |
| | } |
| | } |
| |
|
| | std::string getSupport() const |
| | { |
| | return faceSelection.getAsPropertyLinkSubString(); |
| | } |
| |
|
| | App::DocumentObject* getObject() const |
| | { |
| | return faceSelection.getObject(); |
| | } |
| |
|
| | private: |
| | void setThroughModeOfBody(PartDesign::Body* activeBody) |
| | { |
| | |
| | PartDesignGui::ViewProviderBody* vpBody = dynamic_cast<PartDesignGui::ViewProviderBody*>( |
| | Gui::Application::Instance->getViewProvider(activeBody) |
| | ); |
| | if (vpBody) { |
| | vpBody->DisplayModeBody.setValue("Through"); |
| | } |
| | } |
| |
|
| | private: |
| | mutable Gui::SelectionObject faceSelection; |
| | }; |
| |
|
| | class SupportPlaneValidator |
| | { |
| | public: |
| | explicit SupportPlaneValidator(Gui::SelectionObject faceSelection) |
| | : faceSelection(faceSelection) |
| | {} |
| |
|
| | std::string getSupport() const |
| | { |
| | return faceSelection.getAsPropertyLinkSubString(); |
| | } |
| |
|
| | App::DocumentObject* getObject() const |
| | { |
| | return faceSelection.getObject(); |
| | } |
| |
|
| | private: |
| | mutable Gui::SelectionObject faceSelection; |
| | }; |
| |
|
| | class SketchPreselection |
| | { |
| | public: |
| | SketchPreselection( |
| | Gui::Document* guidocument, |
| | PartDesign::Body* activeBody, |
| | std::tuple<Gui::SelectionFilter, Gui::SelectionFilter, Gui::SelectionFilter> filter |
| | ) |
| | : guidocument(guidocument) |
| | , activeBody(activeBody) |
| | , faceFilter(std::get<0>(filter)) |
| | , planeFilter(std::get<1>(filter)) |
| | , sketchFilter(std::get<2>(filter)) |
| | {} |
| |
|
| | bool matches() |
| | { |
| | return faceFilter.match() || planeFilter.match() || sketchFilter.match(); |
| | } |
| |
|
| | std::string getSupport() const |
| | { |
| | return supportString; |
| | } |
| |
|
| | void createSupport() |
| | { |
| | createBodyOrThrow(); |
| |
|
| | |
| | App::DocumentObject* selectedObject {}; |
| |
|
| | if (faceFilter.match()) { |
| | Gui::SelectionObject faceSelObject = faceFilter.Result[0][0]; |
| | SupportFaceValidator validator {faceSelObject}; |
| | validator.handleSelectedBody(activeBody); |
| | validator.throwIfInvalid(); |
| |
|
| | selectedObject = validator.getObject(); |
| | supportString = validator.getSupport(); |
| | } |
| | else if (planeFilter.match()) { |
| | SupportPlaneValidator validator(planeFilter.Result[0][0]); |
| | selectedObject = validator.getObject(); |
| | supportString = validator.getSupport(); |
| | } |
| | else { |
| | |
| | Gui::SelectionObject sketchSelObject = sketchFilter.Result[0][0]; |
| | selectedObject = sketchSelObject.getObject(); |
| | supportString = sketchSelObject.getAsPropertyLinkSubString(); |
| | } |
| |
|
| | handleIfSupportOutOfBody(selectedObject); |
| | } |
| |
|
| | void createSketchOnSupport(const std::string& supportString) |
| | { |
| | |
| | App::Document* appdocument = guidocument->getDocument(); |
| | std::string FeatName = appdocument->getUniqueObjectName("Sketch"); |
| |
|
| | guidocument->openCommand(QT_TRANSLATE_NOOP("Command", "Sketch on Face")); |
| | FCMD_OBJ_CMD(activeBody, "newObject('Sketcher::SketchObject','" << FeatName << "')"); |
| | auto Feat = activeBody->getDocument()->getObject(FeatName.c_str()); |
| | FCMD_OBJ_CMD(Feat, "AttachmentSupport = " << supportString); |
| | if (sketchFilter.match()) { |
| | FCMD_OBJ_CMD( |
| | Feat, |
| | "MapMode = '" << Attacher::AttachEngine::getModeName(Attacher::mmObjectXY) << "'" |
| | ); |
| | } |
| | else { |
| | FCMD_OBJ_CMD( |
| | Feat, |
| | "MapMode = '" << Attacher::AttachEngine::getModeName(Attacher::mmFlatFace) << "'" |
| | ); |
| | } |
| | Gui::Command::updateActive(); |
| | PartDesignGui::setEdit(Feat, activeBody); |
| | } |
| |
|
| | private: |
| | void createBodyOrThrow() |
| | { |
| | if (!activeBody) { |
| | activeBody = PartDesignGui::getBody( true); |
| | if (activeBody) { |
| | tryAddNewBodyToActivePart(); |
| | } |
| | else { |
| | throw RejectException(); |
| | } |
| | } |
| | } |
| |
|
| | void tryAddNewBodyToActivePart() |
| | { |
| | App::Part* activePart = PartDesignGui::getActivePart(); |
| | if (activePart) { |
| | activePart->addObject(activeBody); |
| | } |
| | } |
| |
|
| | void handleIfSupportOutOfBody(App::DocumentObject* selectedObject) |
| | { |
| | if (!activeBody->hasObject(selectedObject)) { |
| | if (!selectedObject->isDerivedFrom(App::Plane::getClassTypeId())) { |
| | |
| |
|
| | |
| | |
| | |
| | QDialog dia(Gui::getMainWindow()); |
| | PartDesignGui::Ui_DlgReference dlg; |
| | dlg.setupUi(&dia); |
| | dia.setModal(true); |
| | int result = dia.exec(); |
| | if (result == QDialog::Rejected) { |
| | throw RejectException(); |
| | } |
| |
|
| | if (!dlg.radioXRef->isChecked()) { |
| | guidocument->openCommand(QT_TRANSLATE_NOOP("Command", "Make copy")); |
| | auto copy = makeCopy(selectedObject, dlg.radioIndependent->isChecked()); |
| | supportString = supportFromCopy(copy); |
| | guidocument->commitCommand(); |
| | } |
| | } |
| | } |
| | } |
| |
|
| | App::DocumentObject* makeCopy(App::DocumentObject* selectedObject, bool independent) |
| | { |
| | std::string sub; |
| | if (faceFilter.match()) { |
| | sub = faceFilter.Result[0][0].getSubNames()[0]; |
| | } |
| | auto copy = PartDesignGui::TaskFeaturePick::makeCopy(selectedObject, sub, independent); |
| |
|
| | addToBodyOrPart(copy); |
| |
|
| | return copy; |
| | } |
| |
|
| | std::string supportFromCopy(App::DocumentObject* copy) |
| | { |
| | std::string supportString; |
| | if (planeFilter.match()) { |
| | supportString = Gui::Command::getObjectCmd(copy, "(", ",'')"); |
| | } |
| | else { |
| | |
| | |
| | supportString = Gui::Command::getObjectCmd(copy, "(", ",'Face1')"); |
| | } |
| | return supportString; |
| | } |
| |
|
| | void addToBodyOrPart(App::DocumentObject* object) |
| | { |
| | auto activePart = PartDesignGui::getPartFor(activeBody, false); |
| | if (activeBody) { |
| | activeBody->addObject(object); |
| | } |
| | else if (activePart) { |
| | activePart->addObject(object); |
| | } |
| | } |
| |
|
| | private: |
| | Gui::Document* guidocument; |
| | PartDesign::Body* activeBody; |
| | Gui::SelectionFilter faceFilter; |
| | Gui::SelectionFilter planeFilter; |
| | Gui::SelectionFilter sketchFilter; |
| | std::string supportString; |
| | }; |
| |
|
| | class PlaneFinder |
| | { |
| | public: |
| | PlaneFinder(App::Document* appdocument, PartDesign::Body* activeBody) |
| | : appdocument(appdocument) |
| | , activeBody(activeBody) |
| | {} |
| |
|
| | std::vector<App::DocumentObject*> getPlanes() const |
| | { |
| | return planes; |
| | } |
| |
|
| | std::vector<PartDesignGui::TaskFeaturePick::featureStatus> getStatus() const |
| | { |
| | return status; |
| | } |
| |
|
| | unsigned countValidPlanes() const |
| | { |
| | return validPlaneCount; |
| | } |
| |
|
| | void findBasePlanes() |
| | { |
| | try { |
| | tryFindBasePlanes(); |
| | } |
| | catch (const Base::Exception& ex) { |
| | Base::Console().error("%s\n", ex.what()); |
| | } |
| | } |
| |
|
| | void findDatumPlanes() |
| | { |
| | App::GeoFeatureGroupExtension* geoGroup = getGroupExtensionOfBody(); |
| | const std::vector<Base::Type> types |
| | = {PartDesign::Plane::getClassTypeId(), App::Plane::getClassTypeId()}; |
| | auto datumPlanes = appdocument->getObjectsOfType(types); |
| |
|
| | for (auto plane : datumPlanes) { |
| | if (std::find(planes.begin(), planes.end(), plane) != planes.end()) { |
| | continue; |
| | } |
| |
|
| | planes.push_back(plane); |
| | |
| | if (activeBody->hasObject(plane, true)) { |
| | if (!activeBody->isAfterInsertPoint(plane)) { |
| | validPlaneCount++; |
| | status.push_back(PartDesignGui::TaskFeaturePick::validFeature); |
| | } |
| | else { |
| | status.push_back(PartDesignGui::TaskFeaturePick::afterTip); |
| | } |
| | } |
| | else { |
| | PartDesign::Body* planeBody = PartDesign::Body::findBodyOf(plane); |
| | if (planeBody) { |
| | if ((geoGroup && geoGroup->hasObject(planeBody, true)) |
| | || !App::GeoFeatureGroupExtension::getGroupOfObject(planeBody)) { |
| | status.push_back(PartDesignGui::TaskFeaturePick::otherBody); |
| | } |
| | else { |
| | status.push_back(PartDesignGui::TaskFeaturePick::otherPart); |
| | } |
| | } |
| | else { |
| | if ((geoGroup && geoGroup->hasObject(plane, true)) |
| | || App::GeoFeatureGroupExtension::getGroupOfObject(plane)) { |
| | status.push_back(PartDesignGui::TaskFeaturePick::otherPart); |
| | } |
| | else { |
| | status.push_back(PartDesignGui::TaskFeaturePick::notInBody); |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | void findShapeBinderPlanes() |
| | { |
| |
|
| | |
| | auto shapeBinders(appdocument->getObjectsOfType(PartDesign::ShapeBinder::getClassTypeId())); |
| | auto binders(appdocument->getObjectsOfType(PartDesign::SubShapeBinder::getClassTypeId())); |
| | shapeBinders.insert(shapeBinders.end(), binders.begin(), binders.end()); |
| | for (auto binder : shapeBinders) { |
| | |
| | if (activeBody->hasObject(binder)) { |
| | Part::TopoShape shape = static_cast<Part::Feature*>(binder)->Shape.getShape(); |
| | if (shape.isPlanar()) { |
| | if (!activeBody->isAfterInsertPoint(binder)) { |
| | validPlaneCount++; |
| | planes.push_back(binder); |
| | status.push_back(PartDesignGui::TaskFeaturePick::validFeature); |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | private: |
| | void tryFindBasePlanes() |
| | { |
| | auto* origin = activeBody->getOrigin(); |
| | for (auto plane : origin->planes()) { |
| | planes.push_back(plane); |
| | status.push_back(PartDesignGui::TaskFeaturePick::basePlane); |
| | validPlaneCount++; |
| | } |
| | } |
| |
|
| | App::GeoFeatureGroupExtension* getGroupExtensionOfBody() const |
| | { |
| | App::GeoFeatureGroupExtension* geoGroup {nullptr}; |
| | if (activeBody) { |
| | auto group(App::GeoFeatureGroupExtension::getGroupOfObject(activeBody)); |
| | if (group) { |
| | geoGroup = group->getExtensionByType<App::GeoFeatureGroupExtension>(); |
| | } |
| | } |
| |
|
| | return geoGroup; |
| | } |
| |
|
| | private: |
| | App::Document* appdocument; |
| | PartDesign::Body* activeBody; |
| | unsigned validPlaneCount = 0; |
| | std::vector<App::DocumentObject*> planes; |
| | std::vector<PartDesignGui::TaskFeaturePick::featureStatus> status; |
| | }; |
| |
|
| | class SketchRequestSelection |
| | { |
| | public: |
| | SketchRequestSelection(Gui::Document* guidocument, PartDesign::Body* activeBody) |
| | : guidocument(guidocument) |
| | , activeBody(activeBody) |
| | {} |
| |
|
| | void findSupport() |
| | { |
| | try { |
| | |
| | guidocument->openCommand(QT_TRANSLATE_NOOP("Command", "New Sketch")); |
| | tryFindSupport(); |
| | } |
| | catch (const RejectException&) { |
| | guidocument->abortCommand(); |
| | throw; |
| | } |
| | catch (const MissingPlanesException&) { |
| | guidocument->abortCommand(); |
| | throw; |
| | } |
| | } |
| |
|
| | private: |
| | void tryFindSupport() |
| | { |
| | createBodyOrThrow(); |
| |
|
| | bool useAttachment = App::GetApplication() |
| | .GetParameterGroupByPath( |
| | "User parameter:BaseApp/Preferences/Mod/PartDesign" |
| | ) |
| | ->GetBool("NewSketchUseAttachmentDialog", false); |
| | if (useAttachment) { |
| | createSketchAndShowAttachment(); |
| | } |
| | else { |
| | findAndSelectPlane(); |
| | } |
| | } |
| |
|
| | void createBodyOrThrow() |
| | { |
| | if (!activeBody) { |
| | App::Document* appdocument = guidocument->getDocument(); |
| | activeBody = PartDesignGui::makeBody(appdocument); |
| | if (activeBody) { |
| | tryAddNewBodyToActivePart(); |
| | } |
| | else { |
| | throw RejectException(); |
| | } |
| | } |
| | } |
| |
|
| | void tryAddNewBodyToActivePart() |
| | { |
| | App::Part* activePart = PartDesignGui::getActivePart(); |
| | if (activePart) { |
| | activePart->addObject(activeBody); |
| | } |
| | } |
| |
|
| | void setOriginTemporaryVisibility() |
| | { |
| | auto* origin = activeBody->getOrigin(); |
| | auto* vpo = dynamic_cast<Gui::ViewProviderCoordinateSystem*>( |
| | Gui::Application::Instance->getViewProvider(origin) |
| | ); |
| | if (vpo) { |
| | vpo->setTemporaryVisibility(Gui::DatumElement::Planes | Gui::DatumElement::Axes); |
| | vpo->setPlaneLabelVisibility(true); |
| | } |
| | } |
| |
|
| | void createSketchAndShowAttachment() |
| | { |
| | setOriginTemporaryVisibility(); |
| |
|
| | |
| | App::Document* doc = activeBody->getDocument(); |
| | std::string FeatName = doc->getUniqueObjectName("Sketch"); |
| | FCMD_OBJ_CMD(activeBody, "newObject('Sketcher::SketchObject','" << FeatName << "')"); |
| | auto sketch = doc->getObject(FeatName.c_str()); |
| |
|
| | PartDesign::Body* partDesignBody = activeBody; |
| | auto onAccept = [partDesignBody, sketch]() { |
| | resetOriginVisibility(partDesignBody); |
| |
|
| | Gui::Selection().clearSelection(); |
| |
|
| | PartDesignGui::setEdit(sketch, partDesignBody); |
| | }; |
| | auto onReject = [partDesignBody]() { |
| | resetOriginVisibility(partDesignBody); |
| | }; |
| |
|
| | Gui::Selection().clearSelection(); |
| |
|
| | |
| | auto* vps = dynamic_cast<SketcherGui::ViewProviderSketch*>( |
| | Gui::Application::Instance->getViewProvider(sketch) |
| | ); |
| | vps->showAttachmentEditor(onAccept, onReject); |
| | } |
| |
|
| | static void resetOriginVisibility(PartDesign::Body* partDesignBody) |
| | { |
| | auto* origin = partDesignBody->getOrigin(); |
| | auto* vpo = dynamic_cast<Gui::ViewProviderCoordinateSystem*>( |
| | Gui::Application::Instance->getViewProvider(origin) |
| | ); |
| | if (vpo) { |
| | vpo->resetTemporaryVisibility(); |
| | vpo->resetTemporarySize(); |
| | vpo->setPlaneLabelVisibility(false); |
| | } |
| | } |
| |
|
| | void findAndSelectPlane() |
| | { |
| | App::Document* appdocument = guidocument->getDocument(); |
| | PlaneFinder planeFinder {appdocument, activeBody}; |
| |
|
| | planeFinder.findBasePlanes(); |
| | planeFinder.findDatumPlanes(); |
| | planeFinder.findShapeBinderPlanes(); |
| |
|
| | std::vector<App::DocumentObject*> planes = planeFinder.getPlanes(); |
| | std::vector<PartDesignGui::TaskFeaturePick::featureStatus> status = planeFinder.getStatus(); |
| | unsigned validPlaneCount = planeFinder.countValidPlanes(); |
| |
|
| | for (auto& plane : planes) { |
| | auto* planeViewProvider |
| | = Gui::Application::Instance->getViewProvider<Gui::ViewProviderPlane>(plane); |
| |
|
| | |
| | if (!planeViewProvider || !planeViewProvider->getRole().empty()) { |
| | continue; |
| | } |
| |
|
| | planeViewProvider->setLabelVisibility(true); |
| | planeViewProvider->setTemporaryScale( |
| | Gui::ViewParams::instance()->getDatumTemporaryScaleFactor() |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | App::Document* documentOfBody = appdocument; |
| | PartDesign::Body* partDesignBody = activeBody; |
| |
|
| | auto restorePlaneVisibility = [planes]() { |
| | for (auto& plane : planes) { |
| | auto* planeViewProvider |
| | = Gui::Application::Instance->getViewProvider<Gui::ViewProviderPlane>(plane); |
| | if (!planeViewProvider) { |
| | continue; |
| | } |
| |
|
| | planeViewProvider->resetTemporarySize(); |
| | planeViewProvider->setLabelVisibility(false); |
| | } |
| | }; |
| |
|
| | |
| | auto acceptFunction = |
| | [restorePlaneVisibility](const std::vector<App::DocumentObject*>& features) -> bool { |
| | restorePlaneVisibility(); |
| | return !features.empty(); |
| | }; |
| |
|
| | |
| | auto processFunction = [documentOfBody, |
| | partDesignBody](const std::vector<App::DocumentObject*>& features) { |
| | SketchRequestSelection::createSketch(documentOfBody, partDesignBody, features); |
| | }; |
| |
|
| | |
| | std::string docname = documentOfBody->getName(); |
| | auto rejectFunction = [docname, restorePlaneVisibility]() { |
| | restorePlaneVisibility(); |
| | Gui::Document* document = Gui::Application::Instance->getDocument(docname.c_str()); |
| | if (document) { |
| | document->abortCommand(); |
| | } |
| | }; |
| |
|
| | |
| | |
| | |
| |
|
| | if (validPlaneCount == 0) { |
| | throw MissingPlanesException(); |
| | } |
| | else if (validPlaneCount == 1) { |
| | processFunction(planes); |
| | } |
| | else if (validPlaneCount > 1) { |
| | checkForShownDialog(); |
| | Gui::Selection().clearSelection(); |
| |
|
| | |
| | Gui::Control().showDialog(new PartDesignGui::TaskDlgFeaturePick( |
| | planes, |
| | status, |
| | acceptFunction, |
| | processFunction, |
| | true, |
| | rejectFunction |
| | )); |
| | } |
| | } |
| |
|
| | void checkForShownDialog() |
| | { |
| | Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); |
| | PartDesignGui::TaskDlgFeaturePick* pickDlg |
| | = qobject_cast<PartDesignGui::TaskDlgFeaturePick*>(dlg); |
| | if (dlg && !pickDlg) { |
| | QMessageBox msgBox(Gui::getMainWindow()); |
| | msgBox.setText(QObject::tr("A dialog is already open in the task panel")); |
| | msgBox.setInformativeText(QObject::tr("Close this dialog?")); |
| | msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); |
| | msgBox.setDefaultButton(QMessageBox::Yes); |
| | int ret = msgBox.exec(); |
| | if (ret == QMessageBox::Yes) { |
| | Gui::Control().closeDialog(); |
| | } |
| | else { |
| | throw RejectException(); |
| | } |
| | } |
| |
|
| | if (dlg) { |
| | Gui::Control().closeDialog(); |
| | } |
| | } |
| |
|
| | static void createSketch( |
| | App::Document* documentOfBody, |
| | PartDesign::Body* partDesignBody, |
| | const std::vector<App::DocumentObject*>& features |
| | ) |
| | { |
| | |
| | |
| | if (features.empty()) { |
| | return; |
| | } |
| | std::string FeatName = documentOfBody->getUniqueObjectName("Sketch"); |
| | auto* plane = static_cast<App::Plane*>(features.front()); |
| | auto* lcs = plane->getLCS(); |
| |
|
| | std::string supportString; |
| | if (lcs) { |
| | supportString = Gui::Command::getObjectCmd(lcs, "(") + ",['" |
| | + plane->getNameInDocument() + "'])"; |
| | } |
| | else { |
| | supportString = Gui::Command::getObjectCmd(plane, "(", ",[''])"); |
| | } |
| |
|
| | App::Document* doc = partDesignBody->getDocument(); |
| | if (!doc->hasPendingTransaction()) { |
| | doc->openTransaction(QT_TRANSLATE_NOOP("Command", "New Sketch")); |
| | } |
| |
|
| | FCMD_OBJ_CMD(partDesignBody, "newObject('Sketcher::SketchObject','" << FeatName << "')"); |
| | auto Feat = doc->getObject(FeatName.c_str()); |
| | FCMD_OBJ_CMD(Feat, "AttachmentSupport = " << supportString); |
| | FCMD_OBJ_CMD( |
| | Feat, |
| | "MapMode = '" << Attacher::AttachEngine::getModeName(Attacher::mmFlatFace) << "'" |
| | ); |
| | Gui::Command::updateActive(); |
| | PartDesignGui::setEdit(Feat, partDesignBody); |
| | } |
| |
|
| | private: |
| | Gui::Document* guidocument; |
| | PartDesign::Body* activeBody; |
| | }; |
| |
|
| | } |
| |
|
| | SketchWorkflow::SketchWorkflow(Gui::Document* document) |
| | : guidocument(document) |
| | { |
| | appdocument = guidocument->getDocument(); |
| | } |
| |
|
| | void SketchWorkflow::createSketch() |
| | { |
| | try { |
| | tryCreateSketch(); |
| | } |
| | catch (const RejectException&) { |
| | } |
| | catch (const WrongSelectionException&) { |
| | QMessageBox::warning( |
| | Gui::getMainWindow(), |
| | QObject::tr("Several sub-elements selected"), |
| | QObject::tr("Select a single face as support for a sketch!") |
| | ); |
| | } |
| | catch (const WrongSupportException&) { |
| | QMessageBox::warning( |
| | Gui::getMainWindow(), |
| | QObject::tr("No support face selected"), |
| | QObject::tr("Select a face as support for a sketch!") |
| | ); |
| | } |
| | catch (const SupportNotPlanarException&) { |
| | QMessageBox::warning( |
| | Gui::getMainWindow(), |
| | QObject::tr("No planar support"), |
| | QObject::tr("Need a planar face as support for a sketch!") |
| | ); |
| | } |
| | catch (const MissingPlanesException&) { |
| | QMessageBox::warning( |
| | Gui::getMainWindow(), |
| | QObject::tr("No valid planes in this document"), |
| | QObject::tr("Create a plane first or select a face to sketch on") |
| | ); |
| | } |
| | } |
| |
|
| | void SketchWorkflow::tryCreateSketch() |
| | { |
| | auto result = shouldCreateBody(); |
| | auto shouldMakeBody = std::get<0>(result); |
| | activeBody = std::get<1>(result); |
| | if (shouldAbort(shouldMakeBody)) { |
| | return; |
| | } |
| |
|
| | auto filters = getFilters(); |
| | SketchPreselection sketchOnFace {guidocument, activeBody, filters}; |
| |
|
| | if (sketchOnFace.matches()) { |
| | |
| | sketchOnFace.createSupport(); |
| | sketchOnFace.createSketchOnSupport(sketchOnFace.getSupport()); |
| | } |
| | else { |
| | SketchRequestSelection requestSelection {guidocument, activeBody}; |
| | requestSelection.findSupport(); |
| | } |
| | } |
| |
|
| | std::tuple<bool, PartDesign::Body*> SketchWorkflow::shouldCreateBody() |
| | { |
| | auto shouldMakeBody {false}; |
| |
|
| | |
| | |
| | |
| | App::DocumentObject* topParent; |
| | PartDesign::Body* pdBody |
| | = PartDesignGui::getBody( false, true, true, &topParent); |
| | if (pdBody && topParent->isLink()) { |
| | auto* xLink = dynamic_cast<App::Link*>(topParent); |
| | pdBody->Placement.setValue(xLink->Placement.getValue()); |
| | } |
| | if (!pdBody) { |
| | if (appdocument->countObjectsOfType<PartDesign::Body>() == 0) { |
| | shouldMakeBody = true; |
| | } |
| | else { |
| | PartDesignGui::DlgActiveBody dia(Gui::getMainWindow(), appdocument); |
| | if (dia.exec() == QDialog::Accepted) { |
| | pdBody = dia.getActiveBody(); |
| | } |
| | } |
| | } |
| |
|
| | return std::make_tuple(shouldMakeBody, pdBody); |
| | } |
| |
|
| | bool SketchWorkflow::shouldAbort(bool shouldMakeBody) const |
| | { |
| | return !shouldMakeBody && !activeBody; |
| | } |
| |
|
| | std::tuple<Gui::SelectionFilter, Gui::SelectionFilter, Gui::SelectionFilter> SketchWorkflow::getFilters() const |
| | { |
| | |
| | |
| | |
| | |
| | |
| |
|
| | Gui::SelectionFilter FaceFilter("SELECT Part::Feature SUBELEMENT Face COUNT 1"); |
| | Gui::SelectionFilter PlaneFilter("SELECT App::Plane COUNT 1", activeBody); |
| | Gui::SelectionFilter PlaneFilter2("SELECT PartDesign::Plane COUNT 1", activeBody); |
| | Gui::SelectionFilter SketchFilter("SELECT Part::Part2DObject COUNT 1", activeBody); |
| |
|
| | if (PlaneFilter2.match()) { |
| | PlaneFilter = PlaneFilter2; |
| | } |
| |
|
| | return std::make_tuple(FaceFilter, PlaneFilter, SketchFilter); |
| | } |
| |
|