Core: Add App::LocalCoordinateSystem.

Most of App::Origin is moved into this sub class of App::Origin.
Add App::Point. Change graphics of the planes/axis.
Remove scale-by-content behavior and make it fixed size on screen.
This commit is contained in:
PaddleStroke
2024-11-26 10:16:03 +01:00
parent 3993bfede7
commit 4ebb66838c
23 changed files with 823 additions and 819 deletions

View File

@@ -2150,6 +2150,8 @@ void Application::initTypes()
App::DatumElement ::init();
App::Plane ::init();
App::Line ::init();
App::Point ::init();
App::LocalCoordinateSystem ::init();
App::Part ::init();
App::Origin ::init();
App::Link ::init();

View File

@@ -1,5 +1,7 @@
/***************************************************************************
* Copyright (c) 2015 Stefan Tröger <stefantroeger@gmx.net> *
* Copyright (c) 2015 Alexander Golubev (Fat-Zer) <fatzer2@gmail.com> *
* Copyright (c) 2024 Ondsel (PL Boyer) <development@ondsel.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
@@ -21,42 +23,318 @@
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <string>
#endif
#include <App/Document.h>
#include <Base/Exception.h>
#include <Base/Placement.h>
#include "Datums.h"
#include "Document.h"
#include "Origin.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
using namespace App;
PROPERTY_SOURCE(App::DatumElement, App::GeoFeature)
PROPERTY_SOURCE(App::Plane, App::DatumElement)
PROPERTY_SOURCE(App::Line, App::DatumElement)
PROPERTY_SOURCE(App::Point, App::DatumElement)
PROPERTY_SOURCE(App::LocalCoordinateSystem, App::GeoFeature)
DatumElement::DatumElement()
DatumElement::DatumElement(bool hideRole)
{
ADD_PROPERTY_TYPE(Role, (""), 0, App::Prop_ReadOnly, "Role of the feature in the Origin");
ADD_PROPERTY_TYPE(Role,
(""),
0,
App::Prop_ReadOnly,
"Role of the datum in the local coordinate system.");
// Set placement to read-only
Placement.setStatus(Property::Hidden, true);
// The role is hidden by default. It is visible only when the datum is in a LCS
if (hideRole) {
Role.setStatus(Property::Hidden, true);
}
}
DatumElement::~DatumElement() = default;
Origin* DatumElement::getOrigin()
bool DatumElement::getCameraAlignmentDirection(Base::Vector3d& direction, const char* subname) const
{
Q_UNUSED(subname);
Placement.getValue().getRotation().multVec(Base::Vector3d(0., 0., 1.), direction);
return true;
}
App::LocalCoordinateSystem* DatumElement::getLCS()
{
auto inList = getInList();
for (auto* obj : inList) {
auto* lcs = dynamic_cast<App::LocalCoordinateSystem*>(obj);
if (lcs) {
return lcs;
}
}
return nullptr;
}
bool DatumElement::isOriginFeature()
{
auto lcs = getLCS();
return lcs ? lcs->isOrigin() : false;
}
// ----------------------------------------------------------------------------
LocalCoordinateSystem::LocalCoordinateSystem()
: extension(this)
{
ADD_PROPERTY_TYPE(OriginFeatures,
(nullptr),
0,
App::Prop_Hidden,
"Axis and baseplanes controlled by the LCS");
setStatus(App::NoAutoExpand, true);
extension.initExtension(this);
}
LocalCoordinateSystem::~LocalCoordinateSystem() = default;
bool LocalCoordinateSystem::getCameraAlignmentDirection(Base::Vector3d& direction,
const char* subname) const
{
Q_UNUSED(subname);
Placement.getValue().getRotation().multVec(Base::Vector3d(0., 0., 1.), direction);
return true;
}
App::DatumElement* LocalCoordinateSystem::getDatumElement(const char* role) const
{
const auto& features = OriginFeatures.getValues();
auto featIt = std::find_if(features.begin(), features.end(), [role](App::DocumentObject* obj) {
return obj->isDerivedFrom(App::DatumElement::getClassTypeId())
&& strcmp(static_cast<App::DatumElement*>(obj)->Role.getValue(), role) == 0;
});
if (featIt != features.end()) {
return static_cast<App::DatumElement*>(*featIt);
}
std::stringstream err;
err << "LocalCoordinateSystem \"" << getFullName() << "\" doesn't contain feature with role \""
<< role << '"';
throw Base::RuntimeError(err.str().c_str());
}
App::Line* LocalCoordinateSystem::getAxis(const char* role) const
{
App::DatumElement* feat = getDatumElement(role);
if (feat->isDerivedFrom(App::Line::getClassTypeId())) {
return static_cast<App::Line*>(feat);
}
std::stringstream err;
err << "LocalCoordinateSystem \"" << getFullName() << "\" contains bad Axis object for role \""
<< role << '"';
throw Base::RuntimeError(err.str().c_str());
}
App::Plane* LocalCoordinateSystem::getPlane(const char* role) const
{
App::DatumElement* feat = getDatumElement(role);
if (feat->isDerivedFrom(App::Plane::getClassTypeId())) {
return static_cast<App::Plane*>(feat);
}
std::stringstream err;
err << "LocalCoordinateSystem \"" << getFullName() << "\" contains bad Plane object for role \""
<< role << '"';
throw Base::RuntimeError(err.str().c_str());
}
App::Point* LocalCoordinateSystem::getPoint(const char* role) const
{
App::DatumElement* feat = getDatumElement(role);
if (feat->isDerivedFrom(App::Point::getClassTypeId())) {
return static_cast<App::Point*>(feat);
}
std::stringstream err;
err << "LocalCoordinateSystem \"" << getFullName() << "\" contains bad Point object for role \""
<< role << '"';
throw Base::RuntimeError(err.str().c_str());
}
bool LocalCoordinateSystem::hasObject(const DocumentObject* obj) const
{
const auto& features = OriginFeatures.getValues();
return std::find(features.begin(), features.end(), obj) != features.end();
}
short LocalCoordinateSystem::mustExecute() const
{
if (OriginFeatures.isTouched()) {
return 1;
}
return DocumentObject::mustExecute();
}
App::DocumentObjectExecReturn* LocalCoordinateSystem::execute()
{
try { // try to find all base axis and planes in the origin
for (const char* role : AxisRoles) {
App::Line* axis = getAxis(role);
assert(axis);
(void)axis;
}
for (const char* role : PlaneRoles) {
App::Plane* plane = getPlane(role);
assert(plane);
(void)plane;
}
}
catch (const Base::Exception& ex) {
setError();
return new App::DocumentObjectExecReturn(ex.what());
}
return DocumentObject::execute();
}
const std::vector<LocalCoordinateSystem::SetupData>& LocalCoordinateSystem::getSetupData()
{
static const std::vector<SetupData> setupData = {
// clang-format off
{App::Line::getClassTypeId(), AxisRoles[0], tr("X-axis"), Base::Rotation()},
{App::Line::getClassTypeId(), AxisRoles[1], tr("Y-axis"), Base::Rotation(Base::Vector3d(1, 1, 1), M_PI * 2 / 3)},
{App::Line::getClassTypeId(), AxisRoles[2], tr("Z-axis"), Base::Rotation(Base::Vector3d(1,-1, 1), M_PI * 2 / 3)},
{App::Plane::getClassTypeId(), PlaneRoles[0], tr("XY-plane"), Base::Rotation()},
{App::Plane::getClassTypeId(), PlaneRoles[1], tr("XZ-plane"), Base::Rotation(1.0, 0.0, 0.0, 1.0)},
{App::Plane::getClassTypeId(), PlaneRoles[2], tr("YZ-plane"), Base::Rotation(Base::Vector3d(1, 1, 1), M_PI * 2 / 3)},
{App::Point::getClassTypeId(), PointRoles[0], tr("Origin"), Base::Rotation()}
// clang-format on
};
return setupData;
}
DatumElement* LocalCoordinateSystem::createDatum(SetupData& data)
{
App::Document* doc = getDocument();
auto origins = doc->getObjectsOfType(App::Origin::getClassTypeId());
std::string objName = doc->getUniqueObjectName(data.role);
App::DocumentObject* featureObj = doc->addObject(data.type.getName(), objName.c_str());
auto originIt = std::find_if(origins.begin(), origins.end(), [this](DocumentObject* origin) {
assert(origin->isDerivedFrom(App::Origin::getClassTypeId()));
return static_cast<App::Origin*>(origin)->hasObject(this);
});
if (originIt == origins.end()) {
return nullptr;
assert(featureObj && featureObj->isDerivedFrom(App::DatumElement::getClassTypeId()));
QByteArray byteArray = data.label.toUtf8();
featureObj->Label.setValue(byteArray.constData());
auto* feature = static_cast<App::DatumElement*>(featureObj);
feature->Placement.setValue(Base::Placement(Base::Vector3d(), data.rot));
feature->Role.setValue(data.role);
feature->Placement.setStatus(Property::Hidden, true);
return feature;
}
LocalCoordinateSystem::SetupData LocalCoordinateSystem::getData(const char* role)
{
const auto& setupData = getSetupData();
for (auto data : setupData) {
if (std::strcmp(role, data.role) == 0) {
return data;
}
}
else {
assert((*originIt)->isDerivedFrom(App::Origin::getClassTypeId()));
return static_cast<App::Origin*>(*originIt);
return LocalCoordinateSystem::SetupData();
}
void LocalCoordinateSystem::setupObject()
{
std::vector<App::DocumentObject*> links;
const auto& setupData = getSetupData();
for (auto data : setupData) {
links.push_back(createDatum(data));
}
OriginFeatures.setValues(links);
}
void LocalCoordinateSystem::unsetupObject()
{
const auto& objsLnk = OriginFeatures.getValues();
// Copy to set to assert we won't call method more then one time for each object
std::set<App::DocumentObject*> objs(objsLnk.begin(), objsLnk.end());
// Remove all controlled objects
for (auto obj : objs) {
// Check that previous deletes didn't indirectly remove one of our objects
const auto& objsLnk = OriginFeatures.getValues();
if (std::find(objsLnk.begin(), objsLnk.end(), obj) != objsLnk.end()) {
if (!obj->isRemoving()) {
obj->getDocument()->removeObject(obj->getNameInDocument());
}
}
}
}
// ----------------------------------------------------------------------------
LocalCoordinateSystem::LCSExtension::LCSExtension(LocalCoordinateSystem* obj)
: obj(obj)
{
Group.setStatus(Property::Transient, true);
}
void LocalCoordinateSystem::LCSExtension::initExtension(ExtensionContainer* obj)
{
App::GroupExtension::initExtension(obj);
}
bool LocalCoordinateSystem::LCSExtension::extensionGetSubObject(DocumentObject*& ret,
const char* subname,
PyObject** pyobj,
Base::Matrix4D* mat,
bool,
int depth) const
{
if (!subname || subname[0] == '\0') {
return false;
}
// mapping of object name to role name
std::string name(subname);
for (int i = 0; i < 3; i++) {
if (name.rfind(LocalCoordinateSystem::AxisRoles[i], 0) == 0) {
name = LocalCoordinateSystem::AxisRoles[i];
break;
}
if (name.rfind(LocalCoordinateSystem::PlaneRoles[i], 0) == 0) {
name = LocalCoordinateSystem::PlaneRoles[i];
break;
}
}
if (name.rfind(LocalCoordinateSystem::PointRoles[0], 0) == 0) {
name = LocalCoordinateSystem::PointRoles[0];
}
try {
ret = obj->getDatumElement(name.c_str());
if (!ret) {
return false;
}
const char* dot = strchr(subname, '.');
if (dot) {
subname = dot + 1;
}
else {
subname = "";
}
ret = ret->getSubObject(subname, pyobj, mat, true, depth + 1);
return true;
}
catch (const Base::Exception& e) {
e.ReportException();
return false;
}
}

View File

@@ -1,5 +1,7 @@
/***************************************************************************
* Copyright (c) 2012 Jürgen Riegel <juergen.riegel@web.de> *
* Copyright (c) 2015 Stefan Tröger <stefantroeger@gmx.net> *
* Copyright (c) 2015 Alexander Golubev (Fat-Zer) <fatzer2@gmail.com> *
* Copyright (c) 2024 Ondsel (PL Boyer) <development@ondsel.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
@@ -24,29 +26,37 @@
#define DATUMS_H
#include "GeoFeature.h"
#include "GeoFeatureGroupExtension.h"
#include "QCoreApplication"
namespace Base
{
class Rotation;
}
namespace App
{
class LocalCoordinateSystem;
class Origin;
/** Plane Object
* Used to define planar support for all kind of operations in the document space
*/
class AppExport DatumElement: public App::GeoFeature
{
PROPERTY_HEADER_WITH_OVERRIDE(App::DatumElement);
public:
/// additional information about the feature usage (e.g. "BasePlane-XY" or "Axis-X" in a Origin)
/// additional information about the feature usage (e.g. "BasePlane-XY" or "Axis-X")
PropertyString Role;
/// Constructor
DatumElement();
DatumElement(bool hideRole = true);
~DatumElement() override;
/// Finds the origin object this plane belongs to
App::Origin* getOrigin();
App::LocalCoordinateSystem* getLCS();
bool getCameraAlignmentDirection(Base::Vector3d& direction, const char* subname) const override;
/// Returns true if this DatumElement is part of a App::Origin.
bool isOriginFeature();
};
class AppExport Plane: public App::DatumElement
@@ -71,6 +81,172 @@ public:
}
};
class AppExport Point: public App::DatumElement
{
PROPERTY_HEADER_WITH_OVERRIDE(App::DatumElement);
public:
const char* getViewProviderName() const override
{
return "Gui::ViewProviderPoint";
}
};
class AppExport LocalCoordinateSystem: public App::GeoFeature
{
PROPERTY_HEADER_WITH_OVERRIDE(App::LocalCoordinateSystem);
Q_DECLARE_TR_FUNCTIONS(App::LocalCoordinateSystem)
public:
/// Constructor
LocalCoordinateSystem();
~LocalCoordinateSystem() override;
/// returns the type name of the ViewProvider
const char* getViewProviderName() const override
{
return "Gui::ViewProviderOrigin";
}
bool getCameraAlignmentDirection(Base::Vector3d& direction, const char* subname) const override;
/** @name Axis and plane access
* This functions returns casted axis and planes objects and asserts they are set correctly
* otherwise Base::Exception is thrown.
*/
///@{
// returns origin point
App::Point* getOrigin() const
{
return getPoint(PointRoles[0]);
}
// returns X axis
App::Line* getX() const
{
return getAxis(AxisRoles[0]);
}
// returns Y axis
App::Line* getY() const
{
return getAxis(AxisRoles[1]);
}
// returns Z axis
App::Line* getZ() const
{
return getAxis(AxisRoles[2]);
}
// returns XY plane
App::Plane* getXY() const
{
return getPlane(PlaneRoles[0]);
}
// returns XZ plane
App::Plane* getXZ() const
{
return getPlane(PlaneRoles[1]);
}
// returns YZ plane
App::Plane* getYZ() const
{
return getPlane(PlaneRoles[2]);
}
/// Returns all axis objects to iterate on them
std::vector<App::Line*> axes() const
{
return {getX(), getY(), getZ()};
}
/// Returns all base planes objects to iterate on them
std::vector<App::Plane*> planes() const
{
return {getXY(), getXZ(), getYZ()};
}
/// Returns all controlled objects (both planes and axis) to iterate on them
std::vector<App::DatumElement*> baseObjects() const
{
return {getX(), getY(), getZ(), getXY(), getXZ(), getYZ(), getOrigin()};
}
/// Returns an axis by it's name
App::DatumElement* getDatumElement(const char* role) const;
/// Returns an axis by it's name
App::Line* getAxis(const char* role) const;
/// Returns an axis by it's name
App::Plane* getPlane(const char* role) const;
/// Returns a point by it's name
App::Point* getPoint(const char* role) const;
///@}
/// Returns true if the given object is part of the origin
bool hasObject(const DocumentObject* obj) const;
/// Returns true on changing DatumElement set
short mustExecute() const override;
/// Axis types
static constexpr const char* AxisRoles[3] = {"X_Axis", "Y_Axis", "Z_Axis"};
/// Baseplane types
static constexpr const char* PlaneRoles[3] = {"XY_Plane", "XZ_Plane", "YZ_Plane"};
/// Points types
static constexpr const char* PointRoles[1] = {"Origin"};
virtual bool isOrigin()
{
return false;
};
// Axis links
PropertyLinkList OriginFeatures;
protected:
/// Checks integrity of the LCS
App::DocumentObjectExecReturn* execute() override;
/// Creates all corresponding Axes and Planes objects for the LCS if they aren't linked yet
void setupObject() override;
/// Removes all planes and axis if they are still linked to the document
void unsetupObject() override;
private:
struct SetupData;
void setupDatumElement(App::PropertyLink& featProp, const SetupData& data);
class LCSExtension: public GeoFeatureGroupExtension
{
LocalCoordinateSystem* obj;
public:
explicit LCSExtension(LocalCoordinateSystem* obj);
void initExtension(ExtensionContainer* obj) override;
bool extensionGetSubObject(DocumentObject*& ret,
const char* subname,
PyObject**,
Base::Matrix4D*,
bool,
int) const override;
};
LCSExtension extension;
struct SetupData
{
Base::Type type;
const char* role = nullptr;
QString label;
Base::Rotation rot;
};
static const std::vector<SetupData>& getSetupData();
DatumElement* createDatum(SetupData& data);
SetupData getData(const char* role);
};
} // namespace App
#endif /* end of include guard: DATUMS_H */

View File

@@ -312,7 +312,10 @@ void Document::exportGraphviz(std::ostream& out) const
}
if (!sgraph) {
if (docObj->isDerivedFrom(DatumElement::getClassTypeId())) {
sgraph = GraphList[static_cast<DatumElement*>(docObj)->getOrigin()];
auto* lcs = static_cast<DatumElement*>(docObj)->getLCS();
if (lcs) {
sgraph = GraphList[lcs];
}
}
}
}

View File

@@ -23,240 +23,19 @@
#include "PreCompiled.h"
#ifndef _PreComp_
#include <string>
#endif
#include <App/Document.h>
#include <Base/Exception.h>
#include <Base/Placement.h>
#include "Origin.h"
#include "Datums.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
using namespace App;
PROPERTY_SOURCE(App::Origin, App::DocumentObject)
PROPERTY_SOURCE(App::Origin, App::LocalCoordinateSystem)
Origin::Origin()
: extension(this)
{
ADD_PROPERTY_TYPE(OriginFeatures,
(nullptr),
0,
App::Prop_Hidden,
"Axis and baseplanes controlled by the origin");
setStatus(App::NoAutoExpand, true);
extension.initExtension(this);
// App::Origin is a LCS for which placement is fixed to identity.
Placement.setStatus(Property::Hidden, true);
}
Origin::~Origin() = default;
App::DatumElement* Origin::getOriginFeature(const char* role) const
{
const auto& features = OriginFeatures.getValues();
auto featIt = std::find_if(features.begin(), features.end(), [role](App::DocumentObject* obj) {
return obj->isDerivedFrom(App::DatumElement::getClassTypeId())
&& strcmp(static_cast<App::DatumElement*>(obj)->Role.getValue(), role) == 0;
});
if (featIt != features.end()) {
return static_cast<App::DatumElement*>(*featIt);
}
else {
std::stringstream err;
err << "Origin \"" << getFullName() << "\" doesn't contain feature with role \"" << role
<< '"';
throw Base::RuntimeError(err.str().c_str());
}
}
App::Line* Origin::getAxis(const char* role) const
{
App::DatumElement* feat = getOriginFeature(role);
if (feat->isDerivedFrom(App::Line::getClassTypeId())) {
return static_cast<App::Line*>(feat);
}
else {
std::stringstream err;
err << "Origin \"" << getFullName() << "\" contains bad Axis object for role \"" << role
<< '"';
throw Base::RuntimeError(err.str().c_str());
}
}
App::Plane* Origin::getPlane(const char* role) const
{
App::DatumElement* feat = getOriginFeature(role);
if (feat->isDerivedFrom(App::Plane::getClassTypeId())) {
return static_cast<App::Plane*>(feat);
}
else {
std::stringstream err;
err << "Origin \"" << getFullName() << "\" contains bad Plane object for role \"" << role
<< '"';
throw Base::RuntimeError(err.str().c_str());
}
}
bool Origin::hasObject(const DocumentObject* obj) const
{
const auto& features = OriginFeatures.getValues();
return std::find(features.begin(), features.end(), obj) != features.end();
}
short Origin::mustExecute() const
{
if (OriginFeatures.isTouched()) {
return 1;
}
else {
return DocumentObject::mustExecute();
}
}
App::DocumentObjectExecReturn* Origin::execute()
{
try { // try to find all base axis and planes in the origin
for (const char* role : AxisRoles) {
App::Line* axis = getAxis(role);
assert(axis);
(void)axis;
}
for (const char* role : PlaneRoles) {
App::Plane* plane = getPlane(role);
assert(plane);
(void)plane;
}
}
catch (const Base::Exception& ex) {
setError();
return new App::DocumentObjectExecReturn(ex.what());
}
return DocumentObject::execute();
}
void Origin::setupObject()
{
const static struct
{
const Base::Type type;
const char* role;
const QString label;
Base::Rotation rot;
} setupData[] = {
// clang-format off
{App::Line::getClassTypeId(), AxisRoles[0], tr("X-axis"), Base::Rotation()},
{App::Line::getClassTypeId(), AxisRoles[1], tr("Y-axis"), Base::Rotation(Base::Vector3d(1,1,1), M_PI*2/3)},
{App::Line::getClassTypeId(), AxisRoles[2], tr("Z-axis"), Base::Rotation(Base::Vector3d(1,-1,1), M_PI*2/3)},
{App::Plane::getClassTypeId(), PlaneRoles[0], tr("XY-plane"), Base::Rotation()},
{App::Plane::getClassTypeId(), PlaneRoles[1], tr("XZ-plane"), Base::Rotation(1.0, 0.0, 0.0, 1.0 )},
{App::Plane::getClassTypeId(), PlaneRoles[2], tr("YZ-plane"), Base::Rotation(Base::Vector3d(1,1,1), M_PI*2/3)}
// clang-format on
};
App::Document* doc = getDocument();
std::vector<App::DocumentObject*> links;
for (auto data : setupData) {
std::string objName = doc->getUniqueObjectName(data.role);
App::DocumentObject* featureObj = doc->addObject(data.type.getName(), objName.c_str());
assert(featureObj && featureObj->isDerivedFrom(App::DatumElement::getClassTypeId()));
QByteArray byteArray = data.label.toUtf8();
featureObj->Label.setValue(byteArray.constData());
App::DatumElement* feature = static_cast<App::DatumElement*>(featureObj);
feature->Placement.setValue(Base::Placement(Base::Vector3d(), data.rot));
feature->Role.setValue(data.role);
links.push_back(feature);
}
OriginFeatures.setValues(links);
}
void Origin::unsetupObject()
{
const auto& objsLnk = OriginFeatures.getValues();
// Copy to set to assert we won't call methode more then one time for each object
std::set<App::DocumentObject*> objs(objsLnk.begin(), objsLnk.end());
// Remove all controlled objects
for (auto obj : objs) {
// Check that previous deletes wasn't inderectly removed one of our objects
const auto& objsLnk = OriginFeatures.getValues();
if (std::find(objsLnk.begin(), objsLnk.end(), obj) != objsLnk.end()) {
if (!obj->isRemoving()) {
obj->getDocument()->removeObject(obj->getNameInDocument());
}
}
}
}
// ----------------------------------------------------------------------------
Origin::OriginExtension::OriginExtension(Origin* obj)
: obj(obj)
{
Group.setStatus(Property::Transient, true);
}
void Origin::OriginExtension::initExtension(ExtensionContainer* obj)
{
App::GroupExtension::initExtension(obj);
}
bool Origin::OriginExtension::extensionGetSubObject(DocumentObject*& ret,
const char* subname,
PyObject** pyobj,
Base::Matrix4D* mat,
bool,
int depth) const
{
if (!subname || subname[0] == '\0') {
return false;
}
// mapping of object name to role name
std::string name(subname);
for (int i = 0; i < 3; i++) {
if (name.rfind(Origin::AxisRoles[i], 0) == 0) {
name = Origin::AxisRoles[i];
break;
}
if (name.rfind(Origin::PlaneRoles[i], 0) == 0) {
name = Origin::PlaneRoles[i];
break;
}
}
try {
ret = obj->getOriginFeature(name.c_str());
if (!ret) {
return false;
}
const char* dot = strchr(subname, '.');
if (dot) {
subname = dot + 1;
}
else {
subname = "";
}
ret = ret->getSubObject(subname, pyobj, mat, true, depth + 1);
return true;
}
catch (const Base::Exception& e) {
e.ReportException();
return false;
}
}

View File

@@ -26,16 +26,13 @@
#define APP_Origin_H
#include "Datums.h"
#include "GeoFeatureGroupExtension.h"
#include "QCoreApplication"
namespace App
{
/** Base class of all geometric document objects.
*/
class AppExport Origin: public App::DocumentObject
class AppExport Origin: public App::LocalCoordinateSystem
{
PROPERTY_HEADER_WITH_OVERRIDE(App::Origin);
Q_DECLARE_TR_FUNCTIONS(App::Origin)
@@ -51,116 +48,10 @@ public:
return "Gui::ViewProviderOrigin";
}
/** @name Axis and plane access
* This functions returns casted axis and planes objects and asserts they are set correctly
* otherwise Base::Exception is thrown.
*/
///@{
// returns X axis
App::Line* getX() const
bool isOrigin() override
{
return getAxis(AxisRoles[0]);
}
// returns Y axis
App::Line* getY() const
{
return getAxis(AxisRoles[1]);
}
// returns Z axis
App::Line* getZ() const
{
return getAxis(AxisRoles[2]);
}
// returns XY plane
App::Plane* getXY() const
{
return getPlane(PlaneRoles[0]);
}
// returns XZ plane
App::Plane* getXZ() const
{
return getPlane(PlaneRoles[1]);
}
// returns YZ plane
App::Plane* getYZ() const
{
return getPlane(PlaneRoles[2]);
}
/// Returns all axis objects to iterate on them
std::vector<App::Line*> axes() const
{
return {getX(), getY(), getZ()};
}
/// Returns all base planes objects to iterate on them
std::vector<App::Plane*> planes() const
{
return {getXY(), getXZ(), getYZ()};
}
/// Returns all controlled objects (both planes and axis) to iterate on them
std::vector<App::DatumElement*> baseObjects() const
{
return {getX(), getY(), getZ(), getXY(), getXZ(), getYZ()};
}
/// Returns an axis by it's name
App::DatumElement* getOriginFeature(const char* role) const;
/// Returns an axis by it's name
App::Line* getAxis(const char* role) const;
/// Returns an axis by it's name
App::Plane* getPlane(const char* role) const;
///@}
/// Returns true if the given object is part of the origin
bool hasObject(const DocumentObject* obj) const;
/// Returns the default bounding box of the origin (use this if you confused what should be s )
// TODO Delete me if not really needed (2015-09-01, Fat-Zer)
static Base::BoundBox3d defaultBoundBox();
/// Returns true on changing OriginFeature set
short mustExecute() const override;
/// Axis types
static constexpr const char* AxisRoles[3] = {"X_Axis", "Y_Axis", "Z_Axis"};
/// Baseplane types
static constexpr const char* PlaneRoles[3] = {"XY_Plane", "XZ_Plane", "YZ_Plane"};
// Axis links
PropertyLinkList OriginFeatures;
protected:
/// Checks integrity of the Origin
App::DocumentObjectExecReturn* execute() override;
/// Creates all corresponding Axes and Planes objects for the origin if they aren't linked yet
void setupObject() override;
/// Removes all planes and axis if they are still linked to the document
void unsetupObject() override;
private:
struct SetupData;
void setupOriginFeature(App::PropertyLink& featProp, const SetupData& data);
class OriginExtension: public GeoFeatureGroupExtension
{
Origin* obj;
public:
explicit OriginExtension(Origin* obj);
void initExtension(ExtensionContainer* obj) override;
bool extensionGetSubObject(DocumentObject*& ret,
const char* subname,
PyObject**,
Base::Matrix4D*,
bool,
int) const override;
return true;
};
OriginExtension extension;
};
} // namespace App

View File

@@ -121,7 +121,8 @@ App::DocumentObject* OriginGroupExtension::getGroupOfObject(const DocumentObject
if (o->hasExtension(App::OriginGroupExtension::getExtensionClassTypeId())) {
return o;
}
else if (isOriginFeature && o->isDerivedFrom(App::Origin::getClassTypeId())) {
else if (isOriginFeature
&& o->isDerivedFrom(App::LocalCoordinateSystem::getClassTypeId())) {
auto result = getGroupOfObject(o);
if (result) {
return result;
@@ -221,16 +222,24 @@ void OriginGroupExtension::relinkToOrigin(App::DocumentObject* obj)
std::vector<App::DocumentObject*> result;
std::vector<App::Property*> list;
obj->getPropertyList(list);
auto isOriginFeature = [](App::DocumentObject* obj) -> bool {
// Check if the object is a DatumElement
if (auto* datumElement = dynamic_cast<App::DatumElement*>(obj)) {
// Check if the DatumElement is an origin
return datumElement->isOriginFeature();
}
return false;
};
for (App::Property* prop : list) {
if (prop->isDerivedFrom<App::PropertyLink>()) {
auto p = static_cast<App::PropertyLink*>(prop);
if (!p->getValue()
|| !p->getValue()->isDerivedFrom(App::DatumElement::getClassTypeId())) {
if (!p->getValue() || !isOriginFeature(p->getValue())) {
continue;
}
p->setValue(getOrigin()->getOriginFeature(
p->setValue(getOrigin()->getDatumElement(
static_cast<DatumElement*>(p->getValue())->Role.getValue()));
}
else if (prop->isDerivedFrom<App::PropertyLinkList>()) {
@@ -239,11 +248,11 @@ void OriginGroupExtension::relinkToOrigin(App::DocumentObject* obj)
std::vector<App::DocumentObject*> result;
bool changed = false;
for (App::DocumentObject* o : vec) {
if (!o || !o->isDerivedFrom(App::DatumElement::getClassTypeId())) {
if (!isOriginFeature(o)) {
result.push_back(o);
}
else {
result.push_back(getOrigin()->getOriginFeature(
result.push_back(getOrigin()->getDatumElement(
static_cast<DatumElement*>(o)->Role.getValue()));
changed = true;
}
@@ -254,13 +263,12 @@ void OriginGroupExtension::relinkToOrigin(App::DocumentObject* obj)
}
else if (prop->isDerivedFrom<App::PropertyLinkSub>()) {
auto p = static_cast<App::PropertyLinkSub*>(prop);
if (!p->getValue()
|| !p->getValue()->isDerivedFrom(App::DatumElement::getClassTypeId())) {
if (!p->getValue() || !isOriginFeature(p->getValue())) {
continue;
}
std::vector<std::string> subValues = p->getSubValues();
p->setValue(getOrigin()->getOriginFeature(
p->setValue(getOrigin()->getDatumElement(
static_cast<DatumElement*>(p->getValue())->Role.getValue()),
subValues);
}
@@ -269,8 +277,8 @@ void OriginGroupExtension::relinkToOrigin(App::DocumentObject* obj)
auto vec = p->getSubListValues();
bool changed = false;
for (auto& v : vec) {
if (v.first && v.first->isDerivedFrom(App::DatumElement::getClassTypeId())) {
v.first = getOrigin()->getOriginFeature(
if (isOriginFeature(v.first)) {
v.first = getOrigin()->getDatumElement(
static_cast<DatumElement*>(v.first)->Role.getValue());
changed = true;
}