Python Matrix Transformations on FreeCAD Objects

Performing matrix transformations on FreeCAD objects using Python allows you to precisely manipulate geometry through 4x4 transformation matrices, enabling translation, rotation, scaling, and shearing. This guide covers how to construct transformation matrices using the FreeCAD API, apply them to an object's spatial placement, and transform underlying geometric shapes directly for advanced modeling tasks.

Understanding FreeCAD Matrix Basics

FreeCAD provides the FreeCAD.Matrix class to represent 4x4 affine transformation matrices. A 4x4 matrix can represent 3D translation, rotation, scaling, and shear in homogeneous coordinates.

To initialize an identity matrix:

import FreeCAD as App
import FreeCADGui as Gui

# Create a 4x4 identity matrix
mat = App.Matrix()

You can define matrix elements manually or use built-in manipulation methods:

  • mat.move(App.Vector(x, y, z)) applies a translation.
  • mat.rotateX(angle_in_radians), mat.rotateY(angle), mat.rotateZ(angle) apply rotations around global axes.
  • mat.scale(App.Vector(sx, sy, sz)) applies scaling along each axis.

Method 1: Transforming Object Placement

FreeCAD objects have a Placement property defining their location and orientation in the 3D scene. This method is ideal for rigid-body transformations (translations and rotations) because it updates the object's position without altering its underlying topology or geometry.

import FreeCAD as App

doc = App.ActiveDocument
obj = doc.ActiveObject

# Create and define the transformation matrix
mat = App.Matrix()
mat.move(App.Vector(10, 0, 5))  # Translate 10 mm in X, 5 mm in Z
mat.rotateZ(1.5708)             # Rotate ~90 degrees around Z axis (in radians)

# Convert the matrix into a Placement and apply it
new_placement = App.Placement(mat)

# Option A: Replace current placement entirely
obj.Placement = new_placement

# Option B: Multiply with current placement to apply relatively
# obj.Placement = new_placement.multiply(obj.Placement)

doc.recompute()

Note: Object Placement only supports rigid transformations. If your matrix includes non-uniform scaling or shearing, converting it to a Placement will discard those non-rigid components.

Method 2: Transforming Geometry Directly

To apply non-uniform scaling, reflection, or shearing, you must apply the matrix directly to the object's Shape using OpenCASCADE-level transformations.

FreeCAD's Part.Shape provides two primary methods:

  • transformShape(Matrix): Alters the shape geometry in-place.
  • transformGeometry(Matrix): Creates and returns a transformed copy of the geometry.
import FreeCAD as App
import Part

doc = App.ActiveDocument
obj = doc.ActiveObject

# Define a transformation matrix with non-uniform scaling
mat = App.Matrix(
    2.0, 0.0, 0.0, 10.0,  # Row 1: X-scale = 2, X-translation = 10
    0.0, 1.0, 0.0, 0.0,   # Row 2: Y-scale = 1
    0.0, 0.0, 0.5, 0.0,   # Row 3: Z-scale = 0.5
    0.0, 0.0, 0.0, 1.0    # Row 4: Homogeneous coordinate
)

# Apply transformation directly to the shape
transformed_shape = obj.Shape.transformGeometry(mat)

# Assign the transformed shape back to the object
obj.Shape = transformed_shape

doc.recompute()

Combining Matrix Transformations

Matrix multiplication is associative, allowing you to combine several discrete transformations into a single operation. In FreeCAD, operations are executed in order using the multVec() or matrix multiplication methods.

import FreeCAD as App

# Matrix A: Translation
mat_trans = App.Matrix()
mat_trans.move(App.Vector(50, 0, 0))

# Matrix B: Rotation
mat_rot = App.Matrix()
mat_rot.rotateY(0.7854)  # 45 degrees

# Combined transformation: mat_trans * mat_rot
combined_mat = mat_trans.multiply(mat_rot)

# Apply to active object
obj = App.ActiveDocument.ActiveObject
obj.Placement = App.Placement(combined_mat)
App.ActiveDocument.recompute()

Always call doc.recompute() after altering an object's Placement or Shape to refresh the graphical viewport and dependency graph.