cudaslicer/examples/python_quickstart.py
2026-09-25 18:09:19 +03:00

119 lines
4.4 KiB
Python

#!/usr/bin/env python3
"""
CUDASlicer Python Quickstart & Integration Example
=================================================
Demonstrates how to use `cudaslicer` in a Python project with:
- first_layer_height
- perimeters_count and layer_width (Perimeter 1: -0.5w, Perimeter 2: -1.5w, etc.)
- default pitch_mm = 0.10
- outputs: perimeters and infill_mask (-perimeters_count * layer_width)
"""
import time
import numpy as np
import trimesh
import cudaslicer
def example_mask_offsetting():
print("--- 1. GPU Mask Offsetting ---")
# Create a 200x200 test grid with a square
grid = np.zeros((200, 200), dtype=np.uint8)
grid[50:150, 50:150] = 1
t0 = time.perf_counter()
# Generate 2 perimeters and infill mask with layer_width=0.45 mm, default pitch_mm=0.10 mm
perimeters, infill_mask = cudaslicer.offset_masks(
masks=grid,
perimeters_count=2,
layer_width=0.45,
pitch_mm=0.10 # default is 0.10
)
t1 = time.perf_counter()
print(f"Mask offset completed in {(t1 - t0)*1000:.3f} ms")
print(f"Original area (pixels): {grid.sum()}")
print(f"Perimeter 1 (-0.5*width = -0.225mm) area (pixels): {perimeters[0].sum()}")
print(f"Perimeter 2 (-1.5*width = -0.675mm) area (pixels): {perimeters[1].sum()}")
print(f"Infill mask (-2.0*width = -0.900mm) area (pixels): {infill_mask.sum()}\n")
def example_polygon_offsetting():
print("--- 2. Single Layer Polygon Offsetting ---")
# Define an L-shaped polygon
l_poly = np.array([
[0.0, 0.0],
[30.0, 0.0],
[30.0, 10.0],
[10.0, 10.0],
[10.0, 30.0],
[0.0, 30.0]
], dtype=np.float32)
t0 = time.perf_counter()
layer_res = cudaslicer.offset_polygons(
layers=[l_poly],
perimeters_count=2,
layer_width=0.45,
pitch_mm=0.10,
pad_mm=1.0,
return_infill_mask=True
)
t1 = time.perf_counter()
perimeters, infill_mask = layer_res # Unpack directly!
print(f"Polygon offsetting completed in {(t1 - t0)*1000:.3f} ms")
print(f" Perimeter 1 (-0.225mm): {len(perimeters[0])} loop(s), vertex count: {[len(c) for c in perimeters[0]]}")
print(f" Perimeter 2 (-0.675mm): {len(perimeters[1])} loop(s), vertex count: {[len(c) for c in perimeters[1]]}")
print(f" Infill contours (-0.900mm): {len(layer_res.infill_contours)} loop(s), vertex count: {[len(c) for c in layer_res.infill_contours]}")
if infill_mask is not None:
print(f" Infill mask raster shape: {infill_mask.shape}, active pixels: {infill_mask.sum()}")
print()
def example_mesh_slicing_and_offset():
print("--- 3. 100% GPU Direct 3D Mesh Slicing & Offsetting ---")
mesh = trimesh.load("benchy.stl")
print(f"Loaded mesh with {len(mesh.faces)} triangles. Running 100% GPU Slicing pipeline...")
t0 = time.perf_counter()
layers = cudaslicer.slice_mesh_and_offset(
mesh_or_triangles=mesh,
layer_height=0.20,
first_layer_height=0.25, # custom first layer height
perimeters_count=2,
layer_width=0.45,
pitch_mm=0.10, # default 0.10
pad_mm=1.5,
return_infill_mask=True
)
t1 = time.perf_counter()
total_ms = (t1 - t0) * 1000
print(f"100% GPU Slicing & Offsetting done in {total_ms:.2f} ms ({len(layers)} layers)")
print(f"Throughput: {len(layers) / (total_ms / 1000.0):.1f} layers/second!")
# Inspect first layer and a middle layer
layer_0 = layers[0]
print(f"\nLayer 0 (Z = {layer_0.z:.2f} mm - First Layer Height):")
perims_0, infill_mask_0 = layer_0
print(f" Perimeters: {len(perims_0)} passes (Outer: {len(perims_0[0])} loops, Inner: {len(perims_0[1])} loops)")
print(f" Infill Mask: {infill_mask_0.shape}, Infill Contours: {len(layer_0.infill_contours)} loop(s)")
mid_idx = len(layers) // 2
layer_mid = layers[mid_idx]
print(f"Layer {mid_idx} (Z = {layer_mid.z:.2f} mm):")
perims_mid, infill_mask_mid = layer_mid
print(f" Perimeters: {len(perims_mid)} passes (Outer: {len(perims_mid[0])} loops, Inner: {len(perims_mid[1])} loops)")
print(f" Infill Mask: {infill_mask_mid.shape}, Infill Contours: {len(layer_mid.infill_contours)} loop(s)\n")
if __name__ == "__main__":
if not cudaslicer.is_available():
print("Error: CUDA GPU is not available.")
exit(1)
print(f"CUDASlicer Version: {cudaslicer.__version__}")
example_mask_offsetting()
example_polygon_offsetting()
example_mesh_slicing_and_offset()