The I/O module provides functions for reading and writing mesh data in STL format (both ASCII and binary) and OBJ format (ASCII).
Read an STL file and return mesh data:
import trueform as tf
import numpy as np
# Read STL file
faces, points = tf.read_stl("model.stl")
# faces: (N, 3) array with dtype np.int32
# points: (M, 3) array with dtype np.float32
# Create Mesh from loaded data
mesh = tf.Mesh(faces, points)
print(f"Loaded {len(faces)} faces, {len(points)} points")
# For large meshes (> 2 billion vertices), use int64 indices
faces, points = tf.read_stl("large_model.stl", index_dtype=np.int64)
Read an OBJ file and return mesh data:
import trueform as tf
import numpy as np
# Read triangular mesh
faces, points = tf.read_obj("model.obj", ngon=3)
# faces: (N, 3) array with dtype np.int32
# points: (M, 3) array with dtype np.float32
# Read quad mesh
faces, points = tf.read_obj("quad_model.obj", ngon=4)
# faces: (N, 4) array with dtype np.int32
# Create Mesh from loaded data
mesh = tf.Mesh(faces, points)
print(f"Loaded {len(faces)} faces, {len(points)} points")
# For large meshes, use int64 indices
faces, points = tf.read_obj("large_model.obj", ngon=3, index_dtype=np.int64)
ngon parameter is required because numpy arrays cannot be ragged (all rows must have the same length).Write mesh data to binary STL format:
# Write from tuple (faces, points)
faces = np.array([[0, 1, 2]], dtype=np.int32)
points = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0]], dtype=np.float32)
tf.write_stl((faces, points), "output.stl")
# Write from Mesh object
mesh = tf.Mesh(faces, points)
tf.write_stl(mesh, "output_mesh.stl")
With transformation parameter:
# Apply transformation during write
transform = np.eye(4, dtype=np.float32)
transform[:3, 3] = [10, 0, 5] # Translate by (10, 0, 5)
tf.write_stl((faces, points), "translated.stl", transformation=transform)
Using mesh transformation property:
# Set transformation on mesh
mesh = tf.Mesh(faces, points)
mesh.transformation = transform
tf.write_stl(mesh, "mesh_with_transform.stl") # Transformation applied automatically
# Override mesh transformation
override_transform = np.eye(4, dtype=np.float32)
override_transform[2, 3] = 20 # Different Z translation
tf.write_stl(mesh, "overridden.stl", transformation=override_transform)
transformation parameter overrides mesh.transformation property.Write mesh data to ASCII OBJ format:
# Write triangular mesh from tuple (faces, points)
faces = np.array([[0, 1, 2]], dtype=np.int32)
points = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0]], dtype=np.float32)
tf.write_obj((faces, points), "triangle.obj")
# Write quad mesh
faces = np.array([[0, 1, 2, 3]], dtype=np.int32)
points = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]], dtype=np.float32)
tf.write_obj((faces, points), "quad.obj")
# Write from Mesh object
mesh = tf.Mesh(faces, points)
tf.write_obj(mesh, "output_mesh.obj")
With transformation parameter:
# Apply transformation during write
transform = np.eye(4, dtype=np.float32)
transform[:3, 3] = [10, 0, 5] # Translate by (10, 0, 5)
tf.write_obj((faces, points), "translated.obj", transformation=transform)
Using mesh transformation property:
# Set transformation on mesh
mesh = tf.Mesh(faces, points)
mesh.transformation = transform
tf.write_obj(mesh, "mesh_with_transform.obj") # Transformation applied automatically
import trueform as tf
import numpy as np
# Read STL file
faces, points = tf.read_stl("input.stl")
# Create transformation (translate + rotate)
transform = np.eye(4, dtype=np.float32)
transform[:3, 3] = [5, 0, 0] # Translation
angle = np.radians(45)
transform[0, 0] = np.cos(angle)
transform[0, 1] = -np.sin(angle)
transform[1, 0] = np.sin(angle)
transform[1, 1] = np.cos(angle)
# Write with transformation
tf.write_stl((faces, points), "transformed.stl", transformation=transform)
# Or via Mesh object
mesh = tf.Mesh(faces, points)
mesh.transformation = transform
tf.write_stl(mesh, "transformed_mesh.stl")