Merge pull request #13525 from Ondsel-Development/td_dimension

TechDraw: Smart dimension tool
This commit is contained in:
WandererFan
2024-05-13 12:31:32 -04:00
committed by GitHub
44 changed files with 3614 additions and 780 deletions

View File

@@ -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}
)

288
src/Gui/ToolHandler.cpp Normal file
View File

@@ -0,0 +1,288 @@
/***************************************************************************
* Copyright (c) 2024 Pierre-Louis Boyer <development@ondsel.com> *
* *
* 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 <cmath>
#include <QGuiApplication>
#include <QPainter>
#include <Inventor/events/SoKeyboardEvent.h>
#endif // #ifndef _PreComp_
#include <Base/Console.h>
#include <Base/Exception.h>
#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 *******************************************/
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<unsigned long, unsigned long>();
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<unsigned long, unsigned long>& 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<QPixmap>& pixmaps)
{
// Create a pixmap that will contain icon and each autoconstraint icon
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
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()
{
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<Gui::View3DInventor*>(view)->getViewer();
}
return nullptr;
}

127
src/Gui/ToolHandler.h Normal file
View File

@@ -0,0 +1,127 @@
/***************************************************************************
* Copyright (c) 2024 Pierre-Louis Boyer <development@ondsel.com> *
* *
* 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 <QCursor>
#include <QPixmap>
#include <Base/Parameter.h>
#include <Base/Tools2D.h>
#include "Selection.h"
namespace Gui
{
class View3DInventorViewer;
class GuiExport ToolHandler
{
public:
ToolHandler() = default;
virtual ~ToolHandler() = default;
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<QPixmap>& 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<unsigned long, unsigned long>& colorMapping =
std::map<unsigned long, unsigned long>());
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

View File

@@ -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

View File

@@ -270,7 +270,8 @@ void CurveConverter::OnChange(Base::Subject<const char*>& 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<QWidget> 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::View3DInventor*>(Gui::getMainWindow()->activeWindow());
if (view) {
Gui::View3DInventorViewer* viewer = dynamic_cast<Gui::View3DInventor*>(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<unsigned long, unsigned long>();
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<unsigned long, unsigned long>& 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<QPixmap>& 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<QPixmap>::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<QPixmap>
DrawSketchHandler::suggestedConstraintsPixmaps(std::vector<AutoConstraint>& 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<Gui::View3DInventor*>(view)->getViewer();
}
return nullptr;
}

View File

@@ -31,6 +31,7 @@
#include <Base/Parameter.h>
#include <Base/Tools2D.h>
#include <Gui/Selection.h>
#include <Gui/ToolHandler.h>
#include <Mod/Part/App/Geometry.h>
#include <Mod/Sketcher/App/Constraint.h>
@@ -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<QWidget> 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<Base::Vector2d>& EditCurve) const;
void drawEdit(const std::list<std::vector<Base::Vector2d>>& list) const;
void drawEdit(const std::vector<Part::Geometry*>& 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<unsigned long, unsigned long>& colorMapping =
std::map<unsigned long, unsigned long>());
void addCursorTail(std::vector<QPixmap>& pixmaps);
void applyCursor(QCursor& newCursor);
void setCrosshairCursor(const QString& svgName);
void setCrosshairCursor(const char* svgName);
protected:
/**
@@ -325,9 +274,6 @@ protected:
suggestedConstraintsPixmaps(std::vector<AutoConstraint>& suggestedConstraints);
ViewProviderSketch* sketchgui;
QCursor oldCursor;
QCursor actCursor;
QPixmap actCursorPixmap;
QWidget* toolwidget;
};

View File

@@ -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);
}
@@ -128,9 +131,14 @@ 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;
if (areaMeasure) {
userVal = userVal / convertValue; // divide again as area is length²
qBasicUnit = qBasicUnit + QString::fromUtf8("²");
}
}
if (isTooSmall(userVal, formatSpecifier)) {
@@ -153,37 +161,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 "";
}
}

View File

@@ -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());
}

View File

@@ -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

View File

@@ -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",
@@ -206,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");
}
@@ -253,12 +263,30 @@ Part::TopoShape ReferenceEntry::asTopoShapeEdge(const TopoDS_Edge &edge)
return { edge };
}
Part::TopoShape ReferenceEntry::asTopoShapeFace(const TopoDS_Face &face)
{
return { face };
}
std::string ReferenceEntry::geomType() const
{
// Base::Console().Message("RE::geomType() - subName: **%s**\n", getSubName().c_str());
return DrawUtil::getGeomTypeFromName(getSubName());
}
GeomType ReferenceEntry::geomEdgeType() const
{
int geoId = TechDraw::DrawUtil::getIndexFromName(getSubName());
auto dvp = static_cast<TechDraw::DrawViewPart*>(getObject());
BaseGeomPtr geom = dvp->getGeomByIndex(geoId);
if (geomType() == "Edge" && geom) {
return geom->getGeomType();
}
return GeomType::NOTDEF;
}
bool ReferenceEntry::isWholeObject() const
{
return getSubName().empty();
@@ -314,12 +342,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;
}

View File

@@ -33,6 +33,7 @@
#include <TopoDS_Vertex.hxx>
#include <Mod/Part/App/TopoShape.h>
#include <Mod/TechDraw/App/Geometry.h>
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;
@@ -86,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;

View File

@@ -59,13 +59,31 @@
using namespace TechDraw;
void DrawDimHelper::makeExtentDim(DrawViewPart* dvp, std::vector<std::string> edgeNames,
DrawViewDimension* DrawDimHelper::makeExtentDim(DrawViewPart* dvp,
const std::string& dimType, ReferenceVector references2d)
{
std::vector<std::string> 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<std::string> 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<std::string> 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<std::string> ed
Base::Interpreter().runStringArg(
"App.activeDocument().%s.DirExtent = %d", dimName.c_str(), dimNum);
TechDraw::DrawViewDimExtent* dimExt =
dynamic_cast<TechDraw::DrawViewDimExtent*>(doc->getObject(dimName.c_str()));
auto* dimExt = dynamic_cast<DrawViewDimExtent*>(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<std::string> 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<TechDraw::DrawViewDimExtent*>(doc->getObject(dimName.c_str()));
auto* dimExt = dynamic_cast<DrawViewDimExtent*>(doc->getObject(dimName.c_str()));
if (!dimExt) {
throw Base::TypeError("Dim extent not found");
}

View File

@@ -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<std::string> 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,

View File

@@ -31,6 +31,8 @@
#include <QString>
#include <QStringList>
#include <BRepGProp.hxx>
#include <GProp_GProps.hxx>
#include <BRep_Tool.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
@@ -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<DrawViewPart>() && !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<std::string>& 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<std::string>& 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;
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -348,6 +348,7 @@ class TechDrawExport Face
TopoDS_Face toOccFace() const;
std::vector<Wire *> wires;
double getArea() const;
Base::Vector3d getCenter() const;
};
using FacePtr = std::shared_ptr<Face>;

View File

@@ -26,6 +26,8 @@
#include "PreCompiled.h"
#ifndef _PreComp_
#include <BRepGProp.hxx>
#include <GProp_GProps.hxx>
#endif
#include <BRepAdaptor_Curve.hxx>
@@ -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");

View File

@@ -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);

View File

@@ -125,11 +125,11 @@ PyMOD_INIT_FUNC(TechDrawGui)
// instantiating the commands
CreateTechDrawCommands();
CreateTechDrawCommandsDims();
CreateTechDrawCommandsDecorate();
CreateTechDrawCommandsAnnotate();
CreateTechDrawCommandsExtensionDims();
CreateTechDrawCommandsExtensions();
CreateTechDrawCommandsDims();
CreateTechDrawCommandsStack();
TechDrawGui::Workbench::init();

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -25,6 +25,8 @@
# include <QApplication>
# include <QMessageBox>
# include <sstream>
# include <BRepGProp.hxx>
# include <GProp_GProps.hxx>
#endif
# include <App/Document.h>
@@ -52,6 +54,7 @@
#include "DrawGuiUtil.h"
#include "TaskCustomizeFormat.h"
#include "TaskSelectLineAttributes.h"
#include "CommandExtensionDims.h"
using namespace TechDrawGui;
@@ -78,7 +81,7 @@ namespace TechDrawGui {
std::vector<TechDraw::DrawViewDimension*>_getDimensions(std::vector<Gui::SelectionObject> selection, std::string needDimType);
std::vector<dimVertex> _getVertexInfo(TechDraw::DrawViewPart* objFeat,
std::vector<std::string> subNames);
TechDraw::DrawViewDimension* _createLinDimension(Gui::Command* cmd,
TechDraw::DrawViewDimension* _createLinDimension(
TechDraw::DrawViewPart* objFeat,
std::string startVertex,
std::string endVertex,
@@ -1280,7 +1283,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 +1350,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)
@@ -1404,7 +1407,37 @@ void execCreateObliqueChainDimension(Gui::Command* cmd) {
}
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create Oblique Chain Dim"));
const std::vector<std::string> subNames = selection[0].getSubNames();
std::vector<TechDraw::ReferenceEntry> 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<DrawViewDimension*> TechDrawGui::makeObliqueChainDimension(std::vector<TechDraw::ReferenceEntry> refs)
{
if (refs.empty()) {
return {};
}
std::vector<std::string> subNames;
auto* objFeat = static_cast<DrawViewPart*>(refs[0].getObject());
for (auto& ref : refs) {
subNames.push_back(ref.getSubName());
}
std::vector<DrawViewDimension*> dims;
std::vector<dimVertex> allVertexes, carrierVertexes;
allVertexes = _getVertexInfo(objFeat, subNames);
if (!allVertexes.empty() && allVertexes.size() > 1) {
@@ -1443,17 +1476,16 @@ 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);
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)
@@ -1630,7 +1662,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 +1735,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);
@@ -1760,7 +1792,37 @@ void execCreateObliqueCoordDimension(Gui::Command* cmd) {
}
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create Oblique Coord Dim"));
const std::vector<std::string> subNames = selection[0].getSubNames();
std::vector<TechDraw::ReferenceEntry> 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<DrawViewDimension*> TechDrawGui::makeObliqueCoordDimension(std::vector<TechDraw::ReferenceEntry> refs)
{
if (refs.empty()) {
return {};
}
std::vector<std::string> subNames;
auto* objFeat = static_cast<DrawViewPart*>(refs[0].getObject());
for (auto& ref : refs) {
subNames.push_back(ref.getSubName());
}
std::vector<DrawViewDimension*> dims;
std::vector<dimVertex> allVertexes, carrierVertexes;
allVertexes = _getVertexInfo(objFeat, subNames);
if (!allVertexes.empty() && allVertexes.size() > 1) {
@@ -1804,17 +1866,16 @@ 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);
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)
@@ -1991,7 +2052,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 +2121,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 +2301,19 @@ void CmdTechDrawExtensionCreateLengthArc::activated(int iMsg) {
}
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create Arc Length Dim"));
const std::vector<std::string> 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<TechDraw::AOC>(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());
ReferenceEntry ref(objFeat, selection[0].getSubNames()[0]);
TechDraw::DrawViewDimension* dim = makeArcLengthDimension(ref);
if (dim) {
objFeat->refreshCEGeoms();
objFeat->requestPaint();
getSelection().clearSelection();
Gui::Command::commitCommand();
}
else {
Gui::Command::abortCommand();
}
Gui::Command::commitCommand();
}
bool CmdTechDrawExtensionCreateLengthArc::isActive()
@@ -2329,6 +2362,51 @@ bool CmdTechDrawExtensionCustomizeFormat::isActive()
return (havePage && haveView);
}
DrawViewDimension* TechDrawGui::makeArcLengthDimension(const ReferenceEntry& ref)
{
DrawViewDimension* dim = nullptr;
auto* dvp = static_cast<DrawViewPart*>(ref.getObject());
int geoId = DrawUtil::getIndexFromName(ref.getSubName());
BaseGeomPtr geom = dvp->getGeomByIndex(geoId);
// 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() / dvp->getScale();
Base::Vector3d startPt = edge->getStartPoint();
Base::Vector3d endPt = edge->getEndPoint();
startPt.y = -startPt.y;
endPt.y = -endPt.y;
std::stringstream startName, endName, formatSpec;
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;
}
namespace TechDrawGui {
//===========================================================================
// internal helper routines
@@ -2387,7 +2465,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 +2475,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<App::DocumentObject*> objs;
std::vector<std::string> 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<TechDraw::DrawViewDimension*>(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<TechDraw::DrawViewDimension*>(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();

View File

@@ -0,0 +1,41 @@
/***************************************************************************
* 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
#include <Mod/TechDraw/TechDrawGlobal.h>
namespace TechDraw
{
class ReferenceEntry;
class DrawViewDimension;
}
namespace TechDrawGui {
TechDraw::DrawViewDimension* makeArcLengthDimension(const TechDraw::ReferenceEntry& ref);
std::vector<TechDraw::DrawViewDimension*> makeObliqueChainDimension(std::vector<TechDraw::ReferenceEntry> refs);
std::vector<TechDraw::DrawViewDimension*> makeObliqueCoordDimension(std::vector<TechDraw::ReferenceEntry> refs);
}
#endif // TECHDRAWGUI_CommandExtensionDims_H

View File

@@ -116,7 +116,7 @@ DimensionGeometryType TechDraw::validateDimSelection(
StringVector subNames;
TechDraw::DrawViewPart* dvpSave(nullptr);
for (auto& ref : references) {
TechDraw::DrawViewPart* dvp = dynamic_cast<TechDraw::DrawViewPart*>(ref.getObject());
auto* dvp = dynamic_cast<TechDraw::DrawViewPart*>(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<TechDraw::DrawViewPart*>(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)

View File

@@ -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,

View File

@@ -524,9 +524,9 @@ Multiplier of 'Font Size'</string>
<item row="9" column="2">
<widget class="Gui::PrefDoubleSpinBox" name="pdsbGapISO">
<property name="toolTip">
<string>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.</string>
<string>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.</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@@ -545,8 +545,8 @@ Normally, no gap is used. If using a gap, the recommended value 8.</string>
<item row="10" column="2">
<widget class="Gui::PrefDoubleSpinBox" name="pdsbGapASME">
<property name="toolTip">
<string>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.</string>
<string>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.</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@@ -618,6 +618,56 @@ Normally, no gap is used. If a gap is used, the recommended value is 6.</string>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Tools</string>
</property>
<layout class="QGridLayout" name="gridLayout_general">
<item row="0" column="0">
<widget class="QLabel" name="dimensioningLabel">
<property name="text">
<string>Dimensioning tools:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="dimensioningMode">
<property name="toolTip">
<string>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.</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="radiusDiameterLabel">
<property name="text">
<string>Dimension tool diameter/radius mode:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="radiusDiameterMode">
<property name="toolTip">
<string>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.</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">

View File

@@ -25,6 +25,7 @@
#include "PreCompiled.h"
#include <Base/Tools.h>
#include <App/Application.h>
#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<int>::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);
}
/**

View File

@@ -45,6 +45,7 @@ protected:
void saveSettings() override;
void loadSettings() override;
void changeEvent(QEvent *e) override;
void dimensioningModeChanged(int index);
int prefArrowStyle() const;

View File

@@ -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(); }
@@ -755,13 +758,27 @@ void MDIViewPage::sceneSelectionChanged()
std::vector<Gui::SelectionObject> treeSel = Gui::Selection().getSelectionEx();
QList<QGraphicsItem*> 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 +788,48 @@ void MDIViewPage::setTreeToSceneSelect()
bool saveBlock = blockSelection(true);// block selectionChanged signal from Tree/Observer
blockSceneSelection(true);
Gui::Selection().clearSelection();
QList<QGraphicsItem*> sceneSel = m_qgSceneSelected;
for (QList<QGraphicsItem*>::iterator it = sceneSel.begin(); it != sceneSel.end(); ++it) {
QGIView* itemView = dynamic_cast<QGIView*>(*it);
for (auto* scene : m_qgSceneSelected) {
auto* itemView = dynamic_cast<QGIView*>(scene);
if (!itemView) {
QGIEdge* edge = dynamic_cast<QGIEdge*>(*it);
if (edge) {
QGraphicsItem* parent = edge->parentItem();
if (!parent) {
continue;
}
QGIView* viewItem = dynamic_cast<QGIView*>(parent);
if (!viewItem) {
continue;
}
TechDraw::DrawView* viewObj = viewItem->getViewObject();
std::stringstream ss;
ss << "Edge" << edge->getProjIndex();
//bool accepted =
static_cast<void>(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<QGIView*>(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<QGIVertex*>(*it);
if (vert) {
QGraphicsItem* parent = vert->parentItem();
if (!parent) {
continue;
}
auto* edge = dynamic_cast<QGIEdge*>(scene);
auto* vert = dynamic_cast<QGIVertex*>(scene);
auto* face = dynamic_cast<QGIFace*>(scene);
if (edge || vert || face) {
const char* ssn = getSceneSubName(scene).c_str();
QGIView* viewItem = dynamic_cast<QGIView*>(parent);
if (!viewItem) {
continue;
}
TechDraw::DrawView* viewObj = viewItem->getViewObject();
std::stringstream ss;
ss << "Vertex" << vert->getProjIndex();
//bool accepted =
static_cast<void>(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<QGIFace*>(*it);
if (face) {
QGraphicsItem* parent = face->parentItem();
if (!parent) {
continue;
}
QGIView* viewItem = dynamic_cast<QGIView*>(parent);
if (!viewItem) {
continue;
}
TechDraw::DrawView* viewObj = viewItem->getViewObject();
std::stringstream ss;
ss << "Face" << face->getProjIndex();
//bool accepted =
static_cast<void>(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<QGIDatumLabel*>(*it);
if (dimLabel) {
QGraphicsItem* dimParent = dimLabel->QGraphicsItem::parentItem();
if (!dimParent) {
continue;
}
QGIView* dimItem = dynamic_cast<QGIView*>(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<QGIDatumLabel*>(scene) || dynamic_cast<QGMText*>(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<void>(Gui::Selection().addSelection(dimObj->getDocument()->getName(),
dimObj->getNameInDocument()));
}
QGMText* mText = dynamic_cast<QGMText*>(*it);
if (mText) {
QGraphicsItem* textParent = mText->QGraphicsItem::parentItem();
if (!textParent) {
continue;
}
QGIView* parent = dynamic_cast<QGIView*>(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<void>(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 +838,138 @@ void MDIViewPage::setTreeToSceneSelect()
blockSelection(saveBlock);
}
std::string MDIViewPage::getSceneSubName(QGraphicsItem* scene)
{
auto* edge = dynamic_cast<QGIEdge*>(scene);
auto* vert = dynamic_cast<QGIVertex*>(scene);
auto* face = dynamic_cast<QGIFace*>(scene);
if (edge || vert || face) {
auto* viewItem = dynamic_cast<QGIView*>(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<Gui::SelectionObject> treeSel)
{
auto* itemView = dynamic_cast<QGIView*>(sn);
if (!itemView) {
auto* parent = dynamic_cast<QGIView*>(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<QGIEdge*>(sn) || dynamic_cast<QGIVertex*>(sn) || dynamic_cast<QGIFace*>(sn)) {
sub_name = getSceneSubName(sn);
}
else if (dynamic_cast<QGIDatumLabel*>(sn) || dynamic_cast<QGMText*>(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<QGraphicsItem*> 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<QGIView*>(sn);
if (!itemView) {
auto* parent = dynamic_cast<QGIView*>(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<QGIEdge*>(sn) || dynamic_cast<QGIVertex*>(sn) || dynamic_cast<QGIFace*>(sn)) {
sub_name = getSceneSubName(sn);
}
else if (dynamic_cast<QGIDatumLabel*>(sn) || dynamic_cast<QGMText*>(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<Gui::SelectionObject> treeSel,
QList<QGraphicsItem*> sceneSel)
{
@@ -1020,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<QGIDatumLabel*>(scene);
if (dl) {
dl->setSelectability(val);
}
}
}
// ----------------------------------------------------------------------------
void MDIViewPagePy::init_type()

View File

@@ -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();
@@ -127,6 +130,9 @@ protected:
void onDeleteObject(const App::DocumentObject& obj);
bool compareSelections(std::vector<Gui::SelectionObject> treeSel, QList<QGraphicsItem*> sceneSel);
void addSceneToTreeSel(QGraphicsItem* scene, std::vector<Gui::SelectionObject> treeSel);
void removeSelFromTreeSel(QList<QGraphicsItem*> sceneSel, Gui::SelectionObject& sel);
std::string getSceneSubName(QGraphicsItem* scene);
void setTreeToSceneSelect();
void sceneSelectionManager();
@@ -144,6 +150,7 @@ private:
std::string m_objectName;
std::string m_documentName;
bool isSelectionBlocked;
bool isContextualMenuEnabled;
QPointer<QGSPage> m_scene;
QString m_currentPath;

View File

@@ -33,6 +33,7 @@
#include <App/Material.h>
#include <Base/Console.h>
#include <Base/Parameter.h>
#include <Gui/Selection.h>
#include <Mod/TechDraw/App/Preferences.h>
#include <Mod/TechDraw/App/LineGenerator.h>
@@ -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()

View File

@@ -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)
{
@@ -717,9 +723,9 @@ void QGIViewDimension::draw()
return;
}
TechDraw::DrawViewDimension* dim = dynamic_cast<TechDraw::DrawViewDimension*>(getViewObject());
auto* dim = dynamic_cast<TechDraw::DrawViewDimension*>(getViewObject());
if (!dim ||//nothing to draw, don't try
!dim->isDerivedFrom(TechDraw::DrawViewDimension::getClassTypeId())
!dim->isDerivedFrom<TechDraw::DrawViewDimension>()
|| !dim->has2DReferences()) {
datumLabel->hide();
hide();
@@ -767,6 +773,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);
}
@@ -1255,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};
@@ -1275,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<ViewProviderDimension*>(getViewProvider(getViewObject()));
auto arrowSize = vp->Arrowsize.getValue();
arrow->setSize(arrowSize);
@@ -1403,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);
@@ -1423,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,
@@ -2085,6 +2095,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;
bool forcePointStyle = true;
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 lineAngle = jointDirection.Angle();
double jointPositions = jointDirection.Length();
drawDimensionLine(areaPath, centerPoint, lineAngle, 0.0, jointPositions, labelRectangle, 1, standardStyle, flipArrow, forcePointStyle);
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, forcePointStyle);
}
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, forcePointStyle);
}
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 +2589,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()));

View File

@@ -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,
@@ -261,10 +262,14 @@ protected:
double endAngle, double startRotation, const Base::BoundBox2d &labelRectangle,
double centerOverhang, int standardStyle, int renderExtent, bool flipArrow) const;
void drawAreaExecutive(const Base::Vector2d &centerPoint, 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;

View File

@@ -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<TechDrawHandler>(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); }

View File

@@ -71,6 +71,7 @@ class QGILeaderLine;
class QGIRichAnno;
class QGITile;
class QGVNavStyle;
class TechDrawHandler;
class TechDrawGuiExport QGVPage: public QGraphicsView
{
@@ -101,6 +102,10 @@ public:
void showGrid(bool state) { m_showGrid = state; }
void updateViewport() { viewport()->repaint(); }
void activateHandler(TechDrawHandler* newHandler);
void deactivateHandler();
bool isHandlerActive() { return toolHandler != nullptr; }
bool isBalloonPlacing() const { return balloonPlacing; }
void setBalloonPlacing(bool isPlacing) { balloonPlacing = isPlacing; }
@@ -196,6 +201,8 @@ private:
MDIViewPage* m_parentMDI;
QContextMenuEvent* m_saveContextEvent;
std::unique_ptr<TechDrawHandler> toolHandler;
};
}// namespace TechDrawGui

View File

@@ -86,10 +86,12 @@
<file>icons/square.svg</file>
<file>icons/TechDraw_3PtAngleDimension.svg</file>
<file>icons/TechDraw_AngleDimension.svg</file>
<file>icons/TechDraw_AreaDimension.svg</file>
<file>icons/TechDraw_Balloon.svg</file>
<file>icons/TechDraw_CameraOrientation.svg</file>
<file>icons/TechDraw_DiameterDimension.svg</file>
<file>icons/TechDraw_Dimension.svg</file>
<file>icons/TechDraw_Dimension_Pointer.svg</file>
<file>icons/TechDraw_DimensionRepair.svg</file>
<file>icons/TechDraw_ExtensionAreaAnnotation.svg</file>
<file>icons/TechDraw_ExtensionArcLengthAnnotation.svg</file>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.5 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,146 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
height="64"
width="64"
id="svg12"
sodipodi:docname="TechDraw_Dimension_Pointer.svg"
inkscape:version="1.1-beta1 (77e7b44db3, 2021-03-28)"
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">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="14.59375"
inkscape:cx="29.910064"
inkscape:cy="29.498929"
inkscape:window-width="3840"
inkscape:window-height="1571"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg12"
objecttolerance="10.0"
gridtolerance="10.0"
guidetolerance="10.0"
inkscape:pageshadow="0"
showgrid="false" />
<defs
id="defs16">
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3026"
id="linearGradient927"
x1="16.969255"
y1="39.85923"
x2="58.005249"
y2="39.85923"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3026"
inkscape:collect="always">
<stop
id="stop3028"
offset="0"
style="stop-color:#c4a000;stop-opacity:1" />
<stop
id="stop3030"
offset="1"
style="stop-color:#fce94f;stop-opacity:1" />
</linearGradient>
</defs>
<g
id="crosshair"
style="stroke:#ffffff;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter"
transform="translate(-0.4111349)">
<path
d="m 16,3 v 9 m 0,8 v 9 M 3,16 h 9 m 8,0 h 9"
id="path9" />
</g>
<g
id="g1123"
transform="matrix(0.92503381,0,0,0.92503381,6.1433162,7.4809763)">
<path
style="fill:none;stroke:#302b00;stroke-width:4;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:100;stroke-dasharray:none;stroke-dashoffset:8.71;stroke-opacity:1"
id="path3"
sodipodi:type="arc"
sodipodi:cx="42.62447"
sodipodi:cy="32.611259"
sodipodi:rx="16.283468"
sodipodi:ry="16.283468"
sodipodi:start="5.3462224"
sodipodi:end="0.51990659"
sodipodi:arc-type="arc"
sodipodi:open="true"
transform="rotate(12.779233)"
d="m 52.268157,19.490641 a 16.283468,16.283468 0 0 1 4.488175,21.21023" />
<path
style="fill:none;stroke:#302b00;stroke-width:8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:100;stroke-dasharray:none;stroke-dashoffset:8.71;stroke-opacity:1"
d="M 54.090138,23.080858 18.968981,44.576119 56.005249,56.637604"
id="path1" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:100;stroke-dasharray:none;stroke-dashoffset:8.71;stroke-opacity:1"
id="path3-6"
sodipodi:type="arc"
sodipodi:cx="42.62447"
sodipodi:cy="32.658588"
sodipodi:rx="16.283468"
sodipodi:ry="16.283468"
sodipodi:start="5.2511532"
sodipodi:end="0.51990659"
sodipodi:arc-type="arc"
sodipodi:open="true"
transform="rotate(12.779233)"
d="M 50.979121,18.681781 A 16.283468,16.283468 0 0 1 56.756332,40.7482" />
<path
style="fill:none;stroke:url(#linearGradient927);stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:100;stroke-dasharray:none;stroke-dashoffset:8.71;stroke-opacity:1"
d="M 54.090138,23.080858 18.968981,44.576119 56.005249,56.637604"
id="path1-3" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:100;stroke-dasharray:none;stroke-dashoffset:8.71;stroke-opacity:1"
d="M 54.03712,22.151886 18.920565,43.727975 55.94574,55.594886"
id="path2"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;stroke:#302b00;stroke-width:4;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:100;stroke-dasharray:none;stroke-dashoffset:8.71;stroke-opacity:1"
d="M 59.334145,21.127535 49.123924,6.3035436"
id="path4" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:100;stroke-dasharray:none;stroke-dashoffset:8.71;stroke-opacity:1"
d="M 59.334145,21.127535 49.123924,6.3035439"
id="path4-7" />
<path
style="fill:none;stroke:#302b00;stroke-width:4;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:100;stroke-dasharray:none;stroke-dashoffset:8.71;stroke-opacity:1"
d="M 14.780546,48.06322 4.5703249,33.239228"
id="path4-2" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:100;stroke-dasharray:none;stroke-dashoffset:8.71;stroke-opacity:1"
d="M 14.780546,48.06322 4.5703248,33.239228"
id="path4-7-9" />
<path
style="fill:none;stroke:#302b00;stroke-width:4;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:100;stroke-dasharray:none;stroke-dashoffset:8.71;stroke-opacity:1"
d="M 39.969325,13.041079 15.273234,28.142693"
id="path6" />
<path
style="fill:#fce94f;fill-opacity:1;stroke:#302b00;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:100;stroke-dasharray:none;stroke-dashoffset:8.71;stroke-opacity:1"
d="m 38.468308,8.9727464 c 9.40717,-0.9537682 9.40717,-0.9537682 9.40717,-0.9537682 l -4.952425,8.2021028 z"
id="path5" />
<path
style="fill:#fce94f;fill-opacity:1;stroke:#302b00;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:100;stroke-dasharray:none;stroke-dashoffset:8.71;stroke-opacity:1"
d="M 16.774251,32.211025 C 7.3670811,33.164794 7.3670811,33.164794 7.3670811,33.164794 L 12.319506,24.96269 Z"
id="path5-1" />
<path
style="fill:none;stroke:#fce94f;stroke-width:2.00001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:100;stroke-dasharray:none;stroke-dashoffset:8.71;stroke-opacity:1"
d="M 40.879356,12.483498 14.021683,28.964296"
id="path6-2" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@@ -0,0 +1,131 @@
/***************************************************************************
* Copyright (c) 2024 Pierre-Louis Boyer <development@ondsel.com> *
* *
* 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 <cmath>
#include <QGuiApplication>
#include <QPainter>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QTimer>
#include <Inventor/events/SoKeyboardEvent.h>
#endif // #ifndef _PreComp_
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Gui/Application.h>
#include <Gui/CommandT.h>
#include <Gui/MainWindow.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
#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)
{
auto* mdi = dynamic_cast<MDIViewPage*>(Gui::getMainWindow()->activeWindow());
if (!mdi) {
return;
}
mdi->enableContextualMenu(false);
viewPage = vp;
if (!Gui::ToolHandler::activate()) {
viewPage->deactivateHandler();
}
}
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<MDIViewPage*>(Gui::getMainWindow()->activeWindow());
if (!mdi) {
return;
}
mdi->enableContextualMenu(true);
});
}
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();
}
}
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
if (event->button() == Qt::RightButton) {
quit();
event->accept();
}
}
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();
}

View File

@@ -0,0 +1,67 @@
/***************************************************************************
* Copyright (c) 2024 Pierre-Louis Boyer <development@ondsel.com> *
* *
* 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 <Gui/ToolHandler.h>
#include <Mod/TechDraw/TechDrawGlobal.h>
namespace TechDrawGui
{
class QGVPage;
class TechDrawGuiExport TechDrawHandler : public Gui::ToolHandler
{
public:
TechDrawHandler();
virtual ~TechDrawHandler();
void activate(QGVPage* vPage);
void deactivate() override;
void quit() override;
virtual void mouseMoveEvent(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);
TechDraw::DrawPage* getPage();
protected:
QWidget* getCursorWidget() override;
void setWidgetCursor(QCursor cursor) override;
QGVPage* viewPage;
};
} // namespace TechDrawGui
#endif // TechDrawGUI_TechDrawHandler_H

View File

@@ -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";
}
}

View File

@@ -28,6 +28,7 @@
#endif
#include "Workbench.h"
#include <App/Application.h>
#include <Gui/MenuManager.h>
#include <Gui/ToolBarManager.h>
@@ -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";
@@ -89,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.
@@ -305,14 +308,30 @@ 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";
*dims << "TechDraw_ExtentGroup";
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_AreaDimension";
*dims << "TechDraw_ExtentGroup";
}
// TechDraw_LinkDimension is DEPRECATED. Use TechDraw_DimensionRepair instead.
// *dims << "TechDraw_LinkDimension";
*dims << "TechDraw_Balloon";
@@ -329,8 +348,10 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
*extattribs << "TechDraw_ExtensionPositionSectionView";
*extattribs << "TechDraw_ExtensionPosChainDimensionGroup";
*extattribs << "TechDraw_ExtensionCascadeDimensionGroup";
*extattribs << "TechDraw_ExtensionAreaAnnotation";
*extattribs << "TechDraw_ExtensionArcLengthAnnotation";
if (separatedTools) {
*extattribs << "TechDraw_ExtensionAreaAnnotation";
*extattribs << "TechDraw_ExtensionArcLengthAnnotation";
}
*extattribs << "TechDraw_ExtensionCustomizeFormat";
Gui::ToolBarItem* extcenter = new Gui::ToolBarItem(root);
@@ -344,10 +365,12 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
Gui::ToolBarItem* extdimensions = new Gui::ToolBarItem(root);
extdimensions->setCommand("TechDraw Extend Dimensions");
*extdimensions << "TechDraw_ExtensionCreateChainDimensionGroup";
*extdimensions << "TechDraw_ExtensionCreateCoordDimensionGroup";
*extdimensions << "TechDraw_ExtensionChamferDimensionGroup";
*extdimensions << "TechDraw_ExtensionCreateLengthArc";
if (separatedTools) {
*extdimensions << "TechDraw_ExtensionCreateChainDimensionGroup";
*extdimensions << "TechDraw_ExtensionCreateCoordDimensionGroup";
*extdimensions << "TechDraw_ExtensionChamferDimensionGroup";
*extdimensions << "TechDraw_ExtensionCreateLengthArc";
}
*extdimensions << "TechDraw_ExtensionInsertPrefixGroup";
*extdimensions << "TechDraw_ExtensionIncreaseDecreaseGroup";
@@ -406,6 +429,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";