mirror of
https://github.com/gumyr/build123d.git
synced 2025-12-06 02:30:55 -08:00
171 lines
6 KiB
Python
171 lines
6 KiB
Python
"""
|
|
|
|
name: toy_truck.py
|
|
by: Gumyr
|
|
date: April 4th 2025
|
|
|
|
desc:
|
|
|
|
This example demonstrates how to design a toy truck using BuildPart and
|
|
BuildSketch in Builder mode. The model includes a detailed body, cab, grill,
|
|
and bumper, showcasing techniques like sketch reuse, symmetry, tapered
|
|
extrusions, selective filleting, and the use of joints for part assembly.
|
|
Ideal for learning complex part construction and hierarchical modeling in
|
|
build123d.
|
|
|
|
license:
|
|
|
|
Copyright 2025 Gumyr
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
|
|
"""
|
|
|
|
# [Code]
|
|
from build123d import *
|
|
from ocp_vscode import show
|
|
|
|
# Toy Truck Blue
|
|
truck_color = Color(0x4683CE)
|
|
|
|
# Create the main truck body — from bumper to bed, excluding the cab
|
|
with BuildPart() as body:
|
|
# The body has two axes of symmetry, so we start with a centered sketch.
|
|
# The default workplane is Plane.XY.
|
|
with BuildSketch() as body_skt:
|
|
Rectangle(20, 35)
|
|
# Fillet all the corners of the sketch.
|
|
# Alternatively, you could use RectangleRounded.
|
|
fillet(body_skt.vertices(), 1)
|
|
|
|
# Extrude the body shape upward
|
|
extrude(amount=10, taper=4)
|
|
# Reuse the sketch by accessing it explicitly
|
|
extrude(body_skt.sketch, amount=8, taper=2)
|
|
|
|
# Create symmetric fenders on Plane.YZ
|
|
with BuildSketch(Plane.YZ) as fender:
|
|
# The trapezoid has asymmetric angles (80°, 88°)
|
|
Trapezoid(18, 6, 80, 88, align=Align.MIN)
|
|
# Fillet top edge vertices (Y-direction highest group)
|
|
fillet(fender.vertices().group_by(Axis.Y)[-1], 1.5)
|
|
|
|
# Extrude the fender in both directions
|
|
extrude(amount=10.5, both=True)
|
|
|
|
# Create wheel wells with a shifted sketch on Plane.YZ
|
|
with BuildSketch(Plane.YZ.shift_origin((0, 3.5, 0))) as wheel_well:
|
|
Trapezoid(12, 4, 70, 85, align=Align.MIN)
|
|
fillet(wheel_well.vertices().group_by(Axis.Y)[-1], 2)
|
|
|
|
# Subtract the wheel well geometry
|
|
extrude(amount=10.5, both=True, mode=Mode.SUBTRACT)
|
|
|
|
# Fillet the top edges of the body
|
|
fillet(body.edges().group_by(Axis.Z)[-1], 1)
|
|
|
|
# Isolate a set of body edges and preview before filleting
|
|
body_edges = body.edges().group_by(Axis.Z)[-6]
|
|
fillet(body_edges, 0.1)
|
|
|
|
# Combine edge groups from both sides of the fender and fillet them
|
|
fender_edges = body.edges().group_by(Axis.X)[0] + body.edges().group_by(Axis.X)[-1]
|
|
fender_edges = fender_edges.group_by(Axis.Z)[1:]
|
|
fillet(fender_edges, 0.4)
|
|
|
|
# Create a sketch on the front of the truck for the grill
|
|
with BuildSketch(
|
|
Plane.XZ.offset(-body.vertices().sort_by(Axis.Y)[-1].Y - 0.5)
|
|
) as grill:
|
|
Rectangle(16, 8.5, align=(Align.CENTER, Align.MIN))
|
|
fillet(grill.vertices().group_by(Axis.Y)[-1], 1)
|
|
|
|
# Add headlights (subtractive circles)
|
|
with Locations((0, 6.5)):
|
|
with GridLocations(12, 0, 2, 1):
|
|
Circle(1, mode=Mode.SUBTRACT)
|
|
|
|
# Add air vents (subtractive slots)
|
|
with Locations((0, 3)):
|
|
with GridLocations(0, 0.8, 1, 4):
|
|
SlotOverall(10, 0.5, mode=Mode.SUBTRACT)
|
|
|
|
# Extrude the grill forward
|
|
extrude(amount=2)
|
|
|
|
# Fillet only the outer grill edges (exclude headlight/vent cuts)
|
|
grill_perimeter = body.faces().sort_by(Axis.Y)[-1].outer_wire()
|
|
fillet(grill_perimeter.edges(), 0.2)
|
|
|
|
# Create the bumper as a separate part inside the body
|
|
with BuildPart() as bumper:
|
|
# Find the midpoint of a front edge and shift slightly to position the bumper
|
|
front_cnt = body.edges().group_by(Axis.Z)[0].sort_by(Axis.Y)[-1] @ 0.5 - (0, 3)
|
|
|
|
with BuildSketch() as bumper_plan:
|
|
# Use BuildLine to draw an elliptical arc and offset
|
|
with BuildLine():
|
|
EllipticalCenterArc(front_cnt, 20, 4, start_angle=60, end_angle=120)
|
|
offset(amount=1)
|
|
make_face()
|
|
|
|
# Extrude the bumper symmetrically
|
|
extrude(amount=1, both=True)
|
|
fillet(bumper.edges(), 0.25)
|
|
|
|
# Define a joint on top of the body to connect the cab later
|
|
RigidJoint("body_top", joint_location=Location((0, -7.5, 10)))
|
|
body.part.color = truck_color
|
|
|
|
# Create the cab as an independent part to mount on the body
|
|
with BuildPart() as cab:
|
|
with BuildSketch() as cab_plan:
|
|
RectangleRounded(16, 16, 1)
|
|
# Split the sketch to work on one symmetric half
|
|
split(bisect_by=Plane.YZ)
|
|
|
|
# Extrude the cab forward and upward at an angle
|
|
extrude(amount=7, dir=(0, 0.15, 1))
|
|
fillet(cab.edges().group_by(Axis.Z)[-1].group_by(Axis.X)[1:], 1)
|
|
|
|
# Rear window
|
|
with BuildSketch(Plane.XZ.shift_origin((0, 0, 3))) as rear_window:
|
|
RectangleRounded(8, 4, 0.75)
|
|
extrude(amount=10, mode=Mode.SUBTRACT)
|
|
|
|
# Front window
|
|
with BuildSketch(Plane.XZ) as front_window:
|
|
RectangleRounded(15.2, 11, 0.75)
|
|
extrude(amount=-10, mode=Mode.SUBTRACT)
|
|
|
|
# Side windows
|
|
with BuildSketch(Plane.YZ) as side_window:
|
|
with Locations((3.5, 0)):
|
|
with GridLocations(10, 0, 2, 1):
|
|
Trapezoid(9, 5.5, 80, 100, align=(Align.CENTER, Align.MIN))
|
|
fillet(side_window.vertices().group_by(Axis.Y)[-1], 0.5)
|
|
extrude(amount=12, both=True, mode=Mode.SUBTRACT)
|
|
|
|
# Mirror to complete the cab
|
|
mirror(about=Plane.YZ)
|
|
|
|
# Define joint on cab base
|
|
RigidJoint("cab_base", joint_location=Location((0, 0, 0)))
|
|
cab.part.color = truck_color
|
|
|
|
# Attach the cab to the truck body using joints
|
|
body.joints["body_top"].connect_to(cab.joints["cab_base"])
|
|
|
|
# Show the result
|
|
show(image, body.part, cab.part)
|
|
# [End]
|