Architecture¶
This page explains the core architecture of COMPAS Slicer - how data flows from mesh to G-code, and how the main components interact.
The Slicing Pipeline¶
Every slicing workflow follows this pipeline:
flowchart LR
A[Mesh] --> B[Slicer]
B --> C[Layers & Paths]
C --> D[PrintOrganizer]
D --> E[PrintPoints]
E --> F[Output]
F --> G[G-code]
F --> H[JSON]
F --> I[Grasshopper]
Each stage transforms the data:
| Stage | Input | Output | Purpose |
|---|---|---|---|
| Slicer | Mesh | Layers containing Paths | Intersect mesh with cutting surfaces |
| PrintOrganizer | Layers/Paths | PrintPoints | Add fabrication parameters |
| Output | PrintPoints | G-code/JSON | Export for machines or visualization |
Core Data Structures¶
Hierarchy¶
The geometric data is organized hierarchically:
After print organization:
Layer¶
A Layer represents one "slice" of the model. In planar slicing, all points share the same Z height. In non-planar slicing (curved, scalar field), points can vary in height.
from compas_slicer.geometry import Layer
layer = Layer(paths=[path1, path2])
layer.is_closed # True if all paths are closed contours
Key attributes:
paths- List of Path objects in this layeris_raft- Whether this is a raft layer (special handling)
Path¶
A Path is a single contour - either closed (loop) or open (line). A layer can have multiple paths when:
- The slice intersects multiple disconnected regions
- The model has holes (inner and outer contours)
from compas_slicer.geometry import Path
path = Path(points=[pt1, pt2, pt3], is_closed=True)
len(path) # Number of points
Key attributes:
points- List of COMPAS Point objectsis_closed- Whether the path forms a closed loop
PrintPoint¶
A PrintPoint extends a geometric point with all the information needed for fabrication:
from compas_slicer.geometry import PrintPoint
pp = PrintPoint(
pt=Point(0, 0, 10),
layer_height=0.4,
mesh_normal=Vector(0, 0, 1)
)
# Fabrication parameters (set by PrintOrganizer)
pp.velocity = 30.0 # mm/s
pp.extruder_toggle = True # extrusion on/off
pp.wait_time = 0.0 # pause at point
Key attributes:
| Attribute | Type | Description |
|---|---|---|
pt |
Point | XYZ position |
layer_height |
float | Layer height at this point |
mesh_normal |
Vector | Surface normal from mesh |
up_vector |
Vector | Tool orientation (Z-axis of tool frame) |
frame |
Frame | Full tool frame for robotic fabrication |
velocity |
float | Travel/print speed in mm/s |
extruder_toggle |
bool | Whether extruder is on |
wait_time |
float | Pause duration in seconds |
Slicers¶
All slicers inherit from BaseSlicer and implement generate_paths():
class BaseSlicer:
def __init__(self, mesh: Mesh):
self.mesh = mesh
self.layers: list[Layer] = []
def generate_paths(self) -> None:
"""Override in subclass to generate self.layers"""
raise NotImplementedError
Available Slicers¶
| Slicer | Algorithm | Use Case |
|---|---|---|
PlanarSlicer |
Horizontal plane intersection via CGAL | Standard FDM printing |
InterpolationSlicer |
Geodesic interpolation between boundaries | Curved shells, domes |
ScalarFieldSlicer |
Isocurves of scalar field on mesh | Custom layer patterns |
UVSlicer |
UV parameterization contours | Developable surfaces |
Print Organization¶
The PrintOrganizer converts geometric paths to fabrication-ready PrintPoints:
from compas_slicer.print_organization import PlanarPrintOrganizer
# Create organizer from slicer
organizer = PlanarPrintOrganizer(slicer)
organizer.create_printpoints()
# Access printpoints
for layer_key in organizer.printpoints_dict:
for path_key in organizer.printpoints_dict[layer_key]:
printpoints = organizer.printpoints_dict[layer_key][path_key]
Post-Processing Functions¶
After creating printpoints, apply fabrication parameters:
from compas_slicer.print_organization import (
set_linear_velocity_constant,
set_extruder_toggle,
add_safety_printpoints,
)
# Set constant velocity
set_linear_velocity_constant(organizer, velocity=25.0)
# Set extrusion on/off based on path structure
set_extruder_toggle(organizer, slicer)
# Add safety moves between layers
add_safety_printpoints(organizer, z_hop=10.0)
Data Flow Example¶
Here's the complete flow for planar slicing:
from compas.datastructures import Mesh
from compas_slicer.slicers import PlanarSlicer
from compas_slicer.print_organization import PlanarPrintOrganizer
from compas_slicer.print_organization import (
set_linear_velocity_constant,
set_extruder_toggle,
)
# 1. Load mesh
mesh = Mesh.from_obj("model.obj")
# 2. Slice mesh into layers
slicer = PlanarSlicer(mesh, layer_height=0.4)
slicer.generate_paths()
# Result: slicer.layers = [Layer, Layer, ...]
# 3. Create printpoints with fabrication data
organizer = PlanarPrintOrganizer(slicer)
organizer.create_printpoints()
# Result: organizer.printpoints_dict[layer][path] = [PrintPoint, ...]
# 4. Set fabrication parameters
set_linear_velocity_constant(organizer, velocity=30.0)
set_extruder_toggle(organizer, slicer)
# 5. Export
organizer.printpoints_collection.to_json("output.json")
Module Organization¶
compas_slicer/
├── geometry/ # Layer, Path, PrintPoint, PrintPointsCollection
├── slicers/ # BaseSlicer, PlanarSlicer, InterpolationSlicer, etc.
├── print_organization/ # PrintOrganizers and parameter functions
├── pre_processing/ # Mesh prep: move_mesh_to_point, get_distance_of_pt_from_mesh
├── post_processing/ # Path mods: simplify_paths_rdp, sort_paths, generate_brim
└── utilities/ # I/O, geometry helpers
Next Steps¶
- Slicing Algorithms - Deep dive into how each slicer works
- Print Organization - Fabrication parameter details
- Examples - Complete working code