| name | cad-cam |
| description | CAD/CAM fundamentals including geometric modeling, manufacturing automation, toolpath generation, CNC programming, and 3D printing |
| license | MIT |
| compatibility | opencode |
| metadata | {"audience":"engineers","category":"engineering"} |
What I do
- Create 3D geometric models using CAD software
- Generate CNC toolpaths for manufacturing
- Program CNC machines using G-code and CAM software
- Design for additive manufacturing (3D printing)
- Perform toolpath simulation and verification
- Optimize machining parameters for efficiency
- Convert CAD models to manufacturing formats
- Verify tool collision and machine limits
When to use me
When creating 3D models, generating CNC toolpaths, programming CNC machines, or designing parts for additive manufacturing.
Core Concepts
- Solid modeling (CSG, B-rep)
- Surface modeling and NURBS
- Feature-based modeling
- Toolpath strategies (contour, pocketing, drilling)
- CNC programming (G-code, M-code)
- Feed and speed calculations
- Tool geometry and compensation
- Additive manufacturing processes (FDM, SLA, SLS)
- Build orientation and support generation
- Post-processing for different machine controllers
Code Examples
G-Code Generation
from dataclasses import dataclass
from typing import List, Tuple
import math
@dataclass
class GCodeCommand:
code: str
x: float = None
y: float = None
z: float = None
f: float = None
s: float = None
def rapid_move(x: float, y: float, z: float) -> str:
"""Generate G0 rapid move command."""
return f"G0 X{x:.4f} Y{y:.4f} Z{z:.4f}"
def linear_move(x: float, y: float, z: float, f: float) -> str:
"""Generate G1 linear move command."""
return f"G1 X{x:.4f} Y{y:.4f} Z{z:.4f} F{f:.1f}"
() -> :
g_code = direction ==
() -> []:
[
rapid_move(x, y, z_start),
,
,
rapid_move(x, y, z_retract)
]
() -> :
q:
gcode = [
,
,
,
,
rapid_move(, , ),
linear_move(, , -, ),
linear_move(, , -, ),
linear_move(, , -, ),
linear_move(, , -, ),
,
]
line gcode[:]:
(line)
Toolpath Generation
from typing import List, Tuple
import numpy as np
def offset_polygon(
vertices: List[Tuple[float, float]],
offset: float,
corner_style: str = "round"
) -> List[Tuple[float, float]]:
"""Generate offset contour for tool radius compensation."""
offset_vertices = []
n = len(vertices)
for i in range(n):
p1 = vertices[i]
p2 = vertices[(i + 1) % n]
p0 = vertices[(i - 1) % n]
v1 = np.array(p2) - np.array(p1)
v0 = np.array(p1) - np.array(p0)
angle1 = math.atan2(v1[1], v1[0])
angle0 = math.atan2(v0[1], v0[0])
if corner_style == "round":
radius = offset
center = np.array(p1) + np.array([
radius * math.cos((angle0 + angle1) / 2),
radius * math.sin((angle0 + angle1) / 2)
])
for t in np.linspace(0, 1, 9):
angle = angle0 + (angle1 - angle0) * t
offset_vertices.append((
center[0] + radius * math.cos(angle + math.pi/2),
center[] + radius * math.sin(angle + math.pi/)
))
:
bisector = (angle0 + angle1) /
offset_vertices.append((
p1[] + offset * math.cos(bisector + math.pi/),
p1[] + offset * math.sin(bisector + math.pi/)
))
offset_vertices
() -> [[, ]]:
xmin, xmax, ymin, ymax = bbox
path = []
direction == :
y np.arange(ymin, ymax, stepover):
(y - ymin) / stepover % == :
path.extend([(xmin, y), (xmax, y)])
:
path.extend([(xmax, y), (xmin, y)])
:
x np.arange(xmin, xmax, stepover):
(x - xmin) / stepover % == :
path.extend([(x, ymin), (x, ymax)])
:
path.extend([(x, ymax), (x, ymin)])
path
() -> [[, , ]]:
path = []
r = start_radius
theta =
r <= end_radius:
x = center[] + r * math.cos(theta)
y = center[] + r * math.sin(theta)
z = -r / end_radius *
path.append((x, y, z))
r +=
theta += angle_per_step
path
() -> [[, , ]]:
path = []
current_depth =
current_depth < total_depth:
current_depth += stepdown
current_depth > total_depth:
current_depth = total_depth
angle =
angle < * math.pi:
x = center[] + (radius + slot_width/ * math.cos(angle)) * math.cos(angle/)
y = center[] + (radius + slot_width/ * math.cos(angle)) * math.sin(angle/)
z = -current_depth
path.append((x, y, z))
angle +=
path
bbox = (, , , )
path = raster_toolpath(bbox, , )
()
Feeds and Speeds
@dataclass
class ToolParameters:
diameter: float
num_flutes: int
material: str
hardness: float
@dataclass
class MaterialProperties:
name: str
hardness: float
tensile_strength: float
machinability_rating: float
def calculate_spindle_speed(
cutting_speed: float,
tool_diameter: float
) -> float:
"""Calculate spindle RPM."""
return (1000 * cutting_speed) / (math.pi * tool_diameter)
def calculate_feed_rate(
spindle_speed: float,
feed_per_tooth: float,
num_flutes: int
) -> float:
"""Calculate feed rate mm/min."""
return spindle_speed * feed_per_tooth * num_flutes
def calculate_material_removal_rate(
width: float,
depth: float,
feed_rate: float
) -> float:
"""Calculate MRR mm³/min."""
return width * depth * feed_rate
def calculate_power_requirement() -> :
mrr * specific_energy /
() -> :
material_data = {
: {: , : , : },
: {: , : , : },
: {: , : , : },
: {: , : , : }
}
modifiers = {
: {: , : },
: {: , : },
: {: , : }
}
m = material_data.get(material, material_data[])
op_mod = modifiers.get(operation, {: , : })
vc = m[] * op_mod[]
fz = m[] * op_mod[]
n = calculate_spindle_speed(vc)
vf, tool_diameter = calculate_feed_rate(n, fz, num_flutes)
{
: n,
: vf,
: fz
}
settings = estimate_feeds_speeds(, , , )
()
()
Additive Manufacturing
@dataclass
class AMBuildSettings:
layer_height: float
infill_percentage: float
infill_pattern: str
build_temperature: float
bed_temperature: float
print_speed: float
support_type: str
def estimate_build_time(
num_layers: int,
layer_area: float,
print_speed: float,
travel_speed: float = 150,
layer_change_time: float = 5
) -> float:
"""Estimate total build time in hours."""
print_time = (num_layers * layer_area) / print_speed / 60
travel_factor = 0.3
layer_time = num_layers * layer_change_time / 60
return (print_time * (1 + travel_factor) + layer_time) / 60
def calculate_material_usage(
volume_mm3: float,
infill_percentage: float = 20,
support_percentage: float = 10
) -> float:
"""Calculate required material in grams."""
density = 1.24
volume_cm3 = volume_mm3 / 1000
total_volume = volume_cm3 * (1 + infill_percentage/) * ( + support_percentage/)
total_volume * density
() -> [, , ]:
x, y, z = build_volume
min_surface_roughness:
(x, y, )
max_strength:
(, y, z)
(x, y, z)
() -> []:
[{
: overhang_angle_threshold,
: support_density,
: support_density <
}]
build = AMBuildSettings(
layer_height=,
infill_percentage=,
infill_pattern=,
print_speed=
)
time = estimate_build_time(, *, )
material = calculate_material_usage(**, , )
()
()
CAM Post-Processing
@dataclass
class PostProcessorConfig:
machine_type: str
control_system: str
output_format: str
arc_output: str
tool_change_mcode: str
coolant_mcodes: Tuple[str, str]
def generate_post_processor(
config: PostProcessorConfig
) -> dict:
"""Generate post-processor configuration."""
return {
"header": [
f"O1234 ({config.machine_type} program)",
"G90 G21 G40",
f"G54 (Work coordinate: {config.control_system})"
],
"tool_change": f"M6 T#{{TOOL_NUMBER}} ({config.tool_change_mcode})",
"coolant_on": config.coolant_mcodes[0],
"coolant_off": config.coolant_mcodes[1],
"arc_format": config.arc_output,
"footer": ["M5", "M30"]
}
def interpolate_gcode(
input_points: List[Tuple[float, float, float]],
tolerance: float = 0.01
) -> List[Tuple[float, float, ]]:
output = [input_points[]]
i (, (input_points)):
p1 = input_points[i-]
p2 = input_points[i]
dist = math.sqrt(
(p2[]-p1[])** +
(p2[]-p1[])** +
(p2[]-p1[])**
)
num_points = (, (dist / tolerance))
j (, num_points):
t = j / num_points
output.append((
p1[] + (p2[]-p1[]) * t,
p1[] + (p2[]-p1[]) * t,
p1[] + (p2[]-p1[]) * t
))
output
() -> []:
warnings = []
i, (x, y, z) (toolpath):
x < machine_limits[] x > machine_limits[]:
warnings.append()
y < machine_limits[] y > machine_limits[]:
warnings.append()
z < machine_limits[] z > machine_limits[]:
warnings.append()
warnings
config = PostProcessorConfig(
machine_type=,
control_system=,
output_format=,
arc_output=,
tool_change_mcode=,
coolant_on=,
coolant_off=
)
post = generate_post_processor(config)
(, post[][])
(, post[][])
Best Practices
- Always verify toolpaths before cutting using simulation
- Use proper work coordinate systems and origin points
- Consider tool deflection and vibration in feed/speed calculations
- Use appropriate stock allowances for finish passes
- Verify machine limits and tool lengths before running programs
- Optimize toolpaths for reduced cycle time
- Use proper fixturing to minimize vibration
- Consider tolerances and shrink factors in CAD models
- Document CAM settings and post-processor configuration
- Test programs with air cuts before production runs