Temporarily remove object - re-add in FreeCAD Python?

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
sdaau_ml
Posts: 35
Joined: Fri Dec 07, 2018 12:18 am

Temporarily remove object - re-add in FreeCAD Python?

Post by sdaau_ml »

Code: Select all

OS: Ubuntu 18.04.1 LTS
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.18.15379 (Git)
Build type: Release
Branch: master
Hash: 3290c36d28551875f02333c2e01af80e38b8ad02
Python version: 2.7.15rc1
Qt version: 4.8.7
Coin version: 4.0.0a
OCC version: 7.3.0
Locale: English/UnitedStates (en_US)
I'd like to write a script, where I save a copy of the document with one set of objects removed, second and third set of objects present; and a copy of the same document but with second set of objects removed, and first and third set of objects present.

Conceptually, it would be easiest for me to store references to objects in arrays/lists, then remove/add objects from these lists to the document before each save. So I'm stuck at whether it is possibly to remove an object only temporarily from a FreeCAD document - that is, whether it is possible to re-add it again once it is removed.

So, let's say I have some object in FreeCAD, and I get a reference to it thus:

Code: Select all

myobj = App.ActiveDocument.getObject("MyObject")
Then, if after some time, I remove that object from the document:

Code: Select all

App.ActiveDocument.removeObject("MyObject")
... it clearly disappears from view - but if I enter the object reference myobj on the Python console in FreeCAD, I can see it still has data (though trying, say myobj. so as to try to raise autocomplete, typically causes FreeCAD to crash).

Now, the thing is, just like .getObject and .removeObject, also .addObject operates on strings, including the object name. So I cannot use an object reference with it. There is App.ActiveDocument.Objects list, but it is read-only, and doing .append(myobj) on it is silently ignored.

Now, the thing is, this object could be a result of some complex calculation, and so I wouldn't want to reinstantiate it at this point. Therefore, the best for me would be to re-add it to the document from the existing object reference and memory content. Is there a FreeCAD Python command (or approach) which would allow for that?
wmayer
Founder
Posts: 20319
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: Temporarily remove object - re-add in FreeCAD Python?

Post by wmayer »

In order to remove an object tmp. from the document you must open a transaction, remove the object(s) and commit the transaction. After having saved the document just call undo.

Code: Select all

doc=App.newDocument()
box=doc.addObject("Part::Box").Name
cyl=doc.addObject("Part::Cylinder").Name
sph=doc.addObject("Part::Sphere").Name
doc.recompute()

doc.openTransaction("Remove object")
doc.removeObject(box)
doc.commitTransaction()
doc.saveAs("doc1.FCStd")
doc.undo()

doc.openTransaction("Remove object")
doc.removeObject(cyl)
doc.commitTransaction()
doc.saveAs("doc2.FCStd")
doc.undo()

doc.openTransaction("Remove object")
doc.removeObject(sph)
doc.commitTransaction()
doc.saveAs("doc3.FCStd")
doc.undo()
But you must be careful between opening and undoing a transaction not to call any other function that internally opens a transaction or adding/removing objects because otherwise you will mess up your document.
... it clearly disappears from view - but if I enter the object reference myobj on the Python console in FreeCAD, I can see it still has data (though trying, say myobj. so as to try to raise autocomplete, typically causes FreeCAD to crash).
FreeCAD shouldn't crash. However, myobj is getting invalidated and when trying to access it a ReferenceError should be raised.
sdaau_ml
Posts: 35
Joined: Fri Dec 07, 2018 12:18 am

Re: Temporarily remove object - re-add in FreeCAD Python?

Post by sdaau_ml »

Many thanks @wmayer:
wmayer wrote: Sat Jan 12, 2019 4:01 pm In order to remove an object tmp. from the document you must open a transaction, remove the object(s) and commit the transaction. After having saved the document just call undo.
...
But you must be care between opening and undoing a transaction not to call any other function that internally opens a transaction or adding/removing objects because otherwise you will mess up your document.
Great suggestion, thanks - just to mention, also Select All, Cut, Copy and Paste in FreeCAD Python is a possibility here, too...
wmayer wrote: Sat Jan 12, 2019 4:01 pm FreeCAD shouldn't crash. However, myobj is getting invalidated and when trying to access it a ReferenceError should be raised.
Just tried it again, with my version of FreeCAD: startup, Ctrl-N for new file, Draft/Circle - draw any circle, then:

Code: Select all

myobj = App.ActiveDocument.getObject("Circle")
App.ActiveDocument.removeObject("Circle")
myobj.
As soon as I type the dot, FreeCAD crashes, here is my stack trace printed in terminal:

Code: Select all

...
Circle options : [:Increase snap radius, Z:Restrict Z, Q:Add custom snap point, ]:Decrease snap radius, Y:Restrict Y, X:Restrict X, S:Snap On/Off

Pick center point:
Pick radius:

Program received signal SIGSEGV, Segmentation fault.
#0  /lib/x86_64-linux-gnu/libc.so.6(+0x3ef20) [0x7fcd48c30f20]
#1  /lib/x86_64-linux-gnu/libc.so.6(+0x18e5a1) [0x7fcd48d805a1]
#2  0x7fcd1056a8ba in App::FeaturePythonT<Part::Part2DObject>::Save(Base::Writer&) const from /path/to/freecad-build-18.04/Mod/Part/Part.so+0x1a
#3  0x7fcd4adeb6a6 in Base::PersistencePy::getContent() const from /path/to/freecad-build-18.04/lib/libFreeCADBase.so+0x246
#4  0x7fcd4adebced in Base::PersistencePy::staticCallback_getContent(_object*, void*) from /path/to/freecad-build-18.04/lib/libFreeCADBase.so+0x2d
#5  /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(_PyObject_GenericGetAttrWithDict+0xbb) [0x7fcd4a8c2feb]
#6  0x7fcd4adf33de in Base::PyObjectBase::_getattr(char const*) from /path/to/freecad-build-18.04/lib/libFreeCADBase.so+0xce
#7  0x7fcd4ad83178 in Base::BaseClassPy::_getattr(char const*) from /path/to/freecad-build-18.04/lib/libFreeCADBase.so+0xb8
#8  0x7fcd4adec688 in Base::PersistencePy::_getattr(char const*) from /path/to/freecad-build-18.04/lib/libFreeCADBase.so+0xb8
#9  0x7fcd4b2dc0e8 in App::PropertyContainerPy::_getattr(char const*) from /path/to/freecad-build-18.04/lib/libFreeCADApp.so+0xb8
#10  0x7fcd4b24d698 in App::ExtensionContainerPy::_getattr(char const*) from /path/to/freecad-build-18.04/lib/libFreeCADApp.so+0xb8
#11  0x7fcd4b25f7c8 in App::DocumentObjectPy::_getattr(char const*) from /path/to/freecad-build-18.04/lib/libFreeCADApp.so+0xb8
#12  0x7fcd4b258af8 in App::GeoFeaturePy::_getattr(char const*) from /path/to/freecad-build-18.04/lib/libFreeCADApp.so+0xb8
#13  0x7fcd10627998 in Part::PartFeaturePy::_getattr(char const*) from /path/to/freecad-build-18.04/Mod/Part/Part.so+0xb8
#14  0x7fcd10629398 in Part::Part2DObjectPy::_getattr(char const*) from /path/to/freecad-build-18.04/Mod/Part/Part.so+0xb8
#15  0x7fcd4adf3f9d in Base::PyObjectBase::__getattro(_object*, _object*) from /path/to/freecad-build-18.04/lib/libFreeCADBase.so+0x9d
#16  /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_GetAttrString+0x34) [0x7fcd4a8c21f4]
#17  0x7fcd4bb553dd in Gui::CallTipsList::extractTipsFromObject(Py::Object&, Py::List&, QMap<QString, Gui::CallTip>&) const from /path/to/freecad-build-18.04/lib/libFreeCADGui.so+0x21d
#18  0x7fcd4bb577d5 in Gui::CallTipsList::extractTips(QString const&) const from /path/to/freecad-build-18.04/lib/libFreeCADGui.so+0xb55
#19  0x7fcd4bb5808f in Gui::CallTipsList::showTips(QString const&) from /path/to/freecad-build-18.04/lib/libFreeCADGui.so+0x1df
#20  0x7fcd4bb655e3 in Gui::PythonConsole::keyPressEvent(QKeyEvent*) from /path/to/freecad-build-18.04/lib/libFreeCADGui.so+0x513
#21  0x7fcd49c923d3 in QWidget::event(QEvent*) from /usr/lib/x86_64-linux-gnu/libQtGui.so.4+0xd43
#22  0x7fcd4a05b65e in QFrame::event(QEvent*) from /usr/lib/x86_64-linux-gnu/libQtGui.so.4+0x1e
#23  0x7fcd4a0e0dab in QAbstractScrollArea::event(QEvent*) from /usr/lib/x86_64-linux-gnu/libQtGui.so.4+0x2bb
#24  0x7fcd4a0ff605 in QPlainTextEdit::event(QEvent*) from /usr/lib/x86_64-linux-gnu/libQtGui.so.4+0x55
#25  0x7fcd49c3b03c in QApplicationPrivate::notify_helper(QObject*, QEvent*) from /usr/lib/x86_64-linux-gnu/libQtGui.so.4+0x8c
#26  0x7fcd49c432c3 in QApplication::notify(QObject*, QEvent*) from /usr/lib/x86_64-linux-gnu/libQtGui.so.4+0x1603
#27  0x7fcd4b9f9568 in Gui::GUIApplication::notify(QObject*, QEvent*) from /path/to/freecad-build-18.04/lib/libFreeCADGui.so+0x88
#28  0x7fcd4970e8ad in QCoreApplication::notifyInternal(QObject*, QEvent*) from /usr/lib/x86_64-linux-gnu/libQtCore.so.4+0x8d
#29  /usr/lib/x86_64-linux-gnu/libQtGui.so.4(+0x26f703) [0x7fcd49ce5703]
#30  /usr/lib/x86_64-linux-gnu/libQtGui.so.4(+0x26fc12) [0x7fcd49ce5c12]
#31  0x7fcd49cbdd81 in QApplication::x11ProcessEvent(_XEvent*) from /usr/lib/x86_64-linux-gnu/libQtGui.so.4+0x751
#32  /usr/lib/x86_64-linux-gnu/libQtGui.so.4(+0x272592) [0x7fcd49ce8592]
#33  /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0(g_main_context_dispatch+0x2e7) [0x7fcd42700387]
#34  /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0(+0x4c5c0) [0x7fcd427005c0]
#35  /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0(g_main_context_iteration+0x2c) [0x7fcd4270064c]
#36  0x7fcd4973f20e in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) from /usr/lib/x86_64-linux-gnu/libQtCore.so.4+0x7e
#37  /usr/lib/x86_64-linux-gnu/libQtGui.so.4(+0x272666) [0x7fcd49ce8666]
#38  0x7fcd4970d12f in QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) from /usr/lib/x86_64-linux-gnu/libQtCore.so.4+0x3f
#39  0x7fcd4970d495 in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) from /usr/lib/x86_64-linux-gnu/libQtCore.so.4+0x1b5
#40  0x7fcd49713459 in QCoreApplication::exec() from /usr/lib/x86_64-linux-gnu/libQtCore.so.4+0x99
#41  0x7fcd4b985a1a in Gui::Application::runApplication() from /path/to/freecad-build-18.04/lib/libFreeCADGui.so+0x16ba
#42  /path/to/freecad-build-18.04/bin/FreeCAD(main+0x6db) [0x559dfb90e3db]
#43  /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7) [0x7fcd48c13b97]
#44  /path/to/freecad-build-18.04/bin/FreeCAD(_start+0x2a) [0x559dfb90f58a]
Since it happens in `App::FeaturePythonT<Part::Part2DObject>::Save(Base::Writer&)`, maybe it is because I'm doing this in an "Unnamed" file, which is saved nowhere yet?
wmayer
Founder
Posts: 20319
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: Temporarily remove object - re-add in FreeCAD Python?

Post by wmayer »

Post Reply