[Measure] Add features, viewproviders and preferences for unified measurement facility
This commit is contained in:
@@ -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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
|
||||
|
||||
Reference in New Issue
Block a user