Apologies for the delayed update. I can't say the issue is solved, in that I still don't completely understand the strange behavior of my original macro, or why running the final image-saving command from the console makes it work, but after some research and trial and error, I have developed macro(s) that do what I need.
I first tried eliminating the text creation in my original macro to see if that was the problem, but it didn't help. I then tried inserting the Python equivalent of the View - Fit All command into the macro, and hooray, the sphere object and axis cross were properly saved to the image file!
Thus encouraged, i re-inserted the text timestamp code back into the macro, but the saved image did not include the text. However, the text
was part of the global scene, which was evident by zooming out a little in the FreeCAD display. It was here I realized that text objects are
ignored by the View - Fit All command.
Anyway, to make a long story short(er), I eventually developed two different ways to do what I wanted (save both a rendered object and a text string to an image file from a macro). They include some cosmetic mods relative to the original, but the basic content/function remains unchanged.
The first is the more clunky of the two, but it's nevertheless effective:
Code: Select all
import Part
import Draft
import os
#Create a new document
FreeCAD.newDocument('TestPictureSave')
#Create an object
App.ActiveDocument.addObject("Part::Sphere","Sphere")
FreeCAD.getDocument('TestPictureSave').getObject('Sphere').Radius = '20 mm'
#Set Draw Style to Shaded
Gui.runCommand('Std_DrawStyle',5)
#Create a camera-facing text timestamp for this snapshot, then position, size, and color it
_text_ = Draft.make_text(["t = 0.00 msec"], placement=FreeCAD.Vector(50.0, 50.0, 0.0),screen=True)
FreeCADGui.getDocument('TestPictureSave').getObject('Text').FontSize = '40 mm'
FreeCADGui.getDocument('TestPictureSave').getObject('Text').TextColor = (1.00000000,1.00000000,1.00000000)
#Now create a temporary shape string and place it in the vicinity of the text above
str = "."
fontfile = "C:/Windows/winsxs/amd64_microsoft-windows-font-truetype-arial_31bf3856ad364e35_6.1.7601.17514_none_d0a9759ec3fa9e2d/arial.ttf"
ss=Draft.makeShapeString(str,fontfile)
plm=FreeCAD.Placement()
plm.Base=FreeCAD.Vector(50.0, 50.0, 0.0)
plm.Rotation.Q=(0.0, 0.0, 0.0, 1.0)
ss.Placement=plm
FreeCADGui.getDocument('TestPictureSave').getObject('ShapeString').Transparency = 100
######## TEST
App.ActiveDocument.recompute()
######## TEST
Gui.Selection.clearSelection()
#Set view to Fit All
FreeCADGui.ActiveDocument.ActiveView.fitAll()
#Remove the ShapeString
App.getDocument('TestPictureSave').removeObject('ShapeString')
#Display the coordinate axes
Gui.ActiveDocument.ActiveView.setAxisCross(True)
#Take the snapshot and save it as a jpeg file
deskpath = os.path.expanduser('~/Desktop')
picpath = os.path.join(deskpath, 'PictureSavedFromMacro.jpg')
Gui.ActiveDocument.activeView().saveImage(picpath,1505,618,'Current')
The temporary ShapeString
is recognized by the Fit All command, and thus the desired timestamp text is effectively pulled into the scene on the 'coattails' of the ShapeString. So, why not just use a ShapeString for the timestamp in the first place? The reason is that the "screen=True" option in the Draft.make_text command forces the text to face the camera, and it
maintains that orientation regardless of whatever other reorientations you subsequently apply to the scene... this is handy for the ultimate video-generating process this is supporting later.
The second method is more concise and general... it explicitly specifies the camera parameters before saving the image, although it requires a preliminary determination of what those camera parameters should be. These can be obtained by rendering the object/text in the FreeCAD display, then orienting/navigating until the desired scene composition is achieved, then capturing the current camera settings with the Gui.ActiveDocument.ActiveView.getCamera() command from the Python console, then inserting these data into the macro, specifically supplying them to the Gui.ActiveDocument.ActiveView.setCamera() command:
Code: Select all
import Part
import Draft
import os
FreeCAD.newDocument('TestPictureSave')
# Create an object
App.ActiveDocument.addObject("Part::Sphere", "Sphere")
FreeCAD.getDocument('TestPictureSave').getObject('Sphere').Radius = '20 mm'
#Set Draw Style to Shaded
Gui.runCommand('Std_DrawStyle',5)
# Display the coordinate axes
Gui.ActiveDocument.ActiveView.setAxisCross(True)
# Create a text timestamp, then position, size, and color it
_text_ = Draft.make_text(["t = 0.00 msec"], placement=FreeCAD.Vector(50.0, 50.0, 0.0),screen=True)
FreeCADGui.getDocument('TestPictureSave').getObject('Text').FontSize = '40 mm'
FreeCADGui.getDocument('TestPictureSave').getObject('Text').TextColor = (1.0,1.0,1.0)
App.ActiveDocument.recompute()
Gui.Selection.clearSelection()
camdat = '#Inventor V2.1 ascii\n\n\nOrthographicCamera {\n viewportMapping ADJUST_CAMERA\n position 8.8219976 8.4894114 100\n orientation 0 0 1 0\n nearDistance 42.657673\n farDistance 120.12\n aspectRatio 1\n focalDistance 100\n height 149.18246\n\n}\n'
Gui.ActiveDocument.ActiveView.setCamera(camdat)
#Take the snapshot and save it as a jpeg file
deskpath = os.path.expanduser('~/Desktop')
picpath = os.path.join(deskpath, 'PictureSavedFromMacro.jpg')
Gui.ActiveDocument.activeView().saveImage(picpath,1505,618,'Current')
So I guess I'm going to declare victory, in the sense that I have a working method, although as noted above I'm not sure I fully understand all the subtleties, particularly as to whether/when commands executed from a macro are equivalent to the same commands executed in the Python console.