Files
cadSet/text-to-cad/models/cad-router-v1/gear_28t_4mm/gear_28t_4mm.py
T
2026-07-27 16:01:32 +08:00

271 lines
9.4 KiB
Python

"""Parametric 28-tooth spur gear generated with SimpleCADAPI."""
import json
import sys
from pathlib import Path
_PROJECT_ROOT = Path(__file__).resolve().parents[4]
_SIMPLECADAPI_SRC = _PROJECT_ROOT / "SimpleCADAPI" / "src"
if str(_SIMPLECADAPI_SRC) not in sys.path:
sys.path.insert(0, str(_SIMPLECADAPI_SRC))
import simplecadapi as scad
N_TEETH = 28
MODULE_MM = 1.0
PRESSURE_ANGLE_DEG = 20.0
THICKNESS_MM = 4.0
BORE_DIAMETER_MM = 5.0
ADDENDUM_FACTOR = 1.0
CLEARANCE_FACTOR = 0.25
BACKLASH_MM = 0.0
VIEWER_SELECTED_EDGE = {
"reference_id": "e344",
"row_index": 343,
"description": "top circular edge of the center bore",
}
BORE_TOP_CHAMFER_DISTANCE_MM = 3.0
EDIT_HOLE_AXIS = (0.0, 0.0, 1.0)
EDIT_HOLES = [
{
"diameter_mm": 2.0,
"center_mm": (-2.9189440262073063, 5.47686606164935, THICKNESS_MM),
},
{
"diameter_mm": 2.0,
"center_mm": (7.5974463825483305, -0.8433357012066764, THICKNESS_MM),
},
]
EDIT_HOLE_PATTERNS = [
{
"diameter_mm": 2.0,
"rows": 2,
"columns": 2,
"pitch_x_mm": 8.0,
"pitch_y_mm": 8.0,
"depth": "through",
"direction": "face_normal",
"orientation": "surface_xy",
"center_mm": (0.24688766006678975, -8.367405492677905, THICKNESS_MM),
"selected_face": {
"reference_id": "f5",
"selector": "f5",
"face_index": 2785,
"row_index": 4,
"normal": (0.0, 0.0, 1.0),
},
},
]
EDIT_POCKETS = [
{
"shape": "rectangle",
"width_mm": 10.0,
"height_mm": 6.0,
"depth_mm": 1.0,
"center_mm": (-8.717129036056448, -0.9462437095981322, THICKNESS_MM),
"direction": "face_normal",
"orientation": "surface_xy",
"selected_face": {
"reference_id": "f5",
"selector": "f5",
"face_index": 5428,
"row_index": 4,
"normal": (0.0, 0.0, 1.0),
},
},
]
def hole_pattern_centers(pattern):
x_center, y_center, z_center = pattern["center_mm"]
x_start = x_center - (pattern["columns"] - 1) * pattern["pitch_x_mm"] / 2.0
y_start = y_center - (pattern["rows"] - 1) * pattern["pitch_y_mm"] / 2.0
return [
(
x_start + column * pattern["pitch_x_mm"],
y_start + row * pattern["pitch_y_mm"],
z_center,
)
for row in range(pattern["rows"])
for column in range(pattern["columns"])
]
def generate() -> None:
output_dir = Path(__file__).resolve().parent
with scad.GraphSession() as session:
gear_blank = scad.std.gear.make_spur_gear_rsolid(
n_teeth=N_TEETH,
module=MODULE_MM,
pressure_angle=PRESSURE_ANGLE_DEG,
gear_height=THICKNESS_MM,
addendum_factor=ADDENDUM_FACTOR,
clearance_factor=CLEARANCE_FACTOR,
backlash=BACKLASH_MM,
)
blank_faces = scad.ql.select(items=gear_blank.get_faces()).all()
print("gear_blank_faces", len(blank_faces))
bore_radius = BORE_DIAMETER_MM / 2.0
bore = scad.make_cylinder_rsolid(
radius=bore_radius,
height=THICKNESS_MM + 2.0,
bottom_face_center=(0.0, 0.0, -1.0),
axis=(0.0, 0.0, 1.0),
)
bore_top_chamfer = scad.make_cone_rsolid(
bottom_radius=bore_radius,
height=BORE_TOP_CHAMFER_DISTANCE_MM,
top_radius=bore_radius + BORE_TOP_CHAMFER_DISTANCE_MM,
bottom_face_center=(
0.0,
0.0,
THICKNESS_MM - BORE_TOP_CHAMFER_DISTANCE_MM,
),
axis=(0.0, 0.0, 1.0),
)
edit_hole_cutters = [
scad.make_cylinder_rsolid(
radius=hole["diameter_mm"] / 2.0,
height=THICKNESS_MM + 2.0,
bottom_face_center=(hole["center_mm"][0], hole["center_mm"][1], -1.0),
axis=EDIT_HOLE_AXIS,
)
for hole in EDIT_HOLES
]
pattern_hole_cutters = [
scad.make_cylinder_rsolid(
radius=pattern["diameter_mm"] / 2.0,
height=THICKNESS_MM + 2.0,
bottom_face_center=(center[0], center[1], -1.0),
axis=EDIT_HOLE_AXIS,
)
for pattern in EDIT_HOLE_PATTERNS
for center in hole_pattern_centers(pattern)
]
pocket_cutters = [
scad.make_box_rsolid(
width=pocket["width_mm"],
height=pocket["height_mm"],
depth=pocket["depth_mm"] + 0.02,
bottom_face_center=(
pocket["center_mm"][0],
pocket["center_mm"][1],
THICKNESS_MM - pocket["depth_mm"],
),
)
for pocket in EDIT_POCKETS
]
print("viewer_edit_holes", len(edit_hole_cutters))
print("viewer_edit_pattern_holes", len(pattern_hole_cutters))
print("viewer_edit_pockets", len(pocket_cutters))
gear = scad.cut_rsolid(
gear_blank,
[
bore,
bore_top_chamfer,
*edit_hole_cutters,
*pattern_hole_cutters,
*pocket_cutters,
],
skip_non_intersecting=False,
)
gear = scad.apply_tag(shape=gear, tag="role.power_transmission.gear")
gear = scad.apply_tag(shape=gear, tag="feature.viewer_edit_point_hole")
gear = scad.apply_tag(shape=gear, tag="feature.viewer_edit_hole_pattern")
gear = scad.apply_tag(shape=gear, tag="feature.viewer_edit_rectangular_pocket")
gear = scad.apply_tag(shape=gear, tag="feature.viewer_selected_edge_chamfer")
final_faces = scad.ql.select(items=gear.get_faces()).all()
final_edges = scad.ql.select(items=gear.get_edges()).all()
print("final_topology", {"faces": len(final_faces), "edges": len(final_edges)})
model_json = scad.export_model_json(session=session, indent=2)
(output_dir / "gear_28t_4mm.model.json").write_text(model_json, encoding="utf-8")
scad.export_step(shapes=gear, filename=str(output_dir / "gear_28t_4mm.step"))
scad.export_stl(shapes=gear, filename=str(output_dir / "gear_28t_4mm.stl"))
pitch_diameter_mm = MODULE_MM * N_TEETH
outside_diameter_mm = MODULE_MM * (N_TEETH + 2.0 * ADDENDUM_FACTOR)
root_diameter_mm = MODULE_MM * (
N_TEETH - 2.0 * (ADDENDUM_FACTOR + CLEARANCE_FACTOR)
)
validation = {
"n_teeth": N_TEETH,
"pitch_diameter_mm": pitch_diameter_mm,
"outside_diameter_mm": outside_diameter_mm,
"root_diameter_mm": root_diameter_mm,
"thickness_mm": THICKNESS_MM,
"bore_diameter_mm": BORE_DIAMETER_MM,
"viewer_selected_edge": VIEWER_SELECTED_EDGE,
"bore_top_chamfer_distance_mm": BORE_TOP_CHAMFER_DISTANCE_MM,
"bore_top_chamfer_top_diameter_mm": BORE_DIAMETER_MM
+ 2.0 * BORE_TOP_CHAMFER_DISTANCE_MM,
"edit_holes": [
{
"diameter_mm": hole["diameter_mm"],
"center_mm": list(hole["center_mm"]),
}
for hole in EDIT_HOLES
],
"edit_hole_count": len(EDIT_HOLES),
"edit_hole_axis": list(EDIT_HOLE_AXIS),
"edit_hole_patterns": [
{
"diameter_mm": pattern["diameter_mm"],
"rows": pattern["rows"],
"columns": pattern["columns"],
"pitch_x_mm": pattern["pitch_x_mm"],
"pitch_y_mm": pattern["pitch_y_mm"],
"depth": pattern["depth"],
"direction": pattern["direction"],
"orientation": pattern["orientation"],
"center_mm": list(pattern["center_mm"]),
"hole_centers_mm": [
list(center) for center in hole_pattern_centers(pattern)
],
"selected_face": {
**pattern["selected_face"],
"normal": list(pattern["selected_face"]["normal"]),
},
}
for pattern in EDIT_HOLE_PATTERNS
],
"edit_hole_pattern_count": len(EDIT_HOLE_PATTERNS),
"edit_hole_pattern_hole_count": sum(
pattern["rows"] * pattern["columns"] for pattern in EDIT_HOLE_PATTERNS
),
"edit_pockets": [
{
"shape": pocket["shape"],
"width_mm": pocket["width_mm"],
"height_mm": pocket["height_mm"],
"depth_mm": pocket["depth_mm"],
"center_mm": list(pocket["center_mm"]),
"direction": pocket["direction"],
"orientation": pocket["orientation"],
"selected_face": {
**pocket["selected_face"],
"normal": list(pocket["selected_face"]["normal"]),
},
}
for pocket in EDIT_POCKETS
],
"edit_pocket_count": len(EDIT_POCKETS),
"volume_mm3": round(gear.get_volume(), 6),
"faces": len(final_faces),
"edges": len(final_edges),
"tags": scad.list_tags(shape=gear),
"graph_nodes": session.graph.node_count,
}
(output_dir / "validation.json").write_text(
json.dumps(validation, indent=2, ensure_ascii=False) + "\n",
encoding="utf-8",
)
print("validation", validation)
if __name__ == "__main__":
generate()