FreeCAD / src /Mod /Part /App /AttachEnginePyImp.cpp
AbdulElahGwaith's picture
Upload folder using huggingface_hub
985c397 verified
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* Copyright (c) 2016 Viktor Titov (DeepSOIC) <vv.titov@gmail.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include <Standard_Failure.hxx>
#include <App/DocumentObjectPy.h>
#include <Base/PlacementPy.h>
#include "AttachEnginePy.h"
#include "AttachEnginePy.cpp"
#include "AttachExtensionPy.h"
#include "OCCError.h"
#include "TopoShapePy.h"
using namespace Attacher;
// returns a string which represents the object e.g. when printed in python
std::string AttachEnginePy::representation() const
{
return {"<Attacher::AttachEngine>"};
}
PyObject* AttachEnginePy::PyMake(struct _typeobject*, PyObject*, PyObject*)
{
// create a new instance of AttachEngine3D
return new AttachEnginePy(new AttachEngine3D);
}
// constructor method
int AttachEnginePy::PyInit(PyObject* args, PyObject* /*kwd*/)
{
PyObject* o;
if (PyArg_ParseTuple(args, "")) {
return 0;
}
PyErr_Clear();
if (PyArg_ParseTuple(args, "O!", &(AttachEnginePy::Type), &o)) {
AttachEngine* attacher = static_cast<AttachEnginePy*>(o)->getAttachEnginePtr();
AttachEngine* oldAttacher = this->getAttachEnginePtr();
this->_pcTwinPointer = attacher->copy();
delete oldAttacher;
return 0;
}
PyErr_Clear();
char* typeName;
if (PyArg_ParseTuple(args, "s", &typeName)) {
Base::Type t = Base::Type::fromName(typeName);
AttachEngine* pNewAttacher = nullptr;
if (t.isDerivedFrom(AttachEngine::getClassTypeId())) {
pNewAttacher = static_cast<Attacher::AttachEngine*>(
Base::Type::createInstanceByName(typeName)
);
}
if (!pNewAttacher) {
std::stringstream errMsg;
errMsg << "Object if this type is not derived from AttachEngine: " << typeName;
PyErr_SetString(Base::PyExc_FC_GeneralError, errMsg.str().c_str());
return -1;
}
AttachEngine* oldAttacher = this->getAttachEnginePtr();
this->_pcTwinPointer = pNewAttacher;
delete oldAttacher;
return 0;
}
PyErr_SetString(
PyExc_TypeError,
"Wrong set of constructor arguments. Can be: (), ('Attacher::AttachEngine3D'), "
"('Attacher::AttachEnginePlane'), ('Attacher::AttachEngineLine'), "
"('Attacher::AttachEnginePoint'), (other_attacher_instance)."
);
return -1;
}
Py::String AttachEnginePy::getAttacherType() const
{
return {std::string(this->getAttachEnginePtr()->getTypeId().getName())};
}
/**
* @brief macro ATTACHERPY_STDCATCH_ATTR: catch for exceptions in attribute
* code (re-throws the exception converted to Py::Exception). It is a helper
* to avoid repeating the same error handling code over and over again.
*/
#define ATTACHERPY_STDCATCH_ATTR \
catch (Standard_Failure & e) \
{ \
throw Py::Exception(Part::PartExceptionOCCError, e.GetMessageString()); \
} \
catch (Base::Exception & e) \
{ \
e.setPyException(); \
throw Py::Exception(); \
}
Py::String AttachEnginePy::getMode() const
{
try {
AttachEngine& attacher = *(this->getAttachEnginePtr());
return {attacher.getModeName(attacher.mapMode)};
}
ATTACHERPY_STDCATCH_ATTR;
}
void AttachEnginePy::setMode(Py::String arg)
{
try {
AttachEngine& attacher = *(this->getAttachEnginePtr());
std::string modeName = static_cast<std::string>(arg);
attacher.mapMode = attacher.getModeByName(modeName);
}
ATTACHERPY_STDCATCH_ATTR;
}
Py::Object AttachEnginePy::getReferences() const
{
try {
AttachEngine& attacher = *(this->getAttachEnginePtr());
Py::List ret;
int i = 0;
for (auto obj : attacher.getRefObjects()) {
ret.append(
Py::TupleN(Py::asObject(obj->getPyObject()), Py::String(attacher.subnames[i++]))
);
}
return ret;
}
ATTACHERPY_STDCATCH_ATTR;
}
void AttachEnginePy::setReferences(Py::Object arg)
{
try {
AttachEngine& attacher = *(this->getAttachEnginePtr());
App::PropertyLinkSubList references;
references.setPyObject(arg.ptr());
attacher.setReferences(references);
}
ATTACHERPY_STDCATCH_ATTR;
}
Py::Object AttachEnginePy::getAttachmentOffset() const
{
try {
AttachEngine& attacher = *(this->getAttachEnginePtr());
return Py::Object(new Base::PlacementPy(new Base::Placement(attacher.attachmentOffset)), true);
}
ATTACHERPY_STDCATCH_ATTR;
}
void AttachEnginePy::setAttachmentOffset(Py::Object arg)
{
try {
AttachEngine& attacher = *(this->getAttachEnginePtr());
if (PyObject_TypeCheck(arg.ptr(), &(Base::PlacementPy::Type))) {
const Base::PlacementPy* plmPy = static_cast<const Base::PlacementPy*>(arg.ptr());
attacher.attachmentOffset = *(plmPy->getPlacementPtr());
}
else {
std::string error = std::string("type must be 'Placement', not ");
error += arg.type().as_string();
throw Py::TypeError(error);
}
}
ATTACHERPY_STDCATCH_ATTR;
}
Py::Boolean AttachEnginePy::getReverse() const
{
try {
AttachEngine& attacher = *(this->getAttachEnginePtr());
return {attacher.mapReverse};
}
ATTACHERPY_STDCATCH_ATTR;
}
void AttachEnginePy::setReverse(Py::Boolean arg)
{
try {
AttachEngine& attacher = *(this->getAttachEnginePtr());
attacher.mapReverse = arg.isTrue();
}
ATTACHERPY_STDCATCH_ATTR;
}
Py::Float AttachEnginePy::getParameter() const
{
try {
AttachEngine& attacher = *(this->getAttachEnginePtr());
return Py::Float(attacher.attachParameter);
}
ATTACHERPY_STDCATCH_ATTR;
}
void AttachEnginePy::setParameter(Py::Float arg)
{
try {
AttachEngine& attacher = *(this->getAttachEnginePtr());
attacher.attachParameter = (double)arg;
}
ATTACHERPY_STDCATCH_ATTR;
}
Py::List AttachEnginePy::getCompleteModeList() const
{
try {
Py::List ret;
AttachEngine& attacher = *(this->getAttachEnginePtr());
for (int imode = 0; imode < mmDummy_NumberOfModes; imode++) {
ret.append(Py::String(attacher.getModeName(eMapMode(imode))));
}
return ret;
}
ATTACHERPY_STDCATCH_ATTR;
}
Py::List AttachEnginePy::getCompleteRefTypeList() const
{
try {
Py::List ret;
AttachEngine& attacher = *(this->getAttachEnginePtr());
for (int irt = 0; irt < rtDummy_numberOfShapeTypes; irt++) {
ret.append(Py::String(attacher.getRefTypeName(eRefType(irt))));
}
return ret;
}
ATTACHERPY_STDCATCH_ATTR;
}
Py::List AttachEnginePy::getImplementedModes() const
{
try {
Py::List ret;
AttachEngine& attacher = *(this->getAttachEnginePtr());
for (int imode = 0; imode < mmDummy_NumberOfModes; imode++) {
if (!attacher.modeRefTypes[imode].empty()) {
ret.append(Py::String(attacher.getModeName(eMapMode(imode))));
}
}
return ret;
}
ATTACHERPY_STDCATCH_ATTR;
}
/**
* @brief macro ATTACHERPY_STDCATCH_METH: catch for exceptions in method code
* (returns NULL if an exception is caught). It is a helper to avoid repeating
* the same error handling code over and over again.
*/
#define ATTACHERPY_STDCATCH_METH \
catch (Standard_Failure & e) \
{ \
PyErr_SetString(Part::PartExceptionOCCError, e.GetMessageString()); \
return NULL; \
} \
catch (Base::Exception & e) \
{ \
PyErr_SetString(Base::PyExc_FC_GeneralError, e.what()); \
return NULL; \
} \
catch (const Py::Exception&) \
{ \
return NULL; \
}
PyObject* AttachEnginePy::getModeInfo(PyObject* args)
{
char* modeName;
if (!PyArg_ParseTuple(args, "s", &modeName)) {
return nullptr;
}
try {
AttachEngine& attacher = *(this->getAttachEnginePtr());
eMapMode mmode = attacher.getModeByName(modeName);
Py::List pyListOfCombinations;
Py::List pyCombination;
refTypeStringList& listOfCombinations = attacher.modeRefTypes.at(mmode);
for (const refTypeString& combination : listOfCombinations) {
pyCombination = Py::List(combination.size());
for (std::size_t iref = 0; iref < combination.size(); iref++) {
pyCombination[iref] = Py::String(AttachEngine::getRefTypeName(combination[iref]));
}
pyListOfCombinations.append(pyCombination);
}
Py::Dict ret;
ret["ReferenceCombinations"] = pyListOfCombinations;
ret["ModeIndex"] = Py::Long(mmode);
try {
Py::Module module(PyImport_ImportModule("PartGui"), true);
if (module.isNull() || !module.hasAttr("AttachEngineResources")) {
// in v0.14+, the GUI module can be loaded in console mode (but doesn't have all its
// document methods)
throw Py::RuntimeError("Gui is not up"); // DeepSOIC: wanted to throw ImportError
// here, but it's not defined, so I don't
// know...
}
Py::Object submod(module.getAttr("AttachEngineResources"));
Py::Callable method(submod.getAttr("getModeStrings"));
Py::Tuple arg(2);
arg.setItem(0, Py::String(this->getAttachEnginePtr()->getTypeId().getName()));
arg.setItem(1, Py::Long(mmode));
Py::List strs = method.apply(arg);
assert(strs.size() == 2);
ret["UserFriendlyName"] = strs[0];
ret["BriefDocu"] = strs[1];
}
catch (Py::Exception& e) {
if (PyErr_ExceptionMatches(PyExc_ImportError)) {
// the GUI is not up.
Base::Console().warning(
"AttachEngine: Gui not up, so no gui-related entries in getModeInfo.\n"
);
e.clear();
}
else {
Base::Console().warning("AttachEngine.getModeInfo: error obtaining GUI strings\n");
e.clear();
}
}
catch (Base::Exception& e) {
Base::Console().warning("AttachEngine.getModeInfo: error obtaining GUI strings:");
Base::Console().warning(e.what());
Base::Console().warning("\n");
}
return Py::new_reference_to(ret);
}
ATTACHERPY_STDCATCH_METH;
}
PyObject* AttachEnginePy::getRefTypeOfShape(PyObject* args)
{
PyObject* pcObj;
if (!PyArg_ParseTuple(args, "O!", &(Part::TopoShapePy::Type), &pcObj)) {
return nullptr;
}
try {
TopoDS_Shape shape = static_cast<Part::TopoShapePy*>(pcObj)->getTopoShapePtr()->getShape();
eRefType rt = AttachEngine::getShapeType(shape);
return Py::new_reference_to(Py::String(AttachEngine::getRefTypeName(rt)));
}
ATTACHERPY_STDCATCH_METH;
}
PyObject* AttachEnginePy::isFittingRefType(PyObject* args)
{
char* type_shape_str;
char* type_need_str;
if (!PyArg_ParseTuple(args, "ss", &type_shape_str, &type_need_str)) {
return nullptr;
}
try {
eRefType type_shape = AttachEngine::getRefTypeByName(std::string(type_shape_str));
eRefType type_need = AttachEngine::getRefTypeByName(std::string(type_need_str));
bool result = AttachEngine::isShapeOfType(type_shape, type_need) > -1;
return Py::new_reference_to(Py::Boolean(result));
}
ATTACHERPY_STDCATCH_METH;
}
PyObject* AttachEnginePy::downgradeRefType(PyObject* args)
{
char* type_shape_str;
if (!PyArg_ParseTuple(args, "s", &type_shape_str)) {
return nullptr;
}
try {
eRefType type_shape = AttachEngine::getRefTypeByName(std::string(type_shape_str));
eRefType result = AttachEngine::downgradeType(type_shape);
return Py::new_reference_to(Py::String(AttachEngine::getRefTypeName(result)));
}
ATTACHERPY_STDCATCH_METH;
}
PyObject* AttachEnginePy::getRefTypeInfo(PyObject* args)
{
char* typeName;
if (!PyArg_ParseTuple(args, "s", &typeName)) {
return nullptr;
}
try {
AttachEngine& attacher = *(this->getAttachEnginePtr());
eRefType rt = attacher.getRefTypeByName(typeName);
Py::Dict ret;
ret["TypeIndex"] = Py::Long(rt);
ret["Rank"] = Py::Long(AttachEngine::getTypeRank(rt));
try {
Py::Module module(PyImport_ImportModule("PartGui"), true);
if (module.isNull() || !module.hasAttr("AttachEngineResources")) {
// in v0.14+, the GUI module can be loaded in console mode (but doesn't have all its
// document methods)
throw Py::RuntimeError("Gui is not up"); // DeepSOIC: wanted to throw ImportError
// here, but it's not defined, so I don't
// know...
}
Py::Object submod(module.getAttr("AttachEngineResources"));
Py::Callable method(submod.getAttr("getRefTypeUserFriendlyName"));
Py::Tuple arg(1);
arg.setItem(0, Py::Long(rt));
Py::String st = method.apply(arg);
ret["UserFriendlyName"] = st;
}
catch (Py::Exception& e) {
if (PyErr_ExceptionMatches(PyExc_ImportError)) {
// the GUI is not up.
Base::Console().warning(
"AttachEngine: Gui not up, so no gui-related entries in getModeInfo.\n"
);
e.clear();
}
else {
Base::Console().warning("AttachEngine.getRefTypeInfo: error obtaining GUI strings\n");
e.clear();
}
}
catch (Base::Exception& e) {
Base::Console().warning("AttachEngine.getRefTypeInfo: error obtaining GUI strings:");
Base::Console().warning(e.what());
Base::Console().warning("\n");
}
return Py::new_reference_to(ret);
}
ATTACHERPY_STDCATCH_METH;
}
PyObject* AttachEnginePy::copy(PyObject* args) const
{
if (!PyArg_ParseTuple(args, "")) {
return nullptr;
}
return new AttachEnginePy(this->getAttachEnginePtr()->copy());
}
PyObject* AttachEnginePy::calculateAttachedPlacement(PyObject* args) const
{
PyObject* pcObj;
if (!PyArg_ParseTuple(args, "O!", &(Base::PlacementPy::Type), &pcObj)) {
return nullptr;
}
try {
const Base::Placement& plm = *(static_cast<const Base::PlacementPy*>(pcObj)->getPlacementPtr());
Base::Placement result;
try {
result = this->getAttachEnginePtr()->calculateAttachedPlacement(plm);
}
catch (ExceptionCancel&) {
Py_IncRef(Py_None);
return Py_None;
}
return new Base::PlacementPy(new Base::Placement(result));
}
ATTACHERPY_STDCATCH_METH;
return nullptr;
}
PyObject* AttachEnginePy::suggestModes(PyObject* args)
{
if (!PyArg_ParseTuple(args, "")) {
return nullptr;
}
try {
AttachEngine& attacher = *(this->getAttachEnginePtr());
SuggestResult sugr;
attacher.suggestMapModes(sugr);
Py::Dict result;
{ // sugr.allApplicableModes
Py::List pyList;
for (eMapMode mmode : sugr.allApplicableModes) {
pyList.append(Py::String(AttachEngine::getModeName(mmode)));
}
result["allApplicableModes"] = pyList;
}
{ // sugr.bestFitMode
result["bestFitMode"] = Py::String(AttachEngine::getModeName(sugr.bestFitMode));
}
{ // sugr.error
bool isError = sugr.message == SuggestResult::srUnexpectedError
|| sugr.message == SuggestResult::srLinkBroken;
result["error"] = Py::String(isError ? sugr.error.what() : "");
}
{ // sugr.message
std::string msg;
switch (sugr.message) {
case SuggestResult::srIncompatibleGeometry:
msg = "IncompatibleGeometry";
break;
case SuggestResult::srLinkBroken:
msg = "LinkBroken";
break;
case SuggestResult::srNoModesFit:
msg = "NoModesFit";
break;
case SuggestResult::srOK:
msg = "OK";
break;
case SuggestResult::srUnexpectedError:
msg = "UnexpectedError";
break;
default:
msg = "<message index out of range>";
}
result["message"] = Py::String(msg);
}
{ // sugr.nextRefTypeHint
Py::List pyList;
for (eRefType rt : sugr.nextRefTypeHint) {
pyList.append(Py::String(AttachEngine::getRefTypeName(rt)));
}
result["nextRefTypeHint"] = pyList;
}
{ // sugr.reachableModes
Py::Dict pyRM;
for (std::pair<const eMapMode, refTypeStringList>& rm : sugr.reachableModes) {
Py::List pyListOfCombinations;
for (refTypeString& rts : rm.second) {
Py::List pyCombination;
for (eRefType rt : rts) {
pyCombination.append(Py::String(AttachEngine::getRefTypeName(rt)));
}
pyListOfCombinations.append(pyCombination);
}
pyRM[AttachEngine::getModeName(rm.first)] = pyListOfCombinations;
}
result["reachableModes"] = pyRM;
}
{ // sugr.references_Types
Py::List pyList;
for (eRefType rt : sugr.references_Types) {
pyList.append(Py::String(AttachEngine::getRefTypeName(rt)));
}
result["references_Types"] = pyList;
}
return Py::new_reference_to(result);
}
ATTACHERPY_STDCATCH_METH;
}
PyObject* AttachEnginePy::readParametersFromFeature(PyObject* args)
{
PyObject* obj;
if (!PyArg_ParseTuple(args, "O!", &(App::DocumentObjectPy::Type), &obj)) {
return nullptr;
}
try {
App::DocumentObjectPy* dobjpy = static_cast<App::DocumentObjectPy*>(obj);
App::DocumentObject* dobj = dobjpy->getDocumentObjectPtr();
if (!dobj->hasExtension(Part::AttachExtension::getExtensionClassTypeId())) {
throw Py::TypeError("Supplied object has no Part::AttachExtension");
}
Part::AttachExtension* feat = dobj->getExtensionByType<Part::AttachExtension>();
AttachEngine& attacher = *(this->getAttachEnginePtr());
attacher.setUp(
feat->AttachmentSupport,
eMapMode(feat->MapMode.getValue()),
feat->MapReversed.getValue(),
feat->MapPathParameter.getValue(),
0.0,
0.0,
feat->AttachmentOffset.getValue()
);
return Py::new_reference_to(Py::None());
}
ATTACHERPY_STDCATCH_METH;
}
PyObject* AttachEnginePy::writeParametersToFeature(PyObject* args)
{
PyObject* obj;
if (!PyArg_ParseTuple(args, "O!", &(App::DocumentObjectPy::Type), &obj)) {
return nullptr;
}
try {
App::DocumentObjectPy* dobjpy = static_cast<App::DocumentObjectPy*>(obj);
App::DocumentObject* dobj = dobjpy->getDocumentObjectPtr();
if (!dobj->hasExtension(Part::AttachExtension::getExtensionClassTypeId())) {
throw Py::TypeError("Supplied object has no Part::AttachExtension");
}
Part::AttachExtension* feat = dobj->getExtensionByType<Part::AttachExtension>();
const AttachEngine& attacher = *(this->getAttachEnginePtr());
feat->AttachmentSupport.setValues(attacher.getRefObjects(), attacher.getSubValues());
feat->MapMode.setValue(attacher.mapMode);
feat->MapReversed.setValue(attacher.mapReverse);
feat->MapPathParameter.setValue(attacher.attachParameter);
feat->AttachmentOffset.setValue(attacher.attachmentOffset);
return Py::new_reference_to(Py::None());
}
ATTACHERPY_STDCATCH_METH;
}
PyObject* AttachEnginePy::getCustomAttributes(const char*) const
{
return nullptr;
}
int AttachEnginePy::setCustomAttributes(const char*, PyObject*)
{
return 0;
}