Support macros and console logs in Assembly
This commit is contained in:
@@ -56,6 +56,18 @@ For a temporary document it returns its transient directory.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getUniqueObjectName">
|
||||
<Documentation>
|
||||
<UserDocu>getUniqueObjectName(objName) -> objName
|
||||
|
||||
Return the same name, or the name made unique, for Example Box -> Box002 if there are conflicting name
|
||||
already in the document.
|
||||
|
||||
ObjName : str
|
||||
Object name.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="mergeProject">
|
||||
<Documentation>
|
||||
<UserDocu>Merges this document with another project file</UserDocu>
|
||||
|
||||
@@ -217,6 +217,18 @@ PyObject* DocumentPy::getFileName(PyObject* args)
|
||||
return Py::new_reference_to(Py::String(fn));
|
||||
}
|
||||
|
||||
PyObject* DocumentPy::getUniqueObjectName(PyObject *args)
|
||||
{
|
||||
char *sName;
|
||||
if (!PyArg_ParseTuple(args, "s", &sName))
|
||||
return nullptr;
|
||||
PY_TRY {
|
||||
auto newName = getDocumentPtr()->getUniqueObjectName(sName);
|
||||
return Py::new_reference_to(Py::String(newName));
|
||||
}
|
||||
PY_CATCH;
|
||||
}
|
||||
|
||||
PyObject* DocumentPy::mergeProject(PyObject * args)
|
||||
{
|
||||
char* filename;
|
||||
|
||||
@@ -159,7 +159,7 @@ DocumentObject *GeoFeature::resolveElement(DocumentObject *obj, const char *subn
|
||||
}
|
||||
if(geoFeature)
|
||||
*geoFeature = geo;
|
||||
if(!obj || (filter && geo!=filter))
|
||||
if(filter && geo!=filter)
|
||||
return nullptr;
|
||||
if(!element || !element[0]) {
|
||||
if(append)
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#define putpix()
|
||||
|
||||
#include <App/Application.h>
|
||||
|
||||
class QCloseEvent;
|
||||
@@ -340,6 +338,8 @@ public:
|
||||
|
||||
static PyObject* sDoCommand (PyObject *self,PyObject *args);
|
||||
static PyObject* sDoCommandGui (PyObject *self,PyObject *args);
|
||||
static PyObject* sDoCommandEval (PyObject *self,PyObject *args);
|
||||
static PyObject* sDoCommandSkip (PyObject *self,PyObject *args);
|
||||
static PyObject* sAddModule (PyObject *self,PyObject *args);
|
||||
|
||||
static PyObject* sShowDownloads (PyObject *self,PyObject *args);
|
||||
|
||||
@@ -316,6 +316,19 @@ PyMethodDef Application::Methods[] = {
|
||||
"but doesn't record it in macros.\n"
|
||||
"\n"
|
||||
"cmd : str"},
|
||||
{"doCommandEval", (PyCFunction) Application::sDoCommandEval, METH_VARARGS,
|
||||
"doCommandEval(cmd) -> PyObject\n"
|
||||
"\n"
|
||||
"Runs the given string without showing in the python console or recording in\n"
|
||||
"macros, and returns the result.\n"
|
||||
"\n"
|
||||
"cmd : str"},
|
||||
{"doCommandSkip", (PyCFunction) Application::sDoCommandSkip, METH_VARARGS,
|
||||
"doCommandSkip(cmd) -> None\n"
|
||||
"\n"
|
||||
"Record the given string in the Macro but comment it out in the console\n"
|
||||
"\n"
|
||||
"cmd : str"},
|
||||
{"addModule", (PyCFunction) Application::sAddModule, METH_VARARGS,
|
||||
"addModule(mod) -> None\n"
|
||||
"\n"
|
||||
@@ -1352,6 +1365,43 @@ PyObject* Application::sDoCommandGui(PyObject * /*self*/, PyObject *args)
|
||||
return PyRun_String(sCmd, Py_file_input, dict, dict);
|
||||
}
|
||||
|
||||
PyObject* Application::sDoCommandEval(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
char *sCmd = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "s", &sCmd))
|
||||
return nullptr;
|
||||
|
||||
Gui::Command::LogDisabler d1;
|
||||
Gui::SelectionLogDisabler d2;
|
||||
|
||||
PyObject *module, *dict;
|
||||
|
||||
Base::PyGILStateLocker locker;
|
||||
module = PyImport_AddModule("__main__");
|
||||
if (!module)
|
||||
return nullptr;
|
||||
|
||||
dict = PyModule_GetDict(module);
|
||||
if (!dict)
|
||||
return nullptr;
|
||||
|
||||
return PyRun_String(sCmd, Py_eval_input, dict, dict);
|
||||
}
|
||||
|
||||
PyObject* Application::sDoCommandSkip(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
char *sCmd = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "s", &sCmd))
|
||||
return nullptr;
|
||||
|
||||
Gui::Command::LogDisabler d1;
|
||||
Gui::SelectionLogDisabler d2;
|
||||
|
||||
Gui::Command::printPyCaller();
|
||||
Gui::Application::Instance->macroManager()->addLine(MacroManager::App, sCmd);
|
||||
return Py::None().ptr();
|
||||
}
|
||||
|
||||
PyObject* Application::sAddModule(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
char *pstr;
|
||||
|
||||
@@ -70,15 +70,24 @@ class CommandCreateAssembly:
|
||||
App.setActiveTransaction("Create assembly")
|
||||
|
||||
activeAssembly = UtilsAssembly.activeAssembly()
|
||||
Gui.addModule("UtilsAssembly")
|
||||
if activeAssembly:
|
||||
assembly = activeAssembly.newObject("Assembly::AssemblyObject", "Assembly")
|
||||
commands = (
|
||||
"activeAssembly = UtilsAssembly.activeAssembly()\n"
|
||||
'assembly = activeAssembly.newObject("Assembly::AssemblyObject", "Assembly")\n'
|
||||
)
|
||||
else:
|
||||
assembly = App.ActiveDocument.addObject("Assembly::AssemblyObject", "Assembly")
|
||||
commands = (
|
||||
'assembly = App.ActiveDocument.addObject("Assembly::AssemblyObject", "Assembly")\n'
|
||||
)
|
||||
|
||||
assembly.Type = "Assembly"
|
||||
commands = commands + 'assembly.Type = "Assembly"\n'
|
||||
commands = commands + 'assembly.newObject("Assembly::JointGroup", "Joints")'
|
||||
|
||||
Gui.doCommand(commands)
|
||||
if not activeAssembly:
|
||||
Gui.ActiveDocument.setEdit(assembly)
|
||||
assembly.newObject("Assembly::JointGroup", "Joints")
|
||||
Gui.doCommandGui("Gui.ActiveDocument.setEdit(assembly)")
|
||||
|
||||
App.closeActiveTransaction()
|
||||
|
||||
|
||||
|
||||
@@ -324,11 +324,16 @@ class TaskAssemblyCreateBom(QtCore.QObject):
|
||||
|
||||
def createBomObject(self):
|
||||
assembly = UtilsAssembly.activeAssembly()
|
||||
Gui.addModule("UtilsAssembly")
|
||||
if assembly is not None:
|
||||
bom_group = UtilsAssembly.getBomGroup(assembly)
|
||||
self.bomObj = bom_group.newObject("Assembly::BomObject", "Bill of Materials")
|
||||
commands = (
|
||||
"bom_group = UtilsAssembly.getBomGroup(assembly)\n"
|
||||
'bomObj = bom_group.newObject("Assembly::BomObject", "Bill of Materials")'
|
||||
)
|
||||
else:
|
||||
self.bomObj = App.activeDocument().addObject("Assembly::BomObject", "Bill of Materials")
|
||||
commands = 'bomObj = App.activeDocument().addObject("Assembly::BomObject", "Bill of Materials")'
|
||||
Gui.doCommand(commands)
|
||||
self.bomObj = Gui.doCommandEval("bomObj")
|
||||
|
||||
def export(self):
|
||||
self.bomObj.recompute()
|
||||
|
||||
@@ -58,8 +58,10 @@ def activateJoint(index):
|
||||
if JointObject.activeTask:
|
||||
JointObject.activeTask.reject()
|
||||
|
||||
panel = TaskAssemblyCreateJoint(index)
|
||||
dialog = Gui.Control.showDialog(panel)
|
||||
Gui.addModule("JointObject") # NOLINT
|
||||
Gui.doCommand(f"panel = JointObject.TaskAssemblyCreateJoint({index})")
|
||||
Gui.doCommandGui("dialog = Gui.Control.showDialog(panel)")
|
||||
dialog = Gui.doCommandEval("dialog")
|
||||
if dialog is not None:
|
||||
dialog.setAutoCloseOnTransactionChange(True)
|
||||
dialog.setDocumentName(App.ActiveDocument.Name)
|
||||
@@ -476,16 +478,21 @@ class CommandGroupGearBelt:
|
||||
|
||||
|
||||
def createGroundedJoint(obj):
|
||||
assembly = UtilsAssembly.activeAssembly()
|
||||
if not assembly:
|
||||
if not UtilsAssembly.activeAssembly():
|
||||
return
|
||||
|
||||
joint_group = UtilsAssembly.getJointGroup(assembly)
|
||||
|
||||
ground = joint_group.newObject("App::FeaturePython", "GroundedJoint")
|
||||
JointObject.GroundedJoint(ground, obj)
|
||||
JointObject.ViewProviderGroundedJoint(ground.ViewObject)
|
||||
return ground
|
||||
Gui.addModule("UtilsAssembly")
|
||||
Gui.addModule("JointObject")
|
||||
commands = (
|
||||
f'obj = App.ActiveDocument.getObject("{obj.Name}")\n'
|
||||
"assembly = UtilsAssembly.activeAssembly()\n"
|
||||
"joint_group = UtilsAssembly.getJointGroup(assembly)\n"
|
||||
'ground = joint_group.newObject("App::FeaturePython", "GroundedJoint")\n'
|
||||
"JointObject.GroundedJoint(ground, obj)"
|
||||
)
|
||||
Gui.doCommand(commands)
|
||||
Gui.doCommandGui("JointObject.ViewProviderGroundedJoint(ground.ViewObject)")
|
||||
return Gui.doCommandEval("ground")
|
||||
|
||||
|
||||
class CommandToggleGrounded:
|
||||
@@ -540,9 +547,12 @@ class CommandToggleGrounded:
|
||||
ungrounded = False
|
||||
for joint in joint_group.Group:
|
||||
if hasattr(joint, "ObjectToGround") and joint.ObjectToGround == moving_part:
|
||||
doc = App.ActiveDocument
|
||||
doc.removeObject(joint.Name)
|
||||
doc.recompute()
|
||||
commands = (
|
||||
"doc = App.ActiveDocument\n"
|
||||
f'doc.removeObject("{joint.Name}")\n'
|
||||
"doc.recompute()\n"
|
||||
)
|
||||
Gui.doCommand(commands)
|
||||
ungrounded = True
|
||||
break
|
||||
if ungrounded:
|
||||
|
||||
@@ -74,8 +74,10 @@ class CommandCreateView:
|
||||
if not assembly:
|
||||
return
|
||||
|
||||
self.panel = TaskAssemblyCreateView()
|
||||
Gui.Control.showDialog(self.panel)
|
||||
Gui.addModule("CommandCreateView") # NOLINT
|
||||
Gui.doCommand("panel = CommandCreateView.TaskAssemblyCreateView()")
|
||||
self.panel = Gui.doCommandEval("panel")
|
||||
Gui.doCommandGui("Gui.Control.showDialog(panel)")
|
||||
|
||||
|
||||
######### Exploded View Object ###########
|
||||
@@ -524,6 +526,11 @@ class TaskAssemblyCreateView(QtCore.QObject):
|
||||
UtilsAssembly.restoreAssemblyPartsPlacements(self.assembly, self.initialPlcs)
|
||||
for move in self.viewObj.Moves:
|
||||
move.Visibility = False
|
||||
commands = f'obj = App.ActiveDocument.getObject("{self.viewObj.Name}")\n'
|
||||
for move in self.viewObj.Moves:
|
||||
more = UtilsAssembly.generatePropertySettings("obj.Moves[0]", move)
|
||||
commands = commands + more
|
||||
Gui.doCommand(commands[:-1]) # Don't use the last \n
|
||||
App.closeActiveTransaction()
|
||||
return True
|
||||
|
||||
@@ -695,16 +702,27 @@ class TaskAssemblyCreateView(QtCore.QObject):
|
||||
self.blockDraggerMove = False
|
||||
|
||||
def createExplodedViewObject(self):
|
||||
view_group = UtilsAssembly.getViewGroup(self.assembly)
|
||||
self.viewObj = view_group.newObject("App::FeaturePython", "Exploded View")
|
||||
|
||||
ExplodedView(self.viewObj)
|
||||
ViewProviderExplodedView(self.viewObj.ViewObject)
|
||||
Gui.addModule("UtilsAssembly")
|
||||
commands = (
|
||||
f'assembly = App.ActiveDocument.getObject("{self.assembly.Name}")\n'
|
||||
"view_group = UtilsAssembly.getViewGroup(assembly)\n"
|
||||
'viewObj = view_group.newObject("App::FeaturePython", "Exploded View")\n'
|
||||
"CommandCreateView.ExplodedView(viewObj)"
|
||||
)
|
||||
Gui.doCommand(commands)
|
||||
self.viewObj = Gui.doCommandEval("viewObj")
|
||||
Gui.doCommandGui("CommandCreateView.ViewProviderExplodedView(viewObj.ViewObject)")
|
||||
|
||||
def createExplodedStepObject(self, moveType_index=0):
|
||||
self.currentStep = self.assembly.newObject("App::FeaturePython", "Move")
|
||||
ExplodedViewStep(self.currentStep, moveType_index)
|
||||
ViewProviderExplodedViewStep(self.currentStep.ViewObject)
|
||||
commands = (
|
||||
f'assembly = App.ActiveDocument.getObject("{self.assembly.Name}")\n'
|
||||
'currentStep = assembly.newObject("App::FeaturePython", "Move")\n'
|
||||
f"CommandCreateView.ExplodedViewStep(currentStep, {moveType_index})"
|
||||
)
|
||||
Gui.doCommand(commands)
|
||||
self.currentStep = Gui.doCommandEval("currentStep")
|
||||
Gui.doCommandGui("CommandCreateView.ViewProviderExplodedViewStep(currentStep.ViewObject)")
|
||||
|
||||
self.currentStep.MovementTransform = App.Placement()
|
||||
|
||||
@@ -727,7 +745,7 @@ class TaskAssemblyCreateView(QtCore.QObject):
|
||||
for obj, init_plc in zip(self.selectedObjs, self.selectedObjsInitPlc):
|
||||
obj.Placement = init_plc
|
||||
|
||||
self.currentStep.Document.removeObject(self.currentStep.Name)
|
||||
Gui.doCommand(f'App.ActiveDocument.removeObject("{self.currentStep.Name}")')
|
||||
self.currentStep = None
|
||||
|
||||
Gui.Selection.clearSelection()
|
||||
|
||||
@@ -74,7 +74,7 @@ class CommandExportASMT:
|
||||
)
|
||||
|
||||
if filePath:
|
||||
assembly.exportAsASMT(filePath)
|
||||
Gui.doCommand(f'assembly.exportAsASMT("{filePath}")')
|
||||
|
||||
|
||||
if App.GuiUp:
|
||||
|
||||
@@ -80,7 +80,6 @@ class CommandInsertLink:
|
||||
if not assembly:
|
||||
return
|
||||
view = Gui.activeDocument().activeView()
|
||||
|
||||
self.panel = TaskAssemblyInsertLink(assembly, view)
|
||||
Gui.Control.showDialog(self.panel)
|
||||
|
||||
@@ -125,7 +124,32 @@ class TaskAssemblyInsertLink(QtCore.QObject):
|
||||
|
||||
# if self.partMoving:
|
||||
# self.endMove()
|
||||
Gui.addModule("UtilsAssembly")
|
||||
commands = "assembly = UtilsAssembly.activeAssembly()\n"
|
||||
for insertionItem in self.insertionStack:
|
||||
object = insertionItem["addedObject"]
|
||||
translation = insertionItem["translation"]
|
||||
commands = commands + (
|
||||
f'item = assembly.newObject("App::Link", "{object.Name}")\n'
|
||||
f'item.LinkedObject = App.ActiveDocument.getObject("{object.LinkedObject.Name}")\n'
|
||||
f'item.Label = "{object.Label}"\n'
|
||||
)
|
||||
|
||||
if translation != App.Vector():
|
||||
commands = commands + (
|
||||
f"item.Placement.base = App.Vector({translation.x}."
|
||||
f"{translation.y},"
|
||||
f"{translation.z})\n"
|
||||
)
|
||||
|
||||
# Ground the first item if that happened
|
||||
if self.groundedObj:
|
||||
commands = (
|
||||
commands
|
||||
+ f'CommandCreateJoint.createGroundedJoint(App.ActiveDocument.getObject("{self.groundedObj.Name}"))\n'
|
||||
)
|
||||
|
||||
Gui.doCommandSkip(commands[:-1]) # Get rid of last \n
|
||||
App.closeActiveTransaction()
|
||||
return True
|
||||
|
||||
|
||||
@@ -67,8 +67,9 @@ class CommandSolveAssembly:
|
||||
if not assembly:
|
||||
return
|
||||
|
||||
Gui.addModule("UtilsAssembly")
|
||||
App.setActiveTransaction("Solve assembly")
|
||||
assembly.solve()
|
||||
Gui.doCommand("UtilsAssembly.activeAssembly().solve()")
|
||||
App.closeActiveTransaction()
|
||||
|
||||
|
||||
|
||||
@@ -1417,6 +1417,9 @@ class TaskAssemblyCreateJoint(QtCore.QObject):
|
||||
else:
|
||||
self.joint.Document.removeObject(self.joint.Name)
|
||||
|
||||
cmds = UtilsAssembly.generatePropertySettings("obj", self.joint)
|
||||
Gui.doCommand(cmds)
|
||||
|
||||
App.closeActiveTransaction()
|
||||
return True
|
||||
|
||||
|
||||
@@ -1170,3 +1170,34 @@ def getParentPlacementIfNeeded(part):
|
||||
return linkGroup.Placement
|
||||
|
||||
return Base.Placement()
|
||||
|
||||
|
||||
def generatePropertySettings(objectName, documentObject):
|
||||
commands = []
|
||||
if hasattr(documentObject, "Name"):
|
||||
commands.append(f'{objectName} = App.ActiveDocument.getObject("{documentObject.Name}")')
|
||||
for propertyName in documentObject.PropertiesList:
|
||||
propertyValue = documentObject.getPropertyByName(propertyName)
|
||||
propertyType = documentObject.getTypeIdOfProperty(propertyName)
|
||||
# Note: OpenCascade precision is 1e-07, angular precision is 1e-05. For purposes of creating a Macro,
|
||||
# we are forcing a reduction in precision so as to get round numbers like 0 instead of tiny near 0 values
|
||||
if propertyType == "App::PropertyFloat":
|
||||
commands.append(f"{objectName}.{propertyName} = {propertyValue:.5f}")
|
||||
elif propertyType == "App::PropertyInt" or propertyType == "App::PropertyBool":
|
||||
commands.append(f"{objectName}.{propertyName} = {propertyValue}")
|
||||
elif propertyType == "App::PropertyString" or propertyType == "App::PropertyEnumeration":
|
||||
commands.append(f'{objectName}.{propertyName} = "{propertyValue}"')
|
||||
elif propertyType == "App::PropertyPlacement":
|
||||
commands.append(
|
||||
f"{objectName}.{propertyName} = App.Placement("
|
||||
f"App.Vector({propertyValue.Base.x:.5f},{propertyValue.Base.y:.5f},{propertyValue.Base.z:.5f}),"
|
||||
f"App.Rotation(*{[round(n,5) for n in propertyValue.Rotation.getYawPitchRoll()]}))"
|
||||
)
|
||||
elif propertyType == "App::PropertyXLinkSubHidden":
|
||||
commands.append(
|
||||
f'{objectName}.{propertyName} = [App.ActiveDocument.getObject("{propertyValue[0].Name}"), {propertyValue[1]}]'
|
||||
)
|
||||
else:
|
||||
# print("Not processing properties of type ", propertyType)
|
||||
pass
|
||||
return "\n".join(commands) + "\n"
|
||||
|
||||
Reference in New Issue
Block a user