Skip to main content

Parts

A Part is a solid. It may consist of several separate bodies (part.solids() lists them).

Primitives​

from smlibpy import *

Box(40, 30, 10) # length (X), width (Y), height (Z)
Cylinder(5, 20) # radius, height, along Z
Cone(10, 4, 15) # bottom radius, top radius, height
Cone(10, 0, 15) # a pointed cone
Sphere(8)
Torus(20, 4) # major and minor radius
Wedge(20, 10, 8) # a ramp

All are centered on the origin; align changes that per axis:

Box(40, 30, 10, align=(Align.CENTER, Align.CENTER, Align.MIN))   # sits on the XY plane

Extrude​

plate = Rectangle(40, 30).extrude(5)              # along the sketch normal
both = Circle(5).extrude(10, both=True) # 10 to each side
drafted = Rectangle(30, 30).extrude(10, taper=8) # sides lean in by 8 degrees
slanted = Circle(5).extrude(20, direction=(0, 1, 2))

A negative amount extrudes against the normal, which is how pockets are cut into faces:

part = Box(50, 50, 20)
part -= Rectangle(30, 20).on(part.faces().top()).extrude(-5)

Revolve​

Revolve a sketch about an axis in its plane. By default the axis is the sketch's local Y axis through its plane origin. A Polygon keeps its plane origin at the world origin, so on Plane.front the default axis is the world Z axis, the usual lathe setup. Centered constructors (Rectangle, Circle, ...) and make_face put the plane origin in the middle of the region: for Rectangle(10, 20).translate(15, 0).on(Plane.front) the default axis is the line x = 15, which crosses the region, so revolve() raises. Pass the axis:

section = Polygon((10, 0), (30, 0), (30, 5), (15, 5), (15, 20), (10, 20))
spool = section.on(Plane.front).revolve()
quarter = section.on(Plane.front).revolve(Z, 90)
tube = Rectangle(10, 20).translate(15, 0).on(Plane.front).revolve(Z)

Loft​

A loft blends a series of cross sections:

transition = loft([Rectangle(30, 30), Circle(12).translate(0, 0, 25)])
vase = loft([Circle(15), Circle(25).translate(0, 0, 30), Circle(10).translate(0, 0, 60)])
straight = loft([Rectangle(20, 20), RegularPolygon(10, 6).translate(0, 0, 20)], ruled=True)

Sweep​

A sweep moves a profile along a path. smlibpy centers the profile on the start of the path and turns it to face along the path, so profiles are simply drawn in XY:

path = Spline((0, 0, 0), (0, 20, 30), (40, 20, 50))
tube = sweep(Circle(3) - Circle(2), path)

spring = sweep(Circle(1), Helix(pitch=5, height=30, radius=10))

frame = sweep(Rectangle(6, 4), Polyline((0, 0, 0), (0, 0, 40), (40, 0, 40))) # mitered corner
elbow = sweep(Circle(4), Wire([Line((0, 0, 0), (0, 0, 20)),
CenterArc((15, 20), 15, 180, -90, plane=Plane.front)]))

translational=True keeps the profile's orientation fixed along the path instead of turning it.

Booleans and patterns​

block = Box(60, 40, 20)
block -= Cylinder(8, 30) # through hole
block += Cylinder(6, 10).translate(0, 0, 15) # boss on top
block &= Sphere(40) # keep what's inside a sphere

plate = Box(80, 60, 6) - GridLocations(60, 40, 2, 2) * Cylinder(3, 10)
wheel = Cylinder(40, 8) - PolarLocations(25, 6) * Cylinder(6, 10)

Holes​

Hole tools point down from the origin, so placed on a face they drill into it:

part = Box(60, 40, 10)
top = part.faces().top()
part -= Hole(3, 10).on(top) # plain, at the center
part -= (GridLocations(40, 20, 2, 2) * CounterBoreHole(2, 4, 3, 10)).on(top)
part -= (Pos(-20, 0) * CounterSinkHole(2, 4, 10)).on(top)

CounterBoreHole(radius, counter_bore_radius, counter_bore_depth, depth) and CounterSinkHole(radius, counter_sink_radius, depth, angle=82).

Moving and copying​

Parts move like every shape: translate, rotate(axis, angle), mirror(plane), scale(factor), moved(location) and on(plane).

half = Box(20, 10, 10).translate(10, 0, 0)
whole = half + half.mirror(Plane.YZ)

Next: features.