From 0b191c477bd35263ee33f45bf75acfdbc57c926b Mon Sep 17 00:00:00 2001 From: wandererfan Date: Tue, 19 Sep 2023 08:41:22 -0400 Subject: [PATCH] [TD]initial implementation of cosmetic cicle command --- src/Mod/TechDraw/App/DrawViewPartPy.xml | 10 + src/Mod/TechDraw/App/DrawViewPartPyImp.cpp | 96 +++++- src/Mod/TechDraw/App/Geometry.cpp | 2 +- src/Mod/TechDraw/App/Geometry.h | 17 + src/Mod/TechDraw/Gui/CMakeLists.txt | 4 + src/Mod/TechDraw/Gui/CommandAnnotate.cpp | 150 +++++++++ src/Mod/TechDraw/Gui/Resources/TechDraw.qrc | 1 + .../icons/actions/TechDraw_CosmeticCircle.svg | 179 +++++++++++ src/Mod/TechDraw/Gui/TaskCosmeticCircle.cpp | 304 ++++++++++++++++++ src/Mod/TechDraw/Gui/TaskCosmeticCircle.h | 128 ++++++++ src/Mod/TechDraw/Gui/TaskCosmeticCircle.ui | 252 +++++++++++++++ src/Mod/TechDraw/Gui/Workbench.cpp | 3 + 12 files changed, 1141 insertions(+), 5 deletions(-) create mode 100644 src/Mod/TechDraw/Gui/Resources/icons/actions/TechDraw_CosmeticCircle.svg create mode 100644 src/Mod/TechDraw/Gui/TaskCosmeticCircle.cpp create mode 100644 src/Mod/TechDraw/Gui/TaskCosmeticCircle.h create mode 100644 src/Mod/TechDraw/Gui/TaskCosmeticCircle.ui diff --git a/src/Mod/TechDraw/App/DrawViewPartPy.xml b/src/Mod/TechDraw/App/DrawViewPartPy.xml index e0fd128a37..7b916213f8 100644 --- a/src/Mod/TechDraw/App/DrawViewPartPy.xml +++ b/src/Mod/TechDraw/App/DrawViewPartPy.xml @@ -73,6 +73,16 @@ tag = makeCosmeticCircleArc(center, radius, start, end) - add a CosmeticEdge at center with radius radius(View coordinates) from start angle to end angle. Returns tag of new CosmeticEdge. + + + tag = makeCosmeticCircle3d(center, radius) - add a CosmeticEdge at center (3d point) with radius. Returns tag of new CosmeticEdge. + + + + + tag = makeCosmeticCircleArc3d(center, radius, start, end) - add a CosmeticEdge at center (3d point) with radius from start angle to end angle. Returns tag of new CosmeticEdge. + + ce = getCosmeticEdge(id) - returns CosmeticEdge with unique id. diff --git a/src/Mod/TechDraw/App/DrawViewPartPyImp.cpp b/src/Mod/TechDraw/App/DrawViewPartPyImp.cpp index c1cefa3b7f..90c16212da 100644 --- a/src/Mod/TechDraw/App/DrawViewPartPyImp.cpp +++ b/src/Mod/TechDraw/App/DrawViewPartPyImp.cpp @@ -388,9 +388,9 @@ PyObject* DrawViewPartPy::makeCosmeticCircle(PyObject *args) } DrawViewPart* dvp = getDrawViewPartPtr(); - Base::Vector3d pnt1 = DrawUtil::invertY(static_cast(pPnt1)->value()); + Base::Vector3d pnt1 = static_cast(pPnt1)->value(); TechDraw::BaseGeomPtr bg = std::make_shared (pnt1, radius); - std::string newTag = dvp->addCosmeticEdge(bg); + std::string newTag = dvp->addCosmeticEdge(bg->inverted()); TechDraw::CosmeticEdge* ce = dvp->getCosmeticEdge(newTag); if (ce) { ce->permaRadius = radius; @@ -428,9 +428,97 @@ PyObject* DrawViewPartPy::makeCosmeticCircleArc(PyObject *args) //from here on is almost duplicate of makeCosmeticCircle DrawViewPart* dvp = getDrawViewPartPtr(); - Base::Vector3d pnt1 = DrawUtil::invertY(static_cast(pPnt1)->value()); + Base::Vector3d pnt1 = static_cast(pPnt1)->value(); TechDraw::BaseGeomPtr bg = std::make_shared (pnt1, radius, angle1, angle2); - std::string newTag = dvp->addCosmeticEdge(bg); + std::string newTag = dvp->addCosmeticEdge(bg->inverted()); + TechDraw::CosmeticEdge* ce = dvp->getCosmeticEdge(newTag); + if (ce) { + ce->permaRadius = radius; + ce->m_format.m_style = style; + ce->m_format.m_weight = weight; + if (!pColor) + ce->m_format.m_color = defCol; + else + ce->m_format.m_color = DrawUtil::pyTupleToColor(pColor); + } + else { + PyErr_SetString(PyExc_RuntimeError, "DVPPI:makeCosmeticCircleArc - arc creation failed"); + return nullptr; + } + + //int link = + dvp->add1CEToGE(newTag); + dvp->requestPaint(); + + return PyUnicode_FromString(newTag.c_str()); //return tag for new CE +} + +PyObject* DrawViewPartPy::makeCosmeticCircle3d(PyObject *args) +{ + PyObject* pPnt1 = nullptr; + double radius = 5.0; + int style = LineFormat::getDefEdgeStyle(); + double weight = LineFormat::getDefEdgeWidth(); + App::Color defCol = LineFormat::getDefEdgeColor(); + PyObject* pColor = nullptr; + + if (!PyArg_ParseTuple(args, "O!d|idO!", &(Base::VectorPy::Type), &pPnt1, + &radius, + &style, &weight, + &PyTuple_Type, &pColor)) { + return nullptr; + } + + DrawViewPart* dvp = getDrawViewPartPtr(); + Base::Vector3d pnt1 = static_cast(pPnt1)->value(); + // center, project and invert the 3d point + Base::Vector3d centroid = dvp->getOriginalCentroid(); + pnt1 = DrawUtil::invertY(dvp->projectPoint(pnt1 - centroid)); + TechDraw::BaseGeomPtr bg = std::make_shared (pnt1, radius); + std::string newTag = dvp->addCosmeticEdge(bg->inverted()); + TechDraw::CosmeticEdge* ce = dvp->getCosmeticEdge(newTag); + if (ce) { + ce->permaRadius = radius; + ce->m_format.m_style = style; + ce->m_format.m_weight = weight; + ce->m_format.m_color = pColor ? DrawUtil::pyTupleToColor(pColor) : defCol; + } + else { + PyErr_SetString(PyExc_RuntimeError, "DVPPI:makeCosmeticCircle - circle creation failed"); + return nullptr; + } + //int link = + dvp->add1CEToGE(newTag); + dvp->requestPaint(); + + return PyUnicode_FromString(newTag.c_str()); //return tag for new CE +} + +PyObject* DrawViewPartPy::makeCosmeticCircleArc3d(PyObject *args) +{ + PyObject* pPnt1 = nullptr; + double radius = 5.0; + double angle1 = 0.0; + double angle2 = 360.0; + int style = LineFormat::getDefEdgeStyle(); + double weight = LineFormat::getDefEdgeWidth(); + App::Color defCol = LineFormat::getDefEdgeColor(); + PyObject* pColor = nullptr; + + if (!PyArg_ParseTuple(args, "O!ddd|idO!", &(Base::VectorPy::Type), &pPnt1, + &radius, &angle1, &angle2, + &style, &weight, &PyTuple_Type, &pColor)) { + return nullptr; + } + + //from here on is almost duplicate of makeCosmeticCircle + DrawViewPart* dvp = getDrawViewPartPtr(); + Base::Vector3d pnt1 = static_cast(pPnt1)->value(); + // center, project and invert the 3d point + Base::Vector3d centroid = dvp->getOriginalCentroid(); + pnt1 = DrawUtil::invertY(dvp->projectPoint(pnt1 - centroid)); + TechDraw::BaseGeomPtr bg = std::make_shared (pnt1, radius, angle1, angle2); + std::string newTag = dvp->addCosmeticEdge(bg->inverted()); TechDraw::CosmeticEdge* ce = dvp->getCosmeticEdge(newTag); if (ce) { ce->permaRadius = radius; diff --git a/src/Mod/TechDraw/App/Geometry.cpp b/src/Mod/TechDraw/App/Geometry.cpp index b0c0d300ae..2a7d2e8138 100644 --- a/src/Mod/TechDraw/App/Geometry.cpp +++ b/src/Mod/TechDraw/App/Geometry.cpp @@ -423,7 +423,7 @@ bool BaseGeom::closed() // return a BaseGeom similar to this, but inverted with respect to Y axis BaseGeomPtr BaseGeom::inverted() { - Base::Console().Message("BG::inverted()\n"); +// Base::Console().Message("BG::inverted()\n"); TopoDS_Shape invertedShape = ShapeUtils::invertGeometry(occEdge); TopoDS_Edge invertedEdge = TopoDS::Edge(invertedShape); return baseFactory(invertedEdge); diff --git a/src/Mod/TechDraw/App/Geometry.h b/src/Mod/TechDraw/App/Geometry.h index ff13526280..504f722d7e 100644 --- a/src/Mod/TechDraw/App/Geometry.h +++ b/src/Mod/TechDraw/App/Geometry.h @@ -147,6 +147,11 @@ class TechDrawExport BaseGeom : public std::enable_shared_from_this void setCosmeticTag(std::string t) { cosmeticTag = t; } Part::TopoShape asTopoShape(double scale); + virtual double getStartAngle() { return 0.0; } + virtual double getEndAngle() { return 0.0; } + virtual bool clockwiseAngle() { return false; } + virtual void clockwiseAngle(bool direction) { (void) direction; } + protected: void createNewTag(); @@ -217,6 +222,10 @@ class TechDrawExport AOE: public Ellipse ~AOE() override = default; public: + double getStartAngle() override { return startAngle; } + double getEndAngle() override { return endAngle; } + bool clockwiseAngle() override { return cw; } + void clockwiseAngle(bool direction) override { cw = direction; } Base::Vector3d startPnt; //TODO: The points are used for drawing, the angles for bounding box calcs - seems redundant Base::Vector3d endPnt; Base::Vector3d midPnt; @@ -241,6 +250,11 @@ class TechDrawExport AOC: public Circle ~AOC() override = default; public: + double getStartAngle() override { return startAngle; } + double getEndAngle() override { return endAngle; } + bool clockwiseAngle() override { return cw; } + void clockwiseAngle(bool direction) override { cw = direction; } + std::string toString() const override; void Save(Base::Writer& w) const override; void Restore(Base::XMLReader& r) override; @@ -284,6 +298,9 @@ class TechDrawExport BSpline: public BaseGeom ~BSpline() override = default; public: + double getStartAngle() override { return startAngle; } + double getEndAngle() override { return endAngle; } + Base::Vector3d startPnt; Base::Vector3d endPnt; Base::Vector3d midPnt; diff --git a/src/Mod/TechDraw/Gui/CMakeLists.txt b/src/Mod/TechDraw/Gui/CMakeLists.txt index fb93a034ba..8329fa4690 100644 --- a/src/Mod/TechDraw/Gui/CMakeLists.txt +++ b/src/Mod/TechDraw/Gui/CMakeLists.txt @@ -87,6 +87,7 @@ set(TechDrawGui_UIC_SRCS TaskProjection.ui TaskComplexSection.ui TaskDimRepair.ui + TaskCosmeticCircle.ui ) @@ -228,6 +229,9 @@ SET(TechDrawGui_SRCS TaskDimRepair.cpp TaskDimRepair.h TaskDimRepair.ui + TaskCosmeticCircle.cpp + TaskCosmeticCircle.h + TaskCosmeticCircle.ui Widgets/CompassDialWidget.cpp Widgets/CompassDialWidget.h Widgets/CompassWidget.cpp diff --git a/src/Mod/TechDraw/Gui/CommandAnnotate.cpp b/src/Mod/TechDraw/Gui/CommandAnnotate.cpp index b3ed6e0ea3..ef3b6cdcba 100644 --- a/src/Mod/TechDraw/Gui/CommandAnnotate.cpp +++ b/src/Mod/TechDraw/Gui/CommandAnnotate.cpp @@ -57,6 +57,7 @@ #include "TaskRichAnno.h" #include "TaskSurfaceFinishSymbols.h" #include "TaskWeldingSymbol.h" +#include "TaskCosmeticCircle.h" #include "ViewProviderViewPart.h" @@ -73,6 +74,7 @@ void execCenterLine(Gui::Command* cmd); void exec2LineCenterLine(Gui::Command* cmd); void exec2PointCenterLine(Gui::Command* cmd); void execLine2Points(Gui::Command* cmd); +void execCosmeticCircle(Gui::Command* cmd); std::vector getSelectedSubElements(Gui::Command* cmd, TechDraw::DrawViewPart* &dvp, std::string subType = "Edge"); @@ -1110,6 +1112,153 @@ void execLine2Points(Gui::Command* cmd) is3d)); } +//=========================================================================== +// TechDraw_CosmeticCircle +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawCosmeticCircle) + +CmdTechDrawCosmeticCircle::CmdTechDrawCosmeticCircle() + : Command("TechDraw_CosmeticCircle") +{ + sAppModule = "TechDraw"; + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Add Cosmetic Circle"); + sToolTipText = sMenuText; + sWhatsThis = "TechDraw_CosmeticCircle"; + sStatusTip = sToolTipText; + sPixmap = "actions/TechDraw_CosmeticCircle"; +} + +void CmdTechDrawCosmeticCircle::activated(int iMsg) +{ + Q_UNUSED(iMsg); + + Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); + if (dlg) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Task In Progress"), + QObject::tr("Close active task dialog and try again.")); + return; + } + + execCosmeticCircle(this); + + updateActive(); + Gui::Selection().clearSelection(); +} + +bool CmdTechDrawCosmeticCircle::isActive() +{ + bool havePage = DrawGuiUtil::needPage(this); + bool haveView = DrawGuiUtil::needView(this, true); + return (havePage && haveView); +} + +void execCosmeticCircle(Gui::Command* cmd) +{ + TechDraw::DrawPage* page = DrawGuiUtil::findPage(cmd); + if (!page) { + return; + } + + std::vector selection = cmd->getSelection().getSelectionEx(); + TechDraw::DrawViewPart* baseFeat = nullptr; + std::vector subNames2D; + std::vector< std::pair > objs3D; + if (selection.empty()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong Selection"), + QObject::tr("Selection is empty.")); + return; + } + + for (auto& so: selection) { + if (so.getObject()->isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId())) { + baseFeat = static_cast (so.getObject()); + subNames2D = so.getSubNames(); + } else if (so.getObject()->isDerivedFrom(Part::Feature::getClassTypeId())) { + std::vector subNames3D = so.getSubNames(); + for (auto& sub3D: subNames3D) { + std::pair temp; + temp.first = static_cast(so.getObject()); + temp.second = sub3D; + objs3D.push_back(temp); + } + } else { + //garbage + } + } + + if (!baseFeat) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong Selection"), + QObject::tr("You must select a base View for the circle.")); + return; + } + + std::vector edgeNames; + std::vector vertexNames; + for (auto& s: subNames2D) { + std::string geomType = DrawUtil::getGeomTypeFromName(s); + if (geomType == "Vertex") { + vertexNames.push_back(s); + } else if (geomType == "Edge") { + edgeNames.push_back(s); + } + } + + //check if editing existing edge + if (!edgeNames.empty() && (edgeNames.size() == 1)) { + TechDraw::CosmeticEdge* ce = baseFeat->getCosmeticEdgeBySelection(edgeNames.front()); + if (!ce) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong Selection"), + QObject::tr("Selection is not a Cosmetic edge.")); + return; + } + Gui::Control().showDialog(new TaskDlgCosmeticCircle(baseFeat, + edgeNames.front())); + return; + } + + std::vector points; + std::vector is3d; + //get the 2D points + if (!vertexNames.empty()) { + for (auto& v2d: vertexNames) { + int idx = DrawUtil::getIndexFromName(v2d); + TechDraw::VertexPtr v = baseFeat->getProjVertexByIndex(idx); + if (v) { + points.push_back(v->point()); + is3d.push_back(false); + } + } + } + //get the 3D points + if (!objs3D.empty()) { + for (auto& o3D: objs3D) { + int idx = DrawUtil::getIndexFromName(o3D.second); + Part::TopoShape s = o3D.first->Shape.getShape(); + TopoDS_Vertex v = TopoDS::Vertex(s.getSubShape(TopAbs_VERTEX, idx)); + Base::Vector3d p = DrawUtil::vertex2Vector(v); + points.push_back(p); + is3d.push_back(true); + } + } + + if (points.empty()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong Selection"), + QObject::tr("Please select a center for the circle.")); + return; + } + + bool centerIs3d = false; + if (!is3d.empty()) { + centerIs3d = is3d.front(); + } + + Gui::Control().showDialog(new TaskDlgCosmeticCircle(baseFeat, + points.front(), + centerIs3d)); +} + //=========================================================================== // TechDraw_CosmeticEraser //=========================================================================== @@ -1500,6 +1649,7 @@ void CreateTechDrawCommandsAnnotate() rcCmdMgr.addCommand(new CmdTechDraw2LineCenterLine()); rcCmdMgr.addCommand(new CmdTechDraw2PointCenterLine()); rcCmdMgr.addCommand(new CmdTechDraw2PointCosmeticLine()); + rcCmdMgr.addCommand(new CmdTechDrawCosmeticCircle()); rcCmdMgr.addCommand(new CmdTechDrawAnnotation()); rcCmdMgr.addCommand(new CmdTechDrawCosmeticEraser()); rcCmdMgr.addCommand(new CmdTechDrawDecorateLine()); diff --git a/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc b/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc index 84bc48b256..e19c7dad52 100644 --- a/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc +++ b/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc @@ -54,6 +54,7 @@ icons/actions/TechDraw_WeldSymbol.svg icons/actions/TechDraw_SurfaceFinishSymbols.svg icons/actions/TechDraw_ComplexSection.svg + icons/actions/TechDraw_CosmeticCircle.svg icons/arrow-ccw.svg icons/arrow-cw.svg icons/arrow-down.svg diff --git a/src/Mod/TechDraw/Gui/Resources/icons/actions/TechDraw_CosmeticCircle.svg b/src/Mod/TechDraw/Gui/Resources/icons/actions/TechDraw_CosmeticCircle.svg new file mode 100644 index 0000000000..22efc682e8 --- /dev/null +++ b/src/Mod/TechDraw/Gui/Resources/icons/actions/TechDraw_CosmeticCircle.svg @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/src/Mod/TechDraw/Gui/TaskCosmeticCircle.cpp b/src/Mod/TechDraw/Gui/TaskCosmeticCircle.cpp new file mode 100644 index 0000000000..07df28f69d --- /dev/null +++ b/src/Mod/TechDraw/Gui/TaskCosmeticCircle.cpp @@ -0,0 +1,304 @@ +/*************************************************************************** + * Copyright (c) 2023 WandererFan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ui_TaskCosmeticCircle.h" +#include "TaskCosmeticCircle.h" + + +using namespace Gui; +using namespace TechDraw; +using namespace TechDrawGui; +using DU = DrawUtil; + +//ctor for edit +TaskCosmeticCircle::TaskCosmeticCircle(TechDraw::DrawViewPart* partFeat, + std::string circleName) : + ui(new Ui_TaskCosmeticCircle), + m_partFeat(partFeat), + m_circleName(circleName), + m_ce(nullptr), + m_saveCE(nullptr), + m_createMode(false) +{ + //existence of partFeat is checked in calling command + + m_ce = m_partFeat->getCosmeticEdgeBySelection(m_circleName); + if (!m_ce) { + Base::Console().Error("TaskCosmeticCircle - bad parameters. Can not proceed.\n"); + return; + } + + ui->setupUi(this); + + setUiEdit(); +} + +//ctor for creation +TaskCosmeticCircle::TaskCosmeticCircle(TechDraw::DrawViewPart* partFeat, + Base::Vector3d center, bool is3d) : + ui(new Ui_TaskCosmeticCircle), + m_partFeat(partFeat), + m_ce(nullptr), + m_saveCE(nullptr), + m_center(center), + m_createMode(true), + m_is3d(is3d) +{ + //existence of partFeat is checked in calling command + + ui->setupUi(this); + + setUiPrimary(); +} + +TaskCosmeticCircle::~TaskCosmeticCircle() +{ + if (m_saveCE) { + delete m_saveCE; + } +} + +void TaskCosmeticCircle::updateTask() +{ +// blockUpdate = true; + +// blockUpdate = false; +} + +void TaskCosmeticCircle::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + } +} + +void TaskCosmeticCircle::setUiPrimary() +{ + setWindowTitle(QObject::tr("Create Cosmetic Line")); +// Base::Console().Message("TCC::setUiPrimary() - m_center: %s is3d: %d\n", +// DU::formatVector(m_center).c_str(), m_is3d); + double rotDeg = m_partFeat->Rotation.getValue(); + double rotRad = rotDeg * M_PI / 180.0; + Base::Vector3d centroid = m_partFeat->getCurrentCentroid(); + Base::Vector3d p1; + if (m_is3d) { + // center, project and invert the 3d point + p1 = DrawUtil::invertY(m_partFeat->projectPoint(m_center - centroid)); + ui->rb2d1->setChecked(false); + ui->rb3d1->setChecked(true); + } else { + // invert, unscale and unrotate the selected 2d point + // shift by centroid? + p1 = DU::invertY(m_center) / m_partFeat->getScale(); + if (rotDeg != 0.0) { + // we always rotate around the origin. + p1.RotateZ(-rotRad); + } + ui->rb2d1->setChecked(true); + ui->rb3d1->setChecked(false); + } + + ui->qsbCenterX->setUnit(Base::Unit::Length); + ui->qsbCenterX->setValue(p1.x); + ui->qsbCenterY->setUnit(Base::Unit::Length); + ui->qsbCenterY->setValue(p1.y); + ui->qsbCenterY->setUnit(Base::Unit::Length); + ui->qsbCenterZ->setValue(p1.z); +} + +void TaskCosmeticCircle::setUiEdit() +{ + setWindowTitle(QObject::tr("Edit Cosmetic Line")); + + ui->rb2d1->setChecked(true); + ui->rb3d1->setChecked(false); + + Base::Vector3d p1 = DrawUtil::invertY(m_ce->permaStart); + ui->qsbCenterX->setValue(p1.x); + ui->qsbCenterY->setValue(p1.y); + ui->qsbCenterZ->setValue(p1.z); + + ui->qsbRadius->setValue(m_ce->permaRadius); + + double angleDeg = m_ce->m_geometry->getStartAngle() * 180.0 / M_PI; + ui->qsbStartAngle->setValue(angleDeg); + angleDeg = m_ce->m_geometry->getEndAngle() * 180.0 / M_PI; + ui->qsbEndAngle->setValue(angleDeg); +} + +//****************************************************************************** +void TaskCosmeticCircle::createCosmeticCircle(void) +{ +// Base::Console().Message("TCL::createCosmeticCircle()\n"); + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create Cosmetic Line")); + + double x = ui->qsbCenterX->value().getValue(); + double y = ui->qsbCenterY->value().getValue(); + double z = ui->qsbCenterZ->value().getValue(); + Base::Vector3d p0(x, y, z); + + TechDraw::BaseGeomPtr bg; + if (ui->qsbStartAngle->value().getValue() == 0.0 && + ui->qsbEndAngle->value().getValue() == 0.0) { + bg = std::make_shared (p0, ui->qsbRadius->value().getValue()); + } else { + bg = std::make_shared(p0, ui->qsbRadius->value().getValue(), + ui->qsbStartAngle->value().getValue(), + ui->qsbEndAngle->value().getValue()); + } + + // note cEdges are inverted when added to the dvp geometry, so we need to + // invert them here + m_tag = m_partFeat->addCosmeticEdge(bg->inverted()); + m_ce = m_partFeat->getCosmeticEdge(m_tag); + + Gui::Command::commitCommand(); +} + +void TaskCosmeticCircle::updateCosmeticCircle(void) +{ +// Base::Console().Message("TCL::updateCosmeticCircle()\n"); + double x = ui->qsbCenterX->value().getValue(); + double y = ui->qsbCenterY->value().getValue(); + double z = ui->qsbCenterZ->value().getValue(); + Base::Vector3d p0(x, y, z); + + //replace the geometry + m_ce->permaRadius = ui->qsbRadius->value().getValue(); + + TechDraw::BaseGeomPtr bg; + if (ui->qsbStartAngle->value().getValue() == 0.0 && + ui->qsbEndAngle->value().getValue() == 0.0) { + bg = std::make_shared (p0, m_ce->permaRadius); + } else { + bg = std::make_shared(p0, ui->qsbRadius->value().getValue(), + ui->qsbStartAngle->value().getValue(), + ui->qsbEndAngle->value().getValue()); + } + m_ce->m_geometry = bg->inverted(); + p0 = DU::invertY(p0); + m_ce->permaStart = p0; + m_ce->permaEnd = p0; +} + +//****************************************************************************** + +bool TaskCosmeticCircle::accept() +{ + if (m_createMode) { + createCosmeticCircle(); + m_partFeat->add1CEToGE(m_tag); + m_partFeat->refreshCEGeoms(); + m_partFeat->requestPaint(); + } else { + //update mode + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Update CosmeticCircle")); + updateCosmeticCircle(); + m_partFeat->refreshCEGeoms(); + m_partFeat->requestPaint(); + Gui::Command::updateActive(); + Gui::Command::commitCommand(); + } + + Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()"); + + return true; +} + +bool TaskCosmeticCircle::reject() +{ + //there's nothing to do. + Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()"); + return false; +} +//////////////////////////////////////////////////////////////////////////////// +TaskDlgCosmeticCircle::TaskDlgCosmeticCircle(TechDraw::DrawViewPart* partFeat, + Base::Vector3d point, + bool is3d) + : TaskDialog() +{ + widget = new TaskCosmeticCircle(partFeat, point, is3d); + taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("actions/TechDraw_CosmeticCircle"), + widget->windowTitle(), true, nullptr); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskDlgCosmeticCircle::TaskDlgCosmeticCircle(TechDraw::DrawViewPart* partFeat, + std::string circleName) + : TaskDialog() +{ + widget = new TaskCosmeticCircle(partFeat, circleName); + taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("actions/TechDraw_CosmeticCircle"), + widget->windowTitle(), true, nullptr); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskDlgCosmeticCircle::~TaskDlgCosmeticCircle() +{ +} + +void TaskDlgCosmeticCircle::update() +{ +// widget->updateTask(); +} + +//==== calls from the TaskView =============================================================== +void TaskDlgCosmeticCircle::open() +{ +} + +void TaskDlgCosmeticCircle::clicked(int) +{ +} + +bool TaskDlgCosmeticCircle::accept() +{ + widget->accept(); + return true; +} + +bool TaskDlgCosmeticCircle::reject() +{ + widget->reject(); + return true; +} + +#include + diff --git a/src/Mod/TechDraw/Gui/TaskCosmeticCircle.h b/src/Mod/TechDraw/Gui/TaskCosmeticCircle.h new file mode 100644 index 0000000000..12fc33ad8d --- /dev/null +++ b/src/Mod/TechDraw/Gui/TaskCosmeticCircle.h @@ -0,0 +1,128 @@ +/*************************************************************************** + * Copyright (c) 2023 WandererFan * + * * + * 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_TASKCOSMETICCIRCLE_H +#define TECHDRAWGUI_TASKCOSMETICCIRCLE_H + +#include +#include +#include +#include + + +namespace TechDraw +{ +class DrawPage; +class DrawView; +class DrawViewPart; +class CosmeticEdge; +class Face; +class LineFormat; +} + +namespace TechDrawGui +{ +class QGSPage; +class QGVPage; +class QGIView; +class QGIPrimPath; +class MDIViewPage; +class ViewProviderViewPart; +class Ui_TaskCosmeticCircle; + +class TaskCosmeticCircle : public QWidget +{ + Q_OBJECT + +public: + TaskCosmeticCircle(TechDraw::DrawViewPart* partFeat, + Base::Vector3d center, bool is3d); + TaskCosmeticCircle(TechDraw::DrawViewPart* partFeat, + std::string circleName); + ~TaskCosmeticCircle() override; + + virtual bool accept(); + virtual bool reject(); + void updateTask(); + +protected: + void changeEvent(QEvent *e) override; + + void setUiPrimary(); + void setUiEdit(); + + void createCosmeticCircle(); + void updateCosmeticCircle(); + +private: + std::unique_ptr ui; + + TechDraw::DrawViewPart* m_partFeat; + + std::string m_circleName; + TechDraw::CosmeticEdge* m_ce; + TechDraw::CosmeticEdge* m_saveCE; + Base::Vector3d m_center; + double m_radius; + bool m_createMode; + std::string m_tag; + bool m_is3d; +}; + +class TaskDlgCosmeticCircle : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskDlgCosmeticCircle(TechDraw::DrawViewPart* partFeat, + Base::Vector3d center, bool is3d); + TaskDlgCosmeticCircle(TechDraw::DrawViewPart* partFeat, + std::string circleName) +; ~TaskDlgCosmeticCircle() override; + +public: + /// is called the TaskView when the dialog is opened + void open() override; + /// is called by the framework if an button is clicked which has no accept or reject role + void clicked(int) override; + /// is called by the framework if the dialog is accepted (Ok) + bool accept() override; + /// is called by the framework if the dialog is rejected (Cancel) + bool reject() override; + /// is called by the framework if the user presses the help button + void helpRequested() override { return;} + bool isAllowedAlterDocument() const override + { return false; } + void update(); + +protected: + +private: + TaskCosmeticCircle* widget; + + Gui::TaskView::TaskBox* taskbox; +}; + +} //namespace TechDrawGui + +#endif // #ifndef TECHDRAWGUI_TASKCOSMETICCIRCLE_H + diff --git a/src/Mod/TechDraw/Gui/TaskCosmeticCircle.ui b/src/Mod/TechDraw/Gui/TaskCosmeticCircle.ui new file mode 100644 index 0000000000..12bde53ed7 --- /dev/null +++ b/src/Mod/TechDraw/Gui/TaskCosmeticCircle.ui @@ -0,0 +1,252 @@ + + + TechDrawGui::TaskCosmeticCircle + + + + 0 + 0 + 350 + 368 + + + + + 0 + 0 + + + + + 250 + 0 + + + + Cosmetic Circle + + + + + + + + View + + + + + + + false + + + false + + + Qt::NoFocus + + + false + + + + + + + + + + + Treat the center point as a 2d point within the parent View. Z coordinate is ignored. + + + 2d Point + + + true + + + true + + + + + + + Treat the center point as a 3d point and project it onto the parent View. + + + 3d Point + + + true + + + + + + + Circle Center + + + + + + + + + + + X: + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Y: + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Z: + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + Radius: + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 10.000000000000000 + + + + + + + + + + + Start Angle: + + + + + + + End angle (conventional) of arc in degrees. + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + End Angle: + + + + + + + Start angle (conventional) of arc in degrees. + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Arc of Circle + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Gui::QuantitySpinBox + QWidget +
Gui/QuantitySpinBox.h
+
+
+ + + + +
diff --git a/src/Mod/TechDraw/Gui/Workbench.cpp b/src/Mod/TechDraw/Gui/Workbench.cpp index 60d11b8105..75d3bc62b9 100644 --- a/src/Mod/TechDraw/Gui/Workbench.cpp +++ b/src/Mod/TechDraw/Gui/Workbench.cpp @@ -176,6 +176,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const *lines << "TechDraw_2LineCenterLine"; *lines << "TechDraw_2PointCenterLine"; *lines << "TechDraw_2PointCosmeticLine"; + *lines << "TechDraw_CosmeticCircle"; *lines << "Separator"; *lines << "TechDraw_DecorateLine"; *lines << "TechDraw_ShowAll"; @@ -376,6 +377,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const *anno << "TechDraw_CosmeticVertexGroup"; *anno << "TechDraw_CenterLineGroup"; *anno << "TechDraw_2PointCosmeticLine"; + *anno << "TechDraw_CosmeticCircle"; *anno << "TechDraw_CosmeticEraser"; *anno << "TechDraw_DecorateLine"; *anno << "TechDraw_ShowAll"; @@ -485,6 +487,7 @@ Gui::ToolBarItem* Workbench::setupCommandBars() const *anno << "TechDraw_CosmeticVertexGroup"; *anno << "TechDraw_CenterLineGroup"; *anno << "TechDraw_2PointCosmeticLine"; + *anno << "TechDraw_CosmeticCircle"; *anno << "TechDraw_CosmeticEraser"; *anno << "TechDraw_DecorateLine"; *anno << "TechDraw_ShowAll";