Given a FreeCAD model that consists of
the python script below opens this model, changes the radius cell in the Spreadsheet to 15, call recompute() on the spreadsheet, invokes touch() on the icosahedron, calls recompute() on the document, and finally tessellates the icosahedron. The z coordinate of the vertex at index 11 in the tessellated mesh happens to be equal to the icosahedron's radius. I was expecting it to change to 15, according to the parameter change. But it remains at its original value 50. What am I doing wrong?
To my understanding the macro's execute method should get invoked during the recomputation of the document.
When I trace Document.recompute() with pudb, I only see it executing Facebinder.execute() but not Icosahedron.execute(). The path it takes from Document.recompute() to Facebinder.execute() method is not visible in pudb; it immediately stops in Facebinder.execute().
FREECADPATH = '/usr/local/lib' # path to your FreeCAD.so or FreeCAD.dll POLYHEDRONS_PATH = '/home/user/.FreeCAD/Mod/Pyramids-and-Polyhedrons'
import sys
sys.path.append(FREECADPATH)
sys.path.append(POLYHEDRONS_PATH)
import FreeCAD
filename = 'icosahedron.FCStd'
newRadius = 15
doc = FreeCAD.open(filename)
sheet = doc.Spreadsheet
sheet.set('radius', str(newRadius))
sheet.recompute()
print('radius = ' + str(sheet.get('radius')))
icosahedron = doc.getObjectsByLabel('Icosahedron')[0]
print('icosahedron.Radius = '+str(icosahedron.Radius))
icosahedron.touch()
doc.recompute()
print('icosahedron.Radius = '+str(icosahedron.Radius))
(vertices, faces) = icosahedron.Shape.tessellate(1)
z11 = vertices[11][2]
print('z11 = ' + str(z11))
FreeCAD.closeDocument(doc.Name)
I figured it out. The reason was Pyramids-and-Polyhedrons
not being imported after all.
The first problem was that Pyramids-and-Polyhedrons
imports FreeCADGui
(in order to install its workbench), which depends on certain native libs that need to be added to LD_LIBRARY_PATH
before running the script:
export LD_LIBRARY_PATH=$(echo $(find /usr/local/lib/python3.7/site-packages -maxdepth 2 -mindepth 2 -type f -name *.so* | sed -r 's|/[^/]+$||' | sort -u) | sed -E 's/ /:/g')
Now FreeCADGui
could be imported, but it was lacking the required addCommand
method that Pyramids-and-Polyhedrons
invokes. I found out that FreeCADGui
will only be fully initialized after FreeCADGui.showMainWindow()
has been called. This requires a display, however, and I want to run the script as part of a headless toolchain in a Docker container. Therefore I added Xvfb
to the image. I'm launching it in the background before running the updated script with DISPLAY
pointing to Xvfb
:
FREECADPATH = '/usr/local/lib' # path to your FreeCAD.so or FreeCAD.dll file
POLYHEDRONS_PATH = '/home/user/.FreeCAD/Mod/Pyramids-and-Polyhedrons'
import sys
sys.path.append(FREECADPATH)
sys.path.append(POLYHEDRONS_PATH)
import FreeCAD
import FreeCADGui
FreeCADGui.showMainWindow()
import polyhedrons
filename = 'icosahedron.FCStd'
newRadius = 15
doc = FreeCAD.open(filename)
sheet = doc.Spreadsheet
sheet.set('radius', str(newRadius))
sheet.recompute()
print('radius = ' + str(sheet.get('radius')))
icosahedron = doc.getObjectsByLabel('Icosahedron')[0]
print('icosahedron.Radius = '+str(icosahedron.Radius))
breakpoint()
icosahedron.touch()
doc.recompute()
print('icosahedron.Radius = '+str(icosahedron.Radius))
(vertices, faces) = icosahedron.Shape.tessellate(1)
z11 = vertices[11][2]
print('z11 = ' + str(z11))
FreeCAD.closeDocument(doc.Name)
Now the output is
...
z11 = 15.0
as expected.