---
title: Tutorial 43 Building a Custom Slicer Core
description: The ultimate G-code challenge.
---
Tutorial 43 Building a Custom Slicer Core
1. Lesson Header
- Lesson Number: 43
- Level: Master
- Title: Building a Custom Slicer Core
- Estimated Duration: 90 Minutes
- Prerequisites: Lesson 34 (Infill), Lesson 37 (Voxelizer), Geometry (Triangle Intersections)
- What You Will Build: A "Vase Mode Slicer" for STL files.
2. Concept Introduction
The Slicing Pipeline.
How does Cura/PrusaSlicer work?
1. Import: Read STL (Triangles).
2. Slice: Intersect triangles with a Plane at Z height. Result: Lines.
3. Contour: Connect lines into closed Polygons.
4. Offset: Shrink polygons by Nozzle_Width / 2 (Inset).
5. Path: Generate G-code for the inset polygons.
6. Infill: Fill the inside.
We will build Steps 1-5 for a single-wall vase.
3. Machine State Explanation
Plane-Triangle Intersection.
A triangle has 3 vertices (V1, V2, V3).
A plane has height Z.
If all 3 vertices are above/below Z -> No intersection.
If 1 is above and 2 below (or vice versa) -> The plane cuts the triangle. The intersection is a Line Segment.
4. Command Breakdown
- Python
numpy-stl: Library to read STL files. - Math: Linear interpolation to find intersection points.
5. Minimal Working Example
The Triangle Slice.
V1=(0,0,0), V2=(10,0,0), V3=(0,10,10).
Slice at Z=5.
Edge V1-V3 crosses Z=5 at (0,5,5).
Edge V2-V3 crosses Z=5 at (5,5,5).
Segment: (0,5) to (5,5).
6. Visual Representation
Interactive preview is available in the interactive reader.
7. Build Exercise
Task: Write a Python Slicer.
Input: cube.stl.
Output: cube.gcode.
Mode: Vase (Spiralize).
Algorithm:
1. Load STL.
2. Find Z min/max.
3. Loop Z from min to max by layer_height.
4. Find all intersecting segments.
5. Chain segments into a loop (Nearest Neighbor).
6. Write G-code points.
8. Deep Insight Section
Manifoldness.
Real STLs are messy. Holes, flipped normals, self-intersections.
Robust slicers spend 50% of their code fixing bad geometry.
Our simple slicer will fail on bad meshes.
Solution: Repair with Netfabb/Meshmixer first.
9. Common Failure Modes
- Unsorted Segments: The intersection gives a bag of lines. You must sort them
End -> Startto form a continuous path. - Floating Point Errors:
Z=10.0000001might miss a vertex atZ=10. Use an epsilon tolerance.
10. Real-World Application
Non-Planar Slicers.
Simulating 5-axis printing requires slicing with Curved Surfaces instead of flat planes.
The math is the same (Intersection), just harder geometry.
11. Final Clean Version
The Mini Slicer:
import numpy as np
from stl import mesh
def intersect_triangle_plane(v1, v2, v3, z):
# Check if edges cross Z
points = []
def get_intersect(p1, p2, z):
if p2[2] == p1[2]: return None
t = (z - p1[2]) / (p2[2] - p1[2])
if 0 <= t <= 1:
return p1 + t * (p2 - p1)
return None
# Check 3 edges
i1 = get_intersect(v1, v2, z)
i2 = get_intersect(v2, v3, z)
i3 = get_intersect(v3, v1, z)
# Collect valid points
if i1 is not None: points.append(i1)
if i2 is not None: points.append(i2)
if i3 is not None: points.append(i3)
# Remove duplicates
unique = []
for p in points:
if not any(np.allclose(p, u) for u in unique):
unique.append(p)
if len(unique) == 2:
return (unique[0], unique[1])
return None
# Main Slicing Loop
my_mesh = mesh.Mesh.from_file('vase.stl')
z_min, z_max = my_mesh.z.min(), my_mesh.z.max()
layer_height = 0.2
with open("sliced.gcode", "w") as f:
f.write("G28\nG1 Z0.2\n")
for z in np.arange(z_min, z_max, layer_height):
segments = []
for i in range(len(my_mesh.vectors)):
tri = my_mesh.vectors[i]
seg = intersect_triangle_plane(tri[0], tri[1], tri[2], z)
if seg: segments.append(seg)
# Sort segments to form a contour
# (Simplified: Just write them as lines, printer will jump)
# Real slicer needs sorting!
for s in segments:
f.write(f"G0 X{s[0][0]:.3f} Y{s[0][1]:.3f}\n")
f.write(f"G1 X{s[1][0]:.3f} Y{s[1][1]:.3f} E...\n")
f.write("G28 X0 Y0\n")
12. Stretch Challenge
Challenge: Implement Offsetting.
The contour is the edge of the object.
The nozzle must move inside by Nozzle_Radius.
Calculate the normal vector of each segment and shift it inwards.
This is hard for concave shapes (Self-intersection). Use the Shapely library.