Modules | PY
I/O
File I/O operations for reading and writing mesh data.
The I/O module provides functions for reading and writing mesh data in STL format (both ASCII and binary) and OBJ format (ASCII).
Reading
STL Files
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)
OBJ Files
Read an OBJ file and return mesh data:
import trueform as tf
import numpy as np
# Read OBJ file (default: dynamic polygons)
faces, points = tf.read_obj("model.obj")
# faces: OffsetBlockedArray (variable-length face blocks)
# points: (M, 3) array with dtype np.float32
# Create Mesh from loaded data
mesh = tf.Mesh(faces, points)
print(f"Loaded {mesh.number_of_faces} faces, {mesh.number_of_points} points")
# Read as fixed-size triangles
faces, points = tf.read_obj("model.obj", ngon=3)
# faces: (N, 3) array with dtype np.int32
# Read as fixed-size quads
faces, points = tf.read_obj("quad_model.obj", ngon=4)
# faces: (N, 4) array with dtype np.int32
# For large meshes, use int64 indices
faces, points = tf.read_obj("large_model.obj", index_dtype=np.int64)
The default
ngon=None returns an OffsetBlockedArray for faces, which supports mixed polygon sizes (triangles, quads, n-gons in the same file). Use ngon=3 or ngon=4 when you know all faces have the same size and want a regular 2D ndarray.Writing
STL Files
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 Priority: Explicit
transformation parameter overrides mesh.transformation property.OBJ Files
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 dynamic mesh (mixed polygon sizes)
faces, points = tf.read_obj("mixed.obj")
tf.write_obj((faces, points), "output.obj")
# Write from Mesh object (fixed or dynamic)
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
Round-trip Example
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")
For implementation details, see the C++ I/O documentation.
