From 4aa80c1890f6066695ced0e2267373839cd3a646 Mon Sep 17 00:00:00 2001 From: Kavin Teenakul Date: Wed, 7 Jan 2026 15:16:24 +0700 Subject: [PATCH] [Std_Measure] Add diameter measurement (#24853) * Add diameter measurement support * change author name and change icon * correct svg size to 64x64 * Update src/Mod/Measure/App/MeasureDiameter.cpp Co-authored-by: Kacper Donat * somehow to icon color is undefine in inkscape, change to black * Revert "somehow to icon color is undefine in inkscape, change to black" This reverts commit 2277c1b9f4a7ab7519856986e2d6aec6e37ebf3e. modified: src/Mod/Measure/Gui/Resources/icons/Measurement-Diameter.svg * fix black color icon --------- Co-authored-by: Kacper Donat --- src/Mod/Measure/App/AppMeasure.cpp | 10 ++ src/Mod/Measure/App/CMakeLists.txt | 2 + src/Mod/Measure/App/MeasureDiameter.cpp | 163 ++++++++++++++++++ src/Mod/Measure/App/MeasureDiameter.h | 83 +++++++++ src/Mod/Measure/Gui/AppMeasureGui.cpp | 1 + src/Mod/Measure/Gui/Resources/Measure.qrc | 1 + .../Resources/icons/Measurement-Diameter.svg | 38 ++++ .../Measure/Gui/ViewProviderMeasureBase.cpp | 1 + src/Mod/Measure/Gui/ViewProviderMeasureBase.h | 11 ++ 9 files changed, 310 insertions(+) create mode 100644 src/Mod/Measure/App/MeasureDiameter.cpp create mode 100644 src/Mod/Measure/App/MeasureDiameter.h create mode 100644 src/Mod/Measure/Gui/Resources/icons/Measurement-Diameter.svg diff --git a/src/Mod/Measure/App/AppMeasure.cpp b/src/Mod/Measure/App/AppMeasure.cpp index 65e5d9f9c6..760dbefd56 100644 --- a/src/Mod/Measure/App/AppMeasure.cpp +++ b/src/Mod/Measure/App/AppMeasure.cpp @@ -43,6 +43,7 @@ #include "MeasurePosition.h" #include "MeasureLength.h" #include "MeasureArea.h" +#include "MeasureDiameter.h" #include "MeasureRadius.h" namespace Measure @@ -106,6 +107,7 @@ PyMOD_INIT_FUNC(Measure) Measure::MeasurePosition ::init(); Measure::MeasureLength ::init(); Measure::MeasureArea ::init(); + Measure::MeasureDiameter ::init(); Measure::MeasureRadius ::init(); // Add fundamental umf Measure Types @@ -158,6 +160,14 @@ PyMOD_INIT_FUNC(Measure) nullptr ); + App::MeasureManager::addMeasureType( + "DIAMETER", + "Diameter", + "Measure::MeasureDiameter", + MeasureDiameter::isValidSelection, + MeasureDiameter::isPrioritizedSelection + ); + App::MeasureManager::addMeasureType( "RADIUS", QT_TRANSLATE_NOOP("TaskMeasure", "Radius"), diff --git a/src/Mod/Measure/App/CMakeLists.txt b/src/Mod/Measure/App/CMakeLists.txt index 1b3f8f695a..078e0ee7b2 100644 --- a/src/Mod/Measure/App/CMakeLists.txt +++ b/src/Mod/Measure/App/CMakeLists.txt @@ -38,6 +38,8 @@ SET(MeasureModule_SRCS MeasureLength.h MeasureArea.cpp MeasureArea.h + MeasureDiameter.cpp + MeasureDiameter.h MeasureRadius.cpp MeasureRadius.h diff --git a/src/Mod/Measure/App/MeasureDiameter.cpp b/src/Mod/Measure/App/MeasureDiameter.cpp new file mode 100644 index 0000000000..8131250ae0 --- /dev/null +++ b/src/Mod/Measure/App/MeasureDiameter.cpp @@ -0,0 +1,163 @@ +/*************************************************************************** + * Copyright (c) 2025 Kavin Teenakul * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "MeasureDiameter.h" + +using namespace Measure; + +PROPERTY_SOURCE(Measure::MeasureDiameter, Measure::MeasureBase) + +MeasureDiameter::MeasureDiameter() +{ + ADD_PROPERTY_TYPE(Element, (nullptr), "Measurement", App::Prop_None, "Element to get the diameter from"); + Element.setScope(App::LinkScope::Global); + Element.setAllowExternal(true); + + ADD_PROPERTY_TYPE( + Diameter, + (0.0), + "Measurement", + App::PropertyType(App::Prop_ReadOnly | App::Prop_Output), + "Diameter of selection" + ); +} + +MeasureDiameter::~MeasureDiameter() = default; + +bool MeasureDiameter::isValidSelection(const App::MeasureSelection& selection) +{ + if (selection.empty() || selection.size() > 1) { + return false; + } + + auto element = selection.front(); + auto type = App::MeasureManager::getMeasureElementType(element); + + if (type == App::MeasureElementType::INVALID) { + return false; + } + + if (type != App::MeasureElementType::CIRCLE && type != App::MeasureElementType::ARC) { + return false; + } + + return true; +} + +bool MeasureDiameter::isPrioritizedSelection(const App::MeasureSelection& selection) +{ + if (selection.size() != 1) { + return false; + } + + auto element = selection.front(); + auto type = App::MeasureManager::getMeasureElementType(element); + + if (type == App::MeasureElementType::CIRCLE || type == App::MeasureElementType::ARC) { + return true; + } + + return false; +} + +void MeasureDiameter::parseSelection(const App::MeasureSelection& selection) +{ + auto element = selection.front(); + auto objT = element.object; + + std::vector subElementList {objT.getSubName()}; + Element.setValue(objT.getObject(), subElementList); +} + +App::DocumentObjectExecReturn* MeasureDiameter::execute() +{ + auto info = getMeasureInfoFirst(); + if (!info || !info->valid) { + return new App::DocumentObjectExecReturn("Cannot calculate diameter"); + } + + Diameter.setValue(info->radius * 2.0); + return DocumentObject::StdReturn; +} + +void MeasureDiameter::onChanged(const App::Property* prop) +{ + if (isRestoring() || isRemoving()) { + return; + } + + if (prop == &Element) { + auto ret = recompute(); + delete ret; + } + + MeasureBase::onChanged(prop); +} + +Base::Placement MeasureDiameter::getPlacement() +{ + auto loc = getMeasureInfoFirst()->pointOnCurve; + auto p = Base::Placement(); + p.setPosition(loc); + return p; +} + +Base::Vector3d MeasureDiameter::getPointOnCurve() const +{ + return getMeasureInfoFirst()->pointOnCurve; +} + +Part::MeasureRadiusInfoPtr MeasureDiameter::getMeasureInfoFirst() const +{ + const App::DocumentObject* object = Element.getValue(); + const std::vector& subElements = Element.getSubValues(); + + if (!object || subElements.empty()) { + return std::make_shared(); + } + + App::SubObjectT subject {object, subElements.front().c_str()}; + auto info = getMeasureInfo(subject); + if (!info || !info->valid) { + return std::make_shared(); + } + + return std::dynamic_pointer_cast(info); +} + +std::vector MeasureDiameter::getSubject() const +{ + return {Element.getValue()}; +} diff --git a/src/Mod/Measure/App/MeasureDiameter.h b/src/Mod/Measure/App/MeasureDiameter.h new file mode 100644 index 0000000000..85d177960a --- /dev/null +++ b/src/Mod/Measure/App/MeasureDiameter.h @@ -0,0 +1,83 @@ +/*************************************************************************** + * Copyright (c) 2024 Kavin Teenakul * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + + +#ifndef MEASURE_MEASUREDIAMETER_H +#define MEASURE_MEASUREDIAMETER_H + +#include + +#include +#include +#include +#include +#include + +#include + +#include "MeasureBase.h" + +namespace Measure +{ + +class MeasureExport MeasureDiameter: public Measure::MeasureBaseExtendable +{ + PROPERTY_HEADER_WITH_OVERRIDE(Measure::MeasureDiameter); + +public: + MeasureDiameter(); + ~MeasureDiameter() override; + + App::PropertyLinkSub Element; + App::PropertyDistance Diameter; + + App::DocumentObjectExecReturn* execute() override; + const char* getViewProviderName() const override + { + return "MeasureGui::ViewProviderMeasureDiameter"; + } + + static bool isValidSelection(const App::MeasureSelection& selection); + static bool isPrioritizedSelection(const App::MeasureSelection& selection); + void parseSelection(const App::MeasureSelection& selection) override; + + std::vector getInputProps() override + { + return {"Element"}; + } + App::Property* getResultProp() override + { + return &this->Diameter; + } + + Base::Placement getPlacement() override; + Base::Vector3d getPointOnCurve() const; + + std::vector getSubject() const override; + +private: + void onChanged(const App::Property* prop) override; + Part::MeasureRadiusInfoPtr getMeasureInfoFirst() const; +}; + +} // namespace Measure + +#endif // MEASURE_MEASUREDIAMETER_H diff --git a/src/Mod/Measure/Gui/AppMeasureGui.cpp b/src/Mod/Measure/Gui/AppMeasureGui.cpp index 9307a4528b..e58d1878f9 100644 --- a/src/Mod/Measure/Gui/AppMeasureGui.cpp +++ b/src/Mod/Measure/Gui/AppMeasureGui.cpp @@ -101,6 +101,7 @@ PyMOD_INIT_FUNC(MeasureGui) MeasureGui::ViewProviderMeasureLength ::init(); MeasureGui::ViewProviderMeasurePosition ::init(); MeasureGui::ViewProviderMeasureRadius ::init(); + MeasureGui::ViewProviderMeasureDiameter ::init(); MeasureGui::ViewProviderMeasureCOM ::init(); // clang-format on diff --git a/src/Mod/Measure/Gui/Resources/Measure.qrc b/src/Mod/Measure/Gui/Resources/Measure.qrc index 8baf77aaf0..5de7944d12 100644 --- a/src/Mod/Measure/Gui/Resources/Measure.qrc +++ b/src/Mod/Measure/Gui/Resources/Measure.qrc @@ -9,6 +9,7 @@ icons/Measurement-Group.svg icons/Measurement-Inertia.svg icons/Measurement-Position.svg + icons/Measurement-Diameter.svg icons/Measurement-Radius.svg icons/Measurement-Volume.svg diff --git a/src/Mod/Measure/Gui/Resources/icons/Measurement-Diameter.svg b/src/Mod/Measure/Gui/Resources/icons/Measurement-Diameter.svg new file mode 100644 index 0000000000..ccd1d248f1 --- /dev/null +++ b/src/Mod/Measure/Gui/Resources/icons/Measurement-Diameter.svg @@ -0,0 +1,38 @@ + + + + + + diff --git a/src/Mod/Measure/Gui/ViewProviderMeasureBase.cpp b/src/Mod/Measure/Gui/ViewProviderMeasureBase.cpp index 222e312935..d6de257074 100644 --- a/src/Mod/Measure/Gui/ViewProviderMeasureBase.cpp +++ b/src/Mod/Measure/Gui/ViewProviderMeasureBase.cpp @@ -742,4 +742,5 @@ PROPERTY_SOURCE(MeasureGui::ViewProviderMeasureArea, MeasureGui::ViewProviderMea PROPERTY_SOURCE(MeasureGui::ViewProviderMeasureLength, MeasureGui::ViewProviderMeasure) PROPERTY_SOURCE(MeasureGui::ViewProviderMeasurePosition, MeasureGui::ViewProviderMeasure) PROPERTY_SOURCE(MeasureGui::ViewProviderMeasureRadius, MeasureGui::ViewProviderMeasure) +PROPERTY_SOURCE(MeasureGui::ViewProviderMeasureDiameter, MeasureGui::ViewProviderMeasure) PROPERTY_SOURCE(MeasureGui::ViewProviderMeasureCOM, MeasureGui::ViewProviderMeasure) diff --git a/src/Mod/Measure/Gui/ViewProviderMeasureBase.h b/src/Mod/Measure/Gui/ViewProviderMeasureBase.h index 34c9945dcd..5af5372d0c 100644 --- a/src/Mod/Measure/Gui/ViewProviderMeasureBase.h +++ b/src/Mod/Measure/Gui/ViewProviderMeasureBase.h @@ -245,6 +245,17 @@ public: } }; +class ViewProviderMeasureDiameter: public ViewProviderMeasure +{ + PROPERTY_HEADER(MeasureGui::ViewProviderMeasureDiameter); + +public: + ViewProviderMeasureDiameter() + { + sPixmap = "Measurement-Diameter"; + } +}; + class ViewProviderMeasureCOM: public ViewProviderMeasure { PROPERTY_HEADER(MeasureGui::ViewProviderMeasureCOM);