Files
create/src/App/PropertyGeo.cpp
2025-12-25 11:55:37 -06:00

1350 lines
43 KiB
C++

// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include <Base/MatrixPy.h>
#include <Base/PlacementPy.h>
#include <Base/Reader.h>
#include <Base/Quantity.h>
#include <Base/QuantityPy.h>
#include <Base/Rotation.h>
#include <Base/RotationPy.h>
#include <Base/Stream.h>
#include <Base/Tools.h>
#include <Base/VectorPy.h>
#include <Base/Writer.h>
#include "ComplexGeoData.h"
#include "Document.h"
#include "PropertyGeo.h"
#include "Placement.h"
#include "ObjectIdentifier.h"
using namespace App;
using namespace Base;
using namespace std;
//**************************************************************************
//**************************************************************************
// PropertyVector
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyVector, App::Property)
//**************************************************************************
// Construction/Destruction
PropertyVector::PropertyVector() = default;
PropertyVector::~PropertyVector() = default;
//**************************************************************************
// Base class implementer
void PropertyVector::setValue(const Base::Vector3d& vec)
{
aboutToSetValue();
_cVec = vec;
hasSetValue();
}
void PropertyVector::setValue(double x, double y, double z)
{
aboutToSetValue();
_cVec.Set(x, y, z);
hasSetValue();
}
const Base::Vector3d& PropertyVector::getValue() const
{
return _cVec;
}
PyObject* PropertyVector::getPyObject()
{
return new Base::VectorPy(_cVec);
}
void PropertyVector::setPyObject(PyObject* value)
{
if (PyObject_TypeCheck(value, &(Base::VectorPy::Type))) {
Base::VectorPy* pcObject = static_cast<Base::VectorPy*>(value);
Base::Vector3d* val = pcObject->getVectorPtr();
setValue(*val);
}
else if (PyTuple_Check(value) && PyTuple_Size(value) == 3) {
PyObject* item {};
Base::Vector3d cVec;
// x
item = PyTuple_GetItem(value, 0);
if (PyFloat_Check(item)) {
cVec.x = PyFloat_AsDouble(item);
}
else if (PyLong_Check(item)) {
cVec.x = (double)PyLong_AsLong(item);
}
else {
throw Base::TypeError("Not allowed type used in tuple (float expected)...");
}
// y
item = PyTuple_GetItem(value, 1);
if (PyFloat_Check(item)) {
cVec.y = PyFloat_AsDouble(item);
}
else if (PyLong_Check(item)) {
cVec.y = (double)PyLong_AsLong(item);
}
else {
throw Base::TypeError("Not allowed type used in tuple (float expected)...");
}
// z
item = PyTuple_GetItem(value, 2);
if (PyFloat_Check(item)) {
cVec.z = PyFloat_AsDouble(item);
}
else if (PyLong_Check(item)) {
cVec.z = (double)PyLong_AsLong(item);
}
else {
throw Base::TypeError("Not allowed type used in tuple (float expected)...");
}
setValue(cVec);
}
else {
std::string error = std::string("type must be 'Vector' or tuple of three floats, not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
}
void PropertyVector::Save(Base::Writer& writer) const
{
// clang-format off
writer.Stream() << writer.ind()
<< "<PropertyVector"
<< " valueX=\"" << _cVec.x << "\""
<< " valueY=\"" << _cVec.y << "\""
<< " valueZ=\"" << _cVec.z << "\""
<< "/>\n";
// clang-format on
}
void PropertyVector::Restore(Base::XMLReader& reader)
{
// read my Element
reader.readElement("PropertyVector");
// get the value of my Attribute
aboutToSetValue();
_cVec.x = reader.getAttribute<double>("valueX");
_cVec.y = reader.getAttribute<double>("valueY");
_cVec.z = reader.getAttribute<double>("valueZ");
hasSetValue();
}
Property* PropertyVector::Copy() const
{
PropertyVector* p = new PropertyVector();
p->_cVec = _cVec;
return p;
}
void PropertyVector::Paste(const Property& from)
{
aboutToSetValue();
_cVec = dynamic_cast<const PropertyVector&>(from)._cVec;
hasSetValue();
}
void PropertyVector::getPaths(std::vector<ObjectIdentifier>& paths) const
{
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("x")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("y")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("z")));
}
const boost::any PropertyVector::getPathValue(const ObjectIdentifier& path) const
{
Base::Unit unit = getUnit();
if (unit != Unit::One) {
std::string p = path.getSubPathStr();
if (p == ".x" || p == ".y" || p == ".z") {
// Convert double to quantity
return Base::Quantity(boost::any_cast<double>(Property::getPathValue(path)), unit);
}
}
return Property::getPathValue(path);
}
bool PropertyVector::getPyPathValue(const ObjectIdentifier& path, Py::Object& res) const
{
Base::Unit unit = getUnit();
if (unit == Unit::One) {
return false;
}
std::string p = path.getSubPathStr();
if (p == ".x") {
res = Py::asObject(new QuantityPy(new Quantity(getValue().x, unit)));
}
else if (p == ".y") {
res = Py::asObject(new QuantityPy(new Quantity(getValue().y, unit)));
}
else if (p == ".z") {
res = Py::asObject(new QuantityPy(new Quantity(getValue().z, unit)));
}
else {
return false;
}
return true;
}
//**************************************************************************
// PropertyVectorDistance
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyVectorDistance, App::PropertyVector)
//**************************************************************************
// Construction/Destruction
PropertyVectorDistance::PropertyVectorDistance() = default;
PropertyVectorDistance::~PropertyVectorDistance() = default;
//**************************************************************************
// PropertyPosition
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyPosition, App::PropertyVector)
//**************************************************************************
// Construction/Destruction
PropertyPosition::PropertyPosition() = default;
PropertyPosition::~PropertyPosition() = default;
//**************************************************************************
// PropertyPosition
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyDirection, App::PropertyVector)
//**************************************************************************
// Construction/Destruction
PropertyDirection::PropertyDirection() = default;
PropertyDirection::~PropertyDirection() = default;
//**************************************************************************
// PropertyVectorList
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyVectorList, App::PropertyLists)
//**************************************************************************
// Construction/Destruction
PropertyVectorList::PropertyVectorList() = default;
PropertyVectorList::~PropertyVectorList() = default;
//**************************************************************************
// Base class implementer
void PropertyVectorList::setValue(double x, double y, double z)
{
setValue(Base::Vector3d(x, y, z));
}
PyObject* PropertyVectorList::getPyObject()
{
PyObject* list = PyList_New(getSize());
for (int i = 0; i < getSize(); i++) {
PyList_SetItem(list, i, new VectorPy(_lValueList[i]));
}
return list;
}
Base::Vector3d PropertyVectorList::getPyValue(PyObject* item) const
{
PropertyVector val;
val.setPyObject(item);
return val.getValue();
}
void PropertyVectorList::Save(Base::Writer& writer) const
{
if (!writer.isForceXML()) {
writer.Stream() << writer.ind() << "<VectorList file=\"" << writer.addFile(getName(), this)
<< "\"/>" << std::endl;
}
}
void PropertyVectorList::Restore(Base::XMLReader& reader)
{
reader.readElement("VectorList");
std::string file(reader.getAttribute<const char*>("file"));
if (!file.empty()) {
// initiate a file read
reader.addFile(file.c_str(), this);
}
}
void PropertyVectorList::SaveDocFile(Base::Writer& writer) const
{
Base::OutputStream str(writer.Stream());
uint32_t uCt = (uint32_t)getSize();
str << uCt;
if (!isSinglePrecision()) {
for (const auto& it : _lValueList) {
str << it.x << it.y << it.z;
}
}
else {
for (const auto& it : _lValueList) {
float x = (float)it.x;
float y = (float)it.y;
float z = (float)it.z;
str << x << y << z;
}
}
}
void PropertyVectorList::RestoreDocFile(Base::Reader& reader)
{
Base::InputStream str(reader);
uint32_t uCt = 0;
str >> uCt;
std::vector<Base::Vector3d> values(uCt);
if (!isSinglePrecision()) {
for (auto& it : values) {
str >> it.x >> it.y >> it.z;
}
}
else {
Base::Vector3f vec;
for (auto& it : values) {
str >> vec.x >> vec.y >> vec.z;
it.Set(vec.x, vec.y, vec.z);
}
}
setValues(values);
}
Property* PropertyVectorList::Copy() const
{
PropertyVectorList* p = new PropertyVectorList();
p->_lValueList = _lValueList;
return p;
}
void PropertyVectorList::Paste(const Property& from)
{
setValues(dynamic_cast<const PropertyVectorList&>(from)._lValueList);
}
unsigned int PropertyVectorList::getMemSize() const
{
return static_cast<unsigned int>(_lValueList.size() * sizeof(Base::Vector3d));
}
//**************************************************************************
//**************************************************************************
// PropertyMatrix
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyMatrix, App::Property)
//**************************************************************************
// Construction/Destruction
PropertyMatrix::PropertyMatrix() = default;
PropertyMatrix::~PropertyMatrix() = default;
//**************************************************************************
// Base class implementer
void PropertyMatrix::setValue(const Base::Matrix4D& mat)
{
aboutToSetValue();
_cMat = mat;
hasSetValue();
}
const Base::Matrix4D& PropertyMatrix::getValue() const
{
return _cMat;
}
PyObject* PropertyMatrix::getPyObject()
{
return new Base::MatrixPy(_cMat);
}
void PropertyMatrix::setPyObject(PyObject* value)
{
if (PyObject_TypeCheck(value, &(Base::MatrixPy::Type))) {
Base::MatrixPy* pcObject = static_cast<Base::MatrixPy*>(value);
setValue(pcObject->value());
}
else if (PyTuple_Check(value) && PyTuple_Size(value) == 16) {
PyObject* item;
Base::Matrix4D cMatrix;
const int dim = 4;
for (int x = 0; x < dim; x++) {
for (int y = 0; y < dim; y++) {
item = PyTuple_GetItem(value, x + y * dim);
if (PyFloat_Check(item)) {
cMatrix[x][y] = PyFloat_AsDouble(item);
}
else if (PyLong_Check(item)) {
cMatrix[x][y] = (double)PyLong_AsLong(item);
}
else {
throw Base::TypeError(
"Not allowed type used in matrix tuple (a number expected)...");
}
}
}
setValue(cMatrix);
}
else {
std::string error = std::string("type must be 'Matrix' or tuple of 16 float or int, not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
}
void PropertyMatrix::Save(Base::Writer& writer) const
{
// clang-format off
writer.Stream() << writer.ind() << "<PropertyMatrix";
writer.Stream() << " a11=\"" << _cMat[0][0] << "\" a12=\"" << _cMat[0][1] << "\" a13=\"" << _cMat[0][2] << "\" a14=\"" << _cMat[0][3] << "\"";
writer.Stream() << " a21=\"" << _cMat[1][0] << "\" a22=\"" << _cMat[1][1] << "\" a23=\"" << _cMat[1][2] << "\" a24=\"" << _cMat[1][3] << "\"";
writer.Stream() << " a31=\"" << _cMat[2][0] << "\" a32=\"" << _cMat[2][1] << "\" a33=\"" << _cMat[2][2] << "\" a34=\"" << _cMat[2][3] << "\"";
writer.Stream() << " a41=\"" << _cMat[3][0] << "\" a42=\"" << _cMat[3][1] << "\" a43=\"" << _cMat[3][2] << "\" a44=\"" << _cMat[3][3] << "\"";
writer.Stream() <<"/>" << endl;
// clang-format on
}
void PropertyMatrix::Restore(Base::XMLReader& reader)
{
// read my Element
reader.readElement("PropertyMatrix");
// get the value of my Attribute
aboutToSetValue();
_cMat[0][0] = reader.getAttribute<double>("a11");
_cMat[0][1] = reader.getAttribute<double>("a12");
_cMat[0][2] = reader.getAttribute<double>("a13");
_cMat[0][3] = reader.getAttribute<double>("a14");
_cMat[1][0] = reader.getAttribute<double>("a21");
_cMat[1][1] = reader.getAttribute<double>("a22");
_cMat[1][2] = reader.getAttribute<double>("a23");
_cMat[1][3] = reader.getAttribute<double>("a24");
_cMat[2][0] = reader.getAttribute<double>("a31");
_cMat[2][1] = reader.getAttribute<double>("a32");
_cMat[2][2] = reader.getAttribute<double>("a33");
_cMat[2][3] = reader.getAttribute<double>("a34");
_cMat[3][0] = reader.getAttribute<double>("a41");
_cMat[3][1] = reader.getAttribute<double>("a42");
_cMat[3][2] = reader.getAttribute<double>("a43");
_cMat[3][3] = reader.getAttribute<double>("a44");
hasSetValue();
}
Property* PropertyMatrix::Copy() const
{
PropertyMatrix* p = new PropertyMatrix();
p->_cMat = _cMat;
return p;
}
void PropertyMatrix::Paste(const Property& from)
{
aboutToSetValue();
_cMat = dynamic_cast<const PropertyMatrix&>(from)._cMat;
hasSetValue();
}
//**************************************************************************
//**************************************************************************
// PropertyPlacement
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyPlacement, App::Property)
//**************************************************************************
// Construction/Destruction
PropertyPlacement::PropertyPlacement() = default;
PropertyPlacement::~PropertyPlacement() = default;
//**************************************************************************
// Base class implementer
void PropertyPlacement::setValue(const Base::Placement& pos)
{
aboutToSetValue();
_cPos = pos;
hasSetValue();
}
bool PropertyPlacement::setValueIfChanged(const Base::Placement& pos, double tol, double atol)
{
if (_cPos.getPosition().IsEqual(pos.getPosition(), tol)
&& _cPos.getRotation().isSame(pos.getRotation(), atol)) {
return false;
}
setValue(pos);
return true;
}
const Base::Placement& PropertyPlacement::getValue() const
{
return _cPos;
}
void PropertyPlacement::getPaths(std::vector<ObjectIdentifier>& paths) const
{
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Base"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("x")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Base"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("y")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Base"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("z")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Rotation"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Angle")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Rotation"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Axis"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("x")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Rotation"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Axis"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("y")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Rotation"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Axis"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("z")));
}
namespace
{
double toDouble(const boost::any& value)
{
double avalue {};
if (value.type() == typeid(Base::Quantity)) {
avalue = boost::any_cast<Base::Quantity>(value).getValue();
}
else if (value.type() == typeid(double)) {
avalue = boost::any_cast<double>(value);
}
else if (value.type() == typeid(int)) {
avalue = boost::any_cast<int>(value);
}
else if (value.type() == typeid(unsigned int)) {
avalue = boost::any_cast<unsigned int>(value);
}
else if (value.type() == typeid(short)) {
avalue = boost::any_cast<short>(value);
}
else if (value.type() == typeid(unsigned short)) {
avalue = boost::any_cast<unsigned short>(value);
}
else if (value.type() == typeid(long)) {
avalue = boost::any_cast<long>(value);
}
else if (value.type() == typeid(unsigned long)) {
avalue = boost::any_cast<unsigned long>(value);
}
else {
throw std::bad_cast();
}
return avalue;
}
} // namespace
void PropertyPlacement::setPathValue(const ObjectIdentifier& path, const boost::any& value)
{
auto updateAxis = [this](int index, double coord) {
Base::Vector3d axis;
double angle;
Base::Vector3d base = _cPos.getPosition();
Base::Rotation rot = _cPos.getRotation();
rot.getRawValue(axis, angle);
axis[index] = coord;
rot.setValue(axis, angle);
Base::Placement plm(base, rot);
setValue(plm);
};
auto updateYawPitchRoll = [this](int index, double angle) {
Base::Vector3d base = _cPos.getPosition();
Base::Rotation rot = _cPos.getRotation();
double yaw, pitch, roll;
rot.getYawPitchRoll(yaw, pitch, roll);
if (index == 0) {
if (angle < -180.0 || angle > 180.0) {
throw Base::ValueError("Yaw angle is out of range [-180, +180]");
}
yaw = angle;
}
else if (index == 1) {
if (angle < -90.0 || angle > 90.0) {
throw Base::ValueError("Pitch angle is out of range [-90, +90]");
}
pitch = angle;
}
else if (index == 2) {
if (angle < -180.0 || angle > 180.0) {
throw Base::ValueError("Roll angle is out of range [-180, +180]");
}
roll = angle;
}
rot.setYawPitchRoll(yaw, pitch, roll);
Base::Placement plm(base, rot);
setValue(plm);
};
std::string subpath = path.getSubPathStr();
if (subpath == ".Rotation.Angle") {
double avalue = toDouble(value);
Property::setPathValue(path, Base::toRadians(avalue));
}
else if (subpath == ".Rotation.Axis.x") {
updateAxis(0, toDouble(value));
}
else if (subpath == ".Rotation.Axis.y") {
updateAxis(1, toDouble(value));
}
else if (subpath == ".Rotation.Axis.z") {
updateAxis(2, toDouble(value));
}
else if (subpath == ".Rotation.Yaw") {
updateYawPitchRoll(0, toDouble(value));
}
else if (subpath == ".Rotation.Pitch") {
updateYawPitchRoll(1, toDouble(value));
}
else if (subpath == ".Rotation.Roll") {
updateYawPitchRoll(2, toDouble(value));
}
else {
Property::setPathValue(path, value);
}
}
const boost::any PropertyPlacement::getPathValue(const ObjectIdentifier& path) const
{
auto getAxis = [](const Base::Placement& plm) {
Base::Vector3d axis;
double angle;
const Base::Rotation& rot = plm.getRotation();
rot.getRawValue(axis, angle);
return axis;
};
auto getYawPitchRoll = [](const Base::Placement& plm) {
Base::Vector3d ypr;
const Base::Rotation& rot = plm.getRotation();
rot.getYawPitchRoll(ypr.x, ypr.y, ypr.z);
return ypr;
};
std::string p = path.getSubPathStr();
if (p == ".Rotation.Angle") {
// Convert angle to degrees
return Base::Quantity(
Base::toDegrees(boost::any_cast<double>(Property::getPathValue(path))),
Unit::Angle);
}
else if (p == ".Base.x" || p == ".Base.y" || p == ".Base.z") {
// Convert double to quantity
return Base::Quantity(boost::any_cast<double>(Property::getPathValue(path)), Unit::Length);
}
else if (p == ".Rotation.Axis.x") {
return getAxis(_cPos).x;
}
else if (p == ".Rotation.Axis.y") {
return getAxis(_cPos).y;
}
else if (p == ".Rotation.Axis.z") {
return getAxis(_cPos).z;
}
else if (p == ".Rotation.Yaw") {
return getYawPitchRoll(_cPos).x;
}
else if (p == ".Rotation.Pitch") {
return getYawPitchRoll(_cPos).y;
}
else if (p == ".Rotation.Roll") {
return getYawPitchRoll(_cPos).z;
}
else {
return Property::getPathValue(path);
}
}
bool PropertyPlacement::getPyPathValue(const ObjectIdentifier& path, Py::Object& res) const
{
auto getAxis = [](const Base::Placement& plm) {
Base::Vector3d axis;
double angle;
const Base::Rotation& rot = plm.getRotation();
rot.getRawValue(axis, angle);
return axis;
};
auto getYawPitchRoll = [](const Base::Placement& plm) {
Base::Vector3d ypr;
const Base::Rotation& rot = plm.getRotation();
rot.getYawPitchRoll(ypr.x, ypr.y, ypr.z);
return ypr;
};
std::string p = path.getSubPathStr();
if (p == ".Rotation.Angle") {
Base::Vector3d axis;
double angle;
_cPos.getRotation().getValue(axis, angle);
res = Py::asObject(new QuantityPy(new Quantity(Base::toDegrees(angle), Unit::Angle)));
return true;
}
else if (p == ".Base.x") {
res = Py::asObject(new QuantityPy(new Quantity(_cPos.getPosition().x, Unit::Length)));
return true;
}
else if (p == ".Base.y") {
res = Py::asObject(new QuantityPy(new Quantity(_cPos.getPosition().y, Unit::Length)));
return true;
}
else if (p == ".Base.z") {
res = Py::asObject(new QuantityPy(new Quantity(_cPos.getPosition().z, Unit::Length)));
return true;
}
else if (p == ".Rotation.Axis.x") {
res = Py::Float(getAxis(_cPos).x);
return true;
}
else if (p == ".Rotation.Axis.y") {
res = Py::Float(getAxis(_cPos).y);
return true;
}
else if (p == ".Rotation.Axis.z") {
res = Py::Float(getAxis(_cPos).z);
return true;
}
else if (p == ".Rotation.Yaw") {
res = Py::Float(getYawPitchRoll(_cPos).x);
return true;
}
else if (p == ".Rotation.Pitch") {
res = Py::Float(getYawPitchRoll(_cPos).y);
return true;
}
else if (p == ".Rotation.Roll") {
res = Py::Float(getYawPitchRoll(_cPos).z);
return true;
}
return false;
}
PyObject* PropertyPlacement::getPyObject()
{
return new Base::PlacementPy(new Base::Placement(_cPos));
}
void PropertyPlacement::setPyObject(PyObject* value)
{
if (PyObject_TypeCheck(value, &(Base::MatrixPy::Type))) {
Base::MatrixPy* pcObject = static_cast<Base::MatrixPy*>(value);
Base::Matrix4D mat = pcObject->value();
Base::Placement p;
p.fromMatrix(mat);
setValue(p);
}
else if (PyObject_TypeCheck(value, &(Base::PlacementPy::Type))) {
setValue(*static_cast<Base::PlacementPy*>(value)->getPlacementPtr());
}
else {
std::string error = std::string("type must be 'Matrix' or 'Placement', not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
}
void PropertyPlacement::Save(Base::Writer& writer) const
{
// clang-format off
writer.Stream() << writer.ind() << "<PropertyPlacement";
writer.Stream() << " Px=\"" << _cPos.getPosition().x << "\""
<< " Py=\"" << _cPos.getPosition().y << "\""
<< " Pz=\"" << _cPos.getPosition().z << "\"";
writer.Stream() << " Q0=\"" << _cPos.getRotation()[0] << "\""
<< " Q1=\"" << _cPos.getRotation()[1] << "\""
<< " Q2=\"" << _cPos.getRotation()[2] << "\""
<< " Q3=\"" << _cPos.getRotation()[3] << "\"";
Vector3d axis;
double rfAngle {};
_cPos.getRotation().getRawValue(axis, rfAngle);
writer.Stream() << " A=\"" << rfAngle << "\""
<< " Ox=\"" << axis.x << "\""
<< " Oy=\"" << axis.y << "\""
<< " Oz=\"" << axis.z << "\"";
writer.Stream() << "/>" << std::endl;
// clang-format on
}
void PropertyPlacement::Restore(Base::XMLReader& reader)
{
// read my Element
reader.readElement("PropertyPlacement");
// get the value of my Attribute
aboutToSetValue();
if (reader.hasAttribute("A")) {
_cPos = Base::Placement(Vector3d(reader.getAttribute<double>("Px"),
reader.getAttribute<double>("Py"),
reader.getAttribute<double>("Pz")),
Rotation(Vector3d(reader.getAttribute<double>("Ox"),
reader.getAttribute<double>("Oy"),
reader.getAttribute<double>("Oz")),
reader.getAttribute<double>("A")));
}
else {
_cPos = Base::Placement(Vector3d(reader.getAttribute<double>("Px"),
reader.getAttribute<double>("Py"),
reader.getAttribute<double>("Pz")),
Rotation(reader.getAttribute<double>("Q0"),
reader.getAttribute<double>("Q1"),
reader.getAttribute<double>("Q2"),
reader.getAttribute<double>("Q3")));
}
hasSetValue();
}
Property* PropertyPlacement::Copy() const
{
PropertyPlacement* p = new PropertyPlacement();
p->_cPos = _cPos;
return p;
}
void PropertyPlacement::Paste(const Property& from)
{
aboutToSetValue();
_cPos = dynamic_cast<const PropertyPlacement&>(from)._cPos;
hasSetValue();
}
//**************************************************************************
// PropertyPlacementList
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyPlacementList, App::PropertyLists)
//**************************************************************************
// Construction/Destruction
PropertyPlacementList::PropertyPlacementList() = default;
PropertyPlacementList::~PropertyPlacementList() = default;
//**************************************************************************
// Base class implementer
PyObject* PropertyPlacementList::getPyObject()
{
PyObject* list = PyList_New(getSize());
for (int i = 0; i < getSize(); i++) {
PyList_SetItem(list, i, new Base::PlacementPy(new Base::Placement(_lValueList[i])));
}
return list;
}
Base::Placement PropertyPlacementList::getPyValue(PyObject* item) const
{
PropertyPlacement val;
val.setPyObject(item);
return val.getValue();
}
void PropertyPlacementList::Save(Base::Writer& writer) const
{
if (!writer.isForceXML()) {
writer.Stream() << writer.ind() << "<PlacementList file=\""
<< writer.addFile(getName(), this) << "\"/>" << std::endl;
}
}
void PropertyPlacementList::Restore(Base::XMLReader& reader)
{
reader.readElement("PlacementList");
std::string file(reader.getAttribute<const char*>("file"));
if (!file.empty()) {
// initiate a file read
reader.addFile(file.c_str(), this);
}
}
void PropertyPlacementList::SaveDocFile(Base::Writer& writer) const
{
Base::OutputStream str(writer.Stream());
uint32_t uCt = (uint32_t)getSize();
str << uCt;
if (!isSinglePrecision()) {
for (const auto& it : _lValueList) {
str << it.getPosition().x << it.getPosition().y << it.getPosition().z
<< it.getRotation()[0] << it.getRotation()[1] << it.getRotation()[2]
<< it.getRotation()[3];
}
}
else {
for (const auto& it : _lValueList) {
float x = (float)it.getPosition().x;
float y = (float)it.getPosition().y;
float z = (float)it.getPosition().z;
float q0 = (float)it.getRotation()[0];
float q1 = (float)it.getRotation()[1];
float q2 = (float)it.getRotation()[2];
float q3 = (float)it.getRotation()[3];
str << x << y << z << q0 << q1 << q2 << q3;
}
}
}
void PropertyPlacementList::RestoreDocFile(Base::Reader& reader)
{
Base::InputStream str(reader);
uint32_t uCt = 0;
str >> uCt;
std::vector<Base::Placement> values(uCt);
if (!isSinglePrecision()) {
for (auto& it : values) {
Base::Vector3d pos;
double q0, q1, q2, q3;
str >> pos.x >> pos.y >> pos.z >> q0 >> q1 >> q2 >> q3;
Base::Rotation rot(q0, q1, q2, q3);
it.setPosition(pos);
it.setRotation(rot);
}
}
else {
float x {}, y {}, z {};
float q0 {}, q1 {}, q2 {}, q3 {};
for (auto& it : values) {
str >> x >> y >> z >> q0 >> q1 >> q2 >> q3;
Base::Vector3d pos(x, y, z);
Base::Rotation rot(q0, q1, q2, q3);
it.setPosition(pos);
it.setRotation(rot);
}
}
setValues(values);
}
Property* PropertyPlacementList::Copy() const
{
PropertyPlacementList* p = new PropertyPlacementList();
p->_lValueList = _lValueList;
return p;
}
void PropertyPlacementList::Paste(const Property& from)
{
setValues(dynamic_cast<const PropertyPlacementList&>(from)._lValueList);
}
unsigned int PropertyPlacementList::getMemSize() const
{
return static_cast<unsigned int>(_lValueList.size() * sizeof(Base::Vector3d));
}
//**************************************************************************
//**************************************************************************
// PropertyPlacement
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyPlacementLink, App::PropertyLink)
//**************************************************************************
// Construction/Destruction
PropertyPlacementLink::PropertyPlacementLink() = default;
PropertyPlacementLink::~PropertyPlacementLink() = default;
App::Placement* PropertyPlacementLink::getPlacementObject() const
{
if (_pcLink->isDerivedFrom<App::Placement>()) {
return dynamic_cast<App::Placement*>(_pcLink);
}
else {
return nullptr;
}
}
//**************************************************************************
// Base class implementer
Property* PropertyPlacementLink::Copy() const
{
PropertyPlacementLink* p = new PropertyPlacementLink();
p->_pcLink = _pcLink;
return p;
}
void PropertyPlacementLink::Paste(const Property& from)
{
aboutToSetValue();
_pcLink = dynamic_cast<const PropertyPlacementLink&>(from)._pcLink;
hasSetValue();
}
//**************************************************************************
//**************************************************************************
// PropertyRotation
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyRotation, App::Property)
PropertyRotation::PropertyRotation() = default;
PropertyRotation::~PropertyRotation() = default;
void PropertyRotation::setValue(const Base::Rotation& rot)
{
aboutToSetValue();
_rot = rot;
hasSetValue();
}
bool PropertyRotation::setValueIfChanged(const Base::Rotation& rot, double atol)
{
if (_rot.isSame(rot, atol)) {
return false;
}
setValue(rot);
return true;
}
const Base::Rotation& PropertyRotation::getValue() const
{
return _rot;
}
void PropertyRotation::getPaths(std::vector<ObjectIdentifier>& paths) const
{
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Angle")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Axis"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("x")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Axis"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("y")));
paths.push_back(ObjectIdentifier(*this)
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Axis"))
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("z")));
}
void PropertyRotation::setPathValue(const ObjectIdentifier& path, const boost::any& value)
{
auto updateAxis = [this](int index, double coord) {
Base::Vector3d axis;
double angle;
_rot.getRawValue(axis, angle);
axis[index] = coord;
setValue(Base::Rotation {axis, angle});
};
std::string subpath = path.getSubPathStr();
if (subpath == ".Angle") {
double avalue = toDouble(value);
Property::setPathValue(path, Base::toRadians(avalue));
}
else if (subpath == ".Axis.x") {
updateAxis(0, toDouble(value));
}
else if (subpath == ".Axis.y") {
updateAxis(1, toDouble(value));
}
else if (subpath == ".Axis.z") {
updateAxis(2, toDouble(value));
}
else {
Property::setPathValue(path, value);
}
}
const boost::any PropertyRotation::getPathValue(const ObjectIdentifier& path) const
{
auto getAxis = [](const Base::Rotation& rot) {
Base::Vector3d axis;
double angle;
rot.getRawValue(axis, angle);
return axis;
};
std::string p = path.getSubPathStr();
if (p == ".Angle") {
// Convert angle to degrees
return Base::Quantity(
Base::toDegrees(boost::any_cast<double>(Property::getPathValue(path))),
Unit::Angle);
}
else if (p == ".Axis.x") {
return getAxis(_rot).x;
}
else if (p == ".Axis.y") {
return getAxis(_rot).y;
}
else if (p == ".Axis.z") {
return getAxis(_rot).z;
}
else {
return Property::getPathValue(path);
}
}
bool PropertyRotation::getPyPathValue(const ObjectIdentifier& path, Py::Object& res) const
{
auto getAxis = [](const Base::Rotation& rot) {
Base::Vector3d axis;
double angle;
rot.getRawValue(axis, angle);
return axis;
};
std::string p = path.getSubPathStr();
if (p == ".Angle") {
Base::Vector3d axis;
double angle;
_rot.getValue(axis, angle);
res = Py::asObject(new QuantityPy(new Quantity(Base::toDegrees(angle), Unit::Angle)));
return true;
}
else if (p == ".Axis.x") {
res = Py::Float(getAxis(_rot).x);
return true;
}
else if (p == ".Axis.y") {
res = Py::Float(getAxis(_rot).y);
return true;
}
else if (p == ".Axis.z") {
res = Py::Float(getAxis(_rot).z);
return true;
}
return false;
}
PyObject* PropertyRotation::getPyObject()
{
return new Base::RotationPy(new Base::Rotation(_rot));
}
void PropertyRotation::setPyObject(PyObject* value)
{
if (PyObject_TypeCheck(value, &(Base::MatrixPy::Type))) {
Base::MatrixPy* object = static_cast<Base::MatrixPy*>(value);
Base::Matrix4D mat = object->value();
Base::Rotation p;
p.setValue(mat);
setValue(p);
}
else if (PyObject_TypeCheck(value, &(Base::RotationPy::Type))) {
setValue(*static_cast<Base::RotationPy*>(value)->getRotationPtr());
}
else {
std::string error = std::string("type must be 'Matrix' or 'Rotation', not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
}
void PropertyRotation::Save(Base::Writer& writer) const
{
Vector3d axis;
double rfAngle {};
_rot.getRawValue(axis, rfAngle);
writer.Stream() << writer.ind() << "<PropertyRotation";
writer.Stream() << " A=\"" << rfAngle << "\""
<< " Ox=\"" << axis.x << "\""
<< " Oy=\"" << axis.y << "\""
<< " Oz=\"" << axis.z << "\""
<< "/>\n";
}
void PropertyRotation::Restore(Base::XMLReader& reader)
{
reader.readElement("PropertyRotation");
aboutToSetValue();
_rot = Rotation(Vector3d(reader.getAttribute<double>("Ox"),
reader.getAttribute<double>("Oy"),
reader.getAttribute<double>("Oz")),
reader.getAttribute<double>("A"));
hasSetValue();
}
Property* PropertyRotation::Copy() const
{
PropertyRotation* p = new PropertyRotation();
p->_rot = _rot;
return p;
}
void PropertyRotation::Paste(const Property& from)
{
aboutToSetValue();
_rot = dynamic_cast<const PropertyRotation&>(from)._rot;
hasSetValue();
}
// ------------------------------------------------------------
TYPESYSTEM_SOURCE_ABSTRACT(App::PropertyGeometry, App::Property)
PropertyGeometry::PropertyGeometry() = default;
PropertyGeometry::~PropertyGeometry() = default;
// ------------------------------------------------------------
TYPESYSTEM_SOURCE_ABSTRACT(App::PropertyComplexGeoData, App::PropertyGeometry)
PropertyComplexGeoData::PropertyComplexGeoData() = default;
PropertyComplexGeoData::~PropertyComplexGeoData() = default;
std::string PropertyComplexGeoData::getElementMapVersion(bool) const
{
auto data = getComplexData();
if (!data) {
return std::string();
}
auto owner = freecad_cast<DocumentObject*>(getContainer());
std::ostringstream ss;
if (owner && owner->getDocument() && owner->getDocument()->getStringHasher() == data->Hasher) {
ss << "1.";
}
else {
ss << "0.";
}
ss << data->getElementMapVersion();
return ss.str();
}
bool PropertyComplexGeoData::checkElementMapVersion(const char* ver) const
{
auto data = getComplexData();
if (!data) {
return false;
}
auto owner = freecad_cast<DocumentObject*>(getContainer());
std::ostringstream ss;
const char* prefix;
if (owner && owner->getDocument() && owner->getDocument()->getStringHasher() == data->Hasher) {
prefix = "1.";
}
else {
prefix = "0.";
}
if (!boost::starts_with(ver, prefix)) {
return true;
}
return data->checkElementMapVersion(ver + 2);
}
void PropertyComplexGeoData::afterRestore()
{
auto data = getComplexData();
if (data && data->isRestoreFailed()) {
data->resetRestoreFailure();
auto owner = freecad_cast<DocumentObject*>(getContainer());
if (owner && owner->getDocument()
&& !owner->getDocument()->testStatus(App::Document::PartialDoc)) {
owner->getDocument()->addRecomputeObject(owner);
}
}
PropertyGeometry::afterRestore();
}