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

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

View File

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

View File

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

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

View 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

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

View 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

View 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>;
}

View 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

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

View 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;
}

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

View 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

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

View 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

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

View 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

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

View 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

View File

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

View File

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

View 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);
}

View 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