Get Volume and Area of Shapes in FreeCAD
~2 minutes read
Extract with a macro the volume and area values of shapes in FreeCAD.
To extract the values of all shapes from a tree structure, it is necessary to proceed as follows:
- Iterate though the tree view to parse all existing shapes, and doing so recursively.
- For each shape, get:
- Label
- Volume
- Area
- Bounding Box
- Or add any other information.
- Add these values to the dictionary containing the info for that shape.
- Then, write the dictionary into a file in the same folder as the FreeCAD document.
The following code shows an implementation of the steps described above:
import FreeCAD
import json
original_stdout = sys.stdout
tree_objects = []
properties_objects = []
def iterate_document_tree(obj, level=0) -> None:
"""
Recursively iterates through the FreeCAD document tree, starting from a given object.
"""
tree_objects.append({"ObjectName": obj.Name, "Label": obj.Label})
# Check if the object has children (e.g., a group or a body)
if hasattr(obj, "Group") and obj.Group:
for child_obj in obj.Group:
iterate_document_tree(child_obj, level + 1)
elif hasattr(obj, "Shape") and hasattr(obj.Shape, "ChildObjects") and obj.Shape.ChildObjects:
for child_obj in obj.Shape.ChildObjects:
iterate_document_tree(child_obj, level + 1)
def get_properties() -> None:
for object in tree_objects:
try:
target_object = App.ActiveDocument.getObjectsByLabel(
object["Label"])
properties_objects.append({"part_number": object["Label"],
"volume": f"{round(target_object[0].Shape.Volume, 2)} mm\u00b3",
"area": f"{round(target_object[0].Shape.Area, 2)} mm\u00b2",
"bbox_x": f"{round(target_object[0].Shape.BoundBox.XLength, 2)} mm",
"bbox_y": f"{round(target_object[0].Shape.BoundBox.YLength, 2)} mm",
"bbox_z": f"{round(target_object[0].Shape.BoundBox.ZLength, 2)} mm"})
except Exception as err:
print(f"Error on: {object["Label"]}: {err}")
finally:
pass
# Get the active document
doc = FreeCAD.ActiveDocument
if doc:
print("Iterating through the FreeCAD document tree.")
# Iterate through all top-level objects in the document
for obj in doc.Objects:
iterate_document_tree(obj)
get_properties()
# To save in the same folder as the parsed document.
try:
with open(doc.FileName.rsplit("/", 1)[0] + "/freecad-data.json", "w") as file:
json.dump(properties_objects, file, indent=4)
print("File saved successfully.")
except Exception as err:
print(err)
print("File could not be saved.")
finally:
pass
else:
print("No active FreeCAD document found.")
The exported file (which should be in the same folder that the file.FCStd) should return a list (depending on the design):
[
{
"part_number": "SU-A-0001L",
"volume": "32148.47 mm\u00b3",
"area": "25682.94 mm\u00b2",
"bbox_x": "112.98 mm",
"bbox_y": "42.6 mm",
"bbox_z": "59.45 mm"
},
{
"part_number": "SU-P-0001L",
"volume": "8205.05 mm\u00b3",
"area": "6962.71 mm\u00b2",
"bbox_x": "61.48 mm",
"bbox_y": "24.6 mm",
"bbox_z": "50.8 mm"
}
]
This can be added to FreeCAD as a macro. Be sure to save the CAD document first before starting the macro.
Note: This has not been tested on Windows. There might be an issue due to file path formats using backslash ( \ ) on Windows instead of forward slash ( / ) on Unix-like system.