Import CAD projects and cad-router v1
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
# Simple CAD Examples
|
||||
|
||||
These examples cover compact part generators that are not already represented
|
||||
by the benchmark suite.
|
||||
|
||||
The remaining prompts are:
|
||||
|
||||
1. Cylindrical spacer sleeve with a central through-bore and rounded rim edges.
|
||||
2. Square mounting block with a vertical through-hole and two side clearance holes.
|
||||
3. Gusset plate with a triangular web, base holes, and softened perimeter edges.
|
||||
4. Rectangular clamp block with a split slot and two transverse screw holes.
|
||||
5. Shaft collar with a central bore, radial set-screw hole, and chamfered faces.
|
||||
6. Pulley wheel with a central hub, outer groove, and circular through-bore.
|
||||
7. Spur gear blank with central bore, raised hub, and simplified perimeter teeth.
|
||||
8. Flywheel disk with central bore, annular rim, and lightening holes.
|
||||
9. Cam follower roller with central bearing bore and rounded outer profile.
|
||||
10. Small enclosure cover with raised rim, corner screw holes, and shallow recessed center.
|
||||
11. Cylindrical cap with hollow interior, top boss, and rounded external edges.
|
||||
12. Retainer plate with elongated slot, two circular holes, and chamfered perimeter.
|
||||
13. Keyed shaft hub with central bore, keyway slot, and bolt-hole pattern.
|
||||
14. T-slot slider block with central channel, side relief cuts, and mounting holes.
|
||||
15. Mounting plate with central circular cutout, elongated side slot, four corner holes, and rounded edges.
|
||||
16. Basic shape mating test fixture for assembly-helper surface and collision checks.
|
||||
|
||||
The flat rectangular plate, circular flange, L-bracket, U/clevis bracket, and
|
||||
open-top electronics enclosure examples are intentionally omitted here because
|
||||
`models/benchmarks/` already carries richer versions.
|
||||
|
||||
## Files
|
||||
|
||||
- `*.step`: Primary STEP files for each simple example.
|
||||
- `*.py`: Python generators for each example.
|
||||
- `simple_model_library.py`: Shared build123d implementation helpers used by the generators.
|
||||
@@ -0,0 +1,307 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from math import sqrt
|
||||
|
||||
from build123d import *
|
||||
from cadpy.assembly import AssemblyHelper
|
||||
|
||||
|
||||
# Units: millimeters.
|
||||
# Origin: base plate center, XY on plate center plane, +Z upward.
|
||||
# The cone uses a shallow visible seat because it is taller than the 10 mm base.
|
||||
# The triangular prism uses a full-depth V-groove so the matching angled faces
|
||||
# visibly nest while the part remains a separate component.
|
||||
# Two seats are intentionally over-inserted to exercise the viewer's collision
|
||||
# analysis overlay. The square block is exactly seated to exercise contact
|
||||
# surface highlighting.
|
||||
|
||||
BASE_LENGTH = 120.0
|
||||
BASE_WIDTH = 70.0
|
||||
BASE_THICKNESS = 10.0
|
||||
BASE_TOP_Z = BASE_THICKNESS / 2
|
||||
CLEARANCE = 0.2
|
||||
|
||||
PEG_DIAMETER = 16.0
|
||||
PEG_HEIGHT = 25.0
|
||||
BLOCK_SIZE = 18.0
|
||||
CONE_BASE_DIAMETER = 22.0
|
||||
CONE_HEIGHT = 25.0
|
||||
SPHERE_DIAMETER = 20.0
|
||||
PRISM_LENGTH = 35.0
|
||||
PRISM_SIDE = 18.0
|
||||
PRISM_HEIGHT = sqrt(3.0) * PRISM_SIDE / 2.0
|
||||
|
||||
POCKET_DEPTH = 3.0
|
||||
CONE_SEAT_DEPTH = 5.0
|
||||
SPHERE_CUP_RADIUS = SPHERE_DIAMETER / 2.0 + CLEARANCE / 2.0
|
||||
V_GROOVE_DEPTH = BASE_THICKNESS
|
||||
V_GROOVE_SIDE_CLEARANCE = CLEARANCE / 2.0
|
||||
V_GROOVE_BOTTOM_WIDTH = 4.0 * V_GROOVE_SIDE_CLEARANCE / sqrt(3.0)
|
||||
V_GROOVE_TOP_WIDTH = 2.0 * (V_GROOVE_DEPTH + 2.0 * V_GROOVE_SIDE_CLEARANCE) / sqrt(3.0)
|
||||
PEG_COLLISION_DEPTH = 0.8
|
||||
PRISM_COLLISION_DEPTH = 1.0
|
||||
BLOCK_CONTACT_OFFSET = 0.0
|
||||
|
||||
CUBE_TOP_PAD_SIZE = 14.0
|
||||
CUBE_TOP_PAD_HEIGHT = 2.5
|
||||
CUBE_TOP_POST_RADIUS = 1.8
|
||||
CUBE_TOP_POST_HEIGHT = 7.0
|
||||
CUBE_TOP_POST_SPACING = 8.0
|
||||
CUBE_TOP_CAP_LENGTH = 13.0
|
||||
CUBE_TOP_CAP_WIDTH = 4.5
|
||||
CUBE_TOP_CAP_HEIGHT = 2.5
|
||||
CUBE_TOP_BEAD_DIAMETER = 4.5
|
||||
|
||||
STATIONS = {
|
||||
"cylindrical_peg": (-48.0, 0.0),
|
||||
"square_block": (-24.0, 0.0),
|
||||
"cone": (0.0, 0.0),
|
||||
"sphere": (24.0, 0.0),
|
||||
"triangular_prism": (48.0, 0.0),
|
||||
}
|
||||
|
||||
|
||||
def _triangular_prism(side: float, length: float):
|
||||
height = sqrt(3.0) * side / 2.0
|
||||
with BuildPart() as prism:
|
||||
with BuildSketch(Plane.XZ):
|
||||
Polygon(
|
||||
(-side / 2.0, height / 2.0),
|
||||
(side / 2.0, height / 2.0),
|
||||
(0.0, -height / 2.0),
|
||||
)
|
||||
extrude(amount=length)
|
||||
return prism.part.moved(Location((0.0, length / 2.0, 0.0)))
|
||||
|
||||
|
||||
def _v_groove_tool(depth: float, length: float, side_clearance: float):
|
||||
top_half_width = (depth + 2.0 * side_clearance) / sqrt(3.0)
|
||||
bottom_half_width = 2.0 * side_clearance / sqrt(3.0)
|
||||
with BuildPart() as groove:
|
||||
with BuildSketch(Plane.XZ):
|
||||
Polygon(
|
||||
(-top_half_width, 0.0),
|
||||
(top_half_width, 0.0),
|
||||
(bottom_half_width, -depth),
|
||||
(-bottom_half_width, -depth),
|
||||
)
|
||||
extrude(amount=length)
|
||||
return groove.part.moved(Location((0.0, length / 2.0, 0.0)))
|
||||
|
||||
|
||||
def _make_base():
|
||||
base = Box(BASE_LENGTH, BASE_WIDTH, BASE_THICKNESS)
|
||||
|
||||
peg_x, peg_y = STATIONS["cylindrical_peg"]
|
||||
peg_pocket = Cylinder(
|
||||
radius=(PEG_DIAMETER + CLEARANCE) / 2.0,
|
||||
height=POCKET_DEPTH + 0.4,
|
||||
).moved(Location((peg_x, peg_y, BASE_TOP_Z - POCKET_DEPTH / 2.0 + 0.2)))
|
||||
base = base - peg_pocket
|
||||
|
||||
block_x, block_y = STATIONS["square_block"]
|
||||
block_pocket = Box(
|
||||
BLOCK_SIZE + CLEARANCE,
|
||||
BLOCK_SIZE + CLEARANCE,
|
||||
POCKET_DEPTH + 0.4,
|
||||
).moved(Location((block_x, block_y, BASE_TOP_Z - POCKET_DEPTH / 2.0 + 0.2)))
|
||||
base = base - block_pocket
|
||||
|
||||
cone_x, cone_y = STATIONS["cone"]
|
||||
cone_seat = Cone(
|
||||
0.0,
|
||||
(CONE_BASE_DIAMETER + CLEARANCE) / 2.0,
|
||||
CONE_SEAT_DEPTH,
|
||||
).moved(Location((cone_x, cone_y, BASE_TOP_Z - CONE_SEAT_DEPTH / 2.0)))
|
||||
base = base - cone_seat
|
||||
|
||||
sphere_x, sphere_y = STATIONS["sphere"]
|
||||
sphere_cup = Sphere(SPHERE_CUP_RADIUS).moved(Location((sphere_x, sphere_y, BASE_TOP_Z)))
|
||||
base = base - sphere_cup
|
||||
|
||||
prism_x, prism_y = STATIONS["triangular_prism"]
|
||||
groove = _v_groove_tool(
|
||||
V_GROOVE_DEPTH,
|
||||
PRISM_LENGTH + CLEARANCE,
|
||||
V_GROOVE_SIDE_CLEARANCE,
|
||||
).moved(Location((prism_x, prism_y, 0.0)))
|
||||
base = base - groove
|
||||
|
||||
base.label = "base_plate"
|
||||
base.color = Color(0.58, 0.62, 0.66, 1.0)
|
||||
return base
|
||||
|
||||
|
||||
def _make_peg():
|
||||
peg = Cylinder(radius=PEG_DIAMETER / 2.0, height=PEG_HEIGHT)
|
||||
peg.label = "cylindrical_peg"
|
||||
peg.color = Color(0.86, 0.24, 0.20, 1.0)
|
||||
return peg
|
||||
|
||||
|
||||
def _make_block():
|
||||
block = Box(BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)
|
||||
block.label = "square_block"
|
||||
block.color = Color(0.18, 0.53, 0.88, 1.0)
|
||||
return block
|
||||
|
||||
|
||||
def _make_cone():
|
||||
cone = Cone(0.0, CONE_BASE_DIAMETER / 2.0, CONE_HEIGHT)
|
||||
cone.label = "cone"
|
||||
cone.color = Color(0.95, 0.64, 0.16, 1.0)
|
||||
return cone
|
||||
|
||||
|
||||
def _make_sphere():
|
||||
sphere = Sphere(SPHERE_DIAMETER / 2.0)
|
||||
sphere.label = "sphere"
|
||||
sphere.color = Color(0.45, 0.72, 0.34, 1.0)
|
||||
return sphere
|
||||
|
||||
|
||||
def _make_prism():
|
||||
prism = _triangular_prism(PRISM_SIDE, PRISM_LENGTH)
|
||||
prism.label = "triangular_prism"
|
||||
prism.color = Color(0.58, 0.34, 0.74, 1.0)
|
||||
return prism
|
||||
|
||||
|
||||
def _make_cube_top_pad():
|
||||
pad = Box(CUBE_TOP_PAD_SIZE, CUBE_TOP_PAD_SIZE, CUBE_TOP_PAD_HEIGHT).moved(
|
||||
Location((0.0, 0.0, CUBE_TOP_PAD_HEIGHT / 2.0))
|
||||
)
|
||||
pad.label = "cube_top_pad"
|
||||
pad.color = Color(0.10, 0.14, 0.20, 1.0)
|
||||
return pad
|
||||
|
||||
|
||||
def _make_cube_top_post(x_offset: float, name: str):
|
||||
post = Cylinder(radius=CUBE_TOP_POST_RADIUS, height=CUBE_TOP_POST_HEIGHT).moved(
|
||||
Location((x_offset, 0.0, CUBE_TOP_PAD_HEIGHT + CUBE_TOP_POST_HEIGHT / 2.0))
|
||||
)
|
||||
post.label = name
|
||||
post.color = Color(0.84, 0.30, 0.50, 1.0)
|
||||
return post
|
||||
|
||||
|
||||
def _make_cube_top_cap():
|
||||
cap = Box(CUBE_TOP_CAP_LENGTH, CUBE_TOP_CAP_WIDTH, CUBE_TOP_CAP_HEIGHT).moved(
|
||||
Location(
|
||||
(
|
||||
0.0,
|
||||
0.0,
|
||||
CUBE_TOP_PAD_HEIGHT + CUBE_TOP_POST_HEIGHT + CUBE_TOP_CAP_HEIGHT / 2.0,
|
||||
)
|
||||
)
|
||||
)
|
||||
cap.label = "cube_top_bridge_cap"
|
||||
cap.color = Color(0.12, 0.70, 0.74, 1.0)
|
||||
return cap
|
||||
|
||||
|
||||
def _make_cube_top_bead():
|
||||
bead_radius = CUBE_TOP_BEAD_DIAMETER / 2.0
|
||||
bead = Sphere(bead_radius).moved(
|
||||
Location(
|
||||
(
|
||||
0.0,
|
||||
0.0,
|
||||
CUBE_TOP_PAD_HEIGHT + CUBE_TOP_POST_HEIGHT + CUBE_TOP_CAP_HEIGHT + bead_radius,
|
||||
)
|
||||
)
|
||||
)
|
||||
bead.label = "cube_top_bead"
|
||||
bead.color = Color(0.98, 0.86, 0.20, 1.0)
|
||||
return bead
|
||||
|
||||
|
||||
def _make_cube_top_subassembly():
|
||||
subassembly = AssemblyHelper("cube_top_subassembly")
|
||||
subassembly.add(_make_cube_top_pad(), "cube_top_pad")
|
||||
subassembly.add(
|
||||
_make_cube_top_post(-CUBE_TOP_POST_SPACING / 2.0, "cube_top_left_post"),
|
||||
"cube_top_left_post",
|
||||
)
|
||||
subassembly.add(
|
||||
_make_cube_top_post(CUBE_TOP_POST_SPACING / 2.0, "cube_top_right_post"),
|
||||
"cube_top_right_post",
|
||||
)
|
||||
subassembly.add(_make_cube_top_cap(), "cube_top_bridge_cap")
|
||||
subassembly.add(_make_cube_top_bead(), "cube_top_bead")
|
||||
return subassembly.build()
|
||||
|
||||
|
||||
def gen_step():
|
||||
asm = AssemblyHelper("basic_shape_mating_test_fixture")
|
||||
|
||||
base = asm.add(_make_base(), "base_plate")
|
||||
peg = asm.add(_make_peg(), "cylindrical_peg")
|
||||
block = asm.add(_make_block(), "square_block")
|
||||
cone = asm.add(_make_cone(), "cone")
|
||||
sphere = asm.add(_make_sphere(), "sphere")
|
||||
prism = asm.add(_make_prism(), "triangular_prism")
|
||||
cube_top_subassembly = asm.add(
|
||||
_make_cube_top_subassembly(),
|
||||
"cube_top_subassembly",
|
||||
)
|
||||
|
||||
peg_x, peg_y = STATIONS["cylindrical_peg"]
|
||||
peg_seat = asm.rigid_frame(base, "peg_pocket_floor", Location((peg_x, peg_y, BASE_TOP_Z - POCKET_DEPTH)))
|
||||
peg_bottom = asm.rigid_frame(peg, "bottom_center", Location((0.0, 0.0, -PEG_HEIGHT / 2.0)))
|
||||
asm.face_to_face(peg_seat, peg_bottom, offset=-PEG_COLLISION_DEPTH)
|
||||
|
||||
block_x, block_y = STATIONS["square_block"]
|
||||
block_seat = asm.rigid_frame(
|
||||
base,
|
||||
"block_pocket_floor",
|
||||
Location((block_x, block_y, BASE_TOP_Z - POCKET_DEPTH)),
|
||||
)
|
||||
block_bottom = asm.rigid_frame(block, "bottom_center", Location((0.0, 0.0, -BLOCK_SIZE / 2.0)))
|
||||
asm.face_to_face(block_seat, block_bottom, offset=BLOCK_CONTACT_OFFSET)
|
||||
|
||||
asm.rigid_frame(block, "top_center", Location((0.0, 0.0, BLOCK_SIZE / 2.0)))
|
||||
cube_top_seat = asm.rigid_frame(
|
||||
base,
|
||||
"cube_top_subassembly_seat",
|
||||
Location((block_x, block_y, BASE_TOP_Z - POCKET_DEPTH + BLOCK_CONTACT_OFFSET + BLOCK_SIZE)),
|
||||
)
|
||||
cube_top_subassembly_bottom = asm.rigid_frame(
|
||||
cube_top_subassembly,
|
||||
"bottom_center",
|
||||
Location((0.0, 0.0, 0.0)),
|
||||
)
|
||||
asm.face_to_face(
|
||||
cube_top_seat,
|
||||
cube_top_subassembly_bottom,
|
||||
label="cube_top_subassembly_on_square_block",
|
||||
)
|
||||
|
||||
cone_x, cone_y = STATIONS["cone"]
|
||||
cone_tip_seat = asm.rigid_frame(
|
||||
base,
|
||||
"cone_countersink_tip",
|
||||
Location((cone_x, cone_y, BASE_TOP_Z - CONE_SEAT_DEPTH)),
|
||||
)
|
||||
cone_tip = asm.rigid_frame(cone, "tip", Location((0.0, 0.0, -CONE_HEIGHT / 2.0)))
|
||||
asm.coaxial(cone_tip_seat, cone_tip, offset=0.1)
|
||||
|
||||
sphere_x, sphere_y = STATIONS["sphere"]
|
||||
sphere_cup_center = asm.rigid_frame(base, "sphere_cup_center", Location((sphere_x, sphere_y, BASE_TOP_Z)))
|
||||
sphere_center = asm.rigid_frame(sphere, "center", Location((0.0, 0.0, 0.0)))
|
||||
asm.coaxial(sphere_cup_center, sphere_center, offset=0.1)
|
||||
|
||||
prism_x, prism_y = STATIONS["triangular_prism"]
|
||||
prism_v_bottom = asm.rigid_frame(
|
||||
base,
|
||||
"v_groove_bottom",
|
||||
Location((prism_x, prism_y, BASE_TOP_Z - V_GROOVE_DEPTH)),
|
||||
)
|
||||
prism_bottom_vertex = asm.rigid_frame(
|
||||
prism,
|
||||
"bottom_vertex",
|
||||
Location((0.0, 0.0, -PRISM_HEIGHT / 2.0)),
|
||||
)
|
||||
asm.face_to_face(prism_v_bottom, prism_bottom_vertex, offset=-PRISM_COLLISION_DEPTH)
|
||||
|
||||
return asm.build()
|
||||
@@ -0,0 +1,7 @@
|
||||
# Prompt: Cam follower roller with central bearing bore and rounded outer profile.
|
||||
|
||||
from simple_model_library import make_cam_follower_roller
|
||||
|
||||
|
||||
def gen_step():
|
||||
return make_cam_follower_roller()
|
||||
@@ -0,0 +1,7 @@
|
||||
# Prompt: Cylindrical cap with hollow interior, top boss, and rounded external edges.
|
||||
|
||||
from simple_model_library import make_cylindrical_cap
|
||||
|
||||
|
||||
def gen_step():
|
||||
return make_cylindrical_cap()
|
||||
@@ -0,0 +1,7 @@
|
||||
# Prompt: Cylindrical spacer sleeve with a central through-bore and rounded rim edges.
|
||||
|
||||
from simple_model_library import make_cylindrical_spacer_sleeve
|
||||
|
||||
|
||||
def gen_step():
|
||||
return make_cylindrical_spacer_sleeve()
|
||||
@@ -0,0 +1,7 @@
|
||||
# Prompt: Flywheel disk with central bore, annular rim, and lightening holes.
|
||||
|
||||
from simple_model_library import make_flywheel_disk
|
||||
|
||||
|
||||
def gen_step():
|
||||
return make_flywheel_disk()
|
||||
@@ -0,0 +1,7 @@
|
||||
# Prompt: Gusset plate with a triangular web, base holes, and softened perimeter edges.
|
||||
|
||||
from simple_model_library import make_gusset_plate
|
||||
|
||||
|
||||
def gen_step():
|
||||
return make_gusset_plate()
|
||||
@@ -0,0 +1,7 @@
|
||||
# Prompt: Keyed shaft hub with central bore, keyway slot, and bolt-hole pattern.
|
||||
|
||||
from simple_model_library import make_keyed_shaft_hub
|
||||
|
||||
|
||||
def gen_step():
|
||||
return make_keyed_shaft_hub()
|
||||
@@ -0,0 +1,7 @@
|
||||
# Prompt: Mounting plate with central circular cutout, elongated side slot, four corner holes, and rounded edges.
|
||||
|
||||
from simple_model_library import make_mounting_plate
|
||||
|
||||
|
||||
def gen_step():
|
||||
return make_mounting_plate()
|
||||
@@ -0,0 +1,7 @@
|
||||
# Prompt: Pulley wheel with a central hub, outer groove, and circular through-bore.
|
||||
|
||||
from simple_model_library import make_pulley_wheel
|
||||
|
||||
|
||||
def gen_step():
|
||||
return make_pulley_wheel()
|
||||
@@ -0,0 +1,7 @@
|
||||
# Prompt: Rectangular clamp block with a split slot and two transverse screw holes.
|
||||
|
||||
from simple_model_library import make_rectangular_clamp_block
|
||||
|
||||
|
||||
def gen_step():
|
||||
return make_rectangular_clamp_block()
|
||||
@@ -0,0 +1,7 @@
|
||||
# Prompt: Retainer plate with elongated slot, two circular holes, and chamfered perimeter.
|
||||
|
||||
from simple_model_library import make_retainer_plate
|
||||
|
||||
|
||||
def gen_step():
|
||||
return make_retainer_plate()
|
||||
@@ -0,0 +1,7 @@
|
||||
# Prompt: Shaft collar with a central bore, radial set-screw hole, and chamfered faces.
|
||||
|
||||
from simple_model_library import make_shaft_collar
|
||||
|
||||
|
||||
def gen_step():
|
||||
return make_shaft_collar()
|
||||
@@ -0,0 +1,451 @@
|
||||
# Prompt: Shared implementation library for the simple CAD prompt scripts.
|
||||
|
||||
from math import cos, sin, tau
|
||||
|
||||
from build123d import (
|
||||
Align,
|
||||
Box,
|
||||
BuildPart,
|
||||
BuildSketch,
|
||||
Color,
|
||||
Cylinder,
|
||||
Location,
|
||||
Locations,
|
||||
Mode,
|
||||
Plane,
|
||||
Polygon,
|
||||
RectangleRounded,
|
||||
Torus,
|
||||
add,
|
||||
chamfer,
|
||||
extrude,
|
||||
fillet,
|
||||
)
|
||||
|
||||
|
||||
def _polar_point(radius: float, angle: float) -> tuple[float, float]:
|
||||
return (radius * cos(angle), radius * sin(angle))
|
||||
|
||||
|
||||
def _safe_fillet(shape, edges, radius: float):
|
||||
selected = list(edges)
|
||||
if not selected:
|
||||
return shape
|
||||
try:
|
||||
return fillet(selected, radius=radius)
|
||||
except Exception:
|
||||
return shape
|
||||
|
||||
|
||||
def _safe_chamfer(shape, edges, length: float):
|
||||
selected = list(edges)
|
||||
if not selected:
|
||||
return shape
|
||||
try:
|
||||
return chamfer(selected, length=length)
|
||||
except Exception:
|
||||
return shape
|
||||
|
||||
|
||||
def _line_edges(shape):
|
||||
return [edge for edge in shape.edges() if str(edge.geom_type).endswith("LINE")]
|
||||
|
||||
|
||||
def _circular_edges(shape, *, radius: float | None = None, axis: str | None = None, coordinate: float | None = None):
|
||||
edges = []
|
||||
for edge in shape.edges():
|
||||
try:
|
||||
edge_radius = edge.radius
|
||||
edge_center = edge.arc_center
|
||||
edge_normal = edge.normal()
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if radius is not None and abs(edge_radius - radius) > 0.08:
|
||||
continue
|
||||
|
||||
if axis is not None:
|
||||
components = {
|
||||
"x": abs(edge_normal.X),
|
||||
"y": abs(edge_normal.Y),
|
||||
"z": abs(edge_normal.Z),
|
||||
}
|
||||
if components[axis] < 1.0 - 1e-4:
|
||||
continue
|
||||
|
||||
if coordinate is not None:
|
||||
coord = {"x": edge_center.X, "y": edge_center.Y, "z": edge_center.Z}[axis or "z"]
|
||||
if abs(coord - coordinate) > 0.08:
|
||||
continue
|
||||
|
||||
edges.append(edge)
|
||||
return edges
|
||||
|
||||
|
||||
def _finish(shape, label: str, color: Color):
|
||||
shape.label = label
|
||||
shape.color = color
|
||||
return shape
|
||||
|
||||
|
||||
def _hole_z(diameter: float, height: float, x: float, y: float, z_min: float = -1.0):
|
||||
with Locations(Location((x, y, z_min))):
|
||||
Cylinder(
|
||||
radius=diameter / 2.0,
|
||||
height=height,
|
||||
align=(Align.CENTER, Align.CENTER, Align.MIN),
|
||||
mode=Mode.SUBTRACT,
|
||||
)
|
||||
|
||||
|
||||
def _hole_x(diameter: float, length: float, x: float, y: float, z: float):
|
||||
with Locations(Location((x, y, z))):
|
||||
Cylinder(
|
||||
radius=diameter / 2.0,
|
||||
height=length,
|
||||
rotation=(0.0, 90.0, 0.0),
|
||||
align=(Align.CENTER, Align.CENTER, Align.CENTER),
|
||||
mode=Mode.SUBTRACT,
|
||||
)
|
||||
|
||||
|
||||
def _hole_y(diameter: float, length: float, x: float, y: float, z: float):
|
||||
with Locations(Location((x, y, z))):
|
||||
Cylinder(
|
||||
radius=diameter / 2.0,
|
||||
height=length,
|
||||
rotation=(90.0, 0.0, 0.0),
|
||||
align=(Align.CENTER, Align.CENTER, Align.CENTER),
|
||||
mode=Mode.SUBTRACT,
|
||||
)
|
||||
|
||||
|
||||
def _slot_z(length: float, width: float, height: float, center: tuple[float, float], z_min: float, *, axis: str = "x"):
|
||||
span = max(0.0, length - width)
|
||||
if axis == "x":
|
||||
if span > 0.01:
|
||||
with Locations(Location((center[0], center[1], z_min))):
|
||||
Box(span, width, height, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT)
|
||||
for x_offset in (-span / 2.0, span / 2.0):
|
||||
_hole_z(width, height, center[0] + x_offset, center[1], z_min)
|
||||
else:
|
||||
if span > 0.01:
|
||||
with Locations(Location((center[0], center[1], z_min))):
|
||||
Box(width, span, height, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT)
|
||||
for y_offset in (-span / 2.0, span / 2.0):
|
||||
_hole_z(width, height, center[0], center[1] + y_offset, z_min)
|
||||
|
||||
|
||||
def _trapezoid_tooth_profile(
|
||||
*,
|
||||
teeth: int,
|
||||
root_radius: float,
|
||||
tip_radius: float,
|
||||
phase: float,
|
||||
root_span_fraction: float = 0.72,
|
||||
tip_span_fraction: float = 0.38,
|
||||
):
|
||||
points = []
|
||||
pitch_angle = tau / teeth
|
||||
for tooth_index in range(teeth):
|
||||
center_angle = phase + tooth_index * pitch_angle
|
||||
points.extend(
|
||||
(
|
||||
_polar_point(root_radius, center_angle - root_span_fraction * pitch_angle / 2.0),
|
||||
_polar_point(tip_radius, center_angle - tip_span_fraction * pitch_angle / 2.0),
|
||||
_polar_point(tip_radius, center_angle + tip_span_fraction * pitch_angle / 2.0),
|
||||
_polar_point(root_radius, center_angle + root_span_fraction * pitch_angle / 2.0),
|
||||
)
|
||||
)
|
||||
return points
|
||||
|
||||
|
||||
def make_cylindrical_spacer_sleeve():
|
||||
outer_radius = 15.0
|
||||
bore_radius = 5.0
|
||||
height = 28.0
|
||||
|
||||
with BuildPart() as model:
|
||||
Cylinder(outer_radius, height, align=(Align.CENTER, Align.CENTER, Align.MIN))
|
||||
_hole_z(bore_radius * 2.0, height + 2.0, 0.0, 0.0)
|
||||
|
||||
rim_edges = []
|
||||
for z_pos in (0.0, height):
|
||||
rim_edges.extend(_circular_edges(model.part, radius=outer_radius, axis="z", coordinate=z_pos))
|
||||
rim_edges.extend(_circular_edges(model.part, radius=bore_radius, axis="z", coordinate=z_pos))
|
||||
part = _safe_fillet(model.part, rim_edges, 1.1)
|
||||
return _finish(part, "cylindrical_spacer_sleeve_through_bore_rounded_rims", Color(0.68, 0.68, 0.64, 1.0))
|
||||
|
||||
|
||||
def make_square_mounting_block():
|
||||
size = 48.0
|
||||
height = 28.0
|
||||
|
||||
with BuildPart() as model:
|
||||
Box(size, size, height, align=(Align.CENTER, Align.CENTER, Align.MIN))
|
||||
_hole_z(12.0, height + 2.0, 0.0, 0.0)
|
||||
for y_pos in (-14.0, 14.0):
|
||||
_hole_x(5.5, size + 2.0, 0.0, y_pos, height / 2.0)
|
||||
|
||||
part = _safe_chamfer(model.part, _line_edges(model.part), 0.8)
|
||||
return _finish(part, "square_mounting_block_vertical_and_side_clearance_holes", Color(0.50, 0.58, 0.64, 1.0))
|
||||
|
||||
|
||||
def make_gusset_plate():
|
||||
base_length = 88.0
|
||||
base_width = 30.0
|
||||
base_thickness = 6.0
|
||||
web_thickness = 8.0
|
||||
web_height = 48.0
|
||||
|
||||
with BuildPart() as web:
|
||||
with BuildSketch(Plane.YZ):
|
||||
Polygon(
|
||||
[
|
||||
(-12.0, base_thickness),
|
||||
(12.0, base_thickness),
|
||||
(12.0, base_thickness + web_height),
|
||||
],
|
||||
align=None,
|
||||
)
|
||||
extrude(amount=web_thickness)
|
||||
web_part = web.part.moved(Location((-web_thickness / 2.0, 0.0, 0.0)))
|
||||
|
||||
with BuildPart() as model:
|
||||
Box(base_length, base_width, base_thickness, align=(Align.CENTER, Align.CENTER, Align.MIN))
|
||||
add(web_part, mode=Mode.ADD)
|
||||
for x_pos in (-28.0, 28.0):
|
||||
_hole_z(6.0, base_thickness + 2.0, x_pos, -6.0)
|
||||
|
||||
part = _safe_fillet(model.part, _line_edges(model.part), 0.9)
|
||||
return _finish(part, "gusset_plate_triangular_web_base_holes_softened_edges", Color(0.58, 0.63, 0.58, 1.0))
|
||||
|
||||
|
||||
def make_rectangular_clamp_block():
|
||||
length = 70.0
|
||||
width = 34.0
|
||||
height = 28.0
|
||||
|
||||
with BuildPart() as model:
|
||||
Box(length, width, height, align=(Align.CENTER, Align.CENTER, Align.MIN))
|
||||
with Locations(Location((0.0, 0.0, -1.0))):
|
||||
Box(length + 2.0, 4.0, height + 2.0, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT)
|
||||
for x_pos in (-20.0, 20.0):
|
||||
_hole_y(5.5, width + 2.0, x_pos, 0.0, height / 2.0)
|
||||
|
||||
part = _safe_chamfer(model.part, _line_edges(model.part), 0.7)
|
||||
return _finish(part, "rectangular_clamp_block_split_slot_two_transverse_screw_holes", Color(0.57, 0.60, 0.64, 1.0))
|
||||
|
||||
|
||||
def make_shaft_collar():
|
||||
outer_radius = 21.0
|
||||
bore_radius = 10.0
|
||||
height = 16.0
|
||||
|
||||
with BuildPart() as model:
|
||||
Cylinder(outer_radius, height, align=(Align.CENTER, Align.CENTER, Align.MIN))
|
||||
_hole_z(bore_radius * 2.0, height + 2.0, 0.0, 0.0)
|
||||
_hole_x(5.0, outer_radius + 3.0, outer_radius / 2.0, 0.0, height / 2.0)
|
||||
|
||||
edge_set = []
|
||||
for z_pos in (0.0, height):
|
||||
edge_set.extend(_circular_edges(model.part, axis="z", coordinate=z_pos))
|
||||
part = _safe_chamfer(model.part, edge_set, 0.8)
|
||||
return _finish(part, "shaft_collar_bore_radial_set_screw_hole_chamfered_faces", Color(0.46, 0.50, 0.55, 1.0))
|
||||
|
||||
|
||||
def make_pulley_wheel():
|
||||
outer_radius = 35.0
|
||||
thickness = 16.0
|
||||
hub_radius = 18.0
|
||||
hub_height = 24.0
|
||||
|
||||
with BuildPart() as model:
|
||||
Cylinder(outer_radius, thickness, align=(Align.CENTER, Align.CENTER, Align.MIN))
|
||||
with Locations(Location((0.0, 0.0, thickness / 2.0))):
|
||||
Cylinder(hub_radius, hub_height, align=(Align.CENTER, Align.CENTER, Align.CENTER), mode=Mode.ADD)
|
||||
Torus(outer_radius - 1.2, 3.0, mode=Mode.SUBTRACT)
|
||||
_hole_z(10.0, hub_height + 4.0, 0.0, 0.0, z_min=-4.0)
|
||||
|
||||
part = _safe_fillet(model.part, _circular_edges(model.part, axis="z"), 0.8)
|
||||
return _finish(part, "pulley_wheel_central_hub_outer_groove_through_bore", Color(0.42, 0.46, 0.50, 1.0))
|
||||
|
||||
|
||||
def make_spur_gear_blank():
|
||||
thickness = 10.0
|
||||
teeth = 24
|
||||
root_radius = 35.0
|
||||
tip_radius = 39.0
|
||||
hub_radius = 17.0
|
||||
hub_height = 16.0
|
||||
|
||||
with BuildPart() as model:
|
||||
with BuildSketch(Plane.XY):
|
||||
Polygon(
|
||||
_trapezoid_tooth_profile(
|
||||
teeth=teeth,
|
||||
root_radius=root_radius,
|
||||
tip_radius=tip_radius,
|
||||
phase=-tau / teeth / 2.0,
|
||||
),
|
||||
align=None,
|
||||
)
|
||||
extrude(amount=thickness)
|
||||
with Locations(Location((0.0, 0.0, -3.0))):
|
||||
Cylinder(hub_radius, hub_height, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.ADD)
|
||||
_hole_z(18.0, hub_height + 4.0, 0.0, 0.0, z_min=-4.0)
|
||||
|
||||
part = _safe_chamfer(model.part, _circular_edges(model.part, axis="z"), 0.6)
|
||||
return _finish(part, "spur_gear_blank_central_bore_raised_hub_simplified_teeth", Color(0.70, 0.58, 0.36, 1.0))
|
||||
|
||||
|
||||
def make_flywheel_disk():
|
||||
radius = 45.0
|
||||
thickness = 12.0
|
||||
|
||||
with BuildPart() as model:
|
||||
Cylinder(radius, thickness, align=(Align.CENTER, Align.CENTER, Align.MIN))
|
||||
with Locations(Location((0.0, 0.0, thickness - 2.2))):
|
||||
Cylinder(34.0, 3.0, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT)
|
||||
with Locations(Location((0.0, 0.0, -0.8))):
|
||||
Cylinder(34.0, 3.0, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT)
|
||||
_hole_z(18.0, thickness + 2.0, 0.0, 0.0)
|
||||
for index in range(6):
|
||||
x_pos, y_pos = _polar_point(25.0, tau * index / 6)
|
||||
_hole_z(10.0, thickness + 2.0, x_pos, y_pos)
|
||||
|
||||
part = _safe_fillet(model.part, _circular_edges(model.part, axis="z"), 0.8)
|
||||
return _finish(part, "flywheel_disk_central_bore_annular_rim_lightening_holes", Color(0.59, 0.61, 0.63, 1.0))
|
||||
|
||||
|
||||
def make_cam_follower_roller():
|
||||
radius = 16.0
|
||||
width = 18.0
|
||||
|
||||
with BuildPart() as model:
|
||||
Cylinder(radius, width, align=(Align.CENTER, Align.CENTER, Align.MIN))
|
||||
_hole_z(12.0, width + 2.0, 0.0, 0.0)
|
||||
|
||||
edge_set = []
|
||||
for z_pos in (0.0, width):
|
||||
edge_set.extend(_circular_edges(model.part, radius=radius, axis="z", coordinate=z_pos))
|
||||
edge_set.extend(_circular_edges(model.part, radius=6.0, axis="z", coordinate=z_pos))
|
||||
part = _safe_fillet(model.part, edge_set, 1.8)
|
||||
return _finish(part, "cam_follower_roller_bearing_bore_rounded_outer_profile", Color(0.60, 0.64, 0.67, 1.0))
|
||||
|
||||
|
||||
def make_small_enclosure_cover():
|
||||
length = 90.0
|
||||
width = 60.0
|
||||
base_thickness = 4.0
|
||||
rim_height = 3.0
|
||||
|
||||
with BuildPart() as model:
|
||||
with BuildSketch(Plane.XY):
|
||||
RectangleRounded(length, width, 4.0, align=(Align.CENTER, Align.CENTER))
|
||||
extrude(amount=base_thickness)
|
||||
with Locations(Location((0.0, 0.0, base_thickness))):
|
||||
with BuildSketch(Plane.XY):
|
||||
RectangleRounded(length - 10.0, width - 10.0, 3.0, align=(Align.CENTER, Align.CENTER))
|
||||
extrude(amount=rim_height, mode=Mode.ADD)
|
||||
with Locations(Location((0.0, 0.0, base_thickness - 0.8))):
|
||||
Box(58.0, 28.0, rim_height + 1.2, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT)
|
||||
with Locations(Location((0.0, 0.0, base_thickness))):
|
||||
Box(66.0, 36.0, rim_height + 1.0, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT)
|
||||
for x_pos in (-35.0, 35.0):
|
||||
for y_pos in (-22.0, 22.0):
|
||||
_hole_z(4.2, base_thickness + 1.5, x_pos, y_pos)
|
||||
|
||||
part = _safe_fillet(model.part, _line_edges(model.part), 0.5)
|
||||
return _finish(part, "small_enclosure_cover_raised_rim_corner_screw_holes_recessed_center", Color(0.38, 0.51, 0.62, 1.0))
|
||||
|
||||
|
||||
def make_cylindrical_cap():
|
||||
outer_radius = 21.0
|
||||
height = 28.0
|
||||
wall = 3.0
|
||||
top_thickness = 4.0
|
||||
|
||||
with BuildPart() as model:
|
||||
Cylinder(outer_radius, height, align=(Align.CENTER, Align.CENTER, Align.MIN))
|
||||
with Locations(Location((0.0, 0.0, -1.0))):
|
||||
Cylinder(outer_radius - wall, height - top_thickness + 1.0, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT)
|
||||
with Locations(Location((0.0, 0.0, height))):
|
||||
Cylinder(10.0, 6.0, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.ADD)
|
||||
|
||||
part = _safe_fillet(model.part, _circular_edges(model.part, axis="z"), 1.0)
|
||||
return _finish(part, "cylindrical_cap_hollow_interior_top_boss_rounded_external_edges", Color(0.52, 0.57, 0.61, 1.0))
|
||||
|
||||
|
||||
def make_retainer_plate():
|
||||
length = 82.0
|
||||
width = 34.0
|
||||
thickness = 6.0
|
||||
|
||||
with BuildPart() as model:
|
||||
Box(length, width, thickness, align=(Align.CENTER, Align.CENTER, Align.MIN))
|
||||
_slot_z(36.0, 10.0, thickness + 2.0, (0.0, 0.0), -1.0)
|
||||
for x_pos in (-30.0, 30.0):
|
||||
_hole_z(7.0, thickness + 2.0, x_pos, 0.0)
|
||||
|
||||
part = _safe_chamfer(model.part, _line_edges(model.part), 0.8)
|
||||
return _finish(part, "retainer_plate_elongated_slot_two_holes_chamfered_perimeter", Color(0.60, 0.62, 0.66, 1.0))
|
||||
|
||||
|
||||
def make_keyed_shaft_hub():
|
||||
outer_radius = 27.0
|
||||
height = 22.0
|
||||
bore_radius = 10.0
|
||||
|
||||
with BuildPart() as model:
|
||||
Cylinder(outer_radius, height, align=(Align.CENTER, Align.CENTER, Align.MIN))
|
||||
_hole_z(bore_radius * 2.0, height + 2.0, 0.0, 0.0)
|
||||
with Locations(Location((0.0, bore_radius + 2.0, -1.0))):
|
||||
Box(6.0, 7.0, height + 2.0, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT)
|
||||
for index in range(4):
|
||||
x_pos, y_pos = _polar_point(19.5, tau * index / 4.0 + tau / 8.0)
|
||||
_hole_z(5.5, height + 2.0, x_pos, y_pos)
|
||||
|
||||
part = _safe_chamfer(model.part, _circular_edges(model.part, axis="z"), 0.7)
|
||||
return _finish(part, "keyed_shaft_hub_central_bore_keyway_bolt_hole_pattern", Color(0.49, 0.52, 0.56, 1.0))
|
||||
|
||||
|
||||
def make_t_slot_slider_block():
|
||||
length = 80.0
|
||||
width = 36.0
|
||||
height = 18.0
|
||||
|
||||
with BuildPart() as model:
|
||||
Box(length, width, height, align=(Align.CENTER, Align.CENTER, Align.MIN))
|
||||
with Locations(Location((0.0, 0.0, 6.0))):
|
||||
Box(length + 2.0, 24.0, 6.0, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT)
|
||||
with Locations(Location((0.0, 0.0, 6.0))):
|
||||
Box(length + 2.0, 10.0, height, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT)
|
||||
for y_pos in (-18.0, 18.0):
|
||||
with Locations(Location((0.0, y_pos, 8.0))):
|
||||
Box(48.0, 5.0, 8.0, align=(Align.CENTER, Align.CENTER, Align.CENTER), mode=Mode.SUBTRACT)
|
||||
for x_pos in (-28.0, 28.0):
|
||||
for y_pos in (-14.0, 14.0):
|
||||
_hole_z(4.5, height + 2.0, x_pos, y_pos)
|
||||
|
||||
part = _safe_chamfer(model.part, _line_edges(model.part), 0.5)
|
||||
return _finish(part, "t_slot_slider_block_central_channel_side_reliefs_mounting_holes", Color(0.47, 0.53, 0.55, 1.0))
|
||||
|
||||
|
||||
def make_mounting_plate():
|
||||
length = 100.0
|
||||
width = 70.0
|
||||
thickness = 8.0
|
||||
|
||||
with BuildPart() as model:
|
||||
with BuildSketch(Plane.XY):
|
||||
RectangleRounded(length, width, 5.0, align=(Align.CENTER, Align.CENTER))
|
||||
extrude(amount=thickness)
|
||||
_hole_z(28.0, thickness + 2.0, 0.0, 0.0)
|
||||
_slot_z(30.0, 8.0, thickness + 2.0, (32.0, 0.0), -1.0, axis="y")
|
||||
for x_pos in (-38.0, 38.0):
|
||||
for y_pos in (-24.0, 24.0):
|
||||
_hole_z(5.5, thickness + 2.0, x_pos, y_pos)
|
||||
|
||||
part = _safe_fillet(model.part, _line_edges(model.part), 0.8)
|
||||
return _finish(part, "mounting_plate_central_cutout_side_slot_four_corner_holes_rounded_edges", Color(0.58, 0.65, 0.69, 1.0))
|
||||
@@ -0,0 +1,7 @@
|
||||
# Prompt: Small enclosure cover with raised rim, corner screw holes, and shallow recessed center.
|
||||
|
||||
from simple_model_library import make_small_enclosure_cover
|
||||
|
||||
|
||||
def gen_step():
|
||||
return make_small_enclosure_cover()
|
||||
@@ -0,0 +1,7 @@
|
||||
# Prompt: Spur gear blank with central bore, raised hub, and simplified perimeter teeth.
|
||||
|
||||
from simple_model_library import make_spur_gear_blank
|
||||
|
||||
|
||||
def gen_step():
|
||||
return make_spur_gear_blank()
|
||||
@@ -0,0 +1,7 @@
|
||||
# Prompt: Square mounting block with a vertical through-hole and two side clearance holes.
|
||||
|
||||
from simple_model_library import make_square_mounting_block
|
||||
|
||||
|
||||
def gen_step():
|
||||
return make_square_mounting_block()
|
||||
@@ -0,0 +1,7 @@
|
||||
# Prompt: T-slot slider block with central channel, side relief cuts, and mounting holes.
|
||||
|
||||
from simple_model_library import make_t_slot_slider_block
|
||||
|
||||
|
||||
def gen_step():
|
||||
return make_t_slot_slider_block()
|
||||
Reference in New Issue
Block a user