From 71b924e7dcbb4dfd077615e7da715ab1b6056efa Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Fri, 12 Apr 2024 08:35:09 +0200 Subject: [PATCH 1/9] Core/Sketcher: Create ToolHandler class in core for core reuse accross other wbs. --- src/Gui/CMakeLists.txt | 2 + src/Gui/ToolHandler.cpp | 299 +++++++++++++++++++++ src/Gui/ToolHandler.h | 127 +++++++++ src/Mod/Sketcher/Gui/DrawSketchHandler.cpp | 263 ++---------------- src/Mod/Sketcher/Gui/DrawSketchHandler.h | 78 +----- 5 files changed, 462 insertions(+), 307 deletions(-) create mode 100644 src/Gui/ToolHandler.cpp create mode 100644 src/Gui/ToolHandler.h diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index cb75c5cc66..57dc5d60d8 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -1217,6 +1217,7 @@ SET(FreeCADGui_CPP_SRCS ManualAlignment.cpp StartupProcess.cpp TransactionObject.cpp + ToolHandler.cpp ) SET(FreeCADGui_SRCS Application.h @@ -1254,6 +1255,7 @@ SET(FreeCADGui_SRCS ManualAlignment.h StartupProcess.h TransactionObject.h + ToolHandler.h ${FreeCADGui_SDK_MOC_HDRS} ) diff --git a/src/Gui/ToolHandler.cpp b/src/Gui/ToolHandler.cpp new file mode 100644 index 0000000000..683d3dc189 --- /dev/null +++ b/src/Gui/ToolHandler.cpp @@ -0,0 +1,299 @@ +/*************************************************************************** + * Copyright (c) 2024 Pierre-Louis Boyer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#include + +#include +#include + +#include +#endif // #ifndef _PreComp_ + +#include +#include + +#include "Application.h" +#include "BitmapFactory.h" +#include "CommandT.h" +#include "MainWindow.h" +#include "View3DInventor.h" +#include "View3DInventorViewer.h" + +#include "ToolHandler.h" + +using namespace Gui; + +/**************************** ToolHandler *******************************************/ +ToolHandler::ToolHandler() +{} + +ToolHandler::~ToolHandler() +{} + +QString ToolHandler::getCrosshairCursorSVGName() const +{ + return QString::fromLatin1("None"); +} + +bool ToolHandler::activate() +{ + // save the cursor at the time the DSH is activated + QWidget* cw = getCursorWidget(); + if (cw) { + oldCursor = cw->cursor(); + + updateCursor(); + + this->preActivated(); + this->activated(); + return true; + } + + return false; +} + +void ToolHandler::deactivate() +{ + this->deactivated(); + this->postDeactivated(); + + unsetCursor(); +} + +//************************************************************************** +// Helpers + +unsigned long ToolHandler::getCrosshairColor() +{ + unsigned long color = 0xFFFFFFFF; // white + ParameterGrp::handle hGrp = + App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); + color = hGrp->GetUnsigned("CursorCrosshairColor", color); + // from rgba to rgb + color = (color >> 8) & 0xFFFFFF; + return color; +} + +void ToolHandler::setCrosshairCursor(const QString& svgName) +{ + const unsigned long defaultCrosshairColor = 0xFFFFFF; + unsigned long color = getCrosshairColor(); + auto colorMapping = std::map(); + colorMapping[defaultCrosshairColor] = color; + // hot spot of all SVG icons should be 8,8 for 32x32 size (16x16 for 64x64) + int hotX = 8; + int hotY = 8; + setSvgCursor(svgName, hotX, hotY, colorMapping); +} + +void ToolHandler::setCrosshairCursor(const char* svgName) +{ + QString cursorName = QString::fromLatin1(svgName); + setCrosshairCursor(cursorName); +} + +void ToolHandler::setSvgCursor(const QString& cursorName, + int x, + int y, + const std::map& colorMapping) +{ + // The TechDraw_Pointer_*.svg icons have a default size of 64x64. When directly creating + // them with a size of 32x32 they look very bad. + // As a workaround the icons are created with 64x64 and afterwards the pixmap is scaled to + // 32x32. This workaround is only needed if pRatio is equal to 1.0 + // + qreal pRatio = devicePixelRatio(); + bool isRatioOne = (pRatio == 1.0); + qreal defaultCursorSize = isRatioOne ? 64 : 32; + qreal hotX = x; + qreal hotY = y; +#if !defined(Q_OS_WIN32) && !defined(Q_OS_MAC) + if (qGuiApp->platformName() == QLatin1String("xcb")) { + hotX *= pRatio; + hotY *= pRatio; + } +#endif + qreal cursorSize = defaultCursorSize * pRatio; + + QPixmap pointer = Gui::BitmapFactory().pixmapFromSvg(cursorName.toStdString().c_str(), + QSizeF(cursorSize, cursorSize), + colorMapping); + if (isRatioOne) { + pointer = pointer.scaled(32, 32); + } + pointer.setDevicePixelRatio(pRatio); + setCursor(pointer, hotX, hotY, false); +} + +void ToolHandler::setCursor(const QPixmap& p, int x, int y, bool autoScale) +{ + + QWidget* cw = getCursorWidget(); + if (cw) { + QCursor cursor; + QPixmap p1(p); + // TODO remove autoScale after all cursors are SVG-based + if (autoScale) { + qreal pRatio = devicePixelRatio(); + int newWidth = p.width() * pRatio; + int newHeight = p.height() * pRatio; + p1 = p1.scaled(newWidth, newHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation); + p1.setDevicePixelRatio(pRatio); + qreal hotX = x; + qreal hotY = y; +#if !defined(Q_OS_WIN32) && !defined(Q_OS_MAC) + if (qGuiApp->platformName() == QLatin1String("xcb")) { + hotX *= pRatio; + hotY *= pRatio; + } +#endif + cursor = QCursor(p1, hotX, hotY); + } + else { + // already scaled + cursor = QCursor(p1, x, y); + } + + actCursor = cursor; + actCursorPixmap = p1; + + setWidgetCursor(cursor); + } +} + +void ToolHandler::addCursorTail(std::vector& pixmaps) +{ + // Create a pixmap that will contain icon and each autoconstraint icon + Gui::MDIView* view = Gui::getMainWindow()->activeWindow(); + if (view && view->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) { + QPixmap baseIcon = QPixmap(actCursorPixmap); + baseIcon.setDevicePixelRatio(actCursorPixmap.devicePixelRatio()); + qreal pixelRatio = baseIcon.devicePixelRatio(); + // cursor size in device independent pixels + qreal baseCursorWidth = baseIcon.width(); + qreal baseCursorHeight = baseIcon.height(); + + int tailWidth = 0; + for (auto const& p : pixmaps) { + tailWidth += p.width(); + } + + int newIconWidth = baseCursorWidth + tailWidth; + int newIconHeight = baseCursorHeight; + + QPixmap newIcon(newIconWidth, newIconHeight); + newIcon.fill(Qt::transparent); + + QPainter qp; + qp.begin(&newIcon); + + qp.drawPixmap(QPointF(0, 0), + baseIcon.scaled(baseCursorWidth * pixelRatio, + baseCursorHeight * pixelRatio, + Qt::KeepAspectRatio, + Qt::SmoothTransformation)); + + // Iterate through pixmaps and them to the cursor pixmap + std::vector::iterator pit = pixmaps.begin(); + int i = 0; + qreal currentIconX = baseCursorWidth; + qreal currentIconY; + + for (; pit != pixmaps.end(); ++pit, i++) { + QPixmap icon = *pit; + currentIconY = baseCursorHeight - icon.height(); + qp.drawPixmap(QPointF(currentIconX, currentIconY), icon); + currentIconX += icon.width(); + } + + qp.end(); // Finish painting + + // Create the new cursor with the icon. + QPoint p = actCursor.hotSpot(); + newIcon.setDevicePixelRatio(pixelRatio); + QCursor newCursor(newIcon, p.x(), p.y()); + applyCursor(newCursor); + } +} + +void ToolHandler::updateCursor() +{ + auto cursorstring = getCrosshairCursorSVGName(); + + if (cursorstring != QString::fromLatin1("None")) { + setCrosshairCursor(cursorstring); + } +} + +void ToolHandler::applyCursor() +{ + applyCursor(actCursor); +} + +void ToolHandler::applyCursor(QCursor& newCursor) +{ + setWidgetCursor(newCursor); +} + +void ToolHandler::unsetCursor() +{ + setWidgetCursor(oldCursor); +} + +qreal ToolHandler::devicePixelRatio() +{ + qreal pixelRatio = 1; + + QWidget* cw = getCursorWidget(); + if (cw) { + pixelRatio = cw->devicePixelRatio(); + } + return pixelRatio; +} + +QWidget* ToolHandler::getCursorWidget() +{ + Gui::View3DInventorViewer* viewer = getViewer(); + if (viewer) { + return viewer->getWidget(); + } + return nullptr; +} + +void ToolHandler::setWidgetCursor(QCursor cursor) +{ + QWidget* cw = getCursorWidget(); + if (cw) { + cw->setCursor(cursor); + } +} + +Gui::View3DInventorViewer* ToolHandler::getViewer() +{ + Gui::MDIView* view = Gui::getMainWindow()->activeWindow(); + if (view && view->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) { + return static_cast(view)->getViewer(); + } + return nullptr; +} diff --git a/src/Gui/ToolHandler.h b/src/Gui/ToolHandler.h new file mode 100644 index 0000000000..4532bc3a54 --- /dev/null +++ b/src/Gui/ToolHandler.h @@ -0,0 +1,127 @@ +/*************************************************************************** + * Copyright (c) 2024 Pierre-Louis Boyer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef GUI_ToolHandler_H +#define GUI_ToolHandler_H + +#include +#include + +#include +#include + +#include "Selection.h" + + +namespace Gui +{ +class View3DInventorViewer; + + +class GuiExport ToolHandler +{ +public: + ToolHandler(); + virtual ~ToolHandler(); + + bool activate(); + virtual void deactivate(); + + virtual void quit() + {} + + /// updates the actCursor with the icon by calling getCrosshairCursorSVGName(), + /// enabling to set data member dependent icons (i.e. for different construction methods) + void updateCursor(); + +private: // NVI + virtual void preActivated() + {} + virtual void activated() + {} + virtual void deactivated() + {} + virtual void postDeactivated() + {} + +protected: // NVI requiring base implementation + virtual QString getCrosshairCursorSVGName() const; + + +protected: + // helpers + /** + * Sets a cursor for 3D inventor view. + * pixmap as a cursor image in device independent pixels. + * + * \param autoScale - set this to false if pixmap already scaled for HiDPI + **/ + + /** @name Icon helpers */ + //@{ + void setCursor(const QPixmap& pixmap, int x, int y, bool autoScale = true); + + + void unsetCursor(); + + /// restitutes the DSH cached cursor (without any tail due to autoconstraints, ...) + void applyCursor(); + + void addCursorTail(std::vector& pixmaps); + + /// returns the color to be used for the crosshair (configurable as a parameter) + unsigned long getCrosshairColor(); + + /// functions to set the cursor to a given svgName (to be migrated to NVI style) + + qreal devicePixelRatio(); + //@} + + View3DInventorViewer* getViewer(); + + virtual QWidget* getCursorWidget(); + + virtual void setWidgetCursor(QCursor cursor); + +private: + void setSvgCursor(const QString& svgName, int x, int y, + const std::map& colorMapping = + std::map()); + + + void applyCursor(QCursor& newCursor); + + void setCrosshairCursor(const QString& svgName); + void setCrosshairCursor(const char* svgName); + +protected: + + QCursor oldCursor; + QCursor actCursor; + QPixmap actCursorPixmap; +}; + + +} // namespace Gui + + +#endif // GUI_ToolHandler_H diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp index 9bf503e569..f9799f4bcd 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp +++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp @@ -270,7 +270,8 @@ void CurveConverter::OnChange(Base::Subject& rCaller, const char* s // Construction/Destruction DrawSketchHandler::DrawSketchHandler() - : sketchgui(nullptr) + : Gui::ToolHandler() + , sketchgui(nullptr) {} DrawSketchHandler::~DrawSketchHandler() @@ -281,11 +282,6 @@ std::string DrawSketchHandler::getToolName() const return "DSH_None"; } -QString DrawSketchHandler::getCrosshairCursorSVGName() const -{ - return QString::fromLatin1("None"); -} - std::unique_ptr DrawSketchHandler::createWidget() const { return nullptr; @@ -311,36 +307,20 @@ void DrawSketchHandler::activate(ViewProviderSketch* vp) { sketchgui = vp; - // save the cursor at the time the DSH is activated - auto* view = dynamic_cast(Gui::getMainWindow()->activeWindow()); - - if (view) { - Gui::View3DInventorViewer* viewer = dynamic_cast(view)->getViewer(); - oldCursor = viewer->getWidget()->cursor(); - - updateCursor(); - - this->signalToolChanged(); - - this->preActivated(); - this->activated(); - } - else { + if (!Gui::ToolHandler::activate()) { sketchgui->purgeHandler(); } } void DrawSketchHandler::deactivate() { - this->deactivated(); - this->postDeactivated(); + Gui::ToolHandler::deactivate(); ViewProviderSketchDrawSketchHandlerAttorney::setConstraintSelectability(*sketchgui, true); // clear temporary Curve and Markers from the scenograph clearEdit(); clearEditMarkers(); resetPositionText(); - unsetCursor(); setAngleSnapping(false); ViewProviderSketchDrawSketchHandlerAttorney::signalToolChanged(*sketchgui, "DSH_None"); @@ -348,25 +328,10 @@ void DrawSketchHandler::deactivate() void DrawSketchHandler::preActivated() { + this->signalToolChanged(); ViewProviderSketchDrawSketchHandlerAttorney::setConstraintSelectability(*sketchgui, false); } -void DrawSketchHandler::quit() -{ - assert(sketchgui); - - Gui::Selection().rmvSelectionGate(); - Gui::Selection().rmvPreselect(); - - sketchgui->purgeHandler(); -} - -void DrawSketchHandler::toolWidgetChanged(QWidget* newwidget) -{ - toolwidget = newwidget; - onWidgetChanged(); -} - void DrawSketchHandler::registerPressedKey(bool pressed, int key) { // the default behaviour is to quit - specific handler categories may @@ -383,6 +348,23 @@ void DrawSketchHandler::pressRightButton(Base::Vector2d /*onSketchPos*/) quit(); } + +void DrawSketchHandler::quit() +{ + assert(sketchgui); + + Gui::Selection().rmvSelectionGate(); + Gui::Selection().rmvPreselect(); + + sketchgui->purgeHandler(); +} + +void DrawSketchHandler::toolWidgetChanged(QWidget* newwidget) +{ + toolwidget = newwidget; + onWidgetChanged(); +} + //************************************************************************** // Helpers @@ -396,198 +378,6 @@ int DrawSketchHandler::getHighestCurveIndex() return sketchgui->getSketchObject()->getHighestCurveIndex(); } -unsigned long DrawSketchHandler::getCrosshairColor() -{ - unsigned long color = 0xFFFFFFFF; // white - ParameterGrp::handle hGrp = - App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); - color = hGrp->GetUnsigned("CursorCrosshairColor", color); - // from rgba to rgb - color = (color >> 8) & 0xFFFFFF; - return color; -} - -void DrawSketchHandler::setCrosshairCursor(const QString& svgName) -{ - const unsigned long defaultCrosshairColor = 0xFFFFFF; - unsigned long color = getCrosshairColor(); - auto colorMapping = std::map(); - colorMapping[defaultCrosshairColor] = color; - // hot spot of all SVG icons should be 8,8 for 32x32 size (16x16 for 64x64) - int hotX = 8; - int hotY = 8; - setSvgCursor(svgName, hotX, hotY, colorMapping); -} - -void DrawSketchHandler::setCrosshairCursor(const char* svgName) -{ - QString cursorName = QString::fromLatin1(svgName); - setCrosshairCursor(cursorName); -} - -void DrawSketchHandler::setSvgCursor(const QString& cursorName, - int x, - int y, - const std::map& colorMapping) -{ - // The Sketcher_Pointer_*.svg icons have a default size of 64x64. When directly creating - // them with a size of 32x32 they look very bad. - // As a workaround the icons are created with 64x64 and afterwards the pixmap is scaled to - // 32x32. This workaround is only needed if pRatio is equal to 1.0 - // - qreal pRatio = devicePixelRatio(); - bool isRatioOne = (pRatio == 1.0); - qreal defaultCursorSize = isRatioOne ? 64 : 32; - qreal hotX = x; - qreal hotY = y; -#if !defined(Q_OS_WIN32) && !defined(Q_OS_MAC) - if (qGuiApp->platformName() == QLatin1String("xcb")) { - hotX *= pRatio; - hotY *= pRatio; - } -#endif - qreal cursorSize = defaultCursorSize * pRatio; - - QPixmap pointer = Gui::BitmapFactory().pixmapFromSvg(cursorName.toStdString().c_str(), - QSizeF(cursorSize, cursorSize), - colorMapping); - if (isRatioOne) { - pointer = pointer.scaled(32, 32); - } - pointer.setDevicePixelRatio(pRatio); - setCursor(pointer, hotX, hotY, false); -} - -void DrawSketchHandler::setCursor(const QPixmap& p, int x, int y, bool autoScale) -{ - Gui::View3DInventorViewer* viewer = getViewer(); - if (viewer) { - QCursor cursor; - QPixmap p1(p); - // TODO remove autoScale after all cursors are SVG-based - if (autoScale) { - qreal pRatio = viewer->devicePixelRatio(); - int newWidth = p.width() * pRatio; - int newHeight = p.height() * pRatio; - p1 = p1.scaled(newWidth, newHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation); - p1.setDevicePixelRatio(pRatio); - qreal hotX = x; - qreal hotY = y; -#if !defined(Q_OS_WIN32) && !defined(Q_OS_MAC) - if (qGuiApp->platformName() == QLatin1String("xcb")) { - hotX *= pRatio; - hotY *= pRatio; - } -#endif - cursor = QCursor(p1, hotX, hotY); - } - else { - // already scaled - cursor = QCursor(p1, x, y); - } - - actCursor = cursor; - actCursorPixmap = p1; - - viewer->getWidget()->setCursor(cursor); - } -} - -void DrawSketchHandler::addCursorTail(std::vector& pixmaps) -{ - // Create a pixmap that will contain icon and each autoconstraint icon - Gui::MDIView* view = Gui::getMainWindow()->activeWindow(); - if (view && view->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) { - QPixmap baseIcon = QPixmap(actCursorPixmap); - baseIcon.setDevicePixelRatio(actCursorPixmap.devicePixelRatio()); - qreal pixelRatio = baseIcon.devicePixelRatio(); - // cursor size in device independent pixels - qreal baseCursorWidth = baseIcon.width(); - qreal baseCursorHeight = baseIcon.height(); - - int tailWidth = 0; - for (auto const& p : pixmaps) { - tailWidth += p.width(); - } - - int newIconWidth = baseCursorWidth + tailWidth; - int newIconHeight = baseCursorHeight; - - QPixmap newIcon(newIconWidth, newIconHeight); - newIcon.fill(Qt::transparent); - - QPainter qp; - qp.begin(&newIcon); - - qp.drawPixmap(QPointF(0, 0), - baseIcon.scaled(baseCursorWidth * pixelRatio, - baseCursorHeight * pixelRatio, - Qt::KeepAspectRatio, - Qt::SmoothTransformation)); - - // Iterate through pixmaps and them to the cursor pixmap - std::vector::iterator pit = pixmaps.begin(); - int i = 0; - qreal currentIconX = baseCursorWidth; - qreal currentIconY; - - for (; pit != pixmaps.end(); ++pit, i++) { - QPixmap icon = *pit; - currentIconY = baseCursorHeight - icon.height(); - qp.drawPixmap(QPointF(currentIconX, currentIconY), icon); - currentIconX += icon.width(); - } - - qp.end(); // Finish painting - - // Create the new cursor with the icon. - QPoint p = actCursor.hotSpot(); - newIcon.setDevicePixelRatio(pixelRatio); - QCursor newCursor(newIcon, p.x(), p.y()); - applyCursor(newCursor); - } -} - -void DrawSketchHandler::updateCursor() -{ - auto cursorstring = getCrosshairCursorSVGName(); - - if (cursorstring != QString::fromLatin1("None")) { - setCrosshairCursor(cursorstring); - } -} - -void DrawSketchHandler::applyCursor() -{ - applyCursor(actCursor); -} - -void DrawSketchHandler::applyCursor(QCursor& newCursor) -{ - Gui::View3DInventorViewer* viewer = getViewer(); - if (viewer) { - viewer->getWidget()->setCursor(newCursor); - } -} - -void DrawSketchHandler::unsetCursor() -{ - Gui::View3DInventorViewer* viewer = getViewer(); - if (viewer) { - viewer->getWidget()->setCursor(oldCursor); - } -} - -qreal DrawSketchHandler::devicePixelRatio() -{ - qreal pixelRatio = 1; - Gui::View3DInventorViewer* viewer = getViewer(); - if (viewer) { - pixelRatio = viewer->devicePixelRatio(); - } - return pixelRatio; -} - std::vector DrawSketchHandler::suggestedConstraintsPixmaps(std::vector& suggestedConstraints) { @@ -1284,12 +1074,3 @@ void DrawSketchHandler::signalToolChanged() const { ViewProviderSketchDrawSketchHandlerAttorney::signalToolChanged(*sketchgui, this->getToolName()); } - -Gui::View3DInventorViewer* DrawSketchHandler::getViewer() -{ - Gui::MDIView* view = Gui::getMainWindow()->activeWindow(); - if (view && view->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) { - return static_cast(view)->getViewer(); - } - return nullptr; -} diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.h b/src/Mod/Sketcher/Gui/DrawSketchHandler.h index c12a39e3c2..ab66917f07 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandler.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -137,26 +138,28 @@ private: * implemented in DrawSketchHandler and used from its derived classes by virtue of the inheritance. * This promotes a concentrating the coupling in a single point (and code reuse). */ -class SketcherGuiExport DrawSketchHandler +class SketcherGuiExport DrawSketchHandler: public Gui::ToolHandler { public: DrawSketchHandler(); virtual ~DrawSketchHandler(); void activate(ViewProviderSketch*); - void deactivate(); + void deactivate() override; + + virtual void mouseMove(Base::Vector2d pos) = 0; + virtual bool pressButton(Base::Vector2d pos) = 0; + virtual bool releaseButton(Base::Vector2d pos) = 0; + + virtual void registerPressedKey(bool pressed, int key); + virtual void pressRightButton(Base::Vector2d pos); - virtual void mouseMove(Base::Vector2d onSketchPos) = 0; - virtual bool pressButton(Base::Vector2d onSketchPos) = 0; - virtual bool releaseButton(Base::Vector2d onSketchPos) = 0; virtual bool onSelectionChanged(const Gui::SelectionChanges&) { return false; } - virtual void registerPressedKey(bool pressed, int key); - virtual void pressRightButton(Base::Vector2d onSketchPos); - virtual void quit(); + void quit() override; friend class ViewProviderSketch; @@ -215,19 +218,12 @@ public: //@} private: // NVI - virtual void preActivated(); - virtual void activated() - {} - virtual void deactivated() - {} - virtual void postDeactivated() - {} + void preActivated() override; virtual void onWidgetChanged() {} protected: // NVI requiring base implementation virtual std::string getToolName() const; - virtual QString getCrosshairCursorSVGName() const; virtual std::unique_ptr createWidget() const; virtual bool isWidgetVisible() const; @@ -235,37 +231,6 @@ protected: // NVI requiring base implementation virtual QString getToolWidgetText() const; protected: - // helpers - /** - * Sets a cursor for 3D inventor view. - * pixmap as a cursor image in device independent pixels. - * - * \param autoScale - set this to false if pixmap already scaled for HiDPI - **/ - - /** @name Icon helpers */ - //@{ - void setCursor(const QPixmap& pixmap, int x, int y, bool autoScale = true); - - /// updates the actCursor with the icon by calling getCrosshairCursorSVGName(), - /// enabling to set data member dependent icons (i.e. for different construction methods) - void updateCursor(); - - /// restitutes the cursor that was in use at the moment of starting the DrawSketchHandler (i.e. - /// oldCursor) - void unsetCursor(); - - /// restitutes the DSH cached cursor (e.g. without any tail due to autoconstraints, ...) - void applyCursor(); - - /// returns the color to be used for the crosshair (configurable as a parameter) - unsigned long getCrosshairColor(); - - /// functions to set the cursor to a given svgName (to be migrated to NVI style) - - qreal devicePixelRatio(); - //@} - void drawEdit(const std::vector& EditCurve) const; void drawEdit(const std::list>& list) const; void drawEdit(const std::vector& geometries) const; @@ -300,22 +265,6 @@ protected: void signalToolChanged() const; - Gui::View3DInventorViewer* getViewer(); - -private: - void setSvgCursor(const QString& svgName, - int x, - int y, - const std::map& colorMapping = - std::map()); - - void addCursorTail(std::vector& pixmaps); - - void applyCursor(QCursor& newCursor); - - void setCrosshairCursor(const QString& svgName); - void setCrosshairCursor(const char* svgName); - protected: /** @@ -325,9 +274,6 @@ protected: suggestedConstraintsPixmaps(std::vector& suggestedConstraints); ViewProviderSketch* sketchgui; - QCursor oldCursor; - QCursor actCursor; - QPixmap actCursorPixmap; QWidget* toolwidget; }; From 4ecd54275b604d49eb59f239d2348967bb832233 Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Mon, 15 Apr 2024 15:54:20 +0200 Subject: [PATCH 2/9] Sketcher: Dimension : little fixes --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 409c43b89b..c29345db24 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -1376,6 +1376,7 @@ public: , selLine({}) , selCircleArc({}) , selEllipseAndCo({}) + , selSplineAndCo({}) , initialSelection(std::move(SubNames)) , numberOfConstraintsCreated(0) { @@ -1616,6 +1617,15 @@ protected: Sketcher::SketchObject* Obj; + void clearRefVectors() + { + selPoints.clear(); + selLine.clear(); + selCircleArc.clear(); + selEllipseAndCo.clear(); + selSplineAndCo.clear(); + } + void handleInitialSelection() { if (initialSelection.size() == 0) { @@ -1648,11 +1658,7 @@ protected: bool selAllowed = makeAppropriateConstraint(Base::Vector2d(0.,0.)); if (!selAllowed) { - selPoints.clear(); - selLine.clear(); - selCircleArc.clear(); - selEllipseAndCo.clear(); - selSplineAndCo.clear(); + clearRefVectors(); } } @@ -1686,10 +1692,7 @@ protected: numberOfConstraintsCreated = 0; specialConstraint = SpecialConstraint::None; previousOnSketchPos = Base::Vector2d(0.f, 0.f); - selPoints.clear(); - selLine.clear(); - selCircleArc.clear(); - selEllipseAndCo.clear(); + clearRefVectors(); } else { sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider From 57bc4babea30f7384a2e6e6630852d21a26e2322 Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Thu, 18 Apr 2024 19:08:02 +0200 Subject: [PATCH 3/9] TechDraw: Implement smart dimension tool. --- src/Mod/TechDraw/App/DimensionReferences.cpp | 19 + src/Mod/TechDraw/App/DimensionReferences.h | 4 + src/Mod/TechDraw/Gui/AppTechDrawGui.cpp | 2 +- src/Mod/TechDraw/Gui/CMakeLists.txt | 3 + src/Mod/TechDraw/Gui/CommandCreateDims.cpp | 960 +++++++++++++++++- src/Mod/TechDraw/Gui/CommandExtensionDims.cpp | 134 +-- src/Mod/TechDraw/Gui/CommandExtensionDims.h | 35 + .../Gui/DlgPrefsTechDrawDimensions.ui | 60 +- .../Gui/DlgPrefsTechDrawDimensionsImp.cpp | 92 ++ .../Gui/DlgPrefsTechDrawDimensionsImp.h | 1 + src/Mod/TechDraw/Gui/MDIViewPage.cpp | 309 +++--- src/Mod/TechDraw/Gui/MDIViewPage.h | 3 + src/Mod/TechDraw/Gui/PreferencesGui.cpp | 4 +- src/Mod/TechDraw/Gui/QGVPage.cpp | 76 +- src/Mod/TechDraw/Gui/QGVPage.h | 6 + src/Mod/TechDraw/Gui/Resources/TechDraw.qrc | 1 + .../Resources/icons/TechDraw_Dimension.svg | 247 ++--- .../icons/TechDraw_Dimension_Pointer.svg | 146 +++ src/Mod/TechDraw/Gui/TechDrawHandler.cpp | 107 ++ src/Mod/TechDraw/Gui/TechDrawHandler.h | 66 ++ src/Mod/TechDraw/Gui/Workbench.cpp | 36 +- 21 files changed, 1941 insertions(+), 370 deletions(-) create mode 100644 src/Mod/TechDraw/Gui/CommandExtensionDims.h create mode 100644 src/Mod/TechDraw/Gui/Resources/icons/TechDraw_Dimension_Pointer.svg create mode 100644 src/Mod/TechDraw/Gui/TechDrawHandler.cpp create mode 100644 src/Mod/TechDraw/Gui/TechDrawHandler.h diff --git a/src/Mod/TechDraw/App/DimensionReferences.cpp b/src/Mod/TechDraw/App/DimensionReferences.cpp index 3cfed7f2f8..0ff93e4819 100644 --- a/src/Mod/TechDraw/App/DimensionReferences.cpp +++ b/src/Mod/TechDraw/App/DimensionReferences.cpp @@ -86,6 +86,12 @@ ReferenceEntry& ReferenceEntry::operator=(const ReferenceEntry& otherRef) } +bool ReferenceEntry::operator==(const ReferenceEntry& otherRef) const +{ + return getObjectName() == otherRef.getObjectName() && getSubName() == otherRef.getSubName(); +} + + TopoDS_Shape ReferenceEntry::getGeometry() const { // Base::Console().Message("RE::getGeometry() - objectName: %s sub: **%s**\n", @@ -259,6 +265,19 @@ std::string ReferenceEntry::geomType() const return DrawUtil::getGeomTypeFromName(getSubName()); } +GeomType ReferenceEntry::geomEdgeType() const +{ + int geoId = TechDraw::DrawUtil::getIndexFromName(getSubName()); + auto dvp = static_cast(getObject()); + BaseGeomPtr geom = dvp->getGeomByIndex(geoId); + + if (geomType() == "Edge" && geom) { + return geom->getGeomType(); + } + + return GeomType::NOTDEF; +} + bool ReferenceEntry::isWholeObject() const { return getSubName().empty(); diff --git a/src/Mod/TechDraw/App/DimensionReferences.h b/src/Mod/TechDraw/App/DimensionReferences.h index 19b1a11681..47943623f6 100644 --- a/src/Mod/TechDraw/App/DimensionReferences.h +++ b/src/Mod/TechDraw/App/DimensionReferences.h @@ -33,6 +33,7 @@ #include #include +#include namespace App { @@ -59,6 +60,7 @@ public: ~ReferenceEntry() = default; ReferenceEntry& operator= (const ReferenceEntry& otherRef); + bool operator== (const ReferenceEntry& otherRef) const; App::DocumentObject* getObject() const; void setObject(App::DocumentObject* docObj) { m_object = docObj; } @@ -71,6 +73,8 @@ public: TopoDS_Shape getGeometry() const; std::string geomType() const; + GeomType geomEdgeType() const; + bool isWholeObject() const; Part::TopoShape asTopoShape() const; diff --git a/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp b/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp index 0b4feec49e..89263a47fa 100644 --- a/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp +++ b/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp @@ -125,11 +125,11 @@ PyMOD_INIT_FUNC(TechDrawGui) // instantiating the commands CreateTechDrawCommands(); - CreateTechDrawCommandsDims(); CreateTechDrawCommandsDecorate(); CreateTechDrawCommandsAnnotate(); CreateTechDrawCommandsExtensionDims(); CreateTechDrawCommandsExtensions(); + CreateTechDrawCommandsDims(); CreateTechDrawCommandsStack(); TechDrawGui::Workbench::init(); diff --git a/src/Mod/TechDraw/Gui/CMakeLists.txt b/src/Mod/TechDraw/Gui/CMakeLists.txt index fbd3c490c6..2951db9ad5 100644 --- a/src/Mod/TechDraw/Gui/CMakeLists.txt +++ b/src/Mod/TechDraw/Gui/CMakeLists.txt @@ -102,6 +102,7 @@ SET(TechDrawGui_SRCS CommandDecorate.cpp CommandAnnotate.cpp CommandExtensionDims.cpp + CommandExtensionDims.h CommandExtensionPack.cpp CommandStack.cpp DimensionValidators.cpp @@ -223,6 +224,8 @@ SET(TechDrawGui_SRCS TaskCosmeticCircle.cpp TaskCosmeticCircle.h TaskCosmeticCircle.ui + TechDrawHandler.cpp + TechDrawHandler.h Widgets/CompassDialWidget.cpp Widgets/CompassDialWidget.h Widgets/CompassWidget.cpp diff --git a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp index 5b32915763..07e4e32630 100644 --- a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp +++ b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp @@ -46,21 +46,30 @@ #include #include #include +#include #include #include #include #include +#include "CommandExtensionDims.h" #include "DimensionValidators.h" #include "DrawGuiUtil.h" +#include "QGIViewDimension.h" +#include "QGVPage.h" +#include "MDIViewPage.h" #include "TaskDimRepair.h" #include "TaskLinkDim.h" +#include "TechDrawHandler.h" +#include "ViewProviderDimension.h" +#include "ViewProviderDrawingView.h" +#include "ViewProviderDrawingView.h" using namespace TechDrawGui; using namespace TechDraw; using namespace std; - +using DimensionType = TechDraw::DrawViewDimension::DimensionType; //=========================================================================== // utility routines @@ -82,16 +91,881 @@ void execExtent(Gui::Command* cmd, int direction); DrawViewDimension* dimensionMaker(TechDraw::DrawViewPart* dvp, std::string dimType, ReferenceVector references2d, ReferenceVector references3d); +DrawViewDimension* dimMaker(TechDraw::DrawViewPart* dvp, std::string dimType, + ReferenceVector references2d, ReferenceVector references3d); void positionDimText(DrawViewDimension* dim); -//NOTE: this is not shown in toolbar and doesn't always work right in the menu. -// should be removed. +void activateHandler(TechDrawHandler* newHandler) +{ + auto* mdi = dynamic_cast(Gui::getMainWindow()->activeWindow()); + if (!mdi) { + return; + } + + ViewProviderPage* vp = mdi->getViewProviderPage(); + if (!vp) { + return; + } + + QGVPage* viewPage = vp->getQGVPage(); + if (!viewPage) { + return; + } + viewPage->activateHandler(newHandler); +} + //=========================================================================== -// TechDraw_NewDimension +// TechDraw_Dimension //=========================================================================== -// this is deprecated. use individual add dimension commands. +class GeomSelectionSizes +{ +public: + GeomSelectionSizes(size_t s_pts, size_t s_lns, size_t s_cir, size_t s_ell, size_t s_spl, size_t s_fcs) : + s_pts(s_pts), s_lns(s_lns), s_cir(s_cir), s_ell(s_ell), s_spl(s_spl), s_fcs(s_fcs) {} + ~GeomSelectionSizes() {} + + bool hasPoints() const { return s_pts > 0; } + bool hasLines() const { return s_lns > 0; } + bool hasCirclesOrArcs() const { return s_cir > 0; } + bool hasEllipseAndCo() const { return s_ell > 0; } + bool hasSplineAndCo() const { return s_spl > 0; } + bool hasFaces() const { return s_fcs > 0; } + + bool has1Face() const { return s_pts == 0 && s_lns == 0 && s_cir == 0 && s_ell == 0 && s_spl == 0 && s_fcs == 1; } + + bool has1Point() const { return s_pts == 1 && s_lns == 0 && s_cir == 0 && s_ell == 0 && s_spl == 0 && s_fcs == 0; } + bool has2Points() const { return s_pts == 2 && s_lns == 0 && s_cir == 0 && s_ell == 0 && s_spl == 0 && s_fcs == 0; } + bool has1Point1Line() const { return s_pts == 1 && s_lns == 1 && s_cir == 0 && s_ell == 0 && s_spl == 0 && s_fcs == 0; } + bool has3Points() const { return s_pts == 3 && s_lns == 0 && s_cir == 0 && s_ell == 0 && s_spl == 0 && s_fcs == 0; } + bool has4MorePoints() const { return s_pts >= 4 && s_lns == 0 && s_cir == 0 && s_ell == 0 && s_spl == 0 && s_fcs == 0; } + bool has2Points1Line() const { return s_pts == 2 && s_lns == 1 && s_cir == 0 && s_ell == 0 && s_spl == 0 && s_fcs == 0; } + bool has3MorePoints1Line() const { return s_pts >= 3 && s_lns == 1 && s_cir == 0 && s_ell == 0 && s_spl == 0 && s_fcs == 0; } + bool has1Point1Circle() const { return s_pts == 1 && s_lns == 0 && s_cir == 1 && s_ell == 0 && s_spl == 0 && s_fcs == 0; } + bool has1Point1Ellipse() const { return s_pts == 1 && s_lns == 0 && s_cir == 0 && s_ell == 1 && s_spl == 0 && s_fcs == 0; } + + bool has1Line() const { return s_pts == 0 && s_lns == 1 && s_cir == 0 && s_ell == 0 && s_spl == 0 && s_fcs == 0; } + bool has2Lines() const { return s_pts == 0 && s_lns == 2 && s_cir == 0 && s_ell == 0 && s_spl == 0 && s_fcs == 0; } + bool has3MoreLines() const { return s_pts == 0 && s_lns >= 3 && s_cir == 0 && s_ell == 0 && s_spl == 0 && s_fcs == 0; } + bool has1Line1Circle() const { return s_pts == 0 && s_lns == 1 && s_cir == 1 && s_ell == 0 && s_spl == 0 && s_fcs == 0; } + bool has1Line2Circles() const { return s_pts == 0 && s_lns == 1 && s_cir == 2 && s_ell == 0 && s_spl == 0 && s_fcs == 0; } + bool has1Line1Ellipse() const { return s_pts == 0 && s_lns == 1 && s_cir == 0 && s_ell == 1 && s_spl == 0 && s_fcs == 0; } + + bool has1Circle() const { return s_pts == 0 && s_lns == 0 && s_cir == 1 && s_ell == 0 && s_spl == 0 && s_fcs == 0; } + bool has2Circles() const { return s_pts == 0 && s_lns == 0 && s_cir == 2 && s_ell == 0 && s_spl == 0 && s_fcs == 0; } + bool has3MoreCircles() const { return s_pts == 0 && s_lns == 0 && s_cir >= 3 && s_ell == 0 && s_spl == 0 && s_fcs == 0; } + bool has1Circle1Ellipse() const { return s_pts == 0 && s_lns == 0 && s_cir == 1 && s_ell == 1 && s_spl == 0 && s_fcs == 0; } + + bool has1Ellipse() const { return s_pts == 0 && s_lns == 0 && s_cir == 0 && s_ell == 1 && s_spl == 0 && s_fcs == 0; } + bool has2Ellipses() const { return s_pts == 0 && s_lns == 0 && s_cir == 0 && s_ell == 2 && s_spl == 0 && s_fcs == 0; } + bool has1Point1Spline1MoreEdge() const { return s_pts == 1 && s_spl >= 1 && (s_lns + s_cir + s_ell + s_spl) == 2 && s_fcs == 0; } + + size_t s_pts, s_lns, s_cir, s_ell, s_spl, s_fcs; +}; + +class TDHandlerDimension : public TechDrawHandler, + public Gui::SelectionObserver +{ +public: + explicit TDHandlerDimension(ReferenceVector refs, TechDraw::DrawViewPart* pFeat) + : SelectionObserver(true) + , specialDimension(SpecialDimension::None) + , availableDimension(AvailableDimension::FIRST) + , previousPos(QPoint(0, 0)) + , selPoints({}) + , selLine({}) + , selCircleArc({}) + , selEllipseArc({}) + , selSplineAndCo({}) + , selFaces({}) + , addedRef(ReferenceEntry()) + , removedRef(ReferenceEntry()) + , initialSelection(std::move(refs)) + , partFeat(pFeat) + , dim(nullptr) + , blockRemoveSel(false) + { + } + ~TDHandlerDimension() + { + } + + enum class AvailableDimension { + FIRST, + SECOND, + THIRD, + FOURTH, + FIFTH, + RESET + }; + + enum class SpecialDimension { + LineOr2PointsDistance, + None + }; + + + void activated() + { + Gui::Selection().setSelectionStyle(Gui::SelectionSingleton::SelectionStyle::GreedySelection); + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Insert Dimension")); + handleInitialSelection(); + } + + void deactivated() + { + Gui::Selection().setSelectionStyle(Gui::SelectionSingleton::SelectionStyle::NormalSelection); + Gui::Command::abortCommand(); + } + + void keyPressEvent(QKeyEvent* event) + { + if (event->key() == Qt::Key_M) { + if (availableDimension == AvailableDimension::FIRST) { + availableDimension = AvailableDimension::SECOND; + } + else if (availableDimension == AvailableDimension::SECOND) { + availableDimension = AvailableDimension::THIRD; + } + else if (availableDimension == AvailableDimension::THIRD) { + availableDimension = AvailableDimension::FOURTH; + } + else if (availableDimension == AvailableDimension::FOURTH) { + availableDimension = AvailableDimension::FIFTH; + } + else if (availableDimension == AvailableDimension::FIFTH || availableDimension == AvailableDimension::RESET) { + availableDimension = AvailableDimension::FIRST; + } + makeAppropriateDimension(previousPos); + event->accept(); + } + else if (event->key() == Qt::Key_Z && (QApplication::keyboardModifiers() & Qt::ControlModifier)) { + // User trying to cancel with Ctrl-Z + quit(); + event->accept(); + } + } + void keyReleaseEvent(QKeyEvent* event) + { + if (event->key() == Qt::Key_Z && (QApplication::keyboardModifiers() & Qt::ControlModifier)) { + // User trying to cancel with Ctrl-Z + quit(); + event->accept(); + } + else { + TechDrawHandler::keyReleaseEvent(event); + } + } + + void mouseMoveEvent(QMouseEvent* event) override + { + previousPos = event->pos(); + + //Change distance dimension based on position of mouse. + if (specialDimension == SpecialDimension::LineOr2PointsDistance){ + updateDistanceType(event->pos()); + } + + moveDimension(event->pos()); + } + + QGIDatumLabel* getDimLabel(DrawViewDimension* d) + { + auto* vp = dynamic_cast(Gui::Application::Instance->getViewProvider(d)); + if (!vp) { + return nullptr; + } + auto* qgivDimension(dynamic_cast(vp->getQView())); + if (!qgivDimension) { + return nullptr; + } + return qgivDimension->getDatumLabel(); + } + void moveDimension(QPoint& pos) + { + if (!dim) { return; } + auto label = getDimLabel(dim); + if (!label) { return; } + + label->setPos(getDimPositionToBe(pos)); + } + QPointF getDimPositionToBe(QPoint& pos) + { + auto* vpp = dynamic_cast(Gui::Application::Instance->getViewProvider(partFeat)); + if (!vpp) { return QPointF(); } + + QPointF scenePos = viewPage->mapToScene(pos) - vpp->getQView()->pos(); + return scenePos; + } + void finishDimensionMove() + { + auto label = getDimLabel(dim); + double x = Rez::appX(label->X()), y = Rez::appX(label->Y()); + Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.X = %f", + dim->getNameInDocument(), x); + Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.Y = %f", + dim->getNameInDocument(), -y); + } + + bool mousePressEvent(QMouseEvent* event) override + { + if (event->button() == Qt::RightButton && dim) { + Gui::Selection().clearSelection(); + clearAndRestartCommand(); + event->accept(); + return true; + } + return TechDrawHandler::mousePressEvent(event); + } + + bool mouseReleaseEvent(QMouseEvent* event) override + { + //Base::Console().Warning("mouseReleaseEvent TH\n"); + bool finalize = true; + + if (removedRef.hasGeometry()) { + finalize = false; + //Base::Console().Warning("RmvSelection \n"); + // Remove the reference from the vector + ReferenceVector& selVector = getSelectionVector(removedRef); + selVector.erase(std::remove(selVector.begin(), selVector.end(), removedRef), selVector.end()); + + if (!selectionEmpty()) { + availableDimension = AvailableDimension::FIRST; + makeAppropriateDimension(event->pos()); + } + else { + clearAndRestartCommand(); + } + removedRef = ReferenceEntry(); + } + + if (addedRef.hasGeometry()) { + finalize = false; + //Base::Console().Warning("AddSelection\n"); + //add the geometry to its type vector. Temporarily if not selAllowed + ReferenceVector& selVector = getSelectionVector(addedRef); + selVector.push_back(addedRef); + + availableDimension = AvailableDimension::FIRST; + bool selAllowed = makeAppropriateDimension(event->pos()); + + if (!selAllowed) { + // remove from selection + blockRemoveSel = true; + + Gui::Selection().rmvSelection(addedRef.getObject()->getDocument()->getName(), addedRef.getObject()->getNameInDocument(), addedRef.getSubName().c_str()); + blockRemoveSel = false; + + if (selVector == selFaces) { + // if sel face and not allowed, then a dimension is being created + // and user clicked on a face to drop it. + // Better would be to disable face selectability when needed. + finalize = true; + } + } + addedRef = ReferenceEntry(); + } + + + // Finalize if click on empty space. + if (finalize && dim) { + finalizeCommand(); + } + return true; + } + + void onSelectionChanged(const Gui::SelectionChanges& msg) + { + //Base::Console().Warning("onSelectionChanged %d - --%s--\n", (int)msg.Type, msg.pSubName); + + if (msg.Type == Gui::SelectionChanges::ClrSelection) { + //clearAndRestartCommand(); + return; + } + + if (msg.pSubName[0] == '\0' || msg.Object.getObjectName().empty() + || msg.Object.getDocument() != getPage()->getDocument()) { + if (msg.Type == Gui::SelectionChanges::AddSelection) { + Gui::Selection().rmvSelection(msg.pDocName, msg.pObjectName, msg.pSubName); + } + return; + } + + /*if (msg.Type == Gui::SelectionChanges::SetPreselect) { + Base::Console().Warning("SetPreselect\n"); + std::string geomName = DrawUtil::getGeomTypeFromName(msg.pSubName); + edgeOrPointPreselected = geomName == "Edge" || geomName == "Vertex"; + return; + } + else if (msg.Type == Gui::SelectionChanges::RmvPreselect) { + Base::Console().Warning("RmvPreselect\n"); + edgeOrPointPreselected = false; + return; + }*/ + + App::DocumentObject* obj = msg.Object.getObject(); + if (!obj) { + return; + } + + auto* dvp = dynamic_cast(obj); + if (!dvp) { + return; + } + + if (partFeat && partFeat != dvp) { + // Dimensions can only be within one view. + + if (msg.Type == Gui::SelectionChanges::AddSelection) { + Gui::Selection().rmvSelection(msg.pDocName, msg.pObjectName, msg.pSubName); + } + return; + } + else { + partFeat = dvp; + } + + if (msg.Type == Gui::SelectionChanges::AddSelection) { + addedRef = ReferenceEntry(dvp, msg.pSubName); + } + else if (msg.Type == Gui::SelectionChanges::RmvSelection) { + if (!blockRemoveSel) { + removedRef = ReferenceEntry(dvp, msg.pSubName); + } + } + } + +private: + QString getCrosshairCursorSVGName() const override + { + return QString::fromLatin1("TechDraw_Dimension_Pointer"); + } + +protected: + SpecialDimension specialDimension; + AvailableDimension availableDimension; + + QPoint previousPos; + + ReferenceVector selPoints; + ReferenceVector selLine; + ReferenceVector selCircleArc; + ReferenceVector selEllipseArc; + ReferenceVector selSplineAndCo; + ReferenceVector selFaces; + + ReferenceEntry addedRef; + ReferenceEntry removedRef; + + ReferenceVector initialSelection; + + TechDraw::DrawViewPart* partFeat; + + DrawViewDimension* dim; + + bool blockRemoveSel; + + void clearRefVectors() + { + selPoints.clear(); + selLine.clear(); + selCircleArc.clear(); + selEllipseArc.clear(); + selSplineAndCo.clear(); + selFaces.clear(); + } + + void handleInitialSelection() + { + if (initialSelection.size() == 0) { + return; + } + + availableDimension = AvailableDimension::FIRST; + + // Add the selected elements to their corresponding selection vectors + for (auto& ref : initialSelection) { + ReferenceVector& selVector = getSelectionVector(ref); + selVector.push_back(ref); + } + + // See if the selection is valid + bool selAllowed = makeAppropriateDimension(QPoint()); + + if (!selAllowed) { + clearRefVectors(); + } + } + + void finalizeCommand() + { + //Base::Console().Warning("finalizeCommand \n"); + + finishDimensionMove(); + + // Ask for the value of datum dimensions + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/TechDraw"); + + Gui::Command::commitCommand(); + + // Touch the parent feature so the dimension in tree view appears as a child + partFeat->touch(true); + + // This code enables the continuous creation mode. + bool continuousMode = hGrp->GetBool("ContinuousCreationMode", true); + if (continuousMode) { + Gui::Selection().clearSelection(); + clearAndRestartCommand(); + } + else { + viewPage->deactivateHandler(); // no code after this line, Handler get deleted in QGVPage + } + } + + ReferenceVector& getSelectionVector(ReferenceEntry& ref) + { + static ReferenceVector emptyVector; + + std::string subName = ref.getSubName(); + auto* dvp = static_cast(ref.getObject()); + + std::string geomName = DrawUtil::getGeomTypeFromName(subName); + if (geomName == "Face") { + return selFaces; + } + else if (geomName == "Edge") { + + int GeoId(TechDraw::DrawUtil::getIndexFromName(subName)); + TechDraw::BaseGeomPtr geom = dvp->getGeomByIndex(GeoId); + if (!geom) { + return emptyVector; + } + + if (geom->getGeomType() == TechDraw::GENERIC) { + TechDraw::GenericPtr gen1 = std::static_pointer_cast(geom); + if (gen1->points.size() < 2) { + return emptyVector; + } + return selLine; + //Base::Vector3d line = gen1->points.at(1) - gen1->points.at(0); + } + else if (geom->getGeomType() == TechDraw::CIRCLE || geom->getGeomType() == TechDraw::ARCOFCIRCLE) { + return selCircleArc; + } + else if (geom->getGeomType() == TechDraw::ELLIPSE || geom->getGeomType() == TechDraw::ARCOFELLIPSE) { + return selEllipseArc; + } + else if (geom->getGeomType() == TechDraw::BSPLINE) { + //TechDraw::BSplinePtr spline = std::static_pointer_cast(geom); + //if (spline->isCircle()) { + // return isBSplineCircle; + //} + //else { + //} + return selSplineAndCo; + } + } + else if (geomName == "Vertex") { + return selPoints; + } + + return emptyVector; + } + + /* + bool notSelectedYet(const ReferenceEntry& elem) + { + auto contains = [&](const ReferenceVector& vec, const ReferenceEntry& elem) { + for (const auto& x : vec) + { + if (x == elem){ + return true; + } + } + return false; + }; + + return !contains(selPoints, elem) + && !contains(selLine, elem) + && !contains(selCircleArc, elem) + && !contains(selEllipseArc, elem) + && !contains(selFaces, elem); + }*/ + + bool selectionEmpty() + { + return selPoints.empty() && selLine.empty() && selCircleArc.empty() && selEllipseArc.empty() && selFaces.empty(); + } + + bool makeAppropriateDimension(QPoint& pos) { + bool selAllowed = false; + //Base::Console().Warning("makeAppropriateDimension %d %d %d %d %d %d\n", selPoints.size(), selLine.size(), selCircleArc.size(), selEllipseArc.size(), selSplineAndCo.size(), selFaces.size()); + + GeomSelectionSizes selection(selPoints.size(), selLine.size(), selCircleArc.size(), selEllipseArc.size(), selSplineAndCo.size(), selFaces.size()); + if (selection.hasFaces()) { + makeCts_Faces(selAllowed, pos); + } + else if (selection.hasPoints()) { + if (selection.has1Point()) { selAllowed = true; } + else if (selection.has2Points()) { makeCts_2Point(selAllowed, pos); } + else if (selection.has3Points()) { makeCts_3Point(selAllowed, pos); } + else if (selection.has1Point1Line()) { makeCts_1Point1Line(selAllowed, pos); } + else if (selection.has1Point1Circle()) { makeCts_1Point1Circle(selAllowed, pos); } + else if (selection.has1Point1Ellipse()) { makeCts_1Point1Ellipse(selAllowed, pos); } + } + else if (selection.hasLines()) { + if (selection.has1Line()) { makeCts_1Line(selAllowed, pos); } + else if (selection.has2Lines()) { makeCts_2Line(selAllowed, pos); } + else if (selection.has1Line1Circle()) { makeCts_1Line1Circle(selAllowed, pos); } + else if (selection.has1Line1Ellipse()) { makeCts_1Line1Ellipse(selAllowed, pos); } + } + else if (selection.hasCirclesOrArcs()) { + if (selection.has1Circle()) { makeCts_1Circle(selAllowed, pos); } + else if (selection.has2Circles()) { makeCts_2Circle(selAllowed, pos); } + } + else if (selection.hasEllipseAndCo()) { + if (selection.has1Ellipse()) { makeCts_1Ellipse(selAllowed, pos); } + if (selection.has2Ellipses()) { makeCts_2Ellipses(selAllowed, pos); } + } + return selAllowed; + } + + // TODO + void makeCts_Faces(bool& selAllowed, QPoint& pos) + { + //area + if (availableDimension == AvailableDimension::FIRST) { + /*restartCommand(QT_TRANSLATE_NOOP("Command", "Add Area dimension")); + createAreaDimension(pos); + selAllowed = true; + availableDimension = AvailableDimension::RESET;*/ + } + } + + void makeCts_2Point(bool& selAllowed, QPoint& pos) + { + //distance + if (availableDimension == AvailableDimension::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance dimension")); + createDistanceDimension("Distance", selPoints[0], selPoints[1], pos); + specialDimension = SpecialDimension::LineOr2PointsDistance; + selAllowed = true; + availableDimension = AvailableDimension::RESET; + } + } + + void makeCts_3Point(bool& selAllowed, QPoint& pos) + { + //angle + if (availableDimension == AvailableDimension::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 3-points angle dimension")); + create3pAngleDimension(selPoints[0], selPoints[1], selPoints[2], pos); + selAllowed = true; + } + else if (availableDimension == AvailableDimension::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 3-points angle dimension")); + create3pAngleDimension(selPoints[1], selPoints[2], selPoints[0], pos); + } + else if (availableDimension == AvailableDimension::THIRD) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 3-points angle dimension")); + create3pAngleDimension(selPoints[2], selPoints[0], selPoints[1], pos); + availableDimension = AvailableDimension::RESET; + } + } + + void makeCts_1Point1Line(bool& selAllowed, QPoint& pos) + { + //distance + if (availableDimension == AvailableDimension::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add point to line Distance dimension")); + createDistanceDimension("Distance", selPoints[0], selLine[0], pos); + selAllowed = true; + availableDimension = AvailableDimension::RESET; + } + } + + void makeCts_1Point1Circle(bool& selAllowed, QPoint& pos) + { + //Distance + if (availableDimension == AvailableDimension::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add length dimension")); + createDistanceDimension("Distance", selPoints[0], selCircleArc[0], pos); + selAllowed = true; + availableDimension = AvailableDimension::RESET; + } + } + + void makeCts_1Point1Ellipse(bool& selAllowed, QPoint& pos) + { + //Distance + if (availableDimension == AvailableDimension::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add length dimension")); + createDistanceDimension("Distance", selPoints[0], selEllipseArc[0], pos); + selAllowed = true; + availableDimension = AvailableDimension::RESET; + } + } + + void makeCts_1Line(bool& selAllowed, QPoint& pos) + { + //distance + if (availableDimension == AvailableDimension::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add length dimension")); + createDistanceDimension("Distance", selLine[0], ReferenceEntry(), pos); + specialDimension = SpecialDimension::LineOr2PointsDistance; + selAllowed = true; + availableDimension = AvailableDimension::RESET; + } + } + + void makeCts_2Line(bool& selAllowed, QPoint& pos) + { + //angle (if parallel: Distance (see in createAngleDimension)). + if (availableDimension == AvailableDimension::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Angle dimension")); + createAngleDimension(selLine[0], selLine[1], pos); + selAllowed = true; + availableDimension = AvailableDimension::RESET; + } + } + + void makeCts_1Line1Circle(bool& selAllowed, QPoint& pos) + { + //distance + if (availableDimension == AvailableDimension::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add circle to line Distance dimension")); + createDistanceDimension("Distance", selCircleArc[0], selLine[0], pos); + selAllowed = true; + availableDimension = AvailableDimension::RESET; + } + } + + void makeCts_1Line1Ellipse(bool& selAllowed, QPoint& pos) + { + //distance + if (availableDimension == AvailableDimension::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add ellipse to line Distance dimension")); + createDistanceDimension("Distance", selEllipseArc[0], selLine[0], pos); + selAllowed = true; + availableDimension = AvailableDimension::RESET; + } + } + + void makeCts_1Circle(bool& selAllowed, QPoint& pos) + { + if (availableDimension == AvailableDimension::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Radius dimension")); + createRadiusDiameterDimension(selCircleArc[0], pos, true); + selAllowed = true; + } + if (availableDimension == AvailableDimension::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Radius dimension")); + createRadiusDiameterDimension(selCircleArc[0], pos, false); + if (selCircleArc[0].geomEdgeType() != TechDraw::ARCOFCIRCLE) { + availableDimension = AvailableDimension::RESET; + } + } + if (availableDimension == AvailableDimension::THIRD) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Arc Length dimension")); + createArcLengthDimension(selCircleArc[0], pos); + availableDimension = AvailableDimension::RESET; + } + } + + void makeCts_2Circle(bool& selAllowed, QPoint& pos) + { + //Distance + if (availableDimension == AvailableDimension::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add circle to circle Distance dimension")); + createDistanceDimension("Distance", selCircleArc[0], selCircleArc[0], pos); + selAllowed = true; + availableDimension = AvailableDimension::RESET; + } + } + + void makeCts_1Ellipse(bool& selAllowed, QPoint& pos) + { + if (availableDimension == AvailableDimension::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Radius dimension")); + createRadiusDiameterDimension(selEllipseArc[0], pos, true); + selAllowed = true; + } + if (availableDimension == AvailableDimension::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Radius dimension")); + createRadiusDiameterDimension(selEllipseArc[0], pos, false); + availableDimension = AvailableDimension::RESET; + } + } + + void makeCts_2Ellipses(bool& selAllowed, QPoint& pos) + { + //Distance + if (availableDimension == AvailableDimension::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add ellipse to ellipse Distance dimension")); + createDistanceDimension("Distance", selEllipseArc[0], selEllipseArc[0], pos); + selAllowed = true; + availableDimension = AvailableDimension::RESET; + } + } + + //TODO + void createAreaDimension(QPoint& pos) + { + /*// see CmdTechDrawExtensionAreaAnnotation::activated + Base::Vector3d center; + double totalArea = 0.0; + for (auto& ref : selFaces) { + TechDraw::FacePtr face = partFeat->getFace(ref.getSubName()); + if (!face) { + continue; + } + + GProp_GProps faceProps; + BRepGProp::SurfaceProperties(face->toOccFace(), faceProps); + + double faceArea = faceProps.Mass(); + totalArea += faceArea; + center += faceArea * DrawUtil::toVector3d(faceProps.CentreOfMass()); + } + if (totalArea > 0.0) { + center /= totalArea; + } + + //function (and file) to create in CommandExtensionPack.h + auto* areaBalloon = createAreaBalloon(totalArea, center);*/ + } + + void createRadiusDiameterDimension(ReferenceEntry ref, QPoint& pos, bool firstCstr) { + bool isCircleGeom = true; + + int GeoId(TechDraw::DrawUtil::getIndexFromName(ref.getSubName())); + TechDraw::BaseGeomPtr geom = partFeat->getGeomByIndex(GeoId); + isCircleGeom = geom->getGeomType() == TechDraw::CIRCLE || TechDraw::ELLIPSE; + + // Use same preference as in sketcher? + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/TechDraw/dimensioning"); + bool dimensioningDiameter = hGrp->GetBool("DimensioningDiameter", true); + bool dimensioningRadius = hGrp->GetBool("DimensioningRadius", true); + + if ((firstCstr && dimensioningRadius && !dimensioningDiameter) || + (!firstCstr && !dimensioningRadius && dimensioningDiameter) || + (firstCstr && dimensioningRadius && dimensioningDiameter && !isCircleGeom) || + (!firstCstr && dimensioningRadius && dimensioningDiameter && isCircleGeom)) { + dim = dimMaker(partFeat, "Radius", { ref }, {}); + } + else { + dim = dimMaker(partFeat, "Diameter", { ref }, {}); + } + + moveDimension(pos); + } + + void createAngleDimension(ReferenceEntry ref1, ReferenceEntry ref2, QPoint& pos) { + if (TechDraw::isValidMultiEdge({ ref1, ref2 }) != isAngle) { + //isValidMultiEdge check if lines are parallel. + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance dimension")); + createDistanceDimension("Distance", ref1, ref2, pos); + return; + } + + dim = dimMaker(partFeat, "Angle", {ref1, ref2}, {}); + + moveDimension(pos); + } + + void create3pAngleDimension(ReferenceEntry ref1, ReferenceEntry ref2, ReferenceEntry ref3, QPoint& pos) + { + dim = dimMaker(partFeat, "Angle3Pt", {ref1, ref2, ref3}, {}); + + moveDimension(pos); + } + + void createArcLengthDimension(ReferenceEntry ref, QPoint& pos) + { + dim = makeArcLengthDimension(ref); + + moveDimension(pos); + } + + void createDistanceDimension(std::string type, ReferenceEntry ref1, ReferenceEntry ref2, QPoint& pos) { + ReferenceVector refs = { ref1 }; + if (ref2.hasGeometry()) { // if valid + refs.push_back(ref2); + } + + dim = dimMaker(partFeat, type, refs, {}); + + moveDimension(pos); + } + + void updateDistanceType(QPoint& pos) + { + if (!dim) { + return; + } + + auto type = static_cast(dim->Type.getValue()); + + TechDraw::pointPair pp = dim->getLinearPoints(); + Base::Vector3d pnt1 = Rez::guiX(pp.first()); + Base::Vector3d pnt2 = Rez::guiX(pp.second()); + + QPointF fpos = getDimPositionToBe(pos); + + double minX, minY, maxX, maxY; + minX = min(pnt1.x, pnt2.x); + maxX = max(pnt1.x, pnt2.x); + minY = min(pnt1.y, pnt2.y); + maxY = max(pnt1.y, pnt2.y); + + std::string newType = "Distance"; + if (fpos.x() > minX && fpos.x() < maxX + && (fpos.y() < minY || fpos.y() > maxY) && type != DimensionType::DistanceX) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceX dimension")); + newType = "DistanceX"; + } + else if (fpos.y() > minY && fpos.y() < maxY + && (fpos.x() < minX || fpos.x() > maxX) && type != DimensionType::DistanceY) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceY dimension")); + newType = "DistanceY"; + } + else if ((((fpos.y() < minY || fpos.y() > maxY) && (fpos.x() < minX || fpos.x() > maxX)) + || (fpos.y() > minY && fpos.y() < maxY && fpos.x() > minX && fpos.x() < maxX)) && type != DimensionType::Distance) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance dimension")); + } + else { + return; + } + specialDimension = SpecialDimension::LineOr2PointsDistance; + + if (selLine.size() == 1) { + createDistanceDimension(newType, selLine[0], ReferenceEntry(), pos); + } + else { + createDistanceDimension(newType, selPoints[0], selPoints[1], pos); + } + } + + void restartCommand(const char* cstrName) { + specialDimension = SpecialDimension::None; + Gui::Command::abortCommand(); + Gui::Command::openCommand(cstrName); + + dim = nullptr; + } + + void clearAndRestartCommand() { + Gui::Command::abortCommand(); + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Dimension")); + specialDimension = SpecialDimension::None; + previousPos = QPoint(0,0); + clearRefVectors(); + partFeat = nullptr; + dim = nullptr; + } +}; DEF_STD_CMD_A(CmdTechDrawDimension) @@ -101,7 +975,9 @@ CmdTechDrawDimension::CmdTechDrawDimension() sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Insert Dimension"); - sToolTipText = sMenuText; + sToolTipText = QT_TR_NOOP("Dimension contextually based on your selection.\n" + "Depending on your selection you might have several dimensions available. You can cycle through them using the M key.\n" + "Left clicking on empty space will validate the current Dimensiont. Right clicking or pressing Esc will cancel."); sWhatsThis = "TechDraw_Dimension"; sStatusTip = sToolTipText; sPixmap = "TechDraw_Dimension"; @@ -110,6 +986,13 @@ CmdTechDrawDimension::CmdTechDrawDimension() void CmdTechDrawDimension::activated(int iMsg) { Q_UNUSED(iMsg); + + ReferenceVector references2d; + ReferenceVector references3d; + TechDraw::DrawViewPart* partFeat = + TechDraw::getReferencesFromSelection(references2d, references3d); + + activateHandler(new TDHandlerDimension(references2d, partFeat)); } bool CmdTechDrawDimension::isActive() @@ -119,6 +1002,41 @@ bool CmdTechDrawDimension::isActive() return (havePage && haveView); } + +// Comp for dimension tools ============================================= + +class CmdTechDrawCompDimensionTools : public Gui::GroupCommand +{ +public: + CmdTechDrawCompDimensionTools() + : GroupCommand("TechDraw_CompDimensionTools") + { + sAppModule = "TechDraw"; + sGroup = "TechDraw"; + sMenuText = QT_TR_NOOP("Dimension"); + sToolTipText = QT_TR_NOOP("Dimension tools."); + sWhatsThis = "TechDraw_CompDimensionTools"; + sStatusTip = sToolTipText; + eType = ForEdit; + + setCheckable(false); + setRememberLast(false); + + addCommand("TechDraw_Dimension"); + addCommand(); //separator + addCommand("TechDraw_LengthDimension"); + addCommand("TechDraw_HorizontalDimension"); + addCommand("TechDraw_VerticalDimension"); + addCommand("TechDraw_RadiusDimension"); + addCommand("TechDraw_DiameterDimension"); + addCommand("TechDraw_AngleDimension"); + addCommand("TechDraw_3PtAngleDimension"); + addCommand("TechDraw_ExtensionCreateLengthArc"); + } + + const char* className() const override { return "CmdTechDrawCompDimensionTools"; } +}; + //=========================================================================== // TechDraw_RadiusDimension //=========================================================================== @@ -1345,6 +2263,7 @@ void CreateTechDrawCommandsDims() rcCmdMgr.addCommand(new CmdTechDrawLinkDimension()); rcCmdMgr.addCommand(new CmdTechDrawLandmarkDimension()); rcCmdMgr.addCommand(new CmdTechDrawDimensionRepair()); + rcCmdMgr.addCommand(new CmdTechDrawCompDimensionTools()); } //------------------------------------------------------------------------------ @@ -1352,11 +2271,27 @@ void CreateTechDrawCommandsDims() //Common code to build a dimension feature DrawViewDimension* dimensionMaker(TechDraw::DrawViewPart* dvp, std::string dimType, ReferenceVector references2d, ReferenceVector references3d) +{ + TechDraw::DrawViewDimension* dim = dimMaker(dvp, dimType, references2d, references3d); + + Gui::Command::commitCommand(); + + // Touch the parent feature so the dimension in tree view appears as a child + dvp->touch(true); + + // Select only the newly created dimension + Gui::Selection().clearSelection(); + Gui::Selection().addSelection(dvp->getDocument()->getName(), dim->getNameInDocument()); + + return dim; +} + +DrawViewDimension* dimMaker(TechDraw::DrawViewPart* dvp, std::string dimType, + ReferenceVector references2d, ReferenceVector references3d) { TechDraw::DrawPage* page = dvp->findParentPage(); std::string PageName = page->getNameInDocument(); - TechDraw::DrawViewDimension* dim = nullptr; std::string dimName = dvp->getDocument()->getUniqueObjectName("Dimension"); Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create Dimension")); @@ -1374,7 +2309,7 @@ DrawViewDimension* dimensionMaker(TechDraw::DrawViewPart* dvp, std::string dimTy dimName.c_str(), "Projected"); - dim = + auto* dim = dynamic_cast(dvp->getDocument()->getObject(dimName.c_str())); if (!dim) { throw Base::TypeError("CmdTechDrawNewDiameterDimension - dim not found\n"); @@ -1389,16 +2324,9 @@ DrawViewDimension* dimensionMaker(TechDraw::DrawViewPart* dvp, std::string dimTy PageName.c_str(), dimName.c_str()); - Gui::Command::commitCommand(); - - // Touch the parent feature so the dimension in tree view appears as a child - dvp->touch(true); - - // Select only the newly created dimension - Gui::Selection().clearSelection(); - Gui::Selection().addSelection(dvp->getDocument()->getName(), dim->getNameInDocument()); dim->recomputeFeature(); + return dim; } diff --git a/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp b/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp index 60f07baa9c..bf55681a0d 100644 --- a/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp +++ b/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp @@ -52,6 +52,7 @@ #include "DrawGuiUtil.h" #include "TaskCustomizeFormat.h" #include "TaskSelectLineAttributes.h" +#include "CommandExtensionDims.h" using namespace TechDrawGui; @@ -78,7 +79,7 @@ namespace TechDrawGui { std::vector_getDimensions(std::vector selection, std::string needDimType); std::vector _getVertexInfo(TechDraw::DrawViewPart* objFeat, std::vector subNames); - TechDraw::DrawViewDimension* _createLinDimension(Gui::Command* cmd, + TechDraw::DrawViewDimension* _createLinDimension( TechDraw::DrawViewPart* objFeat, std::string startVertex, std::string endVertex, @@ -1280,7 +1281,7 @@ void execCreateHorizChainDimension(Gui::Command* cmd) { float yMaster = 0.0; for (long unsigned int n = 0; n < allVertexes.size() - 1; n++) { TechDraw::DrawViewDimension* dim; - dim = _createLinDimension(cmd, objFeat, allVertexes[n].name, allVertexes[n + 1].name, "DistanceX"); + dim = _createLinDimension(objFeat, allVertexes[n].name, allVertexes[n + 1].name, "DistanceX"); TechDraw::pointPair pp = dim->getLinearPoints(); Base::Vector3d mid = (pp.first() + pp.second()) / 2.0; dim->X.setValue(mid.x); @@ -1347,7 +1348,7 @@ void execCreateVertChainDimension(Gui::Command* cmd) { double fontSize = Preferences::dimFontSizeMM(); for (long unsigned int n = 0; n < allVertexes.size() - 1; n++) { TechDraw::DrawViewDimension* dim; - dim = _createLinDimension(cmd, objFeat, allVertexes[n].name, allVertexes[n + 1].name, "DistanceY"); + dim = _createLinDimension(objFeat, allVertexes[n].name, allVertexes[n + 1].name, "DistanceY"); TechDraw::pointPair pp = dim->getLinearPoints(); Base::Vector3d mid = (pp.first() + pp.second()) / 2.0; if (n == 0) @@ -1443,7 +1444,7 @@ void execCreateObliqueChainDimension(Gui::Command* cmd) { double fontSize = Preferences::dimFontSizeMM(); for (long unsigned int n = 0; n < allVertexes.size() - 1; n++) { TechDraw::DrawViewDimension* dim; - dim = _createLinDimension(cmd, objFeat, carrierVertexes[n].name, carrierVertexes[n + 1].name, "Distance"); + dim = _createLinDimension(objFeat, carrierVertexes[n].name, carrierVertexes[n + 1].name, "Distance"); TechDraw::pointPair pp = dim->getLinearPoints(); Base::Vector3d mid = (pp.first() + pp.second()) / 2.0 + delta; dim->X.setValue(mid.x); @@ -1630,7 +1631,7 @@ void execCreateHorizCoordDimension(Gui::Command* cmd) { dimDistance = -dimDistance; for (long unsigned int n = 0; n < allVertexes.size() - 1; n++) { TechDraw::DrawViewDimension* dim; - dim = _createLinDimension(cmd, objFeat, allVertexes[0].name, allVertexes[n + 1].name, "DistanceX"); + dim = _createLinDimension(objFeat, allVertexes[0].name, allVertexes[n + 1].name, "DistanceX"); TechDraw::pointPair pp = dim->getLinearPoints(); Base::Vector3d mid = (pp.first() + pp.second()) / 2.0; dim->X.setValue(mid.x); @@ -1703,7 +1704,7 @@ void execCreateVertCoordDimension(Gui::Command* cmd) { double fontSize = Preferences::dimFontSizeMM(); for (long unsigned int n = 0; n < allVertexes.size() - 1; n++) { TechDraw::DrawViewDimension* dim; - dim = _createLinDimension(cmd, objFeat, allVertexes[0].name, allVertexes[n + 1].name, "DistanceY"); + dim = _createLinDimension(objFeat, allVertexes[0].name, allVertexes[n + 1].name, "DistanceY"); TechDraw::pointPair pp = dim->getLinearPoints(); Base::Vector3d mid = (pp.first() + pp.second()) / 2.0; dim->X.setValue(xMaster + dimDistance * n); @@ -1804,7 +1805,7 @@ void execCreateObliqueCoordDimension(Gui::Command* cmd) { double fontSize = Preferences::dimFontSizeMM(); for (long unsigned int n = 0; n < allVertexes.size() - 1; n++) { TechDraw::DrawViewDimension* dim; - dim = _createLinDimension(cmd, objFeat, carrierVertexes[0].name, carrierVertexes[n + 1].name, "Distance"); + dim = _createLinDimension(objFeat, carrierVertexes[0].name, carrierVertexes[n + 1].name, "Distance"); TechDraw::pointPair pp = dim->getLinearPoints(); Base::Vector3d mid = (pp.first() + pp.second()) / 2.0 + delta * (n + 1); dim->X.setValue(mid.x); @@ -1991,7 +1992,7 @@ void execCreateHorizChamferDimension(Gui::Command* cmd) { if (!allVertexes.empty() && allVertexes.size() > 1) { const auto Pi180 = 180.0 / M_PI; TechDraw::DrawViewDimension* dim; - dim = _createLinDimension(cmd, objFeat, allVertexes[0].name, allVertexes[1].name, "DistanceX"); + dim = _createLinDimension(objFeat, allVertexes[0].name, allVertexes[1].name, "DistanceX"); float yMax = std::max(abs(allVertexes[0].point.y), abs(allVertexes[1].point.y)) + 7.0; if (std::signbit(allVertexes[0].point.y)) yMax = -yMax; @@ -2060,7 +2061,7 @@ void execCreateVertChamferDimension(Gui::Command* cmd) { if (!allVertexes.empty() && allVertexes.size() > 1) { const auto Pi180 = 180.0 / M_PI; TechDraw::DrawViewDimension* dim; - dim = _createLinDimension(cmd, objFeat, allVertexes[0].name, allVertexes[1].name, "DistanceY"); + dim = _createLinDimension(objFeat, allVertexes[0].name, allVertexes[1].name, "DistanceY"); float xMax = std::max(abs(allVertexes[0].point.x), abs(allVertexes[1].point.x)) + 7.0; if (std::signbit(allVertexes[0].point.x)) xMax = -xMax; @@ -2240,47 +2241,17 @@ void CmdTechDrawExtensionCreateLengthArc::activated(int iMsg) { } Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create Arc Length Dim")); - const std::vector subNames = selection[0].getSubNames(); - int geoId = TechDraw::DrawUtil::getIndexFromName(subNames[0]); - TechDraw::BaseGeomPtr geom = objFeat->getGeomByIndex(geoId); - std::string geoType = TechDraw::DrawUtil::getGeomTypeFromName(subNames[0]); - if (geoType == "Edge" && geom->getGeomType() == TechDraw::ARCOFCIRCLE) { - TechDraw::AOCPtr arcTag = std::static_pointer_cast(geom); - float radius = arcTag->radius; - Base::Vector3d centerPt = arcTag->center; - centerPt.y = -centerPt.y; - Base::Vector3d startPt = arcTag->startPnt; - startPt.y = -startPt.y; - Base::Vector3d endPt = arcTag->endPnt; - endPt.y = -endPt.y; - std::stringstream startName, endName, formatSpec; - double scale = objFeat->getScale(); - Base::Vector3d cvPoint = CosmeticVertex::makeCanonicalPoint(objFeat, startPt); - std::string startVertTag = objFeat->addCosmeticVertex(cvPoint); - int startVertNumber = objFeat->add1CVToGV(startVertTag); - startName << "Vertex" << startVertNumber; - cvPoint = CosmeticVertex::makeCanonicalPoint(objFeat, endPt); - std::string endVertTag = objFeat->addCosmeticVertex(cvPoint); - int endVertNumber = objFeat->add1CVToGV(endVertTag); - endName << "Vertex" << endVertNumber; - TechDraw::DrawViewDimension* dim; - dim = _createLinDimension(this, objFeat, startName.str(), endName.str(), "Distance"); - TechDraw::pointPair pp = dim->getLinearPoints(); - Base::Vector3d mid = (pp.first() + pp.second()) / 2.0; - dim->X.setValue(mid.x); - dim->Y.setValue(-mid.y); - Base::Vector3d radVec1 = startPt - centerPt; - Base::Vector3d radVec2 = endPt - centerPt; - float alpha = acos((radVec1 * radVec2) / (radVec1.Length() * radVec2.Length())); - float arcLength = alpha * radius / scale; - dim->Arbitrary.setValue(true); - formatSpec << "◠ " << arcLength; - dim->FormatSpec.setValue(formatSpec.str()); - objFeat->refreshCEGeoms(); - objFeat->requestPaint(); - getSelection().clearSelection(); + + ReferenceEntry ref(objFeat, selection[0].getSubNames()[0]); + + TechDraw::DrawViewDimension* dim = makeArcLengthDimension(ref); + + if (dim) { + Gui::Command::commitCommand(); + } + else { + Gui::Command::abortCommand(); } - Gui::Command::commitCommand(); } bool CmdTechDrawExtensionCreateLengthArc::isActive() @@ -2329,6 +2300,54 @@ bool CmdTechDrawExtensionCustomizeFormat::isActive() return (havePage && haveView); } +DrawViewDimension* TechDrawGui::makeArcLengthDimension(const ReferenceEntry& ref) +{ + DrawViewDimension* dim = nullptr; + auto* dvp = static_cast(ref.getObject()); + + int geoId = DrawUtil::getIndexFromName(ref.getSubName()); + BaseGeomPtr geom = dvp->getGeomByIndex(geoId); + + if (ref.geomEdgeType() == TechDraw::ARCOFCIRCLE) { + TechDraw::AOCPtr arcTag = std::static_pointer_cast(geom); + float radius = arcTag->radius; + Base::Vector3d centerPt = arcTag->center; + centerPt.y = -centerPt.y; + Base::Vector3d startPt = arcTag->startPnt; + startPt.y = -startPt.y; + Base::Vector3d endPt = arcTag->endPnt; + endPt.y = -endPt.y; + + std::stringstream startName, endName, formatSpec; + double scale = dvp->getScale(); + Base::Vector3d cvPoint = CosmeticVertex::makeCanonicalPoint(dvp, startPt); + std::string startVertTag = dvp->addCosmeticVertex(cvPoint); + int startVertNumber = dvp->add1CVToGV(startVertTag); + startName << "Vertex" << startVertNumber; + cvPoint = CosmeticVertex::makeCanonicalPoint(dvp, endPt); + std::string endVertTag = dvp->addCosmeticVertex(cvPoint); + int endVertNumber = dvp->add1CVToGV(endVertTag); + endName << "Vertex" << endVertNumber; + + dim = _createLinDimension(dvp, startName.str(), endName.str(), "Distance"); + TechDraw::pointPair pp = dim->getLinearPoints(); + Base::Vector3d mid = (pp.first() + pp.second()) / 2.0; + dim->X.setValue(mid.x); + dim->Y.setValue(-mid.y); + Base::Vector3d radVec1 = startPt - centerPt; + Base::Vector3d radVec2 = endPt - centerPt; + float alpha = acos((radVec1 * radVec2) / (radVec1.Length() * radVec2.Length())); + float arcLength = alpha * radius / scale; + dim->Arbitrary.setValue(true); + formatSpec << "◠ " << arcLength; + dim->FormatSpec.setValue(formatSpec.str()); + dvp->refreshCEGeoms(); + dvp->requestPaint(); + } + + return dim; +} + namespace TechDrawGui { //=========================================================================== // internal helper routines @@ -2387,7 +2406,8 @@ namespace TechDrawGui { } return true; } - TechDraw::DrawViewDimension* _createLinDimension(Gui::Command* cmd, + + TechDraw::DrawViewDimension* _createLinDimension( TechDraw::DrawViewPart* objFeat, std::string startVertex, std::string endVertex, @@ -2396,21 +2416,21 @@ namespace TechDrawGui { { TechDraw::DrawPage* page = objFeat->findParentPage(); std::string PageName = page->getNameInDocument(); - TechDraw::DrawViewDimension* dim = nullptr; - std::string FeatName = cmd->getUniqueObjectName("Dimension"); + std::string FeatName = objFeat->getDocument()->getUniqueObjectName("Dimension"); std::vector objs; std::vector subs; objs.push_back(objFeat); objs.push_back(objFeat); subs.push_back(startVertex); subs.push_back(endVertex); - cmd->doCommand(cmd->Doc, "App.activeDocument().addObject('TechDraw::DrawViewDimension', '%s')", FeatName.c_str()); - cmd->doCommand(cmd->Doc, "App.activeDocument().%s.Type = '%s'", FeatName.c_str(), dimType.c_str()); - dim = dynamic_cast(cmd->getDocument()->getObject(FeatName.c_str())); - if (!dim) + Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().addObject('TechDraw::DrawViewDimension', '%s')", FeatName.c_str()); + Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.Type = '%s'", FeatName.c_str(), dimType.c_str()); + auto dim = dynamic_cast(objFeat->getDocument()->getObject(FeatName.c_str())); + if (!dim){ throw Base::TypeError("CmdTechDrawExtensionCreateLinDimension - dim not found\n"); + } dim->References2D.setValues(objs, subs); - cmd->doCommand(cmd->Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", PageName.c_str(), FeatName.c_str()); + Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", PageName.c_str(), FeatName.c_str()); // Touch the parent feature so the dimension in tree view appears as a child objFeat->touch(); diff --git a/src/Mod/TechDraw/Gui/CommandExtensionDims.h b/src/Mod/TechDraw/Gui/CommandExtensionDims.h new file mode 100644 index 0000000000..e94fcbc6ce --- /dev/null +++ b/src/Mod/TechDraw/Gui/CommandExtensionDims.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (c) 2021 edi * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef TECHDRAWGUI_CommandExtensionDims_H +#define TECHDRAWGUI_CommandExtensionDims_H + +namespace TechDraw +{ + class ReferenceEntry; +} + +namespace TechDrawGui { + TechDraw::DrawViewDimension* makeArcLengthDimension(const TechDraw::ReferenceEntry& ref); +} + +#endif // TECHDRAWGUI_CommandExtensionDims_H diff --git a/src/Mod/TechDraw/Gui/DlgPrefsTechDrawDimensions.ui b/src/Mod/TechDraw/Gui/DlgPrefsTechDrawDimensions.ui index eb4870f3f4..a1819701b6 100644 --- a/src/Mod/TechDraw/Gui/DlgPrefsTechDrawDimensions.ui +++ b/src/Mod/TechDraw/Gui/DlgPrefsTechDrawDimensions.ui @@ -524,9 +524,9 @@ Multiplier of 'Font Size' - Controls the size of gap between dimension point and start of extension line for ISO dimensions. -Value * linewidth is the gap. -Normally, no gap is used. If using a gap, the recommended value 8. + Controls the size of gap between dimension point and start of extension line for ISO dimensions. + Value * linewidth is the gap. + Normally, no gap is used. If using a gap, the recommended value 8. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -545,8 +545,8 @@ Normally, no gap is used. If using a gap, the recommended value 8. - Controls the size of gap between dimension point and start of extension line for ASME dimensions. Value * linewidth is the gap. -Normally, no gap is used. If a gap is used, the recommended value is 6. + Controls the size of gap between dimension point and start of extension line for ASME dimensions. Value * linewidth is the gap. + Normally, no gap is used. If a gap is used, the recommended value is 6. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -618,6 +618,56 @@ Normally, no gap is used. If a gap is used, the recommended value is 6. + + + + + 0 + 0 + + + + Tools + + + + + + Dimensioning tools: + + + + + + + Select the type of dimensioning tools for your toolbar: +'Single tool': A single tool for all dimensioning in the toolbar: Distance, Distance X / Y, Angle, Radius. (Others in dropdown) +'Separated tools': Individual tools for each dimensioning tool. +'Both': You will have both the 'Dimension' tool and the separated tools. +This setting is only for the toolbar. Whichever you choose, all tools are always available in the menu and through shortcuts. + + + + + + + Dimension tool diameter/radius mode: + + + + + + + While using the Dimension tool you may choose how to handle circles and arcs: +'Auto': The tool will apply radius to arcs and diameter to circles. +'Diameter': The tool will apply diameter to all. +'Radius': The tool will apply radius to all. + + + + + + diff --git a/src/Mod/TechDraw/Gui/DlgPrefsTechDrawDimensionsImp.cpp b/src/Mod/TechDraw/Gui/DlgPrefsTechDrawDimensionsImp.cpp index 0b4b276e3e..c7ef7746ce 100644 --- a/src/Mod/TechDraw/Gui/DlgPrefsTechDrawDimensionsImp.cpp +++ b/src/Mod/TechDraw/Gui/DlgPrefsTechDrawDimensionsImp.cpp @@ -25,6 +25,7 @@ #include "PreCompiled.h" #include +#include #include "DlgPrefsTechDrawDimensionsImp.h" #include "ui_DlgPrefsTechDrawDimensions.h" @@ -67,6 +68,61 @@ void DlgPrefsTechDrawDimensionsImp::saveSettings() ui->pdsbGapISO->onSave(); ui->pdsbGapASME->onSave(); ui->pdsbLineSpacingFactorISO->onSave(); + + enum + { + DimensionSingleTool, + DimensionSeparateTools, + DimensionBoth + }; + + // Dimensioning constraints mode + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/TechDraw/dimensioning"); + bool singleTool = true; + bool SeparatedTools = false; + int index = ui->dimensioningMode->currentIndex(); + switch (index) { + case DimensionSeparateTools: + singleTool = false; + SeparatedTools = true; + break; + case DimensionBoth: + singleTool = true; + SeparatedTools = true; + break; + } + hGrp->SetBool("SingleDimensioningTool", singleTool); + hGrp->SetBool("SeparatedDimensioningTools", SeparatedTools); + + ui->radiusDiameterMode->setEnabled(index != 1); + + enum + { + DimensionAutoRadiusDiam, + DimensionDiameter, + DimensionRadius + }; + + bool Diameter = true; + bool Radius = true; + index = ui->radiusDiameterMode->currentIndex(); + switch (index) { + case DimensionDiameter: + Diameter = true; + Radius = false; + break; + case DimensionRadius: + Diameter = false; + Radius = true; + break; + } + hGrp->SetBool("DimensioningDiameter", Diameter); + hGrp->SetBool("DimensioningRadius", Radius); + + if (property("dimensioningMode").toInt() != ui->dimensioningMode->currentIndex()) { + requireRestart(); + } } void DlgPrefsTechDrawDimensionsImp::loadSettings() @@ -101,6 +157,42 @@ void DlgPrefsTechDrawDimensionsImp::loadSettings() ui->pdsbGapASME->onRestore(); ui->pdsbLineSpacingFactorISO->onRestore(); + + // Dimensioning constraints mode + ui->dimensioningMode->clear(); + ui->dimensioningMode->addItem(tr("Single tool")); + ui->dimensioningMode->addItem(tr("Separated tools")); + ui->dimensioningMode->addItem(tr("Both")); + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/TechDraw/dimensioning"); + bool singleTool = hGrp->GetBool("SingleDimensioningTool", true); + bool SeparatedTools = hGrp->GetBool("SeparatedDimensioningTools", true); + int index = SeparatedTools ? (singleTool ? 2 : 1) : 0; + ui->dimensioningMode->setCurrentIndex(index); + setProperty("dimensioningMode", index); + connect(ui->dimensioningMode, + QOverload::of(&QComboBox::currentIndexChanged), + this, + &DlgPrefsTechDrawDimensionsImp::dimensioningModeChanged); + + ui->radiusDiameterMode->setEnabled(index != 1); + + // Dimensioning constraints mode + ui->radiusDiameterMode->clear(); + ui->radiusDiameterMode->addItem(tr("Auto")); + ui->radiusDiameterMode->addItem(tr("Diameter")); + ui->radiusDiameterMode->addItem(tr("Radius")); + + bool Diameter = hGrp->GetBool("DimensioningDiameter", true); + bool Radius = hGrp->GetBool("DimensioningRadius", true); + index = Diameter ? (Radius ? 0 : 1) : 2; + ui->radiusDiameterMode->setCurrentIndex(index); +} + +void DlgPrefsTechDrawDimensionsImp::dimensioningModeChanged(int index) +{ + ui->radiusDiameterMode->setEnabled(index != 1); } /** diff --git a/src/Mod/TechDraw/Gui/DlgPrefsTechDrawDimensionsImp.h b/src/Mod/TechDraw/Gui/DlgPrefsTechDrawDimensionsImp.h index 44b66bf16e..c06dcb0d6c 100644 --- a/src/Mod/TechDraw/Gui/DlgPrefsTechDrawDimensionsImp.h +++ b/src/Mod/TechDraw/Gui/DlgPrefsTechDrawDimensionsImp.h @@ -45,6 +45,7 @@ protected: void saveSettings() override; void loadSettings() override; void changeEvent(QEvent *e) override; + void dimensioningModeChanged(int index); int prefArrowStyle() const; diff --git a/src/Mod/TechDraw/Gui/MDIViewPage.cpp b/src/Mod/TechDraw/Gui/MDIViewPage.cpp index 3af07c9e06..edbc80b1d5 100644 --- a/src/Mod/TechDraw/Gui/MDIViewPage.cpp +++ b/src/Mod/TechDraw/Gui/MDIViewPage.cpp @@ -755,13 +755,27 @@ void MDIViewPage::sceneSelectionChanged() std::vector treeSel = Gui::Selection().getSelectionEx(); QList sceneSel = m_qgSceneSelected; - //check if really need to change selection - bool sameSel = compareSelections(treeSel, sceneSel); - if (sameSel) { - return; + + bool saveBlock = blockSelection(true);// block selectionChanged signal from Tree/Observer + blockSceneSelection(true); + + if (sceneSel.empty()) { + if (!treeSel.empty()) { + Gui::Selection().clearSelection(); + } + } + else { + for (auto& sel : treeSel) { + removeSelFromTreeSel(sceneSel, sel); + } + + for (auto* scene : sceneSel) { + addSceneToTreeSel(scene, treeSel); + } } - setTreeToSceneSelect(); + blockSceneSelection(false); + blockSelection(saveBlock); } //Note: Qt says: "no guarantee of selection order"!!! @@ -771,149 +785,48 @@ void MDIViewPage::setTreeToSceneSelect() bool saveBlock = blockSelection(true);// block selectionChanged signal from Tree/Observer blockSceneSelection(true); Gui::Selection().clearSelection(); - QList sceneSel = m_qgSceneSelected; - for (QList::iterator it = sceneSel.begin(); it != sceneSel.end(); ++it) { - QGIView* itemView = dynamic_cast(*it); + + for (auto* scene : m_qgSceneSelected) { + auto* itemView = dynamic_cast(scene); if (!itemView) { - QGIEdge* edge = dynamic_cast(*it); - if (edge) { - QGraphicsItem* parent = edge->parentItem(); - if (!parent) { - continue; - } - - QGIView* viewItem = dynamic_cast(parent); - if (!viewItem) { - continue; - } - - TechDraw::DrawView* viewObj = viewItem->getViewObject(); - - std::stringstream ss; - ss << "Edge" << edge->getProjIndex(); - //bool accepted = - static_cast(Gui::Selection().addSelection(viewObj->getDocument()->getName(), - viewObj->getNameInDocument(), - ss.str().c_str())); - showStatusMsg(viewObj->getDocument()->getName(), viewObj->getNameInDocument(), - ss.str().c_str()); + auto* parent = dynamic_cast(scene->parentItem()); + if (!parent) { + return; + } + TechDraw::DrawView* viewObj = parent->getViewObject(); + if (!viewObj) { continue; } + const char* doc_name = viewObj->getDocument()->getName(); + const char* obj_name = viewObj->getNameInDocument(); - QGIVertex* vert = dynamic_cast(*it); - if (vert) { - QGraphicsItem* parent = vert->parentItem(); - if (!parent) { - continue; - } + auto* edge = dynamic_cast(scene); + auto* vert = dynamic_cast(scene); + auto* face = dynamic_cast(scene); + if (edge || vert || face) { + const char* ssn = getSceneSubName(scene).c_str(); - QGIView* viewItem = dynamic_cast(parent); - if (!viewItem) { - continue; - } - - TechDraw::DrawView* viewObj = viewItem->getViewObject(); - - std::stringstream ss; - ss << "Vertex" << vert->getProjIndex(); - //bool accepted = - static_cast(Gui::Selection().addSelection(viewObj->getDocument()->getName(), - viewObj->getNameInDocument(), - ss.str().c_str())); - showStatusMsg(viewObj->getDocument()->getName(), viewObj->getNameInDocument(), - ss.str().c_str()); - continue; + Gui::Selection().addSelection(doc_name, obj_name, ssn); + showStatusMsg(doc_name, obj_name, ssn); + return; } - - QGIFace* face = dynamic_cast(*it); - if (face) { - QGraphicsItem* parent = face->parentItem(); - if (!parent) { - continue; - } - - QGIView* viewItem = dynamic_cast(parent); - if (!viewItem) { - continue; - } - - TechDraw::DrawView* viewObj = viewItem->getViewObject(); - - std::stringstream ss; - ss << "Face" << face->getProjIndex(); - //bool accepted = - static_cast(Gui::Selection().addSelection(viewObj->getDocument()->getName(), - viewObj->getNameInDocument(), - ss.str().c_str())); - showStatusMsg(viewObj->getDocument()->getName(), viewObj->getNameInDocument(), - ss.str().c_str()); - continue; - } - - QGIDatumLabel* dimLabel = dynamic_cast(*it); - if (dimLabel) { - QGraphicsItem* dimParent = dimLabel->QGraphicsItem::parentItem(); - if (!dimParent) { - continue; - } - - QGIView* dimItem = dynamic_cast(dimParent); - - if (!dimItem) { - continue; - } - - TechDraw::DrawView* dimObj = dimItem->getViewObject(); - if (!dimObj) { - continue; - } - const char* name = dimObj->getNameInDocument(); - if (!name) {//can happen during undo/redo if Dim is selected??? + else if (dynamic_cast(scene) || dynamic_cast(scene)) { + if (!obj_name) {//can happen during undo/redo if Dim is selected??? //Base::Console().Log("INFO - MDIVP::sceneSelectionChanged - dimObj name is null!\n"); continue; } - //bool accepted = - static_cast(Gui::Selection().addSelection(dimObj->getDocument()->getName(), - dimObj->getNameInDocument())); - } - - QGMText* mText = dynamic_cast(*it); - if (mText) { - QGraphicsItem* textParent = mText->QGraphicsItem::parentItem(); - if (!textParent) { - continue; - } - - QGIView* parent = dynamic_cast(textParent); - - if (!parent) { - continue; - } - - TechDraw::DrawView* parentFeat = parent->getViewObject(); - if (!parentFeat) { - continue; - } - const char* name = parentFeat->getNameInDocument(); - if (!name) {//can happen during undo/redo if Dim is selected??? - continue; - } - - //bool accepted = - static_cast(Gui::Selection().addSelection( - parentFeat->getDocument()->getName(), parentFeat->getNameInDocument())); + Gui::Selection().addSelection(doc_name, obj_name); } } else { - TechDraw::DrawView* viewObj = itemView->getViewObject(); if (viewObj && !viewObj->isRemoving()) { - std::string doc_name = viewObj->getDocument()->getName(); - std::string obj_name = viewObj->getNameInDocument(); + const char* doc_name = viewObj->getDocument()->getName(); + const char* obj_name = viewObj->getNameInDocument(); - Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str()); - showStatusMsg(doc_name.c_str(), obj_name.c_str(), ""); + Gui::Selection().addSelection(doc_name, obj_name); + showStatusMsg(doc_name, obj_name, ""); } } } @@ -922,6 +835,138 @@ void MDIViewPage::setTreeToSceneSelect() blockSelection(saveBlock); } +std::string MDIViewPage::getSceneSubName(QGraphicsItem* scene) +{ + auto* edge = dynamic_cast(scene); + auto* vert = dynamic_cast(scene); + auto* face = dynamic_cast(scene); + if (edge || vert || face) { + auto* viewItem = dynamic_cast(scene->parentItem()); + if (viewItem) { + TechDraw::DrawView* viewObj = viewItem->getViewObject(); + + std::stringstream ss; + if (edge) { ss << "Edge" << edge->getProjIndex(); } + else if (vert) { ss << "Vertex" << vert->getProjIndex(); } + else { ss << "Face" << face->getProjIndex(); } + + return ss.str(); + } + } + return ""; +} + +// adds scene to core selection if it's not in already. +void MDIViewPage::addSceneToTreeSel(QGraphicsItem* sn, std::vector treeSel) +{ + auto* itemView = dynamic_cast(sn); + if (!itemView) { + auto* parent = dynamic_cast(sn->parentItem()); + if (!parent) { + return; + } + TechDraw::DrawView* viewObj = parent->getViewObject(); + if (!viewObj) { + return; + } + + const char* doc_name = viewObj->getDocument()->getName(); + const char* obj_name = viewObj->getNameInDocument(); + std::string sub_name; + + if (dynamic_cast(sn) || dynamic_cast(sn) || dynamic_cast(sn)) { + sub_name = getSceneSubName(sn); + } + + else if (dynamic_cast(sn) || dynamic_cast(sn)) { + if (!obj_name) {//can happen during undo/redo if Dim is selected??? + return; + } + } + else { // are there other cases? + return; + } + + if (!Gui::Selection().isSelected(viewObj, sub_name.c_str())) { + Gui::Selection().addSelection(doc_name, obj_name, sub_name.c_str()); + showStatusMsg(doc_name, obj_name, sub_name.c_str()); + } + } + else { + TechDraw::DrawView* viewObj = itemView->getViewObject(); + if (viewObj && !viewObj->isRemoving()) { + const char* doc_name = viewObj->getDocument()->getName(); + const char* obj_name = viewObj->getNameInDocument(); + + if (!Gui::Selection().isSelected(viewObj)) { + Gui::Selection().addSelection(doc_name, obj_name); + showStatusMsg(doc_name, obj_name, ""); + } + } + } +} + +// remove core selection if scene is not selected anymore +void MDIViewPage::removeSelFromTreeSel(QList sceneSel, Gui::SelectionObject& sel) +{ + std::string selDocName = sel.getDocName(); + App::DocumentObject* selObj = sel.getObject(); + + for (auto& sub : sel.getSubNames()) { + bool found = false; + for (auto& sn : sceneSel) { + auto* itemView = dynamic_cast(sn); + if (!itemView) { + auto* parent = dynamic_cast(sn->parentItem()); + if (!parent) { + continue; + } + TechDraw::DrawView* viewObj = parent->getViewObject(); + if (!viewObj) { + continue; + } + + const char* doc_name = viewObj->getDocument()->getName(); + const char* obj_name = viewObj->getNameInDocument(); + std::string sub_name; + + if (dynamic_cast(sn) || dynamic_cast(sn) || dynamic_cast(sn)) { + sub_name = getSceneSubName(sn); + } + + else if (dynamic_cast(sn) || dynamic_cast(sn)) { + if (!obj_name) {//can happen during undo/redo if Dim is selected??? + continue; + } + } + else { // are there other cases? + continue; + } + + if (selDocName == doc_name && selObj == viewObj && sub == sub_name) { + found = true; + break; + } + } + else { + TechDraw::DrawView* viewObj = itemView->getViewObject(); + if (viewObj && !viewObj->isRemoving()) { + const char* doc_name = viewObj->getDocument()->getName(); + const char* obj_name = viewObj->getNameInDocument(); + + if (selDocName == doc_name && selObj == viewObj) { + found = true; + break; + } + } + } + } + if (!found) { + Gui::Selection().rmvSelection(sel.getDocName(), sel.getObject()->getNameInDocument(), sub.c_str()); + } + } +} + bool MDIViewPage::compareSelections(std::vector treeSel, QList sceneSel) { diff --git a/src/Mod/TechDraw/Gui/MDIViewPage.h b/src/Mod/TechDraw/Gui/MDIViewPage.h index 474247305f..6f58a19eba 100644 --- a/src/Mod/TechDraw/Gui/MDIViewPage.h +++ b/src/Mod/TechDraw/Gui/MDIViewPage.h @@ -127,6 +127,9 @@ protected: void onDeleteObject(const App::DocumentObject& obj); bool compareSelections(std::vector treeSel, QList sceneSel); + void addSceneToTreeSel(QGraphicsItem* scene, std::vector treeSel); + void removeSelFromTreeSel(QList sceneSel, Gui::SelectionObject& sel); + std::string getSceneSubName(QGraphicsItem* scene); void setTreeToSceneSelect(); void sceneSelectionManager(); diff --git a/src/Mod/TechDraw/Gui/PreferencesGui.cpp b/src/Mod/TechDraw/Gui/PreferencesGui.cpp index c4cfbcd26a..24059b51d0 100644 --- a/src/Mod/TechDraw/Gui/PreferencesGui.cpp +++ b/src/Mod/TechDraw/Gui/PreferencesGui.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -214,7 +215,8 @@ bool PreferencesGui::showGrid() bool PreferencesGui::multiSelection() { - return Preferences::getPreferenceGroup("General")->GetBool("multiSelection", false); + bool greedy = Gui::Selection().getSelectionStyle() == Gui::SelectionSingleton::SelectionStyle::GreedySelection; + return greedy || Preferences::getPreferenceGroup("General")->GetBool("multiSelection", false); } App::Color PreferencesGui::pageColor() diff --git a/src/Mod/TechDraw/Gui/QGVPage.cpp b/src/Mod/TechDraw/Gui/QGVPage.cpp index 3869bea238..de73224363 100644 --- a/src/Mod/TechDraw/Gui/QGVPage.cpp +++ b/src/Mod/TechDraw/Gui/QGVPage.cpp @@ -63,6 +63,7 @@ #include "QGVNavStyleTouchpad.h" #include "QGVPage.h" #include "Rez.h" +#include "TechDrawHandler.h" #include "ViewProviderPage.h" @@ -167,7 +168,7 @@ public: QGVPage::QGVPage(ViewProviderPage* vpPage, QGSPage* scenePage, QWidget* parent) : QGraphicsView(parent), m_renderer(Native), drawBkg(true), m_vpPage(nullptr), m_scene(scenePage), balloonPlacing(false), m_showGrid(false), - m_navStyle(nullptr), d(new Private(this)) + m_navStyle(nullptr), d(new Private(this)), toolHandler(nullptr) { assert(vpPage); m_vpPage = vpPage; @@ -281,6 +282,31 @@ void QGVPage::setNavigationStyle(std::string navParm) } } + +void QGVPage::activateHandler(TechDrawHandler* newHandler) +{ + if (toolHandler) { + toolHandler->deactivate(); + } + + toolHandler = std::unique_ptr(newHandler); + toolHandler->activate(this); + + // make sure receiver has focus so immediately pressing Escape will be handled by + // ViewProviderSketch::keyPressed() and dismiss the active handler, and not the entire + // sketcher editor + //Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView(); + //mdi->setFocus(); +} + +void QGVPage::deactivateHandler() +{ + if (toolHandler) { + toolHandler->deactivate(); + toolHandler = nullptr; + } +} + void QGVPage::startBalloonPlacing(DrawView* parent) { // Base::Console().Message("QGVP::startBalloonPlacing(%s)\n", parent->getNameInDocument()); @@ -421,7 +447,12 @@ void QGVPage::wheelEvent(QWheelEvent* event) void QGVPage::keyPressEvent(QKeyEvent* event) { - m_navStyle->handleKeyPressEvent(event); + if (toolHandler) { + toolHandler->keyPressEvent(event); + } + else { + m_navStyle->handleKeyPressEvent(event); + } if (!event->isAccepted()) { QGraphicsView::keyPressEvent(event); } @@ -429,7 +460,12 @@ void QGVPage::keyPressEvent(QKeyEvent* event) void QGVPage::keyReleaseEvent(QKeyEvent* event) { - m_navStyle->handleKeyReleaseEvent(event); + if (toolHandler) { + toolHandler->keyReleaseEvent(event); + } + else { + m_navStyle->handleKeyReleaseEvent(event); + } if (!event->isAccepted()) { QGraphicsView::keyReleaseEvent(event); } @@ -465,6 +501,11 @@ void QGVPage::enterEvent(QEvent* event) void QGVPage::enterEvent(QEnterEvent* event) #endif { + if (toolHandler) { + // if the user interacted with another widget than the mdi, the cursor got unset. + // So we reapply it. + toolHandler->updateCursor(); + } QGraphicsView::enterEvent(event); m_navStyle->handleEnterEvent(event); QGraphicsView::enterEvent(event); @@ -478,21 +519,37 @@ void QGVPage::leaveEvent(QEvent* event) void QGVPage::mousePressEvent(QMouseEvent* event) { - m_navStyle->handleMousePressEvent(event); + if (toolHandler && (event->button() != Qt::MiddleButton)) { + toolHandler->mousePressEvent(event); + } + else { + m_navStyle->handleMousePressEvent(event); + } QGraphicsView::mousePressEvent(event); } void QGVPage::mouseMoveEvent(QMouseEvent* event) { - m_navStyle->handleMouseMoveEvent(event); + if (toolHandler) { + toolHandler->mouseMoveEvent(event); + } + else { + m_navStyle->handleMouseMoveEvent(event); + } QGraphicsView::mouseMoveEvent(event); } void QGVPage::mouseReleaseEvent(QMouseEvent* event) { - m_navStyle->handleMouseReleaseEvent(event); - QGraphicsView::mouseReleaseEvent(event); - resetCursor(); + if (toolHandler && (event->button() != Qt::MiddleButton)) { + QGraphicsView::mouseReleaseEvent(event); + toolHandler->mouseReleaseEvent(event); + } + else { + m_navStyle->handleMouseReleaseEvent(event); + QGraphicsView::mouseReleaseEvent(event); + resetCursor(); + } } TechDraw::DrawPage* QGVPage::getDrawPage() { return m_vpPage->getDrawPage(); } @@ -553,8 +610,7 @@ void QGVPage::activateCursor(QCursor cursor) void QGVPage::resetCursor() { - this->setCursor(Qt::ArrowCursor); - viewport()->setCursor(Qt::ArrowCursor); + activateCursor(Qt::ArrowCursor); } void QGVPage::setPanCursor() { activateCursor(panCursor); } diff --git a/src/Mod/TechDraw/Gui/QGVPage.h b/src/Mod/TechDraw/Gui/QGVPage.h index 3b40888650..f123a9d8f1 100644 --- a/src/Mod/TechDraw/Gui/QGVPage.h +++ b/src/Mod/TechDraw/Gui/QGVPage.h @@ -71,6 +71,7 @@ class QGILeaderLine; class QGIRichAnno; class QGITile; class QGVNavStyle; +class TechDrawHandler; class TechDrawGuiExport QGVPage: public QGraphicsView { @@ -101,6 +102,9 @@ public: void showGrid(bool state) { m_showGrid = state; } void updateViewport() { viewport()->repaint(); } + void activateHandler(TechDrawHandler* newHandler); + void deactivateHandler(); + bool isBalloonPlacing() const { return balloonPlacing; } void setBalloonPlacing(bool isPlacing) { balloonPlacing = isPlacing; } @@ -196,6 +200,8 @@ private: MDIViewPage* m_parentMDI; QContextMenuEvent* m_saveContextEvent; + + std::unique_ptr toolHandler; }; }// namespace TechDrawGui diff --git a/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc b/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc index 82812f4187..19cbeef03b 100644 --- a/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc +++ b/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc @@ -90,6 +90,7 @@ icons/TechDraw_CameraOrientation.svg icons/TechDraw_DiameterDimension.svg icons/TechDraw_Dimension.svg + icons/TechDraw_Dimension_Pointer.svg icons/TechDraw_DimensionRepair.svg icons/TechDraw_ExtensionAreaAnnotation.svg icons/TechDraw_ExtensionArcLengthAnnotation.svg diff --git a/src/Mod/TechDraw/Gui/Resources/icons/TechDraw_Dimension.svg b/src/Mod/TechDraw/Gui/Resources/icons/TechDraw_Dimension.svg index c3b098638a..4a59128659 100644 --- a/src/Mod/TechDraw/Gui/Resources/icons/TechDraw_Dimension.svg +++ b/src/Mod/TechDraw/Gui/Resources/icons/TechDraw_Dimension.svg @@ -1,26 +1,24 @@ - - + inkscape:export-ydpi="45" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> - - - - - - - - @@ -131,26 +105,6 @@ offset="1" id="stop3897" /> - - + inkscape:collect="always" + xlink:href="#linearGradient3026" + id="linearGradient927" + x1="16.969255" + y1="39.85923" + x2="58.005249" + y2="39.85923" + gradientUnits="userSpaceOnUse" /> + inkscape:snap-nodes="false" + objecttolerance="10.0" + gridtolerance="10.0" + guidetolerance="10.0" + inkscape:pagecheckerboard="0"> image/svg+xml - [WandererFan] @@ -266,70 +222,81 @@ id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer"> - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/src/Mod/TechDraw/Gui/Resources/icons/TechDraw_Dimension_Pointer.svg b/src/Mod/TechDraw/Gui/Resources/icons/TechDraw_Dimension_Pointer.svg new file mode 100644 index 0000000000..a489693e73 --- /dev/null +++ b/src/Mod/TechDraw/Gui/Resources/icons/TechDraw_Dimension_Pointer.svg @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/TechDraw/Gui/TechDrawHandler.cpp b/src/Mod/TechDraw/Gui/TechDrawHandler.cpp new file mode 100644 index 0000000000..cec5457435 --- /dev/null +++ b/src/Mod/TechDraw/Gui/TechDrawHandler.cpp @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (c) 2024 Pierre-Louis Boyer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#include + +#include +#include + +#include +#endif // #ifndef _PreComp_ + +#include +#include +#include +#include +#include +#include +#include + +#include "MDIViewPage.h" +#include "QGVPage.h" +#include "TechDrawHandler.h" + + +using namespace TechDrawGui; + +/**************************** TechDrawHandler *******************************************/ + +TechDrawHandler::TechDrawHandler() : Gui::ToolHandler(), viewPage(nullptr) +{} + +TechDrawHandler::~TechDrawHandler() +{} + +void TechDrawHandler::activate(QGVPage* vp) +{ + viewPage = vp; + + if (!Gui::ToolHandler::activate()) { + viewPage->deactivateHandler(); + } +} + +void TechDrawHandler::keyReleaseEvent(QKeyEvent* event) +{ + // the default behaviour is to quit - specific handler categories may + // override this behaviour, for example to implement a continuous mode + if (event->key() == Qt::Key_Escape) { + quit(); + event->accept(); + } +} + +bool TechDrawHandler::mousePressEvent(QMouseEvent* event) +{ + // the default behaviour is to quit - specific handler categories may + // override this behaviour, for example to implement a continuous mode + if (event->button() == Qt::RightButton) { + quit(); + event->accept(); + } + return true; +} + +void TechDrawHandler::quit() +{ + viewPage->deactivateHandler(); +} + +QWidget* TechDrawHandler::getCursorWidget() +{ + return viewPage; +} + +void TechDrawHandler::setWidgetCursor(QCursor cursor) +{ + if (viewPage) { + viewPage->setCursor(cursor); + viewPage->viewport()->setCursor(cursor); + } +} + +TechDraw::DrawPage* TechDrawHandler::getPage() +{ + return viewPage->getDrawPage(); +} \ No newline at end of file diff --git a/src/Mod/TechDraw/Gui/TechDrawHandler.h b/src/Mod/TechDraw/Gui/TechDrawHandler.h new file mode 100644 index 0000000000..d1c911541b --- /dev/null +++ b/src/Mod/TechDraw/Gui/TechDrawHandler.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (c) 2024 Pierre-Louis Boyer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef TechDrawGUI_TechDrawHandler_H +#define TechDrawGUI_TechDrawHandler_H + +#include + +#include + +namespace TechDrawGui +{ +class QGVPage; + +class TechDrawGuiExport TechDrawHandler : public Gui::ToolHandler +{ +public: + + TechDrawHandler(); + virtual ~TechDrawHandler(); + + void activate(QGVPage* vPage); + + void quit() override; + + virtual void mouseMoveEvent(QMouseEvent* event) = 0; + virtual bool mousePressEvent(QMouseEvent* event); + virtual bool mouseReleaseEvent(QMouseEvent* event) = 0; + + virtual void keyPressEvent(QKeyEvent* event) = 0; + virtual void keyReleaseEvent(QKeyEvent* event); + + TechDraw::DrawPage* getPage(); + + +protected: + QWidget* getCursorWidget() override; + void setWidgetCursor(QCursor cursor) override; + + QGVPage* viewPage; +}; + + +} // namespace TechDrawGui + + +#endif // TechDrawGUI_TechDrawHandler_H diff --git a/src/Mod/TechDraw/Gui/Workbench.cpp b/src/Mod/TechDraw/Gui/Workbench.cpp index b0651ffaba..aad8d1ae3e 100644 --- a/src/Mod/TechDraw/Gui/Workbench.cpp +++ b/src/Mod/TechDraw/Gui/Workbench.cpp @@ -28,6 +28,7 @@ #endif #include "Workbench.h" +#include #include #include @@ -82,6 +83,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const // dimensions Gui::MenuItem* dimensions = new Gui::MenuItem; dimensions->setCommand("Dimensions"); + *dimensions << "TechDraw_Dimension"; *dimensions << "TechDraw_LengthDimension"; *dimensions << "TechDraw_HorizontalDimension"; *dimensions << "TechDraw_VerticalDimension"; @@ -305,13 +307,28 @@ Gui::ToolBarItem* Workbench::setupToolBars() const Gui::ToolBarItem* dims = new Gui::ToolBarItem(root); dims->setCommand("TechDraw Dimensions"); - *dims << "TechDraw_LengthDimension"; - *dims << "TechDraw_HorizontalDimension"; - *dims << "TechDraw_VerticalDimension"; - *dims << "TechDraw_RadiusDimension"; - *dims << "TechDraw_DiameterDimension"; - *dims << "TechDraw_AngleDimension"; - *dims << "TechDraw_3PtAngleDimension"; + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/TechDraw/dimensioning"); + bool separatedTools = hGrp->GetBool("SeparatedDimensioningTools", true); + if (hGrp->GetBool("SingleDimensioningTool", true)) { + if (separatedTools) { + *dims << "TechDraw_Dimension"; + } + else { + *dims << "TechDraw_CompDimensionTools"; + } + } + if (separatedTools) { + *dims << "TechDraw_LengthDimension"; + *dims << "TechDraw_HorizontalDimension"; + *dims << "TechDraw_VerticalDimension"; + *dims << "TechDraw_RadiusDimension"; + *dims << "TechDraw_DiameterDimension"; + *dims << "TechDraw_AngleDimension"; + *dims << "TechDraw_3PtAngleDimension"; + } + *dims << "TechDraw_ExtentGroup"; // TechDraw_LinkDimension is DEPRECATED. Use TechDraw_DimensionRepair instead. // *dims << "TechDraw_LinkDimension"; @@ -347,7 +364,9 @@ Gui::ToolBarItem* Workbench::setupToolBars() const *extdimensions << "TechDraw_ExtensionCreateChainDimensionGroup"; *extdimensions << "TechDraw_ExtensionCreateCoordDimensionGroup"; *extdimensions << "TechDraw_ExtensionChamferDimensionGroup"; - *extdimensions << "TechDraw_ExtensionCreateLengthArc"; + if (separatedTools) { + *extdimensions << "TechDraw_ExtensionCreateLengthArc"; + } *extdimensions << "TechDraw_ExtensionInsertPrefixGroup"; *extdimensions << "TechDraw_ExtensionIncreaseDecreaseGroup"; @@ -406,6 +425,7 @@ Gui::ToolBarItem* Workbench::setupCommandBars() const Gui::ToolBarItem* dims = new Gui::ToolBarItem(root); dims->setCommand("TechDraw Dimensions"); + *dims << "TechDraw_Dimension"; *dims << "TechDraw_LengthDimension"; *dims << "TechDraw_HorizontalDimension"; *dims << "TechDraw_VerticalDimension"; From 57019d80ea8fe9f8a9251a5f50b2bb274a7a65a0 Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Fri, 19 Apr 2024 15:46:25 +0200 Subject: [PATCH 4/9] TechDraw: Smart Dimension tool : Integrate extent dimensions. --- src/Mod/TechDraw/App/DrawDimHelper.cpp | 44 +++- src/Mod/TechDraw/App/DrawDimHelper.h | 13 +- src/Mod/TechDraw/Gui/CommandCreateDims.cpp | 240 +++++++++++++++------ src/Mod/TechDraw/Gui/Workbench.cpp | 2 +- 4 files changed, 228 insertions(+), 71 deletions(-) diff --git a/src/Mod/TechDraw/App/DrawDimHelper.cpp b/src/Mod/TechDraw/App/DrawDimHelper.cpp index f6b9ec0da1..e07968d1a7 100644 --- a/src/Mod/TechDraw/App/DrawDimHelper.cpp +++ b/src/Mod/TechDraw/App/DrawDimHelper.cpp @@ -59,13 +59,31 @@ using namespace TechDraw; -void DrawDimHelper::makeExtentDim(DrawViewPart* dvp, std::vector edgeNames, +DrawViewDimension* DrawDimHelper::makeExtentDim(DrawViewPart* dvp, + const std::string& dimType, ReferenceVector references2d) +{ + std::vector edgeNames; + for (auto& ref : references2d) { + if (ref.getSubName().empty()) { + continue; + } + std::string geomType = DrawUtil::getGeomTypeFromName(ref.getSubName()); + if (geomType == "Edge") { + edgeNames.push_back(ref.getSubName()); + } + } + int direction = dimType == "DistanceX" ? 0 : dimType == "DistanceY" ? 1 : 2; + + return makeExtentDim(dvp, edgeNames, direction); +} + +DrawViewDimension* DrawDimHelper::makeExtentDim(DrawViewPart* dvp, std::vector edgeNames, int direction) { // Base::Console().Message("DDH::makeExtentDim() - dvp: %s edgeNames: %d\n", // dvp->Label.getValue(), edgeNames.size()); if (!dvp) { - return; + return nullptr; } std::string dimType = "DistanceX"; @@ -74,8 +92,12 @@ void DrawDimHelper::makeExtentDim(DrawViewPart* dvp, std::vector ed dimType = "DistanceY"; dimNum = 1; } + else if (direction == LENGTH) { + dimType = "Distance"; + dimNum = 2; + } - TechDraw::DrawPage* page = dvp->findParentPage(); + DrawPage* page = dvp->findParentPage(); std::string pageName = page->getNameInDocument(); App::Document* doc = dvp->getDocument(); @@ -89,8 +111,7 @@ void DrawDimHelper::makeExtentDim(DrawViewPart* dvp, std::vector ed Base::Interpreter().runStringArg( "App.activeDocument().%s.DirExtent = %d", dimName.c_str(), dimNum); - TechDraw::DrawViewDimExtent* dimExt = - dynamic_cast(doc->getObject(dimName.c_str())); + auto* dimExt = dynamic_cast(doc->getObject(dimName.c_str())); if (!dimExt) { throw Base::TypeError("Dim extent not found"); } @@ -113,6 +134,14 @@ void DrawDimHelper::makeExtentDim(DrawViewPart* dvp, std::vector ed dimName.c_str()); dimExt->recomputeFeature(); + + return dimExt; +} + +void DrawDimHelper::makeExtentDim3d(DrawViewPart* dvp, const std::string& dimType, ReferenceVector references3d) +{ + int direction = dimType == "DistanceX" ? 0 : dimType == "DistanceY" ? 1 : 2; + return makeExtentDim3d(dvp, references3d, direction); } void DrawDimHelper::makeExtentDim3d(DrawViewPart* dvp, ReferenceVector references, int direction) @@ -130,7 +159,7 @@ void DrawDimHelper::makeExtentDim3d(DrawViewPart* dvp, ReferenceVector reference dimNum = 1; } - TechDraw::DrawPage* page = dvp->findParentPage(); + DrawPage* page = dvp->findParentPage(); std::string pageName = page->getNameInDocument(); App::Document* doc = dvp->getDocument(); @@ -144,8 +173,7 @@ void DrawDimHelper::makeExtentDim3d(DrawViewPart* dvp, ReferenceVector reference Base::Interpreter().runStringArg( "App.activeDocument().%s.DirExtent = %d", dimName.c_str(), dimNum); - TechDraw::DrawViewDimExtent* dimExt = - dynamic_cast(doc->getObject(dimName.c_str())); + auto* dimExt = dynamic_cast(doc->getObject(dimName.c_str())); if (!dimExt) { throw Base::TypeError("Dim extent not found"); } diff --git a/src/Mod/TechDraw/App/DrawDimHelper.h b/src/Mod/TechDraw/App/DrawDimHelper.h index c8d315750f..e645e5accf 100644 --- a/src/Mod/TechDraw/App/DrawDimHelper.h +++ b/src/Mod/TechDraw/App/DrawDimHelper.h @@ -44,9 +44,18 @@ class DrawViewDimension; /// Additional functions for working with Dimensions class TechDrawExport DrawDimHelper { public: - static void makeExtentDim(DrawViewPart* dvp, + + static DrawViewDimension* makeExtentDim(DrawViewPart* dvp, + const std::string& dimType, + ReferenceVector references2d); + + static DrawViewDimension* makeExtentDim(DrawViewPart* dvp, std::vector edgeNames, int direction); + + static void makeExtentDim3d(DrawViewPart* dvp, + const std::string& dimType, + ReferenceVector references2d); static void makeExtentDim3d(DrawViewPart* dvp, ReferenceVector references, int direction); @@ -55,7 +64,7 @@ class TechDrawExport DrawDimHelper { TopoDS_Edge& boundary); - static TechDraw::DrawViewDimension* makeDistDim(DrawViewPart* dvp, + static DrawViewDimension* makeDistDim(DrawViewPart* dvp, std::string dimType, Base::Vector3d refMin, Base::Vector3d refMax, diff --git a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp index 07e4e32630..1b193d0319 100644 --- a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp +++ b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp @@ -87,7 +87,7 @@ void execAngle3Pt(Gui::Command* cmd); void execRadius(Gui::Command* cmd); void execDiameter(Gui::Command* cmd); -void execExtent(Gui::Command* cmd, int direction); +void execExtent(Gui::Command* cmd, const std::string& dimType); DrawViewDimension* dimensionMaker(TechDraw::DrawViewPart* dvp, std::string dimType, ReferenceVector references2d, ReferenceVector references3d); @@ -159,7 +159,8 @@ public: bool has1Ellipse() const { return s_pts == 0 && s_lns == 0 && s_cir == 0 && s_ell == 1 && s_spl == 0 && s_fcs == 0; } bool has2Ellipses() const { return s_pts == 0 && s_lns == 0 && s_cir == 0 && s_ell == 2 && s_spl == 0 && s_fcs == 0; } - bool has1Point1Spline1MoreEdge() const { return s_pts == 1 && s_spl >= 1 && (s_lns + s_cir + s_ell + s_spl) == 2 && s_fcs == 0; } + + bool has1SplineAndMore() const { return s_pts >= 0 && s_lns >= 0 && s_cir >= 0 && s_ell >= 0 && s_spl >= 1 && s_fcs == 0; } size_t s_pts, s_lns, s_cir, s_ell, s_spl, s_fcs; }; @@ -179,6 +180,7 @@ public: , selEllipseArc({}) , selSplineAndCo({}) , selFaces({}) + , emptyVector({}) , addedRef(ReferenceEntry()) , removedRef(ReferenceEntry()) , initialSelection(std::move(refs)) @@ -202,6 +204,7 @@ public: enum class SpecialDimension { LineOr2PointsDistance, + ExtendDistance, None }; @@ -221,7 +224,7 @@ public: void keyPressEvent(QKeyEvent* event) { - if (event->key() == Qt::Key_M) { + if (event->key() == Qt::Key_M && !selectionEmpty()) { if (availableDimension == AvailableDimension::FIRST) { availableDimension = AvailableDimension::SECOND; } @@ -266,6 +269,9 @@ public: if (specialDimension == SpecialDimension::LineOr2PointsDistance){ updateDistanceType(event->pos()); } + if (specialDimension == SpecialDimension::ExtendDistance){ + updateExtentDistanceType(event->pos()); + } moveDimension(event->pos()); } @@ -341,28 +347,41 @@ public: removedRef = ReferenceEntry(); } - if (addedRef.hasGeometry()) { + Base::Console().Warning("h1\n"); + if (addedRef.getObject()) { + Base::Console().Warning("h2 -%s-\n", addedRef.getSubName()); finalize = false; //Base::Console().Warning("AddSelection\n"); //add the geometry to its type vector. Temporarily if not selAllowed - ReferenceVector& selVector = getSelectionVector(addedRef); - selVector.push_back(addedRef); + if (addedRef.getSubName() == "") { + Base::Console().Warning("h3\n"); + // This means user selected the view itself. + if (selectionEmpty()) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); + createExtentDistanceDimension("DistanceX", event->pos()); + } + } + else { + Base::Console().Warning("h4\n"); + ReferenceVector& selVector = getSelectionVector(addedRef); + selVector.push_back(addedRef); - availableDimension = AvailableDimension::FIRST; - bool selAllowed = makeAppropriateDimension(event->pos()); + availableDimension = AvailableDimension::FIRST; + bool selAllowed = makeAppropriateDimension(event->pos()); - if (!selAllowed) { - // remove from selection - blockRemoveSel = true; + if (!selAllowed) { + // remove from selection + blockRemoveSel = true; - Gui::Selection().rmvSelection(addedRef.getObject()->getDocument()->getName(), addedRef.getObject()->getNameInDocument(), addedRef.getSubName().c_str()); - blockRemoveSel = false; + Gui::Selection().rmvSelection(addedRef.getObject()->getDocument()->getName(), addedRef.getObject()->getNameInDocument(), addedRef.getSubName().c_str()); + blockRemoveSel = false; - if (selVector == selFaces) { - // if sel face and not allowed, then a dimension is being created - // and user clicked on a face to drop it. - // Better would be to disable face selectability when needed. - finalize = true; + if (selVector == selFaces) { + // if sel face and not allowed, then a dimension is being created + // and user clicked on a face to drop it. + // Better would be to disable face selectability when needed. + finalize = true; + } } } addedRef = ReferenceEntry(); @@ -378,14 +397,14 @@ public: void onSelectionChanged(const Gui::SelectionChanges& msg) { - //Base::Console().Warning("onSelectionChanged %d - --%s--\n", (int)msg.Type, msg.pSubName); + Base::Console().Warning("onSelectionChanged %d - --%s--\n", (int)msg.Type, msg.pSubName); if (msg.Type == Gui::SelectionChanges::ClrSelection) { //clearAndRestartCommand(); return; } - if (msg.pSubName[0] == '\0' || msg.Object.getObjectName().empty() + if (msg.Object.getObjectName().empty() || msg.Object.getDocument() != getPage()->getDocument()) { if (msg.Type == Gui::SelectionChanges::AddSelection) { Gui::Selection().rmvSelection(msg.pDocName, msg.pObjectName, msg.pSubName); @@ -407,11 +426,17 @@ public: App::DocumentObject* obj = msg.Object.getObject(); if (!obj) { + if (msg.Type == Gui::SelectionChanges::AddSelection) { + Gui::Selection().rmvSelection(msg.pDocName, msg.pObjectName, msg.pSubName); + } return; } auto* dvp = dynamic_cast(obj); if (!dvp) { + if (msg.Type == Gui::SelectionChanges::AddSelection) { + Gui::Selection().rmvSelection(msg.pDocName, msg.pObjectName, msg.pSubName); + } return; } @@ -455,6 +480,7 @@ protected: ReferenceVector selEllipseArc; ReferenceVector selSplineAndCo; ReferenceVector selFaces; + ReferenceVector emptyVector; ReferenceEntry addedRef; ReferenceEntry removedRef; @@ -467,16 +493,6 @@ protected: bool blockRemoveSel; - void clearRefVectors() - { - selPoints.clear(); - selLine.clear(); - selCircleArc.clear(); - selEllipseArc.clear(); - selSplineAndCo.clear(); - selFaces.clear(); - } - void handleInitialSelection() { if (initialSelection.size() == 0) { @@ -526,9 +542,11 @@ protected: ReferenceVector& getSelectionVector(ReferenceEntry& ref) { - static ReferenceVector emptyVector; - std::string subName = ref.getSubName(); + if (subName == "") { + return emptyVector; + } + auto* dvp = static_cast(ref.getObject()); std::string geomName = DrawUtil::getGeomTypeFromName(subName); @@ -596,7 +614,24 @@ protected: bool selectionEmpty() { - return selPoints.empty() && selLine.empty() && selCircleArc.empty() && selEllipseArc.empty() && selFaces.empty(); + return selPoints.empty() && selLine.empty() && selCircleArc.empty() && selEllipseArc.empty() && selSplineAndCo.empty() && selFaces.empty(); + } + + ReferenceVector allRefs() + { + ReferenceVector result; + + result.reserve(selPoints.size() + selLine.size() + selCircleArc.size() + selEllipseArc.size() + selSplineAndCo.size() + selFaces.size()); + + // Append each vector to result + result.insert(result.end(), selPoints.begin(), selPoints.end()); + result.insert(result.end(), selLine.begin(), selLine.end()); + result.insert(result.end(), selCircleArc.begin(), selCircleArc.end()); + result.insert(result.end(), selEllipseArc.begin(), selEllipseArc.end()); + result.insert(result.end(), selSplineAndCo.begin(), selSplineAndCo.end()); + result.insert(result.end(), selFaces.begin(), selFaces.end()); + + return result; } bool makeAppropriateDimension(QPoint& pos) { @@ -629,6 +664,9 @@ protected: if (selection.has1Ellipse()) { makeCts_1Ellipse(selAllowed, pos); } if (selection.has2Ellipses()) { makeCts_2Ellipses(selAllowed, pos); } } + else if (selection.hasSplineAndCo()) { + if (selection.has1SplineAndMore()) { makeCts_1SplineAndMore(selAllowed, pos); } + } return selAllowed; } @@ -688,11 +726,15 @@ protected: void makeCts_1Point1Circle(bool& selAllowed, QPoint& pos) { - //Distance + //Distance, extent distance if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add length dimension")); createDistanceDimension("Distance", selPoints[0], selCircleArc[0], pos); selAllowed = true; + } + if (availableDimension == AvailableDimension::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); + createExtentDistanceDimension("DistanceX", pos); availableDimension = AvailableDimension::RESET; } } @@ -704,6 +746,10 @@ protected: restartCommand(QT_TRANSLATE_NOOP("Command", "Add length dimension")); createDistanceDimension("Distance", selPoints[0], selEllipseArc[0], pos); selAllowed = true; + } + if (availableDimension == AvailableDimension::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); + createExtentDistanceDimension("DistanceX", pos); availableDimension = AvailableDimension::RESET; } } @@ -727,28 +773,40 @@ protected: restartCommand(QT_TRANSLATE_NOOP("Command", "Add Angle dimension")); createAngleDimension(selLine[0], selLine[1], pos); selAllowed = true; + } + if (availableDimension == AvailableDimension::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); + createExtentDistanceDimension("DistanceX", pos); availableDimension = AvailableDimension::RESET; } } void makeCts_1Line1Circle(bool& selAllowed, QPoint& pos) { - //distance + //distance, extent distance if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add circle to line Distance dimension")); createDistanceDimension("Distance", selCircleArc[0], selLine[0], pos); selAllowed = true; + } + if (availableDimension == AvailableDimension::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); + createExtentDistanceDimension("DistanceX", pos); availableDimension = AvailableDimension::RESET; } } void makeCts_1Line1Ellipse(bool& selAllowed, QPoint& pos) { - //distance + //distance, extent distance if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add ellipse to line Distance dimension")); createDistanceDimension("Distance", selEllipseArc[0], selLine[0], pos); selAllowed = true; + } + if (availableDimension == AvailableDimension::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); + createExtentDistanceDimension("DistanceX", pos); availableDimension = AvailableDimension::RESET; } } @@ -779,8 +837,12 @@ protected: //Distance if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add circle to circle Distance dimension")); - createDistanceDimension("Distance", selCircleArc[0], selCircleArc[0], pos); + createDistanceDimension("Distance", selCircleArc[0], selCircleArc[1], pos); selAllowed = true; + } + if (availableDimension == AvailableDimension::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); + createExtentDistanceDimension("DistanceX", pos); availableDimension = AvailableDimension::RESET; } } @@ -804,7 +866,22 @@ protected: //Distance if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add ellipse to ellipse Distance dimension")); - createDistanceDimension("Distance", selEllipseArc[0], selEllipseArc[0], pos); + createDistanceDimension("Distance", selEllipseArc[0], selEllipseArc[1], pos); + selAllowed = true; + } + if (availableDimension == AvailableDimension::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); + createExtentDistanceDimension("DistanceX", pos); + availableDimension = AvailableDimension::RESET; + } + } + + void makeCts_1SplineAndMore(bool& selAllowed, QPoint& pos) + { + //Extend + if (availableDimension == AvailableDimension::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); + createExtentDistanceDimension("DistanceX", pos); selAllowed = true; availableDimension = AvailableDimension::RESET; } @@ -900,6 +977,14 @@ protected: moveDimension(pos); } + void createExtentDistanceDimension(std::string type, QPoint& pos) { + specialDimension = SpecialDimension::ExtendDistance; + + dim = DrawDimHelper::makeExtentDim(partFeat, type, allRefs()); + + moveDimension(pos); + } + void updateDistanceType(QPoint& pos) { if (!dim) { @@ -948,6 +1033,41 @@ protected: } } + void updateExtentDistanceType(QPoint& pos) + { + if (!dim) { + return; + } + auto d =dim->References2D.getValues()[0]; + auto type = static_cast(dim->Type.getValue()); + + TechDraw::pointPair pp = dim->getLinearPoints(); + Base::Vector3d pnt1 = Rez::guiX(pp.first()); + Base::Vector3d pnt2 = Rez::guiX(pp.second()); + + QPointF fpos = getDimPositionToBe(pos); + + double minX, minY, maxX, maxY; + minX = min(pnt1.x, pnt2.x); + maxX = max(pnt1.x, pnt2.x); + minY = min(pnt1.y, pnt2.y); + maxY = max(pnt1.y, pnt2.y); + + if (fpos.x() > minX && fpos.x() < maxX + && (fpos.y() < minY || fpos.y() > maxY) && type != DimensionType::DistanceX) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceX extent dimension")); + specialDimension = SpecialDimension::LineOr2PointsDistance; + createExtentDistanceDimension("DistanceX", pos); + } + else if (fpos.y() > minY && fpos.y() < maxY + && (fpos.x() < minX || fpos.x() > maxX) && type != DimensionType::DistanceY) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceY extent dimension")); + specialDimension = SpecialDimension::LineOr2PointsDistance; + createExtentDistanceDimension("DistanceY", pos); + } + } + + void restartCommand(const char* cstrName) { specialDimension = SpecialDimension::None; Gui::Command::abortCommand(); @@ -965,6 +1085,16 @@ protected: partFeat = nullptr; dim = nullptr; } + + void clearRefVectors() + { + selPoints.clear(); + selLine.clear(); + selCircleArc.clear(); + selEllipseArc.clear(); + selSplineAndCo.clear(); + selFaces.clear(); + } }; DEF_STD_CMD_A(CmdTechDrawDimension) @@ -1032,6 +1162,8 @@ public: addCommand("TechDraw_AngleDimension"); addCommand("TechDraw_3PtAngleDimension"); addCommand("TechDraw_ExtensionCreateLengthArc"); + addCommand("TechDraw_HorizontalExtentDimension"); + addCommand("TechDraw_VerticalExtentDimension"); } const char* className() const override { return "CmdTechDrawCompDimensionTools"; } @@ -1864,10 +1996,10 @@ void CmdTechDrawExtentGroup::activated(int iMsg) pcAction->setIcon(pcAction->actions().at(iMsg)->icon()); switch (iMsg) { case 0: - execExtent(this, 0); + execExtent(this, "DistanceX"); break; case 1: - execExtent(this, 1); + execExtent(this, "DistanceY"); break; default: Base::Console().Message("CMD::ExtGrp - invalid iMsg: %d\n", iMsg); @@ -1958,7 +2090,7 @@ void CmdTechDrawHorizontalExtentDimension::activated(int iMsg) return; } - execExtent(this, 0); + execExtent(this, "DistanceX"); } bool CmdTechDrawHorizontalExtentDimension::isActive() @@ -1968,7 +2100,7 @@ bool CmdTechDrawHorizontalExtentDimension::isActive() return (havePage && haveView); } -void execExtent(Gui::Command* cmd, int direction) +void execExtent(Gui::Command* cmd, const std::string& dimType) { bool result = _checkDrawViewPart(cmd); if (!result) { @@ -1977,7 +2109,6 @@ void execExtent(Gui::Command* cmd, int direction) QObject::tr("No View of a Part in selection.")); return; } - ReferenceVector references2d; ReferenceVector references3d; TechDraw::DrawViewPart* partFeat = @@ -2005,6 +2136,7 @@ void execExtent(Gui::Command* cmd, int direction) QObject::tr("Can not make 2d extent dimension from selection")); return; } + //what 3d geometry configuration did we receive? DimensionGeometryType geometryRefs3d; if (geometryRefs2d == TechDraw::isViewReference && !references3d.empty()) { @@ -2022,22 +2154,10 @@ void execExtent(Gui::Command* cmd, int direction) } if (references3d.empty()) { - std::vector edgeNames; - for (auto& ref : references2d) { - if (ref.getSubName().empty()) { - continue; - } - std::string geomType = DrawUtil::getGeomTypeFromName(ref.getSubName()); - if (geomType == "Edge") { - edgeNames.push_back(ref.getSubName()); - } - } - DrawDimHelper::makeExtentDim(partFeat, edgeNames, - direction);//0 - horizontal, 1 - vertical - } else { - DrawDimHelper::makeExtentDim3d(partFeat, - references3d, - direction);//0 - horizontal, 1 - vertical + DrawDimHelper::makeExtentDim(partFeat, dimType, references2d); + } + else { + DrawDimHelper::makeExtentDim3d(partFeat, dimType, references3d); } } @@ -2071,7 +2191,7 @@ void CmdTechDrawVerticalExtentDimension::activated(int iMsg) return; } - execExtent(this, 1); + execExtent(this, "DistanceY"); } bool CmdTechDrawVerticalExtentDimension::isActive() diff --git a/src/Mod/TechDraw/Gui/Workbench.cpp b/src/Mod/TechDraw/Gui/Workbench.cpp index aad8d1ae3e..519941bccd 100644 --- a/src/Mod/TechDraw/Gui/Workbench.cpp +++ b/src/Mod/TechDraw/Gui/Workbench.cpp @@ -327,9 +327,9 @@ Gui::ToolBarItem* Workbench::setupToolBars() const *dims << "TechDraw_DiameterDimension"; *dims << "TechDraw_AngleDimension"; *dims << "TechDraw_3PtAngleDimension"; + *dims << "TechDraw_ExtentGroup"; } - *dims << "TechDraw_ExtentGroup"; // TechDraw_LinkDimension is DEPRECATED. Use TechDraw_DimensionRepair instead. // *dims << "TechDraw_LinkDimension"; *dims << "TechDraw_Balloon"; From e3a5ef350490aee4cbbfa2cdc8a5e7b85742067c Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Sat, 20 Apr 2024 08:36:37 +0200 Subject: [PATCH 5/9] TechDraw: Smart Dimension tool : Integrate chain and coord dimensions. --- src/Gui/ToolHandler.cpp | 5 - src/Gui/ToolHandler.h | 4 +- src/Mod/TechDraw/App/DrawDimHelper.h | 2 +- src/Mod/TechDraw/Gui/CommandCreateDims.cpp | 315 ++++++++++++++---- src/Mod/TechDraw/Gui/CommandExtensionDims.cpp | 78 ++++- src/Mod/TechDraw/Gui/CommandExtensionDims.h | 3 + src/Mod/TechDraw/Gui/Workbench.cpp | 6 +- 7 files changed, 333 insertions(+), 80 deletions(-) diff --git a/src/Gui/ToolHandler.cpp b/src/Gui/ToolHandler.cpp index 683d3dc189..e21036a72b 100644 --- a/src/Gui/ToolHandler.cpp +++ b/src/Gui/ToolHandler.cpp @@ -45,11 +45,6 @@ using namespace Gui; /**************************** ToolHandler *******************************************/ -ToolHandler::ToolHandler() -{} - -ToolHandler::~ToolHandler() -{} QString ToolHandler::getCrosshairCursorSVGName() const { diff --git a/src/Gui/ToolHandler.h b/src/Gui/ToolHandler.h index 4532bc3a54..100fa5bd5f 100644 --- a/src/Gui/ToolHandler.h +++ b/src/Gui/ToolHandler.h @@ -40,8 +40,8 @@ class View3DInventorViewer; class GuiExport ToolHandler { public: - ToolHandler(); - virtual ~ToolHandler(); + ToolHandler() = default; + virtual ~ToolHandler() = default; bool activate(); virtual void deactivate(); diff --git a/src/Mod/TechDraw/App/DrawDimHelper.h b/src/Mod/TechDraw/App/DrawDimHelper.h index e645e5accf..6490ecfbc4 100644 --- a/src/Mod/TechDraw/App/DrawDimHelper.h +++ b/src/Mod/TechDraw/App/DrawDimHelper.h @@ -52,7 +52,7 @@ class TechDrawExport DrawDimHelper { static DrawViewDimension* makeExtentDim(DrawViewPart* dvp, std::vector edgeNames, int direction); - + static void makeExtentDim3d(DrawViewPart* dvp, const std::string& dimType, ReferenceVector references2d); diff --git a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp index 1b193d0319..b26ca27803 100644 --- a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp +++ b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp @@ -28,6 +28,8 @@ #include #include +#include +#include #endif//#ifndef _PreComp_ #include @@ -60,6 +62,7 @@ #include "MDIViewPage.h" #include "TaskDimRepair.h" #include "TaskLinkDim.h" +#include "TaskSelectLineAttributes.h" #include "TechDrawHandler.h" #include "ViewProviderDimension.h" #include "ViewProviderDrawingView.h" @@ -94,7 +97,7 @@ DrawViewDimension* dimensionMaker(TechDraw::DrawViewPart* dvp, std::string dimTy DrawViewDimension* dimMaker(TechDraw::DrawViewPart* dvp, std::string dimType, ReferenceVector references2d, ReferenceVector references3d); -void positionDimText(DrawViewDimension* dim); +void positionDimText(DrawViewDimension* dim, int indexOffset = 0); void activateHandler(TechDrawHandler* newHandler) { @@ -185,7 +188,7 @@ public: , removedRef(ReferenceEntry()) , initialSelection(std::move(refs)) , partFeat(pFeat) - , dim(nullptr) + , dims({}) , blockRemoveSel(false) { } @@ -205,24 +208,26 @@ public: enum class SpecialDimension { LineOr2PointsDistance, ExtendDistance, + ChainDistance, + CoordDistance, None }; - void activated() + void activated() override { Gui::Selection().setSelectionStyle(Gui::SelectionSingleton::SelectionStyle::GreedySelection); Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Insert Dimension")); handleInitialSelection(); } - void deactivated() + void deactivated() override { Gui::Selection().setSelectionStyle(Gui::SelectionSingleton::SelectionStyle::NormalSelection); Gui::Command::abortCommand(); } - void keyPressEvent(QKeyEvent* event) + void keyPressEvent(QKeyEvent* event) override { if (event->key() == Qt::Key_M && !selectionEmpty()) { if (availableDimension == AvailableDimension::FIRST) { @@ -249,7 +254,7 @@ public: event->accept(); } } - void keyReleaseEvent(QKeyEvent* event) + void keyReleaseEvent(QKeyEvent* event) override { if (event->key() == Qt::Key_Z && (QApplication::keyboardModifiers() & Qt::ControlModifier)) { // User trying to cancel with Ctrl-Z @@ -265,15 +270,41 @@ public: { previousPos = event->pos(); + if (dims.empty()){ + return; + } + + bool textToMiddle = false; + Base::Vector3d dirMaster, delta; //Change distance dimension based on position of mouse. if (specialDimension == SpecialDimension::LineOr2PointsDistance){ updateDistanceType(event->pos()); } - if (specialDimension == SpecialDimension::ExtendDistance){ + else if (specialDimension == SpecialDimension::ExtendDistance){ updateExtentDistanceType(event->pos()); } + else if (specialDimension == SpecialDimension::ChainDistance || specialDimension == SpecialDimension::CoordDistance){ + updateChainDistanceType(event->pos()); + textToMiddle = true; + pointPair pp = dims[0]->getLinearPoints(); + dirMaster = pp.second() - pp.first(); + //dirMaster.y = -dirMaster.y; // not needed because y is reversed between property X/Y and scenePositions - moveDimension(event->pos()); + QPointF firstPos = getDimLabel(dims[0])->pos(); + Base::Vector3d pMaster(firstPos.x(), firstPos.y(), 0.0); + Base::Vector3d ipDelta = DrawUtil::getTrianglePoint(pMaster, dirMaster, Base::Vector3d()); + delta = ipDelta.Normalize() * Rez::guiX(activeDimAttributes.getCascadeSpacing()); + } + + int i = 0; + for (auto* dim : dims) { + auto dimType = static_cast(dim->Type.getValue()); + moveDimension(event->pos(), dim, textToMiddle, dirMaster, delta, dimType, i); + + if (specialDimension == SpecialDimension::CoordDistance) { + i++; + } + } } QGIDatumLabel* getDimLabel(DrawViewDimension* d) @@ -288,35 +319,71 @@ public: } return qgivDimension->getDatumLabel(); } - void moveDimension(QPoint& pos) + void moveDimension(QPoint& pos, DrawViewDimension* dim, bool textToMiddle = false, Base::Vector3d dir = Base::Vector3d(), + Base::Vector3d delta = Base::Vector3d(), DimensionType type = DimensionType::Distance, int i = 0) { if (!dim) { return; } auto label = getDimLabel(dim); if (!label) { return; } - label->setPos(getDimPositionToBe(pos)); + label->setPos(getDimPositionToBe(pos, label->pos(), textToMiddle, dir, delta, type, i)); } - QPointF getDimPositionToBe(QPoint& pos) + QPointF getDimPositionToBe(QPoint& pos, QPointF curPos = QPointF(), bool textToMiddle = false, Base::Vector3d dir = Base::Vector3d(), + Base::Vector3d delta = Base::Vector3d(), DimensionType type = DimensionType::Distance, int i = 0) { auto* vpp = dynamic_cast(Gui::Application::Instance->getViewProvider(partFeat)); if (!vpp) { return QPointF(); } + QPointF scenePos = viewPage->mapToScene(pos) - vpp->getQView()->pos(); + + if (textToMiddle) { + // delta is for coord distances. i = 0 when it's a chain so delta is ignored. + float dimDistance = Rez::guiX(activeDimAttributes.getCascadeSpacing()); + if (type == DimensionType::Distance) { + Base::Vector3d pos3d(scenePos.x(), scenePos.y(), 0.0); + float xDim = curPos.x(); + float yDim = curPos.y(); + Base::Vector3d pDim(xDim, yDim, 0.0); + Base::Vector3d p3 = DrawUtil::getTrianglePoint(pos3d, dir, pDim); + p3 = p3 + delta * i; + scenePos = QPointF(p3.x, p3.y); + } + else if(type == DimensionType::DistanceX) { + pointPair pp = dims[0]->getLinearPoints(); + if (Rez::guiX(pp.first().y) > scenePos.y()) + dimDistance = -dimDistance; + + double y = scenePos.y() + i * dimDistance; + scenePos = QPointF(curPos.x(), y); + } + else if(type == DimensionType::DistanceY) { + pointPair pp = dims[0]->getLinearPoints(); + if (Rez::guiX(pp.first().x) > scenePos.x()) + dimDistance = -dimDistance; + + double x = scenePos.x() + i * dimDistance; + scenePos = QPointF(x, curPos.y()); + } + } + return scenePos; } void finishDimensionMove() { - auto label = getDimLabel(dim); - double x = Rez::appX(label->X()), y = Rez::appX(label->Y()); - Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.X = %f", - dim->getNameInDocument(), x); - Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.Y = %f", - dim->getNameInDocument(), -y); + for (auto* dim : dims) { + auto label = getDimLabel(dim); + double x = Rez::appX(label->X()), y = Rez::appX(label->Y()); + Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.X = %f", + dim->getNameInDocument(), x); + Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.Y = %f", + dim->getNameInDocument(), -y); + } } bool mousePressEvent(QMouseEvent* event) override { - if (event->button() == Qt::RightButton && dim) { + if (event->button() == Qt::RightButton && !dims.empty()) { Gui::Selection().clearSelection(); clearAndRestartCommand(); event->accept(); @@ -347,14 +414,13 @@ public: removedRef = ReferenceEntry(); } - Base::Console().Warning("h1\n"); - if (addedRef.getObject()) { - Base::Console().Warning("h2 -%s-\n", addedRef.getSubName()); + if (addedRef.hasGeometry()) { finalize = false; //Base::Console().Warning("AddSelection\n"); //add the geometry to its type vector. Temporarily if not selAllowed if (addedRef.getSubName() == "") { - Base::Console().Warning("h3\n"); + // Behavior deactivated for now because I found it annoying. + // To reactivate replace addedRef.hasGeometry() by addedRef.getObject() above. // This means user selected the view itself. if (selectionEmpty()) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); @@ -389,7 +455,7 @@ public: // Finalize if click on empty space. - if (finalize && dim) { + if (finalize && !dims.empty()) { finalizeCommand(); } return true; @@ -489,7 +555,7 @@ protected: TechDraw::DrawViewPart* partFeat; - DrawViewDimension* dim; + std::vector dims; bool blockRemoveSel; @@ -498,7 +564,7 @@ protected: if (initialSelection.size() == 0) { return; } - + availableDimension = AvailableDimension::FIRST; // Add the selected elements to their corresponding selection vectors @@ -513,7 +579,7 @@ protected: if (!selAllowed) { clearRefVectors(); } - } + } void finalizeCommand() { @@ -523,7 +589,7 @@ protected: // Ask for the value of datum dimensions ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/TechDraw"); - + Gui::Command::commitCommand(); // Touch the parent feature so the dimension in tree view appears as a child @@ -591,7 +657,7 @@ protected: return emptyVector; } - + /* bool notSelectedYet(const ReferenceEntry& elem) { @@ -646,6 +712,7 @@ protected: if (selection.has1Point()) { selAllowed = true; } else if (selection.has2Points()) { makeCts_2Point(selAllowed, pos); } else if (selection.has3Points()) { makeCts_3Point(selAllowed, pos); } + else if (selection.has4MorePoints()) { makeCts_4MorePoints(selAllowed, pos); } else if (selection.has1Point1Line()) { makeCts_1Point1Line(selAllowed, pos); } else if (selection.has1Point1Circle()) { makeCts_1Point1Circle(selAllowed, pos); } else if (selection.has1Point1Ellipse()) { makeCts_1Point1Ellipse(selAllowed, pos); } @@ -696,23 +763,46 @@ protected: void makeCts_3Point(bool& selAllowed, QPoint& pos) { - //angle + // chain distances, angle if (availableDimension == AvailableDimension::FIRST) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add 3-points angle dimension")); - create3pAngleDimension(selPoints[0], selPoints[1], selPoints[2], pos); + restartCommand(QT_TRANSLATE_NOOP("Command", "Add horizontal chain dimensions")); + createChainDimension("DistanceX", pos); selAllowed = true; } - else if (availableDimension == AvailableDimension::SECOND) { + if (availableDimension == AvailableDimension::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add horizontal coordinate dimensions")); + createCoordDimension("DistanceX", pos); + } + if (availableDimension == AvailableDimension::THIRD) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add 3-points angle dimension")); + create3pAngleDimension(selPoints[0], selPoints[1], selPoints[2], pos); + } + else if (availableDimension == AvailableDimension::FOURTH) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add 3-points angle dimension")); create3pAngleDimension(selPoints[1], selPoints[2], selPoints[0], pos); } - else if (availableDimension == AvailableDimension::THIRD) { + else if (availableDimension == AvailableDimension::FIFTH) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add 3-points angle dimension")); create3pAngleDimension(selPoints[2], selPoints[0], selPoints[1], pos); availableDimension = AvailableDimension::RESET; } } + void makeCts_4MorePoints(bool& selAllowed, QPoint& pos) + { + // chain distances + if (availableDimension == AvailableDimension::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add horizontal chain dimension")); + createChainDimension("DistanceX", pos); + selAllowed = true; + } + if (availableDimension == AvailableDimension::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add horizontal coordinate dimensions")); + createCoordDimension("DistanceX", pos); + availableDimension = AvailableDimension::RESET; + } + } + void makeCts_1Point1Line(bool& selAllowed, QPoint& pos) { //distance @@ -926,6 +1016,7 @@ protected: bool dimensioningDiameter = hGrp->GetBool("DimensioningDiameter", true); bool dimensioningRadius = hGrp->GetBool("DimensioningRadius", true); + DrawViewDimension* dim; if ((firstCstr && dimensioningRadius && !dimensioningDiameter) || (!firstCstr && !dimensioningRadius && dimensioningDiameter) || (firstCstr && dimensioningRadius && dimensioningDiameter && !isCircleGeom) || @@ -936,7 +1027,8 @@ protected: dim = dimMaker(partFeat, "Diameter", { ref }, {}); } - moveDimension(pos); + dims.push_back(dim); + moveDimension(pos, dim); } void createAngleDimension(ReferenceEntry ref1, ReferenceEntry ref2, QPoint& pos) { @@ -947,23 +1039,26 @@ protected: return; } - dim = dimMaker(partFeat, "Angle", {ref1, ref2}, {}); + DrawViewDimension* dim = dimMaker(partFeat, "Angle", {ref1, ref2}, {}); - moveDimension(pos); + dims.push_back(dim); + moveDimension(pos, dim); } void create3pAngleDimension(ReferenceEntry ref1, ReferenceEntry ref2, ReferenceEntry ref3, QPoint& pos) { - dim = dimMaker(partFeat, "Angle3Pt", {ref1, ref2, ref3}, {}); + DrawViewDimension* dim = dimMaker(partFeat, "Angle3Pt", {ref1, ref2, ref3}, {}); - moveDimension(pos); + dims.push_back(dim); + moveDimension(pos, dim); } void createArcLengthDimension(ReferenceEntry ref, QPoint& pos) { - dim = makeArcLengthDimension(ref); + DrawViewDimension* dim = makeArcLengthDimension(ref); - moveDimension(pos); + dims.push_back(dim); + moveDimension(pos, dim); } void createDistanceDimension(std::string type, ReferenceEntry ref1, ReferenceEntry ref2, QPoint& pos) { @@ -972,28 +1067,30 @@ protected: refs.push_back(ref2); } - dim = dimMaker(partFeat, type, refs, {}); + DrawViewDimension* dim = dimMaker(partFeat, type, refs, {}); - moveDimension(pos); + dims.push_back(dim); + moveDimension(pos, dim); } void createExtentDistanceDimension(std::string type, QPoint& pos) { specialDimension = SpecialDimension::ExtendDistance; - dim = DrawDimHelper::makeExtentDim(partFeat, type, allRefs()); + DrawViewDimension* dim = DrawDimHelper::makeExtentDim(partFeat, type, allRefs()); - moveDimension(pos); + dims.push_back(dim); + moveDimension(pos, dim); } void updateDistanceType(QPoint& pos) { - if (!dim) { + if (dims.empty()) { return; } - auto type = static_cast(dim->Type.getValue()); - - TechDraw::pointPair pp = dim->getLinearPoints(); + auto type = static_cast(dims[0]->Type.getValue()); + + TechDraw::pointPair pp = dims[0]->getLinearPoints(); Base::Vector3d pnt1 = Rez::guiX(pp.first()); Base::Vector3d pnt2 = Rez::guiX(pp.second()); @@ -1035,13 +1132,13 @@ protected: void updateExtentDistanceType(QPoint& pos) { - if (!dim) { + if (dims.empty()) { return; } - auto d =dim->References2D.getValues()[0]; - auto type = static_cast(dim->Type.getValue()); - - TechDraw::pointPair pp = dim->getLinearPoints(); + + auto type = static_cast(dims[0]->Type.getValue()); + + TechDraw::pointPair pp = dims[0]->getLinearPoints(); Base::Vector3d pnt1 = Rez::guiX(pp.first()); Base::Vector3d pnt2 = Rez::guiX(pp.second()); @@ -1056,24 +1153,112 @@ protected: if (fpos.x() > minX && fpos.x() < maxX && (fpos.y() < minY || fpos.y() > maxY) && type != DimensionType::DistanceX) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceX extent dimension")); - specialDimension = SpecialDimension::LineOr2PointsDistance; createExtentDistanceDimension("DistanceX", pos); } else if (fpos.y() > minY && fpos.y() < maxY && (fpos.x() < minX || fpos.x() > maxX) && type != DimensionType::DistanceY) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceY extent dimension")); - specialDimension = SpecialDimension::LineOr2PointsDistance; createExtentDistanceDimension("DistanceY", pos); } } + void updateChainDistanceType(QPoint& pos) + { + if (dims.empty()) { + return; + } + + double minX = DBL_MAX; + double minY = DBL_MAX; + double maxX = -DBL_MAX; + double maxY = -DBL_MAX; + for (auto dim : dims) { + TechDraw::pointPair pp = dim->getLinearPoints(); + Base::Vector3d pnt1 = Rez::guiX(pp.first()); + Base::Vector3d pnt2 = Rez::guiX(pp.second()); + + minX = min(minX, min(pnt1.x, pnt2.x)); + maxX = max(maxX, max(pnt1.x, pnt2.x)); + minY = min(minY, min(pnt1.y, pnt2.y)); + maxY = max(maxY, max(pnt1.y, pnt2.y)); + } + + QPointF fpos = getDimPositionToBe(pos); + + auto type = static_cast(dims[0]->Type.getValue()); + + if (fpos.x() > minX && fpos.x() < maxX + && (fpos.y() < minY || fpos.y() > maxY) && type != DimensionType::DistanceX) { + if (specialDimension == SpecialDimension::ChainDistance) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add horizontal chain dimensions")); + createChainDimension("DistanceX", pos); + } + else { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add horizontal coord dimensions")); + createCoordDimension("DistanceX", pos); + } + } + else if (fpos.y() > minY && fpos.y() < maxY + && (fpos.x() < minX || fpos.x() > maxX) && type != DimensionType::DistanceY) { + if (specialDimension == SpecialDimension::ChainDistance) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add vertical chain dimensions")); + createChainDimension("DistanceY", pos); + } + else { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add vertical coord dimensions")); + createCoordDimension("DistanceY", pos); + } + } + else if (((fpos.y() < minY || fpos.y() > maxY) && (fpos.x() < minX || fpos.x() > maxX)) && type != DimensionType::Distance) { + if (specialDimension == SpecialDimension::ChainDistance) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add oblique chain dimensions")); + createChainDimension("Distance", pos); + } + else { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add oblique coord dimensions")); + createCoordDimension("Distance", pos); + } + } + } + + void createChainDimension(std::string type, QPoint& pos) + { + specialDimension = SpecialDimension::ChainDistance; + if (type == "Distance") { + dims = makeObliqueChainDimension(selPoints); + } + else { + for (size_t i = 0; i < selPoints.size() - 1; ++i) { + DrawViewDimension* dim = dimMaker(partFeat, type, { selPoints[i], selPoints[i + 1] }, {}); + + dims.push_back(dim); + positionDimText(dim); + } + } + } + + void createCoordDimension(std::string type, QPoint& pos) + { + specialDimension = SpecialDimension::CoordDistance; + if (type == "Distance") { + dims = makeObliqueCoordDimension(selPoints); + } + else { + for (size_t i = 0; i < selPoints.size() - 1; ++i) { + DrawViewDimension* dim = dimMaker(partFeat, type, { selPoints[0], selPoints[i + 1] }, {}); + + dims.push_back(dim); + positionDimText(dim, i); + } + } + } void restartCommand(const char* cstrName) { specialDimension = SpecialDimension::None; Gui::Command::abortCommand(); Gui::Command::openCommand(cstrName); - dim = nullptr; + dims.clear(); } void clearAndRestartCommand() { @@ -1083,7 +1268,7 @@ protected: previousPos = QPoint(0,0); clearRefVectors(); partFeat = nullptr; - dim = nullptr; + dims.clear(); } void clearRefVectors() @@ -1162,8 +1347,17 @@ public: addCommand("TechDraw_AngleDimension"); addCommand("TechDraw_3PtAngleDimension"); addCommand("TechDraw_ExtensionCreateLengthArc"); + addCommand(); //separator addCommand("TechDraw_HorizontalExtentDimension"); addCommand("TechDraw_VerticalExtentDimension"); + addCommand(); //separator + addCommand("TechDraw_ExtensionCreateHorizChainDimension"); + addCommand("TechDraw_ExtensionCreateVertChainDimension"); + addCommand("TechDraw_ExtensionCreateObliqueChainDimension"); + addCommand(); //separator + addCommand("TechDraw_ExtensionCreateHorizCoordDimension"); + addCommand("TechDraw_ExtensionCreateVertCoordDimension"); + addCommand("TechDraw_ExtensionCreateObliqueCoordDimension"); } const char* className() const override { return "CmdTechDrawCompDimensionTools"; } @@ -2392,6 +2586,8 @@ void CreateTechDrawCommandsDims() DrawViewDimension* dimensionMaker(TechDraw::DrawViewPart* dvp, std::string dimType, ReferenceVector references2d, ReferenceVector references3d) { + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create Dimension")); + TechDraw::DrawViewDimension* dim = dimMaker(dvp, dimType, references2d, references3d); Gui::Command::commitCommand(); @@ -2414,7 +2610,6 @@ DrawViewDimension* dimMaker(TechDraw::DrawViewPart* dvp, std::string dimType, std::string dimName = dvp->getDocument()->getUniqueObjectName("Dimension"); - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create Dimension")); Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().addObject('TechDraw::DrawViewDimension', '%s')", dimName.c_str()); @@ -2451,13 +2646,13 @@ DrawViewDimension* dimMaker(TechDraw::DrawViewPart* dvp, std::string dimType, } //position the Dimension text on the view -void positionDimText(DrawViewDimension* dim) +void positionDimText(DrawViewDimension* dim, int offsetIndex) { TechDraw::pointPair pp = dim->getLinearPoints(); Base::Vector3d mid = (pp.first() + pp.second()) / 2.0; dim->X.setValue(mid.x); double fontSize = Preferences::dimFontSizeMM(); - dim->Y.setValue(-mid.y + 0.5 * fontSize); + dim->Y.setValue(-mid.y + (offsetIndex * 1.5 + 0.5) * fontSize); } //=========================================================================== // Selection Validation Helpers diff --git a/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp b/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp index bf55681a0d..64e32d561c 100644 --- a/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp +++ b/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp @@ -1405,7 +1405,37 @@ void execCreateObliqueChainDimension(Gui::Command* cmd) { } Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create Oblique Chain Dim")); - const std::vector subNames = selection[0].getSubNames(); + + std::vector refs; + for (auto& subName : selection[0].getSubNames()) { + refs.push_back(ReferenceEntry(objFeat, subName)); + } + + auto dims = makeObliqueChainDimension(refs); + if(dims.empty()){ + Gui::Command::abortCommand(); + } + else { + objFeat->refreshCEGeoms(); + objFeat->requestPaint(); + cmd->getSelection().clearSelection(); + Gui::Command::commitCommand(); + } +} + +std::vector TechDrawGui::makeObliqueChainDimension(std::vector refs) +{ + if (refs.empty()) { + return {}; + } + + std::vector subNames; + auto* objFeat = static_cast(refs[0].getObject()); + for (auto& ref : refs) { + subNames.push_back(ref.getSubName()); + } + std::vector dims; + std::vector allVertexes, carrierVertexes; allVertexes = _getVertexInfo(objFeat, subNames); if (!allVertexes.empty() && allVertexes.size() > 1) { @@ -1449,12 +1479,11 @@ void execCreateObliqueChainDimension(Gui::Command* cmd) { Base::Vector3d mid = (pp.first() + pp.second()) / 2.0 + delta; dim->X.setValue(mid.x); dim->Y.setValue(-mid.y + 0.5 * fontSize); + dims.push_back(dim); } - objFeat->refreshCEGeoms(); - objFeat->requestPaint(); - cmd->getSelection().clearSelection(); - Gui::Command::commitCommand(); } + + return dims; } DEF_STD_CMD_A(CmdTechDrawExtensionCreateObliqueChainDimension) @@ -1761,7 +1790,37 @@ void execCreateObliqueCoordDimension(Gui::Command* cmd) { } Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create Oblique Coord Dim")); - const std::vector subNames = selection[0].getSubNames(); + + std::vector refs; + for (auto& subName : selection[0].getSubNames()) { + refs.push_back(ReferenceEntry(objFeat, subName)); + } + + auto dims = makeObliqueCoordDimension(refs); + if (dims.empty()) { + Gui::Command::abortCommand(); + } + else { + objFeat->refreshCEGeoms(); + objFeat->requestPaint(); + cmd->getSelection().clearSelection(); + Gui::Command::commitCommand(); + } +} + +std::vector TechDrawGui::makeObliqueCoordDimension(std::vector refs) +{ + if (refs.empty()) { + return {}; + } + + std::vector subNames; + auto* objFeat = static_cast(refs[0].getObject()); + for (auto& ref : refs) { + subNames.push_back(ref.getSubName()); + } + std::vector dims; + std::vector allVertexes, carrierVertexes; allVertexes = _getVertexInfo(objFeat, subNames); if (!allVertexes.empty() && allVertexes.size() > 1) { @@ -1810,12 +1869,11 @@ void execCreateObliqueCoordDimension(Gui::Command* cmd) { Base::Vector3d mid = (pp.first() + pp.second()) / 2.0 + delta * (n + 1); dim->X.setValue(mid.x); dim->Y.setValue(-mid.y + 0.5 * fontSize); + dims.push_back(dim); } } - objFeat->refreshCEGeoms(); - objFeat->requestPaint(); - cmd->getSelection().clearSelection(); - Gui::Command::commitCommand(); + + return dims; } DEF_STD_CMD_A(CmdTechDrawExtensionCreateObliqueCoordDimension) diff --git a/src/Mod/TechDraw/Gui/CommandExtensionDims.h b/src/Mod/TechDraw/Gui/CommandExtensionDims.h index e94fcbc6ce..aebb200b29 100644 --- a/src/Mod/TechDraw/Gui/CommandExtensionDims.h +++ b/src/Mod/TechDraw/Gui/CommandExtensionDims.h @@ -30,6 +30,9 @@ namespace TechDraw namespace TechDrawGui { TechDraw::DrawViewDimension* makeArcLengthDimension(const TechDraw::ReferenceEntry& ref); + + std::vector makeObliqueChainDimension(std::vector refs); + std::vector makeObliqueCoordDimension(std::vector refs); } #endif // TECHDRAWGUI_CommandExtensionDims_H diff --git a/src/Mod/TechDraw/Gui/Workbench.cpp b/src/Mod/TechDraw/Gui/Workbench.cpp index 519941bccd..7087966df1 100644 --- a/src/Mod/TechDraw/Gui/Workbench.cpp +++ b/src/Mod/TechDraw/Gui/Workbench.cpp @@ -361,8 +361,10 @@ Gui::ToolBarItem* Workbench::setupToolBars() const Gui::ToolBarItem* extdimensions = new Gui::ToolBarItem(root); extdimensions->setCommand("TechDraw Extend Dimensions"); - *extdimensions << "TechDraw_ExtensionCreateChainDimensionGroup"; - *extdimensions << "TechDraw_ExtensionCreateCoordDimensionGroup"; + if (separatedTools) { + *extdimensions << "TechDraw_ExtensionCreateChainDimensionGroup"; + *extdimensions << "TechDraw_ExtensionCreateCoordDimensionGroup"; + } *extdimensions << "TechDraw_ExtensionChamferDimensionGroup"; if (separatedTools) { *extdimensions << "TechDraw_ExtensionCreateLengthArc"; From 8c5cfd23ec0e7dd438a66090d2231c69018e90a8 Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Sun, 21 Apr 2024 07:57:13 +0200 Subject: [PATCH 6/9] TechDraw: Improve Arc Length dimension tool so that it can do any edge length: arc of ellipse, bspline. --- src/Mod/TechDraw/Gui/CommandCreateDims.cpp | 24 ++++++- src/Mod/TechDraw/Gui/CommandExtensionDims.cpp | 70 +++++++++---------- src/Mod/TechDraw/Gui/Workbench.cpp | 4 +- 3 files changed, 61 insertions(+), 37 deletions(-) diff --git a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp index b26ca27803..14a565a303 100644 --- a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp +++ b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp @@ -163,7 +163,8 @@ public: bool has1Ellipse() const { return s_pts == 0 && s_lns == 0 && s_cir == 0 && s_ell == 1 && s_spl == 0 && s_fcs == 0; } bool has2Ellipses() const { return s_pts == 0 && s_lns == 0 && s_cir == 0 && s_ell == 2 && s_spl == 0 && s_fcs == 0; } - bool has1SplineAndMore() const { return s_pts >= 0 && s_lns >= 0 && s_cir >= 0 && s_ell >= 0 && s_spl >= 1 && s_fcs == 0; } + bool has1Spline() const { return s_pts == 0 && s_lns == 0 && s_cir == 0 && s_ell == 0 && s_spl == 1 && s_fcs == 0; } + bool has1SplineAndMore() const { return s_spl >= 1 && s_fcs == 0; } size_t s_pts, s_lns, s_cir, s_ell, s_spl, s_fcs; }; @@ -732,6 +733,7 @@ protected: if (selection.has2Ellipses()) { makeCts_2Ellipses(selAllowed, pos); } } else if (selection.hasSplineAndCo()) { + if (selection.has1Spline()) { makeCts_1Spline(selAllowed, pos); } if (selection.has1SplineAndMore()) { makeCts_1SplineAndMore(selAllowed, pos); } } return selAllowed; @@ -947,6 +949,13 @@ protected: if (availableDimension == AvailableDimension::SECOND) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Radius dimension")); createRadiusDiameterDimension(selEllipseArc[0], pos, false); + if (selEllipseArc[0].geomEdgeType() != TechDraw::ARCOFELLIPSE) { + availableDimension = AvailableDimension::RESET; + } + } + if (availableDimension == AvailableDimension::THIRD) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Arc Length dimension")); + createArcLengthDimension(selEllipseArc[0], pos); availableDimension = AvailableDimension::RESET; } } @@ -966,6 +975,17 @@ protected: } } + void makeCts_1Spline(bool& selAllowed, QPoint& pos) + { + //Edge length + if (availableDimension == AvailableDimension::FIRST) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add edge length dimension")); + createArcLengthDimension(selSplineAndCo[0], pos); + selAllowed = true; + availableDimension = AvailableDimension::RESET; + } + } + void makeCts_1SplineAndMore(bool& selAllowed, QPoint& pos) { //Extend @@ -1379,6 +1399,8 @@ CmdTechDrawRadiusDimension::CmdTechDrawRadiusDimension() sWhatsThis = "TechDraw_RadiusDimension"; sStatusTip = sToolTipText; sPixmap = "TechDraw_RadiusDimension"; + sAccel = "D"; + eType = ForEdit; } void CmdTechDrawRadiusDimension::activated(int iMsg) diff --git a/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp b/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp index 64e32d561c..5a777b5b5f 100644 --- a/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp +++ b/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp @@ -2305,6 +2305,8 @@ void CmdTechDrawExtensionCreateLengthArc::activated(int iMsg) { TechDraw::DrawViewDimension* dim = makeArcLengthDimension(ref); if (dim) { + objFeat->refreshCEGeoms(); + objFeat->requestPaint(); Gui::Command::commitCommand(); } else { @@ -2366,42 +2368,40 @@ DrawViewDimension* TechDrawGui::makeArcLengthDimension(const ReferenceEntry& ref int geoId = DrawUtil::getIndexFromName(ref.getSubName()); BaseGeomPtr geom = dvp->getGeomByIndex(geoId); - if (ref.geomEdgeType() == TechDraw::ARCOFCIRCLE) { - TechDraw::AOCPtr arcTag = std::static_pointer_cast(geom); - float radius = arcTag->radius; - Base::Vector3d centerPt = arcTag->center; - centerPt.y = -centerPt.y; - Base::Vector3d startPt = arcTag->startPnt; - startPt.y = -startPt.y; - Base::Vector3d endPt = arcTag->endPnt; - endPt.y = -endPt.y; - - std::stringstream startName, endName, formatSpec; - double scale = dvp->getScale(); - Base::Vector3d cvPoint = CosmeticVertex::makeCanonicalPoint(dvp, startPt); - std::string startVertTag = dvp->addCosmeticVertex(cvPoint); - int startVertNumber = dvp->add1CVToGV(startVertTag); - startName << "Vertex" << startVertNumber; - cvPoint = CosmeticVertex::makeCanonicalPoint(dvp, endPt); - std::string endVertTag = dvp->addCosmeticVertex(cvPoint); - int endVertNumber = dvp->add1CVToGV(endVertTag); - endName << "Vertex" << endVertNumber; - - dim = _createLinDimension(dvp, startName.str(), endName.str(), "Distance"); - TechDraw::pointPair pp = dim->getLinearPoints(); - Base::Vector3d mid = (pp.first() + pp.second()) / 2.0; - dim->X.setValue(mid.x); - dim->Y.setValue(-mid.y); - Base::Vector3d radVec1 = startPt - centerPt; - Base::Vector3d radVec2 = endPt - centerPt; - float alpha = acos((radVec1 * radVec2) / (radVec1.Length() * radVec2.Length())); - float arcLength = alpha * radius / scale; - dim->Arbitrary.setValue(true); - formatSpec << "◠ " << arcLength; - dim->FormatSpec.setValue(formatSpec.str()); - dvp->refreshCEGeoms(); - dvp->requestPaint(); + // Find the edge length. + TechDraw::BaseGeomPtr edge = dvp->getEdge(ref.getSubName()); + if (!edge) { + return nullptr; } + GProp_GProps edgeProps; + BRepGProp::LinearProperties(edge->getOCCEdge(), edgeProps); + double length = edgeProps.Mass(); + + Base::Vector3d startPt = edge->getStartPoint(); + Base::Vector3d endPt = edge->getEndPoint(); + startPt.y = -startPt.y; + endPt.y = -endPt.y; + + std::stringstream startName, endName, formatSpec; + double scale = dvp->getScale(); + Base::Vector3d cvPoint = CosmeticVertex::makeCanonicalPoint(dvp, startPt); + std::string startVertTag = dvp->addCosmeticVertex(cvPoint); + int startVertNumber = dvp->add1CVToGV(startVertTag); + startName << "Vertex" << startVertNumber; + cvPoint = CosmeticVertex::makeCanonicalPoint(dvp, endPt); + std::string endVertTag = dvp->addCosmeticVertex(cvPoint); + int endVertNumber = dvp->add1CVToGV(endVertTag); + endName << "Vertex" << endVertNumber; + + dim = _createLinDimension(dvp, startName.str(), endName.str(), "Distance"); + TechDraw::pointPair pp = dim->getLinearPoints(); + Base::Vector3d mid = (pp.first() + pp.second()) / 2.0; + dim->X.setValue(mid.x); + dim->Y.setValue(-mid.y); + + dim->Arbitrary.setValue(true); + formatSpec << "◠ " << length; + dim->FormatSpec.setValue(formatSpec.str()); return dim; } diff --git a/src/Mod/TechDraw/Gui/Workbench.cpp b/src/Mod/TechDraw/Gui/Workbench.cpp index 7087966df1..a3abac5e24 100644 --- a/src/Mod/TechDraw/Gui/Workbench.cpp +++ b/src/Mod/TechDraw/Gui/Workbench.cpp @@ -347,7 +347,9 @@ Gui::ToolBarItem* Workbench::setupToolBars() const *extattribs << "TechDraw_ExtensionPosChainDimensionGroup"; *extattribs << "TechDraw_ExtensionCascadeDimensionGroup"; *extattribs << "TechDraw_ExtensionAreaAnnotation"; - *extattribs << "TechDraw_ExtensionArcLengthAnnotation"; + if (separatedTools) { + *extattribs << "TechDraw_ExtensionArcLengthAnnotation"; + } *extattribs << "TechDraw_ExtensionCustomizeFormat"; Gui::ToolBarItem* extcenter = new Gui::ToolBarItem(root); From 41650a78d4c9199b4bd5fd252fb03eb87690d08e Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Mon, 22 Apr 2024 14:52:30 +0200 Subject: [PATCH 7/9] TechDraw: Implement 'Area' dimension. --- src/Mod/TechDraw/App/DimensionFormatter.cpp | 40 +++-- src/Mod/TechDraw/App/DimensionGeometry.cpp | 32 ++++ src/Mod/TechDraw/App/DimensionGeometry.h | 18 +++ src/Mod/TechDraw/App/DimensionReferences.cpp | 26 +++- src/Mod/TechDraw/App/DimensionReferences.h | 1 + src/Mod/TechDraw/App/DrawViewDimension.cpp | 92 ++++++++++-- src/Mod/TechDraw/App/DrawViewDimension.h | 9 ++ src/Mod/TechDraw/App/Geometry.cpp | 7 + src/Mod/TechDraw/App/Geometry.h | 1 + src/Mod/TechDraw/App/GeometryMatcher.cpp | 27 ++++ src/Mod/TechDraw/App/GeometryMatcher.h | 1 + src/Mod/TechDraw/Gui/CommandCreateDims.cpp | 140 +++++++++++++----- src/Mod/TechDraw/Gui/CommandExtensionDims.cpp | 2 + src/Mod/TechDraw/Gui/DimensionValidators.cpp | 51 ++++++- src/Mod/TechDraw/Gui/DimensionValidators.h | 3 + src/Mod/TechDraw/Gui/QGIViewDimension.cpp | 91 +++++++++++- src/Mod/TechDraw/Gui/QGIViewDimension.h | 4 + src/Mod/TechDraw/Gui/Resources/TechDraw.qrc | 1 + .../icons/TechDraw_AreaDimension.svg | 88 +++++++++++ .../TechDraw/Gui/ViewProviderDimension.cpp | 2 + src/Mod/TechDraw/Gui/Workbench.cpp | 4 +- 21 files changed, 580 insertions(+), 60 deletions(-) create mode 100644 src/Mod/TechDraw/Gui/Resources/icons/TechDraw_AreaDimension.svg diff --git a/src/Mod/TechDraw/App/DimensionFormatter.cpp b/src/Mod/TechDraw/App/DimensionFormatter.cpp index 1c78d2357e..0b9b756d09 100644 --- a/src/Mod/TechDraw/App/DimensionFormatter.cpp +++ b/src/Mod/TechDraw/App/DimensionFormatter.cpp @@ -63,16 +63,19 @@ std::string DimensionFormatter::formatValue(const qreal value, { // Base::Console().Message("DF::formatValue() - %s isRestoring: %d\n", // m_dimension->getNameInDocument(), m_dimension->isRestoring()); - bool angularMeasure = false; + bool angularMeasure = m_dimension->Type.isValue("Angle") || m_dimension->Type.isValue("Angle3Pt"); + bool areaMeasure = m_dimension->Type.isValue("Area"); QLocale loc; Base::Quantity asQuantity; asQuantity.setValue(value); - if ( (m_dimension->Type.isValue("Angle")) || - (m_dimension->Type.isValue("Angle3Pt")) ) { - angularMeasure = true; + if (angularMeasure) { asQuantity.setUnit(Base::Unit::Angle); - } else { + } + else if (areaMeasure) { + asQuantity.setUnit(Base::Unit::Area); + } + else { asQuantity.setUnit(Base::Unit::Length); } @@ -88,6 +91,9 @@ std::string DimensionFormatter::formatValue(const qreal value, QString qMultiValueStr; QString qBasicUnit = Base::Tools::fromStdString(Base::UnitsApi::getBasicLengthUnit()); + if (areaMeasure) { + qBasicUnit = qBasicUnit + QString::fromUtf8("²"); + } QString formattedValue; if (isMultiValueSchema() && partial == 0) { @@ -128,7 +134,8 @@ std::string DimensionFormatter::formatValue(const qreal value, if (angularMeasure) { userVal = asQuantity.getValue(); qBasicUnit = QString::fromUtf8("°"); - } else { + } + else { double convertValue = Base::Quantity::parse(QString::fromLatin1("1") + qBasicUnit).getValue(); userVal = asQuantity.getValue() / convertValue; } @@ -153,37 +160,44 @@ std::string DimensionFormatter::formatValue(const qreal value, return Base::Tools::toStdString(formatPrefix) + Base::Tools::toStdString(qUserString) + Base::Tools::toStdString(formatSuffix); - } else if (partial == 1) { // prefix number[unit] suffix + } + else if (partial == 1) { // prefix number[unit] suffix if (angularMeasure) { //always insert unit after value return Base::Tools::toStdString(formatPrefix) + formattedValueString + "°" + Base::Tools::toStdString(formatSuffix); - } else if (m_dimension->showUnits()){ + } + else if (m_dimension->showUnits() || areaMeasure){ if (isDim && m_dimension->haveTolerance()) { //unit will be included in tolerance so don't repeat it here return Base::Tools::toStdString(formatPrefix) + formattedValueString + Base::Tools::toStdString(formatSuffix); - } else { + } + else { //no tolerance, so we need to include unit return Base::Tools::toStdString(formatPrefix) + formattedValueString + " " + Base::Tools::toStdString(qBasicUnit) + Base::Tools::toStdString(formatSuffix); } - } else { + } + else { //showUnits is false return Base::Tools::toStdString(formatPrefix) + formattedValueString + Base::Tools::toStdString(formatSuffix); } - } else if (partial == 2) { // just the unit + } + else if (partial == 2) { // just the unit if (angularMeasure) { return Base::Tools::toStdString(qBasicUnit); - } else if (m_dimension->showUnits()) { + } + else if (m_dimension->showUnits() || areaMeasure) { return Base::Tools::toStdString(qBasicUnit); - } else { + } + else { return ""; } } diff --git a/src/Mod/TechDraw/App/DimensionGeometry.cpp b/src/Mod/TechDraw/App/DimensionGeometry.cpp index 60186d6b96..fad87f1308 100644 --- a/src/Mod/TechDraw/App/DimensionGeometry.cpp +++ b/src/Mod/TechDraw/App/DimensionGeometry.cpp @@ -361,3 +361,35 @@ void arcPoints::dump(const std::string& text) const DrawUtil::formatVector(arcEnds.second()).c_str()); Base::Console().Message("arcPoints - midArc: %s\n", DrawUtil::formatVector(midArc).c_str()); } + + +areaPoint::areaPoint() : + area(0.0), + center(Base::Vector3d()) +{ +} + +areaPoint& areaPoint::operator=(const areaPoint& ap) +{ + area = ap.area; + center = ap.center; + return *this; +} + +void areaPoint::move(const Base::Vector3d& offset) +{ + center = center - offset; +} + +void areaPoint::project(const DrawViewPart* dvp) +{ + area = area * dvp->getScale(); + center = dvp->projectPoint(center) * dvp->getScale(); +} + +void areaPoint::dump(const std::string& text) const +{ + Base::Console().Message("areaPoint - %s\n", text.c_str()); + Base::Console().Message("areaPoint - area: %.3f center: %s\n", area, + DrawUtil::formatVector(center).c_str()); +} diff --git a/src/Mod/TechDraw/App/DimensionGeometry.h b/src/Mod/TechDraw/App/DimensionGeometry.h index 3a651dbe48..0a74b2e2eb 100644 --- a/src/Mod/TechDraw/App/DimensionGeometry.h +++ b/src/Mod/TechDraw/App/DimensionGeometry.h @@ -156,6 +156,24 @@ public: bool arcCW; }; +//a convenient container for area dimension +class TechDrawExport areaPoint +{ +public: + areaPoint(); + areaPoint(const areaPoint& ap) = default; + + areaPoint& operator= (const areaPoint& ap); + + void move(const Base::Vector3d& offset); + void project(const DrawViewPart* dvp); + void dump(const std::string& text) const; + +//TODO: setters and getters + double area; + Base::Vector3d center; +}; + } //end namespace TechDraw #endif diff --git a/src/Mod/TechDraw/App/DimensionReferences.cpp b/src/Mod/TechDraw/App/DimensionReferences.cpp index 0ff93e4819..68a1176986 100644 --- a/src/Mod/TechDraw/App/DimensionReferences.cpp +++ b/src/Mod/TechDraw/App/DimensionReferences.cpp @@ -212,6 +212,10 @@ Part::TopoShape ReferenceEntry::asTopoShape() const TopoDS_Edge edge = TopoDS::Edge(geom); return asTopoShapeEdge(edge); } + if (geom.ShapeType() == TopAbs_FACE) { + TopoDS_Face face = TopoDS::Face(geom); + return asTopoShapeFace(face); + } throw Base::RuntimeError("Dimension Reference has unsupported geometry"); } @@ -259,6 +263,19 @@ Part::TopoShape ReferenceEntry::asTopoShapeEdge(const TopoDS_Edge &edge) return { edge }; } +Part::TopoShape ReferenceEntry::asTopoShapeFace(const TopoDS_Face &face) +{ +// Base::Console().Message("RE::asTopoShapeFace()\n"); + TopoDS_Face unscaledFace = face; + if (!is3d()) { + // 2d reference - projected and scaled. scale might have changed, so we need to unscale + auto dvp = static_cast(getObject()); + TopoDS_Shape unscaledShape = ShapeUtils::scaleShape(face, 1.0 / dvp->getScale()); + unscaledFace = TopoDS::Face(unscaledShape); + } + return { unscaledFace }; +} + std::string ReferenceEntry::geomType() const { // Base::Console().Message("RE::geomType() - subName: **%s**\n", getSubName().c_str()); @@ -333,12 +350,19 @@ bool ReferenceEntry::hasGeometry2d() const if (vert) { return true; } - } else if (gType == "Edge") { + } + else if (gType == "Edge") { auto edge = dvp->getGeomByIndex(geomNumber); if (edge) { return true; } } + else if (gType == "Face") { + auto face = dvp->getFace(getSubName()); + if (face) { + return true; + } + } return false; } diff --git a/src/Mod/TechDraw/App/DimensionReferences.h b/src/Mod/TechDraw/App/DimensionReferences.h index 47943623f6..faa5fd769c 100644 --- a/src/Mod/TechDraw/App/DimensionReferences.h +++ b/src/Mod/TechDraw/App/DimensionReferences.h @@ -90,6 +90,7 @@ private: static Part::TopoShape asTopoShapeVertex(const TopoDS_Vertex &vert); static Part::TopoShape asTopoShapeEdge(const TopoDS_Edge& edge); + static Part::TopoShape asTopoShapeFace(const TopoDS_Face& edge); App::DocumentObject* m_object{nullptr}; std::string m_subName; diff --git a/src/Mod/TechDraw/App/DrawViewDimension.cpp b/src/Mod/TechDraw/App/DrawViewDimension.cpp index 45c158a043..4f37c84be3 100644 --- a/src/Mod/TechDraw/App/DrawViewDimension.cpp +++ b/src/Mod/TechDraw/App/DrawViewDimension.cpp @@ -31,6 +31,8 @@ #include #include +#include +#include #include #include #include @@ -93,6 +95,7 @@ const char* DrawViewDimension::TypeEnums[] = {"Distance", "Diameter", "Angle", "Angle3Pt", + "Area", nullptr}; const char* DrawViewDimension::MeasureTypeEnums[] = {"True", "Projected", nullptr}; @@ -267,6 +270,12 @@ void DrawViewDimension::resetArc() m_arcPoints.arcCW = false; } +void DrawViewDimension::resetArea() +{ + m_areaPoint.center = Base::Vector3d(0, 0, 0); + m_areaPoint.area = 0.0; +} + void DrawViewDimension::onChanged(const App::Property* prop) { if (prop == &References3D) { @@ -461,6 +470,7 @@ App::DocumentObjectExecReturn* DrawViewDimension::execute() resetLinear(); resetAngular(); resetArc(); + resetArea(); // we have either or both valid References3D and References2D ReferenceVector references = getEffectiveReferences(); @@ -499,6 +509,13 @@ App::DocumentObjectExecReturn* DrawViewDimension::execute() m_anglePoints = getAnglePointsThreeVerts(references); m_hasGeometry = true; } + else if (Type.isValue("Area")) { + if (getRefType() != oneFace) { + throw Base::RuntimeError("area dimension has non-face references"); + } + m_areaPoint = getAreaParameters(references); + m_hasGeometry = true; + } overrideKeepUpdated(false); return DrawView::execute(); @@ -679,6 +696,9 @@ double DrawViewDimension::getTrueDimValue() const else if (Type.isValue("Angle") || Type.isValue("Angle3Pt")) { result = measurement->angle(); } + else if (Type.isValue("Area")) { + result = measurement->area(); + } else { // tarfu throw Base::ValueError("getDimValue() - Unknown Dimension Type (3)"); } @@ -721,9 +741,8 @@ double DrawViewDimension::getProjectedDimValue() const } } else if (Type.isValue("Radius")) { - arcPoints pts = m_arcPoints; - result = - pts.radius / getViewPart()->getScale(); // Projected BaseGeom is scaled for drawing + // Projected BaseGeom is scaled for drawing + result = m_arcPoints.radius / getViewPart()->getScale(); } else if (Type.isValue("Diameter")) { arcPoints pts = m_arcPoints; @@ -738,6 +757,9 @@ double DrawViewDimension::getProjectedDimValue() const double legAngle = Base::toDegrees(leg0.GetAngle(leg1)); result = legAngle; } + else if (Type.isValue("Area")) { + result = m_areaPoint.area / getViewPart()->getScale(); + } return result; } @@ -927,7 +949,7 @@ arcPoints DrawViewDimension::getArcParameters(ReferenceVector references) ssMessage << getNameInDocument() << " can not find geometry for 2d reference (4)"; throw Base::RuntimeError(ssMessage.str()); } - return arcPointsFromBaseGeom(getViewPart()->getGeomByIndex(iSubelement)); + return arcPointsFromBaseGeom(geom); } // this is a 3d reference @@ -1324,6 +1346,40 @@ anglePoints DrawViewDimension::getAnglePointsThreeVerts(ReferenceVector referenc return pts; } +areaPoint DrawViewDimension::getAreaParameters(ReferenceVector references) +{ + areaPoint pts; + + App::DocumentObject* refObject = references.front().getObject(); + if (refObject->isDerivedFrom() && !references[0].getSubName().empty()) { + // this is a 2d object (a DVP + subelements) + TechDraw::FacePtr face = getViewPart()->getFace(references[0].getSubName()); + if (!face) { + std::stringstream ssMessage; + ssMessage << getNameInDocument() << " can not find geometry for 2d reference (4)"; + throw Base::RuntimeError(ssMessage.str()); + } + + pts.area = face->getArea(); + pts.center = face->getCenter(); + } + else { + // this is a 3d reference + TopoDS_Shape geometry = references[0].getGeometry(); + if (geometry.IsNull() || geometry.ShapeType() != TopAbs_FACE) { + throw Base::RuntimeError("Geometry for dimension reference is null."); + } + const TopoDS_Face& face = TopoDS::Face(geometry); + + GProp_GProps props; + BRepGProp::SurfaceProperties(face, props); + pts.area = props.Mass(); + pts.center = DrawUtil::toVector3d(props.CentreOfMass()); + } + + return pts; +} + DrawViewPart* DrawViewDimension::getViewPart() const { if (References2D.getValues().empty()) { @@ -1411,6 +1467,7 @@ int DrawViewDimension::getRefTypeSubElements(const std::vector& sub int refType = invalidRef; int refEdges{0}; int refVertices{0}; + int refFaces{0}; for (const auto& se : subElements) { if (DrawUtil::getGeomTypeFromName(se) == "Vertex") { @@ -1419,23 +1476,29 @@ int DrawViewDimension::getRefTypeSubElements(const std::vector& sub if (DrawUtil::getGeomTypeFromName(se) == "Edge") { refEdges++; } + if (DrawUtil::getGeomTypeFromName(se) == "Face") { + refFaces++; + } } - if (refEdges == 0 && refVertices == 2) { + if (refEdges == 0 && refVertices == 2 && refFaces == 0) { refType = twoVertex; } - if (refEdges == 0 && refVertices == 3) { + if (refEdges == 0 && refVertices == 3 && refFaces == 0) { refType = threeVertex; } - if (refEdges == 1 && refVertices == 0) { + if (refEdges == 1 && refVertices == 0 && refFaces == 0) { refType = oneEdge; } - if (refEdges == 1 && refVertices == 1) { + if (refEdges == 1 && refVertices == 1 && refFaces == 0) { refType = vertexEdge; } - if (refEdges == 2 && refVertices == 0) { + if (refEdges == 2 && refVertices == 0 && refFaces == 0) { refType = twoEdge; } + if (refEdges == 0 && refVertices == 0 && refFaces == 1) { + refType = oneFace; + } return refType; } @@ -1749,6 +1812,17 @@ bool DrawViewDimension::validateReferenceForm() const return (subGeom0 == "Vertex" && subGeom1 == "Vertex" && subGeom2 == "Vertex"); } + if (Type.isValue("Area")) { + if (references.size() != 1) { + return false; + } + std::string subGeom = DrawUtil::getGeomTypeFromName(references.front().getSubName()); + if (subGeom != "Face") { + return false; + } + return true; + } + return false; } diff --git a/src/Mod/TechDraw/App/DrawViewDimension.h b/src/Mod/TechDraw/App/DrawViewDimension.h index c7d687ab2b..56836c7ae9 100644 --- a/src/Mod/TechDraw/App/DrawViewDimension.h +++ b/src/Mod/TechDraw/App/DrawViewDimension.h @@ -101,6 +101,7 @@ public: twoVertex, vertexEdge, threeVertex, + oneFace, extent }; @@ -178,6 +179,10 @@ public: { return m_anglePoints; } + areaPoint getAreaPoint() + { + return m_areaPoint; + } bool leaderIntersectsArc(Base::Vector3d s, Base::Vector3d pointOnCircle); @@ -228,6 +233,8 @@ protected: virtual anglePoints getAnglePointsTwoEdges(ReferenceVector references); virtual anglePoints getAnglePointsThreeVerts(ReferenceVector references); + virtual areaPoint getAreaParameters(ReferenceVector references); + Measure::Measurement* measurement; double dist2Segs(Base::Vector3d s1, Base::Vector3d e1, Base::Vector3d s2, Base::Vector3d e2) const; @@ -236,6 +243,7 @@ protected: void resetLinear(); void resetAngular(); void resetArc(); + void resetArea(); bool okToProceed(); void updateSavedGeometry(); @@ -252,6 +260,7 @@ private: pointPair m_arrowPositions; arcPoints m_arcPoints; anglePoints m_anglePoints; + areaPoint m_areaPoint; bool m_hasGeometry; friend class DimensionFormatter; diff --git a/src/Mod/TechDraw/App/Geometry.cpp b/src/Mod/TechDraw/App/Geometry.cpp index e73a2faf1a..5c768e7541 100644 --- a/src/Mod/TechDraw/App/Geometry.cpp +++ b/src/Mod/TechDraw/App/Geometry.cpp @@ -168,6 +168,13 @@ Base::Vector3d Face::getCenter() const { return DrawUtil::toVector3d(faceProps.CentreOfMass()); } +double Face::getArea() const { + GProp_GProps faceProps; + BRepGProp::SurfaceProperties(toOccFace(), faceProps); + + return faceProps.Mass(); +} + Face::~Face() { for(auto it : wires) { diff --git a/src/Mod/TechDraw/App/Geometry.h b/src/Mod/TechDraw/App/Geometry.h index 759e9d18ed..86be92638d 100644 --- a/src/Mod/TechDraw/App/Geometry.h +++ b/src/Mod/TechDraw/App/Geometry.h @@ -348,6 +348,7 @@ class TechDrawExport Face TopoDS_Face toOccFace() const; std::vector wires; + double getArea() const; Base::Vector3d getCenter() const; }; using FacePtr = std::shared_ptr; diff --git a/src/Mod/TechDraw/App/GeometryMatcher.cpp b/src/Mod/TechDraw/App/GeometryMatcher.cpp index 004e195860..e7ba33dffa 100644 --- a/src/Mod/TechDraw/App/GeometryMatcher.cpp +++ b/src/Mod/TechDraw/App/GeometryMatcher.cpp @@ -26,6 +26,8 @@ #include "PreCompiled.h" #ifndef _PreComp_ +#include +#include #endif #include @@ -75,9 +77,13 @@ bool GeometryMatcher::compareGeometry(const Part::TopoShape &shape1, const Part: if (geom1.ShapeType() == TopAbs_EDGE) { return compareEdges(geom1, geom2); } + if (geom1.ShapeType() == TopAbs_FACE) { + return compareFaces(geom1, geom2); + } return false; } + bool GeometryMatcher::comparePoints(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2) { // Base::Console().Message("GM::comparePoints()\n"); @@ -92,6 +98,27 @@ bool GeometryMatcher::comparePoints(const TopoDS_Shape& shape1, const TopoDS_Sha return point1.IsEqual(point2, EWTOLERANCE); } +bool GeometryMatcher::compareFaces(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2) +{ + // Base::Console().Message("GM::compareFaces()\n"); + + if (shape1.ShapeType() != TopAbs_FACE || shape2.ShapeType() != TopAbs_FACE) { + // can not compare these shapes + return false; + } + TopoDS_Face face1 = TopoDS::Face(shape1); + TopoDS_Face face2 = TopoDS::Face(shape2); + + //Note: face1.IsSame(face2) and face1.IsEqual(face2) do not work. + + GProp_GProps props1, props2; + BRepGProp::SurfaceProperties(face1, props1); + BRepGProp::SurfaceProperties(face2, props2); + + // Check if areas are approximately equal + return fabs(props1.Mass() - props2.Mass()) < 1e-5; +} + bool GeometryMatcher::compareEdges(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2) { // Base::Console().Message("GM::compareEdges()\n"); diff --git a/src/Mod/TechDraw/App/GeometryMatcher.h b/src/Mod/TechDraw/App/GeometryMatcher.h index 00dd3028dc..9b2d16f929 100644 --- a/src/Mod/TechDraw/App/GeometryMatcher.h +++ b/src/Mod/TechDraw/App/GeometryMatcher.h @@ -58,6 +58,7 @@ public: private: static bool comparePoints(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2); static bool compareEdges(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2); + static bool compareFaces(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2); static bool compareLines(const TopoDS_Edge& edge1, const TopoDS_Edge& edge2); static bool compareCircles(const TopoDS_Edge& edge1, const TopoDS_Edge& edge2); diff --git a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp index 14a565a303..d4d69cc47b 100644 --- a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp +++ b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp @@ -89,6 +89,7 @@ void execAngle(Gui::Command* cmd); void execAngle3Pt(Gui::Command* cmd); void execRadius(Gui::Command* cmd); void execDiameter(Gui::Command* cmd); +void execArea(Gui::Command* cmd); void execExtent(Gui::Command* cmd, const std::string& dimType); @@ -395,7 +396,7 @@ public: bool mouseReleaseEvent(QMouseEvent* event) override { - //Base::Console().Warning("mouseReleaseEvent TH\n"); + // Base::Console().Warning("mouseReleaseEvent TH\n"); bool finalize = true; if (removedRef.hasGeometry()) { @@ -429,7 +430,6 @@ public: } } else { - Base::Console().Warning("h4\n"); ReferenceVector& selVector = getSelectionVector(addedRef); selVector.push_back(addedRef); @@ -464,7 +464,7 @@ public: void onSelectionChanged(const Gui::SelectionChanges& msg) { - Base::Console().Warning("onSelectionChanged %d - --%s--\n", (int)msg.Type, msg.pSubName); + //Base::Console().Warning("onSelectionChanged %d - --%s--\n", (int)msg.Type, msg.pSubName); if (msg.Type == Gui::SelectionChanges::ClrSelection) { //clearAndRestartCommand(); @@ -568,6 +568,9 @@ protected: availableDimension = AvailableDimension::FIRST; + partFeat = dynamic_cast(initialSelection[0].getObject()); + if (!partFeat) { return; } + // Add the selected elements to their corresponding selection vectors for (auto& ref : initialSelection) { ReferenceVector& selVector = getSelectionVector(ref); @@ -707,7 +710,8 @@ protected: GeomSelectionSizes selection(selPoints.size(), selLine.size(), selCircleArc.size(), selEllipseArc.size(), selSplineAndCo.size(), selFaces.size()); if (selection.hasFaces()) { - makeCts_Faces(selAllowed, pos); + if (selection.has1Face()) { makeCts_Faces(selAllowed, pos); } + else { return false; } // nothing else with face works } else if (selection.hasPoints()) { if (selection.has1Point()) { selAllowed = true; } @@ -739,15 +743,14 @@ protected: return selAllowed; } - // TODO void makeCts_Faces(bool& selAllowed, QPoint& pos) { //area if (availableDimension == AvailableDimension::FIRST) { - /*restartCommand(QT_TRANSLATE_NOOP("Command", "Add Area dimension")); - createAreaDimension(pos); + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Area dimension")); + createAreaDimension(selFaces[0], pos); selAllowed = true; - availableDimension = AvailableDimension::RESET;*/ + availableDimension = AvailableDimension::RESET; } } @@ -997,31 +1000,12 @@ protected: } } - //TODO - void createAreaDimension(QPoint& pos) + void createAreaDimension(ReferenceEntry ref, QPoint& pos) { - /*// see CmdTechDrawExtensionAreaAnnotation::activated - Base::Vector3d center; - double totalArea = 0.0; - for (auto& ref : selFaces) { - TechDraw::FacePtr face = partFeat->getFace(ref.getSubName()); - if (!face) { - continue; - } + DrawViewDimension* dim = dimMaker(partFeat, "Area", { ref }, {}); - GProp_GProps faceProps; - BRepGProp::SurfaceProperties(face->toOccFace(), faceProps); - - double faceArea = faceProps.Mass(); - totalArea += faceArea; - center += faceArea * DrawUtil::toVector3d(faceProps.CentreOfMass()); - } - if (totalArea > 0.0) { - center /= totalArea; - } - - //function (and file) to create in CommandExtensionPack.h - auto* areaBalloon = createAreaBalloon(totalArea, center);*/ + dims.push_back(dim); + moveDimension(pos, dim); } void createRadiusDiameterDimension(ReferenceEntry ref, QPoint& pos, bool firstCstr) { @@ -1366,6 +1350,7 @@ public: addCommand("TechDraw_DiameterDimension"); addCommand("TechDraw_AngleDimension"); addCommand("TechDraw_3PtAngleDimension"); + addCommand("TechDraw_AreaDimension"); addCommand("TechDraw_ExtensionCreateLengthArc"); addCommand(); //separator addCommand("TechDraw_HorizontalExtentDimension"); @@ -2095,6 +2080,95 @@ void execAngle3Pt(Gui::Command* cmd) positionDimText(dim); } +//=========================================================================== +// TechDraw_AreaDimension +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawAreaDimension) + +CmdTechDrawAreaDimension::CmdTechDrawAreaDimension() + : Command("TechDraw_AreaDimension") +{ + sAppModule = "TechDraw"; + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Insert Area Dimension"); + sToolTipText = sMenuText; + sWhatsThis = "TechDraw_AreaDimension"; + sStatusTip = sToolTipText; + sPixmap = "TechDraw_AreaDimension"; +} + +void CmdTechDrawAreaDimension::activated(int iMsg) +{ + Q_UNUSED(iMsg); + Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); + if (dlg) { + QMessageBox::warning(Gui::getMainWindow(), + QObject::tr("Task In Progress"), + QObject::tr("Close active task dialog and try again.")); + return; + } + + execArea(this); +} + +bool CmdTechDrawAreaDimension::isActive() +{ + bool havePage = DrawGuiUtil::needPage(this); + bool haveView = DrawGuiUtil::needView(this); + return (havePage && haveView); +} + +void execArea(Gui::Command* cmd) +{ + bool result = _checkDrawViewPart(cmd); + if (!result) { + QMessageBox::warning(Gui::getMainWindow(), + QObject::tr("Incorrect selection"), + QObject::tr("No View of a Part in selection.")); + return; + } + + ReferenceVector references2d; + ReferenceVector references3d; + TechDraw::DrawViewPart* partFeat = + TechDraw::getReferencesFromSelection(references2d, references3d); + + //Define the geometric configuration required for a length dimension + StringVector acceptableGeometry({"Face"}); + std::vector minimumCounts({1}); + std::vector acceptableDimensionGeometrys({isFace}); + + //what 2d geometry configuration did we receive? + DimensionGeometryType geometryRefs2d = validateDimSelection( + references2d, acceptableGeometry, minimumCounts, acceptableDimensionGeometrys); + if (geometryRefs2d == TechDraw::isInvalid) { + QMessageBox::warning(Gui::getMainWindow(), + QObject::tr("Incorrect Selection"), + QObject::tr("Can not make 2d angle dimension from selection")); + return; + } + + //what 3d geometry configuration did we receive? + DimensionGeometryType geometryRefs3d; + if (geometryRefs2d == TechDraw::isViewReference && !references3d.empty()) { + geometryRefs3d = validateDimSelection3d(partFeat, + references3d, + acceptableGeometry, + minimumCounts, + acceptableDimensionGeometrys); + if (geometryRefs3d == TechDraw::isInvalid) { + QMessageBox::warning(Gui::getMainWindow(), + QObject::tr("Incorrect Selection"), + QObject::tr("Can not make 3d angle dimension from selection")); + return; + } + } + + //build the dimension + dimensionMaker(partFeat, "Area", references2d, references3d); +} + // TechDraw_LinkDimension is DEPRECATED. Use TechDraw_DimensionRepair instead. //! link 3D geometry to Dimension(s) on a Page @@ -2593,6 +2667,7 @@ void CreateTechDrawCommandsDims() rcCmdMgr.addCommand(new CmdTechDrawVerticalDimension()); rcCmdMgr.addCommand(new CmdTechDrawAngleDimension()); rcCmdMgr.addCommand(new CmdTechDraw3PtAngleDimension()); + rcCmdMgr.addCommand(new CmdTechDrawAreaDimension()); rcCmdMgr.addCommand(new CmdTechDrawExtentGroup()); rcCmdMgr.addCommand(new CmdTechDrawVerticalExtentDimension()); rcCmdMgr.addCommand(new CmdTechDrawHorizontalExtentDimension()); @@ -2646,8 +2721,7 @@ DrawViewDimension* dimMaker(TechDraw::DrawViewPart* dvp, std::string dimType, dimName.c_str(), "Projected"); - auto* dim = - dynamic_cast(dvp->getDocument()->getObject(dimName.c_str())); + auto* dim = dynamic_cast(dvp->getDocument()->getObject(dimName.c_str())); if (!dim) { throw Base::TypeError("CmdTechDrawNewDiameterDimension - dim not found\n"); } diff --git a/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp b/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp index 5a777b5b5f..abe41eeb39 100644 --- a/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp +++ b/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp @@ -25,6 +25,8 @@ # include # include # include +# include +# include #endif # include diff --git a/src/Mod/TechDraw/Gui/DimensionValidators.cpp b/src/Mod/TechDraw/Gui/DimensionValidators.cpp index e991a938a6..0e2daadc29 100644 --- a/src/Mod/TechDraw/Gui/DimensionValidators.cpp +++ b/src/Mod/TechDraw/Gui/DimensionValidators.cpp @@ -116,7 +116,7 @@ DimensionGeometryType TechDraw::validateDimSelection( StringVector subNames; TechDraw::DrawViewPart* dvpSave(nullptr); for (auto& ref : references) { - TechDraw::DrawViewPart* dvp = dynamic_cast(ref.getObject()); + auto* dvp = dynamic_cast(ref.getObject()); if (dvp) { dvpSave = dvp; if (!ref.getSubName().empty()) { @@ -295,6 +295,10 @@ DimensionGeometryType TechDraw::getGeometryConfiguration(ReferenceVector valid2d if (config > isInvalid) { return config; } + config = isValidSingleFace(valid2dReferences.front()); + if (config > isInvalid) { + return config; + } // no valid configuration found return isInvalid; @@ -336,6 +340,10 @@ DimensionGeometryType TechDraw::getGeometryConfiguration3d(DrawViewPart* dvp, if (config > isInvalid) { return config; } + config = isValidSingleFace3d(dvp, valid3dReferences.front()); + if (config > isInvalid) { + return config; + } config = isValidHybrid3d(dvp, valid3dReferences); if (config > isInvalid) { return config; @@ -461,6 +469,47 @@ DimensionGeometryType TechDraw::isValidSingleEdge3d(DrawViewPart* dvp, Reference return isInvalid; } +//! verify that Selection contains a valid Geometry for a single Edge Dimension +DimensionGeometryType TechDraw::isValidSingleFace(ReferenceEntry ref) +{ + auto objFeat(dynamic_cast(ref.getObject())); + if (!objFeat) { + return isInvalid; + } + + //the Name starts with "Edge" + std::string geomName = DrawUtil::getGeomTypeFromName(ref.getSubName()); + if (geomName != "Face") { + return isInvalid; + } + + auto geom = objFeat->getFace(ref.getSubName()); + if (!geom) { + return isInvalid; + } + + return isFace; +} + +//! verify that Selection contains a valid Geometry for a single Edge Dimension +DimensionGeometryType TechDraw::isValidSingleFace3d(DrawViewPart* dvp, ReferenceEntry ref) +{ + (void)dvp; + //the Name starts with "Edge" + std::string geomName = DrawUtil::getGeomTypeFromName(ref.getSubName()); + if (geomName != "Face") { + return isInvalid; + } + + TopoDS_Shape refShape = ref.getGeometry(); + if (refShape.IsNull() || refShape.ShapeType() != TopAbs_FACE) { + Base::Console().Warning("Geometry for reference is not a face.\n"); + return isInvalid; + } + + return isFace; +} + //! verify that the edge references can make a dimension. Currently only extent //! dimensions support more than 2 edges DimensionGeometryType TechDraw::isValidMultiEdge(ReferenceVector refs) diff --git a/src/Mod/TechDraw/Gui/DimensionValidators.h b/src/Mod/TechDraw/Gui/DimensionValidators.h index 7f371670bd..339f734556 100644 --- a/src/Mod/TechDraw/Gui/DimensionValidators.h +++ b/src/Mod/TechDraw/Gui/DimensionValidators.h @@ -60,6 +60,7 @@ enum DimensionGeometryEnum { isMultiEdge, isZLimited, isHybrid, + isFace, isViewReference //never needs to be specified in the acceptable list }; @@ -89,11 +90,13 @@ bool checkGeometryOccurrences(StringVector subNames, GeomCountMap keyedMinimumCo DimensionGeometryType isValidVertexes(ReferenceVector refs); DimensionGeometryType isValidMultiEdge(ReferenceVector refs); DimensionGeometryType isValidSingleEdge(ReferenceEntry ref); +DimensionGeometryType isValidSingleFace(ReferenceEntry ref); DimensionGeometryType isValidHybrid(ReferenceVector refs); DimensionGeometryType isValidVertexes3d(DrawViewPart* dvp, ReferenceVector refs); DimensionGeometryType isValidMultiEdge3d(DrawViewPart* dvp, ReferenceVector refs); DimensionGeometryType isValidSingleEdge3d(DrawViewPart* dvp, ReferenceEntry ref); +DimensionGeometryType isValidSingleFace3d(DrawViewPart* dvp, ReferenceEntry ref); DimensionGeometryType isValidHybrid3d(DrawViewPart* dvp, ReferenceVector refs); long int mapGeometryTypeToDimType(long int dimType, DimensionGeometryType geometry2d, diff --git a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp index 6a3e7d139d..86aaa7fc9a 100644 --- a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp @@ -717,9 +717,9 @@ void QGIViewDimension::draw() return; } - TechDraw::DrawViewDimension* dim = dynamic_cast(getViewObject()); + auto* dim = dynamic_cast(getViewObject()); if (!dim ||//nothing to draw, don't try - !dim->isDerivedFrom(TechDraw::DrawViewDimension::getClassTypeId()) + !dim->isDerivedFrom() || !dim->has2DReferences()) { datumLabel->hide(); hide(); @@ -767,6 +767,9 @@ void QGIViewDimension::draw() else if (strcmp(dimType, "Angle") == 0 || strcmp(dimType, "Angle3Pt") == 0) { drawAngle(dim, vp); } + else if (strcmp(dimType, "Area") == 0) { + drawArea(dim, vp); + } else { Base::Console().Error("QGIVD::draw - this DimensionType is unknown: %s\n", dimType); } @@ -2085,6 +2088,75 @@ void QGIViewDimension::drawRadiusExecutive(const Base::Vector2d& centerPoint, dimLines->setPath(radiusPath); } +void QGIViewDimension::drawAreaExecutive(const Base::Vector2d& centerPoint, double area, + const Base::BoundBox2d& labelRectangle, + double centerOverhang, int standardStyle, + int renderExtent, bool flipArrow) const +{ + QPainterPath areaPath; + + Base::Vector2d labelCenter(labelRectangle.GetCenter()); + double labelAngle = 0.0; + + if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING + || standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING) { + // The dimensional value text must stay horizontal + + bool left = labelCenter.x < centerPoint.x; + + Base::Vector2d jointDirection; + if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING) { + jointDirection = getIsoRefJointPoint(labelRectangle, left) - centerPoint; + } + else { + jointDirection = getAsmeRefJointPoint(labelRectangle, left) - centerPoint; + } + + double lineAngles = jointDirection.Angle(); + double jointPositions = jointDirection.Length(); + + drawDimensionLine(areaPath, centerPoint, lineAngles, 0.0, + jointPositions, labelRectangle, 1, standardStyle, flipArrow); + + Base::Vector2d outsetPoint(standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING + ? getIsoRefOutsetPoint(labelRectangle, left) + : getAsmeRefOutsetPoint(labelRectangle, left)); + + areaPath.moveTo(toQtGui(outsetPoint)); + areaPath.lineTo(toQtGui(centerPoint + jointDirection)); + } + else if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) { + // We may rotate the label so no reference line is needed + double lineAngle; + double devAngle = computeLineAndLabelAngles(centerPoint, labelCenter, + labelRectangle.Height() * 0.5 + getIsoDimensionLineSpacing(), + lineAngle, labelAngle); + + lineAngle = lineAngle - M_PI; + double labelPosition = -cos(devAngle) * ((labelCenter - centerPoint).Length()); + + drawDimensionLine(areaPath, centerPoint, lineAngle, 0.0, labelPosition, labelRectangle, 1, standardStyle, flipArrow); + } + else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) { + // Text must remain horizontal, but it may split the leader line + Base::Vector2d labelDirection(labelCenter - centerPoint); + double lineAngle = labelDirection.Angle(); + double labelPosition = labelDirection.Length(); + + drawDimensionLine(areaPath, centerPoint, lineAngle, 0.0, labelPosition, labelRectangle, 1, standardStyle, flipArrow); + } + else { + Base::Console().Error( + "QGIVD::drawRadiusExecutive - this Standard&Style is not supported: %d\n", + standardStyle); + } + + datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center()); + datumLabel->setRotation(toQtDeg(labelAngle)); + + dimLines->setPath(areaPath); +} + void QGIViewDimension::drawDistance(TechDraw::DrawViewDimension* dimension, ViewProviderDimension* viewProvider) const { @@ -2510,6 +2582,21 @@ void QGIViewDimension::drawAngle(TechDraw::DrawViewDimension* dimension, dimLines->setPath(anglePath); } +void QGIViewDimension::drawArea(TechDraw::DrawViewDimension* dimension, + ViewProviderDimension* viewProvider) const +{ + Base::BoundBox2d labelRectangle( + fromQtGui(mapRectFromItem(datumLabel, datumLabel->boundingRect()))); + areaPoint areaPoint = dimension->getAreaPoint(); + + double endAngle; + double startRotation; + + drawAreaExecutive( + fromQtApp(areaPoint.center), areaPoint.area, labelRectangle, 0.0, viewProvider->StandardAndStyle.getValue(), + viewProvider->RenderingExtent.getValue(), viewProvider->FlipArrowheads.getValue()); +} + QColor QGIViewDimension::prefNormalColor() { setNormalColor(PreferencesGui::getAccessibleQColor(PreferencesGui::dimQColor())); diff --git a/src/Mod/TechDraw/Gui/QGIViewDimension.h b/src/Mod/TechDraw/Gui/QGIViewDimension.h index 891260abb8..34524c1410 100644 --- a/src/Mod/TechDraw/Gui/QGIViewDimension.h +++ b/src/Mod/TechDraw/Gui/QGIViewDimension.h @@ -261,10 +261,14 @@ protected: double endAngle, double startRotation, const Base::BoundBox2d &labelRectangle, double centerOverhang, int standardStyle, int renderExtent, bool flipArrow) const; + void drawAreaExecutive(const Base::Vector2d ¢erPoint, double area, const Base::BoundBox2d &labelRectangle, + double centerOverhang, int standardStyle, int renderExtent, bool flipArrow) const; + void drawDistance(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const; void drawRadius(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const; void drawDiameter(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const; void drawAngle(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const; + void drawArea(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const; QVariant itemChange( GraphicsItemChange change, const QVariant &value ) override; diff --git a/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc b/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc index 19cbeef03b..132fcfc226 100644 --- a/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc +++ b/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc @@ -86,6 +86,7 @@ icons/square.svg icons/TechDraw_3PtAngleDimension.svg icons/TechDraw_AngleDimension.svg + icons/TechDraw_AreaDimension.svg icons/TechDraw_Balloon.svg icons/TechDraw_CameraOrientation.svg icons/TechDraw_DiameterDimension.svg diff --git a/src/Mod/TechDraw/Gui/Resources/icons/TechDraw_AreaDimension.svg b/src/Mod/TechDraw/Gui/Resources/icons/TechDraw_AreaDimension.svg new file mode 100644 index 0000000000..534f53298b --- /dev/null +++ b/src/Mod/TechDraw/Gui/Resources/icons/TechDraw_AreaDimension.svg @@ -0,0 +1,88 @@ + + + diff --git a/src/Mod/TechDraw/Gui/ViewProviderDimension.cpp b/src/Mod/TechDraw/Gui/ViewProviderDimension.cpp index a08b4fccf3..d40b75a455 100644 --- a/src/Mod/TechDraw/Gui/ViewProviderDimension.cpp +++ b/src/Mod/TechDraw/Gui/ViewProviderDimension.cpp @@ -196,6 +196,8 @@ void ViewProviderDimension::setPixmapForType() sPixmap = "TechDraw_AngleDimension"; } else if (getViewObject()->Type.isValue("Angle3Pt")) { sPixmap = "TechDraw_3PtAngleDimension"; + } else if (getViewObject()->Type.isValue("Area")) { + sPixmap = "TechDraw_ExtensionAreaAnnotation"; } } diff --git a/src/Mod/TechDraw/Gui/Workbench.cpp b/src/Mod/TechDraw/Gui/Workbench.cpp index a3abac5e24..21e17082d2 100644 --- a/src/Mod/TechDraw/Gui/Workbench.cpp +++ b/src/Mod/TechDraw/Gui/Workbench.cpp @@ -91,6 +91,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const *dimensions << "TechDraw_DiameterDimension"; *dimensions << "TechDraw_AngleDimension"; *dimensions << "TechDraw_3PtAngleDimension"; + *dimensions << "TechDraw_AreaDimension"; *dimensions << "TechDraw_HorizontalExtentDimension"; *dimensions << "TechDraw_VerticalExtentDimension"; // TechDraw_LinkDimension is DEPRECATED. Use TechDraw_DimensionRepair instead. @@ -327,6 +328,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const *dims << "TechDraw_DiameterDimension"; *dims << "TechDraw_AngleDimension"; *dims << "TechDraw_3PtAngleDimension"; + *dims << "TechDraw_AreaDimension"; *dims << "TechDraw_ExtentGroup"; } @@ -346,8 +348,8 @@ Gui::ToolBarItem* Workbench::setupToolBars() const *extattribs << "TechDraw_ExtensionPositionSectionView"; *extattribs << "TechDraw_ExtensionPosChainDimensionGroup"; *extattribs << "TechDraw_ExtensionCascadeDimensionGroup"; - *extattribs << "TechDraw_ExtensionAreaAnnotation"; if (separatedTools) { + *extattribs << "TechDraw_ExtensionAreaAnnotation"; *extattribs << "TechDraw_ExtensionArcLengthAnnotation"; } *extattribs << "TechDraw_ExtensionCustomizeFormat"; From cc393632e1939f723637eb21972dc589b29428af Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Mon, 22 Apr 2024 16:59:55 +0200 Subject: [PATCH 8/9] Techdraw: Smart Dimension: Fixes and simplifies code --- src/Mod/TechDraw/App/DimensionFormatter.cpp | 7 +- src/Mod/TechDraw/App/DimensionReferences.cpp | 10 +- src/Mod/TechDraw/Gui/CommandCreateDims.cpp | 400 ++++++++++-------- src/Mod/TechDraw/Gui/CommandExtensionDims.cpp | 3 +- src/Mod/TechDraw/Gui/CommandExtensionDims.h | 3 + src/Mod/TechDraw/Gui/MDIViewPage.cpp | 30 +- src/Mod/TechDraw/Gui/MDIViewPage.h | 4 + src/Mod/TechDraw/Gui/QGIViewDimension.cpp | 29 +- src/Mod/TechDraw/Gui/QGIViewDimension.h | 5 +- src/Mod/TechDraw/Gui/QGVPage.h | 1 + src/Mod/TechDraw/Gui/TechDrawHandler.cpp | 28 +- src/Mod/TechDraw/Gui/TechDrawHandler.h | 5 +- 12 files changed, 306 insertions(+), 219 deletions(-) diff --git a/src/Mod/TechDraw/App/DimensionFormatter.cpp b/src/Mod/TechDraw/App/DimensionFormatter.cpp index 0b9b756d09..1bfa57eb61 100644 --- a/src/Mod/TechDraw/App/DimensionFormatter.cpp +++ b/src/Mod/TechDraw/App/DimensionFormatter.cpp @@ -91,9 +91,6 @@ std::string DimensionFormatter::formatValue(const qreal value, QString qMultiValueStr; QString qBasicUnit = Base::Tools::fromStdString(Base::UnitsApi::getBasicLengthUnit()); - if (areaMeasure) { - qBasicUnit = qBasicUnit + QString::fromUtf8("²"); - } QString formattedValue; if (isMultiValueSchema() && partial == 0) { @@ -138,6 +135,10 @@ std::string DimensionFormatter::formatValue(const qreal value, else { double convertValue = Base::Quantity::parse(QString::fromLatin1("1") + qBasicUnit).getValue(); userVal = asQuantity.getValue() / convertValue; + if (areaMeasure) { + userVal = userVal / convertValue; // divide again as area is length² + qBasicUnit = qBasicUnit + QString::fromUtf8("²"); + } } if (isTooSmall(userVal, formatSpecifier)) { diff --git a/src/Mod/TechDraw/App/DimensionReferences.cpp b/src/Mod/TechDraw/App/DimensionReferences.cpp index 68a1176986..656af6ee88 100644 --- a/src/Mod/TechDraw/App/DimensionReferences.cpp +++ b/src/Mod/TechDraw/App/DimensionReferences.cpp @@ -265,15 +265,7 @@ Part::TopoShape ReferenceEntry::asTopoShapeEdge(const TopoDS_Edge &edge) Part::TopoShape ReferenceEntry::asTopoShapeFace(const TopoDS_Face &face) { -// Base::Console().Message("RE::asTopoShapeFace()\n"); - TopoDS_Face unscaledFace = face; - if (!is3d()) { - // 2d reference - projected and scaled. scale might have changed, so we need to unscale - auto dvp = static_cast(getObject()); - TopoDS_Shape unscaledShape = ShapeUtils::scaleShape(face, 1.0 / dvp->getScale()); - unscaledFace = TopoDS::Face(unscaledShape); - } - return { unscaledFace }; + return { face }; } std::string ReferenceEntry::geomType() const diff --git a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp index d4d69cc47b..53674ac223 100644 --- a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp +++ b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #endif//#ifndef _PreComp_ #include @@ -178,7 +179,7 @@ public: : SelectionObserver(true) , specialDimension(SpecialDimension::None) , availableDimension(AvailableDimension::FIRST) - , previousPos(QPoint(0, 0)) + , mousePos(QPoint(0, 0)) , selPoints({}) , selLine({}) , selCircleArc({}) @@ -218,6 +219,10 @@ public: void activated() override { + auto* mdi = dynamic_cast(Gui::getMainWindow()->activeWindow()); + if (mdi) { + mdi->setDimensionsSelectability(false); + } Gui::Selection().setSelectionStyle(Gui::SelectionSingleton::SelectionStyle::GreedySelection); Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Insert Dimension")); handleInitialSelection(); @@ -225,6 +230,10 @@ public: void deactivated() override { + auto* mdi = dynamic_cast(Gui::getMainWindow()->activeWindow()); + if (mdi) { + mdi->setDimensionsSelectability(true); + } Gui::Selection().setSelectionStyle(Gui::SelectionSingleton::SelectionStyle::NormalSelection); Gui::Command::abortCommand(); } @@ -247,7 +256,7 @@ public: else if (availableDimension == AvailableDimension::FIFTH || availableDimension == AvailableDimension::RESET) { availableDimension = AvailableDimension::FIRST; } - makeAppropriateDimension(previousPos); + makeAppropriateDimension(); event->accept(); } else if (event->key() == Qt::Key_Z && (QApplication::keyboardModifiers() & Qt::ControlModifier)) { @@ -270,7 +279,7 @@ public: void mouseMoveEvent(QMouseEvent* event) override { - previousPos = event->pos(); + mousePos = event->pos(); if (dims.empty()){ return; @@ -280,13 +289,13 @@ public: Base::Vector3d dirMaster, delta; //Change distance dimension based on position of mouse. if (specialDimension == SpecialDimension::LineOr2PointsDistance){ - updateDistanceType(event->pos()); + updateDistanceType(); } else if (specialDimension == SpecialDimension::ExtendDistance){ - updateExtentDistanceType(event->pos()); + updateExtentDistanceType(); } else if (specialDimension == SpecialDimension::ChainDistance || specialDimension == SpecialDimension::CoordDistance){ - updateChainDistanceType(event->pos()); + updateChainDistanceType(); textToMiddle = true; pointPair pp = dims[0]->getLinearPoints(); dirMaster = pp.second() - pp.first(); @@ -301,7 +310,7 @@ public: int i = 0; for (auto* dim : dims) { auto dimType = static_cast(dim->Type.getValue()); - moveDimension(event->pos(), dim, textToMiddle, dirMaster, delta, dimType, i); + moveDimension(mousePos, dim, textToMiddle, dirMaster, delta, dimType, i); if (specialDimension == SpecialDimension::CoordDistance) { i++; @@ -321,7 +330,7 @@ public: } return qgivDimension->getDatumLabel(); } - void moveDimension(QPoint& pos, DrawViewDimension* dim, bool textToMiddle = false, Base::Vector3d dir = Base::Vector3d(), + void moveDimension(QPoint pos, DrawViewDimension* dim, bool textToMiddle = false, Base::Vector3d dir = Base::Vector3d(), Base::Vector3d delta = Base::Vector3d(), DimensionType type = DimensionType::Distance, int i = 0) { if (!dim) { return; } @@ -330,14 +339,14 @@ public: label->setPos(getDimPositionToBe(pos, label->pos(), textToMiddle, dir, delta, type, i)); } - QPointF getDimPositionToBe(QPoint& pos, QPointF curPos = QPointF(), bool textToMiddle = false, Base::Vector3d dir = Base::Vector3d(), + QPointF getDimPositionToBe(QPoint pos, QPointF curPos = QPointF(), bool textToMiddle = false, Base::Vector3d dir = Base::Vector3d(), Base::Vector3d delta = Base::Vector3d(), DimensionType type = DimensionType::Distance, int i = 0) { auto* vpp = dynamic_cast(Gui::Application::Instance->getViewProvider(partFeat)); if (!vpp) { return QPointF(); } - QPointF scenePos = viewPage->mapToScene(pos) - vpp->getQView()->pos(); + QPointF scenePos = viewPage->mapToScene(pos) - vpp->getQView()->scenePos(); if (textToMiddle) { // delta is for coord distances. i = 0 when it's a chain so delta is ignored. @@ -383,86 +392,104 @@ public: } } - bool mousePressEvent(QMouseEvent* event) override + void setDimsSelectability(bool val) { - if (event->button() == Qt::RightButton && !dims.empty()) { - Gui::Selection().clearSelection(); - clearAndRestartCommand(); - event->accept(); - return true; + for (auto dim : dims) { + setDimSelectability(dim, val); + } + } + void setDimSelectability(DrawViewDimension* d, bool val) + { + QGIDatumLabel* label = getDimLabel(d); + if (label) { + label->setSelectability(val); } - return TechDrawHandler::mousePressEvent(event); } - bool mouseReleaseEvent(QMouseEvent* event) override + void mouseReleaseEvent(QMouseEvent* event) override { // Base::Console().Warning("mouseReleaseEvent TH\n"); - bool finalize = true; - - if (removedRef.hasGeometry()) { - finalize = false; - //Base::Console().Warning("RmvSelection \n"); - // Remove the reference from the vector - ReferenceVector& selVector = getSelectionVector(removedRef); - selVector.erase(std::remove(selVector.begin(), selVector.end(), removedRef), selVector.end()); - - if (!selectionEmpty()) { - availableDimension = AvailableDimension::FIRST; - makeAppropriateDimension(event->pos()); - } - else { + if (event->button() == Qt::RightButton) { + if (!dims.empty()) { + Gui::Selection().clearSelection(); clearAndRestartCommand(); - } - removedRef = ReferenceEntry(); - } - - if (addedRef.hasGeometry()) { - finalize = false; - //Base::Console().Warning("AddSelection\n"); - //add the geometry to its type vector. Temporarily if not selAllowed - if (addedRef.getSubName() == "") { - // Behavior deactivated for now because I found it annoying. - // To reactivate replace addedRef.hasGeometry() by addedRef.getObject() above. - // This means user selected the view itself. - if (selectionEmpty()) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); - createExtentDistanceDimension("DistanceX", event->pos()); - } + event->accept(); } else { - ReferenceVector& selVector = getSelectionVector(addedRef); - selVector.push_back(addedRef); + TechDrawHandler::mouseReleaseEvent(event); + } + return; + } + else if (event->button() == Qt::LeftButton) { + mousePos = event->pos(); - availableDimension = AvailableDimension::FIRST; - bool selAllowed = makeAppropriateDimension(event->pos()); + bool finalize = true; - if (!selAllowed) { - // remove from selection - blockRemoveSel = true; + if (removedRef.hasGeometry()) { + finalize = false; + //Base::Console().Warning("RmvSelection \n"); + // Remove the reference from the vector + ReferenceVector& selVector = getSelectionVector(removedRef); + selVector.erase(std::remove(selVector.begin(), selVector.end(), removedRef), selVector.end()); - Gui::Selection().rmvSelection(addedRef.getObject()->getDocument()->getName(), addedRef.getObject()->getNameInDocument(), addedRef.getSubName().c_str()); - blockRemoveSel = false; + if (!selectionEmpty()) { + availableDimension = AvailableDimension::FIRST; + makeAppropriateDimension(); + } + else { + clearAndRestartCommand(); + } + removedRef = ReferenceEntry(); + } - if (selVector == selFaces) { - // if sel face and not allowed, then a dimension is being created - // and user clicked on a face to drop it. - // Better would be to disable face selectability when needed. - finalize = true; + if (addedRef.hasGeometry()) { + finalize = false; + //Base::Console().Warning("AddSelection\n"); + //add the geometry to its type vector. Temporarily if not selAllowed + if (addedRef.getSubName() == "") { + // Behavior deactivated for now because I found it annoying. + // To reactivate replace addedRef.hasGeometry() by addedRef.getObject() above. + // This means user selected the view itself. + if (selectionEmpty()) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); + createExtentDistanceDimension("DistanceX"); } } + else { + ReferenceVector& selVector = getSelectionVector(addedRef); + selVector.push_back(addedRef); + + availableDimension = AvailableDimension::FIRST; + bool selAllowed = makeAppropriateDimension(); + + if (!selAllowed) { + // remove from selection + blockRemoveSel = true; + + Gui::Selection().rmvSelection(addedRef.getObject()->getDocument()->getName(), + addedRef.getObject()->getNameInDocument(), addedRef.getSubName().c_str()); + blockRemoveSel = false; + + if (selVector == selFaces) { + // if sel face and not allowed, then a dimension is being created + // and user clicked on a face to drop it. + // Better would be to disable face selectability when needed. + finalize = true; + } + } + } + addedRef = ReferenceEntry(); } - addedRef = ReferenceEntry(); - } - // Finalize if click on empty space. - if (finalize && !dims.empty()) { - finalizeCommand(); + // Finalize if click on empty space. + if (finalize && !dims.empty()) { + finalizeCommand(); + } } - return true; } - void onSelectionChanged(const Gui::SelectionChanges& msg) + void onSelectionChanged(const Gui::SelectionChanges& msg) override { //Base::Console().Warning("onSelectionChanged %d - --%s--\n", (int)msg.Type, msg.pSubName); @@ -539,7 +566,7 @@ protected: SpecialDimension specialDimension; AvailableDimension availableDimension; - QPoint previousPos; + QPoint mousePos; ReferenceVector selPoints; ReferenceVector selLine; @@ -578,7 +605,7 @@ protected: } // See if the selection is valid - bool selAllowed = makeAppropriateDimension(QPoint()); + bool selAllowed = makeAppropriateDimension(); if (!selAllowed) { clearRefVectors(); @@ -704,316 +731,322 @@ protected: return result; } - bool makeAppropriateDimension(QPoint& pos) { + bool makeAppropriateDimension() { bool selAllowed = false; //Base::Console().Warning("makeAppropriateDimension %d %d %d %d %d %d\n", selPoints.size(), selLine.size(), selCircleArc.size(), selEllipseArc.size(), selSplineAndCo.size(), selFaces.size()); GeomSelectionSizes selection(selPoints.size(), selLine.size(), selCircleArc.size(), selEllipseArc.size(), selSplineAndCo.size(), selFaces.size()); if (selection.hasFaces()) { - if (selection.has1Face()) { makeCts_Faces(selAllowed, pos); } + if (selection.has1Face()) { makeCts_Faces(selAllowed); } else { return false; } // nothing else with face works } else if (selection.hasPoints()) { if (selection.has1Point()) { selAllowed = true; } - else if (selection.has2Points()) { makeCts_2Point(selAllowed, pos); } - else if (selection.has3Points()) { makeCts_3Point(selAllowed, pos); } - else if (selection.has4MorePoints()) { makeCts_4MorePoints(selAllowed, pos); } - else if (selection.has1Point1Line()) { makeCts_1Point1Line(selAllowed, pos); } - else if (selection.has1Point1Circle()) { makeCts_1Point1Circle(selAllowed, pos); } - else if (selection.has1Point1Ellipse()) { makeCts_1Point1Ellipse(selAllowed, pos); } + else if (selection.has2Points()) { makeCts_2Point(selAllowed); } + else if (selection.has3Points()) { makeCts_3Point(selAllowed); } + else if (selection.has4MorePoints()) { makeCts_4MorePoints(selAllowed); } + else if (selection.has1Point1Line()) { makeCts_1Point1Line(selAllowed); } + else if (selection.has1Point1Circle()) { makeCts_1Point1Circle(selAllowed); } + else if (selection.has1Point1Ellipse()) { makeCts_1Point1Ellipse(selAllowed); } } else if (selection.hasLines()) { - if (selection.has1Line()) { makeCts_1Line(selAllowed, pos); } - else if (selection.has2Lines()) { makeCts_2Line(selAllowed, pos); } - else if (selection.has1Line1Circle()) { makeCts_1Line1Circle(selAllowed, pos); } - else if (selection.has1Line1Ellipse()) { makeCts_1Line1Ellipse(selAllowed, pos); } + if (selection.has1Line()) { makeCts_1Line(selAllowed); } + else if (selection.has2Lines()) { makeCts_2Line(selAllowed); } + else if (selection.has1Line1Circle()) { makeCts_1Line1Circle(selAllowed); } + else if (selection.has1Line1Ellipse()) { makeCts_1Line1Ellipse(selAllowed); } } else if (selection.hasCirclesOrArcs()) { - if (selection.has1Circle()) { makeCts_1Circle(selAllowed, pos); } - else if (selection.has2Circles()) { makeCts_2Circle(selAllowed, pos); } + if (selection.has1Circle()) { makeCts_1Circle(selAllowed); } + else if (selection.has2Circles()) { makeCts_2Circle(selAllowed); } } else if (selection.hasEllipseAndCo()) { - if (selection.has1Ellipse()) { makeCts_1Ellipse(selAllowed, pos); } - if (selection.has2Ellipses()) { makeCts_2Ellipses(selAllowed, pos); } + if (selection.has1Ellipse()) { makeCts_1Ellipse(selAllowed); } + if (selection.has2Ellipses()) { makeCts_2Ellipses(selAllowed); } } else if (selection.hasSplineAndCo()) { - if (selection.has1Spline()) { makeCts_1Spline(selAllowed, pos); } - if (selection.has1SplineAndMore()) { makeCts_1SplineAndMore(selAllowed, pos); } + if (selection.has1Spline()) { makeCts_1Spline(selAllowed); } + if (selection.has1SplineAndMore()) { makeCts_1SplineAndMore(selAllowed); } } + + // Make created constraints unselectable. + if (selAllowed) { + setDimsSelectability(false); + } + return selAllowed; } - void makeCts_Faces(bool& selAllowed, QPoint& pos) + void makeCts_Faces(bool& selAllowed) { //area if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Area dimension")); - createAreaDimension(selFaces[0], pos); + createAreaDimension(selFaces[0]); selAllowed = true; availableDimension = AvailableDimension::RESET; } } - void makeCts_2Point(bool& selAllowed, QPoint& pos) + void makeCts_2Point(bool& selAllowed) { //distance if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance dimension")); - createDistanceDimension("Distance", selPoints[0], selPoints[1], pos); + createDistanceDimension("Distance", { selPoints[0], selPoints[1] }); specialDimension = SpecialDimension::LineOr2PointsDistance; selAllowed = true; availableDimension = AvailableDimension::RESET; } } - void makeCts_3Point(bool& selAllowed, QPoint& pos) + void makeCts_3Point(bool& selAllowed) { // chain distances, angle if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add horizontal chain dimensions")); - createChainDimension("DistanceX", pos); + createChainDimension("DistanceX"); selAllowed = true; } if (availableDimension == AvailableDimension::SECOND) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add horizontal coordinate dimensions")); - createCoordDimension("DistanceX", pos); + createCoordDimension("DistanceX"); } if (availableDimension == AvailableDimension::THIRD) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add 3-points angle dimension")); - create3pAngleDimension(selPoints[0], selPoints[1], selPoints[2], pos); + create3pAngleDimension({ selPoints[0], selPoints[1], selPoints[2] }); } else if (availableDimension == AvailableDimension::FOURTH) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add 3-points angle dimension")); - create3pAngleDimension(selPoints[1], selPoints[2], selPoints[0], pos); + create3pAngleDimension({ selPoints[1], selPoints[2], selPoints[0] }); } else if (availableDimension == AvailableDimension::FIFTH) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add 3-points angle dimension")); - create3pAngleDimension(selPoints[2], selPoints[0], selPoints[1], pos); + create3pAngleDimension({ selPoints[2], selPoints[0], selPoints[1] }); availableDimension = AvailableDimension::RESET; } } - void makeCts_4MorePoints(bool& selAllowed, QPoint& pos) + void makeCts_4MorePoints(bool& selAllowed) { // chain distances if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add horizontal chain dimension")); - createChainDimension("DistanceX", pos); + createChainDimension("DistanceX"); selAllowed = true; } if (availableDimension == AvailableDimension::SECOND) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add horizontal coordinate dimensions")); - createCoordDimension("DistanceX", pos); + createCoordDimension("DistanceX"); availableDimension = AvailableDimension::RESET; } } - void makeCts_1Point1Line(bool& selAllowed, QPoint& pos) + void makeCts_1Point1Line(bool& selAllowed) { //distance if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add point to line Distance dimension")); - createDistanceDimension("Distance", selPoints[0], selLine[0], pos); + createDistanceDimension("Distance", { selPoints[0], selLine[0] }); selAllowed = true; availableDimension = AvailableDimension::RESET; } } - void makeCts_1Point1Circle(bool& selAllowed, QPoint& pos) + void makeCts_1Point1Circle(bool& selAllowed) { //Distance, extent distance if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add length dimension")); - createDistanceDimension("Distance", selPoints[0], selCircleArc[0], pos); + createDistanceDimension("Distance", { selPoints[0], selCircleArc[0] }); selAllowed = true; } if (availableDimension == AvailableDimension::SECOND) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); - createExtentDistanceDimension("DistanceX", pos); + createExtentDistanceDimension("DistanceX"); availableDimension = AvailableDimension::RESET; } } - void makeCts_1Point1Ellipse(bool& selAllowed, QPoint& pos) + void makeCts_1Point1Ellipse(bool& selAllowed) { //Distance if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add length dimension")); - createDistanceDimension("Distance", selPoints[0], selEllipseArc[0], pos); + createDistanceDimension("Distance", { selPoints[0], selEllipseArc[0] }); selAllowed = true; } if (availableDimension == AvailableDimension::SECOND) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); - createExtentDistanceDimension("DistanceX", pos); + createExtentDistanceDimension("DistanceX"); availableDimension = AvailableDimension::RESET; } } - void makeCts_1Line(bool& selAllowed, QPoint& pos) + void makeCts_1Line(bool& selAllowed) { //distance if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add length dimension")); - createDistanceDimension("Distance", selLine[0], ReferenceEntry(), pos); + createDistanceDimension("Distance", { selLine[0] }); specialDimension = SpecialDimension::LineOr2PointsDistance; selAllowed = true; availableDimension = AvailableDimension::RESET; } } - void makeCts_2Line(bool& selAllowed, QPoint& pos) + void makeCts_2Line(bool& selAllowed) { //angle (if parallel: Distance (see in createAngleDimension)). if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Angle dimension")); - createAngleDimension(selLine[0], selLine[1], pos); + createAngleDimension(selLine[0], selLine[1]); selAllowed = true; } if (availableDimension == AvailableDimension::SECOND) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); - createExtentDistanceDimension("DistanceX", pos); + createExtentDistanceDimension("DistanceX"); availableDimension = AvailableDimension::RESET; } } - void makeCts_1Line1Circle(bool& selAllowed, QPoint& pos) + void makeCts_1Line1Circle(bool& selAllowed) { //distance, extent distance if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add circle to line Distance dimension")); - createDistanceDimension("Distance", selCircleArc[0], selLine[0], pos); + createDistanceDimension("Distance", { selCircleArc[0], selLine[0] }); selAllowed = true; } if (availableDimension == AvailableDimension::SECOND) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); - createExtentDistanceDimension("DistanceX", pos); + createExtentDistanceDimension("DistanceX"); availableDimension = AvailableDimension::RESET; } } - void makeCts_1Line1Ellipse(bool& selAllowed, QPoint& pos) + void makeCts_1Line1Ellipse(bool& selAllowed) { //distance, extent distance if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add ellipse to line Distance dimension")); - createDistanceDimension("Distance", selEllipseArc[0], selLine[0], pos); + createDistanceDimension("Distance", { selEllipseArc[0], selLine[0] }); selAllowed = true; } if (availableDimension == AvailableDimension::SECOND) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); - createExtentDistanceDimension("DistanceX", pos); + createExtentDistanceDimension("DistanceX"); availableDimension = AvailableDimension::RESET; } } - void makeCts_1Circle(bool& selAllowed, QPoint& pos) + void makeCts_1Circle(bool& selAllowed) { if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Radius dimension")); - createRadiusDiameterDimension(selCircleArc[0], pos, true); + createRadiusDiameterDimension(selCircleArc[0], true); selAllowed = true; } if (availableDimension == AvailableDimension::SECOND) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Radius dimension")); - createRadiusDiameterDimension(selCircleArc[0], pos, false); + createRadiusDiameterDimension(selCircleArc[0], false); if (selCircleArc[0].geomEdgeType() != TechDraw::ARCOFCIRCLE) { availableDimension = AvailableDimension::RESET; } } if (availableDimension == AvailableDimension::THIRD) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Arc Length dimension")); - createArcLengthDimension(selCircleArc[0], pos); + createArcLengthDimension(selCircleArc[0]); availableDimension = AvailableDimension::RESET; } } - void makeCts_2Circle(bool& selAllowed, QPoint& pos) + void makeCts_2Circle(bool& selAllowed) { //Distance if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add circle to circle Distance dimension")); - createDistanceDimension("Distance", selCircleArc[0], selCircleArc[1], pos); + createDistanceDimension("Distance", { selCircleArc[0], selCircleArc[1] }); selAllowed = true; } if (availableDimension == AvailableDimension::SECOND) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); - createExtentDistanceDimension("DistanceX", pos); + createExtentDistanceDimension("DistanceX"); availableDimension = AvailableDimension::RESET; } } - void makeCts_1Ellipse(bool& selAllowed, QPoint& pos) + void makeCts_1Ellipse(bool& selAllowed) { if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Radius dimension")); - createRadiusDiameterDimension(selEllipseArc[0], pos, true); + createRadiusDiameterDimension(selEllipseArc[0], true); selAllowed = true; } if (availableDimension == AvailableDimension::SECOND) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Radius dimension")); - createRadiusDiameterDimension(selEllipseArc[0], pos, false); + createRadiusDiameterDimension(selEllipseArc[0], false); if (selEllipseArc[0].geomEdgeType() != TechDraw::ARCOFELLIPSE) { availableDimension = AvailableDimension::RESET; } } if (availableDimension == AvailableDimension::THIRD) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Arc Length dimension")); - createArcLengthDimension(selEllipseArc[0], pos); + createArcLengthDimension(selEllipseArc[0]); availableDimension = AvailableDimension::RESET; } } - void makeCts_2Ellipses(bool& selAllowed, QPoint& pos) + void makeCts_2Ellipses(bool& selAllowed) { //Distance if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add ellipse to ellipse Distance dimension")); - createDistanceDimension("Distance", selEllipseArc[0], selEllipseArc[1], pos); + createDistanceDimension("Distance", { selEllipseArc[0], selEllipseArc[1] }); selAllowed = true; } if (availableDimension == AvailableDimension::SECOND) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); - createExtentDistanceDimension("DistanceX", pos); + createExtentDistanceDimension("DistanceX"); availableDimension = AvailableDimension::RESET; } } - void makeCts_1Spline(bool& selAllowed, QPoint& pos) + void makeCts_1Spline(bool& selAllowed) { //Edge length if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add edge length dimension")); - createArcLengthDimension(selSplineAndCo[0], pos); + createArcLengthDimension(selSplineAndCo[0]); selAllowed = true; availableDimension = AvailableDimension::RESET; } } - void makeCts_1SplineAndMore(bool& selAllowed, QPoint& pos) + void makeCts_1SplineAndMore(bool& selAllowed) { //Extend if (availableDimension == AvailableDimension::FIRST) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Extent dimension")); - createExtentDistanceDimension("DistanceX", pos); + createExtentDistanceDimension("DistanceX"); selAllowed = true; availableDimension = AvailableDimension::RESET; } } - void createAreaDimension(ReferenceEntry ref, QPoint& pos) + void createAreaDimension(ReferenceEntry ref) { DrawViewDimension* dim = dimMaker(partFeat, "Area", { ref }, {}); dims.push_back(dim); - moveDimension(pos, dim); + moveDimension(mousePos, dim); } - void createRadiusDiameterDimension(ReferenceEntry ref, QPoint& pos, bool firstCstr) { + void createRadiusDiameterDimension(ReferenceEntry ref, bool firstCstr) { bool isCircleGeom = true; int GeoId(TechDraw::DrawUtil::getIndexFromName(ref.getSubName())); TechDraw::BaseGeomPtr geom = partFeat->getGeomByIndex(GeoId); - isCircleGeom = geom->getGeomType() == TechDraw::CIRCLE || TechDraw::ELLIPSE; + isCircleGeom = (geom->getGeomType() == TechDraw::CIRCLE) || (geom->getGeomType() == TechDraw::ELLIPSE); // Use same preference as in sketcher? ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/TechDraw/dimensioning"); @@ -1032,61 +1065,57 @@ protected: } dims.push_back(dim); - moveDimension(pos, dim); + moveDimension(mousePos, dim); } - void createAngleDimension(ReferenceEntry ref1, ReferenceEntry ref2, QPoint& pos) { + void createAngleDimension(ReferenceEntry ref1, ReferenceEntry ref2) { if (TechDraw::isValidMultiEdge({ ref1, ref2 }) != isAngle) { //isValidMultiEdge check if lines are parallel. restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance dimension")); - createDistanceDimension("Distance", ref1, ref2, pos); + createDistanceDimension("Distance", { ref1, ref2 }); return; } DrawViewDimension* dim = dimMaker(partFeat, "Angle", {ref1, ref2}, {}); dims.push_back(dim); - moveDimension(pos, dim); + moveDimension(mousePos, dim); } - void create3pAngleDimension(ReferenceEntry ref1, ReferenceEntry ref2, ReferenceEntry ref3, QPoint& pos) + void create3pAngleDimension(ReferenceVector refs) { - DrawViewDimension* dim = dimMaker(partFeat, "Angle3Pt", {ref1, ref2, ref3}, {}); + DrawViewDimension* dim = dimMaker(partFeat, "Angle3Pt", refs, {}); dims.push_back(dim); - moveDimension(pos, dim); + moveDimension(mousePos, dim); } - void createArcLengthDimension(ReferenceEntry ref, QPoint& pos) + void createArcLengthDimension(ReferenceEntry ref) { DrawViewDimension* dim = makeArcLengthDimension(ref); dims.push_back(dim); - moveDimension(pos, dim); + moveDimension(mousePos, dim); } - void createDistanceDimension(std::string type, ReferenceEntry ref1, ReferenceEntry ref2, QPoint& pos) { - ReferenceVector refs = { ref1 }; - if (ref2.hasGeometry()) { // if valid - refs.push_back(ref2); - } - + void createDistanceDimension(std::string type, ReferenceVector refs) + { DrawViewDimension* dim = dimMaker(partFeat, type, refs, {}); dims.push_back(dim); - moveDimension(pos, dim); + moveDimension(mousePos, dim); } - void createExtentDistanceDimension(std::string type, QPoint& pos) { + void createExtentDistanceDimension(std::string type) { specialDimension = SpecialDimension::ExtendDistance; DrawViewDimension* dim = DrawDimHelper::makeExtentDim(partFeat, type, allRefs()); dims.push_back(dim); - moveDimension(pos, dim); + moveDimension(mousePos, dim); } - void updateDistanceType(QPoint& pos) + void updateDistanceType() { if (dims.empty()) { return; @@ -1098,7 +1127,7 @@ protected: Base::Vector3d pnt1 = Rez::guiX(pp.first()); Base::Vector3d pnt2 = Rez::guiX(pp.second()); - QPointF fpos = getDimPositionToBe(pos); + QPointF fpos = getDimPositionToBe(mousePos); double minX, minY, maxX, maxY; minX = min(pnt1.x, pnt2.x); @@ -1127,14 +1156,15 @@ protected: specialDimension = SpecialDimension::LineOr2PointsDistance; if (selLine.size() == 1) { - createDistanceDimension(newType, selLine[0], ReferenceEntry(), pos); + createDistanceDimension(newType, { selLine[0] }); } else { - createDistanceDimension(newType, selPoints[0], selPoints[1], pos); + createDistanceDimension(newType, { selPoints[0], selPoints[1] }); } + setDimsSelectability(false); } - void updateExtentDistanceType(QPoint& pos) + void updateExtentDistanceType() { if (dims.empty()) { return; @@ -1146,7 +1176,7 @@ protected: Base::Vector3d pnt1 = Rez::guiX(pp.first()); Base::Vector3d pnt2 = Rez::guiX(pp.second()); - QPointF fpos = getDimPositionToBe(pos); + QPointF fpos = getDimPositionToBe(mousePos); double minX, minY, maxX, maxY; minX = min(pnt1.x, pnt2.x); @@ -1157,16 +1187,21 @@ protected: if (fpos.x() > minX && fpos.x() < maxX && (fpos.y() < minY || fpos.y() > maxY) && type != DimensionType::DistanceX) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceX extent dimension")); - createExtentDistanceDimension("DistanceX", pos); + createExtentDistanceDimension("DistanceX"); } else if (fpos.y() > minY && fpos.y() < maxY && (fpos.x() < minX || fpos.x() > maxX) && type != DimensionType::DistanceY) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceY extent dimension")); - createExtentDistanceDimension("DistanceY", pos); + createExtentDistanceDimension("DistanceY"); } + else { + return; + } + + setDimsSelectability(false); } - void updateChainDistanceType(QPoint& pos) + void updateChainDistanceType() { if (dims.empty()) { return; @@ -1187,7 +1222,7 @@ protected: maxY = max(maxY, max(pnt1.y, pnt2.y)); } - QPointF fpos = getDimPositionToBe(pos); + QPointF fpos = getDimPositionToBe(mousePos); auto type = static_cast(dims[0]->Type.getValue()); @@ -1195,37 +1230,42 @@ protected: && (fpos.y() < minY || fpos.y() > maxY) && type != DimensionType::DistanceX) { if (specialDimension == SpecialDimension::ChainDistance) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add horizontal chain dimensions")); - createChainDimension("DistanceX", pos); + createChainDimension("DistanceX"); } else { restartCommand(QT_TRANSLATE_NOOP("Command", "Add horizontal coord dimensions")); - createCoordDimension("DistanceX", pos); + createCoordDimension("DistanceX"); } } else if (fpos.y() > minY && fpos.y() < maxY && (fpos.x() < minX || fpos.x() > maxX) && type != DimensionType::DistanceY) { if (specialDimension == SpecialDimension::ChainDistance) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add vertical chain dimensions")); - createChainDimension("DistanceY", pos); + createChainDimension("DistanceY"); } else { restartCommand(QT_TRANSLATE_NOOP("Command", "Add vertical coord dimensions")); - createCoordDimension("DistanceY", pos); + createCoordDimension("DistanceY"); } } else if (((fpos.y() < minY || fpos.y() > maxY) && (fpos.x() < minX || fpos.x() > maxX)) && type != DimensionType::Distance) { if (specialDimension == SpecialDimension::ChainDistance) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add oblique chain dimensions")); - createChainDimension("Distance", pos); + createChainDimension("Distance"); } else { restartCommand(QT_TRANSLATE_NOOP("Command", "Add oblique coord dimensions")); - createCoordDimension("Distance", pos); + createCoordDimension("Distance"); } } + else { + return; + } + + setDimsSelectability(false); } - void createChainDimension(std::string type, QPoint& pos) + void createChainDimension(std::string type) { specialDimension = SpecialDimension::ChainDistance; if (type == "Distance") { @@ -1241,7 +1281,7 @@ protected: } } - void createCoordDimension(std::string type, QPoint& pos) + void createCoordDimension(std::string type) { specialDimension = SpecialDimension::CoordDistance; if (type == "Distance") { @@ -1269,7 +1309,7 @@ protected: Gui::Command::abortCommand(); Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Dimension")); specialDimension = SpecialDimension::None; - previousPos = QPoint(0,0); + mousePos = QPoint(0,0); clearRefVectors(); partFeat = nullptr; dims.clear(); diff --git a/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp b/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp index abe41eeb39..61c126598f 100644 --- a/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp +++ b/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp @@ -2377,7 +2377,7 @@ DrawViewDimension* TechDrawGui::makeArcLengthDimension(const ReferenceEntry& ref } GProp_GProps edgeProps; BRepGProp::LinearProperties(edge->getOCCEdge(), edgeProps); - double length = edgeProps.Mass(); + double length = edgeProps.Mass() / dvp->getScale(); Base::Vector3d startPt = edge->getStartPoint(); Base::Vector3d endPt = edge->getEndPoint(); @@ -2385,7 +2385,6 @@ DrawViewDimension* TechDrawGui::makeArcLengthDimension(const ReferenceEntry& ref endPt.y = -endPt.y; std::stringstream startName, endName, formatSpec; - double scale = dvp->getScale(); Base::Vector3d cvPoint = CosmeticVertex::makeCanonicalPoint(dvp, startPt); std::string startVertTag = dvp->addCosmeticVertex(cvPoint); int startVertNumber = dvp->add1CVToGV(startVertTag); diff --git a/src/Mod/TechDraw/Gui/CommandExtensionDims.h b/src/Mod/TechDraw/Gui/CommandExtensionDims.h index aebb200b29..aff7159c71 100644 --- a/src/Mod/TechDraw/Gui/CommandExtensionDims.h +++ b/src/Mod/TechDraw/Gui/CommandExtensionDims.h @@ -23,9 +23,12 @@ #ifndef TECHDRAWGUI_CommandExtensionDims_H #define TECHDRAWGUI_CommandExtensionDims_H +#include + namespace TechDraw { class ReferenceEntry; + class DrawViewDimension; } namespace TechDrawGui { diff --git a/src/Mod/TechDraw/Gui/MDIViewPage.cpp b/src/Mod/TechDraw/Gui/MDIViewPage.cpp index edbc80b1d5..f31241c2f7 100644 --- a/src/Mod/TechDraw/Gui/MDIViewPage.cpp +++ b/src/Mod/TechDraw/Gui/MDIViewPage.cpp @@ -110,6 +110,7 @@ MDIViewPage::MDIViewPage(ViewProviderPage* pageVp, Gui::Document* doc, QWidget* connect(m_printAllAction, &QAction::triggered, this, qOverload<>(&MDIViewPage::printAllPages)); isSelectionBlocked = false; + isContextualMenuEnabled = true; QString tabText = QString::fromUtf8(pageVp->getDrawPage()->getNameInDocument()); tabText += QString::fromUtf8("[*]"); @@ -461,14 +462,16 @@ PyObject* MDIViewPage::getPyObject() void MDIViewPage::contextMenuEvent(QContextMenuEvent* event) { // Base::Console().Message("MDIVP::contextMenuEvent() - reason: %d\n", event->reason()); - QMenu menu; - menu.addAction(m_toggleFrameAction); - menu.addAction(m_toggleKeepUpdatedAction); - menu.addAction(m_exportSVGAction); - menu.addAction(m_exportDXFAction); - menu.addAction(m_exportPDFAction); - menu.addAction(m_printAllAction); - menu.exec(event->globalPos()); + if (isContextualMenuEnabled) { + QMenu menu; + menu.addAction(m_toggleFrameAction); + menu.addAction(m_toggleKeepUpdatedAction); + menu.addAction(m_exportSVGAction); + menu.addAction(m_exportDXFAction); + menu.addAction(m_exportPDFAction); + menu.addAction(m_printAllAction); + menu.exec(event->globalPos()); + } } void MDIViewPage::toggleFrame() { m_vpPage->toggleFrameState(); } @@ -1065,6 +1068,17 @@ void MDIViewPage::showStatusMsg(const char* string1, const char* string2, const } } +void MDIViewPage::setDimensionsSelectability(bool val) +{ + for (auto scene : m_scene->items()) { + auto* dl = dynamic_cast(scene); + if (dl) { + dl->setSelectability(val); + } + } +} + + // ---------------------------------------------------------------------------- void MDIViewPagePy::init_type() diff --git a/src/Mod/TechDraw/Gui/MDIViewPage.h b/src/Mod/TechDraw/Gui/MDIViewPage.h index 6f58a19eba..175dcf98b6 100644 --- a/src/Mod/TechDraw/Gui/MDIViewPage.h +++ b/src/Mod/TechDraw/Gui/MDIViewPage.h @@ -109,6 +109,9 @@ public: void setScene(QGSPage* scene, QGVPage* view); void fixSceneDependencies(); + void setDimensionsSelectability(bool val); + void enableContextualMenu(bool val) { isContextualMenuEnabled = val; } + public Q_SLOTS: void viewAll() override; void saveSVG(); @@ -147,6 +150,7 @@ private: std::string m_objectName; std::string m_documentName; bool isSelectionBlocked; + bool isContextualMenuEnabled; QPointer m_scene; QString m_currentPath; diff --git a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp index 86aaa7fc9a..d39918d11e 100644 --- a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp @@ -93,8 +93,7 @@ QGIDatumLabel::QGIDatumLabel() : m_dragState(NoDrag) setCacheMode(QGraphicsItem::NoCache); setFlag(ItemSendsGeometryChanges, true); setFlag(ItemIsMovable, true); - setFlag(ItemIsSelectable, true); - setAcceptHoverEvents(true); + setSelectability(true); setFiltersChildEvents(true); m_dimText = new QGCustomText(); @@ -445,6 +444,13 @@ void QGIDatumLabel::setColor(QColor color) m_unitText->setColor(m_colNormal); } +void QGIDatumLabel::setSelectability(bool val) +{ + setFlag(ItemIsSelectable, val); + setAcceptHoverEvents(val); + setAcceptedMouseButtons(val ? Qt::AllButtons : Qt::NoButton); +} + //************************************************************** QGIViewDimension::QGIViewDimension() : dvDimension(nullptr), hasHover(false), m_lineWidth(0.0) { @@ -1258,7 +1264,7 @@ void QGIViewDimension::resetArrows() const } void QGIViewDimension::drawArrows(int count, const Base::Vector2d positions[], double angles[], - bool flipped) const + bool flipped, bool forcePoint) const { const int arrowCount = 2; QGIArrow* arrows[arrowCount] = {aHead1, aHead2}; @@ -1278,7 +1284,8 @@ void QGIViewDimension::drawArrows(int count, const Base::Vector2d positions[], d continue; } - arrow->setStyle(QGIArrow::getPrefArrowStyle()); + // some dimensions must use point ends (area). The point style is 3. + arrow->setStyle(forcePoint ? 3 : QGIArrow::getPrefArrowStyle()); auto vp = static_cast(getViewProvider(getViewObject())); auto arrowSize = vp->Arrowsize.getValue(); arrow->setSize(arrowSize); @@ -1406,7 +1413,7 @@ void QGIViewDimension::drawDimensionLine(QPainterPath& painterPath, const Base::Vector2d& targetPoint, double lineAngle, double startPosition, double jointPosition, const Base::BoundBox2d& labelRectangle, int arrowCount, - int standardStyle, bool flipArrows) const + int standardStyle, bool flipArrows, bool forcePointStyle) const { // Keep the convention start position <= 0 jointPosition *= normalizeStartPosition(startPosition, lineAngle); @@ -1426,7 +1433,7 @@ void QGIViewDimension::drawDimensionLine(QPainterPath& painterPath, arrowAngles[0] = lineAngle; arrowAngles[1] = lineAngle + M_PI; - drawArrows(arrowCount, arrowPositions, arrowAngles, flipArrows); + drawArrows(arrowCount, arrowPositions, arrowAngles, flipArrows, forcePointStyle); } void QGIViewDimension::drawDimensionArc(QPainterPath& painterPath, const Base::Vector2d& arcCenter, @@ -2097,6 +2104,7 @@ void QGIViewDimension::drawAreaExecutive(const Base::Vector2d& centerPoint, doub Base::Vector2d labelCenter(labelRectangle.GetCenter()); double labelAngle = 0.0; + bool forcePointStyle = true; if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING || standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING) { @@ -2112,11 +2120,10 @@ void QGIViewDimension::drawAreaExecutive(const Base::Vector2d& centerPoint, doub jointDirection = getAsmeRefJointPoint(labelRectangle, left) - centerPoint; } - double lineAngles = jointDirection.Angle(); + double lineAngle = jointDirection.Angle(); double jointPositions = jointDirection.Length(); - drawDimensionLine(areaPath, centerPoint, lineAngles, 0.0, - jointPositions, labelRectangle, 1, standardStyle, flipArrow); + drawDimensionLine(areaPath, centerPoint, lineAngle, 0.0, jointPositions, labelRectangle, 1, standardStyle, flipArrow, forcePointStyle); Base::Vector2d outsetPoint(standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING ? getIsoRefOutsetPoint(labelRectangle, left) @@ -2135,7 +2142,7 @@ void QGIViewDimension::drawAreaExecutive(const Base::Vector2d& centerPoint, doub lineAngle = lineAngle - M_PI; double labelPosition = -cos(devAngle) * ((labelCenter - centerPoint).Length()); - drawDimensionLine(areaPath, centerPoint, lineAngle, 0.0, labelPosition, labelRectangle, 1, standardStyle, flipArrow); + drawDimensionLine(areaPath, centerPoint, lineAngle, 0.0, labelPosition, labelRectangle, 1, standardStyle, flipArrow, forcePointStyle); } else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) { // Text must remain horizontal, but it may split the leader line @@ -2143,7 +2150,7 @@ void QGIViewDimension::drawAreaExecutive(const Base::Vector2d& centerPoint, doub double lineAngle = labelDirection.Angle(); double labelPosition = labelDirection.Length(); - drawDimensionLine(areaPath, centerPoint, lineAngle, 0.0, labelPosition, labelRectangle, 1, standardStyle, flipArrow); + drawDimensionLine(areaPath, centerPoint, lineAngle, 0.0, labelPosition, labelRectangle, 1, standardStyle, flipArrow, forcePointStyle); } else { Base::Console().Error( diff --git a/src/Mod/TechDraw/Gui/QGIViewDimension.h b/src/Mod/TechDraw/Gui/QGIViewDimension.h index 34524c1410..f74a0cdd57 100644 --- a/src/Mod/TechDraw/Gui/QGIViewDimension.h +++ b/src/Mod/TechDraw/Gui/QGIViewDimension.h @@ -87,6 +87,7 @@ public: void setPrettyPre(); void setPrettyNormal(); void setColor(QColor color); + void setSelectability(bool val); QGCustomText* getDimText() { return m_dimText; } void setDimText(QGCustomText* newText) { m_dimText = newText; } @@ -232,7 +233,7 @@ protected: void draw() override; void resetArrows() const; - void drawArrows(int count, const Base::Vector2d positions[], double angles[], bool flipped) const; + void drawArrows(int count, const Base::Vector2d positions[], double angles[], bool flipped, bool forcePoint = false) const; void drawSingleLine(QPainterPath &painterPath, const Base::Vector2d &lineOrigin, double lineAngle, double startPosition, double endPosition) const; @@ -245,7 +246,7 @@ protected: void drawDimensionLine(QPainterPath &painterPath, const Base::Vector2d &targetPoint, double lineAngle, double startPosition, double jointPosition, const Base::BoundBox2d &labelRectangle, - int arrowCount, int standardStyle, bool flipArrows) const; + int arrowCount, int standardStyle, bool flipArrows, bool forcePointStyle = false) const; void drawDimensionArc(QPainterPath &painterPath, const Base::Vector2d &arcCenter, double arcRadius, double endAngle, double startRotation, double jointAngle, const Base::BoundBox2d &labelRectangle, int arrowCount, diff --git a/src/Mod/TechDraw/Gui/QGVPage.h b/src/Mod/TechDraw/Gui/QGVPage.h index f123a9d8f1..c39a9116e9 100644 --- a/src/Mod/TechDraw/Gui/QGVPage.h +++ b/src/Mod/TechDraw/Gui/QGVPage.h @@ -104,6 +104,7 @@ public: void activateHandler(TechDrawHandler* newHandler); void deactivateHandler(); + bool isHandlerActive() { return toolHandler != nullptr; } bool isBalloonPlacing() const { return balloonPlacing; } void setBalloonPlacing(bool isPlacing) { balloonPlacing = isPlacing; } diff --git a/src/Mod/TechDraw/Gui/TechDrawHandler.cpp b/src/Mod/TechDraw/Gui/TechDrawHandler.cpp index cec5457435..182be5879b 100644 --- a/src/Mod/TechDraw/Gui/TechDrawHandler.cpp +++ b/src/Mod/TechDraw/Gui/TechDrawHandler.cpp @@ -26,6 +26,9 @@ #include #include +#include +#include +#include #include #endif // #ifndef _PreComp_ @@ -55,6 +58,12 @@ TechDrawHandler::~TechDrawHandler() void TechDrawHandler::activate(QGVPage* vp) { + auto* mdi = dynamic_cast(Gui::getMainWindow()->activeWindow()); + if (!mdi) { + return; + } + mdi->enableContextualMenu(false); + viewPage = vp; if (!Gui::ToolHandler::activate()) { @@ -62,6 +71,22 @@ void TechDrawHandler::activate(QGVPage* vp) } } +void TechDrawHandler::deactivate() +{ + Gui::ToolHandler::deactivate(); + + // The context menu event of MDIViewPage comes after the tool is deactivated. + // So to prevent the menu from appearing when the tool is cleared by right mouse click + // we set a small timer. + QTimer::singleShot(100, [this]() { // 100 milliseconds delay + auto* mdi = dynamic_cast(Gui::getMainWindow()->activeWindow()); + if (!mdi) { + return; + } + mdi->enableContextualMenu(true); + }); +} + void TechDrawHandler::keyReleaseEvent(QKeyEvent* event) { // the default behaviour is to quit - specific handler categories may @@ -72,7 +97,7 @@ void TechDrawHandler::keyReleaseEvent(QKeyEvent* event) } } -bool TechDrawHandler::mousePressEvent(QMouseEvent* event) +void TechDrawHandler::mouseReleaseEvent(QMouseEvent* event) { // the default behaviour is to quit - specific handler categories may // override this behaviour, for example to implement a continuous mode @@ -80,7 +105,6 @@ bool TechDrawHandler::mousePressEvent(QMouseEvent* event) quit(); event->accept(); } - return true; } void TechDrawHandler::quit() diff --git a/src/Mod/TechDraw/Gui/TechDrawHandler.h b/src/Mod/TechDraw/Gui/TechDrawHandler.h index d1c911541b..3e3c8a81ea 100644 --- a/src/Mod/TechDraw/Gui/TechDrawHandler.h +++ b/src/Mod/TechDraw/Gui/TechDrawHandler.h @@ -39,12 +39,13 @@ public: virtual ~TechDrawHandler(); void activate(QGVPage* vPage); + void deactivate() override; void quit() override; virtual void mouseMoveEvent(QMouseEvent* event) = 0; - virtual bool mousePressEvent(QMouseEvent* event); - virtual bool mouseReleaseEvent(QMouseEvent* event) = 0; + virtual void mousePressEvent(QMouseEvent* event) { Q_UNUSED(event) }; + virtual void mouseReleaseEvent(QMouseEvent* event); virtual void keyPressEvent(QKeyEvent* event) = 0; virtual void keyReleaseEvent(QKeyEvent* event); From 972f711210cc4d48c51a980e48a892236c2b4676 Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Tue, 30 Apr 2024 09:24:05 +0200 Subject: [PATCH 9/9] TechDraw: Smart Dimension tool : Integrate the 'chamfer' tool. --- src/Gui/ToolHandler.cpp | 90 ++++++++++------------ src/Mod/TechDraw/Gui/CommandCreateDims.cpp | 90 +++++++++++++++++++--- src/Mod/TechDraw/Gui/Workbench.cpp | 4 +- 3 files changed, 124 insertions(+), 60 deletions(-) diff --git a/src/Gui/ToolHandler.cpp b/src/Gui/ToolHandler.cpp index e21036a72b..722aa197fd 100644 --- a/src/Gui/ToolHandler.cpp +++ b/src/Gui/ToolHandler.cpp @@ -180,56 +180,50 @@ void ToolHandler::setCursor(const QPixmap& p, int x, int y, bool autoScale) void ToolHandler::addCursorTail(std::vector& pixmaps) { // Create a pixmap that will contain icon and each autoconstraint icon - Gui::MDIView* view = Gui::getMainWindow()->activeWindow(); - if (view && view->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) { - QPixmap baseIcon = QPixmap(actCursorPixmap); - baseIcon.setDevicePixelRatio(actCursorPixmap.devicePixelRatio()); - qreal pixelRatio = baseIcon.devicePixelRatio(); - // cursor size in device independent pixels - qreal baseCursorWidth = baseIcon.width(); - qreal baseCursorHeight = baseIcon.height(); + QPixmap baseIcon = QPixmap(actCursorPixmap); + baseIcon.setDevicePixelRatio(actCursorPixmap.devicePixelRatio()); + qreal pixelRatio = baseIcon.devicePixelRatio(); + // cursor size in device independent pixels + qreal baseCursorWidth = baseIcon.width(); + qreal baseCursorHeight = baseIcon.height(); - int tailWidth = 0; - for (auto const& p : pixmaps) { - tailWidth += p.width(); - } - - int newIconWidth = baseCursorWidth + tailWidth; - int newIconHeight = baseCursorHeight; - - QPixmap newIcon(newIconWidth, newIconHeight); - newIcon.fill(Qt::transparent); - - QPainter qp; - qp.begin(&newIcon); - - qp.drawPixmap(QPointF(0, 0), - baseIcon.scaled(baseCursorWidth * pixelRatio, - baseCursorHeight * pixelRatio, - Qt::KeepAspectRatio, - Qt::SmoothTransformation)); - - // Iterate through pixmaps and them to the cursor pixmap - std::vector::iterator pit = pixmaps.begin(); - int i = 0; - qreal currentIconX = baseCursorWidth; - qreal currentIconY; - - for (; pit != pixmaps.end(); ++pit, i++) { - QPixmap icon = *pit; - currentIconY = baseCursorHeight - icon.height(); - qp.drawPixmap(QPointF(currentIconX, currentIconY), icon); - currentIconX += icon.width(); - } - - qp.end(); // Finish painting - - // Create the new cursor with the icon. - QPoint p = actCursor.hotSpot(); - newIcon.setDevicePixelRatio(pixelRatio); - QCursor newCursor(newIcon, p.x(), p.y()); - applyCursor(newCursor); + int tailWidth = 0; + for (auto const& p : pixmaps) { + tailWidth += p.width(); } + + int newIconWidth = baseCursorWidth + tailWidth; + int newIconHeight = baseCursorHeight; + + QPixmap newIcon(newIconWidth, newIconHeight); + newIcon.fill(Qt::transparent); + + QPainter qp; + qp.begin(&newIcon); + + qp.drawPixmap(QPointF(0, 0), + baseIcon.scaled(baseCursorWidth * pixelRatio, + baseCursorHeight * pixelRatio, + Qt::KeepAspectRatio, + Qt::SmoothTransformation)); + + // Iterate through pixmaps and them to the cursor pixmap + qreal currentIconX = baseCursorWidth; + qreal currentIconY; + + for (auto& icon : pixmaps) { + currentIconY = baseCursorHeight - icon.height(); + qp.drawPixmap(QPointF(currentIconX, currentIconY), icon); + currentIconX += icon.width(); + } + + qp.end(); // Finish painting + + // Create the new cursor with the icon. + QPoint p = actCursor.hotSpot(); + newIcon.setDevicePixelRatio(pixelRatio); + QCursor newCursor(newIcon, p.x(), p.y()); + applyCursor(newCursor); } void ToolHandler::updateCursor() diff --git a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp index 53674ac223..db5b2f332d 100644 --- a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp +++ b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp @@ -31,11 +31,13 @@ #include #include #include +#include #endif//#ifndef _PreComp_ #include #include #include +#include #include #include #include @@ -45,6 +47,8 @@ #include #include #include +#include +#include #include #include #include @@ -83,6 +87,7 @@ using DimensionType = TechDraw::DrawViewDimension::DimensionType; bool _checkSelection(Gui::Command* cmd, unsigned maxObjs = 2); bool _checkDrawViewPart(Gui::Command* cmd); + void execDistance(Gui::Command* cmd); void execDistanceX(Gui::Command* cmd); void execDistanceY(Gui::Command* cmd); @@ -210,6 +215,7 @@ public: enum class SpecialDimension { LineOr2PointsDistance, + LineOr2PointsChamfer, ExtendDistance, ChainDistance, CoordDistance, @@ -288,7 +294,8 @@ public: bool textToMiddle = false; Base::Vector3d dirMaster, delta; //Change distance dimension based on position of mouse. - if (specialDimension == SpecialDimension::LineOr2PointsDistance){ + if (specialDimension == SpecialDimension::LineOr2PointsDistance + || specialDimension == SpecialDimension::LineOr2PointsChamfer){ updateDistanceType(); } else if (specialDimension == SpecialDimension::ExtendDistance){ @@ -795,6 +802,14 @@ protected: createDistanceDimension("Distance", { selPoints[0], selPoints[1] }); specialDimension = SpecialDimension::LineOr2PointsDistance; selAllowed = true; + if (!isVerticalDistance({ selPoints[0], selPoints[1] })) { + availableDimension = AvailableDimension::RESET; + } + } + if (availableDimension == AvailableDimension::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceX Chamfer dimension")); + createDistanceDimension("DistanceX", { selPoints[0], selPoints[1] }, true); + specialDimension = SpecialDimension::LineOr2PointsChamfer; availableDimension = AvailableDimension::RESET; } } @@ -890,6 +905,17 @@ protected: createDistanceDimension("Distance", { selLine[0] }); specialDimension = SpecialDimension::LineOr2PointsDistance; selAllowed = true; + if (!isVerticalDistance({ selLine[0] })) { + availableDimension = AvailableDimension::RESET; + } + // Potential improvement for the future: we could show available modes in cursor trail. + //std::vector pixmaps = { icon("TechDraw_LengthDimension"), icon("TechDraw_ExtensionCreateHorizChamferDimension") }; + //addCursorTail(pixmaps); + } + if (availableDimension == AvailableDimension::SECOND) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceX Chamfer dimension")); + createDistanceDimension("DistanceX", { selLine[0] }, true); + specialDimension = SpecialDimension::LineOr2PointsChamfer; availableDimension = AvailableDimension::RESET; } } @@ -1098,10 +1124,22 @@ protected: moveDimension(mousePos, dim); } - void createDistanceDimension(std::string type, ReferenceVector refs) + void createDistanceDimension(std::string type, ReferenceVector refs, bool chamfer = false) { DrawViewDimension* dim = dimMaker(partFeat, type, refs, {}); + if (chamfer) { + // Add the angle to the label + TechDraw::pointPair pp = dim->getLinearPoints(); + float dx = pp.first().x - pp.second().x; + float dy = pp.first().y - pp.second().y; + int alpha = round(Base::toDegrees(abs(atan(type == "DistanceY" ? (dx / dy) : (dy / dx))))); + std::string sAlpha = std::to_string(alpha); + std::string formatSpec = dim->FormatSpec.getStrValue(); + formatSpec = formatSpec + " x" + sAlpha + "°"; + dim->FormatSpec.setValue(formatSpec); + } + dims.push_back(dim); moveDimension(mousePos, dim); } @@ -1122,13 +1160,14 @@ protected: } auto type = static_cast(dims[0]->Type.getValue()); + SpecialDimension backup = specialDimension; + bool chamfer = specialDimension == SpecialDimension::LineOr2PointsChamfer; TechDraw::pointPair pp = dims[0]->getLinearPoints(); Base::Vector3d pnt1 = Rez::guiX(pp.first()); Base::Vector3d pnt2 = Rez::guiX(pp.second()); QPointF fpos = getDimPositionToBe(mousePos); - double minX, minY, maxX, maxY; minX = min(pnt1.x, pnt2.x); maxX = max(pnt1.x, pnt2.x); @@ -1138,28 +1177,39 @@ protected: std::string newType = "Distance"; if (fpos.x() > minX && fpos.x() < maxX && (fpos.y() < minY || fpos.y() > maxY) && type != DimensionType::DistanceX) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceX dimension")); + if (chamfer) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceX Chamfer dimension")); + } + else { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceX dimension")); + } newType = "DistanceX"; } else if (fpos.y() > minY && fpos.y() < maxY && (fpos.x() < minX || fpos.x() > maxX) && type != DimensionType::DistanceY) { - restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceY dimension")); + if (chamfer) { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceY Chamfer dimension")); + } + else { + restartCommand(QT_TRANSLATE_NOOP("Command", "Add DistanceY dimension")); + } newType = "DistanceY"; } else if ((((fpos.y() < minY || fpos.y() > maxY) && (fpos.x() < minX || fpos.x() > maxX)) - || (fpos.y() > minY && fpos.y() < maxY && fpos.x() > minX && fpos.x() < maxX)) && type != DimensionType::Distance) { + || (fpos.y() > minY && fpos.y() < maxY && fpos.x() > minX && fpos.x() < maxX)) && type != DimensionType::Distance + && !chamfer) { restartCommand(QT_TRANSLATE_NOOP("Command", "Add Distance dimension")); } else { return; } - specialDimension = SpecialDimension::LineOr2PointsDistance; + specialDimension = backup; if (selLine.size() == 1) { - createDistanceDimension(newType, { selLine[0] }); + createDistanceDimension(newType, { selLine[0] }, chamfer); } else { - createDistanceDimension(newType, { selPoints[0], selPoints[1] }); + createDistanceDimension(newType, { selPoints[0], selPoints[1] }, chamfer); } setDimsSelectability(false); } @@ -1297,6 +1347,25 @@ protected: } } + bool isVerticalDistance(ReferenceVector refs) + { + DimensionGeometryType geometryRefs2d = validateDimSelection( + refs, { "Edge", "Vertex" }, { 1, 2 }, { isDiagonal }); + + return geometryRefs2d == TechDraw::isDiagonal; + } + + QPixmap icon(std::string name) + { + qreal pixelRatio = 1; + Gui::View3DInventorViewer* viewer = getViewer(); + if (viewer) { + pixelRatio = viewer->devicePixelRatio(); + } + int width = 16 * pixelRatio; + return Gui::BitmapFactory().pixmapFromSvg(name.c_str(), QSize(width, width)); + } + void restartCommand(const char* cstrName) { specialDimension = SpecialDimension::None; Gui::Command::abortCommand(); @@ -1403,6 +1472,9 @@ public: addCommand("TechDraw_ExtensionCreateHorizCoordDimension"); addCommand("TechDraw_ExtensionCreateVertCoordDimension"); addCommand("TechDraw_ExtensionCreateObliqueCoordDimension"); + addCommand(); //separator + addCommand("TechDraw_ExtensionCreateHorizChamferDimension"); + addCommand("TechDraw_ExtensionCreateVertChamferDimension"); } const char* className() const override { return "CmdTechDrawCompDimensionTools"; } diff --git a/src/Mod/TechDraw/Gui/Workbench.cpp b/src/Mod/TechDraw/Gui/Workbench.cpp index 21e17082d2..6e06e4f1e2 100644 --- a/src/Mod/TechDraw/Gui/Workbench.cpp +++ b/src/Mod/TechDraw/Gui/Workbench.cpp @@ -368,9 +368,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const if (separatedTools) { *extdimensions << "TechDraw_ExtensionCreateChainDimensionGroup"; *extdimensions << "TechDraw_ExtensionCreateCoordDimensionGroup"; - } - *extdimensions << "TechDraw_ExtensionChamferDimensionGroup"; - if (separatedTools) { + *extdimensions << "TechDraw_ExtensionChamferDimensionGroup"; *extdimensions << "TechDraw_ExtensionCreateLengthArc"; } *extdimensions << "TechDraw_ExtensionInsertPrefixGroup";