| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <Inventor/SbString.h> |
| | #include <QApplication> |
| |
|
| | #include <App/Application.h> |
| | #include <Base/Console.h> |
| | #include <Gui/Action.h> |
| | #include <Gui/Application.h> |
| | #include <Gui/BitmapFactory.h> |
| | #include <Gui/CommandT.h> |
| | #include <Gui/Document.h> |
| | #include <Gui/MainWindow.h> |
| | #include <Gui/Notifications.h> |
| | #include <Gui/Selection/Selection.h> |
| | #include <Gui/Selection/SelectionObject.h> |
| | #include <Mod/Sketcher/App/SketchObject.h> |
| |
|
| | #include "DrawSketchHandler.h" |
| | #include "Utils.h" |
| | #include "ViewProviderSketch.h" |
| | #include "SnapManager.h" |
| |
|
| |
|
| | using namespace std; |
| | using namespace SketcherGui; |
| | using namespace Sketcher; |
| |
|
| | void ActivateBSplineHandler(Gui::Document* doc, DrawSketchHandler* handler) |
| | { |
| | std::unique_ptr<DrawSketchHandler> ptr(handler); |
| | if (doc) { |
| | if (doc->getInEdit() && doc->getInEdit()->isDerivedFrom<SketcherGui::ViewProviderSketch>()) { |
| | SketcherGui::ViewProviderSketch* vp = static_cast<SketcherGui::ViewProviderSketch*>( |
| | doc->getInEdit() |
| | ); |
| | vp->purgeHandler(); |
| | vp->activateHandler(std::move(ptr)); |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | bool findBSplineAndKnotIndex( |
| | Sketcher::SketchObject* Obj, |
| | int knotGeoId, |
| | Sketcher::PointPos knotPosId, |
| | int& splineGeoId, |
| | int& knotIndexOCC |
| | ) |
| | { |
| | for (auto const constraint : Obj->Constraints.getValues()) { |
| | if (constraint->Type == Sketcher::InternalAlignment && constraint->First == knotGeoId |
| | && constraint->AlignmentType == Sketcher::BSplineKnotPoint) { |
| | splineGeoId = constraint->Second; |
| | knotIndexOCC = constraint->InternalAlignmentIndex + 1; |
| | return true; |
| | } |
| | } |
| |
|
| | |
| | const Part::Geometry* geo = Obj->getGeometry(knotGeoId); |
| | if (geo->is<Part::GeomBSplineCurve>()) { |
| | splineGeoId = knotGeoId; |
| | switch (knotPosId) { |
| | case Sketcher::PointPos::start: |
| | knotIndexOCC = 1; |
| | return true; |
| | case Sketcher::PointPos::end: |
| | knotIndexOCC = static_cast<const Part::GeomBSplineCurve*>(geo)->countKnots(); |
| | return true; |
| | default: |
| | |
| | |
| | |
| | return false; |
| | } |
| | } |
| |
|
| | return false; |
| | } |
| |
|
| | |
| | DEF_STD_CMD_A(CmdSketcherConvertToNURBS) |
| |
|
| | CmdSketcherConvertToNURBS::CmdSketcherConvertToNURBS() |
| | : Command("Sketcher_BSplineConvertToNURBS") |
| | { |
| | sAppModule = "Sketcher"; |
| | sGroup = "Sketcher"; |
| | sMenuText = QT_TR_NOOP("Geometry to B-Spline"); |
| | sToolTipText = QT_TR_NOOP("Converts the selected geometry to B-splines"); |
| | sWhatsThis = "Sketcher_BSplineConvertToNURBS"; |
| | sStatusTip = sToolTipText; |
| | sPixmap = "Sketcher_BSplineConvertToNURBS"; |
| | sAccel = ""; |
| | eType = ForEdit; |
| | } |
| |
|
| | void CmdSketcherConvertToNURBS::activated(int iMsg) |
| | { |
| | Q_UNUSED(iMsg); |
| |
|
| | |
| | std::vector<Gui::SelectionObject> selection; |
| | selection = getSelection().getSelectionEx(nullptr, Sketcher::SketchObject::getClassTypeId()); |
| |
|
| | |
| | if (selection.size() != 1) { |
| | return; |
| | } |
| |
|
| | |
| | const std::vector<std::string>& SubNames = selection[0].getSubNames(); |
| | Sketcher::SketchObject* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject()); |
| |
|
| | openCommand(QT_TRANSLATE_NOOP("Command", "Convert to NURBS")); |
| |
|
| | std::vector<int> GeoIdList; |
| |
|
| | for (const auto& subName : SubNames) { |
| | |
| | if (subName.size() > 4 && subName.substr(0, 4) == "Edge") { |
| | int GeoId = std::atoi(subName.substr(4, 4000).c_str()) - 1; |
| | GeoIdList.push_back(GeoId); |
| | } |
| | else if (subName.size() > 12 && subName.substr(0, 12) == "ExternalEdge") { |
| | int GeoId = -(std::atoi(subName.substr(12, 4000).c_str()) + 2); |
| | GeoIdList.push_back(GeoId); |
| | } |
| | } |
| |
|
| | |
| | for (auto GeoId : GeoIdList) { |
| | Gui::cmdAppObjectArgs(selection[0].getObject(), "convertToNURBS(%d) ", GeoId); |
| | } |
| | for (auto GeoId : GeoIdList) { |
| | Gui::cmdAppObjectArgs(selection[0].getObject(), "exposeInternalGeometry(%d)", GeoId); |
| | } |
| |
|
| | if (GeoIdList.empty()) { |
| | abortCommand(); |
| |
|
| | Gui::TranslatedUserWarning( |
| | Obj, |
| | QObject::tr("Wrong selection"), |
| | QObject::tr("None of the selected elements is an edge.") |
| | ); |
| | } |
| | else { |
| | commitCommand(); |
| | } |
| | tryAutoRecomputeIfNotSolve(Obj); |
| | } |
| |
|
| | bool CmdSketcherConvertToNURBS::isActive() |
| | { |
| | return isCommandNeedingGeometryActive(getActiveGuiDocument()); |
| | } |
| |
|
| | |
| | DEF_STD_CMD_A(CmdSketcherIncreaseDegree) |
| |
|
| | CmdSketcherIncreaseDegree::CmdSketcherIncreaseDegree() |
| | : Command("Sketcher_BSplineIncreaseDegree") |
| | { |
| | sAppModule = "Sketcher"; |
| | sGroup = "Sketcher"; |
| | sMenuText = QT_TR_NOOP("Increase B-Spline Degree"); |
| | sToolTipText = QT_TR_NOOP("Increases the degree of the B-spline"); |
| | sWhatsThis = "Sketcher_BSplineIncreaseDegree"; |
| | sStatusTip = sToolTipText; |
| | sPixmap = "Sketcher_BSplineIncreaseDegree"; |
| | sAccel = ""; |
| | eType = ForEdit; |
| | } |
| |
|
| | void CmdSketcherIncreaseDegree::activated(int iMsg) |
| | { |
| | Q_UNUSED(iMsg); |
| |
|
| | |
| | std::vector<Gui::SelectionObject> selection; |
| | selection = getSelection().getSelectionEx(nullptr, Sketcher::SketchObject::getClassTypeId()); |
| |
|
| | |
| | if (selection.size() != 1) { |
| | return; |
| | } |
| |
|
| | |
| | const std::vector<std::string>& SubNames = selection[0].getSubNames(); |
| | auto* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject()); |
| |
|
| | openCommand(QT_TRANSLATE_NOOP("Command", "Increase B-spline degree")); |
| |
|
| | bool ignored = false; |
| |
|
| | for (size_t i = 0; i < SubNames.size(); i++) { |
| | |
| | if (SubNames[i].size() > 4 && SubNames[i].substr(0, 4) == "Edge") { |
| | int GeoId = std::atoi(SubNames[i].substr(4, 4000).c_str()) - 1; |
| | const Part::Geometry* geo = Obj->getGeometry(GeoId); |
| |
|
| | if (geo->is<Part::GeomBSplineCurve>()) { |
| | Gui::cmdAppObjectArgs(Obj, "increaseBSplineDegree(%d) ", GeoId); |
| | |
| | Gui::cmdAppObjectArgs(Obj, "exposeInternalGeometry(%d)", GeoId); |
| | } |
| | else { |
| | ignored = true; |
| | } |
| | } |
| | } |
| |
|
| | if (ignored) { |
| | Gui::TranslatedUserWarning( |
| | Obj, |
| | QObject::tr("Wrong selection"), |
| | QObject::tr( |
| | "At least one of the selected " |
| | "objects was not a B-spline and was ignored." |
| | ) |
| | ); |
| | } |
| |
|
| | commitCommand(); |
| | tryAutoRecomputeIfNotSolve(Obj); |
| | getSelection().clearSelection(); |
| | } |
| |
|
| | bool CmdSketcherIncreaseDegree::isActive() |
| | { |
| | return isCommandNeedingBSplineActive(getActiveGuiDocument()); |
| | } |
| |
|
| |
|
| | |
| | DEF_STD_CMD_A(CmdSketcherDecreaseDegree) |
| |
|
| | CmdSketcherDecreaseDegree::CmdSketcherDecreaseDegree() |
| | : Command("Sketcher_BSplineDecreaseDegree") |
| | { |
| | sAppModule = "Sketcher"; |
| | sGroup = "Sketcher"; |
| | sMenuText = QT_TR_NOOP("Decrease B-Spline Degree"); |
| | sToolTipText = QT_TR_NOOP("Decreases the degree of the B-spline"); |
| | sWhatsThis = "Sketcher_BSplineDecreaseDegree"; |
| | sStatusTip = sToolTipText; |
| | sPixmap = "Sketcher_BSplineDecreaseDegree"; |
| | sAccel = ""; |
| | eType = ForEdit; |
| | } |
| |
|
| | void CmdSketcherDecreaseDegree::activated(int iMsg) |
| | { |
| | Q_UNUSED(iMsg); |
| |
|
| | |
| | std::vector<Gui::SelectionObject> selection; |
| | selection = getSelection().getSelectionEx(nullptr, Sketcher::SketchObject::getClassTypeId()); |
| |
|
| | |
| | if (selection.size() != 1) { |
| | return; |
| | } |
| |
|
| | getSelection().clearSelection(); |
| |
|
| | |
| | const std::vector<std::string>& SubNames = selection[0].getSubNames(); |
| | Sketcher::SketchObject* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject()); |
| |
|
| | openCommand(QT_TRANSLATE_NOOP("Command", "Decrease B-spline degree")); |
| |
|
| | bool ignored = false; |
| |
|
| | for (size_t i = 0; i < SubNames.size(); i++) { |
| | |
| | if (SubNames[i].size() > 4 && SubNames[i].substr(0, 4) == "Edge") { |
| | int GeoId = std::atoi(SubNames[i].substr(4, 4000).c_str()) - 1; |
| | const Part::Geometry* geo = Obj->getGeometry(GeoId); |
| |
|
| | if (geo->is<Part::GeomBSplineCurve>()) { |
| | Gui::cmdAppObjectArgs(selection[0].getObject(), "decreaseBSplineDegree(%d) ", GeoId); |
| | |
| | |
| | |
| | |
| | |
| | |
| | break; |
| | |
| | } |
| | else { |
| | ignored = true; |
| | } |
| | } |
| | } |
| |
|
| | if (ignored) { |
| | Gui::TranslatedUserWarning( |
| | Obj, |
| | QObject::tr("Wrong selection"), |
| | QObject::tr( |
| | "At least one of the selected " |
| | "objects was not a B-spline and was ignored." |
| | ) |
| | ); |
| | } |
| |
|
| | commitCommand(); |
| | tryAutoRecomputeIfNotSolve(Obj); |
| | getSelection().clearSelection(); |
| | } |
| |
|
| | bool CmdSketcherDecreaseDegree::isActive() |
| | { |
| | return isCommandNeedingBSplineActive(getActiveGuiDocument()); |
| | } |
| |
|
| | bool isCommandNeedingBSplineKnotActive(Gui::Document* doc) |
| | { |
| | if (!isCommandActive(doc)) { |
| | return false; |
| | } |
| |
|
| | std::vector<Gui::SelectionObject> sel = Gui::Selection().getSelectionEx( |
| | doc->getDocument()->getName(), |
| | Sketcher::SketchObject::getClassTypeId() |
| | ); |
| | if (sel.size() == 1) { |
| | const std::vector<std::string>& names = sel[0].getSubNames(); |
| | if (names.size() != 1) { |
| | return false; |
| | } |
| |
|
| | auto* Obj = static_cast<Sketcher::SketchObject*>(sel[0].getObject()); |
| | if (!Obj) { |
| | return false; |
| | } |
| | const std::string& name = names[0]; |
| |
|
| | int geoId {GeoEnum::GeoUndef}; |
| | PointPos posId {PointPos::none}; |
| | getIdsFromName(name, Obj, geoId, posId); |
| |
|
| | if (geoId == GeoEnum::GeoUndef) { |
| | return false; |
| | } |
| |
|
| | int splineGeoId {GeoEnum::GeoUndef}; |
| | int knotIndexOCC {-1}; |
| |
|
| | return isBsplineKnotOrEndPoint(Obj, geoId, posId) |
| | && findBSplineAndKnotIndex(Obj, geoId, posId, splineGeoId, knotIndexOCC); |
| | } |
| | return false; |
| | } |
| |
|
| | DEF_STD_CMD_A(CmdSketcherIncreaseKnotMultiplicity) |
| |
|
| | CmdSketcherIncreaseKnotMultiplicity::CmdSketcherIncreaseKnotMultiplicity() |
| | : Command("Sketcher_BSplineIncreaseKnotMultiplicity") |
| | { |
| | sAppModule = "Sketcher"; |
| | sGroup = "Sketcher"; |
| | sMenuText = QT_TR_NOOP("Increase Knot Multiplicity"); |
| | sToolTipText = QT_TR_NOOP("Increases the multiplicity of the selected knot of a B-spline"); |
| | sWhatsThis = "Sketcher_BSplineIncreaseKnotMultiplicity"; |
| | sStatusTip = sToolTipText; |
| | sPixmap = "Sketcher_BSplineIncreaseKnotMultiplicity"; |
| | sAccel = ""; |
| | eType = ForEdit; |
| | } |
| |
|
| | void CmdSketcherIncreaseKnotMultiplicity::activated(int iMsg) |
| | { |
| | Q_UNUSED(iMsg); |
| |
|
| | |
| | std::vector<Gui::SelectionObject> selection; |
| | selection = getSelection().getSelectionEx(nullptr, Sketcher::SketchObject::getClassTypeId()); |
| |
|
| | |
| | if (selection.size() != 1) { |
| | return; |
| | } |
| |
|
| | |
| | const std::vector<std::string>& SubNames = selection[0].getSubNames(); |
| |
|
| | if (SubNames.size() > 1) { |
| | |
| | |
| | Gui::TranslatedUserWarning( |
| | getActiveGuiDocument()->getDocument(), |
| | QObject::tr("Wrong selection"), |
| | QObject::tr("The selection comprises more than one item. Select just one knot.") |
| | ); |
| | return; |
| | } |
| |
|
| | Sketcher::SketchObject* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject()); |
| |
|
| | openCommand(QT_TRANSLATE_NOOP("Command", "Increase knot multiplicity")); |
| |
|
| | int GeoId; |
| | Sketcher::PointPos PosId; |
| | getIdsFromName(SubNames[0], Obj, GeoId, PosId); |
| |
|
| | int splineGeoId; |
| | int knotIndexOCC; |
| |
|
| | bool applied = false; |
| | bool notaknot = !( |
| | isBsplineKnotOrEndPoint(Obj, GeoId, PosId) |
| | && findBSplineAndKnotIndex(Obj, GeoId, PosId, splineGeoId, knotIndexOCC) |
| | ); |
| | boost::uuids::uuid bsplinetag; |
| |
|
| | if (!notaknot) { |
| | bsplinetag = Obj->getGeometry(splineGeoId)->getTag(); |
| |
|
| | try { |
| | Gui::cmdAppObjectArgs( |
| | selection[0].getObject(), |
| | "modifyBSplineKnotMultiplicity(%d, %d, %d) ", |
| | splineGeoId, |
| | knotIndexOCC, |
| | 1 |
| | ); |
| | applied = true; |
| |
|
| | |
| | |
| | |
| | } |
| | catch (const Base::CADKernelError& e) { |
| | e.reportException(); |
| | if (e.getTranslatable()) { |
| | Gui::TranslatedUserError( |
| | Obj, |
| | QObject::tr("CAD Kernel Error"), |
| | QObject::tr(e.getMessage().c_str()) |
| | ); |
| | } |
| | getSelection().clearSelection(); |
| | } |
| | catch (const Base::Exception& e) { |
| | e.reportException(); |
| | if (e.getTranslatable()) { |
| | Gui::TranslatedUserError( |
| | Obj, |
| | QObject::tr("Input Error"), |
| | QObject::tr(e.getMessage().c_str()) |
| | ); |
| | } |
| | getSelection().clearSelection(); |
| | } |
| | } |
| |
|
| | if (notaknot) { |
| | Gui::TranslatedUserWarning( |
| | Obj, |
| | QObject::tr("Wrong selection"), |
| | QObject::tr("None of the selected elements is a knot of a B-spline") |
| | ); |
| | } |
| |
|
| | if (applied) { |
| | |
| | const std::vector<Part::Geometry*>& gvals = Obj->getInternalGeometry(); |
| |
|
| | int ngeoid = 0; |
| | bool ngfound = false; |
| |
|
| | for (std::vector<Part::Geometry*>::const_iterator geo = gvals.begin(); geo != gvals.end(); |
| | geo++, ngeoid++) { |
| | if ((*geo) && (*geo)->getTag() == bsplinetag) { |
| | ngfound = true; |
| | break; |
| | } |
| | } |
| |
|
| | if (ngfound) { |
| | try { |
| | |
| | Gui::cmdAppObjectArgs(selection[0].getObject(), "exposeInternalGeometry(%d)", ngeoid); |
| | } |
| | catch (const Base::Exception& e) { |
| | Gui::NotifyUserError( |
| | Obj, |
| | QT_TRANSLATE_NOOP("Notifications", "Invalid Constraint"), |
| | e.what() |
| | ); |
| | getSelection().clearSelection(); |
| | } |
| | } |
| | } |
| |
|
| | if (!applied) { |
| | abortCommand(); |
| | } |
| | else { |
| | commitCommand(); |
| | } |
| |
|
| | tryAutoRecomputeIfNotSolve(Obj); |
| | getSelection().clearSelection(); |
| | } |
| |
|
| | bool CmdSketcherIncreaseKnotMultiplicity::isActive() |
| | { |
| | return isCommandNeedingBSplineKnotActive(getActiveGuiDocument()); |
| | } |
| |
|
| | DEF_STD_CMD_A(CmdSketcherDecreaseKnotMultiplicity) |
| |
|
| | CmdSketcherDecreaseKnotMultiplicity::CmdSketcherDecreaseKnotMultiplicity() |
| | : Command("Sketcher_BSplineDecreaseKnotMultiplicity") |
| | { |
| | sAppModule = "Sketcher"; |
| | sGroup = "Sketcher"; |
| | sMenuText = QT_TR_NOOP("Decrease Knot Multiplicity"); |
| | sToolTipText = QT_TR_NOOP("Decreases the multiplicity of the selected knot of a B-spline"); |
| | sWhatsThis = "Sketcher_BSplineDecreaseKnotMultiplicity"; |
| | sStatusTip = sToolTipText; |
| | sPixmap = "Sketcher_BSplineDecreaseKnotMultiplicity"; |
| | sAccel = ""; |
| | eType = ForEdit; |
| | } |
| |
|
| | void CmdSketcherDecreaseKnotMultiplicity::activated(int iMsg) |
| | { |
| | Q_UNUSED(iMsg); |
| |
|
| | |
| | std::vector<Gui::SelectionObject> selection; |
| | selection = getSelection().getSelectionEx(nullptr, Sketcher::SketchObject::getClassTypeId()); |
| |
|
| | |
| | if (selection.size() != 1) { |
| | return; |
| | } |
| |
|
| | |
| | const std::vector<std::string>& SubNames = selection[0].getSubNames(); |
| |
|
| | if (SubNames.size() > 1) { |
| | |
| | |
| | Gui::TranslatedUserWarning( |
| | getActiveGuiDocument()->getDocument(), |
| | QObject::tr("Wrong selection"), |
| | QObject::tr("The selection comprises more than one item. Select just one knot.") |
| | ); |
| | return; |
| | } |
| |
|
| | Sketcher::SketchObject* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject()); |
| |
|
| | openCommand(QT_TRANSLATE_NOOP("Command", "Decrease knot multiplicity")); |
| |
|
| | int GeoId; |
| | Sketcher::PointPos PosId; |
| | getIdsFromName(SubNames[0], Obj, GeoId, PosId); |
| |
|
| | int splineGeoId; |
| | int knotIndexOCC; |
| |
|
| | bool applied = false; |
| | bool notaknot = !( |
| | isBsplineKnotOrEndPoint(Obj, GeoId, PosId) |
| | && findBSplineAndKnotIndex(Obj, GeoId, PosId, splineGeoId, knotIndexOCC) |
| | ); |
| | boost::uuids::uuid bsplinetag; |
| |
|
| | if (!notaknot) { |
| | bsplinetag = Obj->getGeometry(splineGeoId)->getTag(); |
| |
|
| | try { |
| | Gui::cmdAppObjectArgs( |
| | selection[0].getObject(), |
| | "modifyBSplineKnotMultiplicity(%d, %d, %d) ", |
| | splineGeoId, |
| | knotIndexOCC, |
| | -1 |
| | ); |
| | applied = true; |
| |
|
| | |
| | |
| | } |
| | catch (const Base::Exception& e) { |
| | Gui::TranslatedUserError( |
| | Obj, |
| | QObject::tr("Error"), |
| | QObject::tr(getStrippedPythonExceptionString(e).c_str()) |
| | ); |
| |
|
| | getSelection().clearSelection(); |
| | } |
| | } |
| |
|
| | if (notaknot) { |
| | Gui::TranslatedUserWarning( |
| | Obj, |
| | QObject::tr("Wrong selection"), |
| | QObject::tr("None of the selected elements is a knot of a B-spline") |
| | ); |
| | } |
| |
|
| | if (applied) { |
| | |
| | const std::vector<Part::Geometry*>& gvals = Obj->getInternalGeometry(); |
| |
|
| | int ngeoid = 0; |
| | bool ngfound = false; |
| |
|
| | for (std::vector<Part::Geometry*>::const_iterator geo = gvals.begin(); geo != gvals.end(); |
| | geo++, ngeoid++) { |
| | if ((*geo) && (*geo)->getTag() == bsplinetag) { |
| | ngfound = true; |
| | break; |
| | } |
| | } |
| |
|
| | if (ngfound) { |
| | try { |
| | |
| | Gui::cmdAppObjectArgs(selection[0].getObject(), "exposeInternalGeometry(%d)", ngeoid); |
| | } |
| | catch (const Base::Exception& e) { |
| | Gui::NotifyUserError( |
| | Obj, |
| | QT_TRANSLATE_NOOP("Notifications", "Invalid Constraint"), |
| | e.what() |
| | ); |
| | getSelection().clearSelection(); |
| | } |
| | } |
| | } |
| |
|
| | if (!applied) { |
| | abortCommand(); |
| | } |
| | else { |
| | commitCommand(); |
| | } |
| |
|
| | tryAutoRecomputeIfNotSolve(Obj); |
| | getSelection().clearSelection(); |
| | } |
| |
|
| | bool CmdSketcherDecreaseKnotMultiplicity::isActive() |
| | { |
| | return isCommandNeedingBSplineKnotActive(getActiveGuiDocument()); |
| | } |
| |
|
| |
|
| | |
| | DEF_STD_CMD_ACLU(CmdSketcherCompModifyKnotMultiplicity) |
| |
|
| | CmdSketcherCompModifyKnotMultiplicity::CmdSketcherCompModifyKnotMultiplicity() |
| | : Command("Sketcher_CompModifyKnotMultiplicity") |
| | { |
| | sAppModule = "Sketcher"; |
| | sGroup = "Sketcher"; |
| | sMenuText = QT_TR_NOOP("Modify Knot Multiplicity"); |
| | sToolTipText = QT_TR_NOOP("Modifies the multiplicity of the selected knot of a B-spline"); |
| | sWhatsThis = "Sketcher_CompModifyKnotMultiplicity"; |
| | sStatusTip = sToolTipText; |
| | eType = ForEdit; |
| | } |
| |
|
| | void CmdSketcherCompModifyKnotMultiplicity::activated(int iMsg) |
| | { |
| |
|
| | Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager(); |
| | Gui::Command* cmd; |
| |
|
| | if (iMsg == 0) { |
| | cmd = rcCmdMgr.getCommandByName("Sketcher_BSplineIncreaseKnotMultiplicity"); |
| | } |
| | else if (iMsg == 1) { |
| | cmd = rcCmdMgr.getCommandByName("Sketcher_BSplineDecreaseKnotMultiplicity"); |
| | } |
| | else { |
| | return; |
| | } |
| |
|
| | cmd->invoke(0); |
| |
|
| | |
| | |
| | Gui::ActionGroup* pcAction = qobject_cast<Gui::ActionGroup*>(_pcAction); |
| | QList<QAction*> a = pcAction->actions(); |
| |
|
| | assert(iMsg < a.size()); |
| | pcAction->setIcon(a[iMsg]->icon()); |
| | } |
| |
|
| | Gui::Action* CmdSketcherCompModifyKnotMultiplicity::createAction() |
| | { |
| | Gui::ActionGroup* pcAction = new Gui::ActionGroup(this, Gui::getMainWindow()); |
| | pcAction->setDropDownMenu(true); |
| | applyCommandData(this->className(), pcAction); |
| |
|
| | QAction* c1 = pcAction->addAction(QString()); |
| | c1->setIcon(Gui::BitmapFactory().iconFromTheme("Sketcher_BSplineIncreaseKnotMultiplicity")); |
| | QAction* c2 = pcAction->addAction(QString()); |
| | c2->setIcon(Gui::BitmapFactory().iconFromTheme("Sketcher_BSplineDecreaseKnotMultiplicity")); |
| |
|
| | _pcAction = pcAction; |
| | languageChange(); |
| |
|
| | pcAction->setIcon(c1->icon()); |
| | int defaultId = 0; |
| | pcAction->setProperty("defaultAction", QVariant(defaultId)); |
| |
|
| | return pcAction; |
| | } |
| |
|
| | void CmdSketcherCompModifyKnotMultiplicity::languageChange() |
| | { |
| | Command::languageChange(); |
| |
|
| | if (!_pcAction) { |
| | return; |
| | } |
| | Gui::ActionGroup* pcAction = qobject_cast<Gui::ActionGroup*>(_pcAction); |
| | QList<QAction*> a = pcAction->actions(); |
| |
|
| | QAction* c1 = a[0]; |
| | c1->setText( |
| | QApplication::translate("CmdSketcherCompModifyKnotMultiplicity", "Increase knot multiplicity") |
| | ); |
| | c1->setToolTip( |
| | QApplication::translate( |
| | "Sketcher_BSplineIncreaseKnotMultiplicity", |
| | "Increases the multiplicity of the selected knot of a B-spline" |
| | ) |
| | ); |
| | c1->setStatusTip( |
| | QApplication::translate( |
| | "Sketcher_BSplineIncreaseKnotMultiplicity", |
| | "Increases the multiplicity of the selected knot of a B-spline" |
| | ) |
| | ); |
| | QAction* c2 = a[1]; |
| | c2->setText( |
| | QApplication::translate("CmdSketcherCompModifyKnotMultiplicity", "Decrease knot multiplicity") |
| | ); |
| | c2->setToolTip( |
| | QApplication::translate( |
| | "Sketcher_BSplineDecreaseKnotMultiplicity", |
| | "Decreases the multiplicity of the selected knot of a B-spline" |
| | ) |
| | ); |
| | c2->setStatusTip( |
| | QApplication::translate( |
| | "Sketcher_BSplineDecreaseKnotMultiplicity", |
| | "Decreases the multiplicity of the selected knot of a B-spline" |
| | ) |
| | ); |
| | } |
| |
|
| | void CmdSketcherCompModifyKnotMultiplicity::updateAction(int ) |
| | {} |
| |
|
| | bool CmdSketcherCompModifyKnotMultiplicity::isActive() |
| | { |
| | return isCommandNeedingBSplineKnotActive(getActiveGuiDocument()); |
| | } |
| |
|
| | class DrawSketchHandlerBSplineInsertKnot: public DrawSketchHandler |
| | { |
| | public: |
| | DrawSketchHandlerBSplineInsertKnot(Sketcher::SketchObject* _Obj, int _GeoId) |
| | : Obj(_Obj) |
| | , GeoId(_GeoId) |
| | , EditMarkers(1) |
| | { |
| | auto bsp = static_cast<const Part::GeomBSplineCurve*>(Obj->getGeometry(GeoId)); |
| | guessParam = bsp->getFirstParameter(); |
| | } |
| |
|
| | ~DrawSketchHandlerBSplineInsertKnot() override |
| | {} |
| |
|
| | void mouseMove(SnapManager::SnapHandle snapHandle) override |
| | { |
| | auto bsp = static_cast<const Part::GeomBSplineCurve*>(Obj->getGeometry(GeoId)); |
| | Base::Vector2d onSketchPos = snapHandle.compute(); |
| |
|
| | |
| | |
| | Base::Vector3d onSketchPos3d(onSketchPos.x, onSketchPos.y, 0.0); |
| | SbString text; |
| | text.sprintf(" %.3f", guessParam); |
| | |
| | |
| | bsp->closestParameter(onSketchPos3d, guessParam); |
| |
|
| | Base::Vector3d pointOnCurve3d = bsp->value(guessParam); |
| |
|
| | |
| | Base::Vector2d pointOnCurve(pointOnCurve3d.x, pointOnCurve3d.y); |
| | setPositionText(pointOnCurve, text); |
| |
|
| | EditMarkers[0] = pointOnCurve; |
| | drawEditMarkers(EditMarkers); |
| |
|
| | applyCursor(); |
| | } |
| |
|
| | bool pressButton(Base::Vector2d ) override |
| | { |
| | |
| | return true; |
| | } |
| |
|
| | bool releaseButton(Base::Vector2d onSketchPos) override |
| | { |
| | Q_UNUSED(onSketchPos); |
| |
|
| | Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Insert knot")); |
| |
|
| | bool applied = false; |
| | boost::uuids::uuid bsplinetag = Obj->getGeometry(GeoId)->getTag(); |
| |
|
| | try { |
| | Gui::cmdAppObjectArgs(Obj, "insertBSplineKnot(%d, %lf, %d) ", GeoId, guessParam, 1); |
| | applied = true; |
| |
|
| | |
| | |
| | |
| | } |
| | catch (const Base::CADKernelError& e) { |
| | e.reportException(); |
| | if (e.getTranslatable()) { |
| | Gui::TranslatedUserError( |
| | Obj, |
| | QObject::tr("CAD Kernel Error"), |
| | QObject::tr(e.getMessage().c_str()) |
| | ); |
| | } |
| | } |
| | catch (const Base::Exception& e) { |
| | e.reportException(); |
| | if (e.getTranslatable()) { |
| | Gui::TranslatedUserError( |
| | Obj, |
| | QObject::tr("Input Error"), |
| | QObject::tr(e.getMessage().c_str()) |
| | ); |
| | } |
| | } |
| |
|
| | int newGeoId = 0; |
| | bool newGeoIdFound = false; |
| |
|
| | if (applied) { |
| | |
| | const std::vector<Part::Geometry*>& gvals = Obj->getInternalGeometry(); |
| |
|
| | for (std::vector<Part::Geometry*>::const_iterator geo = gvals.begin(); geo != gvals.end(); |
| | geo++, newGeoId++) { |
| | if ((*geo) && (*geo)->getTag() == bsplinetag) { |
| | newGeoIdFound = true; |
| | break; |
| | } |
| | } |
| |
|
| | if (newGeoIdFound) { |
| | try { |
| | |
| | Gui::cmdAppObjectArgs(Obj, "exposeInternalGeometry(%d)", newGeoId); |
| | } |
| | catch (const Base::Exception& e) { |
| | Gui::NotifyUserError( |
| | Obj, |
| | QT_TRANSLATE_NOOP("Notifications", "Invalid Constraint"), |
| | e.what() |
| | ); |
| | } |
| | } |
| | } |
| |
|
| | if (applied) { |
| | Gui::Command::commitCommand(); |
| | } |
| | else { |
| | Gui::Command::abortCommand(); |
| | } |
| |
|
| | tryAutoRecomputeIfNotSolve(Obj); |
| |
|
| | ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( |
| | "User parameter:BaseApp/Preferences/Mod/Sketcher" |
| | ); |
| | bool continuousMode = hGrp->GetBool("ContinuousCreationMode", true); |
| | if (continuousMode && newGeoIdFound) { |
| | |
| |
|
| | |
| | GeoId = newGeoId; |
| |
|
| | applyCursor(); |
| | |
| | |
| | |
| | |
| | } |
| | else { |
| | sketchgui->purgeHandler(); |
| | } |
| |
|
| | return true; |
| | } |
| |
|
| | private: |
| | QString getCrosshairCursorSVGName() const override |
| | { |
| | return QStringLiteral("Sketcher_Pointer_InsertKnot"); |
| | } |
| |
|
| | protected: |
| | Sketcher::SketchObject* Obj; |
| | int GeoId; |
| | double guessParam; |
| | std::vector<Base::Vector2d> EditMarkers; |
| | }; |
| |
|
| | DEF_STD_CMD_A(CmdSketcherInsertKnot) |
| |
|
| | CmdSketcherInsertKnot::CmdSketcherInsertKnot() |
| | : Command("Sketcher_BSplineInsertKnot") |
| | { |
| | sAppModule = "Sketcher"; |
| | sGroup = "Sketcher"; |
| | sMenuText = QT_TR_NOOP("Insert Knot"); |
| | sToolTipText = QT_TR_NOOP( |
| | "Inserts a knot at a given parameter. If a knot already exists at that " |
| | "parameter, its multiplicity is increased by 1." |
| | ); |
| | sWhatsThis = "Sketcher_BSplineInsertKnot"; |
| | sStatusTip = sToolTipText; |
| | sPixmap = "Sketcher_BSplineInsertKnot"; |
| | sAccel = ""; |
| | eType = ForEdit; |
| | } |
| |
|
| | void CmdSketcherInsertKnot::activated(int iMsg) |
| | { |
| | Q_UNUSED(iMsg); |
| |
|
| | |
| | std::vector<Gui::SelectionObject> selection; |
| | selection = getSelection().getSelectionEx(nullptr, Sketcher::SketchObject::getClassTypeId()); |
| |
|
| | |
| | |
| | if (selection.size() != 1) { |
| | return; |
| | } |
| |
|
| | |
| | const std::vector<std::string>& SubNames = selection[0].getSubNames(); |
| | if (SubNames.empty()) { |
| | |
| | |
| | Gui::TranslatedUserWarning( |
| | getActiveGuiDocument()->getDocument(), |
| | QObject::tr("Selection is empty"), |
| | QObject::tr("Nothing is selected. Select a B-spline.") |
| | ); |
| |
|
| | return; |
| | } |
| | Sketcher::SketchObject* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject()); |
| |
|
| | |
| | int GeoId = std::atoi(SubNames[0].substr(4, 4000).c_str()) - 1; |
| | const Part::Geometry* geo = Obj->getGeometry(GeoId); |
| |
|
| | if (geo->is<Part::GeomBSplineCurve>()) { |
| | ActivateBSplineHandler( |
| | getActiveGuiDocument(), |
| | new DrawSketchHandlerBSplineInsertKnot(Obj, GeoId) |
| | ); |
| | } |
| | else { |
| | Gui::TranslatedUserWarning( |
| | Obj, |
| | QObject::tr("Wrong selection"), |
| | QObject::tr( |
| | "Select a B-spline to insert a knot (not a knot on it). " |
| | "If the curve is not a B-spline, convert it into one first." |
| | ) |
| | ); |
| | } |
| |
|
| | getSelection().clearSelection(); |
| | } |
| |
|
| | bool CmdSketcherInsertKnot::isActive() |
| | { |
| | return isCommandNeedingBSplineActive(getActiveGuiDocument()); |
| | } |
| |
|
| | DEF_STD_CMD_A(CmdSketcherJoinCurves) |
| |
|
| | CmdSketcherJoinCurves::CmdSketcherJoinCurves() |
| | : Command("Sketcher_JoinCurves") |
| | { |
| | sAppModule = "Sketcher"; |
| | sGroup = "Sketcher"; |
| | sMenuText = QT_TR_NOOP("Join Curves"); |
| | sToolTipText = QT_TR_NOOP("Joins 2 curves at selected end points"); |
| | sWhatsThis = "Sketcher_JoinCurves"; |
| | sStatusTip = sToolTipText; |
| | sPixmap = "Sketcher_JoinCurves"; |
| | sAccel = ""; |
| | eType = ForEdit; |
| | } |
| |
|
| | void CmdSketcherJoinCurves::activated(int iMsg) |
| | { |
| | Q_UNUSED(iMsg); |
| |
|
| | |
| | std::vector<Gui::SelectionObject> selection; |
| | selection = getSelection().getSelectionEx(nullptr, Sketcher::SketchObject::getClassTypeId()); |
| |
|
| | |
| | if (selection.size() != 1) { |
| | return; |
| | } |
| |
|
| | |
| | const std::vector<std::string>& SubNames = selection[0].getSubNames(); |
| |
|
| | int GeoIds[2]; |
| | Sketcher::PointPos PosIds[2]; |
| |
|
| | Sketcher::SketchObject* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject()); |
| |
|
| | switch (SubNames.size()) { |
| | case 0: { |
| | |
| | Gui::TranslatedUserWarning( |
| | Obj, |
| | QObject::tr("Selection is empty"), |
| | QObject::tr("Nothing is selected. Select end points of curves.") |
| | ); |
| | return; |
| | } |
| | case 1: { |
| | std::vector<int> GeoIdList; |
| | std::vector<Sketcher::PointPos> PosIdList; |
| |
|
| | int selGeoId; |
| | Sketcher::PointPos selPosId; |
| |
|
| | getIdsFromName(SubNames[0], Obj, selGeoId, selPosId); |
| |
|
| | Obj->getDirectlyCoincidentPoints(selGeoId, selPosId, GeoIdList, PosIdList); |
| |
|
| | |
| | size_t j = 0; |
| | for (size_t i = 0; i < GeoIdList.size(); ++i) { |
| | if (Sketcher::PointPos::start == PosIdList[i] |
| | || Sketcher::PointPos::end == PosIdList[i]) { |
| | if (j < 2) { |
| | GeoIds[j] = GeoIdList[i]; |
| | PosIds[j] = PosIdList[i]; |
| | ++j; |
| | } |
| | else { |
| | Gui::TranslatedUserWarning( |
| | Obj, |
| | QObject::tr("Too many curves on point"), |
| | QObject::tr( |
| | "Exactly two curves should end at the selected point to be " |
| | "able to join them." |
| | ) |
| | ); |
| |
|
| | return; |
| | } |
| | } |
| | } |
| | if (j < 2) { |
| | Gui::TranslatedUserWarning( |
| | Obj, |
| | QObject::tr("Too few curves on point"), |
| | QObject::tr( |
| | "Exactly two curves should end at the " |
| | "selected point to be able to join them." |
| | ) |
| | ); |
| |
|
| | return; |
| | } |
| |
|
| | break; |
| | } |
| | case 2: { |
| | getIdsFromName(SubNames[0], Obj, GeoIds[0], PosIds[0]); |
| | getIdsFromName(SubNames[1], Obj, GeoIds[1], PosIds[1]); |
| | break; |
| | } |
| | default: { |
| | Gui::TranslatedUserWarning( |
| | Obj, |
| | QObject::tr("Wrong selection"), |
| | QObject::tr("Two end points, or coincident point should be selected.") |
| | ); |
| |
|
| | return; |
| | } |
| | } |
| |
|
| | |
| | |
| | bool tangentConstraintExists = false; |
| | for (const auto& constr : Obj->Constraints.getValues()) { |
| | if (constr->Type == Sketcher::ConstraintType::Tangent |
| | && ((constr->First == GeoIds[0] && constr->FirstPos == PosIds[0] |
| | && constr->Second == GeoIds[1] && constr->SecondPos == PosIds[1]) |
| | || (constr->First == GeoIds[1] && constr->FirstPos == PosIds[1] |
| | && constr->Second == GeoIds[0] && constr->SecondPos == PosIds[0]))) { |
| | tangentConstraintExists = true; |
| | } |
| | } |
| |
|
| | Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Join Curves")); |
| | bool applied = false; |
| |
|
| | try { |
| | Gui::cmdAppObjectArgs( |
| | selection[0].getObject(), |
| | "join(%d, %d, %d, %d, %d) ", |
| | GeoIds[0], |
| | static_cast<int>(PosIds[0]), |
| | GeoIds[1], |
| | static_cast<int>(PosIds[1]), |
| | tangentConstraintExists ? 1 : 0 |
| | ); |
| | applied = true; |
| |
|
| | |
| | } |
| | catch (const Base::Exception& e) { |
| | Gui::TranslatedUserError( |
| | Obj, |
| | QObject::tr("Error"), |
| | QObject::tr(getStrippedPythonExceptionString(e).c_str()) |
| | ); |
| |
|
| | getSelection().clearSelection(); |
| | } |
| |
|
| | if (applied) { |
| | Gui::Command::commitCommand(); |
| | } |
| | else { |
| | Gui::Command::abortCommand(); |
| | } |
| |
|
| | tryAutoRecomputeIfNotSolve(Obj); |
| | getSelection().clearSelection(); |
| | } |
| |
|
| | bool CmdSketcherJoinCurves::isActive() |
| | { |
| | return isCommandNeedingBSplineActive(getActiveGuiDocument()); |
| | } |
| |
|
| | void CreateSketcherCommandsBSpline() |
| | { |
| | Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager(); |
| |
|
| | rcCmdMgr.addCommand(new CmdSketcherConvertToNURBS()); |
| | rcCmdMgr.addCommand(new CmdSketcherIncreaseDegree()); |
| | rcCmdMgr.addCommand(new CmdSketcherDecreaseDegree()); |
| | rcCmdMgr.addCommand(new CmdSketcherIncreaseKnotMultiplicity()); |
| | rcCmdMgr.addCommand(new CmdSketcherDecreaseKnotMultiplicity()); |
| | rcCmdMgr.addCommand(new CmdSketcherCompModifyKnotMultiplicity()); |
| | rcCmdMgr.addCommand(new CmdSketcherInsertKnot()); |
| | rcCmdMgr.addCommand(new CmdSketcherJoinCurves()); |
| | } |
| |
|