Merge pull request #9750 from hlorus/gsoc2023_measure
GSoC 2023: Unified Measurement Facility
@@ -130,6 +130,7 @@ macro(InitializeFreeCADBuildOptions)
|
||||
option(BUILD_SPREADSHEET "Build the FreeCAD spreadsheet module" ON)
|
||||
option(BUILD_START "Build the FreeCAD start module" ON)
|
||||
option(BUILD_TEST "Build the FreeCAD test module" ON)
|
||||
option(BUILD_MEASURE "Build the FreeCAD Measure module" ON)
|
||||
option(BUILD_TECHDRAW "Build the FreeCAD Technical Drawing module" ON)
|
||||
option(BUILD_TUX "Build the FreeCAD Tux module" ON)
|
||||
option(BUILD_WEB "Build the FreeCAD Web module" ON)
|
||||
|
||||
@@ -118,6 +118,7 @@ macro(PrintFinalReport)
|
||||
value(BUILD_SPREADSHEET)
|
||||
value(BUILD_START)
|
||||
value(BUILD_SURFACE)
|
||||
value(BUILD_MEASURE)
|
||||
value(BUILD_TECHDRAW)
|
||||
value(BUILD_TEST)
|
||||
value(BUILD_TUX)
|
||||
|
||||
@@ -103,6 +103,7 @@
|
||||
#include "VarSet.h"
|
||||
#include "MaterialObject.h"
|
||||
#include "MeasureDistance.h"
|
||||
#include "MeasureManagerPy.h"
|
||||
#include "Origin.h"
|
||||
#include "OriginFeature.h"
|
||||
#include "OriginGroupExtension.h"
|
||||
@@ -315,6 +316,8 @@ void Application::setupPythonTypes()
|
||||
Base::Interpreter().addType(&App::MaterialPy::Type, pAppModule, "Material");
|
||||
Base::Interpreter().addType(&App::MetadataPy::Type, pAppModule, "Metadata");
|
||||
|
||||
Base::Interpreter().addType(&App::MeasureManagerPy::Type, pAppModule, "MeasureManager");
|
||||
|
||||
Base::Interpreter().addType(&App::StringHasherPy::Type, pAppModule, "StringHasher");
|
||||
Base::Interpreter().addType(&App::StringIDPy::Type, pAppModule, "StringID");
|
||||
|
||||
|
||||
@@ -97,6 +97,7 @@ generate_from_xml(StringIDPy)
|
||||
generate_from_xml(ComplexGeoDataPy)
|
||||
generate_from_xml(PropertyContainerPy)
|
||||
generate_from_xml(MaterialPy)
|
||||
generate_from_xml(MeasureManagerPy)
|
||||
|
||||
generate_from_py(FreeCADInit InitScript.h)
|
||||
generate_from_py(FreeCADTest TestScript.h)
|
||||
@@ -119,6 +120,7 @@ SET(FreeCADApp_XML_SRCS
|
||||
PropertyContainerPy.xml
|
||||
ComplexGeoDataPy.xml
|
||||
MaterialPy.xml
|
||||
MeasureManagerPy.xml
|
||||
StringHasherPy.xml
|
||||
StringIDPy.xml
|
||||
)
|
||||
@@ -283,6 +285,8 @@ SET(FreeCADApp_CPP_SRCS
|
||||
MappedName.cpp
|
||||
Material.cpp
|
||||
MaterialPyImp.cpp
|
||||
MeasureManager.cpp
|
||||
MeasureManagerPyImp.cpp
|
||||
Metadata.cpp
|
||||
MetadataPyImp.cpp
|
||||
ElementNamingUtils.cpp
|
||||
@@ -307,6 +311,7 @@ SET(FreeCADApp_HPP_SRCS
|
||||
MappedName.h
|
||||
MappedElement.h
|
||||
Material.h
|
||||
MeasureManager.h
|
||||
Metadata.h
|
||||
ElementNamingUtils.h
|
||||
StringHasher.h
|
||||
|
||||
180
src/App/MeasureManager.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Friedli <david@friedli-be.ch> *
|
||||
* Copyright (c) 2023 Wandererfan <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 <Base/Console.h>
|
||||
#include <Base/Interpreter.h>
|
||||
#include <Base/VectorPy.h>
|
||||
#include <App/Document.h>
|
||||
|
||||
#include "MeasureManager.h"
|
||||
|
||||
namespace App {
|
||||
|
||||
std::vector<MeasureHandler> MeasureManager::_mMeasureHandlers;
|
||||
std::vector<MeasureType*> MeasureManager::_mMeasureTypes;
|
||||
|
||||
MeasureManager::MeasureManager()
|
||||
{
|
||||
// Constructor implementation
|
||||
}
|
||||
|
||||
|
||||
void MeasureManager::addMeasureHandler(const char* module, MeasureTypeMethod typeCb) {
|
||||
auto item = new MeasureHandler{module, typeCb};
|
||||
_mMeasureHandlers.push_back(*item);
|
||||
}
|
||||
|
||||
bool MeasureManager::hasMeasureHandler(const char* module) {
|
||||
for(MeasureHandler& handler : _mMeasureHandlers) {
|
||||
if (strcmp(handler.module.c_str(), module) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MeasureHandler MeasureManager::getMeasureHandler(const char* module) {
|
||||
for(MeasureHandler handler : _mMeasureHandlers) {
|
||||
if (!strcmp(handler.module.c_str(), module)) {
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
|
||||
MeasureHandler empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
void MeasureManager::addMeasureType(MeasureType* measureType) {
|
||||
_mMeasureTypes.push_back(measureType);
|
||||
}
|
||||
|
||||
void MeasureManager::addMeasureType(std::string id, std::string label, std::string measureObj, MeasureValidateMethod validatorCb, MeasurePrioritizeMethod prioritizeCb) {
|
||||
MeasureType* mType = new MeasureType{id, label, measureObj, validatorCb, prioritizeCb, false, nullptr};
|
||||
_mMeasureTypes.push_back(mType);
|
||||
}
|
||||
|
||||
void MeasureManager::addMeasureType(const char* id, const char* label, const char* measureObj, MeasureValidateMethod validatorCb, MeasurePrioritizeMethod prioritizeCb) {
|
||||
addMeasureType(std::string(id), std::string(label), std::string(measureObj), validatorCb, prioritizeCb);
|
||||
}
|
||||
|
||||
const std::vector<MeasureType*> MeasureManager::getMeasureTypes() {
|
||||
return _mMeasureTypes;
|
||||
}
|
||||
|
||||
|
||||
Py::Tuple MeasureManager::getSelectionPy(const App::MeasureSelection& selection) {
|
||||
// Convert selection to python list
|
||||
Py::Tuple selectionPy(selection.size());
|
||||
|
||||
int i = 0;
|
||||
for (auto it : selection) {
|
||||
|
||||
Py::Dict sel;
|
||||
sel.setItem("object", Py::asObject(it.object.getObject()->getPyObject()));
|
||||
sel.setItem("subName", Py::String(it.object.getSubName()));
|
||||
sel.setItem("pickedPoint", Py::asObject(new Base::VectorPy(it.pickedPoint)));
|
||||
|
||||
selectionPy.setItem(i, sel);
|
||||
|
||||
i++;
|
||||
}
|
||||
return selectionPy;
|
||||
}
|
||||
|
||||
|
||||
std::vector<MeasureType*> MeasureManager::getValidMeasureTypes(App::MeasureSelection selection, std::string mode) {
|
||||
Base::PyGILStateLocker lock;
|
||||
|
||||
// Convert selection to python list
|
||||
Py::Tuple selectionPy = getSelectionPy(selection);
|
||||
|
||||
// Store valid measure types
|
||||
std::vector<MeasureType*> validTypes;
|
||||
std::pair<int, MeasureType>();
|
||||
|
||||
|
||||
// Loop through measure types and check if they work with given selection
|
||||
for (App::MeasureType* mType : getMeasureTypes()){
|
||||
|
||||
if (mode != "" && mType->label != mode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (mType->isPython) {
|
||||
// Parse Python measure types
|
||||
auto measurePyClass = Py::Object(mType->pythonClass);
|
||||
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, selectionPy);
|
||||
|
||||
Py::Object isValid;
|
||||
try {
|
||||
isValid = measurePyClass.callMemberFunction(std::string("isValidSelection"), args);
|
||||
} catch (const Py::Exception&) {
|
||||
Base::PyException e;
|
||||
e.ReportException();
|
||||
isValid = Py::False();
|
||||
}
|
||||
|
||||
if (isValid.as_bool()) {
|
||||
|
||||
// Check priority
|
||||
Py::Object isPriority;
|
||||
try {
|
||||
isPriority = measurePyClass.callMemberFunction("isPrioritySelection", args);
|
||||
} catch (const Py::Exception&) {
|
||||
Base::PyException e;
|
||||
e.ReportException();
|
||||
isPriority = Py::False();
|
||||
}
|
||||
|
||||
if (isPriority.as_bool()) {
|
||||
validTypes.insert(validTypes.begin(), mType);
|
||||
} else {
|
||||
validTypes.push_back(mType);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Parse c++ measure types
|
||||
|
||||
if (mType->validatorCb && !mType->validatorCb(selection)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the measurement type prioritizes the given selection
|
||||
if (mType->prioritizeCb && mType->prioritizeCb(selection)) {
|
||||
validTypes.insert(validTypes.begin(), mType);
|
||||
} else {
|
||||
validTypes.push_back(mType);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return validTypes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace App
|
||||
112
src/App/MeasureManager.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Friedli <david@friedli-be.ch> *
|
||||
* Copyright (c) 2023 Wandererfan <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 MEASUREMANAGER_H
|
||||
#define MEASUREMANAGER_H
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <Python.h>
|
||||
#include <App/DocumentObject.h>
|
||||
#include <Base/Vector3D.h>
|
||||
#include <App/DocumentObserver.h>
|
||||
#include <Base/Interpreter.h>
|
||||
|
||||
#include <FCGlobal.h>
|
||||
|
||||
namespace App {
|
||||
|
||||
// Add your class methods and member variables here
|
||||
enum class MeasureElementType {
|
||||
INVALID,
|
||||
POINT,
|
||||
LINE,
|
||||
LINESEGMENT,
|
||||
CIRCLE,
|
||||
ARC,
|
||||
CURVE, // Has a length but no radius or axis
|
||||
PLANE,
|
||||
CYLINDER,
|
||||
Volume,
|
||||
};
|
||||
|
||||
|
||||
struct MeasureSelectionItem {
|
||||
App::SubObjectT object;
|
||||
Base::Vector3d pickedPoint;
|
||||
};
|
||||
|
||||
|
||||
using MeasureSelection = std::vector<MeasureSelectionItem>;
|
||||
using MeasureValidateMethod = std::function<bool(const MeasureSelection&)>;
|
||||
using MeasurePrioritizeMethod = std::function<bool(const MeasureSelection&)>;
|
||||
using MeasureTypeMethod = std::function<MeasureElementType (App::DocumentObject*, const char*)>;
|
||||
|
||||
struct MeasureType {
|
||||
std::string identifier;
|
||||
std::string label;
|
||||
std::string measureObject;
|
||||
|
||||
// Checks if the measurement works with a given selection
|
||||
MeasureValidateMethod validatorCb;
|
||||
|
||||
// Allows to prioritize this over other measurement types when the measurement type is picked implicitly from the selection.
|
||||
// Gets called only when validatorCb returned true for the given selection
|
||||
MeasurePrioritizeMethod prioritizeCb;
|
||||
|
||||
bool isPython;
|
||||
PyObject* pythonClass;
|
||||
};
|
||||
|
||||
struct MeasureHandler {
|
||||
std::string module;
|
||||
MeasureTypeMethod typeCb;
|
||||
};
|
||||
|
||||
|
||||
class AppExport MeasureManager {
|
||||
public:
|
||||
MeasureManager();
|
||||
|
||||
static void addMeasureHandler(const char* module, MeasureTypeMethod typeCb);
|
||||
static bool hasMeasureHandler(const char* module);
|
||||
static MeasureHandler getMeasureHandler(const char* module);
|
||||
static void addMeasureType(MeasureType* measureType);
|
||||
static void addMeasureType(std::string id, std::string label, std::string measureObj, MeasureValidateMethod validatorCb, MeasurePrioritizeMethod prioritizeCb);
|
||||
static void addMeasureType(const char* id, const char* label, const char* measureObj, MeasureValidateMethod validatorCb, MeasurePrioritizeMethod prioritizeCb);
|
||||
static const std::vector<MeasureType*> getMeasureTypes();
|
||||
static Py::Tuple getSelectionPy(const App::MeasureSelection& selection);
|
||||
static std::vector<MeasureType*> getValidMeasureTypes(App::MeasureSelection selection, std::string mode);
|
||||
|
||||
|
||||
private:
|
||||
static std::vector<MeasureHandler> _mMeasureHandlers;
|
||||
static std::vector<MeasureType*> _mMeasureTypes;
|
||||
};
|
||||
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // MEASUREMANAGER_H
|
||||
43
src/App/MeasureManagerPy.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="PyObjectBase"
|
||||
Name="MeasureManagerPy"
|
||||
Twin="MeasureManager"
|
||||
TwinPointer="MeasureManager"
|
||||
Include="App/MeasureManager.h"
|
||||
FatherInclude="Base/PyObjectBase.h"
|
||||
Namespace="App"
|
||||
Constructor="false"
|
||||
Delete="true"
|
||||
FatherNamespace="Base">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="David Friedli" EMail="david@friedli-be.ch" />
|
||||
<UserDocu>MeasureManager class.
|
||||
|
||||
The MeasureManager handles measure types and geometry handler accross FreeCAD.</UserDocu>
|
||||
<DeveloperDocu>MeasureManager</DeveloperDocu>
|
||||
</Documentation>
|
||||
<Methode Name="addMeasureType" Static="true">
|
||||
<Documentation>
|
||||
<UserDocu>addMeasureType(id, label, measureType) -> None
|
||||
|
||||
Add a new measure type.
|
||||
|
||||
id : str
|
||||
Unique identifier of the measure type.
|
||||
label : str
|
||||
Name of the module.
|
||||
measureType : Measure.MeasureBasePython
|
||||
The actual measure type.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getMeasureTypes" Static="true">
|
||||
<Documentation>
|
||||
<UserDocu>getMeasureTypes() -> List[(id, label, pythonMeasureType)]
|
||||
|
||||
Returns a list of all registered measure types.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
79
src/App/MeasureManagerPyImp.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Friedli <david@friedli-be.ch> *
|
||||
* Copyright (c) 2023 Wandererfan <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"
|
||||
|
||||
// inclusion of the generated files (generated out of MeasureManagerPy.xml)
|
||||
#include "MeasureManagerPy.h"
|
||||
#include "MeasureManagerPy.cpp"
|
||||
|
||||
|
||||
using namespace App;
|
||||
|
||||
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string MeasureManagerPy::representation() const
|
||||
{
|
||||
return "<App::MeasureManager>";
|
||||
}
|
||||
|
||||
PyObject* MeasureManagerPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int MeasureManagerPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PyObject* MeasureManagerPy::addMeasureType(PyObject *args)
|
||||
{
|
||||
PyObject *pyobj = Py_None;
|
||||
char *id, *label;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ssO", &id, &label, &pyobj))
|
||||
return nullptr;
|
||||
|
||||
MeasureManager::addMeasureType(
|
||||
new App::MeasureType{id, label, "", nullptr, nullptr, true, pyobj}
|
||||
);
|
||||
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
|
||||
PyObject* MeasureManagerPy::getMeasureTypes(PyObject *args)
|
||||
{
|
||||
Py::List types;
|
||||
for (auto & it : MeasureManager::getMeasureTypes()) {
|
||||
Py::Tuple type(3);
|
||||
type.setItem(0, Py::String(it->identifier));
|
||||
type.setItem(1, Py::String(it->label));
|
||||
type.setItem(2, Py::Object(it->pythonClass));
|
||||
|
||||
types.append(type);
|
||||
}
|
||||
|
||||
return Py::new_reference_to(types);
|
||||
}
|
||||
@@ -128,7 +128,6 @@ public:
|
||||
static void init();
|
||||
static void destruct();
|
||||
|
||||
protected:
|
||||
static std::string getModuleName(const char* ClassName);
|
||||
|
||||
|
||||
|
||||
135
src/Gui/ArcEngine.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2013 Thomas Anderson <blobfish[at]gmx.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include "ArcEngine.h"
|
||||
#include <vector>
|
||||
|
||||
# include <Inventor/engines/SoCalculator.h>
|
||||
# include <Inventor/engines/SoComposeVec3f.h>
|
||||
# include <Inventor/engines/SoConcatenate.h>
|
||||
# include <Inventor/engines/SoComposeRotation.h>
|
||||
# include <Inventor/engines/SoComposeRotationFromTo.h>
|
||||
|
||||
# include <Inventor/nodekits/SoShapeKit.h>
|
||||
# include <Inventor/nodes/SoCone.h>
|
||||
# include <Inventor/nodes/SoFont.h>
|
||||
# include <Inventor/nodes/SoLineSet.h>
|
||||
# include <Inventor/nodes/SoMaterial.h>
|
||||
# include <Inventor/nodes/SoMatrixTransform.h>
|
||||
# include <Inventor/nodes/SoResetTransform.h>
|
||||
# include <Inventor/nodes/SoSeparator.h>
|
||||
# include <Inventor/nodes/SoTransform.h>
|
||||
# include <Inventor/nodes/SoVertexProperty.h>
|
||||
|
||||
using namespace Gui;
|
||||
|
||||
|
||||
|
||||
SO_ENGINE_SOURCE(ArcEngine)
|
||||
|
||||
ArcEngine::ArcEngine()
|
||||
{
|
||||
SO_ENGINE_CONSTRUCTOR(ArcEngine);
|
||||
|
||||
SO_ENGINE_ADD_INPUT(radius, (10.0));
|
||||
SO_ENGINE_ADD_INPUT(angle, (1.0));
|
||||
SO_ENGINE_ADD_INPUT(deviation, (0.25));
|
||||
|
||||
SO_ENGINE_ADD_OUTPUT(points, SoMFVec3f);
|
||||
SO_ENGINE_ADD_OUTPUT(pointCount, SoSFInt32);
|
||||
SO_ENGINE_ADD_OUTPUT(midpoint, SoSFVec3f);
|
||||
}
|
||||
|
||||
void ArcEngine::initClass()
|
||||
{
|
||||
SO_ENGINE_INIT_CLASS(ArcEngine, SoEngine, "Engine");
|
||||
}
|
||||
|
||||
void ArcEngine::evaluate()
|
||||
{
|
||||
float angle = abs(this->angle.getValue());
|
||||
|
||||
if (radius.getValue() < std::numeric_limits<float>::epsilon() ||
|
||||
deviation.getValue() < std::numeric_limits<float>::epsilon())
|
||||
{
|
||||
defaultValues();
|
||||
return;
|
||||
}
|
||||
|
||||
float deviationAngle(acos((radius.getValue() - deviation.getValue()) / radius.getValue()));
|
||||
std::vector<SbVec3f> tempPoints;
|
||||
int segmentCount;
|
||||
if (deviationAngle >= angle) {
|
||||
segmentCount = 1;
|
||||
}
|
||||
else {
|
||||
segmentCount = static_cast<int>(angle / deviationAngle) + 1;
|
||||
if (segmentCount < 2) {
|
||||
defaultValues();
|
||||
return;
|
||||
}
|
||||
}
|
||||
float angleIncrement = (this->angle.getValue() > 0 ? angle : -angle) / static_cast<float>(segmentCount);
|
||||
for (int index = 0; index < segmentCount + 1; ++index)
|
||||
{
|
||||
SbVec3f currentNormal(1.0, 0.0, 0.0);
|
||||
float currentAngle = index * angleIncrement;
|
||||
SbRotation rotation(SbVec3f(0.0, 0.0, 1.0), currentAngle);
|
||||
rotation.multVec(currentNormal, currentNormal);
|
||||
tempPoints.push_back(currentNormal * radius.getValue());
|
||||
}
|
||||
int tempCount = tempPoints.size(); //for macro.
|
||||
SO_ENGINE_OUTPUT(points, SoMFVec3f, setNum(tempCount));
|
||||
SO_ENGINE_OUTPUT(pointCount, SoSFInt32, setValue(tempCount));
|
||||
std::vector<SbVec3f>::const_iterator it;
|
||||
for (it = tempPoints.begin(); it != tempPoints.end(); ++it)
|
||||
{
|
||||
int currentIndex = it-tempPoints.begin(); //for macro.
|
||||
SbVec3f temp(*it); //for macro
|
||||
SO_ENGINE_OUTPUT(points, SoMFVec3f, set1Value(currentIndex, temp));
|
||||
}
|
||||
|
||||
// Get Midpoint
|
||||
float a = angle / 2;
|
||||
SbRotation rot(SbVec3f(0.0, 0.0, 1.0), a);
|
||||
SbVec3f midPnt(1.0, 0.0, 0.0);
|
||||
rot.multVec(midPnt, midPnt);
|
||||
midPnt = midPnt * radius.getValue();
|
||||
|
||||
SO_ENGINE_OUTPUT(midpoint, SoSFVec3f, setValue(midPnt));
|
||||
|
||||
}
|
||||
|
||||
void ArcEngine::defaultValues()
|
||||
{
|
||||
//just some non-failing info.
|
||||
SO_ENGINE_OUTPUT(points, SoMFVec3f, setNum(2));
|
||||
SbVec3f point1(10.0, 0.0, 0.0);
|
||||
SO_ENGINE_OUTPUT(points, SoMFVec3f, set1Value(0, point1));
|
||||
SbVec3f point2(7.07f, 7.07f, 0.0);
|
||||
SO_ENGINE_OUTPUT(points, SoMFVec3f, set1Value(1, point2));
|
||||
SO_ENGINE_OUTPUT(pointCount, SoSFInt32, setValue(2));
|
||||
SbVec3f point3(7.07f, 7.07f, 0.0);
|
||||
SO_ENGINE_OUTPUT(midpoint, SoSFVec3f, setValue(point3));
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2022 *
|
||||
* Copyright (c) 2013 Thomas Anderson <blobfish[at]gmx.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
@@ -20,39 +20,54 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef GUI_ARCENGINE_H
|
||||
#define GUI_ARCENGINE_H
|
||||
|
||||
#ifndef PARTGUI_DIALOG_DLGSETTINGSMEASURE_H
|
||||
#define PARTGUI_DIALOG_DLGSETTINGSMEASURE_H
|
||||
#include <FCGlobal.h>
|
||||
#include <Inventor/fields/SoMFColor.h>
|
||||
#include <Inventor/engines/SoEngineOutput.h>
|
||||
|
||||
#include <Gui/PropertyPage.h>
|
||||
#include <memory>
|
||||
#include <Inventor/engines/SoSubEngine.h>
|
||||
#include <Inventor/engines/SoEngine.h>
|
||||
#include <Inventor/fields/SoSFColor.h>
|
||||
#include <Inventor/fields/SoSFFloat.h>
|
||||
#include <Inventor/fields/SoSFMatrix.h>
|
||||
#include <Inventor/fields/SoSFRotation.h>
|
||||
#include <Inventor/fields/SoSFString.h>
|
||||
#include <Inventor/fields/SoSFVec3f.h>
|
||||
#include <Inventor/nodekits/SoSeparatorKit.h>
|
||||
|
||||
namespace PartGui {
|
||||
class Ui_DlgSettingsMeasure;
|
||||
class SoText2;
|
||||
class SoTranslation;
|
||||
class SoCoordinate3;
|
||||
class SoIndexedLineSet;
|
||||
|
||||
/**
|
||||
* The DlgSettingsMeasure class implements a preference page to change color
|
||||
* and font settings for Measure Dimensions
|
||||
*/
|
||||
class DlgSettingsMeasure : public Gui::Dialog::PreferencePage
|
||||
namespace Gui {
|
||||
|
||||
|
||||
// /*used for generating points for arc display*/
|
||||
class GuiExport ArcEngine : public SoEngine
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
SO_ENGINE_HEADER(ArcEngine);
|
||||
public:
|
||||
explicit DlgSettingsMeasure(QWidget* parent = nullptr);
|
||||
~DlgSettingsMeasure() override;
|
||||
ArcEngine();
|
||||
static void initClass();
|
||||
|
||||
void saveSettings() override;
|
||||
void loadSettings() override;
|
||||
SoSFFloat radius;
|
||||
SoSFFloat angle;
|
||||
SoSFFloat deviation;
|
||||
|
||||
SoEngineOutput points;
|
||||
SoEngineOutput pointCount;
|
||||
SoEngineOutput midpoint;
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent *e) override;
|
||||
|
||||
void evaluate() override;
|
||||
private:
|
||||
std::unique_ptr<Ui_DlgSettingsMeasure> ui;
|
||||
void onMeasureRefresh();
|
||||
~ArcEngine() override{}
|
||||
void defaultValues(); //some non error values if something goes wrong.
|
||||
};
|
||||
|
||||
} // namespace PartGui
|
||||
} // namespace Gui
|
||||
|
||||
#endif // PARTGUI_DIALOG_DLGSETTINGSMEASURE_H
|
||||
#endif // GUI_ARCENGINE_H
|
||||
@@ -455,6 +455,7 @@ SET(Dialog_CPP_SRCS
|
||||
DownloadManager.cpp
|
||||
DocumentRecovery.cpp
|
||||
TaskElementColors.cpp
|
||||
TaskMeasure.cpp
|
||||
DlgObjectSelection.cpp
|
||||
DlgAddProperty.cpp
|
||||
VectorListEditor.cpp
|
||||
@@ -494,6 +495,7 @@ SET(Dialog_HPP_SRCS
|
||||
DownloadManager.h
|
||||
DocumentRecovery.h
|
||||
TaskElementColors.h
|
||||
TaskMeasure.h
|
||||
DlgObjectSelection.h
|
||||
DlgAddProperty.h
|
||||
VectorListEditor.h
|
||||
@@ -1009,6 +1011,7 @@ SET(Inventor_CPP_SRCS
|
||||
SoTouchEvents.cpp
|
||||
SoMouseWheelEvent.cpp
|
||||
SoFCCSysDragger.cpp
|
||||
ArcEngine.cpp
|
||||
)
|
||||
SET(Inventor_SRCS
|
||||
${Inventor_CPP_SRCS}
|
||||
@@ -1037,6 +1040,7 @@ SET(Inventor_SRCS
|
||||
SoTouchEvents.h
|
||||
SoMouseWheelEvent.h
|
||||
SoFCCSysDragger.h
|
||||
ArcEngine.h
|
||||
)
|
||||
SOURCE_GROUP("View3D\\Inventor" FILES ${Inventor_SRCS})
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
#include "SelectionObject.h"
|
||||
#include "SoAxisCrossKit.h"
|
||||
#include "SoFCOffscreenRenderer.h"
|
||||
#include "TaskMeasure.h"
|
||||
#include "TextureMapping.h"
|
||||
#include "Tools.h"
|
||||
#include "Tree.h"
|
||||
@@ -3189,6 +3190,38 @@ bool StdCmdMeasureDistance::isActive()
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Std_Measure
|
||||
// this is the Unified Measurement Facility Measure command
|
||||
//===========================================================================
|
||||
|
||||
|
||||
DEF_STD_CMD_A(StdCmdMeasure)
|
||||
|
||||
StdCmdMeasure::StdCmdMeasure()
|
||||
:Command("Std_Measure")
|
||||
{
|
||||
sGroup = "Measure";
|
||||
sMenuText = QT_TR_NOOP("&Measure");
|
||||
sToolTipText = QT_TR_NOOP("Measure a feature");
|
||||
sWhatsThis = "Std_Measure";
|
||||
sStatusTip = QT_TR_NOOP("Measure a feature");
|
||||
sPixmap = "umf-measurement";
|
||||
}
|
||||
|
||||
void StdCmdMeasure::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
|
||||
TaskMeasure *task = new TaskMeasure();
|
||||
Gui::Control().showDialog(task);
|
||||
}
|
||||
|
||||
|
||||
bool StdCmdMeasure::isActive(){
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Std_SceneInspector
|
||||
//===========================================================================
|
||||
@@ -4117,6 +4150,7 @@ void CreateViewStdCommands()
|
||||
rcCmdMgr.addCommand(new StdCmdTreeCollapse());
|
||||
rcCmdMgr.addCommand(new StdCmdTreeSelectAllInstances());
|
||||
rcCmdMgr.addCommand(new StdCmdMeasureDistance());
|
||||
rcCmdMgr.addCommand(new StdCmdMeasure());
|
||||
rcCmdMgr.addCommand(new StdCmdSceneInspector());
|
||||
rcCmdMgr.addCommand(new StdCmdTextureMapping());
|
||||
rcCmdMgr.addCommand(new StdCmdDemoMode());
|
||||
|
||||
@@ -135,6 +135,7 @@
|
||||
<file>view-rotate-right.svg</file>
|
||||
<file>view-measurement.svg</file>
|
||||
<file>view-measurement-cross.svg</file>
|
||||
<file>umf-measurement.svg</file>
|
||||
<file>Tree_Annotation.svg</file>
|
||||
<file>Tree_Dimension.svg</file>
|
||||
<file>Tree_Python.svg</file>
|
||||
|
||||
226
src/Gui/Icons/umf-measurement.svg
Normal file
@@ -0,0 +1,226 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="64"
|
||||
height="64"
|
||||
id="svg2869"
|
||||
version="1.1"
|
||||
viewBox="0 0 64 64"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs2871">
|
||||
<linearGradient
|
||||
id="linearGradient10">
|
||||
<stop
|
||||
style="stop-color:#babdb6;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop10" />
|
||||
<stop
|
||||
style="stop-color:#888a85;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop11" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5">
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop19" />
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop20" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="swatch18">
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop18" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="swatch15">
|
||||
<stop
|
||||
style="stop-color:#3d0000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop15" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5-1">
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5" />
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop6" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3836-9">
|
||||
<stop
|
||||
style="stop-color:#a40000;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3838-8" />
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3840-1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient10"
|
||||
id="linearGradient11"
|
||||
x1="12.375"
|
||||
y1="23.75"
|
||||
x2="64"
|
||||
y2="28.5"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata2874">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[maxwxyz]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<dc:date>2024</dc:date>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer3"
|
||||
style="display:inline">
|
||||
<path
|
||||
id="path4498"
|
||||
d="M 31.906888,60.999998 V 12.276532 l -24.5860006,1e-6 -2.904e-4,-3.0939183 24.58542,-6.1826135 h 8.71e-4 15.462656 v 9.2765308 h 13.308118 l 2.89e-4,2.030582 -13.308407,4.061163 v 42.631722 z"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path6"
|
||||
d="m 32.154297,5 h 13.214844 v 9.277344 h 8.55664 l -8.55664,2.611328 V 59 H 33.90625 V 10.277344 H 11.164063 Z"
|
||||
style="fill:url(#linearGradient11);fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path4504"
|
||||
d="m 33.453879,17.976538 9.277594,8.71e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path1"
|
||||
d="m 33.457361,48.841436 6.185063,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path2"
|
||||
d="m 33.457361,41.125284 6.185063,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path3"
|
||||
d="m 33.457361,33.409133 6.185063,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path4"
|
||||
d="m 33.457361,25.692981 6.185063,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5"
|
||||
d="m 33.453879,56.557588 9.277594,8.72e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path11"
|
||||
d="m 34.230469,19.976538 7.724414,8.71e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path12"
|
||||
d="m 34.233368,50.841436 5.14961,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path13"
|
||||
d="m 34.233368,43.125284 5.14961,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path14"
|
||||
d="m 34.233368,35.409133 5.14961,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path15"
|
||||
d="m 34.233368,27.692981 5.14961,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path16"
|
||||
d="m 34.230469,58.557588 8.501004,8.72e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path4500"
|
||||
d="M 7.3208874,27.158429 H 34.22781 l 0.0019,28.741042 H 28.043227 V 37.209528 L 7.3208874,32.571857 Z"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path4502"
|
||||
d="m 45.82444,20.585383 14.854673,4.062178 2.9e-4,2.510868 H 50.463816 l 0.0016,14.741042 h -4.638797 z"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path7"
|
||||
d="M 9.3203125,29.158203 H 32.228516 l 0.002,24.742188 h -2.1875 V 35.607422 L 9.3203125,30.970703 Z"
|
||||
style="fill:#888a85;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path18"
|
||||
d="m 31.176195,46.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path19"
|
||||
d="m 31.176195,48.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path20"
|
||||
d="m 31.176195,42.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path21"
|
||||
d="m 31.176195,44.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path22"
|
||||
d="m 31.176195,38.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path23"
|
||||
d="m 31.176195,40.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path24"
|
||||
d="m 31.176195,50.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path25"
|
||||
d="m 31.176195,52.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path26"
|
||||
d="m 31.176195,34.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path27"
|
||||
d="m 31.176195,36.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.8 KiB |
@@ -74,6 +74,7 @@
|
||||
#include "Inventor/SoAutoZoomTranslation.h"
|
||||
#include "Inventor/SoDrawingGrid.h"
|
||||
#include "propertyeditor/PropertyItem.h"
|
||||
#include "ArcEngine.h"
|
||||
|
||||
|
||||
using namespace Gui;
|
||||
@@ -193,6 +194,8 @@ void Gui::SoFCDB::init()
|
||||
|
||||
SelectionObject ::init();
|
||||
|
||||
ArcEngine ::initClass();
|
||||
|
||||
qRegisterMetaType<Base::Vector3f>("Base::Vector3f");
|
||||
qRegisterMetaType<Base::Vector3d>("Base::Vector3d");
|
||||
qRegisterMetaType<Base::Quantity>("Base::Quantity");
|
||||
|
||||
388
src/Gui/TaskMeasure.cpp
Normal file
@@ -0,0 +1,388 @@
|
||||
/***************************************************************************
|
||||
* 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"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <QApplication>
|
||||
# include <QKeyEvent>
|
||||
#endif
|
||||
|
||||
|
||||
#include "TaskMeasure.h"
|
||||
|
||||
#include "Control.h"
|
||||
#include "MainWindow.h"
|
||||
#include "Application.h"
|
||||
#include "App/Document.h"
|
||||
#include "App/DocumentObjectGroup.h"
|
||||
#include <Gui/BitmapFactory.h>
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
using namespace Gui;
|
||||
|
||||
|
||||
TaskMeasure::TaskMeasure()
|
||||
{
|
||||
qApp->installEventFilter(this);
|
||||
|
||||
this->setButtonPosition(TaskMeasure::South);
|
||||
auto taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("umf-measurement"), tr("Measurement"), true, nullptr);
|
||||
|
||||
// Create mode dropdown and add all registered measuretypes
|
||||
modeSwitch = new QComboBox();
|
||||
modeSwitch->addItem(QString::fromLatin1("Auto"));
|
||||
|
||||
for (App::MeasureType* mType : App::MeasureManager::getMeasureTypes()){
|
||||
modeSwitch->addItem(QString::fromLatin1(mType->label.c_str()));
|
||||
}
|
||||
|
||||
// Connect dropdown's change signal to our onModeChange slot
|
||||
connect(modeSwitch, qOverload<int>(&QComboBox::currentIndexChanged), this, &TaskMeasure::onModeChanged);
|
||||
|
||||
// Result widget
|
||||
valueResult = new QLineEdit();
|
||||
valueResult->setReadOnly(true);
|
||||
|
||||
// Main layout
|
||||
QBoxLayout *layout = taskbox->groupLayout();
|
||||
|
||||
QFormLayout* formLayout = new QFormLayout();
|
||||
formLayout->setHorizontalSpacing(10);
|
||||
// Note: How can the split between columns be kept in the middle?
|
||||
// formLayout->setFieldGrowthPolicy(QFormLayout::FieldGrowthPolicy::ExpandingFieldsGrow);
|
||||
formLayout->setFormAlignment(Qt::AlignCenter);
|
||||
|
||||
formLayout->addRow(QString::fromLatin1("Mode:"), modeSwitch);
|
||||
formLayout->addRow(QString::fromLatin1("Result:"), valueResult);
|
||||
layout->addLayout(formLayout);
|
||||
|
||||
Content.emplace_back(taskbox);
|
||||
|
||||
// engage the selectionObserver
|
||||
attachSelection();
|
||||
|
||||
// Set selection style
|
||||
Gui::Selection().setSelectionStyle(Gui::SelectionSingleton::SelectionStyle::GreedySelection);
|
||||
|
||||
if(!App::GetApplication().getActiveTransaction())
|
||||
App::GetApplication().setActiveTransaction("Add Measurement");
|
||||
|
||||
|
||||
// Call invoke method delayed, otherwise the dialog might not be fully initialized
|
||||
QTimer::singleShot(0, this, &TaskMeasure::invoke);
|
||||
}
|
||||
|
||||
TaskMeasure::~TaskMeasure(){
|
||||
Gui::Selection().setSelectionStyle(Gui::SelectionSingleton::SelectionStyle::NormalSelection);
|
||||
detachSelection();
|
||||
qApp->removeEventFilter(this);
|
||||
}
|
||||
|
||||
|
||||
void TaskMeasure::modifyStandardButtons(QDialogButtonBox* box) {
|
||||
|
||||
QPushButton* btn = box->button(QDialogButtonBox::Apply);
|
||||
btn->setText(tr("Annotate"));
|
||||
btn->setToolTip(tr("Press the Annotate button to add measurement to the document."));
|
||||
connect(btn, &QPushButton::released, this, &TaskMeasure::apply);
|
||||
|
||||
// Disable button by default
|
||||
btn->setEnabled(false);
|
||||
btn = box->button(QDialogButtonBox::Abort);
|
||||
btn->setText(QString::fromLatin1("Close"));
|
||||
btn->setToolTip(tr("Press the Close button to exit."));
|
||||
|
||||
// Connect reset button
|
||||
btn = box->button(QDialogButtonBox::Reset);
|
||||
connect(btn, &QPushButton::released, this, &TaskMeasure::reset);
|
||||
}
|
||||
|
||||
bool canAnnotate(Measure::MeasureBase* obj) {
|
||||
if (obj == nullptr) {
|
||||
// null object, can't annotate this
|
||||
return false;
|
||||
}
|
||||
|
||||
auto vpName = obj->getViewProviderName();
|
||||
// if there is not a vp, return false
|
||||
if ((vpName == nullptr) || (vpName[0] == '\0')){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TaskMeasure::enableAnnotateButton(bool state) {
|
||||
// if the task ui is not init yet we don't have a button box.
|
||||
if (!this->buttonBox) {
|
||||
return;
|
||||
}
|
||||
// Enable/Disable annotate button
|
||||
auto btn = this->buttonBox->button(QDialogButtonBox::Apply);
|
||||
btn->setEnabled(state);
|
||||
}
|
||||
|
||||
void TaskMeasure::setMeasureObject(Measure::MeasureBase* obj) {
|
||||
_mMeasureObject = obj;
|
||||
}
|
||||
|
||||
|
||||
void TaskMeasure::update() {
|
||||
|
||||
// Reset selection if the selected object is not valid
|
||||
for(auto sel : Gui::Selection().getSelection()) {
|
||||
App::DocumentObject* ob = sel.pObject;
|
||||
App::DocumentObject* sub = ob->getSubObject(sel.SubName);
|
||||
std::string mod = Base::Type::getModuleName(sub->getTypeId().getName());
|
||||
|
||||
if (!App::MeasureManager::hasMeasureHandler(mod.c_str())) {
|
||||
Base::Console().Message("No measure handler available for geometry of module: %s\n", mod);
|
||||
clearSelection();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
valueResult->setText(QString::asprintf("-"));
|
||||
|
||||
// Get valid measure type
|
||||
App::MeasureType *measureType(nullptr);
|
||||
|
||||
|
||||
std::string mode = explicitMode ? modeSwitch->currentText().toStdString() : "";
|
||||
|
||||
App::MeasureSelection selection;
|
||||
for (auto s : Gui::Selection().getSelection()) {
|
||||
App::SubObjectT sub(s.pObject, s.SubName);
|
||||
|
||||
App::MeasureSelectionItem item = { sub, Base::Vector3d(s.x, s.y, s.z) };
|
||||
selection.push_back(item);
|
||||
}
|
||||
|
||||
auto measureTypes = App::MeasureManager::getValidMeasureTypes(selection, mode);
|
||||
if (measureTypes.size() > 0) {
|
||||
measureType = measureTypes.front();
|
||||
}
|
||||
|
||||
|
||||
if (!measureType) {
|
||||
|
||||
// Note: If there's no valid measure type we might just restart the selection,
|
||||
// however this requires enough coverage of measuretypes that we can access all of them
|
||||
|
||||
// std::tuple<std::string, std::string> sel = selection.back();
|
||||
// clearSelection();
|
||||
// addElement(measureModule.c_str(), get<0>(sel).c_str(), get<1>(sel).c_str());
|
||||
|
||||
// Reset measure object
|
||||
if (!explicitMode) {
|
||||
setModeSilent(nullptr);
|
||||
}
|
||||
removeObject();
|
||||
enableAnnotateButton(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update tool mode display
|
||||
setModeSilent(measureType);
|
||||
|
||||
if (!_mMeasureObject || measureType->measureObject != _mMeasureObject->getTypeId().getName()) {
|
||||
// we don't already have a measureobject or it isn't the same type as the new one
|
||||
removeObject();
|
||||
|
||||
App::Document *doc = App::GetApplication().getActiveDocument();
|
||||
if (measureType->isPython) {
|
||||
Base::PyGILStateLocker lock;
|
||||
auto pyMeasureClass = measureType->pythonClass;
|
||||
|
||||
// Create a MeasurePython instance
|
||||
auto featurePython = doc->addObject("Measure::MeasurePython", measureType->label.c_str());
|
||||
setMeasureObject((Measure::MeasureBase*)featurePython);
|
||||
|
||||
// Create an instance of the pyMeasureClass, the classe's initializer sets the object as proxy
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::asObject(featurePython->getPyObject()));
|
||||
PyObject_CallObject(pyMeasureClass, args.ptr());
|
||||
}
|
||||
else {
|
||||
// Create measure object
|
||||
setMeasureObject(
|
||||
(Measure::MeasureBase*)doc->addObject(measureType->measureObject.c_str(), measureType->label.c_str())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// we have a valid measure object so we can enable the annotate button
|
||||
enableAnnotateButton(true);
|
||||
|
||||
// Fill measure object's properties from selection
|
||||
_mMeasureObject->parseSelection(selection);
|
||||
|
||||
// Get result
|
||||
valueResult->setText(_mMeasureObject->getResultString());
|
||||
}
|
||||
|
||||
void TaskMeasure::close(){
|
||||
Control().closeDialog();
|
||||
}
|
||||
|
||||
|
||||
void ensureGroup(Measure::MeasureBase* measurement) {
|
||||
// Ensure measurement object is part of the measurements group
|
||||
|
||||
const char* measurementGroupName = "Measurements";
|
||||
if (measurement == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
App::Document* doc = App::GetApplication().getActiveDocument();
|
||||
App::DocumentObject* obj = doc->getObject(measurementGroupName);
|
||||
if (!obj || !obj->isValid()) {
|
||||
obj = doc->addObject("App::DocumentObjectGroup", measurementGroupName);
|
||||
}
|
||||
|
||||
auto group = static_cast<App::DocumentObjectGroup*>(obj);
|
||||
group->addObject(measurement);
|
||||
}
|
||||
|
||||
|
||||
// Runs after the dialog is created
|
||||
void TaskMeasure::invoke() {
|
||||
update();
|
||||
}
|
||||
|
||||
bool TaskMeasure::apply(){
|
||||
ensureGroup(_mMeasureObject);
|
||||
_mMeasureObject = nullptr;
|
||||
reset();
|
||||
|
||||
// Commit transaction
|
||||
App::GetApplication().closeActiveTransaction();
|
||||
App::GetApplication().setActiveTransaction("Add Measurement");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TaskMeasure::reject(){
|
||||
removeObject();
|
||||
close();
|
||||
|
||||
// Abort transaction
|
||||
App::GetApplication().closeActiveTransaction(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
void TaskMeasure::reset() {
|
||||
// Reset tool state
|
||||
this->clearSelection();
|
||||
|
||||
// Should the explicit mode also be reset?
|
||||
// setModeSilent(nullptr);
|
||||
// explicitMode = false;
|
||||
|
||||
this->update();
|
||||
}
|
||||
|
||||
|
||||
void TaskMeasure::removeObject() {
|
||||
if (_mMeasureObject == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (_mMeasureObject->isRemoving() ) {
|
||||
return;
|
||||
}
|
||||
_mMeasureObject->getDocument()->removeObject (_mMeasureObject->getNameInDocument());
|
||||
setMeasureObject(nullptr);
|
||||
}
|
||||
|
||||
bool TaskMeasure::hasSelection(){
|
||||
return !Gui::Selection().getSelection().empty();
|
||||
}
|
||||
|
||||
void TaskMeasure::clearSelection(){
|
||||
Gui::Selection().clearSelection();
|
||||
}
|
||||
|
||||
void TaskMeasure::onSelectionChanged(const Gui::SelectionChanges& msg)
|
||||
{
|
||||
// Skip non-relevant events
|
||||
if (msg.Type != SelectionChanges::AddSelection && msg.Type != SelectionChanges::RmvSelection
|
||||
&& msg.Type != SelectionChanges::SetSelection && msg.Type != SelectionChanges::ClrSelection) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
bool TaskMeasure::eventFilter(QObject* obj, QEvent* event) {
|
||||
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
auto keyEvent = static_cast<QKeyEvent*>(event);
|
||||
|
||||
if (keyEvent->key() == Qt::Key_Escape) {
|
||||
|
||||
if (this->hasSelection()) {
|
||||
this->reset();
|
||||
} else {
|
||||
this->reject();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
|
||||
this->apply();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return TaskDialog::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void TaskMeasure::onModeChanged(int index) {
|
||||
explicitMode = (index != 0);
|
||||
this->update();
|
||||
}
|
||||
|
||||
void TaskMeasure::setModeSilent(App::MeasureType* mode) {
|
||||
modeSwitch->blockSignals(true);
|
||||
|
||||
if (mode == nullptr) {
|
||||
modeSwitch->setCurrentIndex(0);
|
||||
}
|
||||
else {
|
||||
modeSwitch->setCurrentText(QString::fromLatin1(mode->label.c_str()));
|
||||
}
|
||||
modeSwitch->blockSignals(false);
|
||||
}
|
||||
|
||||
// Get explicitly set measure type from the mode switch
|
||||
App::MeasureType* TaskMeasure::getMeasureType() {
|
||||
for (App::MeasureType* mType : App::MeasureManager::getMeasureTypes()) {
|
||||
if (mType->label.c_str() == modeSwitch->currentText().toLatin1()) {
|
||||
return mType;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
87
src/Gui/TaskMeasure.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/***************************************************************************
|
||||
* 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 <qcolumnview.h>
|
||||
#include <QString>
|
||||
#include <QComboBox>
|
||||
#include <QLineEdit>
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/MeasureManager.h>
|
||||
|
||||
#include <Mod/Measure/App/MeasureBase.h>
|
||||
|
||||
#include "TaskView/TaskDialog.h"
|
||||
#include "TaskView/TaskView.h"
|
||||
#include "Selection.h"
|
||||
|
||||
namespace Gui {
|
||||
|
||||
class TaskMeasure : public TaskView::TaskDialog, public Gui::SelectionObserver {
|
||||
|
||||
public:
|
||||
TaskMeasure();
|
||||
~TaskMeasure() override;
|
||||
|
||||
void modifyStandardButtons(QDialogButtonBox* box) override;
|
||||
QDialogButtonBox::StandardButtons getStandardButtons() const override {
|
||||
return QDialogButtonBox::Apply | QDialogButtonBox::Abort | QDialogButtonBox::Reset;
|
||||
}
|
||||
|
||||
void invoke();
|
||||
void update();
|
||||
void close();
|
||||
bool apply();
|
||||
bool reject() override;
|
||||
void reset();
|
||||
|
||||
bool hasSelection();
|
||||
void clearSelection();
|
||||
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||
void setMeasureObject(Measure::MeasureBase* obj);
|
||||
|
||||
private:
|
||||
QColumnView* dialog{nullptr};
|
||||
|
||||
void onSelectionChanged(const Gui::SelectionChanges& msg) override;
|
||||
|
||||
Measure::MeasureBase *_mMeasureObject = nullptr;
|
||||
|
||||
QLineEdit* valueResult{nullptr};
|
||||
QLabel* labelResult{nullptr};
|
||||
QComboBox* modeSwitch{nullptr};
|
||||
|
||||
void removeObject();
|
||||
void onModeChanged(int index);
|
||||
void setModeSilent(App::MeasureType* mode);
|
||||
App::MeasureType* getMeasureType();
|
||||
void enableAnnotateButton(bool state);
|
||||
|
||||
// List of measure types
|
||||
std::vector<App::DocumentObject> measureObjects;
|
||||
|
||||
// Stores if the mode is explicitly set by the user or implicitly through the selection
|
||||
bool explicitMode = false;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Gui
|
||||
@@ -814,7 +814,7 @@ ToolBarItem* StdWorkbench::setupToolBars() const
|
||||
view->setCommand("View");
|
||||
*view << "Std_ViewFitAll" << "Std_ViewFitSelection" << "Std_ViewGroup"
|
||||
<< "Separator" << "Std_DrawStyle" << "Std_TreeViewActions"
|
||||
<< "Separator" << "Std_MeasureDistance";
|
||||
<< "Separator" << "Std_MeasureDistance" << "Std_Measure";
|
||||
|
||||
// Individual views
|
||||
auto individualViews = new ToolBarItem(root, ToolBarItem::DefaultVisibility::Hidden);
|
||||
|
||||
@@ -122,8 +122,11 @@ if(BUILD_SURFACE)
|
||||
add_subdirectory(Surface)
|
||||
endif(BUILD_SURFACE)
|
||||
|
||||
if(BUILD_TECHDRAW)
|
||||
if(BUILD_MEASURE)
|
||||
add_subdirectory(Measure)
|
||||
endif(BUILD_MEASURE)
|
||||
|
||||
if(BUILD_TECHDRAW)
|
||||
add_subdirectory(TechDraw)
|
||||
endif(BUILD_TECHDRAW)
|
||||
|
||||
|
||||
@@ -22,14 +22,38 @@
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <App/MeasureManager.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Interpreter.h>
|
||||
|
||||
#include <Mod/Part/App/MeasureInfo.h>
|
||||
#include <Mod/Part/App/MeasureClient.h>
|
||||
|
||||
#include "Measurement.h"
|
||||
#include "MeasurementPy.h"
|
||||
|
||||
// unified measurement facility
|
||||
#include "MeasureBase.h"
|
||||
#include "MeasureBasePy.h"
|
||||
|
||||
#include "MeasureAngle.h"
|
||||
#include "MeasureDistance.h"
|
||||
#include "MeasurePosition.h"
|
||||
#include "MeasureLength.h"
|
||||
#include "MeasureArea.h"
|
||||
#include "MeasureRadius.h"
|
||||
|
||||
namespace Measure {
|
||||
|
||||
// explicit template instantiations
|
||||
template class MeasureExport MeasureBaseExtendable<Part::MeasureAngleInfo>;
|
||||
template class MeasureExport MeasureBaseExtendable<Part::MeasureAreaInfo>;
|
||||
template class MeasureExport MeasureBaseExtendable<Part::MeasureDistanceInfo>;
|
||||
template class MeasureExport MeasureBaseExtendable<Part::MeasureLengthInfo>;
|
||||
template class MeasureExport MeasureBaseExtendable<Part::MeasurePositionInfo>;
|
||||
template class MeasureExport MeasureBaseExtendable<Part::MeasureRadiusInfo>;
|
||||
|
||||
|
||||
class Module : public Py::ExtensionModule<Module>
|
||||
{
|
||||
public:
|
||||
@@ -48,6 +72,7 @@ PyObject* initModule()
|
||||
|
||||
} // namespace Measure
|
||||
|
||||
using namespace Measure;
|
||||
|
||||
/* Python entry */
|
||||
PyMOD_INIT_FUNC(Measure)
|
||||
@@ -62,14 +87,103 @@ PyMOD_INIT_FUNC(Measure)
|
||||
}
|
||||
PyObject* mod = Measure::initModule();
|
||||
// Add Types to module
|
||||
Base::Interpreter().addType(&Measure::MeasurementPy ::Type,mod,"Measurement");
|
||||
Base::Console().Log("Loading Inspection module... done\n");
|
||||
Measure::Measurement ::init();
|
||||
Base::Interpreter().addType(&Measure::MeasurementPy::Type, mod, "Measurement");
|
||||
Base::Interpreter().addType(&Measure::MeasureBasePy::Type, mod, "MeasureBase");
|
||||
|
||||
Measure::Measurement ::init();
|
||||
|
||||
// umf classes
|
||||
Measure::MeasureBase ::init();
|
||||
Measure::MeasurePython ::init();
|
||||
Measure::MeasureAngle ::init();
|
||||
Measure::MeasureDistance ::init();
|
||||
Measure::MeasurePosition ::init();
|
||||
Measure::MeasureLength ::init();
|
||||
Measure::MeasureArea ::init();
|
||||
Measure::MeasureRadius ::init();
|
||||
|
||||
// Add fundamental umf Measure Types
|
||||
|
||||
App::MeasureManager::addMeasureType("DISTANCE",
|
||||
"Distance",
|
||||
"Measure::MeasureDistance",
|
||||
MeasureDistance::isValidSelection,
|
||||
MeasureDistance::isPrioritizedSelection
|
||||
);
|
||||
|
||||
App::MeasureManager::addMeasureType(
|
||||
"ANGLE",
|
||||
"Angle",
|
||||
"Measure::MeasureAngle",
|
||||
MeasureAngle::isValidSelection,
|
||||
MeasureAngle::isPrioritizedSelection
|
||||
);
|
||||
|
||||
App::MeasureManager::addMeasureType(
|
||||
"LENGTH",
|
||||
"Length",
|
||||
"Measure::MeasureLength",
|
||||
MeasureLength::isValidSelection,
|
||||
nullptr
|
||||
);
|
||||
|
||||
App::MeasureManager::addMeasureType(
|
||||
"POSITION",
|
||||
"Position",
|
||||
"Measure::MeasurePosition",
|
||||
MeasurePosition::isValidSelection,
|
||||
nullptr
|
||||
);
|
||||
|
||||
App::MeasureManager::addMeasureType(
|
||||
"AREA",
|
||||
"Area",
|
||||
"Measure::MeasureArea",
|
||||
MeasureArea::isValidSelection,
|
||||
nullptr
|
||||
);
|
||||
|
||||
App::MeasureManager::addMeasureType(
|
||||
"RADIUS",
|
||||
"Radius",
|
||||
"Measure::MeasureRadius",
|
||||
MeasureRadius::isValidSelection,
|
||||
MeasureRadius::isPrioritizedSelection
|
||||
);
|
||||
|
||||
// load measure callbacks from Part module
|
||||
auto lengthList = Part::MeasureClient::reportLengthCB();
|
||||
for (auto& entry : lengthList) {
|
||||
MeasureBaseExtendable<Part::MeasureLengthInfo>::addGeometryHandler(entry.m_module, entry.m_callback);
|
||||
}
|
||||
auto angleList = Part::MeasureClient::reportAngleCB();
|
||||
for (auto& entry : angleList) {
|
||||
MeasureBaseExtendable<Part::MeasureAngleInfo>::addGeometryHandler(entry.m_module, entry.m_callback);
|
||||
}
|
||||
auto areaList = Part::MeasureClient::reportAreaCB();
|
||||
for (auto& entry : areaList) {
|
||||
MeasureBaseExtendable<Part::MeasureAreaInfo>::addGeometryHandler(entry.m_module, entry.m_callback);
|
||||
}
|
||||
auto distanceList = Part::MeasureClient::reportDistanceCB();
|
||||
for (auto& entry : distanceList) {
|
||||
MeasureBaseExtendable<Part::MeasureDistanceInfo>::addGeometryHandler(entry.m_module, entry.m_callback);
|
||||
}
|
||||
auto positionList = Part::MeasureClient::reportPositionCB();
|
||||
for (auto& entry : positionList) {
|
||||
MeasureBaseExtendable<Part::MeasurePositionInfo>::addGeometryHandler(entry.m_module, entry.m_callback);
|
||||
}
|
||||
auto radiusList = Part::MeasureClient::reportRadiusCB();
|
||||
for (auto& entry : radiusList) {
|
||||
MeasureBaseExtendable<Part::MeasureRadiusInfo>::addGeometryHandler(entry.m_module, entry.m_callback);
|
||||
}
|
||||
|
||||
|
||||
Base::Console().Log("Loading Measure module... done\n");
|
||||
PyMOD_Return(mod);
|
||||
}
|
||||
|
||||
// debug print for sketchsolv
|
||||
void debugprint(const std::string& s)
|
||||
void debugprint(const std::string& text)
|
||||
{
|
||||
Base::Console().Log("%s", s.c_str());
|
||||
Base::Console().Log("%s", text.c_str());
|
||||
}
|
||||
|
||||
@@ -17,19 +17,43 @@ set(Measure_LIBS
|
||||
)
|
||||
|
||||
generate_from_xml(MeasurementPy)
|
||||
generate_from_xml(MeasureBasePy)
|
||||
|
||||
SET(Python_SRCS
|
||||
MeasurementPy.xml
|
||||
MeasurementPyImp.cpp
|
||||
MeasureBasePy.xml
|
||||
MeasureBasePyImp.cpp
|
||||
)
|
||||
SOURCE_GROUP("Python" FILES ${Python_SRCS})
|
||||
|
||||
SET(MeasureModule_SRCS
|
||||
AppMeasure.cpp
|
||||
Measurement.cpp
|
||||
Measurement.h
|
||||
PreCompiled.cpp
|
||||
PreCompiled.h
|
||||
AppMeasure.cpp
|
||||
|
||||
# original service routines
|
||||
Measurement.cpp
|
||||
Measurement.h
|
||||
|
||||
# umf
|
||||
MeasureBase.cpp
|
||||
MeasureBase.h
|
||||
MeasureAngle.cpp
|
||||
MeasureAngle.h
|
||||
MeasureDistance.cpp
|
||||
MeasureDistance.h
|
||||
MeasurePosition.cpp
|
||||
MeasurePosition.h
|
||||
MeasureLength.cpp
|
||||
MeasureLength.h
|
||||
MeasureArea.cpp
|
||||
MeasureArea.h
|
||||
MeasureRadius.cpp
|
||||
MeasureRadius.h
|
||||
|
||||
Preferences.cpp
|
||||
Preferences.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP("Module" FILES ${MeasureModule_SRCS})
|
||||
@@ -45,18 +69,9 @@ if(FREECAD_USE_PCH)
|
||||
ADD_MSVC_PRECOMPILED_HEADER(Measure PreCompiled.h PreCompiled.cpp Measure_CPP_SRCS)
|
||||
endif(FREECAD_USE_PCH)
|
||||
|
||||
SET(Measure_Scripts
|
||||
../Init.py
|
||||
)
|
||||
|
||||
add_library(Measure SHARED ${Measure_SRCS} ${Measure_Scripts})
|
||||
add_library(Measure SHARED ${Measure_SRCS})
|
||||
target_link_libraries(Measure ${Measure_LIBS})
|
||||
|
||||
fc_target_copy_resource_flat(Measure
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_BINARY_DIR}/Mod/Measure
|
||||
${Measure_Scripts})
|
||||
|
||||
#if(MSVC)
|
||||
# set_target_properties(Measure PROPERTIES SUFFIX ".pyd")
|
||||
# set_target_properties(Measure PROPERTIES DEBUG_OUTPUT_NAME "Measure_d")
|
||||
|
||||
264
src/Mod/Measure/App/MeasureAngle.cpp
Normal file
@@ -0,0 +1,264 @@
|
||||
/***************************************************************************
|
||||
* 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 <App/PropertyContainer.h>
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/MeasureManager.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/Precision.h>
|
||||
|
||||
#include "MeasureAngle.h"
|
||||
|
||||
using namespace Measure;
|
||||
|
||||
PROPERTY_SOURCE(Measure::MeasureAngle, Measure::MeasureBase)
|
||||
|
||||
|
||||
MeasureAngle::MeasureAngle()
|
||||
{
|
||||
ADD_PROPERTY_TYPE(Element1,(nullptr), "Measurement", App::Prop_None, "First element of the measurement");
|
||||
Element1.setScope(App::LinkScope::Global);
|
||||
Element1.setAllowExternal(true);
|
||||
|
||||
ADD_PROPERTY_TYPE(Element2,(nullptr), "Measurement", App::Prop_None, "Second element of the measurement");
|
||||
Element2.setScope(App::LinkScope::Global);
|
||||
Element2.setAllowExternal(true);
|
||||
|
||||
ADD_PROPERTY_TYPE(Angle,(0.0) ,"Measurement",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output),
|
||||
"Angle between the two elements");
|
||||
Angle.setUnit(Base::Unit::Angle);
|
||||
}
|
||||
|
||||
MeasureAngle::~MeasureAngle() = default;
|
||||
|
||||
|
||||
bool MeasureAngle::isValidSelection(const App::MeasureSelection& selection)
|
||||
{
|
||||
if (selection.size() != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto element : selection) {
|
||||
auto objT = element.object;
|
||||
|
||||
App::DocumentObject* ob = objT.getObject();
|
||||
const std::string& subName = objT.getSubName();
|
||||
const char* className = objT.getSubObject()->getTypeId().getName();
|
||||
std::string mod = Base::Type::getModuleName(className);
|
||||
|
||||
if (!hasGeometryHandler(mod)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
App::MeasureHandler handler = App::MeasureManager::getMeasureHandler(mod.c_str());
|
||||
App::MeasureElementType type = handler.typeCb(ob, subName.c_str());
|
||||
|
||||
if (type == App::MeasureElementType::INVALID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(type == App::MeasureElementType::LINE ||
|
||||
type == App::MeasureElementType::PLANE ||
|
||||
type == App::MeasureElementType::LINESEGMENT)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MeasureAngle::isPrioritizedSelection(const App::MeasureSelection& selection)
|
||||
{
|
||||
if (selection.size() != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the two elements are parallel
|
||||
auto element1 = selection.at(0);
|
||||
auto objT1 = element1.object;
|
||||
App::DocumentObject* ob1 = objT1.getObject();
|
||||
std::string sub1 = objT1.getSubName();
|
||||
Base::Vector3d vec1;
|
||||
getVec(*ob1, sub1, vec1);
|
||||
|
||||
auto element2 = selection.at(1);
|
||||
auto objT2 = element2.object;
|
||||
App::DocumentObject* ob2 = objT2.getObject();
|
||||
std::string sub2 = objT2.getSubName();
|
||||
Base::Vector3d vec2;
|
||||
getVec(*ob2, sub2, vec2);
|
||||
|
||||
|
||||
double angle = std::fmod(vec1.GetAngle(vec2), D_PI);
|
||||
return angle > Base::Precision::Angular();
|
||||
}
|
||||
|
||||
|
||||
void MeasureAngle::parseSelection(const App::MeasureSelection& selection) {
|
||||
|
||||
assert(selection.size() >= 2);
|
||||
|
||||
auto element1 = selection.at(0);
|
||||
auto objT1 = element1.object;
|
||||
App::DocumentObject* ob1 = objT1.getObject();
|
||||
const std::vector<std::string> elems1 = {objT1.getSubName()};
|
||||
Element1.setValue(ob1, elems1);
|
||||
|
||||
auto element2 = selection.at(1);
|
||||
auto objT2 = element2.object;
|
||||
App::DocumentObject* ob2 = objT2.getObject();
|
||||
const std::vector<std::string> elems2 = {objT2.getSubName()};
|
||||
Element2.setValue(ob2, elems2);
|
||||
}
|
||||
|
||||
|
||||
bool MeasureAngle::getVec(App::DocumentObject& ob, std::string& subName, Base::Vector3d& vecOut) {
|
||||
const char* className = ob.getSubObject(subName.c_str())->getTypeId().getName();
|
||||
std::string mod = Base::Type::getModuleName(className);
|
||||
|
||||
if (!hasGeometryHandler(mod)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto handler = getGeometryHandler(mod);
|
||||
App::SubObjectT subject{&ob, subName.c_str()};
|
||||
auto info = handler(subject);
|
||||
|
||||
auto angleInfo = std::dynamic_pointer_cast<Part::MeasureAngleInfo>(info);
|
||||
vecOut = angleInfo->orientation;
|
||||
return true;
|
||||
}
|
||||
|
||||
Base::Vector3d MeasureAngle::getLoc(App::DocumentObject& ob, std::string& subName)
|
||||
{
|
||||
const char* className = ob.getSubObject(subName.c_str())->getTypeId().getName();
|
||||
std::string mod = Base::Type::getModuleName(className);
|
||||
|
||||
if (!hasGeometryHandler(mod)) {
|
||||
return Base::Vector3d();
|
||||
}
|
||||
|
||||
auto handler = getGeometryHandler(mod);
|
||||
App::SubObjectT subject{&ob, subName.c_str()};
|
||||
auto info = handler(subject);
|
||||
auto angleInfo = std::dynamic_pointer_cast<Part::MeasureAngleInfo>(info);
|
||||
return angleInfo->position;
|
||||
}
|
||||
|
||||
gp_Vec MeasureAngle::vector1() {
|
||||
|
||||
App::DocumentObject* ob = Element1.getValue();
|
||||
std::vector<std::string> subs = Element1.getSubValues();
|
||||
|
||||
if (!ob || !ob->isValid() || subs.empty() ) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Base::Vector3d vec;
|
||||
getVec(*ob, subs.at(0), vec);
|
||||
return gp_Vec(vec.x, vec.y, vec.z);
|
||||
}
|
||||
|
||||
gp_Vec MeasureAngle::vector2() {
|
||||
App::DocumentObject* ob = Element2.getValue();
|
||||
std::vector<std::string> subs = Element2.getSubValues();
|
||||
|
||||
if (!ob || !ob->isValid() || subs.empty() ) {
|
||||
return gp_Vec();
|
||||
}
|
||||
|
||||
Base::Vector3d vec;
|
||||
getVec(*ob, subs.at(0), vec);
|
||||
return gp_Vec(vec.x, vec.y, vec.z);
|
||||
}
|
||||
|
||||
gp_Vec MeasureAngle::location1() {
|
||||
|
||||
App::DocumentObject* ob = Element1.getValue();
|
||||
std::vector<std::string> subs = Element1.getSubValues();
|
||||
|
||||
if (!ob || !ob->isValid() || subs.empty() ) {
|
||||
return {};
|
||||
}
|
||||
auto temp = getLoc(*ob, subs.at(0));
|
||||
return {temp.x, temp.y, temp.z};
|
||||
}
|
||||
gp_Vec MeasureAngle::location2() {
|
||||
App::DocumentObject* ob = Element2.getValue();
|
||||
std::vector<std::string> subs = Element2.getSubValues();
|
||||
|
||||
if (!ob || !ob->isValid() || subs.empty() ) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto temp = getLoc(*ob, subs.at(0));
|
||||
return {temp.x, temp.y, temp.z};
|
||||
}
|
||||
|
||||
App::DocumentObjectExecReturn *MeasureAngle::execute()
|
||||
{
|
||||
App::DocumentObject* ob1 = Element1.getValue();
|
||||
std::vector<std::string> subs1 = Element1.getSubValues();
|
||||
|
||||
App::DocumentObject* ob2 = Element2.getValue();
|
||||
std::vector<std::string> subs2 = Element2.getSubValues();
|
||||
|
||||
if (!ob1 || !ob1->isValid() || !ob2 || !ob2->isValid()) {
|
||||
return new App::DocumentObjectExecReturn("Submitted object(s) is not valid");
|
||||
}
|
||||
|
||||
if (subs1.empty() || subs2.empty()) {
|
||||
return new App::DocumentObjectExecReturn("No geometry element picked");
|
||||
}
|
||||
|
||||
Base::Vector3d vec1;
|
||||
getVec(*ob1, subs1.at(0), vec1);
|
||||
|
||||
Base::Vector3d vec2;
|
||||
getVec(*ob2, subs2.at(0), vec2);
|
||||
|
||||
Angle.setValue(Base::toDegrees(vec1.GetAngle(vec2)));
|
||||
|
||||
return DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
void MeasureAngle::onChanged(const App::Property* prop)
|
||||
{
|
||||
|
||||
if (prop == &Element1 || prop == &Element2) {
|
||||
if (!isRestoring()) {
|
||||
App::DocumentObjectExecReturn *ret = recompute();
|
||||
delete ret;
|
||||
}
|
||||
}
|
||||
DocumentObject::onChanged(prop);
|
||||
}
|
||||
|
||||
//! Return the object we are measuring
|
||||
//! used by the viewprovider in determining visibility
|
||||
std::vector<App::DocumentObject*> MeasureAngle::getSubject() const
|
||||
{
|
||||
return {Element1.getValue()};
|
||||
}
|
||||
|
||||
93
src/Mod/Measure/App/MeasureAngle.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/***************************************************************************
|
||||
* 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 APP_MEASUREANGLE_H
|
||||
#define APP_MEASUREANGLE_H
|
||||
|
||||
#include <Mod/Measure/MeasureGlobal.h>
|
||||
|
||||
#include <gp_Vec.hxx>
|
||||
|
||||
#include <App/PropertyGeo.h>
|
||||
#include <App/PropertyLinks.h>
|
||||
#include <App/PropertyUnits.h>
|
||||
#include <Base/Vector3D.h>
|
||||
|
||||
#include <Mod/Part/App/MeasureInfo.h>
|
||||
|
||||
#include "MeasureBase.h"
|
||||
|
||||
|
||||
namespace Measure
|
||||
{
|
||||
|
||||
|
||||
class MeasureExport MeasureAngle : public Measure::MeasureBaseExtendable<Part::MeasureAngleInfo>
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(Measure::MeasureAngle);
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
MeasureAngle();
|
||||
~MeasureAngle() override;
|
||||
|
||||
App::PropertyLinkSub Element1;
|
||||
App::PropertyLinkSub Element2;
|
||||
App::PropertyAngle Angle;
|
||||
|
||||
App::DocumentObjectExecReturn *execute() override;
|
||||
|
||||
const char* getViewProviderName() const override {
|
||||
return "MeasureGui::ViewProviderMeasureAngle";
|
||||
}
|
||||
|
||||
static bool isValidSelection(const App::MeasureSelection& selection);
|
||||
static bool isPrioritizedSelection(const App::MeasureSelection& selection);
|
||||
void parseSelection(const App::MeasureSelection& selection) override;
|
||||
|
||||
std::vector<std::string> getInputProps() override {return {"Element1", "Element2"};}
|
||||
App::Property* getResultProp() override {return &this->Angle;}
|
||||
|
||||
// Return the object we are measuring
|
||||
std::vector<App::DocumentObject*> getSubject() const override;
|
||||
|
||||
|
||||
static bool getVec(App::DocumentObject& ob, std::string& subName, Base::Vector3d& vecOut);
|
||||
Base::Vector3d getLoc(App::DocumentObject& ob, std::string& subName);
|
||||
|
||||
// Orientation Vectors
|
||||
gp_Vec vector1();
|
||||
gp_Vec vector2();
|
||||
|
||||
// Location Vectors
|
||||
gp_Vec location1();
|
||||
gp_Vec location2();
|
||||
|
||||
private:
|
||||
|
||||
void onChanged(const App::Property* prop) override;
|
||||
};
|
||||
|
||||
} //namespace Measure
|
||||
|
||||
|
||||
#endif // APP_MEASUREANGLE_H
|
||||
181
src/Mod/Measure/App/MeasureArea.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
/***************************************************************************
|
||||
* 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 <App/Application.h>
|
||||
#include <App/MeasureManager.h>
|
||||
#include <App/Document.h>
|
||||
|
||||
#include "MeasureArea.h"
|
||||
|
||||
|
||||
using namespace Measure;
|
||||
|
||||
PROPERTY_SOURCE(Measure::MeasureArea, Measure::MeasureBase)
|
||||
|
||||
|
||||
|
||||
MeasureArea::MeasureArea()
|
||||
{
|
||||
ADD_PROPERTY_TYPE(Elements,(nullptr), "Measurement", App::Prop_None, "Element to get the area from");
|
||||
Elements.setScope(App::LinkScope::Global);
|
||||
Elements.setAllowExternal(true);
|
||||
|
||||
ADD_PROPERTY_TYPE(Area,(0.0), "Measurement", App::PropertyType(App::Prop_ReadOnly|App::Prop_Output),
|
||||
"Area of element");
|
||||
|
||||
}
|
||||
|
||||
MeasureArea::~MeasureArea() = default;
|
||||
|
||||
|
||||
bool MeasureArea::isValidSelection(const App::MeasureSelection& selection){
|
||||
|
||||
if (selection.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto element : selection) {
|
||||
auto objT = element.object;
|
||||
|
||||
App::DocumentObject* ob = objT.getObject();
|
||||
const std::string& subName = objT.getSubName();
|
||||
const char* className = objT.getSubObject()->getTypeId().getName();
|
||||
std::string mod = Base::Type::getModuleName(className);
|
||||
|
||||
if (!hasGeometryHandler(mod)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
App::MeasureHandler handler = App::MeasureManager::getMeasureHandler(mod.c_str());
|
||||
App::MeasureElementType type = handler.typeCb(ob, subName.c_str());
|
||||
|
||||
if (type == App::MeasureElementType::INVALID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Also support Cylinder & Volume?
|
||||
if ((type != App::MeasureElementType::PLANE && type != App::MeasureElementType::CYLINDER)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MeasureArea::parseSelection(const App::MeasureSelection& selection) {
|
||||
// Set properties from selection, method is only invoked when isValid Selection returns true
|
||||
|
||||
std::vector<App::DocumentObject*> objects;
|
||||
std::vector<std::string> subElements;
|
||||
|
||||
for (auto element : selection) {
|
||||
auto objT = element.object;
|
||||
|
||||
objects.push_back(objT.getObject());
|
||||
subElements.push_back(objT.getSubName());
|
||||
}
|
||||
|
||||
Elements.setValues(objects, subElements);
|
||||
}
|
||||
|
||||
|
||||
App::DocumentObjectExecReturn *MeasureArea::execute()
|
||||
{
|
||||
recalculateArea();
|
||||
return DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
void MeasureArea::recalculateArea()
|
||||
{
|
||||
const std::vector<App::DocumentObject*>& objects = Elements.getValues();
|
||||
const std::vector<std::string>& subElements = Elements.getSubValues();
|
||||
|
||||
double result(0.0);
|
||||
|
||||
// Loop through Elements and call the valid geometry handler
|
||||
for (std::vector<App::DocumentObject*>::size_type i=0; i<objects.size(); i++) {
|
||||
App::DocumentObject *object = objects.at(i);
|
||||
std::string subElement = subElements.at(i);
|
||||
|
||||
// Get the Geometry handler based on the module
|
||||
const char* className = object->getSubObject(subElement.c_str())->getTypeId().getName();
|
||||
const std::string& mod = Base::Type::getModuleName(className);
|
||||
auto handler = getGeometryHandler(mod);
|
||||
if (!handler) {
|
||||
throw Base::RuntimeError("No geometry handler available for submitted element type");
|
||||
}
|
||||
|
||||
App::SubObjectT subject{object, subElement.c_str()};
|
||||
auto info = handler(subject);
|
||||
auto areaInfo = std::dynamic_pointer_cast<Part::MeasureAreaInfo>(info);
|
||||
result += areaInfo->area;
|
||||
}
|
||||
|
||||
Area.setValue(result);
|
||||
}
|
||||
|
||||
void MeasureArea::onChanged(const App::Property* prop)
|
||||
{
|
||||
if (isRestoring() || isRemoving()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop == &Elements) {
|
||||
recalculateArea();
|
||||
}
|
||||
|
||||
MeasureBase::onChanged(prop);
|
||||
}
|
||||
|
||||
|
||||
Base::Placement MeasureArea::getPlacement() {
|
||||
const std::vector<App::DocumentObject*>& objects = Elements.getValues();
|
||||
const std::vector<std::string>& subElements = Elements.getSubValues();
|
||||
|
||||
if (objects.empty() || subElements.empty()) {
|
||||
return Base::Placement();
|
||||
}
|
||||
|
||||
App::DocumentObject* object = objects.front();
|
||||
std::string subElement = subElements.front();
|
||||
const char* className = object->getSubObject(subElement.c_str())->getTypeId().getName();
|
||||
const std::string& mod = Base::Type::getModuleName(className);
|
||||
|
||||
auto handler = getGeometryHandler(mod);
|
||||
if (!handler) {
|
||||
throw Base::RuntimeError("No geometry handler available for submitted element type");
|
||||
}
|
||||
|
||||
App::SubObjectT subject{object, subElement.c_str()};
|
||||
auto info = handler(subject);
|
||||
auto areaInfo = std::dynamic_pointer_cast<Part::MeasureAreaInfo>(info);
|
||||
return areaInfo->placement;
|
||||
}
|
||||
|
||||
|
||||
//! Return the object we are measuring
|
||||
//! used by the viewprovider in determining visibility
|
||||
std::vector<App::DocumentObject*> MeasureArea::getSubject() const
|
||||
{
|
||||
return Elements.getValues();
|
||||
}
|
||||
86
src/Mod/Measure/App/MeasureArea.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/***************************************************************************
|
||||
* 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 MEASURE_MEASUREAREA_H
|
||||
#define MEASURE_MEASUREAREA_H
|
||||
|
||||
#include <Mod/Measure/MeasureGlobal.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <App/PropertyLinks.h>
|
||||
#include <App/PropertyUnits.h>
|
||||
#include <App/GeoFeature.h>
|
||||
|
||||
#include <Mod/Part/App/MeasureInfo.h>
|
||||
|
||||
#include "MeasureBase.h"
|
||||
|
||||
|
||||
namespace Measure
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
class MeasureExport MeasureArea : public Measure::MeasureBaseExtendable<Part::MeasureAreaInfo>
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(Measure::MeasureArea);
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
MeasureArea();
|
||||
~MeasureArea() override;
|
||||
|
||||
App::PropertyLinkSubList Elements;
|
||||
App::PropertyArea Area;
|
||||
|
||||
App::DocumentObjectExecReturn *execute() override;
|
||||
void recalculateArea();
|
||||
|
||||
const char* getViewProviderName() const override {
|
||||
return "MeasureGui::ViewProviderMeasure";
|
||||
}
|
||||
|
||||
static bool isValidSelection(const App::MeasureSelection& selection);
|
||||
void parseSelection(const App::MeasureSelection& selection) override;
|
||||
|
||||
std::vector<std::string> getInputProps() override {return {"Elements"};}
|
||||
App::Property* getResultProp() override {return &this->Area;}
|
||||
|
||||
// Return a placement for the viewprovider, just use the first element for now
|
||||
Base::Placement getPlacement() override;
|
||||
|
||||
// Return the object we are measuring
|
||||
std::vector<App::DocumentObject*> getSubject() const override;
|
||||
|
||||
|
||||
private:
|
||||
void onChanged(const App::Property* prop) override;
|
||||
|
||||
};
|
||||
|
||||
} //namespace Measure
|
||||
|
||||
|
||||
#endif // MEASURE_MEASUREAREA_H
|
||||
|
||||
211
src/Mod/Measure/App/MeasureBase.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
/***************************************************************************
|
||||
* 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 <App/PropertyGeo.h>
|
||||
#include <Base/PlacementPy.h>
|
||||
#include <App/FeaturePythonPyImp.h>
|
||||
#include <App/DocumentObjectPy.h>
|
||||
|
||||
#include "MeasureBase.h"
|
||||
// Generated from MeasureBasePy.xml
|
||||
#include "MeasureBasePy.h"
|
||||
|
||||
using namespace Measure;
|
||||
|
||||
|
||||
PROPERTY_SOURCE(Measure::MeasureBase, App::DocumentObject)
|
||||
|
||||
MeasureBase::MeasureBase() {
|
||||
ADD_PROPERTY_TYPE(Placement, (Base::Placement()), nullptr, App::PropertyType(App::Prop_ReadOnly|App::Prop_Output|App::Prop_NoRecompute), "Visual placement of the measurement");
|
||||
|
||||
}
|
||||
|
||||
|
||||
PyObject *MeasureBase::getPyObject(void)
|
||||
{
|
||||
if (PythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
PythonObject = Py::Object(new MeasureBasePy(this), true);
|
||||
}
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
|
||||
Py::Object MeasureBase::getProxyObject() const {
|
||||
Base::PyGILStateLocker lock;
|
||||
App::Property* prop = this->getPropertyByName("Proxy");
|
||||
if (!prop) {
|
||||
return Py::None();
|
||||
}
|
||||
return dynamic_cast<App::PropertyPythonObject*>(prop)->getValue();
|
||||
};
|
||||
|
||||
std::vector<App::DocumentObject*> MeasureBase::getSubject() const {
|
||||
Base::PyGILStateLocker lock;
|
||||
|
||||
Py::Object proxy = getProxyObject();
|
||||
|
||||
// Pass the feture object to the proxy
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::Object(const_cast<MeasureBase*>(this)->getPyObject()));
|
||||
|
||||
Py::Object ret;
|
||||
try {
|
||||
ret = proxy.callMemberFunction("getSubject", args);
|
||||
} catch (Py::Exception&) {
|
||||
Base::PyException e;
|
||||
e.ReportException();
|
||||
return {};
|
||||
}
|
||||
|
||||
Py::Sequence retTuple(ret);
|
||||
std::vector<App::DocumentObject*> retVec;
|
||||
for (Py::Object o : retTuple) {
|
||||
retVec.push_back(static_cast<App::DocumentObjectPy*>(o.ptr())->getDocumentObjectPtr());
|
||||
}
|
||||
|
||||
return retVec;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
void MeasureBase::parseSelection(const App::MeasureSelection& selection) {
|
||||
Base::PyGILStateLocker lock;
|
||||
|
||||
Py::Object proxy = getProxyObject();
|
||||
|
||||
// Convert selection to python list
|
||||
Py::Tuple selectionPy = App::MeasureManager::getSelectionPy(selection);
|
||||
|
||||
Py::Tuple args(2);
|
||||
|
||||
// Pass the feture object to the proxy
|
||||
args.setItem(0, Py::Object(const_cast<MeasureBase*>(this)->getPyObject()));
|
||||
args.setItem(1, selectionPy);
|
||||
|
||||
// Call the parseSelection method of the proxy object
|
||||
try {
|
||||
proxy.callMemberFunction("parseSelection", args);
|
||||
} catch (Py::Exception&) {
|
||||
Base::PyException e;
|
||||
e.ReportException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> MeasureBase::getInputProps() {
|
||||
Base::PyGILStateLocker lock;
|
||||
Py::Object proxy = getProxyObject();
|
||||
|
||||
if (proxy.isNone()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Py::Object ret;
|
||||
try {
|
||||
ret = proxy.callMemberFunction("getInputProps");
|
||||
} catch (Py::Exception&) {
|
||||
Base::PyException e;
|
||||
e.ReportException();
|
||||
return {};
|
||||
}
|
||||
Py::Sequence propsPy(ret);
|
||||
|
||||
// Get cpp vector from propsPy
|
||||
std::vector<std::string> props;
|
||||
for (Py::Object o : propsPy) {
|
||||
props.push_back(o.as_string());
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
|
||||
|
||||
QString MeasureBase::getResultString() {
|
||||
Py::Object proxy = getProxyObject();
|
||||
Base::PyGILStateLocker lock;
|
||||
|
||||
if (!proxy.isNone()) {
|
||||
|
||||
// Pass the feture object to the proxy
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::Object(const_cast<MeasureBase*>(this)->getPyObject()));
|
||||
|
||||
Py::Object ret;
|
||||
try {
|
||||
ret = proxy.callMemberFunction("getResultString", args);
|
||||
} catch (Py::Exception&) {
|
||||
Base::PyException e;
|
||||
e.ReportException();
|
||||
return QString();
|
||||
}
|
||||
return QString::fromStdString(ret.as_string());
|
||||
}
|
||||
|
||||
App::Property* prop = getResultProp();
|
||||
if (prop == nullptr) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
if (prop->isDerivedFrom(App::PropertyQuantity::getClassTypeId())) {
|
||||
return static_cast<App::PropertyQuantity*>(prop)->getQuantityValue().getUserString();
|
||||
}
|
||||
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
void MeasureBase::onDocumentRestored() {
|
||||
// Force recompute the measurement
|
||||
recompute();
|
||||
}
|
||||
|
||||
Base::Placement MeasureBase::getPlacement() {
|
||||
return this->Placement.getValue();
|
||||
}
|
||||
|
||||
|
||||
// Python Drawing feature ---------------------------------------------------------
|
||||
|
||||
namespace App {
|
||||
/// @cond DOXERR
|
||||
PROPERTY_SOURCE_TEMPLATE(Measure::MeasurePython, Measure::MeasureBase)
|
||||
template<> const char* Measure::MeasurePython::getViewProviderName(void) const {
|
||||
return "MeasureGui::ViewProviderMeasure";
|
||||
}
|
||||
template<> PyObject* Measure::MeasurePython::getPyObject() {
|
||||
if (PythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
PythonObject = Py::Object(new FeaturePythonPyT<Measure::MeasureBasePy>(this),true);
|
||||
}
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
// explicit template instantiation
|
||||
template class MeasureExport FeaturePythonT<Measure::MeasureBase>;
|
||||
}
|
||||
|
||||
|
||||
131
src/Mod/Measure/App/MeasureBase.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/***************************************************************************
|
||||
* 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 MEASURE_MEASUREBASE_H
|
||||
#define MEASURE_MEASUREBASE_H
|
||||
|
||||
#include <Mod/Measure/MeasureGlobal.h>
|
||||
|
||||
#include <memory>
|
||||
#include <QString>
|
||||
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/MeasureManager.h>
|
||||
#include <App/DocumentObserver.h>
|
||||
#include <App/PropertyStandard.h>
|
||||
#include <App/PropertyUnits.h>
|
||||
#include <App/FeaturePython.h>
|
||||
#include <Base/Quantity.h>
|
||||
#include <Base/Placement.h>
|
||||
#include <Base/Interpreter.h>
|
||||
|
||||
#include <Mod/Part/App/MeasureInfo.h>
|
||||
#include <Mod/Part/App/MeasureClient.h> // needed?
|
||||
|
||||
|
||||
namespace Measure
|
||||
{
|
||||
|
||||
class MeasureExport MeasureBase : public App::DocumentObject
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(Measure::MeasureBase);
|
||||
|
||||
public:
|
||||
MeasureBase();
|
||||
~MeasureBase() override = default;
|
||||
|
||||
App::PropertyPlacement Placement;
|
||||
|
||||
// boost::signals2::signal<void (const MeasureBase*)> signalGuiInit;
|
||||
|
||||
//return PyObject as MeasureBasePy
|
||||
PyObject *getPyObject() override;
|
||||
|
||||
// Initialize measurement properties from selection
|
||||
virtual void parseSelection(const App::MeasureSelection& selection);
|
||||
|
||||
|
||||
virtual QString getResultString();
|
||||
|
||||
virtual std::vector<std::string> getInputProps();
|
||||
virtual App::Property* getResultProp() {return {};};
|
||||
virtual Base::Placement getPlacement();
|
||||
|
||||
// Return the objects that are measured
|
||||
virtual std::vector<App::DocumentObject*> getSubject() const;
|
||||
|
||||
private:
|
||||
Py::Object getProxyObject() const;
|
||||
|
||||
protected:
|
||||
void onDocumentRestored() override;
|
||||
};
|
||||
|
||||
// Create a scriptable object based on MeasureBase
|
||||
using MeasurePython = App::FeaturePythonT<MeasureBase>;
|
||||
|
||||
template <typename T>
|
||||
class MeasureExport MeasureBaseExtendable : public MeasureBase
|
||||
{
|
||||
|
||||
using GeometryHandler = std::function<Part::MeasureInfoPtr (const App::SubObjectT&)>;
|
||||
using HandlerMap = std::map<std::string, GeometryHandler>;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
static void addGeometryHandler(const std::string& module, GeometryHandler callback) {
|
||||
_mGeometryHandlers[module] = callback;
|
||||
}
|
||||
|
||||
static GeometryHandler getGeometryHandler(const std::string& module) {
|
||||
|
||||
if (!hasGeometryHandler(module)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return _mGeometryHandlers[module];
|
||||
}
|
||||
|
||||
static void addGeometryHandlers(const std::vector<std::string>& modules, GeometryHandler callback){
|
||||
// TODO: this will replace a callback with a later one. Should we check that there isn't already a
|
||||
// handler defined for this module?
|
||||
for (auto& mod : modules) {
|
||||
_mGeometryHandlers[mod] = callback;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool hasGeometryHandler(const std::string& module) {
|
||||
return (_mGeometryHandlers.count(module) > 0);
|
||||
}
|
||||
|
||||
private:
|
||||
inline static HandlerMap _mGeometryHandlers = MeasureBaseExtendable<T>::HandlerMap();
|
||||
};
|
||||
|
||||
|
||||
|
||||
} //namespace Measure
|
||||
|
||||
|
||||
#endif // MEASURE_MEASUREBASE_H
|
||||
20
src/Mod/Measure/App/MeasureBasePy.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="DocumentObjectPy"
|
||||
Name="MeasureBasePy"
|
||||
Twin="MeasureBase"
|
||||
TwinPointer="MeasureBase"
|
||||
Include="Mod/Measure/App/MeasureBase.h"
|
||||
Namespace="Measure"
|
||||
FatherInclude="App/DocumentObjectPy.h"
|
||||
FatherNamespace="App"
|
||||
Constructor="true">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="David Friedli(hlorus)" EMail="david@friedli-be.ch" />
|
||||
<UserDocu>User documentation here
|
||||
</UserDocu>
|
||||
<DeveloperDocu>Developer documentation here</DeveloperDocu>
|
||||
</Documentation>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
40
src/Mod/Measure/App/MeasureBasePyImp.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include "MeasureBase.h"
|
||||
|
||||
// Inclusion of the generated files (generated out of MeasureBasePy.xml)
|
||||
#include "MeasureBasePy.h"
|
||||
#include "MeasureBasePy.cpp"
|
||||
|
||||
|
||||
#include <Base/GeometryPyCXX.h>
|
||||
|
||||
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string MeasureBasePy::representation() const
|
||||
{
|
||||
return "<Measure::MeasureBase>";
|
||||
}
|
||||
|
||||
PyObject *MeasureBasePy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper
|
||||
{
|
||||
// create a new instance of MeasureBasePy and the Twin object
|
||||
return new MeasureBasePy(new MeasureBase);
|
||||
}
|
||||
|
||||
|
||||
// constructor method
|
||||
int MeasureBasePy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject *MeasureBasePy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int MeasureBasePy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
231
src/Mod/Measure/App/MeasureDistance.cpp
Normal file
@@ -0,0 +1,231 @@
|
||||
/***************************************************************************
|
||||
* 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 <App/PropertyContainer.h>
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/MeasureManager.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <BRepExtrema_DistShapeShape.hxx>
|
||||
|
||||
#include "MeasureDistance.h"
|
||||
|
||||
|
||||
using namespace Measure;
|
||||
|
||||
PROPERTY_SOURCE(Measure::MeasureDistance, Measure::MeasureBase)
|
||||
|
||||
|
||||
MeasureDistance::MeasureDistance()
|
||||
{
|
||||
ADD_PROPERTY_TYPE(Element1,(nullptr), "Measurement", App::Prop_None, "First element of the measurement");
|
||||
Element1.setScope(App::LinkScope::Global);
|
||||
Element1.setAllowExternal(true);
|
||||
|
||||
ADD_PROPERTY_TYPE(Element2,(nullptr), "Measurement", App::Prop_None, "Second element of the measurement");
|
||||
Element2.setScope(App::LinkScope::Global);
|
||||
Element2.setAllowExternal(true);
|
||||
|
||||
ADD_PROPERTY_TYPE(Distance,(0.0) ,"Measurement",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output),
|
||||
"Distance between the two elements");
|
||||
Distance.setUnit(Base::Unit::Length);
|
||||
|
||||
ADD_PROPERTY_TYPE(Position1,(Base::Vector3d(0.0,0.0,0.0)),"Measurement", App::Prop_Hidden, "Position1");
|
||||
ADD_PROPERTY_TYPE(Position2,(Base::Vector3d(0.0,1.0,0.0)),"Measurement", App::Prop_Hidden, "Position2");
|
||||
|
||||
}
|
||||
|
||||
MeasureDistance::~MeasureDistance() = default;
|
||||
|
||||
|
||||
bool MeasureDistance::isValidSelection(const App::MeasureSelection& selection){
|
||||
|
||||
if (selection.size() != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto element : selection) {
|
||||
|
||||
auto objT = element.object;
|
||||
|
||||
App::DocumentObject* ob = objT.getObject();
|
||||
const std::string& subName = objT.getSubName();
|
||||
const char* className = objT.getSubObject()->getTypeId().getName();
|
||||
std::string mod = Base::Type::getModuleName(className);
|
||||
|
||||
if (!hasGeometryHandler(mod)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
App::MeasureHandler handler = App::MeasureManager::getMeasureHandler(mod.c_str());
|
||||
App::MeasureElementType type = handler.typeCb(ob, subName.c_str());
|
||||
|
||||
if (type == App::MeasureElementType::INVALID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
type != App::MeasureElementType::POINT &&
|
||||
type != App::MeasureElementType::LINE &&
|
||||
type != App::MeasureElementType::LINESEGMENT &&
|
||||
type != App::MeasureElementType::CIRCLE &&
|
||||
type != App::MeasureElementType::ARC &&
|
||||
type != App::MeasureElementType::CURVE &&
|
||||
type != App::MeasureElementType::PLANE &&
|
||||
type != App::MeasureElementType::CYLINDER
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MeasureDistance::isPrioritizedSelection(const App::MeasureSelection& selection) {
|
||||
|
||||
(void)selection;
|
||||
|
||||
// TODO: Check if Elements ar parallel
|
||||
// if (selection.size() == 2) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void MeasureDistance::parseSelection(const App::MeasureSelection& selection) {
|
||||
|
||||
assert(selection.size() >= 2);
|
||||
|
||||
auto element1 = selection.at(0);
|
||||
auto objT1 = element1.object;
|
||||
App::DocumentObject* ob1 = objT1.getObject();
|
||||
const std::vector<std::string> elems1 = {objT1.getSubName()};
|
||||
Element1.setValue(ob1, elems1);
|
||||
|
||||
auto element2 = selection.at(1);
|
||||
auto objT2 = element2.object;
|
||||
App::DocumentObject* ob2 = objT2.getObject();
|
||||
const std::vector<std::string> elems2 = {objT2.getSubName()};
|
||||
Element2.setValue(ob2, elems2);
|
||||
}
|
||||
|
||||
|
||||
bool MeasureDistance::getShape(App::PropertyLinkSub* prop, TopoDS_Shape& rShape) {
|
||||
|
||||
App::DocumentObject* ob = prop->getValue();
|
||||
std::vector<std::string> subs = prop->getSubValues();
|
||||
|
||||
if (!ob || !ob->isValid() || subs.empty() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string subName = subs.at(0);
|
||||
const char* className = ob->getSubObject(subName.c_str())->getTypeId().getName();
|
||||
std::string mod = Base::Type::getModuleName(className);
|
||||
|
||||
if (!hasGeometryHandler(mod)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto handler = getGeometryHandler(mod);
|
||||
std::string obName = static_cast<std::string>(ob->getNameInDocument());
|
||||
App::SubObjectT subject{ob, subName.c_str()};
|
||||
auto info = handler(subject);
|
||||
if (!info->valid) {
|
||||
return false;
|
||||
}
|
||||
auto distanceInfo = std::dynamic_pointer_cast<Part::MeasureDistanceInfo>(info);
|
||||
|
||||
rShape = *distanceInfo->getShape();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
App::DocumentObjectExecReturn *MeasureDistance::execute()
|
||||
{
|
||||
|
||||
App::DocumentObject* ob1 = Element1.getValue();
|
||||
std::vector<std::string> subs1 = Element1.getSubValues();
|
||||
|
||||
App::DocumentObject* ob2 = Element2.getValue();
|
||||
std::vector<std::string> subs2 = Element2.getSubValues();
|
||||
|
||||
if (!ob1 || !ob1->isValid() || !ob2 || !ob2->isValid()) {
|
||||
return new App::DocumentObjectExecReturn("Submitted object(s) is not valid");
|
||||
}
|
||||
|
||||
if (subs1.empty() || subs2.empty()) {
|
||||
return new App::DocumentObjectExecReturn("No geometry element picked");
|
||||
}
|
||||
|
||||
// Get both shapes from geometry handler
|
||||
TopoDS_Shape shape1;
|
||||
if (!this->getShape(&Element1, shape1)) {
|
||||
return new App::DocumentObjectExecReturn("Could not get shape");
|
||||
}
|
||||
|
||||
TopoDS_Shape shape2;
|
||||
if (!this->getShape(&Element2, shape2)) {
|
||||
return new App::DocumentObjectExecReturn("Could not get shape");
|
||||
}
|
||||
|
||||
// Calculate the extrema
|
||||
BRepExtrema_DistShapeShape measure(shape1, shape2);
|
||||
if (!measure.IsDone() || measure.NbSolution() < 1) {
|
||||
return new App::DocumentObjectExecReturn("Could not get extrema");
|
||||
}
|
||||
|
||||
Distance.setValue(measure.Value());
|
||||
|
||||
gp_Pnt p1 = measure.PointOnShape1(1);
|
||||
Position1.setValue(p1.X(), p1.Y(), p1.Z());
|
||||
|
||||
gp_Pnt p2 = measure.PointOnShape2(1);
|
||||
Position2.setValue(p2.X(), p2.Y(), p2.Z());
|
||||
|
||||
|
||||
return DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
void MeasureDistance::onChanged(const App::Property* prop)
|
||||
{
|
||||
|
||||
if (prop == &Element1 || prop == &Element2) {
|
||||
if (!isRestoring()) {
|
||||
App::DocumentObjectExecReturn *ret = recompute();
|
||||
delete ret;
|
||||
}
|
||||
}
|
||||
DocumentObject::onChanged(prop);
|
||||
}
|
||||
|
||||
|
||||
//! Return the object we are measuring
|
||||
//! used by the viewprovider in determining visibility
|
||||
std::vector<App::DocumentObject*> MeasureDistance::getSubject() const
|
||||
{
|
||||
return {Element1.getValue()};
|
||||
}
|
||||
|
||||
87
src/Mod/Measure/App/MeasureDistance.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/***************************************************************************
|
||||
* 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 MEASUREAPP_MEASUREDISTANCE_H
|
||||
#define MEASUREAPP_MEASUREDISTANCE_H
|
||||
|
||||
#include <Mod/Measure/MeasureGlobal.h>
|
||||
|
||||
#include <TopoDS_Shape.hxx>
|
||||
|
||||
#include <App/PropertyGeo.h>
|
||||
#include <App/PropertyLinks.h>
|
||||
#include <App/PropertyUnits.h>
|
||||
|
||||
#include <Mod/Part/App/MeasureInfo.h>
|
||||
|
||||
#include "MeasureBase.h"
|
||||
|
||||
namespace Measure
|
||||
{
|
||||
|
||||
|
||||
|
||||
class MeasureExport MeasureDistance : public Measure::MeasureBaseExtendable<Part::MeasureDistanceInfo>
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(Measure::MeasureDistance);
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
MeasureDistance();
|
||||
~MeasureDistance() override;
|
||||
|
||||
App::PropertyLinkSub Element1;
|
||||
App::PropertyLinkSub Element2;
|
||||
App::PropertyDistance Distance;
|
||||
|
||||
// Position properties for the viewprovider
|
||||
App::PropertyVector Position1;
|
||||
App::PropertyVector Position2;
|
||||
|
||||
App::DocumentObjectExecReturn *execute() override;
|
||||
|
||||
const char* getViewProviderName() const override {
|
||||
return "MeasureGui::ViewProviderMeasureDistance";
|
||||
}
|
||||
|
||||
static bool isValidSelection(const App::MeasureSelection& selection);
|
||||
static bool isPrioritizedSelection(const App::MeasureSelection& selection);
|
||||
void parseSelection(const App::MeasureSelection& selection) override;
|
||||
|
||||
std::vector<std::string> getInputProps() override {return {"Element1", "Element2"};}
|
||||
App::Property* getResultProp() override {return &this->Distance;}
|
||||
|
||||
bool getShape(App::PropertyLinkSub* prop, TopoDS_Shape& rShape);
|
||||
|
||||
// Return the object we are measuring
|
||||
std::vector<App::DocumentObject*> getSubject() const override;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void onChanged(const App::Property* prop) override;
|
||||
};
|
||||
|
||||
} //namespace Measure
|
||||
|
||||
|
||||
#endif // MEASUREAPP_MEASUREDISTANCE_H
|
||||
184
src/Mod/Measure/App/MeasureLength.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
/***************************************************************************
|
||||
* 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 <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/MeasureManager.h>
|
||||
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
|
||||
#include "MeasureLength.h"
|
||||
|
||||
|
||||
using namespace Measure;
|
||||
|
||||
PROPERTY_SOURCE(Measure::MeasureLength, Measure::MeasureBase)
|
||||
|
||||
|
||||
|
||||
MeasureLength::MeasureLength()
|
||||
{
|
||||
ADD_PROPERTY_TYPE(Elements,(nullptr), "Measurement", App::Prop_None, "Elements to get the length from");
|
||||
Elements.setScope(App::LinkScope::Global);
|
||||
Elements.setAllowExternal(true);
|
||||
|
||||
ADD_PROPERTY_TYPE(Length,(0.0) ,"Measurement",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output),
|
||||
"Length of selection");
|
||||
|
||||
}
|
||||
|
||||
MeasureLength::~MeasureLength() = default;
|
||||
|
||||
|
||||
bool MeasureLength::isValidSelection(const App::MeasureSelection& selection){
|
||||
|
||||
if (selection.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto element : selection) {
|
||||
auto objT = element.object;
|
||||
|
||||
App::DocumentObject* ob = objT.getObject();
|
||||
const std::string& subName = objT.getSubName();
|
||||
const char* className = objT.getSubObject()->getTypeId().getName();
|
||||
std::string mod = Base::Type::getModuleName(className);
|
||||
|
||||
if (!hasGeometryHandler(mod)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
App::MeasureHandler handler = App::MeasureManager::getMeasureHandler(mod.c_str());
|
||||
App::MeasureElementType type = handler.typeCb(ob, subName.c_str());
|
||||
|
||||
if (type == App::MeasureElementType::INVALID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((type != App::MeasureElementType::LINESEGMENT && type != App::MeasureElementType::CIRCLE
|
||||
&& type != App::MeasureElementType::ARC && type != App::MeasureElementType::CURVE)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MeasureLength::parseSelection(const App::MeasureSelection& selection) {
|
||||
// Set properties from selection, method is only invoked when isValid Selection returns true
|
||||
|
||||
std::vector<App::DocumentObject*> objects;
|
||||
std::vector<std::string> subElements;
|
||||
|
||||
for (auto element : selection) {
|
||||
auto objT = element.object;
|
||||
|
||||
objects.push_back(objT.getObject());
|
||||
subElements.push_back(objT.getSubName());
|
||||
}
|
||||
|
||||
Elements.setValues(objects, subElements);
|
||||
}
|
||||
|
||||
|
||||
App::DocumentObjectExecReturn *MeasureLength::execute()
|
||||
{
|
||||
recalculateLength();
|
||||
return DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
void MeasureLength::recalculateLength()
|
||||
{
|
||||
const std::vector<App::DocumentObject*>& objects = Elements.getValues();
|
||||
const std::vector<std::string>& subElements = Elements.getSubValues();
|
||||
|
||||
double result(0.0);
|
||||
|
||||
// Loop through Elements and call the valid geometry handler
|
||||
for (std::vector<App::DocumentObject*>::size_type i=0; i<objects.size(); i++) {
|
||||
App::DocumentObject *object = objects.at(i);
|
||||
std::string subElement = subElements.at(i);
|
||||
|
||||
// Get the Geometry handler based on the module
|
||||
const char* className = object->getSubObject(subElement.c_str())->getTypeId().getName();
|
||||
const std::string& mod = Base::Type::getModuleName(className);
|
||||
auto handler = getGeometryHandler(mod);
|
||||
if (!handler) {
|
||||
throw Base::RuntimeError("No geometry handler available for submitted element type");
|
||||
}
|
||||
|
||||
App::SubObjectT subject{object, subElement.c_str()};
|
||||
auto info = handler(subject);
|
||||
auto lengthInfo = std::dynamic_pointer_cast<Part::MeasureLengthInfo>(info);
|
||||
result += lengthInfo->length;
|
||||
}
|
||||
|
||||
Length.setValue(result);
|
||||
}
|
||||
|
||||
void MeasureLength::onChanged(const App::Property* prop)
|
||||
{
|
||||
if (isRestoring() || isRemoving()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop == &Elements) {
|
||||
recalculateLength();
|
||||
}
|
||||
|
||||
MeasureBase::onChanged(prop);
|
||||
}
|
||||
|
||||
|
||||
Base::Placement MeasureLength::getPlacement() {
|
||||
const std::vector<App::DocumentObject*>& objects = Elements.getValues();
|
||||
const std::vector<std::string>& subElements = Elements.getSubValues();
|
||||
|
||||
if (!objects.size() || !subElements.size()) {
|
||||
return Base::Placement();
|
||||
}
|
||||
|
||||
App::DocumentObject* object = objects.front();
|
||||
std::string subElement = subElements.front();
|
||||
const char* className = object->getSubObject(subElement.c_str())->getTypeId().getName();
|
||||
const std::string& mod = Base::Type::getModuleName(className);
|
||||
|
||||
auto handler = getGeometryHandler(mod);
|
||||
if (!handler) {
|
||||
throw Base::RuntimeError("No geometry handler available for submitted element type");
|
||||
}
|
||||
|
||||
App::SubObjectT subject{object, subElement.c_str()};
|
||||
auto info = handler(subject);
|
||||
auto lengthInfo = std::dynamic_pointer_cast<Part::MeasureLengthInfo>(info);
|
||||
return lengthInfo->placement;
|
||||
}
|
||||
|
||||
|
||||
//! Return the object we are measuring
|
||||
//! used by the viewprovider in determining visibility
|
||||
std::vector<App::DocumentObject*> MeasureLength::getSubject() const
|
||||
{
|
||||
return Elements.getValues();
|
||||
}
|
||||
|
||||
81
src/Mod/Measure/App/MeasureLength.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/***************************************************************************
|
||||
* 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 MEASURE_MEASURELENGTH_H
|
||||
#define MEASURE_MEASURELENGTH_H
|
||||
|
||||
#include <Mod/Measure/MeasureGlobal.h>
|
||||
|
||||
#include <App/PropertyLinks.h>
|
||||
#include <App/PropertyUnits.h>
|
||||
#include <App/GeoFeature.h>
|
||||
|
||||
#include <Mod/Part/App/MeasureInfo.h>
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
|
||||
#include "MeasureBase.h"
|
||||
|
||||
namespace Measure
|
||||
{
|
||||
|
||||
class MeasureExport MeasureLength : public Measure::MeasureBaseExtendable<Part::MeasureLengthInfo>
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(Measure::MeasureLength);
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
MeasureLength();
|
||||
~MeasureLength() override;
|
||||
|
||||
App::PropertyLinkSubList Elements;
|
||||
App::PropertyDistance Length;
|
||||
|
||||
App::DocumentObjectExecReturn *execute() override;
|
||||
void recalculateLength();
|
||||
|
||||
const char* getViewProviderName() const override {
|
||||
return "MeasureGui::ViewProviderMeasure";
|
||||
}
|
||||
|
||||
static bool isValidSelection(const App::MeasureSelection& selection);
|
||||
void parseSelection(const App::MeasureSelection& selection) override;
|
||||
|
||||
std::vector<std::string> getInputProps() override {return {"Elements"};}
|
||||
App::Property* getResultProp() override {return &this->Length;}
|
||||
|
||||
// Return a placement for the viewprovider, just use the first element for now
|
||||
Base::Placement getPlacement();
|
||||
|
||||
// Return the object we are measuring
|
||||
std::vector<App::DocumentObject*> getSubject() const override;
|
||||
|
||||
|
||||
private:
|
||||
void onChanged(const App::Property* prop) override;
|
||||
|
||||
};
|
||||
|
||||
} //namespace Measure
|
||||
|
||||
|
||||
#endif // MEASURE_MEASURELENGTH_H
|
||||
|
||||
177
src/Mod/Measure/App/MeasurePosition.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
/***************************************************************************
|
||||
* 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 <App/PropertyContainer.h>
|
||||
#include <App/Application.h>
|
||||
#include <App/MeasureManager.h>
|
||||
#include <App/Document.h>
|
||||
|
||||
#include "MeasurePosition.h"
|
||||
|
||||
|
||||
using namespace Measure;
|
||||
|
||||
PROPERTY_SOURCE(Measure::MeasurePosition, Measure::MeasureBase)
|
||||
|
||||
|
||||
|
||||
MeasurePosition::MeasurePosition()
|
||||
{
|
||||
ADD_PROPERTY_TYPE(Element,(nullptr), "Measurement", App::Prop_None, "Element to get the position from");
|
||||
Element.setScope(App::LinkScope::Global);
|
||||
Element.setAllowExternal(true);
|
||||
|
||||
|
||||
ADD_PROPERTY_TYPE(Position,(0.0, 0.0, 0.0), "Measurement", App::PropertyType(App::Prop_ReadOnly|App::Prop_Output),
|
||||
"The absolute position");
|
||||
|
||||
}
|
||||
|
||||
MeasurePosition::~MeasurePosition() = default;
|
||||
|
||||
|
||||
bool MeasurePosition::isValidSelection(const App::MeasureSelection& selection){
|
||||
|
||||
if (selection.empty() || selection.size() > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto element : selection) {
|
||||
auto objT = element.object;
|
||||
|
||||
App::DocumentObject* ob = objT.getObject();
|
||||
const std::string& subName = objT.getSubName();
|
||||
const char* className = objT.getSubObject()->getTypeId().getName();
|
||||
std::string mod = Base::Type::getModuleName(className);
|
||||
|
||||
if (!hasGeometryHandler(mod)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
App::MeasureHandler handler = App::MeasureManager::getMeasureHandler(mod.c_str());
|
||||
App::MeasureElementType type = handler.typeCb(ob, subName.c_str());
|
||||
|
||||
if (type == App::MeasureElementType::INVALID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type != App::MeasureElementType::POINT) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MeasurePosition::parseSelection(const App::MeasureSelection& selection) {
|
||||
// Set properties from selection, method is only invoked when isValid Selection returns true
|
||||
|
||||
for (auto element : selection) {
|
||||
auto objT = element.object;
|
||||
|
||||
std::vector<std::string> subElements {objT.getSubName()};
|
||||
Element.setValue(objT.getObject(), subElements);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
App::DocumentObjectExecReturn *MeasurePosition::execute()
|
||||
{
|
||||
recalculatePosition();
|
||||
return DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
void MeasurePosition::recalculatePosition()
|
||||
{
|
||||
const App::DocumentObject* object = Element.getValue();
|
||||
const std::vector<std::string>& subElements = Element.getSubValues();
|
||||
|
||||
// Get the position of the first point
|
||||
std::string subElement = subElements.front();
|
||||
|
||||
// Get the Geometry handler based on the module
|
||||
const char* className = object->getSubObject(subElement.c_str())->getTypeId().getName();
|
||||
const std::string& mod = Base::Type::getModuleName(className);
|
||||
auto handler = getGeometryHandler(mod);
|
||||
if (!handler) {
|
||||
throw Base::RuntimeError("No geometry handler available for submitted element type");
|
||||
}
|
||||
|
||||
App::SubObjectT subject{object, subElement.c_str()};
|
||||
auto info = handler(subject);
|
||||
auto positionInfo = std::dynamic_pointer_cast<Part::MeasurePositionInfo>(info);
|
||||
Position.setValue(positionInfo->position);
|
||||
}
|
||||
|
||||
void MeasurePosition::onChanged(const App::Property* prop)
|
||||
{
|
||||
if (isRestoring() || isRemoving()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop == &Element) {
|
||||
recalculatePosition();
|
||||
}
|
||||
DocumentObject::onChanged(prop);
|
||||
}
|
||||
|
||||
|
||||
QString MeasurePosition::getResultString() {
|
||||
App::Property* prop = this->getResultProp();
|
||||
if (prop == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Base::Vector3d value = Position.getValue();
|
||||
QString unit = Position.getUnit().getString();
|
||||
int precision = 2;
|
||||
QString text;
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
QTextStream(&text)
|
||||
<< "X: " << QString::number(value.x, 'f', precision) << " " << unit << endl
|
||||
<< "Y: " << QString::number(value.y, 'f', precision) << " " << unit << endl
|
||||
<< "Z: " << QString::number(value.z, 'f', precision) << " " << unit;
|
||||
#else
|
||||
QTextStream(&text)
|
||||
<< "X: " << QString::number(value.x, 'f', precision) << " " << unit << Qt::endl
|
||||
<< "Y: " << QString::number(value.y, 'f', precision) << " " << unit << Qt::endl
|
||||
<< "Z: " << QString::number(value.z, 'f', precision) << " " << unit;
|
||||
#endif
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
Base::Placement MeasurePosition::getPlacement() {
|
||||
Base::Placement placement;
|
||||
placement.setPosition(Position.getValue());
|
||||
return placement;
|
||||
}
|
||||
|
||||
|
||||
//! Return the object we are measuring
|
||||
//! used by the viewprovider in determining visibility
|
||||
std::vector<App::DocumentObject*> MeasurePosition::getSubject() const
|
||||
{
|
||||
return {Element.getValue()};
|
||||
}
|
||||
82
src/Mod/Measure/App/MeasurePosition.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/***************************************************************************
|
||||
* 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 APP_MEASUREPOSITION_H
|
||||
#define APP_MEASUREPOSITION_H
|
||||
|
||||
#include <Mod/Measure/MeasureGlobal.h>
|
||||
|
||||
#include <QTextStream>
|
||||
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/PropertyGeo.h>
|
||||
#include <App/PropertyUnits.h>
|
||||
|
||||
#include <Mod/Part/App/MeasureInfo.h>
|
||||
|
||||
#include "MeasureBase.h"
|
||||
|
||||
|
||||
namespace Measure
|
||||
{
|
||||
|
||||
|
||||
class MeasureExport MeasurePosition : public Measure::MeasureBaseExtendable<Part::MeasurePositionInfo>
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(Measure::MeasurePosition);
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
MeasurePosition();
|
||||
~MeasurePosition() override;
|
||||
|
||||
App::PropertyLinkSub Element;
|
||||
App::PropertyPosition Position;
|
||||
|
||||
App::DocumentObjectExecReturn *execute() override;
|
||||
void recalculatePosition();
|
||||
|
||||
const char* getViewProviderName() const override {
|
||||
return "MeasureGui::ViewProviderMeasure";
|
||||
}
|
||||
|
||||
static bool isValidSelection(const App::MeasureSelection& selection);
|
||||
void parseSelection(const App::MeasureSelection& selection) override;
|
||||
|
||||
std::vector<std::string> getInputProps() override {return {"Element"};}
|
||||
App::Property* getResultProp() override {return &this->Position;}
|
||||
QString getResultString() override;
|
||||
|
||||
Base::Placement getPlacement() override;
|
||||
|
||||
// Return the object we are measuring
|
||||
std::vector<App::DocumentObject*> getSubject() const override;
|
||||
|
||||
private:
|
||||
|
||||
void onChanged(const App::Property* prop) override;
|
||||
};
|
||||
|
||||
} //namespace Measure
|
||||
|
||||
|
||||
#endif // APP_MEASUREPOSITION_H
|
||||
211
src/Mod/Measure/App/MeasureRadius.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 WandererFan <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 <TopExp_Explorer.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <BRepLProp_CLProps.hxx>
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/MeasureManager.h>
|
||||
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
|
||||
#include "MeasureRadius.h"
|
||||
|
||||
|
||||
using namespace Measure;
|
||||
|
||||
PROPERTY_SOURCE(Measure::MeasureRadius, Measure::MeasureBase)
|
||||
|
||||
|
||||
|
||||
MeasureRadius::MeasureRadius()
|
||||
{
|
||||
ADD_PROPERTY_TYPE(Element,(nullptr), "Measurement", App::Prop_None, "Element to get the radius from");
|
||||
Element.setScope(App::LinkScope::Global);
|
||||
Element.setAllowExternal(true);
|
||||
|
||||
ADD_PROPERTY_TYPE(Radius,(0.0) ,"Measurement",App::PropertyType(App::Prop_ReadOnly|App::Prop_Output),
|
||||
"Radius of selection");
|
||||
|
||||
}
|
||||
|
||||
MeasureRadius::~MeasureRadius() = default;
|
||||
|
||||
//! validate all the object+subelement pairs in the selection. Must be circle or arc
|
||||
//! and have a geometry handler available. We only calculate radius if there is a
|
||||
//! single valid item in the selection
|
||||
bool MeasureRadius::isValidSelection(const App::MeasureSelection& selection){
|
||||
|
||||
if (selection.empty() || selection.size() > 1) {
|
||||
// too few or too many selections
|
||||
return false;
|
||||
}
|
||||
|
||||
auto element = selection.front();
|
||||
auto objT = element.object;
|
||||
|
||||
App::DocumentObject* ob = objT.getObject();
|
||||
const std::string& subName = objT.getSubName();
|
||||
const char* className = objT.getSubObject()->getTypeId().getName();
|
||||
std::string mod = Base::Type::getModuleName(className);
|
||||
|
||||
if (!hasGeometryHandler(mod)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
App::MeasureHandler handler = App::MeasureManager::getMeasureHandler(mod.c_str());
|
||||
App::MeasureElementType type = handler.typeCb(ob, subName.c_str());
|
||||
|
||||
if (type == App::MeasureElementType::INVALID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type != App::MeasureElementType::CIRCLE
|
||||
&& type != App::MeasureElementType::ARC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//! return true if the selection is particularly interesting to MeasureRadius.
|
||||
//! In this case we claim circles and arcs.
|
||||
bool MeasureRadius::isPrioritizedSelection(const App::MeasureSelection& selection) {
|
||||
if (selection.size() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto element = selection.front();
|
||||
auto objT = element.object;
|
||||
|
||||
App::DocumentObject* ob = objT.getObject();
|
||||
const std::string& subName = objT.getSubName();
|
||||
const char* className = objT.getSubObject()->getTypeId().getName();
|
||||
std::string mod = Base::Type::getModuleName(className);
|
||||
|
||||
if (!hasGeometryHandler(mod)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
App::MeasureHandler handler = App::MeasureManager::getMeasureHandler(mod.c_str());
|
||||
App::MeasureElementType type = handler.typeCb(ob, subName.c_str());
|
||||
|
||||
if (type == App::MeasureElementType::CIRCLE
|
||||
|| type == App::MeasureElementType::ARC) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//! Set properties from first item in selection. assumes a valid selection.
|
||||
void MeasureRadius::parseSelection(const App::MeasureSelection& selection) {
|
||||
auto element = selection.front();
|
||||
auto objT = element.object;
|
||||
|
||||
std::vector<std::string> subElementList { objT.getSubName() };
|
||||
Element.setValue(objT.getObject(), subElementList);
|
||||
}
|
||||
|
||||
|
||||
App::DocumentObjectExecReturn *MeasureRadius::execute()
|
||||
{
|
||||
recalculateRadius();
|
||||
return DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
|
||||
void MeasureRadius::recalculateRadius()
|
||||
{
|
||||
Radius.setValue(getMeasureInfoFirst()->radius);
|
||||
}
|
||||
|
||||
void MeasureRadius::onChanged(const App::Property* prop)
|
||||
{
|
||||
if (isRestoring() || isRemoving()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop == &Element) {
|
||||
recalculateRadius();
|
||||
}
|
||||
|
||||
MeasureBase::onChanged(prop);
|
||||
}
|
||||
|
||||
|
||||
//! return a placement (location + orientation) for the first element
|
||||
Base::Placement MeasureRadius::getPlacement() {
|
||||
auto loc = getMeasureInfoFirst()->pointOnCurve;
|
||||
auto p = Base::Placement();
|
||||
p.setPosition(loc);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
//! return the pointOnCurve element in MeasureRadiusInfo for the first element
|
||||
Base::Vector3d MeasureRadius::getPointOnCurve() const
|
||||
{
|
||||
return getMeasureInfoFirst()->pointOnCurve;
|
||||
}
|
||||
|
||||
//! get the handler's result for the first element
|
||||
Part::MeasureRadiusInfoPtr MeasureRadius::getMeasureInfoFirst() const
|
||||
{
|
||||
const App::DocumentObject* object = Element.getValue();
|
||||
const std::vector<std::string>& subElements = Element.getSubValues();
|
||||
|
||||
if (!object || subElements.empty()) {
|
||||
// NOLINTNEXTLINE(modernize-return-braced-init-list)
|
||||
return std::make_shared<Part::MeasureRadiusInfo>();
|
||||
}
|
||||
|
||||
std::string subElement = subElements.front();
|
||||
const char* className = object->getSubObject(subElement.c_str())->getTypeId().getName();
|
||||
const std::string& mod = Base::Type::getModuleName(className);
|
||||
|
||||
auto handler = getGeometryHandler(mod);
|
||||
if (!handler) {
|
||||
throw Base::RuntimeError("No geometry handler available for submitted element type");
|
||||
}
|
||||
|
||||
std::string obName = object->getNameInDocument();
|
||||
App::SubObjectT subject{object, subElement.c_str()};
|
||||
auto info = handler(subject);
|
||||
auto radiusInfo = std::dynamic_pointer_cast<Part::MeasureRadiusInfo>(info);
|
||||
return radiusInfo;
|
||||
}
|
||||
|
||||
//! Return the object we are measuring
|
||||
//! used by the viewprovider in determining visibility
|
||||
std::vector<App::DocumentObject*> MeasureRadius::getSubject() const
|
||||
{
|
||||
return {Element.getValue()};
|
||||
}
|
||||
90
src/Mod/Measure/App/MeasureRadius.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 WandererFan <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 MEASURE_MEASURERADIUS_H
|
||||
#define MEASURE_MEASURERADIUS_H
|
||||
|
||||
#include <Mod/Measure/MeasureGlobal.h>
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/PropertyLinks.h>
|
||||
#include <App/PropertyUnits.h>
|
||||
#include <App/GeoFeature.h>
|
||||
#include <Base/Placement.h>
|
||||
|
||||
#include <Mod/Part/App/MeasureInfo.h>
|
||||
|
||||
#include "MeasureBase.h"
|
||||
|
||||
|
||||
namespace Measure
|
||||
{
|
||||
|
||||
|
||||
class MeasureExport MeasureRadius : public Measure::MeasureBaseExtendable<Part::MeasureRadiusInfo>
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(Measure::MeasureRadius);
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
MeasureRadius();
|
||||
~MeasureRadius() override;
|
||||
|
||||
App::PropertyLinkSub Element;
|
||||
App::PropertyDistance Radius;
|
||||
|
||||
App::DocumentObjectExecReturn *execute() override;
|
||||
const char* getViewProviderName() const override {
|
||||
return "MeasureGui::ViewProviderMeasure";
|
||||
}
|
||||
|
||||
void recalculateRadius();
|
||||
|
||||
static bool isValidSelection(const App::MeasureSelection& selection);
|
||||
static bool isPrioritizedSelection(const App::MeasureSelection& selection);
|
||||
void parseSelection(const App::MeasureSelection& selection) override;
|
||||
|
||||
std::vector<std::string> getInputProps() override {return {"Element"};}
|
||||
App::Property* getResultProp() override {return &this->Radius;}
|
||||
|
||||
// Return a placement for the viewprovider, just use the first element for now
|
||||
Base::Placement getPlacement() override;
|
||||
// Return a point on curve for the viewprovider
|
||||
Base::Vector3d getPointOnCurve() const;
|
||||
|
||||
// Return the object we are measuring
|
||||
std::vector<App::DocumentObject*> getSubject() const override;
|
||||
|
||||
|
||||
private:
|
||||
void onChanged(const App::Property* prop) override;
|
||||
Part::MeasureRadiusInfoPtr getMeasureInfoFirst() const;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} //namespace Measure
|
||||
|
||||
|
||||
#endif // MEASURE_MEASURERADIUS_H
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ TopoDS_Shape Measurement::getShape(App::DocumentObject *obj , const char *subNam
|
||||
|
||||
try {
|
||||
Part::TopoShape partShape = Part::Feature::getTopoShape(obj);
|
||||
App::GeoFeature* geoFeat = dynamic_cast<App::GeoFeature*>(obj);
|
||||
App::GeoFeature* geoFeat = dynamic_cast<App::GeoFeature*>(obj);
|
||||
if (geoFeat) {
|
||||
partShape.setPlacement(geoFeat->globalPlacement());
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- this creates the bindings for the original measurement objects & methods. it is not part of unified measurement facility -->
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="BaseClassPy"
|
||||
|
||||
80
src/Mod/Measure/App/Preferences.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 WandererFan <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"
|
||||
#ifndef _PreComp_
|
||||
# include <string>
|
||||
#endif
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/Material.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Parameter.h>
|
||||
|
||||
#include "Preferences.h"
|
||||
|
||||
|
||||
//getters for parameters used in multiple places.
|
||||
//ensure this is in sync with parameter names and default values on preference pages
|
||||
|
||||
using namespace Measure;
|
||||
|
||||
//! Returns the Measure preference group
|
||||
Base::Reference<ParameterGrp> Preferences::getPreferenceGroup(const char* Name)
|
||||
{
|
||||
return App::GetApplication().GetUserParameter().GetGroup("BaseApp/Preferences/Mod/Measure")->GetGroup(Name);
|
||||
}
|
||||
|
||||
App::Color Preferences::defaultLineColor()
|
||||
{
|
||||
App::Color fcColor;
|
||||
fcColor.setPackedValue(getPreferenceGroup("Appearance")->GetUnsigned("DefaultLineColor", 0xFFFFFFFF));
|
||||
return fcColor;
|
||||
}
|
||||
|
||||
App::Color Preferences::defaultTextColor()
|
||||
{
|
||||
App::Color fcColor;
|
||||
fcColor.setPackedValue(getPreferenceGroup("Appearance")->GetUnsigned("DefaultTextColor", 0x00000000));
|
||||
return fcColor;
|
||||
}
|
||||
|
||||
App::Color Preferences::defaultTextBackgroundColor()
|
||||
{
|
||||
App::Color fcColor;
|
||||
fcColor.setPackedValue(getPreferenceGroup("Appearance")->GetUnsigned("DefaultTextBackgroundColor", 0xFFFFFFFF));
|
||||
return fcColor;
|
||||
}
|
||||
|
||||
double Preferences::defaultDistFactor()
|
||||
{
|
||||
return getPreferenceGroup("Appearance")->GetFloat("DefaultDistFactor", 1.0);
|
||||
}
|
||||
|
||||
int Preferences::defaultFontSize()
|
||||
{
|
||||
return getPreferenceGroup("Appearance")->GetInt("DefaultFontSize", 18);
|
||||
}
|
||||
|
||||
bool Preferences::defaultMirror()
|
||||
{
|
||||
return getPreferenceGroup("Appearance")->GetBool("DefaultMirror", false);
|
||||
}
|
||||
58
src/Mod/Measure/App/Preferences.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 WandererFan <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 Preferences_h_
|
||||
#define Preferences_h_
|
||||
|
||||
#include <Mod/Measure/MeasureGlobal.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <Base/Parameter.h>
|
||||
#include <App/Material.h>
|
||||
|
||||
namespace App
|
||||
{
|
||||
class Color;
|
||||
}
|
||||
|
||||
namespace Measure
|
||||
{
|
||||
|
||||
//getters for parameters used in multiple places.
|
||||
class MeasureExport Preferences
|
||||
{
|
||||
|
||||
public:
|
||||
static Base::Reference<ParameterGrp> getPreferenceGroup(const char* Name);
|
||||
|
||||
static App::Color defaultLineColor();
|
||||
static App::Color defaultTextColor();
|
||||
static double defaultDistFactor();
|
||||
static int defaultFontSize();
|
||||
static bool defaultMirror();
|
||||
static App::Color defaultTextBackgroundColor();
|
||||
};
|
||||
|
||||
|
||||
}//end namespace Measure
|
||||
#endif
|
||||
|
||||
@@ -1,12 +1,29 @@
|
||||
|
||||
add_subdirectory(App)
|
||||
if(FREECAD_BUILD_GUI)
|
||||
#add_subdirectory(Gui)
|
||||
endif(FREECAD_BUILD_GUI)
|
||||
|
||||
set(Measure_Scripts
|
||||
Init.py
|
||||
UtilsMeasure.py
|
||||
MeasureCOM.py
|
||||
)
|
||||
|
||||
if(BUILD_GUI)
|
||||
list(APPEND Measure_Scripts InitGui.py)
|
||||
add_subdirectory(Gui)
|
||||
endif(BUILD_GUI)
|
||||
|
||||
add_custom_target(MeasureScripts ALL
|
||||
SOURCES ${Measure_Scripts}
|
||||
)
|
||||
|
||||
fc_target_copy_resource(MeasureScripts
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_BINARY_DIR}/Mod/Measure
|
||||
${Measure_Scripts})
|
||||
|
||||
INSTALL(
|
||||
FILES
|
||||
Init.py
|
||||
${Measure_Scripts}
|
||||
DESTINATION
|
||||
Mod/Measure
|
||||
)
|
||||
|
||||
99
src/Mod/Measure/Gui/AppMeasureGui.cpp
Normal 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);
|
||||
}
|
||||
90
src/Mod/Measure/Gui/CMakeLists.txt
Normal 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")
|
||||
|
||||
33
src/Mod/Measure/Gui/Command.cpp
Normal 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();
|
||||
}
|
||||
75
src/Mod/Measure/Gui/DlgPrefsMeasureAppearanceImp.cpp
Normal 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>
|
||||
|
||||
55
src/Mod/Measure/Gui/DlgPrefsMeasureAppearanceImp.h
Normal 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
|
||||
|
||||
247
src/Mod/Measure/Gui/DlgPrefsMeasureAppearanceImp.ui
Normal 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>
|
||||
22
src/Mod/Measure/Gui/PreCompiled.cpp
Normal 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"
|
||||
97
src/Mod/Measure/Gui/PreCompiled.h
Normal 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
|
||||
|
||||
6
src/Mod/Measure/Gui/Resources/Measure.qrc
Normal file
@@ -0,0 +1,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>icons/umf-measurement.svg</file>
|
||||
<file>icons/preferences-measure.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
226
src/Mod/Measure/Gui/Resources/icons/preferences-measure.svg
Normal file
@@ -0,0 +1,226 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="64"
|
||||
height="64"
|
||||
id="svg2869"
|
||||
version="1.1"
|
||||
viewBox="0 0 64 64"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs2871">
|
||||
<linearGradient
|
||||
id="linearGradient10">
|
||||
<stop
|
||||
style="stop-color:#babdb6;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop10" />
|
||||
<stop
|
||||
style="stop-color:#888a85;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop11" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5">
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop19" />
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop20" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="swatch18">
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop18" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="swatch15">
|
||||
<stop
|
||||
style="stop-color:#3d0000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop15" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5-1">
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5" />
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop6" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3836-9">
|
||||
<stop
|
||||
style="stop-color:#a40000;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3838-8" />
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3840-1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient10"
|
||||
id="linearGradient11"
|
||||
x1="12.375"
|
||||
y1="23.75"
|
||||
x2="64"
|
||||
y2="28.5"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata2874">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[maxwxyz]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<dc:date>2024</dc:date>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer3"
|
||||
style="display:inline">
|
||||
<path
|
||||
id="path4498"
|
||||
d="M 31.906888,60.999998 V 12.276532 l -24.5860006,1e-6 -2.904e-4,-3.0939183 24.58542,-6.1826135 h 8.71e-4 15.462656 v 9.2765308 h 13.308118 l 2.89e-4,2.030582 -13.308407,4.061163 v 42.631722 z"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path6"
|
||||
d="m 32.154297,5 h 13.214844 v 9.277344 h 8.55664 l -8.55664,2.611328 V 59 H 33.90625 V 10.277344 H 11.164063 Z"
|
||||
style="fill:url(#linearGradient11);fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path4504"
|
||||
d="m 33.453879,17.976538 9.277594,8.71e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path1"
|
||||
d="m 33.457361,48.841436 6.185063,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path2"
|
||||
d="m 33.457361,41.125284 6.185063,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path3"
|
||||
d="m 33.457361,33.409133 6.185063,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path4"
|
||||
d="m 33.457361,25.692981 6.185063,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5"
|
||||
d="m 33.453879,56.557588 9.277594,8.72e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path11"
|
||||
d="m 34.230469,19.976538 7.724414,8.71e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path12"
|
||||
d="m 34.233368,50.841436 5.14961,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path13"
|
||||
d="m 34.233368,43.125284 5.14961,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path14"
|
||||
d="m 34.233368,35.409133 5.14961,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path15"
|
||||
d="m 34.233368,27.692981 5.14961,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path16"
|
||||
d="m 34.230469,58.557588 8.501004,8.72e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path4500"
|
||||
d="M 7.3208874,27.158429 H 34.22781 l 0.0019,28.741042 H 28.043227 V 37.209528 L 7.3208874,32.571857 Z"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path4502"
|
||||
d="m 45.82444,20.585383 14.854673,4.062178 2.9e-4,2.510868 H 50.463816 l 0.0016,14.741042 h -4.638797 z"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path7"
|
||||
d="M 9.3203125,29.158203 H 32.228516 l 0.002,24.742188 h -2.1875 V 35.607422 L 9.3203125,30.970703 Z"
|
||||
style="fill:#888a85;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path18"
|
||||
d="m 31.176195,46.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path19"
|
||||
d="m 31.176195,48.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path20"
|
||||
d="m 31.176195,42.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path21"
|
||||
d="m 31.176195,44.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path22"
|
||||
d="m 31.176195,38.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path23"
|
||||
d="m 31.176195,40.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path24"
|
||||
d="m 31.176195,50.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path25"
|
||||
d="m 31.176195,52.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path26"
|
||||
d="m 31.176195,34.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path27"
|
||||
d="m 31.176195,36.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.8 KiB |
226
src/Mod/Measure/Gui/Resources/icons/umf-measurement.svg
Normal file
@@ -0,0 +1,226 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="64"
|
||||
height="64"
|
||||
id="svg2869"
|
||||
version="1.1"
|
||||
viewBox="0 0 64 64"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs2871">
|
||||
<linearGradient
|
||||
id="linearGradient10">
|
||||
<stop
|
||||
style="stop-color:#babdb6;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop10" />
|
||||
<stop
|
||||
style="stop-color:#888a85;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop11" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5">
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop19" />
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop20" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="swatch18">
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop18" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="swatch15">
|
||||
<stop
|
||||
style="stop-color:#3d0000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop15" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5-1">
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5" />
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop6" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3836-9">
|
||||
<stop
|
||||
style="stop-color:#a40000;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3838-8" />
|
||||
<stop
|
||||
style="stop-color:#ef2929;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3840-1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient10"
|
||||
id="linearGradient11"
|
||||
x1="12.375"
|
||||
y1="23.75"
|
||||
x2="64"
|
||||
y2="28.5"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata2874">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[maxwxyz]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<dc:date>2024</dc:date>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer3"
|
||||
style="display:inline">
|
||||
<path
|
||||
id="path4498"
|
||||
d="M 31.906888,60.999998 V 12.276532 l -24.5860006,1e-6 -2.904e-4,-3.0939183 24.58542,-6.1826135 h 8.71e-4 15.462656 v 9.2765308 h 13.308118 l 2.89e-4,2.030582 -13.308407,4.061163 v 42.631722 z"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path6"
|
||||
d="m 32.154297,5 h 13.214844 v 9.277344 h 8.55664 l -8.55664,2.611328 V 59 H 33.90625 V 10.277344 H 11.164063 Z"
|
||||
style="fill:url(#linearGradient11);fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path4504"
|
||||
d="m 33.453879,17.976538 9.277594,8.71e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path1"
|
||||
d="m 33.457361,48.841436 6.185063,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path2"
|
||||
d="m 33.457361,41.125284 6.185063,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path3"
|
||||
d="m 33.457361,33.409133 6.185063,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path4"
|
||||
d="m 33.457361,25.692981 6.185063,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path5"
|
||||
d="m 33.453879,56.557588 9.277594,8.72e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path11"
|
||||
d="m 34.230469,19.976538 7.724414,8.71e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path12"
|
||||
d="m 34.233368,50.841436 5.14961,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path13"
|
||||
d="m 34.233368,43.125284 5.14961,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path14"
|
||||
d="m 34.233368,35.409133 5.14961,5.81e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path15"
|
||||
d="m 34.233368,27.692981 5.14961,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path16"
|
||||
d="m 34.230469,58.557588 8.501004,8.72e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path4500"
|
||||
d="M 7.3208874,27.158429 H 34.22781 l 0.0019,28.741042 H 28.043227 V 37.209528 L 7.3208874,32.571857 Z"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path4502"
|
||||
d="m 45.82444,20.585383 14.854673,4.062178 2.9e-4,2.510868 H 50.463816 l 0.0016,14.741042 h -4.638797 z"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path7"
|
||||
d="M 9.3203125,29.158203 H 32.228516 l 0.002,24.742188 h -2.1875 V 35.607422 L 9.3203125,30.970703 Z"
|
||||
style="fill:#888a85;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path18"
|
||||
d="m 31.176195,46.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path19"
|
||||
d="m 31.176195,48.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path20"
|
||||
d="m 31.176195,42.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path21"
|
||||
d="m 31.176195,44.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path22"
|
||||
d="m 31.176195,38.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path23"
|
||||
d="m 31.176195,40.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path24"
|
||||
d="m 31.176195,50.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path25"
|
||||
d="m 31.176195,52.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path26"
|
||||
d="m 31.176195,34.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#0b1e23;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path27"
|
||||
d="m 31.176195,36.622396 1.64761,5.8e-4"
|
||||
style="fill:#d3d7cf;fill-rule:evenodd;stroke:#d3d7cf;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.8 KiB |
42
src/Mod/Measure/Gui/Resources/translations/Measure.ts
Normal 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>
|
||||
339
src/Mod/Measure/Gui/ViewProviderMeasureAngle.cpp
Normal 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));
|
||||
}
|
||||
|
||||
73
src/Mod/Measure/Gui/ViewProviderMeasureAngle.h
Normal 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
|
||||
597
src/Mod/Measure/Gui/ViewProviderMeasureBase.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
159
src/Mod/Measure/Gui/ViewProviderMeasureBase.h
Normal 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
|
||||
|
||||
222
src/Mod/Measure/Gui/ViewProviderMeasureDistance.cpp
Normal 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));
|
||||
}
|
||||
69
src/Mod/Measure/Gui/ViewProviderMeasureDistance.h
Normal 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
|
||||
43
src/Mod/Measure/InitGui.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# /***************************************************************************
|
||||
# * 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/>. *
|
||||
# * *
|
||||
# **************************************************************************/
|
||||
|
||||
|
||||
# Import the measure module here in order to ensure that default measurement types are loaded during startup.
|
||||
# Note that they won't auto-load in gui-less mode. Ideally they would be loaded from "Init.py", similar
|
||||
# to how the import/export types are registered. This would require to register measurement types from
|
||||
# python which could complicate things further.
|
||||
|
||||
import Measure
|
||||
from MeasureCOM import makeMeasureCOM, MeasureCOM
|
||||
|
||||
|
||||
# Expose create functions
|
||||
Measure.makeMeasureCOM = makeMeasureCOM
|
||||
|
||||
|
||||
# Register python measure types
|
||||
import FreeCAD
|
||||
FreeCAD.MeasureManager.addMeasureType(
|
||||
"CENTEROFMASS",
|
||||
"Center of Mass",
|
||||
MeasureCOM,
|
||||
)
|
||||
|
||||
152
src/Mod/Measure/MeasureCOM.py
Normal file
@@ -0,0 +1,152 @@
|
||||
# /***************************************************************************
|
||||
# * 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/>. *
|
||||
# * *
|
||||
# **************************************************************************/
|
||||
|
||||
import FreeCAD
|
||||
from FreeCAD import Units, Placement
|
||||
from UtilsMeasure import MeasureBasePython
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
|
||||
|
||||
__title__="Measure Center of Mass Object"
|
||||
__author__ = "David Friedli"
|
||||
__url__ = "http://www.freecad.org"
|
||||
|
||||
|
||||
|
||||
"""
|
||||
The Measure cpp object defines a result and a placement property. The Python measure type
|
||||
adds it's own specific properties. Once the object is recomputed the parent properties are updated
|
||||
based on the specific python properties.
|
||||
|
||||
We'll need some kind of interface for the measure command which exposes "parseSelection", "isValidSelection" etc.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
|
||||
def makeMeasureCOM(name="CenterOfMass"):
|
||||
'''makeMeasureCOM(name): make a CenterofMass measurement'''
|
||||
obj = FreeCAD.ActiveDocument.addObject("Measure::MeasurePython", name)
|
||||
MeasureCOM(obj)
|
||||
return obj
|
||||
|
||||
|
||||
class MeasureCOM(MeasureBasePython):
|
||||
"The MeasureCOM object"
|
||||
|
||||
def __init__(self, obj):
|
||||
obj.Proxy = self
|
||||
|
||||
obj.addProperty("App::PropertyLinkSubGlobal", "Element", "", QT_TRANSLATE_NOOP("App::Property", "Element to measure"))
|
||||
obj.addProperty("App::PropertyPosition", "Result", "", QT_TRANSLATE_NOOP("App::PropertyVector", "The result location"))
|
||||
|
||||
@classmethod
|
||||
def isValidSelection(cls, selection):
|
||||
if not len(selection) == 1:
|
||||
return False
|
||||
|
||||
element = selection[0]
|
||||
ob = element["object"]
|
||||
subName = element["subName"]
|
||||
|
||||
if not ob:
|
||||
return
|
||||
|
||||
sub = ob.getSubObject(subName)
|
||||
if not sub:
|
||||
return
|
||||
|
||||
if not hasattr(sub, "CenterOfMass"):
|
||||
return
|
||||
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def isPrioritySelection(cls, selection):
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def getInputProps(cls):
|
||||
return ("Element",)
|
||||
|
||||
def getSubject(self, obj):
|
||||
if not obj:
|
||||
return ()
|
||||
|
||||
element = obj.Element
|
||||
if not element:
|
||||
return ()
|
||||
|
||||
ob = element[0]
|
||||
if not ob:
|
||||
return ()
|
||||
return (ob,)
|
||||
|
||||
|
||||
def parseSelection(self, obj, selection):
|
||||
item = selection[0]
|
||||
o = item["object"]
|
||||
obj.Element = (o, item["subName"])
|
||||
|
||||
|
||||
def getResultString(self, obj):
|
||||
values = [Units.Quantity(v, Units.Length).getUserPreferred()[0] for v in obj.Result]
|
||||
return "COM\nX: {}\nY: {}\nZ: {}".format(*values)
|
||||
|
||||
def execute(self, obj):
|
||||
element = obj.Element
|
||||
if not element:
|
||||
return
|
||||
|
||||
ob = element[0]
|
||||
subElements = element[1]
|
||||
|
||||
if subElements:
|
||||
subName = subElements[0]
|
||||
sub = ob.getSubObject(subName)
|
||||
|
||||
if not sub or not hasattr(sub, "CenterOfMass"):
|
||||
return
|
||||
com = sub.CenterOfMass
|
||||
|
||||
else:
|
||||
# Get Center of Mass of the object
|
||||
if not hasattr(ob, "Shape"):
|
||||
return
|
||||
|
||||
shape = ob.Shape
|
||||
if not hasattr(shape, "CenterOfMass"):
|
||||
return
|
||||
|
||||
com = shape.CenterOfMass
|
||||
|
||||
obj.Result = com
|
||||
placement = Placement()
|
||||
placement.Base = com
|
||||
obj.Placement = placement
|
||||
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
'''Do something when a property has changed'''
|
||||
|
||||
if prop == "Element":
|
||||
self.execute(obj)
|
||||
@@ -29,9 +29,18 @@
|
||||
// Measure
|
||||
#ifndef MeasureExport
|
||||
#ifdef Measure_EXPORTS
|
||||
# define MeasureExport FREECAD_DECL_EXPORT
|
||||
#define MeasureExport FREECAD_DECL_EXPORT
|
||||
#else
|
||||
# define MeasureExport FREECAD_DECL_IMPORT
|
||||
#define MeasureExport FREECAD_DECL_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// MeasureGui
|
||||
#ifndef MeasureGuiExport
|
||||
#ifdef MeasureGui_EXPORTS
|
||||
# define MeasureGuiExport FREECAD_DECL_EXPORT
|
||||
#else
|
||||
# define MeasureGuiExport FREECAD_DECL_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
52
src/Mod/Measure/UtilsMeasure.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# /***************************************************************************
|
||||
# * 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/>. *
|
||||
# * *
|
||||
# **************************************************************************/
|
||||
|
||||
from abc import ABC, abstractmethod, abstractclassmethod
|
||||
from typing import List, Tuple
|
||||
|
||||
class MeasureBasePython(ABC):
|
||||
|
||||
@abstractclassmethod
|
||||
def isValidSelection(cls, selection):
|
||||
"""Returns True if the given selection is valid for this measurment"""
|
||||
pass
|
||||
|
||||
@abstractclassmethod
|
||||
def isPrioritySelection(cls, selection):
|
||||
"""Returns True if creation of this measurment should be priorized over other measurements for the given selection"""
|
||||
pass
|
||||
|
||||
@abstractclassmethod
|
||||
def getInputProps(cls) -> Tuple[str]:
|
||||
"""Returns all properties that the measurement's result depends on"""
|
||||
return ()
|
||||
|
||||
@abstractmethod
|
||||
def getSubject(self, obj) -> Tuple:
|
||||
"""Returns all objects that are measured, this is used to autohide the measurement if the relevant elements are not visible"""
|
||||
return []
|
||||
|
||||
@abstractmethod
|
||||
def parseSelection(self, obj, selection):
|
||||
"""Sets the measurements properties from the given selection"""
|
||||
pass
|
||||
|
||||
|
||||
@@ -185,6 +185,8 @@
|
||||
#include <ShapeUpgrade/UnifySameDomainPy.h>
|
||||
|
||||
#include <OCAF/ImportExportSettings.h>
|
||||
#include "MeasureClient.h"
|
||||
|
||||
|
||||
namespace Part {
|
||||
extern PyObject* initModule();
|
||||
@@ -552,10 +554,12 @@ PyMOD_INIT_FUNC(Part)
|
||||
Part::Geom2dOffsetCurve ::init();
|
||||
Part::Geom2dTrimmedCurve ::init();
|
||||
|
||||
|
||||
IGESControl_Controller::Init();
|
||||
STEPControl_Controller::Init();
|
||||
|
||||
OCAF::ImportExportSettings::initialize();
|
||||
|
||||
Part::MeasureClient::initialize();
|
||||
|
||||
PyMOD_Return(partModule);
|
||||
}
|
||||
|
||||
@@ -219,6 +219,8 @@ SET(Features_SRCS
|
||||
AttachExtension.cpp
|
||||
PrismExtension.cpp
|
||||
PrismExtension.h
|
||||
VectorAdapter.cpp
|
||||
VectorAdapter.h
|
||||
)
|
||||
SOURCE_GROUP("Features" FILES ${Features_SRCS})
|
||||
|
||||
@@ -543,6 +545,9 @@ SET(Part_SRCS
|
||||
TopoShapeOpCode.h
|
||||
edgecluster.cpp
|
||||
edgecluster.h
|
||||
MeasureClient.cpp
|
||||
MeasureClient.h
|
||||
MeasureInfo.h
|
||||
modelRefine.cpp
|
||||
modelRefine.h
|
||||
Tools.cpp
|
||||
|
||||
496
src/Mod/Part/App/MeasureClient.cpp
Normal file
@@ -0,0 +1,496 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 Wandererfan <wandererfan@gmail.com> *
|
||||
* Copyright (c) 2023 Joel Meijering (EDG5000) <joel@meijering.email> *
|
||||
* Copyright (c) 2023 David Friedli <david@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 <Mod/Part/PartGlobal.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Vertex.hxx>
|
||||
#include <TopAbs.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <BRepAdaptor_Surface.hxx>
|
||||
#include <TopExp.hxx>
|
||||
#include <GProp_GProps.hxx>
|
||||
#include <ShapeAnalysis_Edge.hxx>
|
||||
#include <gp_Circ.hxx>
|
||||
#include <BRepBuilderAPI_Copy.hxx>
|
||||
|
||||
#include <DatumFeature.h>
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/MeasureManager.h>
|
||||
#include <App/DocumentObserver.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Matrix.h>
|
||||
#include <Base/Rotation.h>
|
||||
#include <Base/Vector3D.h>
|
||||
|
||||
#include <Mod/Measure/App/MeasureAngle.h>
|
||||
#include <Mod/Measure/App/MeasureDistance.h>
|
||||
#include <Mod/Measure/App/MeasureLength.h>
|
||||
#include <Mod/Measure/App/MeasurePosition.h>
|
||||
#include <Mod/Measure/App/MeasureArea.h>
|
||||
#include <Mod/Measure/App/MeasureRadius.h>
|
||||
|
||||
#include "VectorAdapter.h"
|
||||
#include "PartFeature.h"
|
||||
|
||||
#include "MeasureClient.h"
|
||||
|
||||
using namespace Part;
|
||||
|
||||
// From: https://github.com/Celemation/FreeCAD/blob/joel_selection_summary_demo/src/Gui/SelectionSummary.cpp
|
||||
|
||||
// Should work with edges and wires
|
||||
static float getLength(TopoDS_Shape& wire){
|
||||
GProp_GProps gprops;
|
||||
BRepGProp::LinearProperties(wire, gprops);
|
||||
return gprops.Mass();
|
||||
}
|
||||
|
||||
static float getFaceArea(TopoDS_Shape& face){
|
||||
GProp_GProps gprops;
|
||||
BRepGProp::SurfaceProperties(face, gprops);
|
||||
return gprops.Mass();
|
||||
}
|
||||
|
||||
static float getRadius(TopoDS_Shape& edge){
|
||||
// gprops.Mass() would be the circumference (length) of the circle (arc)
|
||||
if (edge.ShapeType() == TopAbs_EDGE) {
|
||||
BRepAdaptor_Curve adapt(TopoDS::Edge(edge));
|
||||
if (adapt.GetType() != GeomAbs_Circle) {
|
||||
// TODO: not sure what the error handling here should be. nan? 0.0?
|
||||
return 0.0;
|
||||
}
|
||||
gp_Circ circle = adapt.Circle();
|
||||
return circle.Radius();
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
TopoDS_Shape getLocatedShape(const App::SubObjectT& subject)
|
||||
{
|
||||
App::DocumentObject* obj = subject.getObject();
|
||||
if (!obj) {
|
||||
return {};
|
||||
}
|
||||
Part::TopoShape shape = Part::Feature::getTopoShape(obj);
|
||||
if (shape.isNull()) {
|
||||
return {};
|
||||
}
|
||||
auto geoFeat = dynamic_cast<App::GeoFeature*>(obj);
|
||||
if (geoFeat) {
|
||||
shape.setPlacement(geoFeat->globalPlacement());
|
||||
}
|
||||
|
||||
// Don't get the subShape from datum elements
|
||||
if (obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) {
|
||||
return shape.getShape();
|
||||
}
|
||||
|
||||
if (!subject.getElementName()) {
|
||||
return shape.getShape();
|
||||
}
|
||||
return shape.getSubShape(subject.getElementName(), true);
|
||||
}
|
||||
|
||||
|
||||
App::MeasureElementType PartMeasureTypeCb(App::DocumentObject* ob, const char* subName)
|
||||
{
|
||||
TopoDS_Shape shape = Part::Feature::getShape(ob, subName, true);
|
||||
if (shape.IsNull()) {
|
||||
// failure here on loading document with existing measurement.
|
||||
Base::Console().Message("Part::PartMeasureTypeCb did not retrieve shape for %s, %s\n", ob->getNameInDocument(), subName);
|
||||
return App::MeasureElementType();
|
||||
}
|
||||
TopAbs_ShapeEnum shapeType = shape.ShapeType();
|
||||
|
||||
switch (shapeType) {
|
||||
case TopAbs_VERTEX: {
|
||||
return App::MeasureElementType::POINT;
|
||||
}
|
||||
case TopAbs_EDGE: {
|
||||
const TopoDS_Edge& edge = TopoDS::Edge(shape);
|
||||
BRepAdaptor_Curve curve(edge);
|
||||
|
||||
switch (curve.GetType()) {
|
||||
case GeomAbs_Line: {
|
||||
if (ob->getTypeId().isDerivedFrom(Base::Type::fromName("Part::Datum"))) {
|
||||
return App::MeasureElementType::LINE;
|
||||
}
|
||||
return App::MeasureElementType::LINESEGMENT;
|
||||
}
|
||||
case GeomAbs_Circle: { return App::MeasureElementType::CIRCLE; }
|
||||
case GeomAbs_BezierCurve:
|
||||
case GeomAbs_BSplineCurve: {
|
||||
return App::MeasureElementType::CURVE;
|
||||
}
|
||||
default: { return App::MeasureElementType::INVALID; }
|
||||
}
|
||||
}
|
||||
case TopAbs_FACE: {
|
||||
const TopoDS_Face& face = TopoDS::Face(shape);
|
||||
BRepAdaptor_Surface surface(face);
|
||||
|
||||
switch (surface.GetType()) {
|
||||
case GeomAbs_Cylinder: { return App::MeasureElementType::CYLINDER; }
|
||||
case GeomAbs_Plane: { return App::MeasureElementType::PLANE; }
|
||||
default: { return App::MeasureElementType::INVALID; }
|
||||
}
|
||||
}
|
||||
case TopAbs_SOLID: {
|
||||
return App::MeasureElementType::Volume;
|
||||
}
|
||||
default: {
|
||||
return App::MeasureElementType::INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool getShapeFromStrings(TopoDS_Shape &shapeOut, const App::SubObjectT& subject, Base::Matrix4D *mat)
|
||||
{
|
||||
App::DocumentObject *obj = subject.getObject();
|
||||
if (!obj) {
|
||||
return {};
|
||||
}
|
||||
shapeOut = Part::Feature::getShape(obj, subject.getElementName(), true, mat);
|
||||
return !shapeOut.IsNull();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Part::VectorAdapter buildAdapter(const App::SubObjectT& subject)
|
||||
{
|
||||
if (!subject.getObject()) {
|
||||
return Part::VectorAdapter();
|
||||
}
|
||||
Base::Matrix4D mat;
|
||||
TopoDS_Shape shape = Part::Feature::getShape(subject.getObject(), subject.getElementName(), true);
|
||||
if (shape.IsNull()) {
|
||||
// failure here on loading document with existing measurement.
|
||||
Base::Console().Message("Part::buildAdapter did not retrieve shape for %s, %s\n",
|
||||
subject.getObjectName(), subject.getElementName());
|
||||
return Part::VectorAdapter();
|
||||
}
|
||||
|
||||
TopAbs_ShapeEnum shapeType = shape.ShapeType();
|
||||
|
||||
|
||||
if (shapeType == TopAbs_EDGE)
|
||||
{
|
||||
TopoDS_Shape edgeShape;
|
||||
if (!getShapeFromStrings(edgeShape, subject, &mat)) {
|
||||
return {};
|
||||
}
|
||||
TopoDS_Edge edge = TopoDS::Edge(edgeShape);
|
||||
// make edge orientation so that end of edge closest to pick is head of vector.
|
||||
TopoDS_Vertex firstVertex = TopExp::FirstVertex(edge, Standard_True);
|
||||
TopoDS_Vertex lastVertex = TopExp::LastVertex(edge, Standard_True);
|
||||
if (firstVertex.IsNull() || lastVertex.IsNull()) {
|
||||
return {};
|
||||
}
|
||||
gp_Vec firstPoint = Part::VectorAdapter::convert(firstVertex);
|
||||
gp_Vec lastPoint = Part::VectorAdapter::convert(lastVertex);
|
||||
Base::Vector3d v(0.0, 0.0, 0.0); //v(current.x,current.y,current.z);
|
||||
v = mat*v;
|
||||
gp_Vec pickPoint(v.x, v.y, v.z);
|
||||
double firstDistance = (firstPoint - pickPoint).Magnitude();
|
||||
double lastDistance = (lastPoint - pickPoint).Magnitude();
|
||||
if (lastDistance > firstDistance)
|
||||
{
|
||||
if (edge.Orientation() == TopAbs_FORWARD) {
|
||||
edge.Orientation(TopAbs_REVERSED);
|
||||
}
|
||||
else {
|
||||
edge.Orientation(TopAbs_FORWARD);
|
||||
}
|
||||
}
|
||||
return {edge, pickPoint};
|
||||
}
|
||||
if (shapeType == TopAbs_FACE)
|
||||
{
|
||||
TopoDS_Shape faceShape;
|
||||
if (!getShapeFromStrings(faceShape, subject, &mat)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
TopoDS_Face face = TopoDS::Face(faceShape);
|
||||
Base::Vector3d vTemp(0.0, 0.0, 0.0); //v(current.x, current.y, current.z);
|
||||
vTemp = mat*vTemp;
|
||||
gp_Vec pickPoint(vTemp.x, vTemp.y, vTemp.z);
|
||||
return {face, pickPoint};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
MeasureLengthInfoPtr MeasureLengthHandler(const App::SubObjectT& subject)
|
||||
{
|
||||
TopoDS_Shape shape = getLocatedShape(subject);
|
||||
|
||||
if (shape.IsNull()) {
|
||||
// failure here on loading document with existing measurement.
|
||||
Base::Console().Message("MeasureLengthHandler did not retrieve shape for %s, %s\n",
|
||||
subject.getObjectName(), subject.getElementName());
|
||||
return std::make_shared<MeasureLengthInfo>(false, 0.0, Base::Matrix4D());
|
||||
}
|
||||
TopAbs_ShapeEnum sType = shape.ShapeType();
|
||||
|
||||
if (sType != TopAbs_EDGE) {
|
||||
return std::make_shared<MeasureLengthInfo>(false, 0.0, Base::Matrix4D());
|
||||
}
|
||||
|
||||
// Get Center of mass as the attachment point of the label
|
||||
GProp_GProps gprops;
|
||||
BRepGProp::LinearProperties(shape, gprops);
|
||||
auto origin = gprops.CentreOfMass();
|
||||
|
||||
// Get rotation of line
|
||||
auto edge = TopoDS::Edge(shape);
|
||||
ShapeAnalysis_Edge edgeAnalyzer;
|
||||
gp_Pnt firstPoint = BRep_Tool::Pnt(edgeAnalyzer.FirstVertex(edge));
|
||||
gp_Pnt lastPoint = BRep_Tool::Pnt(edgeAnalyzer.LastVertex(edge));
|
||||
auto dir = (lastPoint.XYZ() - firstPoint.XYZ()).Normalized();
|
||||
Base::Vector3d elementDirection(dir.X(), dir.Y(), dir.Z());
|
||||
Base::Vector3d axisUp(0.0, 0.0, 1.0);
|
||||
Base::Rotation rot(axisUp, elementDirection);
|
||||
|
||||
Base::Placement placement(Base::Vector3d(origin.X(), origin.Y(), origin.Z()), rot);
|
||||
return std::make_shared<MeasureLengthInfo>(true, getLength(shape), placement);
|
||||
}
|
||||
|
||||
MeasureRadiusInfoPtr MeasureRadiusHandler(const App::SubObjectT& subject)
|
||||
{
|
||||
Base::Placement placement; // curve center + orientation
|
||||
Base::Vector3d pointOnCurve;
|
||||
|
||||
TopoDS_Shape shape = getLocatedShape(subject);
|
||||
|
||||
if (shape.IsNull()) {
|
||||
return std::make_shared<MeasureRadiusInfo>( false, 0.0, pointOnCurve, placement);
|
||||
}
|
||||
TopAbs_ShapeEnum sType = shape.ShapeType();
|
||||
|
||||
if (sType != TopAbs_EDGE) {
|
||||
return std::make_shared<MeasureRadiusInfo>( false, 0.0, pointOnCurve, placement);
|
||||
}
|
||||
|
||||
// Get Center of mass as the attachment point of the label
|
||||
GProp_GProps gprops;
|
||||
BRepGProp::LinearProperties(shape, gprops);
|
||||
auto origin = gprops.CentreOfMass();
|
||||
|
||||
TopoDS_Edge edge = TopoDS::Edge(shape);
|
||||
gp_Pnt firstPoint = BRep_Tool::Pnt(TopExp::FirstVertex(edge));
|
||||
pointOnCurve = Base::Vector3d(firstPoint.X(), firstPoint.Y(), firstPoint.Z());
|
||||
// a somewhat arbitrary radius from center -> point on curve
|
||||
auto dir = (firstPoint.XYZ() - origin.XYZ()).Normalized();
|
||||
Base::Vector3d elementDirection(dir.X(), dir.Y(), dir.Z());
|
||||
Base::Vector3d axisUp(0.0, 0.0, 1.0);
|
||||
Base::Rotation rot(axisUp, elementDirection);
|
||||
|
||||
placement = Base::Placement(Base::Vector3d(origin.X(), origin.Y(), origin.Z()), rot);
|
||||
|
||||
return std::make_shared<MeasureRadiusInfo>( true, getRadius(shape), pointOnCurve, placement);
|
||||
}
|
||||
|
||||
|
||||
MeasureAreaInfoPtr MeasureAreaHandler(const App::SubObjectT& subject)
|
||||
{
|
||||
TopoDS_Shape shape = getLocatedShape(subject);
|
||||
|
||||
if (shape.IsNull()) {
|
||||
// failure here on loading document with existing measurement.
|
||||
Base::Console().Message("MeasureLengthHandler did not retrieve shape for %s, %s\n",
|
||||
subject.getObjectName(), subject.getElementName());
|
||||
return std::make_shared<MeasureAreaInfo>(false, 0.0, Base::Matrix4D());
|
||||
}
|
||||
TopAbs_ShapeEnum sType = shape.ShapeType();
|
||||
|
||||
if (sType != TopAbs_FACE) {
|
||||
return std::make_shared<MeasureAreaInfo>(false, 0.0, Base::Matrix4D());
|
||||
}
|
||||
|
||||
// Get Center of mass as the attachment point of the label
|
||||
GProp_GProps gprops;
|
||||
BRepGProp::SurfaceProperties(shape, gprops);
|
||||
auto origin = gprops.CentreOfMass();
|
||||
|
||||
// TODO: Center of Mass might not lie on the surface, somehow snap to the closest point on the surface?
|
||||
|
||||
Base::Placement placement(Base::Vector3d(origin.X(), origin.Y(), origin.Z()), Base::Rotation());
|
||||
return std::make_shared<MeasureAreaInfo>(true, getFaceArea(shape), placement);
|
||||
}
|
||||
|
||||
|
||||
MeasurePositionInfoPtr MeasurePositionHandler(const App::SubObjectT& subject)
|
||||
{
|
||||
TopoDS_Shape shape = getLocatedShape(subject);
|
||||
|
||||
if (shape.IsNull()) {
|
||||
Base::Console().Message("MeasurePositionHandler did not retrieve shape for %s, %s\n",
|
||||
subject.getObjectName(), subject.getElementName());
|
||||
return std::make_shared<MeasurePositionInfo>(false, Base::Vector3d());
|
||||
}
|
||||
TopAbs_ShapeEnum sType = shape.ShapeType();
|
||||
|
||||
if (sType != TopAbs_VERTEX) {
|
||||
return std::make_shared<MeasurePositionInfo>(false, Base::Vector3d());
|
||||
}
|
||||
|
||||
TopoDS_Vertex vertex = TopoDS::Vertex(shape);
|
||||
auto point = BRep_Tool::Pnt(vertex);
|
||||
return std::make_shared<MeasurePositionInfo>( true, Base::Vector3d(point.X(), point.Y(), point.Z()));
|
||||
}
|
||||
|
||||
|
||||
MeasureAngleInfoPtr MeasureAngleHandler(const App::SubObjectT& subject)
|
||||
{
|
||||
TopoDS_Shape shape = getLocatedShape(subject);
|
||||
|
||||
if (shape.IsNull()) {
|
||||
// failure here on loading document with existing measurement.
|
||||
Base::Console().Message("MeasureAngleHandler did not retrieve shape for %s, %s\n",
|
||||
subject.getObjectName(), subject.getElementName());
|
||||
return std::make_shared<MeasureAngleInfo>();
|
||||
}
|
||||
|
||||
TopAbs_ShapeEnum sType = shape.ShapeType();
|
||||
|
||||
Part::VectorAdapter vAdapt = buildAdapter(subject);
|
||||
|
||||
gp_Pnt vec;
|
||||
Base::Vector3d position;
|
||||
if (sType == TopAbs_FACE) {
|
||||
TopoDS_Face face = TopoDS::Face(shape);
|
||||
|
||||
GProp_GProps gprops;
|
||||
BRepGProp::SurfaceProperties(face, gprops);
|
||||
vec = gprops.CentreOfMass();
|
||||
|
||||
} else if (sType == TopAbs_EDGE) {
|
||||
TopoDS_Edge edge = TopoDS::Edge(shape);
|
||||
|
||||
GProp_GProps gprops;
|
||||
BRepGProp::LinearProperties(edge, gprops);
|
||||
vec = gprops.CentreOfMass();
|
||||
}
|
||||
|
||||
position.Set(vec.X(), vec.Y(), vec.Z());
|
||||
|
||||
auto info = std::make_shared<MeasureAngleInfo>(vAdapt.isValid(), (Base::Vector3d)vAdapt, position);
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
MeasureDistanceInfoPtr MeasureDistanceHandler(const App::SubObjectT& subject)
|
||||
{
|
||||
TopoDS_Shape shape = getLocatedShape(subject);
|
||||
|
||||
if (shape.IsNull()) {
|
||||
// failure here on loading document with existing measurement.
|
||||
Base::Console().Message("MeasureDistanceHandler did not retrieve shape for %s, %s\n",
|
||||
subject.getObjectName(), subject.getElementName());
|
||||
return std::make_shared<MeasureDistanceInfo>();
|
||||
}
|
||||
|
||||
// return a persistent copy of the TopoDS_Shape here as shape will go out of scope at end
|
||||
BRepBuilderAPI_Copy copy(shape);
|
||||
const TopoDS_Shape* newShape = new TopoDS_Shape(copy.Shape());
|
||||
return std::make_shared<MeasureDistanceInfo>(true, newShape);
|
||||
}
|
||||
|
||||
|
||||
void Part::MeasureClient::initialize() {
|
||||
App::MeasureManager::addMeasureHandler("Part", PartMeasureTypeCb);
|
||||
|
||||
}
|
||||
|
||||
Part::CallbackRegistrationList Part::MeasureClient::reportLengthCB()
|
||||
{
|
||||
CallbackRegistrationList callbacks;
|
||||
callbacks.emplace_back("Part", "Length", MeasureLengthHandler);
|
||||
callbacks.emplace_back("PartDesign", "Length", MeasureLengthHandler);
|
||||
callbacks.emplace_back("Sketcher", "Length", MeasureLengthHandler);
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
Part::CallbackRegistrationList Part::MeasureClient::reportPositionCB()
|
||||
{
|
||||
CallbackRegistrationList callbacks;
|
||||
callbacks.emplace_back("Part", "Position", MeasurePositionHandler);
|
||||
callbacks.emplace_back("PartDesign", "Position", MeasurePositionHandler);
|
||||
callbacks.emplace_back("Sketcher", "Position", MeasurePositionHandler);
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
Part::CallbackRegistrationList Part::MeasureClient::reportAreaCB()
|
||||
{
|
||||
CallbackRegistrationList callbacks;
|
||||
callbacks.emplace_back("Part", "Area", MeasureAreaHandler);
|
||||
callbacks.emplace_back("PartDesign", "Area", MeasureAreaHandler);
|
||||
callbacks.emplace_back("Sketcher", "Area", MeasureAreaHandler);
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
|
||||
Part::CallbackRegistrationList Part::MeasureClient::reportAngleCB()
|
||||
{
|
||||
CallbackRegistrationList callbacks;
|
||||
callbacks.emplace_back("Part", "Angle", MeasureAngleHandler);
|
||||
callbacks.emplace_back("PartDesign", "Angle", MeasureAngleHandler);
|
||||
callbacks.emplace_back("Sketcher", "Angle", MeasureAngleHandler);
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
|
||||
Part::CallbackRegistrationList Part::MeasureClient::reportDistanceCB()
|
||||
{
|
||||
CallbackRegistrationList callbacks;
|
||||
callbacks.emplace_back("Part", "Distance", MeasureDistanceHandler);
|
||||
callbacks.emplace_back("PartDesign", "Distance", MeasureDistanceHandler);
|
||||
callbacks.emplace_back("Sketcher", "Distance", MeasureDistanceHandler);
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
|
||||
Part::CallbackRegistrationList Part::MeasureClient::reportRadiusCB()
|
||||
{
|
||||
CallbackRegistrationList callbacks;
|
||||
callbacks.emplace_back("Part", "Radius", MeasureRadiusHandler);
|
||||
callbacks.emplace_back("PartDesign", "Radius", MeasureRadiusHandler);
|
||||
callbacks.emplace_back("Sketcher", "Radius", MeasureRadiusHandler);
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
|
||||
52
src/Mod/Part/App/MeasureClient.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 Wandererfan <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 PART_MEASURE_H
|
||||
#define PART_MEASURE_H
|
||||
|
||||
#include <Mod/Part/PartGlobal.h>
|
||||
|
||||
#include "MeasureInfo.h"
|
||||
|
||||
|
||||
|
||||
namespace Part
|
||||
{
|
||||
|
||||
|
||||
class PartExport MeasureClient
|
||||
{
|
||||
public:
|
||||
|
||||
static void initialize();
|
||||
|
||||
static CallbackRegistrationList reportLengthCB();
|
||||
static CallbackRegistrationList reportPositionCB();
|
||||
static CallbackRegistrationList reportAreaCB();
|
||||
static CallbackRegistrationList reportAngleCB();
|
||||
static CallbackRegistrationList reportDistanceCB();
|
||||
static CallbackRegistrationList reportRadiusCB();
|
||||
};
|
||||
|
||||
|
||||
} //namespace Part
|
||||
|
||||
#endif
|
||||
160
src/Mod/Part/App/MeasureInfo.h
Normal file
@@ -0,0 +1,160 @@
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 wandererfan <wandererfan at gmail dot 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/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
//! MeasureInfo.h
|
||||
//! ancestor class and the various flavours of MeasureXXXXXInfo.
|
||||
|
||||
#ifndef PART_MEASUREINFO_H
|
||||
#define PART_MEASUREINFO_H
|
||||
|
||||
#include <Mod/Part/PartGlobal.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <App/DocumentObserver.h>
|
||||
#include <Base/Vector3D.h>
|
||||
#include <Base/Placement.h>
|
||||
|
||||
class TopoDS_Shape;
|
||||
|
||||
namespace Part {
|
||||
|
||||
class MeasureInfo;
|
||||
using MeasureInfoPtr = std::shared_ptr<MeasureInfo>;
|
||||
class MeasureAngleInfo;
|
||||
using MeasureAngleInfoPtr = std::shared_ptr<MeasureAngleInfo>;
|
||||
class MeasureAreaInfo;
|
||||
using MeasureAreaInfoPtr = std::shared_ptr<MeasureAreaInfo>;
|
||||
class MeasureDistanceInfo;
|
||||
using MeasureDistanceInfoPtr = std::shared_ptr<MeasureDistanceInfo>;
|
||||
class MeasureLengthInfo;
|
||||
using MeasureLengthInfoPtr = std::shared_ptr<MeasureLengthInfo>;
|
||||
class MeasurePositionInfo;
|
||||
using MeasurePositionInfoPtr = std::shared_ptr<MeasurePositionInfo>;
|
||||
class MeasureRadiusInfo;
|
||||
using MeasureRadiusInfoPtr = std::shared_ptr<MeasureRadiusInfo>;
|
||||
|
||||
|
||||
class PartExport MeasureInfo {
|
||||
public:
|
||||
// making the destructor virtual so MeasureInfo is polymorphic
|
||||
MeasureInfo() = default;
|
||||
MeasureInfo(bool val) : valid(val) {}
|
||||
virtual ~MeasureInfo() = default;
|
||||
bool valid{false};
|
||||
};
|
||||
|
||||
class PartExport MeasureAngleInfo : public MeasureInfo {
|
||||
public:
|
||||
MeasureAngleInfo() = default;
|
||||
MeasureAngleInfo(bool val, Base::Vector3d orient, Base::Vector3d pos) :
|
||||
MeasureInfo(val), orientation(orient), position(pos) {}
|
||||
~MeasureAngleInfo() override = default;
|
||||
|
||||
Base::Vector3d orientation{0.0, 0.0, 0.0};
|
||||
Base::Vector3d position{0.0, 0.0, 0.0};
|
||||
};
|
||||
|
||||
class PartExport MeasureAreaInfo : public MeasureInfo {
|
||||
public:
|
||||
MeasureAreaInfo() = default;
|
||||
MeasureAreaInfo(bool val, double a2, Base::Placement plm) :
|
||||
MeasureInfo(val), area(a2), placement(plm) {}
|
||||
~MeasureAreaInfo() override = default;
|
||||
|
||||
double area{0};
|
||||
Base::Placement placement{};
|
||||
};
|
||||
|
||||
// Translate geometry reference into an OCC type
|
||||
class PartExport MeasureDistanceInfo : public MeasureInfo {
|
||||
public:
|
||||
MeasureDistanceInfo() = default;
|
||||
explicit MeasureDistanceInfo(bool val, const TopoDS_Shape* shp) :
|
||||
MeasureInfo(val), shape(shp) {}
|
||||
~MeasureDistanceInfo() override = default;
|
||||
|
||||
const TopoDS_Shape* getShape() { return shape; }
|
||||
|
||||
private:
|
||||
const TopoDS_Shape* shape{nullptr};
|
||||
};
|
||||
|
||||
class PartExport MeasureLengthInfo : public MeasureInfo {
|
||||
public:
|
||||
MeasureLengthInfo() = default;
|
||||
MeasureLengthInfo(bool val, double len, Base::Placement plm) :
|
||||
MeasureInfo(val), length(len), placement(plm) {}
|
||||
~MeasureLengthInfo() override = default;
|
||||
|
||||
double length{0};
|
||||
Base::Placement placement{};
|
||||
};
|
||||
|
||||
class PartExport MeasurePositionInfo : public MeasureInfo {
|
||||
public:
|
||||
MeasurePositionInfo() = default;
|
||||
MeasurePositionInfo(bool val, Base::Vector3d pos) :
|
||||
MeasureInfo(val), position(pos) {}
|
||||
~MeasurePositionInfo() override = default;
|
||||
|
||||
Base::Vector3d position{0.0, 0.0, 0.0};
|
||||
};
|
||||
|
||||
class PartExport MeasureRadiusInfo : public MeasureInfo {
|
||||
public:
|
||||
MeasureRadiusInfo() = default;
|
||||
MeasureRadiusInfo(bool val, double rad, Base::Vector3d point, Base::Placement plm) :
|
||||
MeasureInfo(val), radius(rad), pointOnCurve(point), placement(plm) {}
|
||||
~MeasureRadiusInfo() override = default;
|
||||
|
||||
double radius{};
|
||||
Base::Vector3d pointOnCurve;
|
||||
Base::Placement placement; // curve center & circle orientation
|
||||
};
|
||||
|
||||
//! callback registrations
|
||||
// TODO: is there more that one place that GeometryHandler is defined?
|
||||
using GeometryHandler = std::function<Part::MeasureInfoPtr (App::SubObjectT)>;
|
||||
|
||||
class PartExport CallbackRegistrationRecord
|
||||
{
|
||||
public:
|
||||
CallbackRegistrationRecord() = default;
|
||||
CallbackRegistrationRecord(const std::string& module, const std::string& measureType, GeometryHandler callback) :
|
||||
m_module(module), m_measureType(measureType), m_callback(callback)
|
||||
{ }
|
||||
|
||||
std::string m_module;
|
||||
std::string m_measureType;
|
||||
GeometryHandler m_callback;
|
||||
};
|
||||
|
||||
using CallbackRegistrationList = std::vector<CallbackRegistrationRecord>;
|
||||
|
||||
} //end namespace Part
|
||||
|
||||
#endif
|
||||
156
src/Mod/Part/App/VectorAdapter.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2022 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <Mod/Part/PartGlobal.h>
|
||||
#include "VectorAdapter.h"
|
||||
#include "Base/Console.h"
|
||||
#include <string>
|
||||
|
||||
#include "PrimitiveFeature.h"
|
||||
#include "PartFeature.h"
|
||||
|
||||
#include <Standard_Type.hxx>
|
||||
#include <Geom_CylindricalSurface.hxx>
|
||||
#include <Geom_SphericalSurface.hxx>
|
||||
#include <Geom_ElementarySurface.hxx>
|
||||
#include <TopExp.hxx>
|
||||
#include <Geom_Line.hxx>
|
||||
#include <GeomAPI_ProjectPointOnCurve.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
|
||||
|
||||
namespace Part {
|
||||
|
||||
|
||||
VectorAdapter::VectorAdapter() : status(false), vector()
|
||||
{
|
||||
}
|
||||
|
||||
VectorAdapter::VectorAdapter(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn) :
|
||||
status(false), vector(), origin(pickedPointIn)
|
||||
{
|
||||
Handle(Geom_Surface) surface = BRep_Tool::Surface(faceIn);
|
||||
if (surface->IsKind(STANDARD_TYPE(Geom_ElementarySurface)))
|
||||
{
|
||||
Handle(Geom_ElementarySurface) eSurface = Handle(Geom_ElementarySurface)::DownCast(surface);
|
||||
gp_Dir direction = eSurface->Axis().Direction();
|
||||
vector = direction;
|
||||
vector.Normalize();
|
||||
if (faceIn.Orientation() == TopAbs_REVERSED) {
|
||||
vector.Reverse();
|
||||
}
|
||||
if (surface->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)) ||
|
||||
surface->IsKind(STANDARD_TYPE(Geom_SphericalSurface))
|
||||
)
|
||||
{
|
||||
origin = eSurface->Axis().Location().XYZ();
|
||||
projectOriginOntoVector(pickedPointIn);
|
||||
}
|
||||
else {
|
||||
origin = pickedPointIn + vector;
|
||||
}
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
|
||||
VectorAdapter::VectorAdapter(const TopoDS_Edge &edgeIn, const gp_Vec &pickedPointIn) :
|
||||
status(false), vector(), origin(pickedPointIn)
|
||||
{
|
||||
TopoDS_Vertex firstVertex = TopExp::FirstVertex(edgeIn, Standard_True);
|
||||
TopoDS_Vertex lastVertex = TopExp::LastVertex(edgeIn, Standard_True);
|
||||
vector = convert(lastVertex) - convert(firstVertex);
|
||||
if (vector.Magnitude() < Precision::Confusion()) {
|
||||
return;
|
||||
}
|
||||
vector.Normalize();
|
||||
|
||||
status = true;
|
||||
projectOriginOntoVector(pickedPointIn);
|
||||
}
|
||||
|
||||
VectorAdapter::VectorAdapter(const TopoDS_Vertex &vertex1In, const TopoDS_Vertex &vertex2In) :
|
||||
status(false), vector(), origin()
|
||||
{
|
||||
vector = convert(vertex2In) - convert(vertex1In);
|
||||
vector.Normalize();
|
||||
|
||||
//build origin half way.
|
||||
gp_Vec tempVector = (convert(vertex2In) - convert(vertex1In));
|
||||
double mag = tempVector.Magnitude();
|
||||
tempVector.Normalize();
|
||||
tempVector *= (mag / 2.0);
|
||||
origin = tempVector + convert(vertex1In);
|
||||
|
||||
status = true;
|
||||
}
|
||||
|
||||
VectorAdapter::VectorAdapter(const gp_Vec &vector1, const gp_Vec &vector2) :
|
||||
status(false), vector(), origin()
|
||||
{
|
||||
vector = vector2- vector1;
|
||||
vector.Normalize();
|
||||
|
||||
//build origin half way.
|
||||
gp_Vec tempVector = vector2 - vector1;
|
||||
double mag = tempVector.Magnitude();
|
||||
tempVector.Normalize();
|
||||
tempVector *= (mag / 2.0);
|
||||
origin = tempVector + vector1;
|
||||
|
||||
status = true;
|
||||
}
|
||||
|
||||
void VectorAdapter::projectOriginOntoVector(const gp_Vec &pickedPointIn)
|
||||
{
|
||||
Handle(Geom_Curve) heapLine = new Geom_Line(origin.XYZ(), vector.XYZ());
|
||||
gp_Pnt tempPoint(pickedPointIn.XYZ());
|
||||
GeomAPI_ProjectPointOnCurve projection(tempPoint, heapLine);
|
||||
if (projection.NbPoints() < 1) {
|
||||
return;
|
||||
}
|
||||
origin.SetXYZ(projection.Point(1).XYZ());
|
||||
}
|
||||
|
||||
VectorAdapter::operator gp_Lin() const
|
||||
{
|
||||
gp_Pnt tempOrigin;
|
||||
tempOrigin.SetXYZ(origin.XYZ());
|
||||
return gp_Lin(tempOrigin, gp_Dir(vector));
|
||||
}
|
||||
|
||||
|
||||
/*convert a vertex to vector*/
|
||||
gp_Vec VectorAdapter::convert(const TopoDS_Vertex &vertex)
|
||||
{
|
||||
gp_Pnt point = BRep_Tool::Pnt(vertex);
|
||||
gp_Vec out(point.X(), point.Y(), point.Z());
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
90
src/Mod/Part/App/VectorAdapter.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2022 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef PART_VECTORADAPTER_H
|
||||
#define PART_VECTORADAPTER_H
|
||||
|
||||
#include <Mod/Part/PartGlobal.h>
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Vertex.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <gp_Lin.hxx>
|
||||
#include <Base/Vector3D.h>
|
||||
|
||||
namespace Part
|
||||
{
|
||||
|
||||
|
||||
/*! @brief Convert to vector
|
||||
*
|
||||
* Used to construct a vector from various input types
|
||||
*/
|
||||
class VectorAdapter
|
||||
{
|
||||
public:
|
||||
/*!default construction isValid is set to false*/
|
||||
VectorAdapter();
|
||||
/*!Build a vector from a faceIn
|
||||
* @param faceIn vector will be normal to plane and equal to cylindrical axis.
|
||||
* @param pickedPointIn location of pick. straight conversion from sbvec. not accurate.*/
|
||||
VectorAdapter(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn);
|
||||
/*!Build a vector from an edgeIn
|
||||
* @param edgeIn vector will be lastPoint - firstPoint.
|
||||
* @param pickedPointIn location of pick. straight conversion from sbvec. not accurate.*/
|
||||
VectorAdapter(const TopoDS_Edge &edgeIn, const gp_Vec &pickedPointIn);
|
||||
/*!Build a vector From 2 vertices.
|
||||
*vector will be equal to @param vertex2In - @param vertex1In.*/
|
||||
VectorAdapter(const TopoDS_Vertex &vertex1In, const TopoDS_Vertex &vertex2In);
|
||||
/*!Build a vector From 2 vectors.
|
||||
*vector will be equal to @param vector2 - @param vector1.*/
|
||||
VectorAdapter(const gp_Vec &vector1, const gp_Vec &vector2);
|
||||
|
||||
/*!make sure no errors in vector construction.
|
||||
* @return true = vector is good. false = vector is NOT good.*/
|
||||
bool isValid() const {return status;}
|
||||
/*!get the calculated vector.
|
||||
* @return the vector. use isValid to ensure correct results.*/
|
||||
operator gp_Vec() const {return vector;}//explicit bombs
|
||||
/*!build occ line used for extrema calculation*/
|
||||
operator gp_Lin() const;//explicit bombs
|
||||
gp_Vec getPickPoint() const {return origin;}
|
||||
|
||||
operator Base::Vector3d() const {
|
||||
return Base::Vector3d(vector.X(), vector.Y(), vector.Z());
|
||||
}
|
||||
|
||||
|
||||
static gp_Vec convert(const TopoDS_Vertex& vertex);
|
||||
|
||||
private:
|
||||
void projectOriginOntoVector(const gp_Vec &pickedPointIn);
|
||||
bool status;
|
||||
gp_Vec vector;
|
||||
gp_Vec origin;
|
||||
};
|
||||
|
||||
|
||||
} //namespace Part
|
||||
|
||||
#endif
|
||||
@@ -39,9 +39,7 @@
|
||||
#include "PropertyEnumAttacherItem.h"
|
||||
#include "DlgSettings3DViewPartImp.h"
|
||||
#include "DlgSettingsGeneral.h"
|
||||
#include "DlgSettingsMeasure.h"
|
||||
#include "DlgSettingsObjectColor.h"
|
||||
#include "TaskDimension.h"
|
||||
#include "SoBrepEdgeSet.h"
|
||||
#include "SoBrepFaceSet.h"
|
||||
#include "SoBrepPointSet.h"
|
||||
@@ -136,7 +134,6 @@ PyMOD_INIT_FUNC(PartGui)
|
||||
|
||||
Gui::BitmapFactory().addPath(QString::fromLatin1(":/icons/booleans"));
|
||||
Gui::BitmapFactory().addPath(QString::fromLatin1(":/icons/create"));
|
||||
Gui::BitmapFactory().addPath(QString::fromLatin1(":/icons/measure"));
|
||||
Gui::BitmapFactory().addPath(QString::fromLatin1(":/icons/parametric"));
|
||||
Gui::BitmapFactory().addPath(QString::fromLatin1(":/icons/tools"));
|
||||
|
||||
@@ -212,9 +209,6 @@ PyMOD_INIT_FUNC(PartGui)
|
||||
PartGui::ViewProviderRuledSurface ::init();
|
||||
PartGui::ViewProviderFace ::init();
|
||||
PartGui::ViewProviderProjectOnSurface ::init();
|
||||
PartGui::DimensionLinear ::initClass();
|
||||
PartGui::DimensionAngular ::initClass();
|
||||
PartGui::ArcEngine ::initClass();
|
||||
|
||||
PartGui::Workbench ::init();
|
||||
auto manip = std::make_shared<PartGui::WorkbenchManipulator>();
|
||||
@@ -238,7 +232,6 @@ PyMOD_INIT_FUNC(PartGui)
|
||||
(void)new Gui::PrefPageProducer<PartGui::DlgSettingsGeneral>(QT_TRANSLATE_NOOP("QObject", "Part/Part Design"));
|
||||
(void)new Gui::PrefPageProducer<PartGui::DlgSettings3DViewPart>(QT_TRANSLATE_NOOP("QObject", "Part/Part Design"));
|
||||
(void)new Gui::PrefPageProducer<PartGui::DlgSettingsObjectColor>(QT_TRANSLATE_NOOP("QObject", "Part/Part Design"));
|
||||
(void)new Gui::PrefPageProducer<PartGui::DlgSettingsMeasure>(QT_TRANSLATE_NOOP("QObject", "Part/Part Design"));
|
||||
(void)new Gui::PrefPageProducer<PartGui::DlgImportExportIges>(QT_TRANSLATE_NOOP("QObject", "Import-Export"));
|
||||
(void)new Gui::PrefPageProducer<PartGui::DlgImportExportStep>(QT_TRANSLATE_NOOP("QObject", "Import-Export"));
|
||||
Gui::ViewProviderBuilder::add(
|
||||
|
||||
@@ -57,7 +57,6 @@ set(PartGui_UIC_SRCS
|
||||
DlgRevolution.ui
|
||||
DlgSettings3DViewPart.ui
|
||||
DlgSettingsGeneral.ui
|
||||
DlgSettingsMeasure.ui
|
||||
DlgSettingsObjectColor.ui
|
||||
DlgProjectionOnSurface.ui
|
||||
SectionCutting.ui
|
||||
@@ -133,15 +132,9 @@ SET(PartGui_SRCS
|
||||
DlgSettingsGeneral.cpp
|
||||
DlgSettingsGeneral.h
|
||||
DlgSettingsGeneral.ui
|
||||
DlgSettingsMeasure.cpp
|
||||
DlgSettingsMeasure.h
|
||||
DlgSettingsMeasure.ui
|
||||
DlgSettingsObjectColor.cpp
|
||||
DlgSettingsObjectColor.h
|
||||
DlgSettingsObjectColor.ui
|
||||
DlgSettingsMeasure.cpp
|
||||
DlgSettingsMeasure.h
|
||||
DlgSettingsMeasure.ui
|
||||
DlgProjectionOnSurface.cpp
|
||||
DlgProjectionOnSurface.h
|
||||
DlgProjectionOnSurface.ui
|
||||
@@ -248,8 +241,6 @@ SET(PartGui_SRCS
|
||||
TaskSweep.ui
|
||||
TaskThickness.cpp
|
||||
TaskThickness.h
|
||||
TaskDimension.cpp
|
||||
TaskDimension.h
|
||||
TaskCheckGeometry.cpp
|
||||
TaskCheckGeometry.h
|
||||
TaskAttacher.h
|
||||
|
||||
@@ -63,7 +63,6 @@
|
||||
#include "Mirroring.h"
|
||||
#include "SectionCutting.h"
|
||||
#include "TaskCheckGeometry.h"
|
||||
#include "TaskDimension.h"
|
||||
#include "TaskLoft.h"
|
||||
#include "TaskShapeBuilder.h"
|
||||
#include "TaskSweep.h"
|
||||
@@ -2123,225 +2122,6 @@ bool CmdColorPerFace::isActive()
|
||||
return (hasActiveDocument() && !Gui::Control().activeDialog() && objectSelected);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Part_Measure_Linear
|
||||
//===========================================================================
|
||||
|
||||
DEF_STD_CMD_A(CmdMeasureLinear)
|
||||
|
||||
CmdMeasureLinear::CmdMeasureLinear()
|
||||
: Command("Part_Measure_Linear")
|
||||
{
|
||||
sAppModule = "Part";
|
||||
sGroup = QT_TR_NOOP("Part");
|
||||
sMenuText = QT_TR_NOOP("Measure Linear");
|
||||
sToolTipText = QT_TR_NOOP("Measure the linear distance between two points;\n"
|
||||
"if edges or faces are picked, it will measure\n"
|
||||
"between two vertices of them.");
|
||||
sWhatsThis = "Part_Measure_Linear";
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Part_Measure_Linear";
|
||||
}
|
||||
|
||||
void CmdMeasureLinear::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
PartGui::goDimensionLinearRoot();
|
||||
}
|
||||
|
||||
bool CmdMeasureLinear::isActive()
|
||||
{
|
||||
return hasActiveDocument();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Part_Measure_Angular
|
||||
//===========================================================================
|
||||
|
||||
DEF_STD_CMD_A(CmdMeasureAngular)
|
||||
|
||||
CmdMeasureAngular::CmdMeasureAngular()
|
||||
: Command("Part_Measure_Angular")
|
||||
{
|
||||
sAppModule = "Part";
|
||||
sGroup = QT_TR_NOOP("Part");
|
||||
sMenuText = QT_TR_NOOP("Measure Angular");
|
||||
sToolTipText = QT_TR_NOOP("Measure the angle between two edges.");
|
||||
sWhatsThis = "Part_Measure_Angular";
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Part_Measure_Angular";
|
||||
}
|
||||
|
||||
void CmdMeasureAngular::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
PartGui::goDimensionAngularRoot();
|
||||
}
|
||||
|
||||
bool CmdMeasureAngular::isActive()
|
||||
{
|
||||
return hasActiveDocument();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Part_Measure_Refresh
|
||||
//===========================================================================
|
||||
|
||||
DEF_STD_CMD_A(CmdMeasureRefresh)
|
||||
|
||||
CmdMeasureRefresh::CmdMeasureRefresh()
|
||||
: Command("Part_Measure_Refresh")
|
||||
{
|
||||
sAppModule = "Part";
|
||||
sGroup = QT_TR_NOOP("Part");
|
||||
sMenuText = QT_TR_NOOP("Refresh");
|
||||
sToolTipText = QT_TR_NOOP("Recalculate the dimensions\n"
|
||||
"if the measured points have moved.");
|
||||
sWhatsThis = "Part_Measure_Refresh";
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Part_Measure_Refresh";
|
||||
}
|
||||
|
||||
void CmdMeasureRefresh::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
PartGui::refreshDimensions();
|
||||
}
|
||||
|
||||
bool CmdMeasureRefresh::isActive()
|
||||
{
|
||||
return hasActiveDocument();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Part_Measure_Clear_All
|
||||
//===========================================================================
|
||||
|
||||
DEF_STD_CMD_A(CmdMeasureClearAll)
|
||||
|
||||
CmdMeasureClearAll::CmdMeasureClearAll()
|
||||
: Command("Part_Measure_Clear_All")
|
||||
{
|
||||
sAppModule = "Part";
|
||||
sGroup = QT_TR_NOOP("Part");
|
||||
sMenuText = QT_TR_NOOP("Clear All");
|
||||
sToolTipText = QT_TR_NOOP("Clear all dimensions from the active 3D view.");
|
||||
sWhatsThis = "Part_Measure_Clear_All";
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Part_Measure_Clear_All";
|
||||
}
|
||||
|
||||
void CmdMeasureClearAll::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
PartGui::eraseAllDimensions();
|
||||
}
|
||||
|
||||
bool CmdMeasureClearAll::isActive()
|
||||
{
|
||||
return hasActiveDocument();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Part_Measure_Toggle_All
|
||||
//===========================================================================
|
||||
|
||||
DEF_STD_CMD_A(CmdMeasureToggleAll)
|
||||
|
||||
CmdMeasureToggleAll::CmdMeasureToggleAll()
|
||||
: Command("Part_Measure_Toggle_All")
|
||||
{
|
||||
sAppModule = "Part";
|
||||
sGroup = QT_TR_NOOP("Part");
|
||||
sMenuText = QT_TR_NOOP("Toggle All");
|
||||
sToolTipText = QT_TR_NOOP("Toggle on and off "
|
||||
"all currently visible dimensions,\n"
|
||||
"direct, orthogonal, and angular.");
|
||||
sWhatsThis = "Part_Measure_Toggle_All";
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Part_Measure_Toggle_All";
|
||||
}
|
||||
|
||||
void CmdMeasureToggleAll::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
|
||||
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("View");
|
||||
bool visibility = group->GetBool("DimensionsVisible", true);
|
||||
if (visibility)
|
||||
group->SetBool("DimensionsVisible", false);
|
||||
else
|
||||
group->SetBool("DimensionsVisible", true);
|
||||
}
|
||||
|
||||
bool CmdMeasureToggleAll::isActive()
|
||||
{
|
||||
return hasActiveDocument();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Part_Measure_Toggle_3D
|
||||
//===========================================================================
|
||||
|
||||
DEF_STD_CMD_A(CmdMeasureToggle3d)
|
||||
|
||||
CmdMeasureToggle3d::CmdMeasureToggle3d()
|
||||
: Command("Part_Measure_Toggle_3D")
|
||||
{
|
||||
sAppModule = "Part";
|
||||
sGroup = QT_TR_NOOP("Part");
|
||||
sMenuText = QT_TR_NOOP("Toggle 3D");
|
||||
sToolTipText = QT_TR_NOOP("Toggle on and off "
|
||||
"all direct dimensions,\n"
|
||||
"including angular.");
|
||||
sWhatsThis = "Part_Measure_Toggle_3D";
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Part_Measure_Toggle_3D";
|
||||
}
|
||||
|
||||
void CmdMeasureToggle3d::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
PartGui::toggle3d();
|
||||
}
|
||||
|
||||
bool CmdMeasureToggle3d::isActive()
|
||||
{
|
||||
return hasActiveDocument();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Part_Measure_Toggle_Delta
|
||||
//===========================================================================
|
||||
|
||||
DEF_STD_CMD_A(CmdMeasureToggleDelta)
|
||||
|
||||
CmdMeasureToggleDelta::CmdMeasureToggleDelta()
|
||||
: Command("Part_Measure_Toggle_Delta")
|
||||
{
|
||||
sAppModule = "Part";
|
||||
sGroup = QT_TR_NOOP("Part");
|
||||
sMenuText = QT_TR_NOOP("Toggle Delta");
|
||||
sToolTipText = QT_TR_NOOP("Toggle on and off "
|
||||
"all orthogonal dimensions,\n"
|
||||
"meaning that a direct dimension will be decomposed\n"
|
||||
"into its X, Y, and Z components.");
|
||||
sWhatsThis = "Part_Measure_Toggle_Delta";
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Part_Measure_Toggle_Delta";
|
||||
}
|
||||
|
||||
void CmdMeasureToggleDelta::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
PartGui::toggleDelta();
|
||||
}
|
||||
|
||||
bool CmdMeasureToggleDelta::isActive()
|
||||
{
|
||||
return hasActiveDocument();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Part_BoxSelection
|
||||
//===========================================================================
|
||||
@@ -2486,13 +2266,6 @@ void CreatePartCommands()
|
||||
rcCmdMgr.addCommand(new CmdPartThickness());
|
||||
rcCmdMgr.addCommand(new CmdCheckGeometry());
|
||||
rcCmdMgr.addCommand(new CmdColorPerFace());
|
||||
rcCmdMgr.addCommand(new CmdMeasureLinear());
|
||||
rcCmdMgr.addCommand(new CmdMeasureAngular());
|
||||
rcCmdMgr.addCommand(new CmdMeasureRefresh());
|
||||
rcCmdMgr.addCommand(new CmdMeasureClearAll());
|
||||
rcCmdMgr.addCommand(new CmdMeasureToggleAll());
|
||||
rcCmdMgr.addCommand(new CmdMeasureToggle3d());
|
||||
rcCmdMgr.addCommand(new CmdMeasureToggleDelta());
|
||||
rcCmdMgr.addCommand(new CmdBoxSelection());
|
||||
rcCmdMgr.addCommand(new CmdPartProjectionOnSurface());
|
||||
rcCmdMgr.addCommand(new CmdPartSectionCut());
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2022 *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <Gui/Command.h>
|
||||
|
||||
#include "DlgSettingsMeasure.h"
|
||||
#include "ui_DlgSettingsMeasure.h"
|
||||
|
||||
|
||||
using namespace PartGui;
|
||||
|
||||
DlgSettingsMeasure::DlgSettingsMeasure(QWidget* parent)
|
||||
: PreferencePage(parent) , ui(new Ui_DlgSettingsMeasure)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
connect(ui->pushButtonRefresh, &QPushButton::clicked, this, &DlgSettingsMeasure::onMeasureRefresh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the object and frees any allocated resources
|
||||
*/
|
||||
DlgSettingsMeasure::~DlgSettingsMeasure() = default;
|
||||
|
||||
void DlgSettingsMeasure::saveSettings()
|
||||
{
|
||||
ui->dim3dColorButton->onSave();
|
||||
ui->dimDeltaColorButton->onSave();
|
||||
ui->dimAngularColorButton->onSave();
|
||||
|
||||
ui->fontSizeSpinBox->onSave();
|
||||
ui->fontNameComboBox->onSave();
|
||||
|
||||
ui->fontStyleBoldCheckBox->onSave();
|
||||
ui->fontStyleItalicCheckBox->onSave();
|
||||
}
|
||||
|
||||
void DlgSettingsMeasure::loadSettings()
|
||||
{
|
||||
ui->dim3dColorButton->onRestore();
|
||||
ui->dimDeltaColorButton->onRestore();
|
||||
ui->dimAngularColorButton->onRestore();
|
||||
|
||||
ui->fontSizeSpinBox->onRestore();
|
||||
ui->fontNameComboBox->onRestore();
|
||||
ui->fontNameComboBox->addItems(QStringList({QString::fromUtf8("defaultFont")}));
|
||||
|
||||
ui->fontStyleBoldCheckBox->onRestore();
|
||||
ui->fontStyleItalicCheckBox->onRestore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strings of the subwidgets using the current language.
|
||||
*/
|
||||
void DlgSettingsMeasure::changeEvent(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::LanguageChange) {
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
else {
|
||||
QWidget::changeEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void DlgSettingsMeasure::onMeasureRefresh()
|
||||
{
|
||||
DlgSettingsMeasure::saveSettings();
|
||||
Gui::Command::runCommand(Gui::Command::Gui, "Gui.runCommand('Part_Measure_Refresh',0)");
|
||||
}
|
||||
|
||||
#include "moc_DlgSettingsMeasure.cpp"
|
||||
@@ -1,279 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PartGui::DlgSettingsMeasure</class>
|
||||
<widget class="QWidget" name="PartGui::DlgSettingsMeasure">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>282</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Measure</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Measurement settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="Gui::PrefColorButton" name="dim3dColorButton">
|
||||
<property name="color">
|
||||
<color>
|
||||
<red>255</red>
|
||||
<green>0</green>
|
||||
<blue>0</blue>
|
||||
</color>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>Dimensions3dColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Part</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_1">
|
||||
<property name="text">
|
||||
<string>3D color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="Gui::PrefColorButton" name="dimDeltaColorButton">
|
||||
<property name="color">
|
||||
<color>
|
||||
<red>0</red>
|
||||
<green>255</green>
|
||||
<blue>0</blue>
|
||||
</color>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DimensionsDeltaColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Part</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Delta color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="Gui::PrefColorButton" name="dimAngularColorButton">
|
||||
<property name="color">
|
||||
<color>
|
||||
<red>0</red>
|
||||
<green>0</green>
|
||||
<blue>255</blue>
|
||||
</color>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DimensionsAngularColor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Part</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Angular color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="Gui::PrefSpinBox" name="fontSizeSpinBox">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DimensionsFontSize</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Part</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Font size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="Gui::PrefCheckBox" name="fontStyleBoldCheckBox">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Bold</string>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DimensionsFontStyleBold</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Part</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="Gui::PrefCheckBox" name="fontStyleItalicCheckBox">
|
||||
<property name="font">
|
||||
<font>
|
||||
<italic>true</italic>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Italic</string>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DimensionsFontStyleItalic</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Part</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="Gui::PrefFontBox" name="fontNameComboBox">
|
||||
<property name="currentText">
|
||||
<string>defaultFont</string>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DimensionsFontName</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Part</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Font name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButtonRefresh">
|
||||
<property name="text">
|
||||
<string>Refresh existing measurements</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</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>
|
||||
</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::PrefFontBox</class>
|
||||
<extends>QFontComboBox</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -30,15 +30,6 @@
|
||||
<file>icons/create/Part_Torus.svg</file>
|
||||
<file>icons/create/Part_Tube.svg</file>
|
||||
</qresource>
|
||||
<qresource>
|
||||
<file>icons/measure/Part_Measure_Angular.svg</file>
|
||||
<file>icons/measure/Part_Measure_Linear.svg</file>
|
||||
<file>icons/measure/Part_Measure_Refresh.svg</file>
|
||||
<file>icons/measure/Part_Measure_Step_Active.svg</file>
|
||||
<file>icons/measure/Part_Measure_Step_Done.svg</file>
|
||||
<file>icons/measure/Part_Measure_Toggle_3D.svg</file>
|
||||
<file>icons/measure/Part_Measure_Toggle_Delta.svg</file>
|
||||
</qresource>
|
||||
<qresource>
|
||||
<file>icons/parametric/Part_Box_Parametric.svg</file>
|
||||
<file>icons/parametric/Part_Circle_Parametric.svg</file>
|
||||
|
||||
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 13 KiB |
@@ -1,659 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<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"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2943"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="Part_Measure_Refresh.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
version="1.1">
|
||||
<defs
|
||||
id="defs2945">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
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>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
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
|
||||
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
|
||||
inkscape:collect="always"
|
||||
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>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2951" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4158"
|
||||
id="linearGradient3092"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-129.22376,-0.88388348)"
|
||||
x1="419.99387"
|
||||
y1="102.77802"
|
||||
x2="458.7193"
|
||||
y2="69.431564" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4052"
|
||||
id="linearGradient3094"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(168.6744,65.825928)"
|
||||
x1="138.99986"
|
||||
y1="44.863674"
|
||||
x2="92.497559"
|
||||
y2="-14.356517" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4122"
|
||||
id="linearGradient3096"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-88.034794,-1.0606602)"
|
||||
x1="391.3074"
|
||||
y1="120.81136"
|
||||
x2="394.43201"
|
||||
y2="112.43636" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4060"
|
||||
id="linearGradient3098"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(168.6744,65.825928)"
|
||||
x1="103.93729"
|
||||
y1="49.179436"
|
||||
x2="120.49899"
|
||||
y2="0.21229285" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3953"
|
||||
id="linearGradient3959"
|
||||
x1="214.70918"
|
||||
y1="80.886589"
|
||||
x2="218.70918"
|
||||
y2="104.88659"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(80,0)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3961"
|
||||
id="linearGradient3967"
|
||||
x1="196.70918"
|
||||
y1="106.88659"
|
||||
x2="190.70918"
|
||||
y2="80.886589"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(80,0)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3953-5"
|
||||
id="linearGradient3959-3"
|
||||
x1="214.70918"
|
||||
y1="80.886589"
|
||||
x2="218.70918"
|
||||
y2="104.88659"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(80,0)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3953-5">
|
||||
<stop
|
||||
style="stop-color:#babdb6;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3955-6" />
|
||||
<stop
|
||||
style="stop-color:#555753;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3957-2" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2831-2"
|
||||
id="linearGradient4585"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.370336,0,0,1.3589114,0.02150968,-18.214919)"
|
||||
x1="13.478554"
|
||||
y1="10.612206"
|
||||
x2="15.419417"
|
||||
y2="19.115122" />
|
||||
<linearGradient
|
||||
id="linearGradient2831-2">
|
||||
<stop
|
||||
style="stop-color:#3465a4;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop2833-3" />
|
||||
<stop
|
||||
id="stop2855-1"
|
||||
offset="0.33333334"
|
||||
style="stop-color:#5b86be;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#83a8d8;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop2835-6" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2871"
|
||||
id="linearGradient1488"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-1.370336,0,0,-1.3589114,64.512944,44.464873)"
|
||||
x1="37.128052"
|
||||
y1="29.729605"
|
||||
x2="37.065414"
|
||||
y2="26.194071" />
|
||||
<linearGradient
|
||||
id="linearGradient2871"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop2873"
|
||||
offset="0"
|
||||
style="stop-color:#3465a4;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop2875"
|
||||
offset="1"
|
||||
style="stop-color:#3465a4;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3063-2"
|
||||
id="linearGradient4587"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="42.703487"
|
||||
y1="20.547306"
|
||||
x2="26.605606"
|
||||
y2="33.634254" />
|
||||
<linearGradient
|
||||
id="linearGradient3063-2">
|
||||
<stop
|
||||
id="stop3065-6"
|
||||
offset="0"
|
||||
style="stop-color:#729fcf;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop3067-0"
|
||||
offset="1"
|
||||
style="stop-color:#204a87;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2380-9"
|
||||
id="linearGradient3034"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="41.791897"
|
||||
y1="20.134634"
|
||||
x2="23.705669"
|
||||
y2="34.083359" />
|
||||
<linearGradient
|
||||
id="linearGradient2380-9">
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop2382-4" />
|
||||
<stop
|
||||
style="stop-color:#3465a4;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop2384-6" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2380-9"
|
||||
id="linearGradient3034-4"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="26.221533"
|
||||
y1="31.125586"
|
||||
x2="46.731483"
|
||||
y2="21.766298" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2831-2"
|
||||
id="linearGradient4295"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.370336,0,0,1.3589114,0.02150968,-18.214919)"
|
||||
x1="13.478554"
|
||||
y1="10.612206"
|
||||
x2="15.419417"
|
||||
y2="19.115122" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2871"
|
||||
id="linearGradient4297"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-1.370336,0,0,-1.3589114,64.512944,44.464873)"
|
||||
x1="37.128052"
|
||||
y1="29.729605"
|
||||
x2="37.065414"
|
||||
y2="26.194071" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3063-2"
|
||||
id="linearGradient4299"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="42.703487"
|
||||
y1="20.547306"
|
||||
x2="26.605606"
|
||||
y2="33.634254" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="7.6761244"
|
||||
inkscape:cx="44.088329"
|
||||
inkscape:cy="36.738683"
|
||||
inkscape:current-layer="g3629"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1375"
|
||||
inkscape:window-height="876"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-bbox="false"
|
||||
inkscape:snap-nodes="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3059"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<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>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[blobfish]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Part_Measure_Linear</dc:title>
|
||||
<dc:date>2013-12-17</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Part/Gui/Resources/icons/Part_Measure_Linear.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<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"
|
||||
inkscape:connector-curvature="0"
|
||||
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 2,36.000002 l 30,12 0,-6 -2,-4 c 8,-12.000002 0,-24.000002 -4,-34.000002 z"
|
||||
id="path3100"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccc" />
|
||||
<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"
|
||||
inkscape:connector-curvature="0" />
|
||||
<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"
|
||||
inkscape:connector-curvature="0" />
|
||||
<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 4,34.000002 l 12,-4 c 8,-12.000002 0,-24.000002 -4,-34.000002 z"
|
||||
id="path3894"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<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"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:url(#linearGradient3967);fill-opacity:1;stroke:#d3d7cf;stroke-width:1.99999975999999990;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.469561 1.8,32.600002 l 26.2,10.4 0,-2.5 -2.2,-4.5 c 8,-12.000002 1.2,-22.000002 -3.2,-32.100002 z"
|
||||
id="path3100-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccc" />
|
||||
<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"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
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"
|
||||
sodipodi:cx="-93"
|
||||
sodipodi:cy="39"
|
||||
sodipodi:rx="15"
|
||||
sodipodi:ry="15"
|
||||
d="m -78,39 a 15,15 0 0 1 -15,15 15,15 0 0 1 -15,-15 15,15 0 0 1 15,-15 15,15 0 0 1 15,15 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"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccsc" />
|
||||
<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"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<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 37,51 8,-3 16,5 -6,4 z"
|
||||
id="path4003"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(256.70919,66.886588)"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:#d3d7cf;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="m 61,53 0,4 -6,4 0,-4 z"
|
||||
id="path4005"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(256.70919,66.886588)"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<g
|
||||
id="g4314">
|
||||
<g
|
||||
id="g3863"
|
||||
transform="matrix(0.59299466,0,0,0.59299466,283.4333,77.218635)">
|
||||
<path
|
||||
style="color:#000000;display:block;overflow:visible;visibility:visible;fill:url(#linearGradient4295);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient4297);stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
|
||||
d="m 27,-3.6915582 c 0,0 -12.247378,-0.8493196 -8.478954,13.4192502 l -10.534458,0 c 0,0 0.685168,-16.137073 19.013412,-13.4192502 z"
|
||||
id="path2865-9"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true"
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:connector-curvature="0" />
|
||||
<g
|
||||
id="g1878-1"
|
||||
transform="matrix(-0.79349441,-0.66481753,-0.67040672,0.78687903,77.66003,0.94046451)"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true"
|
||||
style="fill:url(#linearGradient4299);fill-opacity:1;stroke:#204a87;stroke-width:0.73280919;stroke-opacity:1">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
id="path1880-27"
|
||||
d="M 44.306783,50.229694 C 62.821497,35.818859 49.664587,13.411704 22.462411,12.49765 L 22.113843,3.1515478 7.6245439,20.496754 22.714328,33.219189 c 0,0 -0.251917,-9.88122 -0.251917,-9.88122 18.82976,0.998977 32.981627,14.071729 21.844372,26.891725 z"
|
||||
style="color:#000000;display:block;overflow:visible;visibility:visible;fill:url(#linearGradient3034);fill-opacity:1;fill-rule:nonzero;stroke:#0b1521;stroke-width:3.26039815;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
style="fill:none;stroke:#729fcf;stroke-width:0.73280919;stroke-opacity:1"
|
||||
inkscape:r_cy="true"
|
||||
inkscape:r_cx="true"
|
||||
transform="matrix(-0.69686517,-0.58385766,-0.58876622,0.69105539,72.350404,1.0127423)"
|
||||
id="g2805-0">
|
||||
<path
|
||||
inkscape:r_cy="true"
|
||||
inkscape:r_cx="true"
|
||||
style="color:#000000;display:block;overflow:visible;visibility:visible;fill:none;stroke:#729fcf;stroke-width:2.20148993;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:21;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
|
||||
d="M 52.368857,42.344789 C 57.336994,33.465615 49.176003,12.601866 19.05552,12.672851 L 18.677956,5.6633463 7.4378077,19.282655 19.129354,29.167094 18.807724,20.554957 c 18.244937,0.381972 33.804002,9.457851 33.561133,21.789832 z"
|
||||
id="path2807-9"
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g3863-0"
|
||||
transform="matrix(-0.59299466,0,0,-0.59299466,322.563,94.41548)">
|
||||
<path
|
||||
style="color:#000000;display:block;overflow:visible;visibility:visible;fill:url(#linearGradient4585);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient1488);stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
|
||||
d="m 27,-3.6915582 c 0,0 -12.247378,-0.8493196 -8.478954,13.4192502 l -10.534458,0 c 0,0 0.685168,-16.137073 19.013412,-13.4192502 z"
|
||||
id="path2865-3"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true"
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:connector-curvature="0" />
|
||||
<g
|
||||
id="g1878-6"
|
||||
transform="matrix(-0.79349441,-0.66481753,-0.67040672,0.78687903,77.66003,0.94046451)"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true"
|
||||
style="fill:url(#linearGradient4587);fill-opacity:1;stroke:#204a87;stroke-width:0.73280919;stroke-opacity:1">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
id="path1880-2"
|
||||
d="M 44.306783,50.229694 C 62.821497,35.818859 49.664587,13.411704 22.462411,12.49765 L 22.113843,3.1515478 7.6245439,20.496754 22.714328,33.219189 c 0,0 -0.251917,-9.88122 -0.251917,-9.88122 18.82976,0.998977 32.981627,14.071729 21.844372,26.891725 z"
|
||||
style="color:#000000;display:block;overflow:visible;visibility:visible;fill:url(#linearGradient3034-4);fill-opacity:1;fill-rule:nonzero;stroke:#0b1521;stroke-width:3.26039815;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
|
||||
inkscape:r_cx="true"
|
||||
inkscape:r_cy="true"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
style="fill:none;stroke:#729fcf;stroke-width:0.73280919;stroke-opacity:1"
|
||||
inkscape:r_cy="true"
|
||||
inkscape:r_cx="true"
|
||||
transform="matrix(-0.69686517,-0.58385766,-0.58876622,0.69105539,72.350404,1.0127423)"
|
||||
id="g2805-4">
|
||||
<path
|
||||
inkscape:r_cy="true"
|
||||
inkscape:r_cx="true"
|
||||
style="color:#000000;display:block;overflow:visible;visibility:visible;fill:none;stroke:#729fcf;stroke-width:2.20148993;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:21;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
|
||||
d="M 52.368857,42.344789 C 57.864671,33.591679 49.176003,12.601866 19.05552,12.672851 L 18.677956,5.6633463 7.4378077,19.282655 19.129354,29.167094 18.807724,20.554957 c 18.244937,0.381972 33.804002,9.457851 33.561133,21.789832 z"
|
||||
id="path2807-5"
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 14 KiB |
@@ -1,374 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2013 Thomas Anderson <blobfish[at]gmx.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TASKDIMENSION_H
|
||||
#define TASKDIMENSION_H
|
||||
|
||||
#include <gp_Lin.hxx>
|
||||
#include <gp_Vec.hxx>
|
||||
|
||||
#include <Inventor/engines/SoSubEngine.h>
|
||||
#include <Inventor/engines/SoEngine.h>
|
||||
#include <Inventor/fields/SoSFColor.h>
|
||||
#include <Inventor/fields/SoSFFloat.h>
|
||||
#include <Inventor/fields/SoSFMatrix.h>
|
||||
#include <Inventor/fields/SoSFRotation.h>
|
||||
#include <Inventor/fields/SoSFString.h>
|
||||
#include <Inventor/fields/SoSFVec3f.h>
|
||||
#include <Inventor/nodekits/SoSeparatorKit.h>
|
||||
|
||||
#include <Base/Matrix.h>
|
||||
#include <Gui/TaskView/TaskDialog.h>
|
||||
#include <Gui/TaskView/TaskView.h>
|
||||
|
||||
|
||||
class TopoDS_Shape;
|
||||
class TopoDS_Face;
|
||||
class TopoDS_Edge;
|
||||
class TopoDS_Vertex;
|
||||
class gp_Pnt;
|
||||
class BRepExtrema_DistShapeShape;
|
||||
|
||||
class QPushButton;
|
||||
class QPixmap;
|
||||
class QLabel;
|
||||
|
||||
namespace Gui{class View3dInventorViewer;}
|
||||
|
||||
namespace PartGui
|
||||
{
|
||||
/*!find shape from selection strings
|
||||
* @param shapeOut search results.
|
||||
* @param doc document name to search.
|
||||
* @param object object name to search.
|
||||
* @param sub sub-object name to search.
|
||||
* @return signal if the search was successful.
|
||||
*/
|
||||
bool getShapeFromStrings(TopoDS_Shape &shapeOut, const std::string &doc, const std::string &object, const std::string &sub, Base::Matrix4D *mat=nullptr);
|
||||
/*!examine pre selection
|
||||
* @param shape1 first shape in current selection
|
||||
* @param shape2 second shape in current selection
|
||||
* @return signal if preselection is valid. false means shape1 and shape2 are invalid.
|
||||
*/
|
||||
bool evaluateLinearPreSelection(TopoDS_Shape &shape1, TopoDS_Shape &shape2);
|
||||
/*!start of the measure linear command*/
|
||||
void goDimensionLinearRoot();
|
||||
/*!does the measure and create dimensions without a dialog
|
||||
* @param shape1 first shape.
|
||||
* @param shape2 second shape.
|
||||
* @todo incorporate some form of "adapt to topods_shape". so we can expand to other types outside OCC.
|
||||
*/
|
||||
void goDimensionLinearNoTask(const TopoDS_Shape &shape1, const TopoDS_Shape &shape2);
|
||||
/*!prints results of measuring to console.
|
||||
* @param measure object containing the measure information
|
||||
*/
|
||||
void dumpLinearResults(const BRepExtrema_DistShapeShape &measure);
|
||||
/*!convenience function to get the viewer*/
|
||||
Gui::View3DInventorViewer* getViewer();
|
||||
/*!adds 3d and delta dimensions to the viewer
|
||||
* @param measure object containing the measure information.
|
||||
*/
|
||||
void addLinearDimensions(const BRepExtrema_DistShapeShape &measure);
|
||||
/*!creates one dimension from points with color
|
||||
* @param point1 first point
|
||||
* @param point2 second point
|
||||
* @param color color of dimension
|
||||
* @return an inventor node to add to a scenegraph
|
||||
*/
|
||||
SoNode* createLinearDimension(const gp_Pnt &point1, const gp_Pnt &point2, const SbColor &color);
|
||||
/*!erases all the dimensions in the viewer.*/
|
||||
void eraseAllDimensions();
|
||||
/*!refresh all the dimensions in the viewer.*/
|
||||
void refreshDimensions();
|
||||
/*!toggles the display status of the 3d dimensions*/
|
||||
void toggle3d();
|
||||
/*!toggles the display status of the delta dimensions*/
|
||||
void toggleDelta();
|
||||
/*!make sure measure command isn't working with everything invisible. Confusing the user*/
|
||||
void ensureSomeDimensionVisible();
|
||||
/*!make sure angle measure command isn't working with 3d off. Confusing the user*/
|
||||
void ensure3dDimensionVisible();
|
||||
/*convert a vertex to vector*/
|
||||
gp_Vec convert(const TopoDS_Vertex &vertex);
|
||||
|
||||
auto getDimensionsFontName();
|
||||
auto getDimensionsFontSize();
|
||||
|
||||
class DimensionLinear : public SoSeparatorKit
|
||||
{
|
||||
SO_KIT_HEADER(DimensionLinear);
|
||||
|
||||
SO_KIT_CATALOG_ENTRY_HEADER(transformation);
|
||||
SO_KIT_CATALOG_ENTRY_HEADER(annotate);
|
||||
SO_KIT_CATALOG_ENTRY_HEADER(leftArrow);
|
||||
SO_KIT_CATALOG_ENTRY_HEADER(rightArrow);
|
||||
SO_KIT_CATALOG_ENTRY_HEADER(line);
|
||||
SO_KIT_CATALOG_ENTRY_HEADER(textSep);
|
||||
public:
|
||||
DimensionLinear();
|
||||
static void initClass();
|
||||
SbBool affectsState() const override;
|
||||
void setupDimension();
|
||||
|
||||
SoSFVec3f point1;
|
||||
SoSFVec3f point2;
|
||||
SoSFString text;
|
||||
SoSFColor dColor;
|
||||
protected:
|
||||
SoSFRotation rotate;
|
||||
SoSFFloat length;
|
||||
SoSFVec3f origin;
|
||||
|
||||
private:
|
||||
~DimensionLinear() override;
|
||||
};
|
||||
|
||||
/*kit for anglular dimensions*/
|
||||
class DimensionAngular : public SoSeparatorKit
|
||||
{
|
||||
SO_KIT_HEADER(DimensionAngular);
|
||||
|
||||
SO_KIT_CATALOG_ENTRY_HEADER(transformation);
|
||||
SO_KIT_CATALOG_ENTRY_HEADER(annotate);
|
||||
SO_KIT_CATALOG_ENTRY_HEADER(arrow1);
|
||||
SO_KIT_CATALOG_ENTRY_HEADER(arrow2);
|
||||
SO_KIT_CATALOG_ENTRY_HEADER(arcSep);
|
||||
SO_KIT_CATALOG_ENTRY_HEADER(textSep);
|
||||
public:
|
||||
DimensionAngular();
|
||||
static void initClass();
|
||||
SbBool affectsState() const override;
|
||||
|
||||
SoSFFloat radius;//radians.
|
||||
SoSFFloat angle;//radians.
|
||||
SoSFString text;
|
||||
SoSFColor dColor;
|
||||
SoSFMatrix matrix;
|
||||
void setupDimension();
|
||||
private:
|
||||
~DimensionAngular() override;
|
||||
};
|
||||
|
||||
/*used for generating points for arc display*/
|
||||
class ArcEngine : public SoEngine
|
||||
{
|
||||
SO_ENGINE_HEADER(ArcEngine);
|
||||
public:
|
||||
ArcEngine();
|
||||
static void initClass();
|
||||
|
||||
SoSFFloat radius;
|
||||
SoSFFloat angle;
|
||||
SoSFFloat deviation;
|
||||
|
||||
SoEngineOutput points;
|
||||
SoEngineOutput pointCount;
|
||||
protected:
|
||||
void evaluate() override;
|
||||
private:
|
||||
~ArcEngine() override = default;
|
||||
void defaultValues(); //some non error values if something goes wrong.
|
||||
};
|
||||
|
||||
/*! a widget with buttons and icons for a controlled selection process*/
|
||||
class SteppedSelection : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SteppedSelection(const uint &buttonCountIn, QWidget *parent = nullptr);
|
||||
~SteppedSelection() override;
|
||||
QPushButton* getButton(const uint &index);
|
||||
void setIconDone(const uint &index);
|
||||
|
||||
protected:
|
||||
using ButtonIconPairType = std::pair<QPushButton *, QLabel *>;
|
||||
std::vector<ButtonIconPairType> buttons;
|
||||
QPixmap *stepActive;
|
||||
QPixmap *stepDone;
|
||||
|
||||
private Q_SLOTS:
|
||||
void selectionSlot(bool checked);
|
||||
void buildPixmaps();
|
||||
|
||||
};
|
||||
|
||||
/*! just convenience container*/
|
||||
class DimSelections
|
||||
{
|
||||
public:
|
||||
enum ShapeType{None, Vertex, Edge, Face};
|
||||
struct DimSelection
|
||||
{
|
||||
std::string documentName;
|
||||
std::string objectName;
|
||||
std::string subObjectName;
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
ShapeType shapeType;
|
||||
};
|
||||
std::vector<DimSelection> selections;
|
||||
};
|
||||
|
||||
/*!widget for buttons controlling the display of dimensions*/
|
||||
class DimensionControl : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DimensionControl(QWidget* parent);
|
||||
QPushButton *resetButton;
|
||||
public Q_SLOTS:
|
||||
void toggle3dSlot(bool);
|
||||
void toggleDeltaSlot(bool);
|
||||
void clearAllSlot(bool);
|
||||
};
|
||||
|
||||
/*!linear dialog*/
|
||||
class TaskMeasureLinear : public Gui::TaskView::TaskDialog, public Gui::SelectionObserver
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TaskMeasureLinear();
|
||||
~TaskMeasureLinear() override;
|
||||
|
||||
QDialogButtonBox::StandardButtons getStandardButtons() const override
|
||||
{return QDialogButtonBox::Close;}
|
||||
bool isAllowedAlterDocument() const override {return false;}
|
||||
bool needsFullSpace() const override {return false;}
|
||||
protected:
|
||||
void onSelectionChanged(const Gui::SelectionChanges& msg) override;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void selection1Slot(bool checked);
|
||||
void selection2Slot(bool checked);
|
||||
void resetDialogSlot(bool);
|
||||
void toggle3dSlot(bool);
|
||||
void toggleDeltaSlot(bool);
|
||||
void clearAllSlot(bool);
|
||||
void selectionClearDelayedSlot();
|
||||
|
||||
public:
|
||||
static void buildDimension(const DimSelections &sel1, const DimSelections &sel2);
|
||||
|
||||
private:
|
||||
void setUpGui();
|
||||
void buildDimension();
|
||||
void clearSelectionStrings();
|
||||
DimSelections selections1;
|
||||
DimSelections selections2;
|
||||
uint buttonSelectedIndex;
|
||||
SteppedSelection *stepped;
|
||||
|
||||
};
|
||||
|
||||
/*! @brief Convert to vector
|
||||
*
|
||||
* Used to construct a vector from various input types
|
||||
*/
|
||||
class VectorAdapter
|
||||
{
|
||||
public:
|
||||
/*!default construction isValid is set to false*/
|
||||
VectorAdapter();
|
||||
/*!Build a vector from a faceIn
|
||||
* @param faceIn vector will be normal to plane and equal to cylindrical axis.
|
||||
* @param pickedPointIn location of pick. straight conversion from sbvec. not accurate.*/
|
||||
VectorAdapter(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn);
|
||||
/*!Build a vector from an edgeIn
|
||||
* @param edgeIn vector will be lastPoint - firstPoint.
|
||||
* @param pickedPointIn location of pick. straight conversion from sbvec. not accurate.*/
|
||||
VectorAdapter(const TopoDS_Edge &edgeIn, const gp_Vec &pickedPointIn);
|
||||
/*!Build a vector From 2 vertices.
|
||||
*vector will be equal to @param vertex2In - @param vertex1In.*/
|
||||
VectorAdapter(const TopoDS_Vertex &vertex1In, const TopoDS_Vertex &vertex2In);
|
||||
/*!Build a vector From 2 vectors.
|
||||
*vector will be equal to @param vector2 - @param vector1.*/
|
||||
VectorAdapter(const gp_Vec &vector1, const gp_Vec &vector2);
|
||||
|
||||
/*!make sure no errors in vector construction.
|
||||
* @return true = vector is good. false = vector is NOT good.*/
|
||||
bool isValid() const {return status;}
|
||||
/*!get the calculated vector.
|
||||
* @return the vector. use isValid to ensure correct results.*/
|
||||
operator gp_Vec() const {return vector;}//explicit bombs
|
||||
/*!build occ line used for extrema calculation*/
|
||||
operator gp_Lin() const;//explicit bombs
|
||||
gp_Vec getPickPoint() const {return origin;}
|
||||
|
||||
private:
|
||||
void projectOriginOntoVector(const gp_Vec &pickedPointIn);
|
||||
bool status;
|
||||
gp_Vec vector;
|
||||
gp_Vec origin;
|
||||
};
|
||||
|
||||
/*!angular dialog class*/
|
||||
class TaskMeasureAngular : public Gui::TaskView::TaskDialog, public Gui::SelectionObserver
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TaskMeasureAngular();
|
||||
~TaskMeasureAngular() override;
|
||||
|
||||
QDialogButtonBox::StandardButtons getStandardButtons() const override
|
||||
{return QDialogButtonBox::Close;}
|
||||
bool isAllowedAlterDocument() const override {return false;}
|
||||
bool needsFullSpace() const override {return false;}
|
||||
protected:
|
||||
void onSelectionChanged(const Gui::SelectionChanges& msg) override;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void selection1Slot(bool checked);
|
||||
void selection2Slot(bool checked);
|
||||
void resetDialogSlot(bool);
|
||||
void toggle3dSlot(bool);
|
||||
void toggleDeltaSlot(bool);
|
||||
void clearAllSlot(bool);
|
||||
void selectionClearDelayedSlot();
|
||||
|
||||
public:
|
||||
static void buildDimension(const DimSelections &sel1, const DimSelections &sel2);
|
||||
|
||||
private:
|
||||
void buildDimension();
|
||||
void setUpGui();
|
||||
void clearSelection();
|
||||
DimSelections selections1;
|
||||
DimSelections selections2;
|
||||
uint buttonSelectedIndex;
|
||||
SteppedSelection *stepped;
|
||||
static VectorAdapter buildAdapter(const DimSelections &selection);
|
||||
};
|
||||
|
||||
/*!start of the measure angular command*/
|
||||
void goDimensionAngularRoot();
|
||||
/*!examine angular pre selection
|
||||
* @param vector1Out first shape in current selection
|
||||
* @param vector2Out second shape in current selection
|
||||
* @return signal if preselection is valid. false means vector1Out and vector2Out are invalid.
|
||||
*/
|
||||
bool evaluateAngularPreSelection(VectorAdapter &vector1Out, VectorAdapter &vector2Out);
|
||||
/*!build angular dimension*/
|
||||
void goDimensionAngularNoTask(const VectorAdapter &vector1Adapter, const VectorAdapter &vector2Adapter);
|
||||
}
|
||||
|
||||
#endif // TASKDIMENSION_H
|
||||
@@ -41,7 +41,6 @@ using namespace PartGui;
|
||||
qApp->translate("Workbench", "Split");
|
||||
qApp->translate("Workbench", "Compound");
|
||||
qApp->translate("Workbench", "Create a copy");
|
||||
qApp->translate("Workbench", "Measure");
|
||||
#endif
|
||||
|
||||
/// @namespace PartGui @class Workbench
|
||||
@@ -140,18 +139,6 @@ Gui::MenuItem* Workbench::setupMenuBar() const
|
||||
<< "Separator"
|
||||
<< "Part_EditAttachment";
|
||||
|
||||
Gui::MenuItem* measure = new Gui::MenuItem;
|
||||
root->insertItem(item,measure);
|
||||
measure->setCommand("Measure");
|
||||
*measure << "Part_Measure_Linear"
|
||||
<< "Part_Measure_Angular"
|
||||
<< "Separator"
|
||||
<< "Part_Measure_Refresh"
|
||||
<< "Part_Measure_Clear_All"
|
||||
<< "Part_Measure_Toggle_All"
|
||||
<< "Part_Measure_Toggle_3D"
|
||||
<< "Part_Measure_Toggle_Delta";
|
||||
|
||||
Gui::MenuItem* view = root->findItem("&View");
|
||||
if (view) {
|
||||
Gui::MenuItem* appr = view->findItem("Std_RandomColor");
|
||||
@@ -210,17 +197,6 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
|
||||
<< "Part_CheckGeometry"
|
||||
<< "Part_Defeaturing";
|
||||
|
||||
Gui::ToolBarItem* measure = new Gui::ToolBarItem(root);
|
||||
measure->setCommand("Measure");
|
||||
*measure << "Part_Measure_Linear"
|
||||
<< "Part_Measure_Angular"
|
||||
<< "Separator"
|
||||
<< "Part_Measure_Refresh"
|
||||
<< "Part_Measure_Clear_All"
|
||||
<< "Part_Measure_Toggle_All"
|
||||
<< "Part_Measure_Toggle_3D"
|
||||
<< "Part_Measure_Toggle_Delta";
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,13 +34,6 @@ void WorkbenchManipulator::modifyMenuBar([[maybe_unused]] Gui::MenuItem* menuBar
|
||||
addSectionCut(menuBar);
|
||||
}
|
||||
|
||||
void WorkbenchManipulator::modifyContextMenu(const char* recipient, Gui::MenuItem* menuBar)
|
||||
{
|
||||
if (strcmp(recipient, "View") == 0) {
|
||||
addSelectionFilter(menuBar);
|
||||
}
|
||||
}
|
||||
|
||||
void WorkbenchManipulator::modifyToolBars(Gui::ToolBarItem* toolBar)
|
||||
{
|
||||
addSelectionFilter(toolBar);
|
||||
@@ -78,12 +71,3 @@ void WorkbenchManipulator::addSelectionFilter(Gui::ToolBarItem* toolBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorkbenchManipulator::addSelectionFilter(Gui::MenuItem* menuBar)
|
||||
{
|
||||
if (auto measure = menuBar->findItem("Measure")) {
|
||||
auto add = new Gui::MenuItem(); // NOLINT
|
||||
add->setCommand("Part_SelectFilter");
|
||||
menuBar->insertItem(measure, add);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,12 +38,6 @@ protected:
|
||||
* The default implementation doesn't change anything.SectionCut
|
||||
*/
|
||||
void modifyMenuBar(Gui::MenuItem* menuBar) override;
|
||||
/*!
|
||||
* \brief modifyContextMenu
|
||||
* Method to manipulate the contextmenu structure of a workbench.
|
||||
* The default implementation doesn't change anything.
|
||||
*/
|
||||
void modifyContextMenu(const char* recipient, Gui::MenuItem* menuBar) override;
|
||||
/*!
|
||||
* \brief modifyToolBars
|
||||
* Method to manipulate the toolbar structure of a workbench
|
||||
@@ -60,7 +54,6 @@ protected:
|
||||
private:
|
||||
static void addSectionCut(Gui::MenuItem* menuBar);
|
||||
static void addSelectionFilter(Gui::ToolBarItem* toolBar);
|
||||
static void addSelectionFilter(Gui::MenuItem* menuBar);
|
||||
};
|
||||
|
||||
} // namespace PartGui
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "DatumLine.h"
|
||||
#include "DatumPlane.h"
|
||||
#include "DatumPoint.h"
|
||||
#include "Measure.h"
|
||||
#include "FeatureBase.h"
|
||||
#include "FeatureBoolean.h"
|
||||
#include "FeatureChamfer.h"
|
||||
@@ -153,5 +154,7 @@ PyMOD_INIT_FUNC(_PartDesign)
|
||||
PartDesign::SubtractiveWedge ::init();
|
||||
PartDesign::FeatureBase ::init();
|
||||
|
||||
PartDesign::Measure ::initialize();
|
||||
|
||||
PyMOD_Return(mod);
|
||||
}
|
||||
|
||||
@@ -117,6 +117,8 @@ SET(Module_SRCS
|
||||
AppPartDesignPy.cpp
|
||||
PreCompiled.cpp
|
||||
PreCompiled.h
|
||||
Measure.cpp
|
||||
Measure.h
|
||||
)
|
||||
SOURCE_GROUP("Module" FILES ${Module_SRCS})
|
||||
|
||||
|
||||
36
src/Mod/PartDesign/App/Measure.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/***************************************************************************
|
||||
* 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 <App/Application.h>
|
||||
#include <App/MeasureManager.h>
|
||||
#include "Base/Console.h"
|
||||
#include "Measure.h"
|
||||
|
||||
|
||||
void PartDesign::Measure::initialize() {
|
||||
const App::MeasureHandler& handler = App::MeasureManager::getMeasureHandler("Part");
|
||||
|
||||
App::MeasureManager::addMeasureHandler("PartDesign", handler.typeCb);
|
||||
}
|
||||
|
||||
44
src/Mod/PartDesign/App/Measure.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/***************************************************************************
|
||||
* 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 PARTDESIGN_MEASURE_H
|
||||
#define PARTDESIGN_MEASURE_H
|
||||
|
||||
#include <Mod/PartDesign/PartDesignGlobal.h>
|
||||
|
||||
|
||||
|
||||
namespace PartDesign
|
||||
{
|
||||
|
||||
|
||||
class PartDesignExport Measure
|
||||
{
|
||||
public:
|
||||
|
||||
static void initialize();
|
||||
|
||||
};
|
||||
|
||||
|
||||
} //namespace PartDesign
|
||||
|
||||
#endif
|
||||
@@ -580,20 +580,6 @@ Gui::MenuItem* Workbench::setupMenuBar() const
|
||||
*part << "Separator" << "PartDesign_WizardShaft";
|
||||
}
|
||||
|
||||
// use Part's measure features also for PartDesign
|
||||
Gui::MenuItem* measure = new Gui::MenuItem;
|
||||
root->insertItem(item, measure);
|
||||
measure->setCommand("Measure");
|
||||
|
||||
*measure << "Part_Measure_Linear"
|
||||
<< "Part_Measure_Angular"
|
||||
<< "Separator"
|
||||
<< "Part_Measure_Refresh"
|
||||
<< "Part_Measure_Clear_All"
|
||||
<< "Part_Measure_Toggle_All"
|
||||
<< "Part_Measure_Toggle_3D"
|
||||
<< "Part_Measure_Toggle_Delta";
|
||||
|
||||
Gui::MenuItem* view = root->findItem("&View");
|
||||
if (view) {
|
||||
Gui::MenuItem* appr = view->findItem("Std_RandomColor");
|
||||
@@ -662,19 +648,6 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
|
||||
<< "Separator"
|
||||
<< "PartDesign_Boolean";
|
||||
|
||||
// use Part's measure features also for PartDesign
|
||||
Gui::ToolBarItem* measure = new Gui::ToolBarItem(root);
|
||||
measure->setCommand("Measure");
|
||||
|
||||
*measure << "Part_Measure_Linear"
|
||||
<< "Part_Measure_Angular"
|
||||
<< "Separator"
|
||||
<< "Part_Measure_Refresh"
|
||||
<< "Part_Measure_Clear_All"
|
||||
<< "Part_Measure_Toggle_All"
|
||||
<< "Part_Measure_Toggle_3D"
|
||||
<< "Part_Measure_Toggle_Delta";
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "SketchObjectSF.h"
|
||||
#include "SketchPy.h"
|
||||
#include "SolverGeometryExtension.h"
|
||||
|
||||
#include "Measure.h"
|
||||
|
||||
namespace Sketcher
|
||||
{
|
||||
@@ -95,6 +95,10 @@ PyMOD_INIT_FUNC(Sketcher)
|
||||
Sketcher::Constraint ::init();
|
||||
Sketcher::PropertyConstraintList ::init();
|
||||
|
||||
// connect to unified measurement facility
|
||||
Sketcher::Measure ::initialize();
|
||||
|
||||
|
||||
Base::Console().Log("Loading Sketcher module... done\n");
|
||||
|
||||
PyMOD_Return(sketcherModule);
|
||||
|
||||
@@ -121,6 +121,8 @@ SET(SketchModule_SRCS
|
||||
AppSketcherPy.cpp
|
||||
PreCompiled.cpp
|
||||
PreCompiled.h
|
||||
Measure.cpp
|
||||
Measure.h
|
||||
)
|
||||
SOURCE_GROUP("Module" FILES ${SketchModule_SRCS})
|
||||
|
||||
|
||||
38
src/Mod/Sketcher/App/Measure.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 Wandererfan <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/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
//! a class for establishing our connection with the unified measurement facility
|
||||
//! we are treating sketches like Part objects for now
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/MeasureManager.h>
|
||||
#include "Base/Console.h"
|
||||
#include "Measure.h"
|
||||
|
||||
|
||||
void Sketcher::Measure::initialize()
|
||||
{
|
||||
const App::MeasureHandler& handler = App::MeasureManager::getMeasureHandler("Part");
|
||||
|
||||
App::MeasureManager::addMeasureHandler("Sketcher", handler.typeCb);
|
||||
}
|
||||
43
src/Mod/Sketcher/App/Measure.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 Wandererfan <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/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
//! a class for establishing our connection with the unified measurement facility
|
||||
|
||||
#ifndef SKETCHER_MEASURE_H
|
||||
#define SKETCHER_MEASURE_H
|
||||
|
||||
#include <Mod/Sketcher/SketcherGlobal.h>
|
||||
|
||||
|
||||
namespace Sketcher
|
||||
{
|
||||
|
||||
|
||||
class SketcherExport Measure
|
||||
{
|
||||
public:
|
||||
static void initialize();
|
||||
};
|
||||
|
||||
|
||||
} // namespace Sketcher
|
||||
|
||||
#endif
|
||||