From 00d8537b66d254ca5b9b380e6848cadc63efe7f6 Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Fri, 6 May 2016 16:48:19 +0300 Subject: [PATCH 01/17] Part: duplicate include cleanup no functional changes --- src/Mod/Part/App/AppPart.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index 21edf90cf..576df44a5 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -51,7 +51,6 @@ #include "PartFeatures.h" #include "BodyBase.h" #include "PrimitiveFeature.h" -#include "Attacher.h" #include "Part2DObject.h" #include "CustomFeature.h" #include "TopoShapePy.h" From a41c79cd55eb3b1ed42e7ef02546277c76af7a6f Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Fri, 6 May 2016 19:46:53 +0300 Subject: [PATCH 02/17] Attacher: AttachableObject should have virtual destructor --- src/Mod/Part/App/AttachableObject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Part/App/AttachableObject.h b/src/Mod/Part/App/AttachableObject.h index 0a3044265..96313456e 100644 --- a/src/Mod/Part/App/AttachableObject.h +++ b/src/Mod/Part/App/AttachableObject.h @@ -59,7 +59,7 @@ class PartExport AttachableObject : public Part::Feature PROPERTY_HEADER(Part::AttachableObject); public: AttachableObject(); - ~AttachableObject(); + virtual ~AttachableObject(); /** * @brief setAttacher sets the AttachEngine object. The class takes the From d21995323ec1308d79508a39876bedb3ec137da8 Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Fri, 6 May 2016 21:48:20 +0300 Subject: [PATCH 03/17] Attacher: change Part2DObject to use Plane attacher by default --- src/Mod/Part/App/Part2DObject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Part/App/Part2DObject.cpp b/src/Mod/Part/App/Part2DObject.cpp index c02b930a0..84ffd8726 100644 --- a/src/Mod/Part/App/Part2DObject.cpp +++ b/src/Mod/Part/App/Part2DObject.cpp @@ -66,7 +66,7 @@ PROPERTY_SOURCE(Part::Part2DObject, Part::AttachableObject) Part2DObject::Part2DObject() { - this->setAttacher(new Attacher::AttachEngine3D); + this->setAttacher(new Attacher::AttachEnginePlane); } From 6ffa0c9b375f3a03ce57edc330b76c7c21a030de Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Mon, 9 May 2016 02:23:32 +0300 Subject: [PATCH 04/17] Attacher: initialize member variables They got garbage values on creation, as was revealed when testing Py interface. --- src/Mod/Part/App/Attacher.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mod/Part/App/Attacher.cpp b/src/Mod/Part/App/Attacher.cpp index 2ec738a32..2809b8291 100644 --- a/src/Mod/Part/App/Attacher.cpp +++ b/src/Mod/Part/App/Attacher.cpp @@ -124,6 +124,8 @@ const char* AttachEngine::eMapModeStrings[]= { TYPESYSTEM_SOURCE_ABSTRACT(Attacher::AttachEngine, Base::BaseClass); AttachEngine::AttachEngine() + : mapReverse(false), attachParameter(0.0), mapMode(mmDeactivated), + surfU(0.0), surfV(0.0) { } From 53bd9b674bbb87447f555add3296164be69ee550 Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Sun, 8 May 2016 18:49:07 +0300 Subject: [PATCH 05/17] Attacher: fix wrong inertial calculation on solids was using surface calculation instead of volume... --- src/Mod/Part/App/Attacher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Part/App/Attacher.cpp b/src/Mod/Part/App/Attacher.cpp index 2809b8291..1fd9642ea 100644 --- a/src/Mod/Part/App/Attacher.cpp +++ b/src/Mod/Part/App/Attacher.cpp @@ -640,7 +640,7 @@ GProp_GProps AttachEngine::getInertialPropsOfShape(const std::vector Date: Sun, 8 May 2016 13:43:10 +0300 Subject: [PATCH 06/17] Attacher: preparations for Py interface of shape type system + add getModeByName to AttachEngine --- src/Mod/Part/App/Attacher.cpp | 83 +++++++++++++++++++++++++++++++++++ src/Mod/Part/App/Attacher.h | 10 ++++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/Mod/Part/App/Attacher.cpp b/src/Mod/Part/App/Attacher.cpp index 1fd9642ea..d0a83b0d8 100644 --- a/src/Mod/Part/App/Attacher.cpp +++ b/src/Mod/Part/App/Attacher.cpp @@ -120,6 +120,38 @@ const char* AttachEngine::eMapModeStrings[]= { NULL}; +//this list must be in sync with eRefType enum. +//These strings are used only by Py interface of Attacher. Strings for use in Gui are in Mod/Part/Gui/AttacherTexts.cpp +const char* AttachEngine::eRefTypeStrings[]= { + "Any", + "Vertex", + "Edge", + "Face", + + "Line", + "Curve", + "Circle", + "Conic", + "Ellipse", + "Parabola", + "Hyperbola", + + "Plane", + "Sphere", + "Revolve", + "Cylinder", + "Torus", + "Cone", + + "Object", + "Solid", + "Wire", + NULL +}; + + + + TYPESYSTEM_SOURCE_ABSTRACT(Attacher::AttachEngine, Base::BaseClass); @@ -578,6 +610,57 @@ std::string AttachEngine::getModeName(eMapMode mmode) return std::string(AttachEngine::eMapModeStrings[mmode]); } +eMapMode AttachEngine::getModeByName(const std::string &modeName) +{ + for (int mmode = 0 ; mmode < mmDummy_NumberOfModes ; mmode++){ + if (strcmp(eMapModeStrings[mmode],modeName.c_str())==0) { + return eMapMode(mmode); + } + } + std::stringstream errMsg; + errMsg << "AttachEngine::getModeByName: mode with this name doesn't exist: " << modeName; + throw Base::Exception(errMsg.str()); +} + +std::string AttachEngine::getRefTypeName(eRefType shapeType) +{ + eRefType flagless = eRefType(shapeType & 0xFF); + if(flagless < 0 || flagless >= rtDummy_numberOfShapeTypes) + throw Base::Exception("eRefType value is out of range"); + std::string result = std::string(eRefTypeStrings[flagless]); + if (shapeType & rtFlagHasPlacement){ + result.append("|Placement"); + } + return result; +} + +eRefType AttachEngine::getRefTypeByName(const std::string& typeName) +{ + std::string flagless; + std::string flags; + size_t seppos = typeName.find('|'); + flagless = typeName.substr(0, seppos); + if(seppos != std::string::npos ){ + flags = typeName.substr(seppos+1); + } + for(int irt = 0 ; irt < rtDummy_numberOfShapeTypes ; irt++){ + if(strcmp(flagless.c_str(),eRefTypeStrings[irt]) == 0){ + if(strcmp("Placement",flags.c_str()) == 0){ + return eRefType(irt | rtFlagHasPlacement); + } else if (flags.length() == 0){ + return eRefType(irt); + } else { + std::stringstream errmsg; + errmsg << "RefType flag not recognized: " << flags; + throw Base::Exception(errmsg.str()); + } + } + } + std::stringstream errmsg; + errmsg << "RefType not recognized: " << typeName; + throw Base::Exception(errmsg.str()); +} + GProp_GProps AttachEngine::getInertialPropsOfShape(const std::vector &shapes) { //explode compounds diff --git a/src/Mod/Part/App/Attacher.h b/src/Mod/Part/App/Attacher.h index d2eb8b22c..c0e880401 100644 --- a/src/Mod/Part/App/Attacher.h +++ b/src/Mod/Part/App/Attacher.h @@ -105,7 +105,8 @@ enum eMapMode { /** * @brief The eRefType enum lists the types of references. If adding one, see - * also AttachEngine::getShapeType(), AttachEngine::downgradeType(), AttacherTexts.cpp/getShTypeText() + * also AttachEngine::eRefTypeStrings, AttachEngine::getShapeType(), + * AttachEngine::downgradeType(), AttacherTexts.cpp/getShTypeText() */ enum eRefType { //topo //ranks: (number of times the type is downgradable) @@ -333,11 +334,18 @@ public://helper functions that may be useful outside of the class */ static std::string getModeName(eMapMode mmode); + static eMapMode getModeByName(const std::string &modeName); + + static std::string getRefTypeName(eRefType shapeType); + + static eRefType getRefTypeByName(const std::string &typeName); + static GProp_GProps getInertialPropsOfShape(const std::vector &shapes); public: //enums static const char* eMapModeStrings[]; + static const char* eRefTypeStrings[]; public: //members From 897a66cbb7dcfcd2654e89d9c8d0fa72580fdafb Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Fri, 6 May 2016 16:50:11 +0300 Subject: [PATCH 07/17] Attacher: Py: withdraw positionBySupport from Part2DObject to be reintroduced later in AttachableObjet Py interface --- src/Mod/Part/App/Part2DObjectPy.xml | 7 ------- src/Mod/Part/App/Part2DObjectPyImp.cpp | 17 ----------------- 2 files changed, 24 deletions(-) diff --git a/src/Mod/Part/App/Part2DObjectPy.xml b/src/Mod/Part/App/Part2DObjectPy.xml index 4698128f1..7172b2fb9 100644 --- a/src/Mod/Part/App/Part2DObjectPy.xml +++ b/src/Mod/Part/App/Part2DObjectPy.xml @@ -13,12 +13,5 @@ This object represents a 2D Shape in a 3D World - - - positionBySupport(): Reposition object based on Support, MapMode and MapPathParameter properties. -Returns True if attachment calculation was successful, false if object is not attached and Placement wasn't updated, -and raises an exception if attachment calculation fails. - - diff --git a/src/Mod/Part/App/Part2DObjectPyImp.cpp b/src/Mod/Part/App/Part2DObjectPyImp.cpp index ed5a01b2c..795e5aba4 100644 --- a/src/Mod/Part/App/Part2DObjectPyImp.cpp +++ b/src/Mod/Part/App/Part2DObjectPyImp.cpp @@ -16,23 +16,6 @@ std::string Part2DObjectPy::representation(void) const return std::string(""); } -PyObject* Part2DObjectPy::positionBySupport(PyObject *args) -{ - if (!PyArg_ParseTuple(args, "")) - return 0; - bool bAttached = false; - try{ - bAttached = this->getPart2DObjectPtr()->positionBySupport(); - } catch (Standard_Failure) { - Handle_Standard_Failure e = Standard_Failure::Caught(); - PyErr_SetString(PartExceptionOCCError, e->GetMessageString()); - return NULL; - } catch (Base::Exception &e) { - PyErr_SetString(Base::BaseExceptionFreeCADError, e.what()); - return NULL; - } - return Py::new_reference_to(Py::Boolean(bAttached)); -} PyObject *Part2DObjectPy::getCustomAttributes(const char* /*attr*/) const From fe295b701b3d491804a161cab77861aa65d936b8 Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Fri, 6 May 2016 16:52:42 +0300 Subject: [PATCH 08/17] Attacher: Py: introduce Py interface of AttachableObject Small - just the introduction. Support for Py features based on AttachableObject. Redirect Part2DObjectPython's father to be AttachableObjectPython. --- src/Mod/Part/App/AppPart.cpp | 1 + src/Mod/Part/App/AttachableObject.cpp | 20 +++++++++ src/Mod/Part/App/AttachableObject.h | 2 + src/Mod/Part/App/AttachableObjectPy.xml | 24 +++++++++++ src/Mod/Part/App/AttachableObjectPyImp.cpp | 48 ++++++++++++++++++++++ src/Mod/Part/App/CMakeLists.txt | 3 ++ src/Mod/Part/App/Part2DObjectPy.xml | 4 +- 7 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 src/Mod/Part/App/AttachableObjectPy.xml create mode 100644 src/Mod/Part/App/AttachableObjectPyImp.cpp diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index 576df44a5..f573eef8e 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -229,6 +229,7 @@ PyMODINIT_FUNC initPart() Part::Feature ::init(); Part::FeatureExt ::init(); Part::AttachableObject ::init(); + Part::AttachableObjectPython::init(); Part::BodyBase ::init(); Part::FeaturePython ::init(); Part::FeatureGeometrySet ::init(); diff --git a/src/Mod/Part/App/AttachableObject.cpp b/src/Mod/Part/App/AttachableObject.cpp index b1e615516..9a4e90913 100644 --- a/src/Mod/Part/App/AttachableObject.cpp +++ b/src/Mod/Part/App/AttachableObject.cpp @@ -30,6 +30,8 @@ #include #include +#include +#include "AttachableObjectPy.h" using namespace Part; @@ -151,4 +153,22 @@ void AttachableObject::updateAttacherVals() this->superPlacement.getValue()); } +namespace App { +/// @cond DOXERR + PROPERTY_SOURCE_TEMPLATE(Part::AttachableObjectPython, Part::AttachableObject) + template<> const char* Part::AttachableObjectPython::getViewProviderName(void) const { + return "PartGui::ViewProviderPython"; + } + template<> PyObject* Part::AttachableObjectPython::getPyObject(void) { + if (PythonObject.is(Py::_None())) { + // ref counter is set to 1 + PythonObject = Py::Object(new FeaturePythonPyT(this),true); + } + return Py::new_reference_to(PythonObject); + } +/// @endcond + +// explicit template instantiation + template class PartExport FeaturePythonT; +} diff --git a/src/Mod/Part/App/AttachableObject.h b/src/Mod/Part/App/AttachableObject.h index 96313456e..251df56a3 100644 --- a/src/Mod/Part/App/AttachableObject.h +++ b/src/Mod/Part/App/AttachableObject.h @@ -104,6 +104,8 @@ private: }; +typedef App::FeaturePythonT AttachableObjectPython; + } // namespace Part #endif // PARTATTACHABLEOBJECT_H diff --git a/src/Mod/Part/App/AttachableObjectPy.xml b/src/Mod/Part/App/AttachableObjectPy.xml new file mode 100644 index 000000000..443f5a645 --- /dev/null +++ b/src/Mod/Part/App/AttachableObjectPy.xml @@ -0,0 +1,24 @@ + + + + + + This object represents an attachable object with OCC shape. + + + + positionBySupport(): Reposition object based on Support, MapMode and MapPathParameter properties. +Returns True if attachment calculation was successful, false if object is not attached and Placement wasn't updated, +and raises an exception if attachment calculation fails. + + + + diff --git a/src/Mod/Part/App/AttachableObjectPyImp.cpp b/src/Mod/Part/App/AttachableObjectPyImp.cpp new file mode 100644 index 000000000..349274d7b --- /dev/null +++ b/src/Mod/Part/App/AttachableObjectPyImp.cpp @@ -0,0 +1,48 @@ + +#include "PreCompiled.h" + +#include "Mod/Part/App/AttachableObject.h" +#include "OCCError.h" + +// inclusion of the generated files (generated out of AttachableObjectPy.xml) +#include "AttachableObjectPy.h" +#include "AttachableObjectPy.cpp" + +using namespace Part; + +// returns a string which represents the object e.g. when printed in python +std::string AttachableObjectPy::representation(void) const +{ + return std::string(""); +} + +PyObject* AttachableObjectPy::positionBySupport(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return 0; + bool bAttached = false; + try{ + bAttached = this->getAttachableObjectPtr()->positionBySupport(); + } catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PartExceptionOCCError, e->GetMessageString()); + return NULL; + } catch (Base::Exception &e) { + PyErr_SetString(Base::BaseExceptionFreeCADError, e.what()); + return NULL; + } + return Py::new_reference_to(Py::Boolean(bAttached)); +} + + +PyObject *AttachableObjectPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int AttachableObjectPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} + + diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index a223b4d2d..68a718123 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -69,6 +69,7 @@ generate_from_xml(RectangularTrimmedSurfacePy) generate_from_xml(SurfaceOfExtrusionPy) generate_from_xml(SurfaceOfRevolutionPy) generate_from_xml(PartFeaturePy) +generate_from_xml(AttachableObjectPy) generate_from_xml(Part2DObjectPy) generate_from_xml(TopoShapePy) generate_from_xml(TopoShapeCompoundPy) @@ -216,6 +217,8 @@ SET(Python_SRCS SurfaceOfRevolutionPyImp.cpp PartFeaturePy.xml PartFeaturePyImp.cpp + AttachableObjectPy.xml + AttachableObjectPyImp.cpp Part2DObjectPy.xml Part2DObjectPyImp.cpp TopoShapePy.xml diff --git a/src/Mod/Part/App/Part2DObjectPy.xml b/src/Mod/Part/App/Part2DObjectPy.xml index 7172b2fb9..299bcd84d 100644 --- a/src/Mod/Part/App/Part2DObjectPy.xml +++ b/src/Mod/Part/App/Part2DObjectPy.xml @@ -1,13 +1,13 @@  From d4f1ef2f7a14ee736bba5460446ad43284a22dcc Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Fri, 6 May 2016 21:52:23 +0300 Subject: [PATCH 09/17] Attacher: Py: add interface for changing attacher type Plus a mechanism to remember attacher type of AttachableObject through save-restore cycle. --- src/Mod/Part/App/AttachableObject.cpp | 46 +++++++++++++++++++++- src/Mod/Part/App/AttachableObject.h | 13 +++++- src/Mod/Part/App/AttachableObjectPy.xml | 10 +++++ src/Mod/Part/App/AttachableObjectPyImp.cpp | 19 +++++++++ 4 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/Mod/Part/App/AttachableObject.cpp b/src/Mod/Part/App/AttachableObject.cpp index 9a4e90913..52fff96c9 100644 --- a/src/Mod/Part/App/AttachableObject.cpp +++ b/src/Mod/Part/App/AttachableObject.cpp @@ -42,6 +42,9 @@ PROPERTY_SOURCE(Part::AttachableObject, Part::Feature); AttachableObject::AttachableObject() : _attacher(0) { + ADD_PROPERTY_TYPE(AttacherType, ("Attacher::AttachEngine3D"), "Attachment",(App::PropertyType)(App::Prop_None),"Class name of attach engine object driving the attachment."); + this->AttacherType.setStatus(App::Property::Status::Hidden, true); + ADD_PROPERTY_TYPE(Support, (0,0), "Attachment",(App::PropertyType)(App::Prop_None),"Support of the 2D geometry"); ADD_PROPERTY_TYPE(MapMode, (mmDeactivated), "Attachment", App::Prop_None, "Mode of attachment to other object"); @@ -69,7 +72,44 @@ void AttachableObject::setAttacher(AttachEngine* attacher) if (_attacher) delete _attacher; _attacher = attacher; - updateAttacherVals(); + if (_attacher){ + const char* typeName = attacher->getTypeId().getName(); + if(strcmp(this->AttacherType.getValue(),typeName)!=0) //make sure we need to change, to break recursive onChange->changeAttacherType->onChange... + this->AttacherType.setValue(typeName); + updateAttacherVals(); + } else { + if (strlen(AttacherType.getValue()) != 0){ //make sure we need to change, to break recursive onChange->changeAttacherType->onChange... + this->AttacherType.setValue(""); + } + } +} + +bool AttachableObject::changeAttacherType(const char* typeName) +{ + //check if we need to actually change anything + if (_attacher){ + if (strcmp(_attacher->getTypeId().getName(),typeName)==0){ + return false; + } + } else if (strlen(typeName) == 0){ + return false; + } + if (strlen(typeName) == 0){ + setAttacher(nullptr); + return true; + } + Base::Type t = Base::Type::fromName(typeName); + if (t.isDerivedFrom(AttachEngine::getClassTypeId())){ + AttachEngine* pNewAttacher = static_cast(Base::Type::createInstanceByName(typeName)); + this->setAttacher(pNewAttacher); + return true; + } else { + std::stringstream errMsg; + errMsg << "Object if this type is not derived from AttachEngine: " << typeName; + throw Base::Exception(errMsg.str()); + } + assert(false);//exec shouldn't ever get here + return false; } bool AttachableObject::positionBySupport() @@ -138,6 +178,10 @@ void AttachableObject::onChanged(const App::Property* prop) } + if(prop == &(this->AttacherType)){ + this->changeAttacherType(this->AttacherType.getValue()); + } + Part::Feature::onChanged(prop); } diff --git a/src/Mod/Part/App/AttachableObject.h b/src/Mod/Part/App/AttachableObject.h index 251df56a3..83bababa0 100644 --- a/src/Mod/Part/App/AttachableObject.h +++ b/src/Mod/Part/App/AttachableObject.h @@ -68,9 +68,20 @@ public: * @param attacher. AttachableObject takes ownership and will delete it eventually. */ virtual void setAttacher(Attacher::AttachEngine* attacher); + + /** + * @brief changeAttacherType + * @param typeName is the typename of new attacher class. Must be derived + * from Attacher::AttachEngine. + * @return true if attacher was changed. false if attacher is already of the + * type requested. Throws if invalid type is supplied. + */ + bool changeAttacherType(const char* typeName); + Attacher::AttachEngine &attacher(void) const {return *_attacher;} - /// if the 2DObject lies on the Face of an other object this links to it + + App::PropertyString AttacherType; App::PropertyLinkSubList Support; App::PropertyEnumeration MapMode; //see AttachEngine::eMapMode App::PropertyBool MapReversed; //inverts Z and X internal axes diff --git a/src/Mod/Part/App/AttachableObjectPy.xml b/src/Mod/Part/App/AttachableObjectPy.xml index 443f5a645..664fbf7a7 100644 --- a/src/Mod/Part/App/AttachableObjectPy.xml +++ b/src/Mod/Part/App/AttachableObjectPy.xml @@ -20,5 +20,15 @@ Returns True if attachment calculation was successful, false if object is not at and raises an exception if attachment calculation fails. + + + changeAttacherType(typename): Changes Attacher class of this object. +typename: string. The following are accepted so far: +'Attacher::AttachEngine3D' +'Attacher::AttachEnginePlane' +'Attacher::AttachEngineLine' +'Attacher::AttachEnginePoint' + + diff --git a/src/Mod/Part/App/AttachableObjectPyImp.cpp b/src/Mod/Part/App/AttachableObjectPyImp.cpp index 349274d7b..82ed1d6ea 100644 --- a/src/Mod/Part/App/AttachableObjectPyImp.cpp +++ b/src/Mod/Part/App/AttachableObjectPyImp.cpp @@ -34,6 +34,25 @@ PyObject* AttachableObjectPy::positionBySupport(PyObject *args) return Py::new_reference_to(Py::Boolean(bAttached)); } +PyObject* AttachableObjectPy::changeAttacherType(PyObject *args) +{ + const char* typeName; + if (!PyArg_ParseTuple(args, "s", &typeName)) + return 0; + bool ret; + try{ + ret = this->getAttachableObjectPtr()->changeAttacherType(typeName); + } catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PartExceptionOCCError, e->GetMessageString()); + return NULL; + } catch (Base::Exception &e) { + PyErr_SetString(Base::BaseExceptionFreeCADError, e.what()); + return NULL; + } + return Py::new_reference_to(Py::Boolean(ret)); +} + PyObject *AttachableObjectPy::getCustomAttributes(const char* /*attr*/) const { From 7000d551b79cfcbd1a426f76730c8a70c73bab75 Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Sat, 7 May 2016 14:13:40 +0300 Subject: [PATCH 10/17] Attacher: Py: create AttachEnginePy Not very useful at the moment, just created the interface. --- src/Mod/Part/App/AppPart.cpp | 3 +++ src/Mod/Part/App/AttachEnginePy.xml | 25 +++++++++++++++++++ src/Mod/Part/App/AttachEnginePyImp.cpp | 33 ++++++++++++++++++++++++++ src/Mod/Part/App/CMakeLists.txt | 3 +++ src/Mod/Part/App/PreCompiled.h | 3 +++ 5 files changed, 67 insertions(+) create mode 100644 src/Mod/Part/App/AttachEnginePy.xml create mode 100644 src/Mod/Part/App/AttachEnginePyImp.cpp diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index f573eef8e..eaa8f9ea5 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -90,6 +90,7 @@ #include "ToroidPy.h" #include "BRepOffsetAPI_MakePipeShellPy.h" #include "PartFeaturePy.h" +#include "AttachEnginePy.h" #include "PropertyGeometryList.h" #include "DatumFeature.h" #include "Attacher.h" @@ -209,6 +210,8 @@ PyMODINIT_FUNC initPart() Base::Interpreter().addType(&Part::PartFeaturePy ::Type,partModule,"Feature"); + Base::Interpreter().addType(&Attacher::AttachEnginePy ::Type,partModule,"AttachEngine"); + PyObject* brepModule = Py_InitModule3("BRepOffsetAPI", 0, "BrepOffsetAPI"); Py_INCREF(brepModule); PyModule_AddObject(partModule, "BRepOffsetAPI", brepModule); diff --git a/src/Mod/Part/App/AttachEnginePy.xml b/src/Mod/Part/App/AttachEnginePy.xml new file mode 100644 index 000000000..a38a81c2a --- /dev/null +++ b/src/Mod/Part/App/AttachEnginePy.xml @@ -0,0 +1,25 @@ + + + + + + AttachEngine abstract class + AttachEngine abstract class - the functinality of AttachableObject, but outside of DocumentObject + + + + Type of engine: 3d, plane, line, or point. + + + + + diff --git a/src/Mod/Part/App/AttachEnginePyImp.cpp b/src/Mod/Part/App/AttachEnginePyImp.cpp new file mode 100644 index 000000000..ebc2e06d9 --- /dev/null +++ b/src/Mod/Part/App/AttachEnginePyImp.cpp @@ -0,0 +1,33 @@ +#include "PreCompiled.h" + +#include "Mod/Part/App/Attacher.h" + +#include "OCCError.h" + +// inclusion of the generated files (generated out of AttachableObjectPy.xml) +#include "AttachEnginePy.h" +#include "AttachEnginePy.cpp" + +using namespace Attacher; + +// returns a string which represents the object e.g. when printed in python +std::string AttachEnginePy::representation(void) const +{ + return std::string(""); +} + +Py::String AttachEnginePy::getAttacherType(void) const +{ + return Py::String(std::string(this->getAttachEnginePtr()->getTypeId().getName())); +} + +PyObject* AttachEnginePy::getCustomAttributes(const char*) const +{ + return 0; +} + +int AttachEnginePy::setCustomAttributes(const char*,PyObject*) +{ + return 0; +} + diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index 68a718123..333557ad6 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -71,6 +71,7 @@ generate_from_xml(SurfaceOfRevolutionPy) generate_from_xml(PartFeaturePy) generate_from_xml(AttachableObjectPy) generate_from_xml(Part2DObjectPy) +generate_from_xml(AttachEnginePy) generate_from_xml(TopoShapePy) generate_from_xml(TopoShapeCompoundPy) generate_from_xml(TopoShapeCompSolidPy) @@ -221,6 +222,8 @@ SET(Python_SRCS AttachableObjectPyImp.cpp Part2DObjectPy.xml Part2DObjectPyImp.cpp + AttachEnginePy.xml + AttachEnginePyImp.cpp TopoShapePy.xml TopoShapePyImp.cpp TopoShapeCompSolidPy.xml diff --git a/src/Mod/Part/App/PreCompiled.h b/src/Mod/Part/App/PreCompiled.h index 67c8bc391..ad0c3508f 100644 --- a/src/Mod/Part/App/PreCompiled.h +++ b/src/Mod/Part/App/PreCompiled.h @@ -34,6 +34,9 @@ # define PartExport #endif +//needed to make autogenerated Py interface source code to compile +#define AttacherExport PartExport + // here get the warnings of too long specifiers disabled (needed for VC6) #ifdef _MSC_VER # pragma warning( disable : 4251 ) From dcc8926236e1fab6165d3b43690082f22d307972 Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Sat, 7 May 2016 14:14:25 +0300 Subject: [PATCH 11/17] Attacher: Py: implement Attacher attribute of AttachableObject --- src/Mod/Part/App/AttachableObject.h | 2 +- src/Mod/Part/App/AttachableObjectPy.xml | 7 +++++++ src/Mod/Part/App/AttachableObjectPyImp.cpp | 20 ++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/Mod/Part/App/AttachableObject.h b/src/Mod/Part/App/AttachableObject.h index 83bababa0..ed68a3958 100644 --- a/src/Mod/Part/App/AttachableObject.h +++ b/src/Mod/Part/App/AttachableObject.h @@ -78,7 +78,7 @@ public: */ bool changeAttacherType(const char* typeName); - Attacher::AttachEngine &attacher(void) const {return *_attacher;} + Attacher::AttachEngine &attacher(void) const {if(!_attacher) throw Base::Exception("AttachableObject: no attacher is set."); return *_attacher;} App::PropertyString AttacherType; diff --git a/src/Mod/Part/App/AttachableObjectPy.xml b/src/Mod/Part/App/AttachableObjectPy.xml index 664fbf7a7..89a75d45e 100644 --- a/src/Mod/Part/App/AttachableObjectPy.xml +++ b/src/Mod/Part/App/AttachableObjectPy.xml @@ -30,5 +30,12 @@ typename: string. The following are accepted so far: 'Attacher::AttachEnginePoint' + + + + AttachEngine object driving this AttachableObject. Returns a copy. + + + diff --git a/src/Mod/Part/App/AttachableObjectPyImp.cpp b/src/Mod/Part/App/AttachableObjectPyImp.cpp index 82ed1d6ea..aa45e065b 100644 --- a/src/Mod/Part/App/AttachableObjectPyImp.cpp +++ b/src/Mod/Part/App/AttachableObjectPyImp.cpp @@ -4,6 +4,8 @@ #include "Mod/Part/App/AttachableObject.h" #include "OCCError.h" +#include "AttachEnginePy.h" + // inclusion of the generated files (generated out of AttachableObjectPy.xml) #include "AttachableObjectPy.h" #include "AttachableObjectPy.cpp" @@ -53,6 +55,24 @@ PyObject* AttachableObjectPy::changeAttacherType(PyObject *args) return Py::new_reference_to(Py::Boolean(ret)); } +Py::Object AttachableObjectPy::getAttacher(void) const +{ + try { + this->getAttachableObjectPtr()->attacher(); //throws if attacher is not set + } catch (Base::Exception) { + return Py::None(); + } + + try { + return Py::Object( new Attacher::AttachEnginePy(this->getAttachableObjectPtr()->attacher().copy()), true); + } catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Py::Exception(Part::PartExceptionOCCError, e->GetMessageString()); + } catch (Base::Exception &e) { + throw Py::Exception(Base::BaseExceptionFreeCADError, e.what()); + } + +} PyObject *AttachableObjectPy::getCustomAttributes(const char* /*attr*/) const { From 8b4f1210ed5a874f9fca292b68a2ef870424bb1f Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Sat, 7 May 2016 21:06:18 +0300 Subject: [PATCH 12/17] Attacher: Py: extend AttachEngine's interface * add constructor attributes: * Mode * CompleteModeList * ImplementedModes * GetModeInfo * References * SuperPlacement * Reverse * Parameter * CompleteRefTypeList methods: * getShapeType * isShapeOfType * downgradeType * getTypeRank * copy * calculateAttachedPlacement * suggestMapModes * readParametersFromFeature * writeParametersToFeature --- src/Mod/Part/App/AttachEnginePy.xml | 143 ++++++++ src/Mod/Part/App/AttachEnginePyImp.cpp | 449 +++++++++++++++++++++++++ 2 files changed, 592 insertions(+) diff --git a/src/Mod/Part/App/AttachEnginePy.xml b/src/Mod/Part/App/AttachEnginePy.xml index a38a81c2a..3c4c3edad 100644 --- a/src/Mod/Part/App/AttachEnginePy.xml +++ b/src/Mod/Part/App/AttachEnginePy.xml @@ -8,6 +8,7 @@ Include="Mod/Part/App/Attacher.h" FatherInclude="Base/BaseClassPy.h" Namespace="Attacher" + Constructor="true" Delete="true" FatherNamespace="Base"> @@ -21,5 +22,147 @@ + + + Current attachment mode. + + + + + + Current attachment mode. + + + + + + Current attachment mode. + + + + + + If True, Z axis of attached placement is flipped. X axis is flipped in addition (CS has to remain right-handed). + + + + + + Value of parameter for some curve attachment modes. Range of 0..1 spans the length of the edge (parameter value can be outside of the range for curves that allow extrapolation. + + + + + + + List of all attachment modes of all AttachEngines. This is the list of modes in MapMode enum properties of AttachableObjects. + + + + + + List of all attachment modes of all AttachEngines. This is the list of modes in MapMode enum properties of AttachableObjects. + + + + + + List of all attachment modes of all AttachEngines. This is the list of modes in MapMode enum properties of AttachableObjects. + + + + + + + getModeInfo(mode): returns supported reference combinations, user-friendly name, and so on. + + + + + getShapeType(shape): returns shape type as interpreted by AttachEngine. Returns a string. + + + + + isShapeOfType(type_shape, type_needed): tests if shape type, specified by type_shape (string), fits a type required by attachment mode type_needed (string). e.g. 'Circle' fits a requirement of 'Edge', and 'Curve' doesn't fit if a 'Circle' is required. + + + + + downgradeType(type): returns next more general type. E.g. downgradeType('Circle') yeilds 'Curve'. + + + + + getTypeRank(type): returns rank of shape type. Rank is how many times the type can be downgraded, before it becomes 'Any'. + + + + + copy(): returns a new instance of AttachEngine. + + + + + calculateAttachedPlacement(orig_placement): returns result of attachment, based +on current Mode, References, etc. SuperPlacment is included. + +original_placement is the previous placement of the object being attached. It +is used to preserve orientation for Translate attachment mode. For other modes, +it is ignored. + +Returns the new placement. If not attached, returns None. If attachment fails, +an exception is raised. + + + + + +suggestMapModes(): runs mode suggestion routine and returns a dictionary with +results and supplementary information. + +Keys: +'allApplicableModes': list of modes that can accept current references. Note +that it is only a check by types, and does not guarantee the modes will +actually work. + +'bestFitMode': mode that fits current references best. Note that the mode may +not be valid for the set of references; check for if 'message' is 'OK'. + +'error': error message for when 'message' is 'UnexpectedError' or +'LinkBroken'. + +'message': general result of suggestion. 'IncompatibleGeometry', 'NoModesFit': +no modes accept current set of references; 'OK': some modes do accept current +set of references (though it's not guarantted the modes will work - surrestor +only checks for correct types); 'UnexpectedError': should never happen. + +'nextRefTypeHint': what more can be added to references to reach other modes +('reachableModes' provide more extended information on this) + +'reachableModes': a dict, where key is mode, and value is a list of sequences +of references that can be added to fit that mode. + +'references_Types': a list of types of geometry linked by references (that's +the input information for suggestor, actually). + + + + + readParametersFromFeature(document_object): sets AttachEngine parameters (References, Mode, etc.) by reading out properties of AttachableObject-derived feature. + + + + + +writeParametersToFeature(document_object): updates properties of +AttachableObject-derived feature with current AttachEngine parameters +(References, Mode, etc.). + +Warning: if a feature linked by AttachEngine.References was deleted, this method +will crash FreeCAD. + + + diff --git a/src/Mod/Part/App/AttachEnginePyImp.cpp b/src/Mod/Part/App/AttachEnginePyImp.cpp index ebc2e06d9..a670b6f05 100644 --- a/src/Mod/Part/App/AttachEnginePyImp.cpp +++ b/src/Mod/Part/App/AttachEnginePyImp.cpp @@ -1,6 +1,13 @@ #include "PreCompiled.h" +#ifndef _PreComp_ +# include +#endif #include "Mod/Part/App/Attacher.h" +#include +#include +#include "AttachableObjectPy.h" +#include "TopoShapePy.h" #include "OCCError.h" @@ -16,11 +23,453 @@ std::string AttachEnginePy::representation(void) const return std::string(""); } +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(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(Base::Type::createInstanceByName(typeName)); + } + if (!pNewAttacher) { + std::stringstream errMsg; + errMsg << "Object if this type is not derived from AttachEngine: " << typeName; + PyErr_SetString(Base::BaseExceptionFreeCADError, errMsg.str().c_str()); + return -1; + } + AttachEngine* oldAttacher = this->getAttachEnginePtr(); + this->_pcTwinPointer = pNewAttacher; + delete oldAttacher; + return 0; + } + + PyErr_SetString(Base::BaseExceptionFreeCADError, "Wrong set of constructor arguments. Can be: (), ('Attacher::AttachEngine3D'), ('Attacher::AttachEnginePlane'), ('Attacher::AttachEngineLine'), ('Attacher::AttachEnginePoint'), (other_attacher_instance)."); + return -1; + +} + + Py::String AttachEnginePy::getAttacherType(void) const { return Py::String(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) {\ + Handle_Standard_Failure e = Standard_Failure::Caught();\ + throw Py::Exception(Part::PartExceptionOCCError, e->GetMessageString());\ + } catch (Base::Exception &e) {\ + throw Py::Exception(Base::BaseExceptionFreeCADError, e.what());\ + } + +Py::String AttachEnginePy::getMode(void) const +{ + try { + AttachEngine &attacher = *(this->getAttachEnginePtr()); + return Py::String(attacher.getModeName(attacher.mapMode)); + } ATTACHERPY_STDCATCH_ATTR; +} + +void AttachEnginePy::setMode(Py::String arg) +{ + try { + AttachEngine &attacher = *(this->getAttachEnginePtr()); + std::string modeName = (std::string)arg; + attacher.mapMode = attacher.getModeByName(modeName); + } ATTACHERPY_STDCATCH_ATTR; +} + +Py::Object AttachEnginePy::getReferences(void) const +{ + try { + AttachEngine &attacher = *(this->getAttachEnginePtr()); + return Py::Object(attacher.references.getPyObject(),true); + } ATTACHERPY_STDCATCH_ATTR; +} + +void AttachEnginePy::setReferences(Py::Object arg) +{ + try { + AttachEngine &attacher = *(this->getAttachEnginePtr()); + attacher.references.setPyObject(arg.ptr()); + } ATTACHERPY_STDCATCH_ATTR; +} + +Py::Object AttachEnginePy::getSuperPlacement(void) const +{ + try { + AttachEngine &attacher = *(this->getAttachEnginePtr()); + return Py::Object(new Base::PlacementPy(new Base::Placement(attacher.superPlacement)),true); + } ATTACHERPY_STDCATCH_ATTR; +} + +void AttachEnginePy::setSuperPlacement(Py::Object arg) +{ + try { + AttachEngine &attacher = *(this->getAttachEnginePtr()); + if (PyObject_TypeCheck(arg.ptr(), &(Base::PlacementPy::Type))) { + const Base::PlacementPy* plmPy = static_cast(arg.ptr()); + attacher.superPlacement = *(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(void) const +{ + try { + AttachEngine &attacher = *(this->getAttachEnginePtr()); + return Py::Boolean(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(void) 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(void) 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(void) 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(void) const +{ + try { + Py::List ret; + AttachEngine &attacher = *(this->getAttachEnginePtr()); + for(int imode = 0 ; imode < mmDummy_NumberOfModes ; imode++){ + if(attacher.modeRefTypes[imode].size() > 0){ + 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) {\ + Handle_Standard_Failure e = Standard_Failure::Caught();\ + PyErr_SetString(Part::PartExceptionOCCError, e->GetMessageString());\ + return NULL;\ + } catch (Base::Exception &e) {\ + PyErr_SetString(Base::BaseExceptionFreeCADError, e.what());\ + return NULL;\ + } catch (const Py::Exception &){\ + return NULL;\ + } + + +PyObject* AttachEnginePy::getModeInfo(PyObject* args) +{ + char* modeName; + if (!PyArg_ParseTuple(args, "s", &modeName)) + return 0; + + 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(int 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::Int(mmode); + return Py::new_reference_to(ret); + } ATTACHERPY_STDCATCH_METH; +} + +PyObject* AttachEnginePy::getShapeType(PyObject* args) +{ + PyObject *pcObj; + if (!PyArg_ParseTuple(args, "O!", &(Part::TopoShapePy::Type), &pcObj)) + return NULL; + + try{ + TopoDS_Shape shape = static_cast(pcObj)->getTopoShapePtr()->_Shape; + eRefType rt = AttachEngine::getShapeType(shape); + return Py::new_reference_to(Py::String(AttachEngine::getRefTypeName(rt))); + } ATTACHERPY_STDCATCH_METH; +} + +PyObject* AttachEnginePy::isShapeOfType(PyObject* args) +{ + char* type_shape_str; + char* type_need_str; + if (!PyArg_ParseTuple(args, "ss", &type_shape_str, &type_need_str)) + return 0; + 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::downgradeType(PyObject* args) +{ + char* type_shape_str; + if (!PyArg_ParseTuple(args, "s", &type_shape_str)) + return 0; + 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::getTypeRank(PyObject* args) +{ + char* type_shape_str; + if (!PyArg_ParseTuple(args, "s", &type_shape_str)) + return 0; + try { + eRefType type_shape = AttachEngine::getRefTypeByName(std::string(type_shape_str)); + int result = AttachEngine::getTypeRank(type_shape); + return Py::new_reference_to(Py::Int(result)); + } ATTACHERPY_STDCATCH_METH; + +} + +PyObject* AttachEnginePy::copy(PyObject* args) +{ + if (!PyArg_ParseTuple(args, "")) + return 0; + + return new AttachEnginePy(this->getAttachEnginePtr()->copy()); +} + +PyObject* AttachEnginePy::calculateAttachedPlacement(PyObject* args) +{ + PyObject *pcObj; + if (!PyArg_ParseTuple(args, "O!", &(Base::PlacementPy::Type), &pcObj)) + return NULL; + try{ + const Base::Placement& plm = *(static_cast(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 NULL; +} + +PyObject* AttachEnginePy::suggestMapModes(PyObject* args) +{ + if (!PyArg_ParseTuple(args, "")) + return 0; + + 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 = ""; + } + 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 &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 NULL; // NULL triggers exception + + try{ + const App::DocumentObjectPy* dobjpy = static_cast(obj); + const App::DocumentObject* dobj = dobjpy->getDocumentObjectPtr(); + if (! dobj->isDerivedFrom(Part::AttachableObject::getClassTypeId())){ + throw Py::TypeError("Supplied object isn't Part::AttachableObject"); + } + const Part::AttachableObject* feat = static_cast(dobj); + AttachEngine &attacher = *(this->getAttachEnginePtr()); + attacher.setUp(feat->Support, + eMapMode(feat->MapMode.getValue()), + feat->MapReversed.getValue(), + feat->MapPathParameter.getValue(), + 0.0,0.0, + feat->superPlacement.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 NULL; // NULL triggers exception + + try{ + App::DocumentObjectPy* dobjpy = static_cast(obj); + App::DocumentObject* dobj = dobjpy->getDocumentObjectPtr(); + if (! dobj->isDerivedFrom(Part::AttachableObject::getClassTypeId())){ + throw Py::TypeError("Supplied object isn't Part::AttachableObject"); + } + Part::AttachableObject* feat = static_cast(dobj); + const AttachEngine &attacher = *(this->getAttachEnginePtr()); + feat->Support.Paste(attacher.references); + feat->MapMode.setValue(attacher.mapMode); + feat->MapReversed.setValue(attacher.mapReverse); + feat->MapPathParameter.setValue(attacher.attachParameter); + feat->superPlacement.setValue(attacher.superPlacement); + return Py::new_reference_to(Py::None()); + } ATTACHERPY_STDCATCH_METH; +} + PyObject* AttachEnginePy::getCustomAttributes(const char*) const { return 0; From 76c0a81fe332775c564c44aab38505352c33a008 Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Fri, 13 May 2016 02:09:42 +0300 Subject: [PATCH 13/17] Attacher: Py: GUI resources interface Routines to get UI strings for attacher: mode names, mode tooltips, ref.type names --- src/Mod/Part/Gui/AppPartGui.cpp | 9 ++++- src/Mod/Part/Gui/AttacherTexts.cpp | 64 +++++++++++++++++++++++++++++- src/Mod/Part/Gui/AttacherTexts.h | 12 +++++- 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/src/Mod/Part/Gui/AppPartGui.cpp b/src/Mod/Part/Gui/AppPartGui.cpp index ec119b937..c9913200c 100644 --- a/src/Mod/Part/Gui/AppPartGui.cpp +++ b/src/Mod/Part/Gui/AppPartGui.cpp @@ -28,6 +28,7 @@ #include +#include "AttacherTexts.h" #include "SoBrepFaceSet.h" #include "SoBrepEdgeSet.h" #include "SoBrepPointSet.h" @@ -117,9 +118,15 @@ PyMODINIT_FUNC initPartGui() return; } - (void)PartGui::initModule(); + PyObject* partGuiModule = PartGui::initModule(); Base::Console().Log("Loading GUI of Part module... done\n"); + PyObject* pAttachEngineTextsModule = Py_InitModule3("AttachEngineResources", AttacherGui::AttacherGuiPy::Methods, + "AttachEngine Gui resources"); + Py_INCREF(pAttachEngineTextsModule); + PyModule_AddObject(partGuiModule, "AttachEngineResources", pAttachEngineTextsModule); + + PartGui::SoBrepFaceSet ::initClass(); PartGui::SoBrepEdgeSet ::initClass(); PartGui::SoBrepPointSet ::initClass(); diff --git a/src/Mod/Part/Gui/AttacherTexts.cpp b/src/Mod/Part/Gui/AttacherTexts.cpp index 742b74c48..8ffc1a5e3 100644 --- a/src/Mod/Part/Gui/AttacherTexts.cpp +++ b/src/Mod/Part/Gui/AttacherTexts.cpp @@ -25,6 +25,8 @@ # include #endif #include "AttacherTexts.h" +#include +#include using namespace Attacher; @@ -262,7 +264,7 @@ TextSet getUIStrings(Base::Type attacherType, eMapMode mmode) } } - assert(false && "No user-friendly string defined for this attachment mode."); + Base::Console().Warning("No user-friendly string defined for this attachment mode and attacher type: %s %s \n",AttachEngine::getModeName(mmode).c_str(), attacherType.getName()); return TwoStrings(QString::fromStdString(AttachEngine::getModeName(mmode)), QString()); } @@ -325,4 +327,64 @@ QStringList getRefListForMode(AttachEngine &attacher, eMapMode mmode) return strlist; } + +// --------------------Py interface--------------------- + +PyObject* AttacherGuiPy::sGetModeStrings(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/) +{ + int modeIndex = 0; + char* attacherType; + if (!PyArg_ParseTuple(args, "si", &attacherType, &modeIndex)) + return NULL; + + try { + Base::Type t = Base::Type::fromName(attacherType); + if (! t.isDerivedFrom(AttachEngine::getClassTypeId())){ + std::stringstream ss; + ss << "Object of this type is not derived from AttachEngine: "; + ss << attacherType; + throw Py::TypeError(ss.str()); + } + TextSet strs = getUIStrings(t,eMapMode(modeIndex)); + Py::List result; + for(QString &s : strs){ + QByteArray ba_utf8 = s.toUtf8(); + result.append(Py::String(ba_utf8.data(), "utf-8")); + } + + return Py::new_reference_to(result); + } catch (const Py::Exception&) { + return 0; + } catch (const Base::Exception& e) { + PyErr_SetString(Base::BaseExceptionFreeCADError, e.what()); + return 0; + } +} + +PyObject* AttacherGuiPy::sGetRefTypeUserFriendlyName(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/) +{ + int refTypeIndex = 0; + if (!PyArg_ParseTuple(args, "i", &refTypeIndex)) + return NULL; + + try { + QByteArray ba_utf8 = getShapeTypeText(eRefType(refTypeIndex)).toUtf8(); + return Py::new_reference_to(Py::String(ba_utf8.data(), "utf-8")); + } catch (const Py::Exception&) { + return 0; + } catch (const Base::Exception& e) { + PyErr_SetString(Base::BaseExceptionFreeCADError, e.what()); + return 0; + } +} + + +PyMethodDef AttacherGuiPy::Methods[] = { + {"getModeStrings", (PyCFunction) AttacherGuiPy::sGetModeStrings, 1, + "getModeStrings(attacher_type, mode_index) - gets mode user-friendly name and brief description."}, + {"getRefTypeUserFriendlyName", (PyCFunction) AttacherGuiPy::sGetRefTypeUserFriendlyName, 1, + "getRefTypeUserFriendlyName(type_index) - gets user-friendly name of AttachEngine's shape type."}, +}; + + } //namespace AttacherGui diff --git a/src/Mod/Part/Gui/AttacherTexts.h b/src/Mod/Part/Gui/AttacherTexts.h index 91bdee8bd..903f604b1 100644 --- a/src/Mod/Part/Gui/AttacherTexts.h +++ b/src/Mod/Part/Gui/AttacherTexts.h @@ -33,8 +33,10 @@ #include #include #include +#include #include + namespace AttacherGui { typedef std::vector TextSet; @@ -54,6 +56,14 @@ QString PartGuiExport getShapeTypeText(Attacher::eRefType type); QStringList PartGuiExport getRefListForMode(Attacher::AttachEngine &attacher, Attacher::eMapMode mmode); -} +// Python interface +class PartGuiExport AttacherGuiPy{ +public: + static PyMethodDef Methods[]; + static PyObject* sGetModeStrings(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/); + static PyObject* sGetRefTypeUserFriendlyName(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/); +}; + +} #endif From 632cf142feac409e7cbdebc7c8eeba602f61d3e4 Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Fri, 13 May 2016 02:10:36 +0300 Subject: [PATCH 14/17] Attacher: Py: add GUI strings to getModeInfo and getTypeInfo --- src/Mod/Part/App/AttachEnginePy.xml | 5 ++ src/Mod/Part/App/AttachEnginePyImp.cpp | 74 ++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/src/Mod/Part/App/AttachEnginePy.xml b/src/Mod/Part/App/AttachEnginePy.xml index 3c4c3edad..ac06a8d60 100644 --- a/src/Mod/Part/App/AttachEnginePy.xml +++ b/src/Mod/Part/App/AttachEnginePy.xml @@ -97,6 +97,11 @@ getTypeRank(type): returns rank of shape type. Rank is how many times the type can be downgraded, before it becomes 'Any'. + + + getTypeInfo(type): returns information (dict) on shape type. Keys:'UserFriendlyName', 'TypeIndex'. + + copy(): returns a new instance of AttachEngine. diff --git a/src/Mod/Part/App/AttachEnginePyImp.cpp b/src/Mod/Part/App/AttachEnginePyImp.cpp index a670b6f05..576548895 100644 --- a/src/Mod/Part/App/AttachEnginePyImp.cpp +++ b/src/Mod/Part/App/AttachEnginePyImp.cpp @@ -257,6 +257,37 @@ PyObject* AttachEnginePy::getModeInfo(PyObject* args) Py::Dict ret; ret["ReferenceCombinations"] = pyListOfCombinations; ret["ModeIndex"] = Py::Int(mmode); + + try { + Py::Module module(PyImport_ImportModule("PartGui"),true); + if (!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::Int(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; } @@ -313,6 +344,49 @@ PyObject* AttachEnginePy::getTypeRank(PyObject* args) } +PyObject* AttachEnginePy::getTypeInfo(PyObject* args) +{ + char* typeName; + if (!PyArg_ParseTuple(args, "s", &typeName)) + return 0; + + try { + AttachEngine &attacher = *(this->getAttachEnginePtr()); + eRefType rt = attacher.getRefTypeByName(typeName); + Py::Dict ret; + ret["TypeIndex"] = Py::Int(rt); + + try { + Py::Module module(PyImport_ImportModule("PartGui"),true); + if (!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::Int(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.getTypeInfo: error obtaining GUI strings\n"); + e.clear(); + } + } catch (Base::Exception &e){ + Base::Console().Warning("AttachEngine.getTypeInfo: 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) { if (!PyArg_ParseTuple(args, "")) From 98a472b18dbc28a15b2b7881b361d09bf1dd5aa4 Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Fri, 13 May 2016 18:41:12 +0300 Subject: [PATCH 15/17] Attacher: Py: renames AttachEngine attributes and methods: getShapeType -> getRefTypeOfShape isShapeOfType -> isFittingRefType downgradeType -> downgradeRefType getTypeRank -> deleted (rank exposed through getRefTypeInfo ) getTypeInfo -> getRefTypeInfo suggestMapModes -> suggestModes --- src/Mod/Part/App/AttachEnginePy.xml | 25 +++++++++-------------- src/Mod/Part/App/AttachEnginePyImp.cpp | 28 ++++++++------------------ 2 files changed, 18 insertions(+), 35 deletions(-) diff --git a/src/Mod/Part/App/AttachEnginePy.xml b/src/Mod/Part/App/AttachEnginePy.xml index ac06a8d60..ac9c36470 100644 --- a/src/Mod/Part/App/AttachEnginePy.xml +++ b/src/Mod/Part/App/AttachEnginePy.xml @@ -77,29 +77,24 @@ getModeInfo(mode): returns supported reference combinations, user-friendly name, and so on. - + - getShapeType(shape): returns shape type as interpreted by AttachEngine. Returns a string. + getRefTypeOfShape(shape): returns shape type as interpreted by AttachEngine. Returns a string. - + - isShapeOfType(type_shape, type_needed): tests if shape type, specified by type_shape (string), fits a type required by attachment mode type_needed (string). e.g. 'Circle' fits a requirement of 'Edge', and 'Curve' doesn't fit if a 'Circle' is required. + isFittingRefType(type_shape, type_needed): tests if shape type, specified by type_shape (string), fits a type required by attachment mode type_needed (string). e.g. 'Circle' fits a requirement of 'Edge', and 'Curve' doesn't fit if a 'Circle' is required. - + - downgradeType(type): returns next more general type. E.g. downgradeType('Circle') yeilds 'Curve'. + downgradeRefType(type): returns next more general type. E.g. downgradeType('Circle') yeilds 'Curve'. - + - getTypeRank(type): returns rank of shape type. Rank is how many times the type can be downgraded, before it becomes 'Any'. - - - - - getTypeInfo(type): returns information (dict) on shape type. Keys:'UserFriendlyName', 'TypeIndex'. + getRefTypeInfo(type): returns information (dict) on shape type. Keys:'UserFriendlyName', 'TypeIndex'. @@ -120,10 +115,10 @@ Returns the new placement. If not attached, returns None. If attachment fails, an exception is raised. - + -suggestMapModes(): runs mode suggestion routine and returns a dictionary with +suggestModes(): runs mode suggestion routine and returns a dictionary with results and supplementary information. Keys: diff --git a/src/Mod/Part/App/AttachEnginePyImp.cpp b/src/Mod/Part/App/AttachEnginePyImp.cpp index 576548895..9984218c3 100644 --- a/src/Mod/Part/App/AttachEnginePyImp.cpp +++ b/src/Mod/Part/App/AttachEnginePyImp.cpp @@ -292,7 +292,7 @@ PyObject* AttachEnginePy::getModeInfo(PyObject* args) } ATTACHERPY_STDCATCH_METH; } -PyObject* AttachEnginePy::getShapeType(PyObject* args) +PyObject* AttachEnginePy::getRefTypeOfShape(PyObject* args) { PyObject *pcObj; if (!PyArg_ParseTuple(args, "O!", &(Part::TopoShapePy::Type), &pcObj)) @@ -305,7 +305,7 @@ PyObject* AttachEnginePy::getShapeType(PyObject* args) } ATTACHERPY_STDCATCH_METH; } -PyObject* AttachEnginePy::isShapeOfType(PyObject* args) +PyObject* AttachEnginePy::isFittingRefType(PyObject* args) { char* type_shape_str; char* type_need_str; @@ -319,7 +319,7 @@ PyObject* AttachEnginePy::isShapeOfType(PyObject* args) } ATTACHERPY_STDCATCH_METH; } -PyObject* AttachEnginePy::downgradeType(PyObject* args) +PyObject* AttachEnginePy::downgradeRefType(PyObject* args) { char* type_shape_str; if (!PyArg_ParseTuple(args, "s", &type_shape_str)) @@ -331,20 +331,7 @@ PyObject* AttachEnginePy::downgradeType(PyObject* args) } ATTACHERPY_STDCATCH_METH; } -PyObject* AttachEnginePy::getTypeRank(PyObject* args) -{ - char* type_shape_str; - if (!PyArg_ParseTuple(args, "s", &type_shape_str)) - return 0; - try { - eRefType type_shape = AttachEngine::getRefTypeByName(std::string(type_shape_str)); - int result = AttachEngine::getTypeRank(type_shape); - return Py::new_reference_to(Py::Int(result)); - } ATTACHERPY_STDCATCH_METH; - -} - -PyObject* AttachEnginePy::getTypeInfo(PyObject* args) +PyObject* AttachEnginePy::getRefTypeInfo(PyObject* args) { char* typeName; if (!PyArg_ParseTuple(args, "s", &typeName)) @@ -355,6 +342,7 @@ PyObject* AttachEnginePy::getTypeInfo(PyObject* args) eRefType rt = attacher.getRefTypeByName(typeName); Py::Dict ret; ret["TypeIndex"] = Py::Int(rt); + ret["Rank"] = Py::Int(AttachEngine::getTypeRank(rt)); try { Py::Module module(PyImport_ImportModule("PartGui"),true); @@ -374,11 +362,11 @@ PyObject* AttachEnginePy::getTypeInfo(PyObject* args) Base::Console().Warning("AttachEngine: Gui not up, so no gui-related entries in getModeInfo.\n"); e.clear(); } else { - Base::Console().Warning("AttachEngine.getTypeInfo: error obtaining GUI strings\n"); + Base::Console().Warning("AttachEngine.getRefTypeInfo: error obtaining GUI strings\n"); e.clear(); } } catch (Base::Exception &e){ - Base::Console().Warning("AttachEngine.getTypeInfo: error obtaining GUI strings:"); + Base::Console().Warning("AttachEngine.getRefTypeInfo: error obtaining GUI strings:"); Base::Console().Warning(e.what()); Base::Console().Warning("\n"); } @@ -415,7 +403,7 @@ PyObject* AttachEnginePy::calculateAttachedPlacement(PyObject* args) return NULL; } -PyObject* AttachEnginePy::suggestMapModes(PyObject* args) +PyObject* AttachEnginePy::suggestModes(PyObject* args) { if (!PyArg_ParseTuple(args, "")) return 0; From 2d8a7614c5e97f3449fbb5f9f39458735914b1f0 Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Sat, 14 May 2016 00:50:30 +0300 Subject: [PATCH 16/17] Attacher: Py: fix docu strings --- src/Mod/Part/App/AttachEnginePy.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Mod/Part/App/AttachEnginePy.xml b/src/Mod/Part/App/AttachEnginePy.xml index ac9c36470..99a605674 100644 --- a/src/Mod/Part/App/AttachEnginePy.xml +++ b/src/Mod/Part/App/AttachEnginePy.xml @@ -67,9 +67,9 @@ - List of all attachment modes of all AttachEngines. This is the list of modes in MapMode enum properties of AttachableObjects. + List of all reference shape types recognized by AttachEngine. - + @@ -94,7 +94,7 @@ - getRefTypeInfo(type): returns information (dict) on shape type. Keys:'UserFriendlyName', 'TypeIndex'. + getRefTypeInfo(type): returns information (dict) on shape type. Keys:'UserFriendlyName', 'TypeIndex', 'Rank'. Rank is the number of times reftype can be downgraded, before it becomes 'Any'. From 71f70eb8558d527a2a4ed9b0a4be053f1e558862 Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Sat, 14 May 2016 02:14:51 +0300 Subject: [PATCH 17/17] AttachEngine: fix crash when referenced objects get deleted ... by verifying if the pointers equal to objects contained in all open documents. Not terribly good, but I can't think of a situation where doing this search might cause trouble. --- src/Mod/Part/App/AttachEnginePyImp.cpp | 2 ++ src/Mod/Part/App/Attacher.cpp | 20 ++++++++++++++++++++ src/Mod/Part/App/Attacher.h | 6 ++++++ 3 files changed, 28 insertions(+) diff --git a/src/Mod/Part/App/AttachEnginePyImp.cpp b/src/Mod/Part/App/AttachEnginePyImp.cpp index 9984218c3..e497dcbcf 100644 --- a/src/Mod/Part/App/AttachEnginePyImp.cpp +++ b/src/Mod/Part/App/AttachEnginePyImp.cpp @@ -111,6 +111,7 @@ Py::Object AttachEnginePy::getReferences(void) const { try { AttachEngine &attacher = *(this->getAttachEnginePtr()); + AttachEngine::verifyReferencesAreSafe(attacher.references); return Py::Object(attacher.references.getPyObject(),true); } ATTACHERPY_STDCATCH_ATTR; } @@ -523,6 +524,7 @@ PyObject* AttachEnginePy::writeParametersToFeature(PyObject* args) } Part::AttachableObject* feat = static_cast(dobj); const AttachEngine &attacher = *(this->getAttachEnginePtr()); + AttachEngine::verifyReferencesAreSafe(attacher.references); feat->Support.Paste(attacher.references); feat->MapMode.setValue(attacher.mapMode); feat->MapReversed.setValue(attacher.mapReverse); diff --git a/src/Mod/Part/App/Attacher.cpp b/src/Mod/Part/App/Attacher.cpp index d0a83b0d8..9fbbc085d 100644 --- a/src/Mod/Part/App/Attacher.cpp +++ b/src/Mod/Part/App/Attacher.cpp @@ -61,6 +61,8 @@ #include "Attacher.h" #include #include +#include +#include using namespace Part; using namespace Attacher; @@ -749,6 +751,7 @@ void AttachEngine::readLinks(const App::PropertyLinkSubList &references, std::vector &storage, std::vector &types) { + verifyReferencesAreSafe(references); const std::vector &objs = references.getValues(); const std::vector &sub = references.getSubValues(); geofs.resize(objs.size()); @@ -830,6 +833,23 @@ void AttachEngine::throwWrongMode(eMapMode mmode) throw Base::Exception(errmsg.str().c_str()); } +void AttachEngine::verifyReferencesAreSafe(const App::PropertyLinkSubList &references) +{ + const std::vector links = references.getValues(); + const std::vector docs = App::GetApplication().getDocuments(); + for(App::DocumentObject* lnk : links){ + bool found = false; + for(App::Document* doc : docs){ + if(doc->isIn(lnk)){ + found = true; + } + } + if (!found){ + throw Base::Exception("AttachEngine: verifyReferencesAreSafe: references point to deleted object."); + } + } +} + //================================================================================= diff --git a/src/Mod/Part/App/Attacher.h b/src/Mod/Part/App/Attacher.h index c0e880401..b2d22b637 100644 --- a/src/Mod/Part/App/Attacher.h +++ b/src/Mod/Part/App/Attacher.h @@ -342,6 +342,12 @@ public://helper functions that may be useful outside of the class static GProp_GProps getInertialPropsOfShape(const std::vector &shapes); + /** + * @brief verifyReferencesAreSafe: checks if pointers in references still + * point to objects contained in open documents. This guarantees the links + * are valid. Throws Base::Exception if invalid links are found. + */ + static void verifyReferencesAreSafe(const App::PropertyLinkSubList& references); public: //enums static const char* eMapModeStrings[];