[Measure] Add features, viewproviders and preferences for unified measurement facility

This commit is contained in:
hlorus
2024-01-14 21:46:50 +01:00
committed by WandererFan
parent 309e1c4155
commit bed703a6f9
49 changed files with 5762 additions and 132 deletions

View File

@@ -0,0 +1,99 @@
/***************************************************************************
* Copyright (c) 2023 David Friedli <david[at]friedli-be.ch> *
* *
* 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 *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "PreCompiled.h"
#include <Base/Console.h>
#include <Base/Interpreter.h>
#include <Base/PyObjectBase.h>
#include <Base/Tools.h>
#include <Gui/Application.h>
#include <Gui/Language/Translator.h>
#include <Gui/WidgetFactory.h>
#include "DlgPrefsMeasureAppearanceImp.h"
#include "ViewProviderMeasureAngle.h"
#include "ViewProviderMeasureDistance.h"
#include "ViewProviderMeasureBase.h"
// use a different name to CreateCommand()
void CreateMeasureCommands();
namespace MeasureGui
{
class Module: public Py::ExtensionModule<Module>
{
public:
Module()
: Py::ExtensionModule<Module>("MeasureGui")
{
initialize("This module is the MeasureGui module.");// register with Python
}
~Module() override = default;
private:
};
PyObject* initModule()
{
return Base::Interpreter().addModule(new Module);
}
}// namespace MeasureGui
/* Python entry */
PyMOD_INIT_FUNC(MeasureGui)
{
if (!Gui::Application::Instance) {
PyErr_SetString(PyExc_ImportError, "Cannot load Gui module in console application.");
PyMOD_Return(nullptr);
}
// load dependent module
try {
Base::Interpreter().loadModule("Measure");
}
catch(const Base::Exception& e) {
PyErr_SetString(PyExc_ImportError, e.what());
PyMOD_Return(nullptr);
}
PyObject* mod = MeasureGui::initModule();
Base::Console().Log("Loading GUI of Measure module... done\n");
// instantiating the commands
CreateMeasureCommands();
MeasureGui::ViewProviderMeasureBase ::init();
MeasureGui::ViewProviderMeasure ::init();
MeasureGui::ViewProviderMeasureAngle ::init();
MeasureGui::ViewProviderMeasureDistance ::init();
// register preferences pages
new Gui::PrefPageProducer<MeasureGui::DlgPrefsMeasureAppearanceImp>(QT_TRANSLATE_NOOP("QObject", "Measure"));
// Q_INIT_RESOURCE(Measure);
PyMOD_Return(mod);
}

View File

@@ -0,0 +1,90 @@
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}
${Boost_INCLUDE_DIRS}
${COIN3D_INCLUDE_DIRS}
${OCC_INCLUDE_DIR}
${PYTHON_INCLUDE_DIRS}
${XercesC_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIR}
)
link_directories(${OCC_LIBRARY_DIR})
link_directories(${OCC_LIBRARY_DIR})
set(MeasureGui_LIBS
Measure
FreeCADGui
)
if(MSVC)
include_directories(
${CMAKE_SOURCE_DIR}/src/3rdParty/OpenGL/api
)
endif(MSVC)
set (Measure_TR_QRC ${CMAKE_CURRENT_BINARY_DIR}/Resources/Measure_translation.qrc)
qt_find_and_add_translation(QM_SRCS "Resources/translations/*_*.ts"
${CMAKE_CURRENT_BINARY_DIR}/Resources/translations)
qt_create_resource_file(${Measure_TR_QRC} ${QM_SRCS})
qt_add_resources(MeasureGui_SRCS Resources/Measure.qrc ${Measure_TR_QRC})
SET(MeasureGui_UIC_SRCS
DlgPrefsMeasureAppearanceImp.ui
)
SET(MeasureGui_SRCS
${CMAKE_SOURCE_DIR}/src/Mod/Measure/InitGui.py
${MeasureGui_SRCS}
AppMeasureGui.cpp
Command.cpp
Resources/Measure.qrc
PreCompiled.cpp
PreCompiled.h
ViewProviderMeasureBase.cpp
ViewProviderMeasureBase.h
ViewProviderMeasureAngle.cpp
ViewProviderMeasureAngle.h
ViewProviderMeasureDistance.cpp
ViewProviderMeasureDistance.h
# Workbench.cpp
# Workbench.h
DlgPrefsMeasureAppearanceImp.ui
DlgPrefsMeasureAppearanceImp.cpp
DlgPrefsMeasureAppearanceImp.h
)
SET(MeasureGuiTaskDlgs_SRCS
DlgPrefsMeasureAppearanceImp.ui
)
#set(MeasureGui_Scripts
# ../InitGui.py
#)
if(FREECAD_USE_PCH)
add_definitions(-D_PreComp_)
GET_MSVC_PRECOMPILED_SOURCE("PreCompiled.cpp" PCH_SRCS ${MeasureGui_SRCS})
ADD_MSVC_PRECOMPILED_HEADER(MeasureGui PreCompiled.h PreCompiled.cpp PCH_SRCS)
endif(FREECAD_USE_PCH)
SET(MeasureGuiIcon_SVG
Resources/icons/preferences-measure.svg
)
add_library(MeasureGui SHARED ${MeasureGui_SRCS} ${MeasureGuiIcon_SVG})
target_link_libraries(MeasureGui ${MeasureGui_LIBS})
SET_BIN_DIR(MeasureGui MeasureGui /Mod/Measure)
SET_PYTHON_PREFIX_SUFFIX(MeasureGui)
fc_copy_sources(MeasureGui "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Measure/" ${MeasureGuiIcon_SVG})
INSTALL(TARGETS MeasureGui DESTINATION ${CMAKE_INSTALL_LIBDIR})
INSTALL(FILES ${MeasureGuiIcon_SVG} DESTINATION "${CMAKE_INSTALL_DATADIR}/Mod/Measure/Resources/icons")

View File

@@ -0,0 +1,33 @@
/***************************************************************************
* Copyright (c) 2023 David Friedli <david[at]friedli-be.ch> *
* *
* 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 *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "PreCompiled.h"
#include <Gui/Application.h>
#include <Gui/Command.h>
using namespace std;
void CreateMeasureCommands() {
Base::Console().Message("Init MeasureGui\n");
Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager();
}

View File

@@ -0,0 +1,75 @@
/**************************************************************************
* Copyright (c) 2023 Wanderer Fan <wandererfan@gmail.com> *
* *
* 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 *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "PreCompiled.h"
#include "DlgPrefsMeasureAppearanceImp.h"
#include "ui_DlgPrefsMeasureAppearanceImp.h"
using namespace MeasureGui;
DlgPrefsMeasureAppearanceImp::DlgPrefsMeasureAppearanceImp( QWidget* parent )
: PreferencePage( parent )
, ui(new Ui_DlgPrefsMeasureAppearanceImp)
{
ui->setupUi(this);
}
DlgPrefsMeasureAppearanceImp::~DlgPrefsMeasureAppearanceImp()
{
// no need to delete child widgets, Qt does it all for us
}
void DlgPrefsMeasureAppearanceImp::saveSettings()
{
ui->cbMirror->onSave();
ui->dsbDistFactor->onSave();
ui->sbFontSize->onSave();
ui->cbText->onSave();
ui->cbLine->onSave();
ui->cbBackground->onSave();
}
void DlgPrefsMeasureAppearanceImp::loadSettings()
{
ui->sbFontSize->onRestore();
ui->cbText->onRestore();
ui->cbBackground->onRestore();
ui->cbLine->onRestore();
ui->cbMirror->onRestore();
ui->dsbDistFactor->onRestore();
}
/**
* Sets the strings of the subwidgets using the current language.
*/
void DlgPrefsMeasureAppearanceImp::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
ui->retranslateUi(this);
}
else {
QWidget::changeEvent(e);
}
}
#include <Mod/Measure/Gui/moc_DlgPrefsMeasureAppearanceImp.cpp>

View File

@@ -0,0 +1,55 @@
/**************************************************************************
* Copyright (c) 2023 Wanderer Fan <wandererfan@gmail.com> *
* *
* 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 *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#ifndef MeasureGui_DlgPrefsAppearanceImp_H
#define MeasureGui_DlgPrefsAppearanceImp_H
#include <memory>
#include <Gui/PropertyPage.h>
#include <Mod/Measure/MeasureGlobal.h>
namespace MeasureGui {
class Ui_DlgPrefsMeasureAppearanceImp;
class DlgPrefsMeasureAppearanceImp : public Gui::Dialog::PreferencePage
{
Q_OBJECT
public:
explicit DlgPrefsMeasureAppearanceImp( QWidget* parent = nullptr );
~DlgPrefsMeasureAppearanceImp() override;
protected:
void saveSettings() override;
void loadSettings() override;
void changeEvent(QEvent *e) override;
private:
std::unique_ptr<Ui_DlgPrefsMeasureAppearanceImp> ui;
};
} // namespace MeasureGui
#endif // MeasureGui_DlgPrefsAppearanceImp_H

View File

@@ -0,0 +1,247 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MeasureGui::DlgPrefsMeasureAppearanceImp</class>
<widget class="QWidget" name="MeasureGui::DlgPrefsMeasureAppearanceImp">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>623</width>
<height>287</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Appearance</string>
</property>
<property name="windowIcon">
<iconset resource="Resources/Measure.qrc">
<normaloff>:/icons/preferences-measure.svg</normaloff>:/icons/preferences-measure.svg</iconset>
</property>
<property name="toolTip">
<string/>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QGroupBox" name="gbMisc">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>200</height>
</size>
</property>
<property name="title">
<string>Default Property Values</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout_5" columnstretch="1,1">
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Distance Factor</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Text color</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::PrefColorButton" name="cbText">
<property name="color">
<color>
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</property>
<property name="prefEntry" stdset="0">
<cstring>DefaultTextColor</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Measure/Appearance</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::PrefSpinBox" name="sbFontSize">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>18</number>
</property>
<property name="prefEntry" stdset="0">
<cstring>DefaultFontSize</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Measure/Appearance</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Gui::PrefColorButton" name="cbLine">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="color">
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</property>
<property name="prefEntry" stdset="0">
<cstring>DefaultLineColor</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Measure/Appearance</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Text size</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="Gui::PrefDoubleSpinBox" name="dsbDistFactor">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
<property name="prefEntry" stdset="0">
<cstring>DefaultDistFactor</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Measure/Appearance</cstring>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Line color</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="Gui::PrefCheckBox" name="cbMirror">
<property name="text">
<string>Mirror</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>DefaultMirror</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Measure/Appearance</cstring>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Background color</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="Gui::PrefColorButton" name="cbBackground">
<property name="color">
<color>
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</property>
<property name="prefEntry" stdset="0">
<cstring>DefaultTextBackgroundColor</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Measure/Appearance</cstring>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::ColorButton</class>
<extends>QPushButton</extends>
<header>Gui/Widgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefSpinBox</class>
<extends>QSpinBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefColorButton</class>
<extends>Gui::ColorButton</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefCheckBox</class>
<extends>QCheckBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefDoubleSpinBox</class>
<extends>QDoubleSpinBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="Resources/Measure.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -0,0 +1,22 @@
/***************************************************************************
* Copyright (c) 2023 David Friedli <david[at]friedli-be.ch> *
* *
* 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 *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "PreCompiled.h"

View File

@@ -0,0 +1,97 @@
/***************************************************************************
* Copyright (c) 2023 David Friedli <david[at]friedli-be.ch> *
* *
* 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 *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#ifndef MEASUREGUI_PRECOMPILED_H
#define MEASUREGUI_PRECOMPILED_H
#include <FCConfig.h>
#include <Mod/Measure/MeasureGlobal.h>
// point at which warnings of overly long specifiers disabled (needed for VC6)
#ifdef _MSC_VER
# pragma warning( disable : 4251 )
# pragma warning( disable : 4503 )
# pragma warning( disable : 4786 ) // specifier longer then 255 chars
# pragma warning( disable : 4273 )
#endif
#ifdef FC_OS_WIN32
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <windows.h>
#endif
#ifdef _PreComp_
// standard
#include <cfloat>
#include <cmath>
// STL
#include <algorithm>
#include <map>
#include <sstream>
#include <string>
#include <vector>
// OpenCasCade
#include <Mod/Part/App/OpenCascadeAll.h>
// Boost
#include <boost/regex.hpp>
#include <boost/algorithm/string/predicate.hpp>
// GL
// Include glext before QtAll/InventorAll
#ifdef FC_OS_WIN32
# include <GL/gl.h>
# include <GL/glext.h>
#else
# ifdef FC_OS_MACOSX
# include <OpenGL/gl.h>
# include <OpenGL/glext.h>
# else
# ifndef GL_GLEXT_PROTOTYPES
# define GL_GLEXT_PROTOTYPES 1
# endif
# include <GL/gl.h>
# include <GL/glext.h>
# endif //FC_OS_MACOSX
#endif //FC_OS_WIN32
// Should come after glext.h to avoid warnings
#include <Inventor/C/glue/gl.h>
// Qt Toolkit
#ifndef __QtAll__
# include <Gui/QtAll.h>
#endif
// Inventor includes OpenGL
#ifndef __InventorAll__
# include <Gui/InventorAll.h>
#endif
#endif //_PreComp_
#endif

View File

@@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>icons/umf-measurement.svg</file>
<file>icons/preferences-measure.svg</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,317 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="64px"
height="64px"
id="svg2943"
version="1.1">
<defs
id="defs2945">
<linearGradient
id="linearGradient4158">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4160" />
<stop
style="stop-color:#f6f6f6;stop-opacity:0;"
offset="1"
id="stop4162" />
</linearGradient>
<linearGradient
id="linearGradient4122">
<stop
style="stop-color:#e3d328;stop-opacity:1;"
offset="0"
id="stop4124" />
<stop
style="stop-color:#e1dec3;stop-opacity:1;"
offset="1"
id="stop4126" />
</linearGradient>
<linearGradient
id="linearGradient4088">
<stop
style="stop-color:#e9cd23;stop-opacity:1;"
offset="0"
id="stop4090" />
<stop
style="stop-color:#040000;stop-opacity:0;"
offset="1"
id="stop4092" />
</linearGradient>
<linearGradient
id="linearGradient4060">
<stop
style="stop-color:#ada9a9;stop-opacity:1;"
offset="0"
id="stop4062" />
<stop
style="stop-color:#ada9a9;stop-opacity:0;"
offset="1"
id="stop4064" />
</linearGradient>
<linearGradient
id="linearGradient4052">
<stop
style="stop-color:#ada9a9;stop-opacity:1;"
offset="0"
id="stop4054" />
<stop
style="stop-color:#ada9a9;stop-opacity:0;"
offset="1"
id="stop4056" />
</linearGradient>
<linearGradient
id="linearGradient4349">
<stop
style="stop-color:#898709;stop-opacity:1;"
offset="0"
id="stop4351" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop4353" />
</linearGradient>
<linearGradient
id="linearGradient5241">
<stop
style="stop-color:#212c45;stop-opacity:1;"
offset="0"
id="stop5243" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop5245" />
</linearGradient>
<linearGradient
id="linearGradient5227"
osb:paint="solid">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop5229" />
</linearGradient>
<linearGradient
id="linearGradient3902">
<stop
style="stop-color:#000000;stop-opacity:0.58823532;"
offset="0"
id="stop3904" />
<stop
style="stop-color:#000000;stop-opacity:0.39215687;"
offset="1"
id="stop3906" />
</linearGradient>
<linearGradient
id="linearGradient3894">
<stop
style="stop-color:#45351d;stop-opacity:1;"
offset="0"
id="stop3896" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop3898" />
</linearGradient>
<linearGradient
id="linearGradient3886">
<stop
style="stop-color:#45351d;stop-opacity:1;"
offset="0"
id="stop3888" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop3890" />
</linearGradient>
<linearGradient
id="linearGradient3792">
<stop
style="stop-color:#aaaaaa;stop-opacity:1;"
offset="0"
id="stop3794" />
<stop
style="stop-color:#d2d2d2;stop-opacity:1;"
offset="1"
id="stop3796" />
</linearGradient>
<linearGradient
id="linearGradient3784">
<stop
style="stop-color:#bebebe;stop-opacity:1;"
offset="0"
id="stop3786" />
<stop
style="stop-color:#ffffff;stop-opacity:0.39215687;"
offset="1"
id="stop3788" />
</linearGradient>
<linearGradient
id="linearGradient3377">
<stop
id="stop3379"
offset="0"
style="stop-color:#71b2f8;stop-opacity:1;" />
<stop
id="stop3381"
offset="1"
style="stop-color:#002795;stop-opacity:1;" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient4052"
id="linearGradient4058"
x1="138.99986"
y1="44.863674"
x2="92.497559"
y2="-14.356517"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(168.6744,65.825928)" />
<linearGradient
xlink:href="#linearGradient4060"
id="linearGradient4066"
x1="103.93729"
y1="49.179436"
x2="120.49899"
y2="0.21229285"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(168.6744,65.825928)" />
<linearGradient
xlink:href="#linearGradient4122"
id="linearGradient4128"
x1="391.3074"
y1="120.81136"
x2="394.43201"
y2="112.43636"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-88.034794,-1.0606602)" />
<linearGradient
xlink:href="#linearGradient4158"
id="linearGradient4164"
x1="419.99387"
y1="102.77802"
x2="458.7193"
y2="69.431564"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-129.22376,-0.88388348)" />
<linearGradient
xlink:href="#linearGradient3953"
id="linearGradient3959"
x1="214.70918"
y1="80.886589"
x2="218.70918"
y2="104.88659"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(80,0)" />
<linearGradient
id="linearGradient3953">
<stop
style="stop-color:#babdb6;stop-opacity:1"
offset="0"
id="stop3955" />
<stop
style="stop-color:#555753;stop-opacity:1"
offset="1"
id="stop3957" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3961"
id="linearGradient3967"
x1="196.70918"
y1="106.88659"
x2="190.70918"
y2="80.886589"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(80,0)" />
<linearGradient
id="linearGradient3961">
<stop
style="stop-color:#babdb6;stop-opacity:1"
offset="0"
id="stop3963" />
<stop
style="stop-color:#d3d7cf;stop-opacity:1"
offset="1"
id="stop3965" />
</linearGradient>
</defs>
<metadata
id="metadata2948">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1">
<g
id="g3629"
transform="translate(-256.70919,-66.886588)">
<path
style="fill:#e3d328;fill-opacity:1;stroke:#040400;stroke-width:0.08838835;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d=""
id="path4102"
transform="translate(256.70919,66.886588)" />
<path
style="fill:#babdb6;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 285.70919,77.886588 -26,-4 c 0,11 0,26.000002 2,36.000002 l 30,12 0,-6 -2,-4 c 8,-12 0,-24.000002 -4,-34.000002 z"
id="path3100" />
<path
style="fill:#555753;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 291.70919,121.88659 12,-4 0,-6 -12,4 z"
id="path3890" />
<path
style="fill:#d3d7cf;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 301.70919,107.88659 -12,4 2,4 12,-4 z"
id="path3892" />
<path
style="fill:#888a85;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 285.70919,77.886588 c 4,10 12,22.000002 4,34.000002 l 12,-4 c 8,-12.000002 0,-24.000002 -4,-34.000002 z"
id="path3894" />
<path
style="fill:#d3d7cf;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 259.70919,73.886588 12,-4 26,4 -12,4 z"
id="path3888" />
<path
style="fill:url(#linearGradient3967);fill-opacity:1;stroke:#d3d7cf;stroke-width:1.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 284.30919,79.786588 -22.6,-3.9 c 0,10.043478 -0.0125,23.469562 1.8,32.600002 l 26.2,10.4 0,-2.5 -2.2,-4.5 c 8,-12 1.2,-22.000002 -3.2,-32.100002 z"
id="path3100-6" />
<path
style="fill:url(#linearGradient3959);fill-opacity:1;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 288.30919,79.086588 c 4,10 9.4,18.3 5.4,29.300002 l 6.6,-2.2 c 6,-9.000002 1.4,-19.300002 -3.8,-29.900002 z"
id="path3894-7" />
<path
style="fill:#555753;fill-opacity:1;stroke:#2e3436;stroke-width:2.25831866;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.6"
id="path3932"
d="m -78,39 a 15,15 0 1 1 -30,0 15,15 0 1 1 30,0 z"
transform="matrix(0.79999998,0.19607832,0,0.9803916,350.10919,74.8866)" />
<path
style="fill:#edd400;fill-opacity:1;stroke:#302b00;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:1.6"
d="m 287.70919,97.827762 -24,-5.882349 c 0,0 -0.82229,-14.095015 12,-11.764699 11.12322,2.021527 12,17.647048 12,17.647048 z"
id="path3932-5" />
<path
style="fill:#edd400;fill-opacity:1;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 294.70919,90.886588 c 2,4 3,11.000002 1,15.000002 l 4,-1 c 2,-4 2,-11.000002 0,-15.000002 z"
id="path3894-7-9" />
<path
style="fill:#edd400;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 293.70919,117.88659 8,-3 16,5 -6,4 z"
id="path4003" />
<path
style="fill:#d3d7cf;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 317.70919,119.88659 0,4 -6,4 0,-4 z"
id="path4005" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,317 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="64px"
height="64px"
id="svg2943"
version="1.1">
<defs
id="defs2945">
<linearGradient
id="linearGradient4158">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4160" />
<stop
style="stop-color:#f6f6f6;stop-opacity:0;"
offset="1"
id="stop4162" />
</linearGradient>
<linearGradient
id="linearGradient4122">
<stop
style="stop-color:#e3d328;stop-opacity:1;"
offset="0"
id="stop4124" />
<stop
style="stop-color:#e1dec3;stop-opacity:1;"
offset="1"
id="stop4126" />
</linearGradient>
<linearGradient
id="linearGradient4088">
<stop
style="stop-color:#e9cd23;stop-opacity:1;"
offset="0"
id="stop4090" />
<stop
style="stop-color:#040000;stop-opacity:0;"
offset="1"
id="stop4092" />
</linearGradient>
<linearGradient
id="linearGradient4060">
<stop
style="stop-color:#ada9a9;stop-opacity:1;"
offset="0"
id="stop4062" />
<stop
style="stop-color:#ada9a9;stop-opacity:0;"
offset="1"
id="stop4064" />
</linearGradient>
<linearGradient
id="linearGradient4052">
<stop
style="stop-color:#ada9a9;stop-opacity:1;"
offset="0"
id="stop4054" />
<stop
style="stop-color:#ada9a9;stop-opacity:0;"
offset="1"
id="stop4056" />
</linearGradient>
<linearGradient
id="linearGradient4349">
<stop
style="stop-color:#898709;stop-opacity:1;"
offset="0"
id="stop4351" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop4353" />
</linearGradient>
<linearGradient
id="linearGradient5241">
<stop
style="stop-color:#212c45;stop-opacity:1;"
offset="0"
id="stop5243" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop5245" />
</linearGradient>
<linearGradient
id="linearGradient5227"
osb:paint="solid">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop5229" />
</linearGradient>
<linearGradient
id="linearGradient3902">
<stop
style="stop-color:#000000;stop-opacity:0.58823532;"
offset="0"
id="stop3904" />
<stop
style="stop-color:#000000;stop-opacity:0.39215687;"
offset="1"
id="stop3906" />
</linearGradient>
<linearGradient
id="linearGradient3894">
<stop
style="stop-color:#45351d;stop-opacity:1;"
offset="0"
id="stop3896" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop3898" />
</linearGradient>
<linearGradient
id="linearGradient3886">
<stop
style="stop-color:#45351d;stop-opacity:1;"
offset="0"
id="stop3888" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop3890" />
</linearGradient>
<linearGradient
id="linearGradient3792">
<stop
style="stop-color:#aaaaaa;stop-opacity:1;"
offset="0"
id="stop3794" />
<stop
style="stop-color:#d2d2d2;stop-opacity:1;"
offset="1"
id="stop3796" />
</linearGradient>
<linearGradient
id="linearGradient3784">
<stop
style="stop-color:#bebebe;stop-opacity:1;"
offset="0"
id="stop3786" />
<stop
style="stop-color:#ffffff;stop-opacity:0.39215687;"
offset="1"
id="stop3788" />
</linearGradient>
<linearGradient
id="linearGradient3377">
<stop
id="stop3379"
offset="0"
style="stop-color:#71b2f8;stop-opacity:1;" />
<stop
id="stop3381"
offset="1"
style="stop-color:#002795;stop-opacity:1;" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient4052"
id="linearGradient4058"
x1="138.99986"
y1="44.863674"
x2="92.497559"
y2="-14.356517"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(168.6744,65.825928)" />
<linearGradient
xlink:href="#linearGradient4060"
id="linearGradient4066"
x1="103.93729"
y1="49.179436"
x2="120.49899"
y2="0.21229285"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(168.6744,65.825928)" />
<linearGradient
xlink:href="#linearGradient4122"
id="linearGradient4128"
x1="391.3074"
y1="120.81136"
x2="394.43201"
y2="112.43636"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-88.034794,-1.0606602)" />
<linearGradient
xlink:href="#linearGradient4158"
id="linearGradient4164"
x1="419.99387"
y1="102.77802"
x2="458.7193"
y2="69.431564"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-129.22376,-0.88388348)" />
<linearGradient
xlink:href="#linearGradient3953"
id="linearGradient3959"
x1="214.70918"
y1="80.886589"
x2="218.70918"
y2="104.88659"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(80,0)" />
<linearGradient
id="linearGradient3953">
<stop
style="stop-color:#babdb6;stop-opacity:1"
offset="0"
id="stop3955" />
<stop
style="stop-color:#555753;stop-opacity:1"
offset="1"
id="stop3957" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3961"
id="linearGradient3967"
x1="196.70918"
y1="106.88659"
x2="190.70918"
y2="80.886589"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(80,0)" />
<linearGradient
id="linearGradient3961">
<stop
style="stop-color:#babdb6;stop-opacity:1"
offset="0"
id="stop3963" />
<stop
style="stop-color:#d3d7cf;stop-opacity:1"
offset="1"
id="stop3965" />
</linearGradient>
</defs>
<metadata
id="metadata2948">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1">
<g
id="g3629"
transform="translate(-256.70919,-66.886588)">
<path
style="fill:#e3d328;fill-opacity:1;stroke:#040400;stroke-width:0.08838835;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d=""
id="path4102"
transform="translate(256.70919,66.886588)" />
<path
style="fill:#babdb6;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 285.70919,77.886588 -26,-4 c 0,11 0,26.000002 2,36.000002 l 30,12 0,-6 -2,-4 c 8,-12 0,-24.000002 -4,-34.000002 z"
id="path3100" />
<path
style="fill:#555753;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 291.70919,121.88659 12,-4 0,-6 -12,4 z"
id="path3890" />
<path
style="fill:#d3d7cf;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 301.70919,107.88659 -12,4 2,4 12,-4 z"
id="path3892" />
<path
style="fill:#888a85;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 285.70919,77.886588 c 4,10 12,22.000002 4,34.000002 l 12,-4 c 8,-12.000002 0,-24.000002 -4,-34.000002 z"
id="path3894" />
<path
style="fill:#d3d7cf;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 259.70919,73.886588 12,-4 26,4 -12,4 z"
id="path3888" />
<path
style="fill:url(#linearGradient3967);fill-opacity:1;stroke:#d3d7cf;stroke-width:1.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 284.30919,79.786588 -22.6,-3.9 c 0,10.043478 -0.0125,23.469562 1.8,32.600002 l 26.2,10.4 0,-2.5 -2.2,-4.5 c 8,-12 1.2,-22.000002 -3.2,-32.100002 z"
id="path3100-6" />
<path
style="fill:url(#linearGradient3959);fill-opacity:1;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 288.30919,79.086588 c 4,10 9.4,18.3 5.4,29.300002 l 6.6,-2.2 c 6,-9.000002 1.4,-19.300002 -3.8,-29.900002 z"
id="path3894-7" />
<path
style="fill:#555753;fill-opacity:1;stroke:#2e3436;stroke-width:2.25831866;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.6"
id="path3932"
d="m -78,39 a 15,15 0 1 1 -30,0 15,15 0 1 1 30,0 z"
transform="matrix(0.79999998,0.19607832,0,0.9803916,350.10919,74.8866)" />
<path
style="fill:#edd400;fill-opacity:1;stroke:#302b00;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:1.6"
d="m 287.70919,97.827762 -24,-5.882349 c 0,0 -0.82229,-14.095015 12,-11.764699 11.12322,2.021527 12,17.647048 12,17.647048 z"
id="path3932-5" />
<path
style="fill:#edd400;fill-opacity:1;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 294.70919,90.886588 c 2,4 3,11.000002 1,15.000002 l 4,-1 c 2,-4 2,-11.000002 0,-15.000002 z"
id="path3894-7-9" />
<path
style="fill:#edd400;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 293.70919,117.88659 8,-3 16,5 -6,4 z"
id="path4003" />
<path
style="fill:#d3d7cf;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 317.70919,119.88659 0,4 -6,4 0,-4 z"
id="path4005" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>MeasureGui::DlgPrefsMeasureAppearanceImp</name>
<message>
<location filename="DlgPrefsMeasureAppearanceImp.ui" line="20"/>
<source>Appearance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="DlgPrefsMeasureAppearanceImp.ui" line="47"/>
<source>Default Property Values</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="DlgPrefsMeasureAppearanceImp.ui" line="55"/>
<source>Distance Factor</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="DlgPrefsMeasureAppearanceImp.ui" line="62"/>
<source>Text color</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="DlgPrefsMeasureAppearanceImp.ui" line="128"/>
<source>Text size</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="DlgPrefsMeasureAppearanceImp.ui" line="151"/>
<source>Line color</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="DlgPrefsMeasureAppearanceImp.ui" line="158"/>
<source>Mirror</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@@ -0,0 +1,339 @@
/***************************************************************************
* Copyright (c) 2023 David Friedli <david[at]friedli-be.ch> *
* Copyright (c) 2013 Thomas Anderson <blobfish[at]gmx.com> *
* *
* 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 *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <sstream>
# include <QApplication>
# include <Inventor/draggers/SoTranslate2Dragger.h>
# include <Inventor/nodes/SoAnnotation.h>
# include <Inventor/nodes/SoBaseColor.h>
# include <Inventor/nodes/SoCoordinate3.h>
# include <Inventor/nodes/SoDrawStyle.h>
# include <Inventor/nodes/SoFontStyle.h>
# include <Inventor/nodes/SoIndexedLineSet.h>
# include <Inventor/nodes/SoPickStyle.h>
# include <Inventor/nodes/SoText2.h>
# include <Inventor/nodes/SoTranslation.h>
# include <Inventor/engines/SoCalculator.h>
# include <Inventor/engines/SoComposeVec3f.h>
# include <Inventor/engines/SoConcatenate.h>
# include <Inventor/engines/SoComposeMatrix.h>
# include <Inventor/engines/SoComposeRotation.h>
# include <Inventor/engines/SoComposeRotationFromTo.h>
# include <Inventor/engines/SoDecomposeRotation.h>
# include <Inventor/engines/SoTransformVec3f.h>
# include <Inventor/nodekits/SoShapeKit.h>
# include <Inventor/nodes/SoFont.h>
# include <Inventor/nodes/SoLineSet.h>
# include <Inventor/nodes/SoMatrixTransform.h>
# include <Inventor/nodes/SoSeparator.h>
# include <Inventor/nodes/SoTransform.h>
# include <Inventor/nodes/SoVertexProperty.h>
# include <Inventor/nodekits/SoBaseKit.h>
#endif
#include <Precision.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Line.hxx>
#include <gp_Vec.hxx>
#include <gp_Lin.hxx>
#include <gp_Pnt.hxx>
# include <GeomAPI_ExtremaCurveCurve.hxx>
# include <GeomAPI_ProjectPointOnCurve.hxx>
#include <App/Application.h>
#include <App/Document.h>
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Base/Quantity.h>
#include <Gui/ArcEngine.h>
#include <Gui/Command.h>
#include <Gui/Document.h>
#include <Gui/ViewParams.h>
#include <Mod/Measure/App/Preferences.h>
#include "ViewProviderMeasureAngle.h"
using namespace MeasureGui;
using namespace Measure;
gp_Lin getLine(gp_Vec& vec, gp_Vec& origin) {
gp_Pnt tempOrigin;
tempOrigin.SetXYZ(origin.XYZ());
return gp_Lin(tempOrigin, gp_Dir(vec));
}
SbMatrix ViewProviderMeasureAngle::getMatrix() {
// Code ported from src/Mod/Part/Gui/TaskDimension.cpp
if (pcObject == nullptr) {
throw Base::RuntimeError("no DocumentObject");
}
Measure::MeasureAngle* measurement = static_cast<Measure::MeasureAngle*>(pcObject);
if (!measurement->Element1.getValue() || measurement->Element1.getSubValues().empty()){
return SbMatrix();
}
if (!measurement->Element2.getValue() || measurement->Element2.getSubValues().empty()){
return SbMatrix();
}
gp_Vec vector1 = measurement->vector1();
gp_Vec vector2 = measurement->vector2();
gp_Vec loc1 = measurement->location1();
gp_Vec loc2 = measurement->location2();
if (vector1.Magnitude() == 0 || vector2.Magnitude() == 0) {
return SbMatrix();
}
gp_Lin lin1 = getLine(vector1, loc1);
gp_Lin lin2 = getLine(vector2, loc2);
SbMatrix dimSys = SbMatrix();
double radius;
if (vector1.IsParallel(vector2, Precision::Angular())) {
//take first point project it onto second vector.
Handle(Geom_Curve) heapLine2 = new Geom_Line(lin2);
gp_Pnt tempPoint(loc1.XYZ());
GeomAPI_ProjectPointOnCurve projection(tempPoint, heapLine2);
if (projection.NbPoints() < 1)
{
throw Base::RuntimeError("parallel vectors: couldn't project onto line");
}
gp_Vec newPoint2;
newPoint2.SetXYZ(projection.Point(1).XYZ());
//if points are colinear, projection doesn't work and returns the same point.
//In this case we just use the original point.
if ((newPoint2 - loc1).Magnitude() < Precision::Confusion())
newPoint2 = loc2;
//now get midpoint between for dim origin.
gp_Vec point1 = loc1;
gp_Vec midPointProjection = newPoint2 - point1;
double distance = midPointProjection.Magnitude();
midPointProjection.Normalize();
midPointProjection *= distance / 2.0;
gp_Vec origin = point1 + midPointProjection;
//yaxis should be the same as vector1, but doing this to eliminate any potential slop from
//using precision::angular. If lines are colinear and we have no plane, we can't establish zAxis from crossing.
//we just the absolute axis.
gp_Vec xAxis = (point1 - origin).Normalized();
gp_Vec zAxis;
if (xAxis.IsParallel(vector1, Precision::Angular())) {
if (!xAxis.IsParallel(gp_Vec(0.0, 0.0, 1.0), Precision::Angular()))
zAxis = gp_Vec(0.0, 0.0, 1.0);
else
zAxis = gp_Vec(0.0, 1.0, 0.0);
}
else
zAxis = xAxis.Crossed(vector1).Normalized();
gp_Vec yAxis = zAxis.Crossed(xAxis).Normalized();
zAxis = xAxis.Crossed(yAxis).Normalized();
dimSys = SbMatrix
(
xAxis.X(), yAxis.X(), zAxis.X(), origin.X(),
xAxis.Y(), yAxis.Y(), zAxis.Y(), origin.Y(),
xAxis.Z(), yAxis.Z(), zAxis.Z(), origin.Z(),
0.0, 0.0, 0.0, 1.0
);
dimSys = dimSys.transpose();
radius = midPointProjection.Magnitude();
} else {
Handle(Geom_Curve) heapLine1 = new Geom_Line(lin1);
Handle(Geom_Curve) heapLine2 = new Geom_Line(lin2);
GeomAPI_ExtremaCurveCurve extrema(heapLine1, heapLine2);
if (extrema.NbExtrema() < 1)
{
throw Base::RuntimeError("couldn't get extrema");
}
gp_Pnt extremaPoint1, extremaPoint2, dimensionOriginPoint;
extrema.Points(1, extremaPoint1, extremaPoint2);
if (extremaPoint1.Distance(extremaPoint2) < Precision::Confusion())
dimensionOriginPoint = extremaPoint1;
else
{
//find halfway point in between extrema points for dimension origin.
gp_Vec vec1(extremaPoint1.XYZ());
gp_Vec vec2(extremaPoint2.XYZ());
gp_Vec connection(vec2-vec1);
Standard_Real distance = connection.Magnitude();
connection.Normalize();
connection *= (distance / 2.0);
dimensionOriginPoint.SetXYZ((vec1 + connection).XYZ());
}
gp_Vec thirdPoint(loc2);
gp_Vec originVector(dimensionOriginPoint.XYZ());
gp_Vec extrema2Vector(extremaPoint2.XYZ());
radius = (loc1 - originVector).Magnitude();
double legOne = (extrema2Vector - originVector).Magnitude();
if (legOne > Precision::Confusion())
{
double legTwo = sqrt(pow(radius, 2) - pow(legOne, 2));
gp_Vec projectionVector(vector2);
projectionVector.Normalize();
projectionVector *= legTwo;
thirdPoint = extrema2Vector + projectionVector;
gp_Vec hyp(thirdPoint - originVector);
hyp.Normalize();
gp_Vec otherSide(loc1 - originVector);
otherSide.Normalize();
}
gp_Vec xAxis = (loc1 - originVector).Normalized();
gp_Vec fakeYAxis = (thirdPoint - originVector).Normalized();
gp_Vec zAxis = (xAxis.Crossed(fakeYAxis)).Normalized();
gp_Vec yAxis = zAxis.Crossed(xAxis).Normalized();
dimSys = SbMatrix
(
xAxis.X(), yAxis.X(), zAxis.X(), dimensionOriginPoint.X(),
xAxis.Y(), yAxis.Y(), zAxis.Y(), dimensionOriginPoint.Y(),
xAxis.Z(), yAxis.Z(), zAxis.Z(), dimensionOriginPoint.Z(),
0.0, 0.0, 0.0, 1.0
);
dimSys = dimSys.transpose();
}
return dimSys;
}
PROPERTY_SOURCE(MeasureGui::ViewProviderMeasureAngle, MeasureGui::ViewProviderMeasureBase)
ViewProviderMeasureAngle::ViewProviderMeasureAngle()
{
sPixmap = "umf-measurement";
// Primary Arc
Gui::ArcEngine *arcEngine = new Gui::ArcEngine();
arcEngine->angle.connectFrom(&fieldAngle);
auto calculatorRadius = new SoCalculator();
calculatorRadius->A.connectFrom(&pDragger->translation);
calculatorRadius->expression.setValue("oa=length(A)");
arcEngine->radius.connectFrom(&calculatorRadius->oa);
arcEngine->deviation.setValue(0.1f);
SoCoordinate3 *coordinates = new SoCoordinate3();
coordinates->point.connectFrom(&arcEngine->points);
SoLineSet *lineSet = new SoLineSet();
lineSet->vertexProperty.setValue(coordinates);
lineSet->numVertices.connectFrom(&arcEngine->pointCount);
lineSet->startIndex.setValue(0);
pLineSeparator->addChild(lineSet);
// Secondary Arc, from midpoint to label
auto engineAngle = new SoCalculator();
engineAngle->A.connectFrom(&arcEngine->midpoint);
engineAngle->B.connectFrom(&pLabelTranslation->translation);
engineAngle->expression.setValue("tA=normalize(A); tB=normalize(B); oa=atan2(tB[1], tB[0])-atan2(tA[1], tA[0])");
Gui::ArcEngine *arcEngineSecondary = new Gui::ArcEngine();
arcEngineSecondary->radius.connectFrom(&calculatorRadius->oa);
arcEngineSecondary->deviation.setValue(0.1f);
arcEngineSecondary->angle.connectFrom(&engineAngle->oa);
// Rotate arc
auto engineRotMidpoint = new SoComposeRotationFromTo(); // absolute angle to midpoint
engineRotMidpoint->from.setValue(SbVec3f(1.0, 0.0, 0.0));
engineRotMidpoint->to.connectFrom(&arcEngine->midpoint);
auto matrixEngine = new SoComposeMatrix();
matrixEngine->rotation.connectFrom(&engineRotMidpoint->rotation);
auto transformEngine = new SoTransformVec3f();
transformEngine->matrix.connectFrom(&matrixEngine->matrix);
transformEngine->vector.connectFrom(&arcEngineSecondary->points);
SoCoordinate3 *coordinatesSecondary = new SoCoordinate3();
coordinatesSecondary->point.connectFrom(&transformEngine->point);
SoLineSet *lineSetSecondary = new SoLineSet();
lineSetSecondary->vertexProperty.setValue(coordinatesSecondary);
lineSetSecondary->numVertices.connectFrom(&arcEngineSecondary->pointCount);
lineSetSecondary->startIndex.setValue(0);
pLineSeparatorSecondary->addChild(lineSetSecondary);
}
void ViewProviderMeasureAngle::redrawAnnotation()
{
auto obj = dynamic_cast<Measure::MeasureAngle*>(getMeasureObject());
double angleDeg = obj->Angle.getValue();
constexpr double radiansPerDegree = M_PI / 180.0;
this->fieldAngle = angleDeg * radiansPerDegree;
// Set matrix
try {
SbMatrix matrix = getMatrix();
pcTransform->setMatrix(matrix);
} catch (const Base::Exception& e) {
Base::Console().Error("Error in ViewProviderMeasureAngle::redrawAnnotation: %s\n", e.what());
return;
}
// Set Label
setLabelValue(static_cast<Measure::MeasureBase*>(pcObject)->getResultString());
}
//! return the feature as a MeasureAngle
Measure::MeasureAngle* ViewProviderMeasureAngle::getMeasureAngle()
{
Measure::MeasureAngle* feature = dynamic_cast<Measure::MeasureAngle*>(pcObject);
if (!feature) {
throw Base::RuntimeError("Feature not found for ViewProviderMeasureAngle");
}
return feature;
}
void ViewProviderMeasureAngle::positionAnno(const Measure::MeasureBase* measureObject) {
(void)measureObject;
setLabelTranslation(SbVec3f(0, 10, 0));
}

View File

@@ -0,0 +1,73 @@
/***************************************************************************
* Copyright (c) 2023 David Friedli <david[at]friedli-be.ch> *
* *
* 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 *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#ifndef GUI_VIEWPROVIDERMEASUREANGLE_H
#define GUI_VIEWPROVIDERMEASUREANGLE_H
#include <Mod/Measure/MeasureGlobal.h>
#include <QObject>
#include <Inventor/fields/SoSFFloat.h>
#include <Inventor/fields/SoSFMatrix.h>
#include <Inventor/fields/SoSFVec3f.h>
#include <Mod/Measure/App/MeasureAngle.h>
#include "ViewProviderMeasureBase.h"
//NOLINTBEGIN
class SoText2;
class SoTranslation;
class SoCoordinate3;
class SoIndexedLineSet;
class SoTransform;
//NOLINTEND
namespace MeasureGui
{
class MeasureGuiExport ViewProviderMeasureAngle : public MeasureGui::ViewProviderMeasureBase
{
PROPERTY_HEADER_WITH_OVERRIDE(MeasureGui::ViewProviderMeasureAngle);
public:
/// Constructor
ViewProviderMeasureAngle();
Measure::MeasureAngle* getMeasureAngle();
void redrawAnnotation() override;
void positionAnno(const Measure::MeasureBase* measureObject) override;
private:
// Fields
SoSFFloat fieldAngle; //radians.
SbMatrix getMatrix();
};
} //namespace MeasureGui
#endif // GUI_VIEWPROVIDERMEASUREANGLE_H

View File

@@ -0,0 +1,597 @@
/***************************************************************************
* Copyright (c) 2023 David Friedli <david[at]friedli-be.ch> *
* *
* 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 *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "Gui/Application.h"
#include "Gui/MDIView.h"
#include "PreCompiled.h"
#ifndef _PreComp_
# include <Inventor/actions/SoGetMatrixAction.h>
# include <Inventor/nodes/SoAnnotation.h>
# include <Inventor/nodes/SoBaseColor.h>
# include <Inventor/nodes/SoCoordinate3.h>
# include <Inventor/nodes/SoCamera.h>
# include <Inventor/nodes/SoDrawStyle.h>
# include <Inventor/nodes/SoIndexedLineSet.h>
# include <Inventor/nodes/SoMarkerSet.h>
# include <Inventor/nodes/SoPickStyle.h>
# include <Inventor/draggers/SoTranslate2Dragger.h>
# include <Inventor/engines/SoComposeMatrix.h>
# include <Inventor/engines/SoTransformVec3f.h>
# include <Inventor/engines/SoConcatenate.h>
#endif
#include <App/DocumentObject.h>
#include <Base/Console.h>
#include <Gui/Document.h>
#include <Gui/ViewParams.h>
#include <Gui/Inventor/MarkerBitmaps.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
#include <Mod/Measure/App/Preferences.h>
#include "ViewProviderMeasureBase.h"
using namespace MeasureGui;
using namespace Measure;
//NOLINTBEGIN
PROPERTY_SOURCE(MeasureGui::ViewProviderMeasureBase, Gui::ViewProviderDocumentObject)
//NOLINTEND
ViewProviderMeasureBase::ViewProviderMeasureBase()
{
static const char *agroup = "Appearance";
//NOLINTBEGIN
ADD_PROPERTY_TYPE(TextColor, (Preferences::defaultTextColor()), agroup, App::Prop_None, "Color for the measurement text");
ADD_PROPERTY_TYPE(TextBackgroundColor, (Preferences::defaultTextBackgroundColor()), agroup, App::Prop_None, "Color for the measurement text background");
ADD_PROPERTY_TYPE(LineColor, (Preferences::defaultLineColor()), agroup, App::Prop_None, "Color for the measurement lines");
ADD_PROPERTY_TYPE(FontSize, (Preferences::defaultFontSize()), agroup, App::Prop_None, "Size of measurement text");
//NOLINTEND
// setupAnnoSceneGraph() - sets up the annotation scene graph
pLabel = new Gui::SoFrameLabel();
pLabel->ref();
pColor = new SoBaseColor();
pColor->ref();
pLabelTranslation = new SoTransform();
pLabelTranslation->ref();
auto ps = getSoPickStyle();
// Dragger
SoSeparator* dragSeparator = new SoSeparator();
pDragger = new SoTranslate2Dragger();
pDragger->ref();
pDraggerOrientation = new SoTransform();
pDraggerOrientation->ref();
dragSeparator->addChild(pDraggerOrientation);
dragSeparator->addChild(pDragger);
// Transform drag location by dragger local orientation and connect to labelTranslation
auto matrixEngine = new SoComposeMatrix();
matrixEngine->rotation.connectFrom(&pDraggerOrientation->rotation);
auto transformEngine = new SoTransformVec3f();
transformEngine->vector.connectFrom(&pDragger->translation);
transformEngine->matrix.connectFrom(&matrixEngine->matrix);
pLabelTranslation->translation.connectFrom(&transformEngine->point);
pTextSeparator = new SoSeparator();
pTextSeparator->ref();
pTextSeparator->addChild(dragSeparator);
pTextSeparator->addChild(pLabelTranslation);
pTextSeparator->addChild(pLabel);
// Empty line separator which can be populated by inherited class
pLineSeparator = new SoSeparator();
pLineSeparator->ref();
pLineSeparator->addChild(ps);
pLineSeparator->addChild(getSoLineStylePrimary());
pLineSeparator->addChild(pColor);
// Secondary line separator
pLineSeparatorSecondary = new SoSeparator();
pLineSeparatorSecondary->ref();
pLineSeparatorSecondary->addChild(ps);
pLineSeparatorSecondary->addChild(getSoLineStyleSecondary());
pLineSeparatorSecondary->addChild(pColor);
pRootSeparator = new SoAnnotation();
pRootSeparator->ref();
pRootSeparator->addChild(pLineSeparator);
pRootSeparator->addChild(pLineSeparatorSecondary);
pRootSeparator->addChild(pTextSeparator);
addDisplayMaskMode(pRootSeparator, "Base");
pRootSeparator->touch();
pTextSeparator->touch();
pLineSeparator->touch();
// Register dragger callback
auto dragger = pDragger;
dragger->addValueChangedCallback(draggerChangedCallback, this);
// Use the label node as the transform handle
SoSearchAction sa;
sa.setInterest(SoSearchAction::FIRST);
sa.setSearchingAll(true);
sa.setNode(pLabel);
sa.apply(pcRoot);
SoPath * labelPath = sa.getPath();
assert(labelPath);
dragger->setPartAsPath("translator", labelPath);
// Hide the dragger feedback during translation
dragger->setPart("translatorActive", NULL);
dragger->setPart("xAxisFeedback", NULL);
dragger->setPart("yAxisFeedback", NULL);
// end setupSceneGraph
// these touches cause onChanged to run which then updates pLabel and pColor with the initial values
TextColor.touch();
TextBackgroundColor.touch();
FontSize.touch();
LineColor.touch();
}
ViewProviderMeasureBase::~ViewProviderMeasureBase()
{
_mVisibilityChangedConnection.disconnect();
pLabel->unref();
pColor->unref();
pDragger->unref();
pDraggerOrientation->unref();
pLabelTranslation->unref();
pTextSeparator->unref();
pLineSeparator->unref();
pRootSeparator->unref();
}
std::vector<std::string> ViewProviderMeasureBase::getDisplayModes() const
{
// add modes
std::vector<std::string> StrList;
StrList.emplace_back("Base");
return StrList;
}
void ViewProviderMeasureBase::setDisplayMode(const char* ModeName)
{
if (strcmp(ModeName, "Base") == 0) {
setDisplayMaskMode("Base");
}
ViewProviderDocumentObject::setDisplayMode(ModeName);
}
void ViewProviderMeasureBase::finishRestoring() {
// Force measurement visibility when loading a document
show();
}
void ViewProviderMeasureBase::onChanged(const App::Property* prop)
{
if (prop == &TextColor) {
const App::Color& color = TextColor.getValue();
pLabel->textColor.setValue(color.r, color.g, color.b);
}
else if (prop == &TextBackgroundColor) {
const App::Color& color = TextBackgroundColor.getValue();
pLabel->backgroundColor.setValue(color.r, color.g, color.b);
}
else if (prop == &LineColor) {
const App::Color& color = LineColor.getValue();
pColor->rgb.setValue(color.r, color.g, color.b);
}
else if (prop == &FontSize) {
pLabel->size = FontSize.getValue();
}
ViewProviderDocumentObject::onChanged(prop);
}
void ViewProviderMeasureBase::draggerChangedCallback(void *data, SoDragger *) {
auto me = static_cast<ViewProviderMeasureBase*>(data);
me->onLabelMoved();
}
void ViewProviderMeasureBase::setLabelValue(const Base::Quantity& value) {
pLabel->string.setValue(value.getUserString().toUtf8().constData());
}
void ViewProviderMeasureBase::setLabelValue(const QString& value) {
auto lines = value.split(QString::fromLatin1("\n"));
int i = 0;
for (auto& it : lines) {
pLabel->string.set1Value(i, it.toUtf8().constData());
i++;
}
}
void ViewProviderMeasureBase::setLabelTranslation(const SbVec3f& position) {
// Set the dragger translation to keep it in sync with pLabelTranslation
pDragger->translation.setValue(position);
}
SoPickStyle* ViewProviderMeasureBase::getSoPickStyle() {
auto ps = new SoPickStyle();
ps->style = SoPickStyle::UNPICKABLE;
return ps;
}
SoDrawStyle* ViewProviderMeasureBase::getSoLineStylePrimary() {
auto style = new SoDrawStyle();
style->lineWidth = 2.0f;
return style;
}
SoDrawStyle* ViewProviderMeasureBase::getSoLineStyleSecondary() {
auto style = new SoDrawStyle();
style->lineWidth = 1.0f;
return style;
}
SoSeparator* ViewProviderMeasureBase::getSoSeparatorText() {
return pTextSeparator;
}
void ViewProviderMeasureBase::positionAnno(const Measure::MeasureBase* measureObject) {
(void)measureObject;
}
void ViewProviderMeasureBase::attach(App::DocumentObject *pcObj)
{
ViewProviderDocumentObject::attach(pcObj);
positionAnno(static_cast<MeasureBase*>(pcObj));
}
//! handle changes to the feature's properties
void ViewProviderMeasureBase::updateData(const App::Property* prop)
{
bool doUpdate = false;
auto obj = getMeasureObject();
if (!obj) {
return;
}
// Check if one of the input properties has been changed
auto inputProps = obj->getInputProps();
if (std::find(inputProps.begin(), inputProps.end(), std::string(prop->getName())) != inputProps.end()) {
doUpdate = true;
// Add connections to be notified when the measured objects are changed
connectToSubject(obj->getSubject());
}
// Check if the result prop has been changed
auto resultProp = obj->getResultProp();
if (resultProp && prop == resultProp){
doUpdate = true;
}
if (doUpdate) {
redrawAnnotation();
}
ViewProviderDocumentObject::updateData(prop);
}
// TODO: should this be pure virtual?
void ViewProviderMeasureBase::redrawAnnotation()
{
// Base::Console().Message("VPMB::redrawAnnotation()\n");
}
//! connect to the subject to receive visibility updates
void ViewProviderMeasureBase::connectToSubject(App::DocumentObject* subject)
{
if (!subject) {
return;
}
// disconnect any existing connection
if (_mVisibilityChangedConnection.connected()) {
_mVisibilityChangedConnection.disconnect();
}
//NOLINTBEGIN
auto bndVisibility = std::bind(&ViewProviderMeasureBase::onSubjectVisibilityChanged, this, std::placeholders::_1, std::placeholders::_2);
//NOLINTEND
_mVisibilityChangedConnection = subject->signalChanged.connect(bndVisibility);
}
//! connect to the subject to receive visibility updates
void ViewProviderMeasureBase::connectToSubject(std::vector<App::DocumentObject*> subject)
{
if (subject.empty()) {
return;
}
// TODO: should we connect to all the subject objects when there is >1?
auto proxy = subject.front();
connectToSubject(proxy);
}
//! retrieve the feature
Measure::MeasureBase* ViewProviderMeasureBase::getMeasureObject()
{
// Note: Cast to MeasurePropertyBase once we use it to provide the needed values e.g. basePosition textPosition etc.
auto feature = dynamic_cast<Measure::MeasureBase*>(pcObject);
if (!feature) {
throw Base::RuntimeError("Feature not found for ViewProviderMeasureBase");
}
return feature;
}
//! calculate a good direction from the elements being measured to the annotation text based on the layout
//! of the elements and relationship with the cardinal axes and the view direction. elementDirection
//! is expected to be a normalized vector.
//! an example of an elementDirection would be the vector from the start of a line to the end.
Base::Vector3d ViewProviderMeasureBase::getTextDirection(Base::Vector3d elementDirection, double tolerance)
{
// TODO: this can fail if the active view is not a 3d view (spreadsheet, techdraw page) and something causes a measure to try to update
// we need to search through the mdi views for a 3d view and take the direction from it (or decide that if the active view is not 3d,
// assume we are looking from the front).
Base::Vector3d viewDirection;
Base::Vector3d upDirection;
Gui::View3DInventor* view = nullptr;
try {
view = dynamic_cast<Gui::View3DInventor*>(this->getActiveView());
} catch (const Base::RuntimeError& e) {
Base::Console().Log("ViewProviderMeasureBase::getTextDirection: Could not get active view\n");
}
if (view) {
Gui::View3DInventorViewer* viewer = view->getViewer();
viewDirection = toVector3d(viewer->getViewDirection()).Normalize();
upDirection = toVector3d(viewer->getUpDirection()).Normalize();
// Measure doesn't work with this kind of active view. Might be dependency graph, might be TechDraw, or ????
//throw Base::RuntimeError("Measure doesn't work with this kind of active view.");
} else {
viewDirection = Base::Vector3d(0.0, 1.0, 0.0);
upDirection = Base::Vector3d(0.0, 0.0, 1.0);
}
Base::Vector3d textDirection = elementDirection.Cross(viewDirection);
if (textDirection.Length() < tolerance) {
// either elementDirection and viewDirection are parallel or one of them is null.
textDirection = elementDirection.Cross(upDirection);
}
return textDirection.Normalize();
}
//! true if the subject of this measurement is visible. For Measures that have multiple object subject,
//! all of the subjects must be visible.
bool ViewProviderMeasureBase::isSubjectVisible()
{
Gui::Document* guiDoc = nullptr;
try {
guiDoc = this->getDocument();
} catch (const Base::RuntimeError& e) {
Base::Console().Log("ViewProviderMeasureBase::isSubjectVisible: Could not get document\n");
return false;
}
// we need these things to proceed
if (!getMeasureObject() ||
getMeasureObject()->getSubject().empty() ||
!guiDoc ) {
return false;
}
for (auto & obj : getMeasureObject()->getSubject()) {
Gui::ViewProvider* vp = guiDoc->getViewProvider(obj);
if (!vp || !vp->isVisible()) {
return false;
}
}
// all of the subject objects are visible
return true;
}
//! gets called when the subject object issues a signalChanged (ie a property change). We are only interested in the subject's
//! Visibility property
void ViewProviderMeasureBase::onSubjectVisibilityChanged(const App::DocumentObject& docObj, const App::Property& prop)
{
if (docObj.isRemoving()) {
return;
}
std::string propName = prop.getName();
if (propName == "Visibility") {
if (!docObj.Visibility.getValue()) {
// show ourselves only if subject is visible
setVisible(false);
} else {
// here, we don't know if we should be visible or not, so we have to check the whole subject
setVisible(isSubjectVisible());
}
}
}
//NOLINTBEGIN
PROPERTY_SOURCE(MeasureGui::ViewProviderMeasure, MeasureGui::ViewProviderMeasureBase)
//NOLINTEND
//! the general purpose view provider. handles area, length, etc - any measure without a specialized VP
ViewProviderMeasure::ViewProviderMeasure()
{
sPixmap = "umf-measurement";
// setupSceneGraph for leader?
const size_t lineCount(3);
// indexes used to create the edges
// this makes a line from verts[0] to verts[1]
static const int32_t lines[lineCount] =
{
0,1,-1
};
pCoords = new SoCoordinate3();
pCoords->ref();
// Combine coordinates from baseTranslation and labelTranslation
auto engineCat = new SoConcatenate(SoMFVec3f::getClassTypeId());
auto origin = new SoSFVec3f();
origin->setValue(0,0,0);
engineCat->input[0]->connectFrom(origin);
engineCat->input[1]->connectFrom(&pLabelTranslation->translation);
pCoords->point.setNum(engineCat->output->getNumConnections());
pCoords->point.connectFrom(engineCat->output);
pLines = new SoIndexedLineSet();
pLines->ref();
pLines->coordIndex.setNum(lineCount);
pLines->coordIndex.setValues(0, lineCount, lines);
auto lineSep = pLineSeparator;
lineSep->addChild(pCoords);
lineSep->addChild(pLines);
auto points = new SoMarkerSet();
points->markerIndex = Gui::Inventor::MarkerBitmaps::getMarkerIndex("CROSS",
Gui::ViewParams::instance()->getMarkerSize());
points->numPoints=1;
lineSep->addChild(points);
// Connect dragger local orientation to view orientation
Gui::View3DInventor* view = nullptr;
try {
view = dynamic_cast<Gui::View3DInventor*>(this->getActiveView());
} catch (const Base::RuntimeError& e) {
Base::Console().Log("ViewProviderMeasure::ViewProviderMeasure: Could not get active view\n");
}
if (view) {
Gui::View3DInventorViewer* viewer = view->getViewer();
auto renderManager = viewer->getSoRenderManager();
auto cam = renderManager->getCamera();
pDraggerOrientation->rotation.connectFrom(&cam->orientation);
}
}
ViewProviderMeasure::~ViewProviderMeasure()
{
pCoords->unref();
pLines->unref();
}
void ViewProviderMeasure::positionAnno(const Measure::MeasureBase* measureObject) {
(void)measureObject;
// Initialize the text position
Base::Vector3d textPos = getTextPosition();
auto srcVec = SbVec3f(textPos.x, textPos.y, textPos.z);
// Translate the position by the local dragger matrix (pDraggerOrientation)
Gui::View3DInventor* view = nullptr;
try {
view = dynamic_cast<Gui::View3DInventor*>(this->getActiveView());
} catch (const Base::RuntimeError& e) {
Base::Console().Log("ViewProviderMeasure::positionAnno: Could not get active view\n");
}
if(!view){
return;
}
Gui::View3DInventorViewer* viewer = view->getViewer();
auto gma = SoGetMatrixAction(viewer->getSoRenderManager()->getViewportRegion());
gma.apply(pDraggerOrientation);
auto mat = gma.getMatrix();
SbVec3f destVec(0, 0, 0);
mat.multVecMatrix(srcVec, destVec);
setLabelTranslation(destVec);
updateView();
}
void ViewProviderMeasure::onChanged(const App::Property* prop)
{
if (pcObject == nullptr) {
return;
}
ViewProviderMeasureBase::onChanged(prop);
}
//! repaint the annotation
void ViewProviderMeasure::redrawAnnotation()
{
// point on element
Base::Vector3d basePos = getBasePosition();
pcTransform->translation.setValue(SbVec3f(basePos.x, basePos.y, basePos.z));
setLabelValue(getMeasureObject()->getResultString());
ViewProviderMeasureBase::redrawAnnotation();
ViewProviderDocumentObject::updateView();
}
Base::Vector3d ViewProviderMeasure::getBasePosition(){
auto measureObject = getMeasureObject();
Base::Placement placement = measureObject->getPlacement();
return placement.getPosition();
}
Base::Vector3d ViewProviderMeasure::getTextPosition(){
constexpr float DefaultLeaderLength{20.0};
auto basePoint = getBasePosition();
Base::Vector3d textDirection(1.0, 1.0, 1.0);
textDirection.Normalize();
return basePoint + textDirection * DefaultLeaderLength;
}
//! called by the system when it is time to display this measure
void ViewProviderMeasureBase::show()
{
if (isSubjectVisible()) {
// only show the annotation if the subject is visible.
// this avoids disconnected annotations floating in space.
ViewProviderDocumentObject::show();
}
}

View File

@@ -0,0 +1,159 @@
/***************************************************************************
* Copyright (c) 2023 David Friedli <david[at]friedli-be.ch> *
* *
* 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 *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#ifndef GUI_VIEWPROVIDER_MEASUREMENTBASE_H
#define GUI_VIEWPROVIDER_MEASUREMENTBASE_H
#include <Mod/Measure/MeasureGlobal.h>
#include <QString>
#include <App/Application.h>
#include <App/PropertyStandard.h>
#include <Base/Parameter.h>
#include <Gui/ViewProviderDocumentObject.h>
#include <Gui/SoTextLabel.h>
#include <Mod/Measure/App/MeasureBase.h>
//NOLINTBEGIN
class SbVec2s;
class SoFontStyle;
class SoBaseColor;
class SoText2;
class SoTranslation;
class SoPickStyle;
class SoCoordinate3;
class SoIndexedLineSet;
class SoTranslate2Dragger;
//NOLINTEND
namespace MeasureGui {
//NOLINTBEGIN
class MeasureGuiExport ViewProviderMeasureBase :public Gui::ViewProviderDocumentObject
{
PROPERTY_HEADER_WITH_OVERRIDE(ViewProviderMeasureBase);
public:
/// constructor.
ViewProviderMeasureBase();
/// destructor.
~ViewProviderMeasureBase() override;
// Display properties
App::PropertyColor TextColor;
App::PropertyColor TextBackgroundColor;
App::PropertyColor LineColor;
App::PropertyInteger FontSize;
//NOLINTEND
/**
* Attaches the document object to this view provider.
*/
bool isPartOfPhysicalObject() const override {return false;};
void attach(App::DocumentObject *pcObj) override;
void updateData(const App::Property* prop) override;
virtual void positionAnno(const Measure::MeasureBase* measureObject);
void finishRestoring() override;
bool useNewSelectionModel() const override {return true;}
std::vector<std::string> getDisplayModes() const override;
void setDisplayMode(const char* ModeName) override;
/// Show the annotation in the 3d window
void show() override;
virtual void redrawAnnotation();
Measure::MeasureBase* getMeasureObject();
virtual bool isSubjectVisible();
static Base::Vector3d toVector3d(SbVec3f svec) { return Base::Vector3d(svec[0], svec[1], svec[2]); }
static SbVec3f toSbVec3f(Base::Vector3d vec3) { return SbVec3f(vec3.x, vec3.y, vec3.z); }
void onSubjectVisibilityChanged(const App::DocumentObject& docObj, const App::Property& prop);
void connectToSubject(App::DocumentObject* subject);
void connectToSubject(std::vector<App::DocumentObject*> subject);
protected:
static void draggerChangedCallback(void* data, SoDragger*);
void onChanged(const App::Property* prop) override;
virtual void onLabelMoved() {};
void setLabelValue(const Base::Quantity& value);
void setLabelValue(const QString& value);
void setLabelTranslation(const SbVec3f& position);
SoPickStyle* getSoPickStyle();
SoDrawStyle* getSoLineStylePrimary();
SoDrawStyle* getSoLineStyleSecondary();
SoSeparator* getSoSeparatorText();
static constexpr double defaultTolerance = 10e-6;
virtual Base::Vector3d getTextDirection(Base::Vector3d elementDirection, double tolerance = defaultTolerance);
// TODO: getters & setters and move variables to private?
bool _mShowTree = true;
Gui::SoFrameLabel * pLabel;
SoTranslate2Dragger* pDragger;
SoTransform* pDraggerOrientation;
SoTransform * pLabelTranslation;
SoBaseColor * pColor;
SoSeparator* pRootSeparator;
SoSeparator* pTextSeparator;
SoSeparator* pLineSeparator;
SoSeparator* pLineSeparatorSecondary;
private:
boost::signals2::connection _mVisibilityChangedConnection;
};
//NOLINTBEGIN
class MeasureGuiExport ViewProviderMeasure : public MeasureGui::ViewProviderMeasureBase
{
PROPERTY_HEADER_WITH_OVERRIDE(MeasureGui::ViewProviderMeasure);
//NOLINTEND
public:
/// Constructor
ViewProviderMeasure();
~ViewProviderMeasure() override;
void redrawAnnotation() override;
void positionAnno(const Measure::MeasureBase* measureObject) override;
protected:
void onChanged(const App::Property* prop) override;
virtual Base::Vector3d getBasePosition();
virtual Base::Vector3d getTextPosition();
private:
SoCoordinate3 * pCoords;
SoIndexedLineSet * pLines;
};
} // namespace Gui
#endif // GUI_VIEWPROVIDER_MEASUREMENTBASE_H

View File

@@ -0,0 +1,222 @@
/***************************************************************************
* Copyright (c) 2023 David Friedli <david[at]friedli-be.ch> *
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* 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 *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <sstream>
# include <QApplication>
# include <Inventor/engines/SoCalculator.h>
# include <Inventor/engines/SoConcatenate.h>
# include <Inventor/nodes/SoAnnotation.h>
# include <Inventor/nodes/SoBaseColor.h>
# include <Inventor/nodes/SoCoordinate3.h>
# include <Inventor/nodes/SoDrawStyle.h>
# include <Inventor/nodes/SoFontStyle.h>
# include <Inventor/nodes/SoIndexedLineSet.h>
# include <Inventor/nodes/SoMarkerSet.h>
# include <Inventor/nodes/SoPickStyle.h>
# include <Inventor/nodes/SoText2.h>
# include <Inventor/nodes/SoTranslation.h>
#endif
#include <Gui/Inventor/MarkerBitmaps.h>
#include <App/Document.h>
#include <App/MeasureDistance.h>
#include <Base/Console.h>
#include <Base/Quantity.h>
#include "Mod/Measure/App/MeasureDistance.h"
#include <Mod/Measure/App/Preferences.h>
#include "ViewProviderMeasureDistance.h"
#include "Gui/Application.h"
#include <Gui/Command.h>
#include "Gui/Document.h"
#include "Gui/ViewParams.h"
using namespace Gui;
using namespace MeasureGui;
using namespace Measure;
PROPERTY_SOURCE(MeasureGui::ViewProviderMeasureDistance, MeasureGui::ViewProviderMeasureBase)
SbMatrix ViewProviderMeasureDistance::getMatrix() {
auto object = dynamic_cast<Measure::MeasureDistance*>(getObject());
auto vec1 = object->Position1.getValue();
auto vec2 = object->Position2.getValue();
const double tolerance(10.0e-6);
SbVec3f origin = toSbVec3f((vec2 + vec1) / 2);
Base::Vector3d localXAxis = (vec2 - vec1).Normalize();
Base::Vector3d localYAxis = getTextDirection(localXAxis, tolerance).Normalize();
// X and Y axis have to be 90° to eachother
assert(fabs(localYAxis.Dot(localXAxis)) < tolerance);
Base::Vector3d localZAxis = localYAxis.Cross(localXAxis).Normalize();
SbMatrix matrix = SbMatrix(
localXAxis.x, localXAxis.y, localXAxis.z, 0,
localYAxis.x, localYAxis.y, localYAxis.z ,0,
localZAxis.x, localZAxis.y, localZAxis.z, 0,
// 0,0,0,1
origin[0], origin[1], origin[2], 1
);
return matrix;
}
//! calculate a good direction from the elements being measured to the annotation text based on the layout
//! of the elements and its relationship with the cardinal axes and the view direction. elementDirection
//! is expected to be a normalized vector.
//! an example of an elementDirection would be the vector from the start of a line to the end.
Base::Vector3d ViewProviderMeasureDistance::getTextDirection(Base::Vector3d elementDirection, double tolerance)
{
const Base::Vector3d stdX(1.0, 0.0, 0.0);
const Base::Vector3d stdY(0.0, 1.0, 0.0);
const Base::Vector3d stdZ(0.0, 0.0, 1.0);
Base::Vector3d textDirection = elementDirection.Cross(stdX);
if (textDirection.Length() < tolerance) {
textDirection = elementDirection.Cross(stdY);
}
if (textDirection.Length() < tolerance) {
textDirection = elementDirection.Cross(stdZ);
}
textDirection.Normalize();
if (textDirection.Dot(stdZ) < 0.0) {
textDirection = textDirection * -1.0;
}
return textDirection.Normalize();
}
ViewProviderMeasureDistance::ViewProviderMeasureDistance()
{
sPixmap = "umf-measurement";
// vert indexes used to create the annotation lines
const size_t lineCount(3);
static const int32_t lines[lineCount] =
{
2,3,-1 // dimension line
};
const size_t lineCountSecondary(9);
static const int32_t linesSecondary[lineCountSecondary] = {
0,2,-1, // extension line 1
1,3,-1, // extension line 2
2,4,-1 // label helper line
};
// Line Coordinates
// 0-1 points on shape (dimension points)
// 2-3 ends of extension lines/dimension line
// 4 label position
pCoords = new SoCoordinate3();
pCoords->ref();
auto engineCoords = new SoCalculator();
engineCoords->a.connectFrom(&fieldDistance);
engineCoords->A.connectFrom(&pLabelTranslation->translation);
engineCoords->expression.setValue("ta=a/2; tb=A[1]; oA=vec3f(ta, 0, 0); oB=vec3f(-ta, 0, 0); "
"oC=vec3f(ta, tb, 0); oD=vec3f(-ta, tb, 0)");
auto engineCat = new SoConcatenate(SoMFVec3f::getClassTypeId());
engineCat->input[0]->connectFrom(&engineCoords->oA);
engineCat->input[1]->connectFrom(&engineCoords->oB);
engineCat->input[2]->connectFrom(&engineCoords->oC);
engineCat->input[3]->connectFrom(&engineCoords->oD);
engineCat->input[4]->connectFrom(&pLabelTranslation->translation);
pCoords->point.connectFrom(engineCat->output);
pCoords->point.setNum(engineCat->output->getNumConnections());
pLines = new SoIndexedLineSet();
pLines->ref();
pLines->coordIndex.setNum(lineCount);
pLines->coordIndex.setValues(0, lineCount, lines);
pLineSeparator->addChild(pCoords);
pLineSeparator->addChild(pLines);
// Secondary Lines
auto lineSetSecondary = new SoIndexedLineSet();
lineSetSecondary->coordIndex.setNum(lineCountSecondary);
lineSetSecondary->coordIndex.setValues(0, lineCountSecondary, linesSecondary);
pLineSeparatorSecondary->addChild(pCoords);
pLineSeparatorSecondary->addChild(lineSetSecondary);
auto points = new SoMarkerSet();
points->markerIndex = Gui::Inventor::MarkerBitmaps::getMarkerIndex("CROSS",
ViewParams::instance()->getMarkerSize());
points->numPoints=2;
pLineSeparator->addChild(points);
}
ViewProviderMeasureDistance::~ViewProviderMeasureDistance()
{
pCoords->unref();
pLines->unref();
}
Measure::MeasureDistance* ViewProviderMeasureDistance::getMeasureDistance()
{
Measure::MeasureDistance* feature = dynamic_cast<Measure::MeasureDistance*>(pcObject);
if (!feature) {
throw Base::RuntimeError("Feature not found for ViewProviderMeasureDistance");
}
return feature;
}
//! repaint the annotation
void ViewProviderMeasureDistance::redrawAnnotation()
{
auto object = dynamic_cast<Measure::MeasureDistance*>(getObject());
auto vec1 = object->Position1.getValue();
auto vec2 = object->Position2.getValue();
// Set the distance
fieldDistance = (vec2 - vec1).Length();
setLabelValue(object->Distance.getQuantityValue().getUserString());
// Set matrix
SbMatrix matrix = getMatrix();
pcTransform->setMatrix(matrix);
ViewProviderMeasureBase::redrawAnnotation();
updateView();
}
void ViewProviderMeasureDistance::positionAnno(const Measure::MeasureBase* measureObject) {
(void)measureObject;
setLabelTranslation(SbVec3f(0, 10, 0));
}

View File

@@ -0,0 +1,69 @@
/***************************************************************************
* Copyright (c) 2023 David Friedli <david[at]friedli-be.ch> *
* *
* 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 *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#ifndef MEASUREGUI_VIEWPROVIDERMEASUREDISTANCE_H
#define MEASUREGUI_VIEWPROVIDERMEASUREDISTANCE_H
#include <Mod/Measure/MeasureGlobal.h>
#include <QObject>
#include <Mod/Measure/App/MeasureDistance.h>
#include "ViewProviderMeasureBase.h"
class SoCoordinate3;
class SoIndexedLineSet;
namespace MeasureGui
{
class MeasureGuiExport ViewProviderMeasureDistance : public MeasureGui::ViewProviderMeasureBase
{
PROPERTY_HEADER_WITH_OVERRIDE(MeasureGui::ViewProviderMeasureDistance);
public:
/// Constructor
ViewProviderMeasureDistance();
~ViewProviderMeasureDistance() override;
Measure::MeasureDistance* getMeasureDistance();
void redrawAnnotation() override;
void positionAnno(const Measure::MeasureBase* measureObject) override;
protected:
Base::Vector3d getTextDirection(Base::Vector3d elementDirection, double tolerance = defaultTolerance) override;
private:
SoCoordinate3 * pCoords;
SoIndexedLineSet * pLines;
SoSFFloat fieldDistance;
SbMatrix getMatrix();
};
} //namespace MeasureGui
#endif // MEASUREGUI_VIEWPROVIDERMEASUREDISTANCE_H