Examples

>>> # 2D — chamfered mounting plate
>>> from scadpy import circle, cuboid, rectangle, sphere, square, text
>>> from scadpy import x, y, z, GRAY, ORANGE
>>> import numpy as np
>>> import math

>>> PLATE_WIDTH  = 80
>>> PLATE_HEIGHT = 50
>>> PLATE_THICKNESS = 10
>>> HOLE_RADIUS  = 4
>>> HOLE_MARGIN  = 10
>>> CHAMFER_SIZE = 8

>>> base  = rectangle([PLATE_WIDTH, PLATE_HEIGHT])
>>> plate = base.chamfer(CHAMFER_SIZE)

>>> for position, normal in zip(base.vertex_coordinates, base.vertex_normals):
...     hole_center = position - HOLE_MARGIN * np.sqrt(2) * normal
...     plate -= circle(HOLE_RADIUS).translate(hole_center)

>>> plate.to_screen()
2026-03-17T09:38:16.466627 image/svg+xml Matplotlib v3.10.6, https://matplotlib.org/
2026-03-17T09:38:16.585207 image/svg+xml Matplotlib v3.10.6, https://matplotlib.org/
>>> # 3D — extruded plate with label
>>> TEXT_THICKNESS = 2

>>> extruded_plate = plate.linear_extrude(PLATE_THICKNESS)
>>> label = text("ScadPy", size=15).linear_extrude(TEXT_THICKNESS)
>>> labelized_extruded_plate = extruded_plate | label.translate(z(PLATE_THICKNESS))
>>> labelized_extruded_plate.to_screen()
>>> # 3D — mounting plate with honeycomb pattern
>>> HEX_RADIUS = 5
>>> HEX_WALL_THICKNESS = 1
>>> NB_X, NB_Y = 5, 4

>>> spacing_x = HEX_RADIUS * np.sqrt(3)
>>> spacing_y = HEX_RADIUS * 1.5

>>> hole = circle(HEX_RADIUS, segment_count=6).rotate(30)
>>> hole = hole.shrink(HEX_WALL_THICKNESS / 2)

>>> holes = hole.linear_pattern(
...     counts=[NB_X, math.ceil(NB_Y / 2)],
...     steps=[np.array([spacing_x, 0]), np.array([0, 2 * spacing_y])],
... )
>>> holes += holes.translate([spacing_x / 2, spacing_y])
>>> holes = holes.translate(-holes.centroid)

>>> honeycomb_extruded_plate = extruded_plate - holes.linear_extrude(PLATE_THICKNESS)
>>> honeycomb_extruded_plate.to_screen()
>>> # 3D — apply a math function to a solid coordinates
>>> waved_sphere = sphere(10)
>>> vertex_coordinates = waved_sphere.vertex_coordinates
>>> vertex_coordinates[:, 2] += 2 * np.sin(vertex_coordinates[:, 0])
>>> waved_sphere = waved_sphere.recoordinate(vertex_coordinates)
>>> waved_sphere.to_screen()
>>> # 3D — parametric ball bearing
>>> BALL_RADIUS    = 3
>>> RACE_RADIUS    = 15
>>> NB_BALLS       = 11
>>> CLEARANCE      = 0.1
>>> RING_HEIGHT    = 7
>>> RACE_THICKNESS = 10

>>> groove  = circle(BALL_RADIUS + CLEARANCE) | rectangle([BALL_RADIUS, RING_HEIGHT])
>>> race    = rectangle([RACE_THICKNESS, RING_HEIGHT]) - groove
>>> bearing = race.radial_extrude(axis=y(), pivot=x(RACE_RADIUS)).color(GRAY)

>>> ball = sphere(BALL_RADIUS).color(ORANGE)
>>> bearing += ball.radial_pattern(count=NB_BALLS, axis=y(), pivot=x(RACE_RADIUS))

>>> bearing.to_screen()
>>> # 3D — dice
>>> SIZE = 20

>>> dice = cuboid(SIZE)
>>> pip  = sphere(SIZE / 12).translate(z(SIZE / 2))

>>> one   = pip
>>> two = (
...     pip.translate([SIZE / 4, SIZE / 4, 0]) +
...     pip.translate([-SIZE / 4, -SIZE / 4, 0])
... )
>>> three = one + two
>>> four  = two + two.rotate(90, z())
>>> five  = one + four
>>> six   = four + pip.translate(x(SIZE / 4)) + pip.translate(x(-SIZE / 4))

>>> dice -= (
...     one
...     + two.rotate(90, x())
...     + three.rotate(90, y())
...     + four.rotate(-90, y())
...     + five.rotate(-90, x())
...     + six.rotate(-180, x())
... )

>>> dice.to_screen()
>>> # 3D — storage box
>>> SIZE_OUTER = 20
>>> SIZE_INNER = 18
>>> FILLET = 1
>>> BASE_HEIGHT = 10
>>> CUT_HEIGHT = 8
>>> CAP_HEIGHT_OUTER = 1.5
>>> CAP_HEIGHT_INNER = 3
>>> CAP_OFFSET_X = 25
>>> CUT_OFFSET_Z = 2

>>> outer_base = square(SIZE_OUTER).fillet(FILLET).linear_extrude(BASE_HEIGHT)
>>> inner_cut = square(SIZE_INNER).linear_extrude(CUT_HEIGHT).translate(z(CUT_OFFSET_Z))
>>> base = outer_base - inner_cut

>>> cap_outer = square(SIZE_OUTER).fillet(FILLET).linear_extrude(CAP_HEIGHT_OUTER)
>>> cap_inner = square(SIZE_INNER).linear_extrude(CAP_HEIGHT_INNER)
>>> cap = (cap_outer | cap_inner).translate(x(CAP_OFFSET_X))

>>> storage_box = base + cap
>>> storage_box.to_screen()