refactor: add DesignIR distillation pipeline

This commit is contained in:
Jerry
2026-07-27 17:24:04 +08:00
parent 0adaac2b2a
commit 550b339bcc
1128 changed files with 10248 additions and 426666 deletions
Binary file not shown.
@@ -1,118 +0,0 @@
{
"schema_version": "1.0",
"request": "Modify the existing build123d connecting rod from the CAD Viewer selection: add a 2 mm wide blind slot along the selected segment on face f18, regenerate STEP, STL, and CAD Viewer mesh/topology assets.",
"route": {
"selected_backend": "build123d",
"runner_skill": "cad",
"project": "text-to-cad",
"confidence": "high",
"fallback_order": [
"simplecadapi",
"cadam"
],
"operation": "modify",
"modification_strategy": "native_parameter_editing",
"decision_path": "route-decision.json"
},
"source": {
"path": "connecting_rod.py",
"format": "python",
"backend": "build123d"
},
"artifacts": [
{
"path": "connecting_rod.step",
"role": "primary"
},
{
"path": "connecting_rod.stl",
"role": "secondary"
},
{
"path": ".connecting_rod.step.glb",
"role": "viewer_mesh_topology"
},
{
"path": "connecting_rod_slot_review_20260723T100007Z.png",
"role": "verification_snapshot"
}
],
"parameters": {
"center_distance_mm": 120.0,
"thickness_mm": 14.0,
"big_end_outer_diameter_mm": 56.0,
"big_end_bore_diameter_mm": 36.0,
"small_end_outer_diameter_mm": 36.0,
"small_end_bore_diameter_mm": 20.0,
"web_width_mm": 24.0,
"pocket_depth_each_side_mm": 3.0,
"viewer_slot_start_mm": [
-28.73179347578467,
-0.3844822039559189
],
"viewer_slot_end_mm": [
24.36043904920138,
-0.24367243243227724
],
"viewer_slot_surface_z_mm": 11.0,
"viewer_slot_width_mm": 2.0,
"viewer_slot_blind_depth_mm": 2.0,
"viewer_slot_bottom_z_mm": 9.0
},
"experience": {
"library": "../../../cad-experience-library/library.json",
"context_kind": "generalized_cad_experience_query",
"methods_applied": []
},
"assumptions": [
"The selected face f18 is the existing top-pocket floor at z=11 mm, so the blind slot cuts inward into the material from z=11 mm down to z=9 mm.",
"The CAD edit intent marks depth as blind but does not provide a numeric depth, so a conservative 2 mm blind depth was used.",
"This V1 sample demonstrates routing and editability rather than a production-rated engine component.",
"Material, fatigue loads, bearing fits, lubrication, fasteners, tolerances, and split big-end construction are intentionally out of scope."
],
"validation": [
{
"check": "STEP generation from editable source",
"result": "scripts/cad step regenerated connecting_rod.step, connecting_rod.stl, and hidden CAD Viewer GLB/topology assets from connecting_rod.py.",
"status": "pass"
},
{
"check": "closed solid topology",
"result": {
"kind": "part",
"shape_count": 1,
"face_count": 23,
"edge_count": 54,
"bounds_mm": [
165.978199,
55.977382,
14.0
]
},
"status": "pass"
},
{
"check": "selected-face slot placement",
"result": "Original selected face f18 remains the top-pocket floor at z=11 mm; new slot bottom face f23 is centered at [-2.185677, -0.314077, 9.0].",
"status": "pass"
},
{
"check": "blind slot depth",
"result": "Slot side faces span z=9.0 mm to z=11.0 mm.",
"status": "pass"
},
{
"check": "slot width",
"result": "Slot end faces are cylinders with radius 1.0 mm, matching the requested 2.0 mm slot width.",
"status": "pass"
},
{
"check": "snapshot review",
"result": "Isometric snapshot shows the connecting rod, existing top pocket, and the new narrow blind slot without visible breakage or disconnected geometry.",
"status": "pass"
}
],
"viewer_links": [
"http://127.0.0.1:5175/?dir=%2FUsers%2Flk%2FProjects%2FcadSet%2Ftext-to-cad%2Fmodels%2Fcad-router-v1&file=connecting_rod.step"
]
}
@@ -1,56 +0,0 @@
{
"schema_version": "1.0",
"request": "Generate a parameterized perforated vase for 3D printing",
"route": {
"selected_backend": "cadam",
"project": "CADAM",
"runner_skill": "cad-router",
"adapter": "skills/cad-router/scripts/cadam_compile.mjs",
"fallback_order": [
"build123d",
"simplecadapi"
],
"workflow_profiles": []
},
"source": {
"path": "cadam_parametric_vase.scad",
"format": "scad",
"backend": "cadam"
},
"artifacts": [
{
"path": "cadam_parametric_vase.stl",
"role": "primary"
}
],
"parameters": {
"height_mm": 80,
"base_radius_mm": 30,
"top_radius_mm": 24,
"wall_mm": 2.4,
"base_mm": 3
},
"assumptions": [
"The repeated perforations are decorative and are not load-bearing features."
],
"validation": [
{
"check": "CADAM OpenSCAD WASM compile",
"status": "passed",
"details": "exit code 0; manifold backend reported NoError; 3816 vertices and 7868 facets"
},
{
"check": "CAD Viewer review",
"status": "passed",
"details": "STL loaded from the task-scoped cad-router-v1 directory"
}
],
"project_contributions": {
"text-to-cad": "router, artifact contract, validation, and CAD Viewer",
"SimpleCADAPI": "available specialist mechanical fallback",
"CADAM": "SCAD source and OpenSCAD-WASM mesh execution"
},
"viewer_links": [
"http://127.0.0.1:4178/?dir=%2FUsers%2Fjerry%2Flinkhand%2FCadSet%2Ftext-to-cad%2Fmodels%2Fcad-router-v1&file=cadam_parametric_vase.stl"
]
}
@@ -1,27 +0,0 @@
// CADAM/OpenSCAD-WASM route sample for CAD Router V1.
$fn = 96;
height = 80;
base_radius = 30;
top_radius = 24;
wall = 2.4;
base = 3;
difference() {
cylinder(h = height, r1 = base_radius, r2 = top_radius);
translate([0, 0, base])
cylinder(
h = height,
r1 = base_radius - wall,
r2 = top_radius - wall
);
for (z = [14 : 14 : 70]) {
for (angle = [0 : 30 : 330]) {
rotate([0, 0, angle + z * 0.75])
translate([base_radius - 1.0 - z * 0.07, 0, z])
rotate([0, 90, 0])
cylinder(h = wall + 5, r = 2.2, center = true, $fn = 24);
}
}
}
Binary file not shown.
@@ -1,86 +0,0 @@
{
"schema_version": "1.0",
"request": "Regenerate the current compact guided-cylinder housing using only promoted generalized CAD experience while preserving the existing parameterized geometry and enlarged central bore.",
"route": {
"selected_backend": "build123d",
"runner_skill": "cad",
"project": "text-to-cad",
"fallback_order": [
"simplecadapi",
"cadam"
],
"workflow_profiles": [
"requirement_refinement",
"visual_repair"
]
},
"source": {
"model_spec": "model-spec.json",
"path": "compact_guided_cylinder.py",
"format": "python",
"backend": "build123d"
},
"artifacts": [
{
"path": "compact_guided_cylinder.step",
"role": "primary"
},
{
"path": "compact_guided_cylinder.stl",
"role": "secondary"
}
],
"parameter_source": "model-spec.json",
"experience": {
"library": "../../../../cad-experience-library/library.json",
"context_kind": "generalized_cad_experience_query",
"query_scope": "global",
"promoted_methods_found": 0,
"methods_applied": [],
"result": "No promoted generalized methods matched; candidate experiences were intentionally excluded from generation."
},
"assumptions": [
"The image has no absolute dimensions; millimetre dimensions preserve visible proportions only.",
"The product is represented as a three-body compound: main extrusion plus two end caps.",
"The four top holes are modeled through the main body because the bottom view shows matching circles.",
"The four large circles on each end are treated as protruding tie-rod ends.",
"The central bore radius was doubled from 4.5 mm to 9 mm; the collar outer diameter was increased from 17 mm to 26 mm to retain a 4 mm radial wall.",
"This is concept geometry, not a pressure-rated or manufacturing-certified pneumatic cylinder."
],
"validation": [
{
"check": "STEP generation",
"result": "passed",
"detail": "Generated a labeled three-body assembly and STL sidecar from the parameterized Python source."
},
{
"check": "Bounding box",
"result": "passed",
"detail": "138 x 60 x 39 mm; dominant axis X."
},
{
"check": "Topology",
"result": "passed",
"detail": "61 faces and 156 edges after the side-groove repair."
},
{
"check": "Visual review",
"result": "passed",
"detail": "Reviewed regenerated isometric and top snapshots. Geometry remains visually consistent with the current parameterized source, including the enlarged central bore and four-hole pattern."
},
{
"check": "Experience isolation",
"result": "passed",
"detail": "The router reported zero generalized methods. No candidate experience, parser input, parser output, private case JSON, source dimensions, or coordinates were used."
},
{
"check": "JSON parameter rebuild",
"result": "passed",
"detail": "The STEP and STL were regenerated from the part-local model-spec.json through the native Python generator."
}
],
"viewer_links": [
"http://127.0.0.1:4179/?dir=%2FUsers%2Fjerry%2Flinkhand%2FCadSet%2Ftext-to-cad%2Fmodels%2Fcad-router-v1%2Fcompact_guided_cylinder_v1&file=compact_guided_cylinder.step",
"http://127.0.0.1:4179/?dir=%2FUsers%2Fjerry%2Flinkhand%2FCadSet%2Ftext-to-cad%2Fmodels%2Fcad-router-v1%2Fcompact_guided_cylinder_v1&file=compact_guided_cylinder.stl"
]
}
@@ -1,197 +0,0 @@
"""Image-inferred compact guided-cylinder housing.
The reference contains no dimensions, so the named dimensions below preserve
its visible proportions rather than claiming a production drawing.
Coordinate convention:
- X: long axis
- Y: width
- Z: height, with the lowest end-cap face at Z = 0
"""
import json
from pathlib import Path
from build123d import Align, Box, Compound, Cylinder, Pos
def _model_parameters():
spec_path = Path(__file__).with_name("model-spec.json")
payload = json.loads(spec_path.read_text(encoding="utf-8"))
return {
name: float(entry["value"])
for name, entry in payload["parameters"].items()
}
PARAMETERS = _model_parameters()
def _parameter(name: str) -> float:
return PARAMETERS[name]
# Overall proportions inferred from the reference image (millimetres).
CORE_LENGTH = _parameter("core_length")
CORE_WIDTH = _parameter("core_width")
CORE_BOTTOM_Z = _parameter("core_bottom_z")
CORE_HEIGHT = _parameter("core_height")
END_CAP_THICKNESS = _parameter("end_cap_thickness")
END_CAP_WIDTH = _parameter("end_cap_width")
END_CAP_HEIGHT = _parameter("end_cap_height")
# Two shallow longitudinal relief grooves on both long side faces.
SIDE_GROOVE_DEPTH = _parameter("side_groove_depth")
SIDE_GROOVE_HEIGHT = _parameter("side_groove_height")
SIDE_GROOVE_Z = (12.0, 24.0)
# Four inferred through mounting holes on the top/bottom pattern.
MOUNT_HOLE_DIAMETER = _parameter("mount_hole_diameter")
MOUNT_HOLE_X = _parameter("mount_hole_x")
MOUNT_HOLE_Y = _parameter("mount_hole_y")
# Central top port and raised collar.
PORT_BORE_DIAMETER = _parameter("port_bore_diameter")
PORT_COLLAR_OUTER_DIAMETER = _parameter("port_collar_outer_diameter")
PORT_COLLAR_HEIGHT = _parameter("port_collar_height")
# Four visible tie-rod ends on each end cap.
TIE_ROD_END_DIAMETER = _parameter("tie_rod_end_diameter")
TIE_ROD_END_PROTRUSION = _parameter("tie_rod_end_protrusion")
TIE_ROD_Y = _parameter("tie_rod_y")
TIE_ROD_Z = (7.0, 31.0)
# Small blind pilot/port visible on both end faces.
END_FACE_HOLE_DIAMETER = _parameter("end_face_hole_diameter")
END_FACE_HOLE_DEPTH = _parameter("end_face_hole_depth")
END_FACE_HOLE_Z = _parameter("end_face_hole_z")
END_CAP_CENTER_X = CORE_LENGTH / 2.0 + END_CAP_THICKNESS / 2.0
TOTAL_LENGTH = CORE_LENGTH + 2.0 * END_CAP_THICKNESS
VISIBLE_LENGTH = TOTAL_LENGTH + 2.0 * TIE_ROD_END_PROTRUSION
TOTAL_HEIGHT = END_CAP_HEIGHT + PORT_COLLAR_HEIGHT
def _x_cylinder(
length: float,
diameter: float,
center_x: float,
center_y: float,
center_z: float,
):
"""Create an X-axis cylinder centered at the requested location."""
return Pos(center_x, center_y, center_z) * Cylinder(
diameter / 2.0,
length,
align=(Align.CENTER, Align.CENTER, Align.CENTER),
rotation=(0.0, 90.0, 0.0),
)
def _make_core():
"""Main extrusion with side grooves, top pattern, and central through port."""
core = Pos(0.0, 0.0, CORE_BOTTOM_Z) * Box(
CORE_LENGTH,
CORE_WIDTH,
CORE_HEIGHT,
align=(Align.CENTER, Align.CENTER, Align.MIN),
)
# Cut two crisp grooves into each long side, stopping at the end-cap seams.
for groove_z in SIDE_GROOVE_Z:
groove_center_y = CORE_WIDTH / 2.0 - SIDE_GROOVE_DEPTH / 2.0 + 0.2
front_tool = Pos(0.0, groove_center_y, groove_z) * Box(
CORE_LENGTH + 1.0,
SIDE_GROOVE_DEPTH + 0.4,
SIDE_GROOVE_HEIGHT,
align=(Align.CENTER, Align.CENTER, Align.CENTER),
)
back_tool = Pos(0.0, -groove_center_y, groove_z) * Box(
CORE_LENGTH + 1.0,
SIDE_GROOVE_DEPTH + 0.4,
SIDE_GROOVE_HEIGHT,
align=(Align.CENTER, Align.CENTER, Align.CENTER),
)
core = core - front_tool - back_tool
# Through mounting pattern visible from top and bottom in the reference.
for x_pos in (-MOUNT_HOLE_X, MOUNT_HOLE_X):
for y_pos in (-MOUNT_HOLE_Y, MOUNT_HOLE_Y):
hole = Pos(x_pos, y_pos, -1.0) * Cylinder(
MOUNT_HOLE_DIAMETER / 2.0,
TOTAL_HEIGHT + 2.0,
align=(Align.CENTER, Align.CENTER, Align.MIN),
)
core = core - hole
port_hole = Pos(0.0, 0.0, -1.0) * Cylinder(
PORT_BORE_DIAMETER / 2.0,
TOTAL_HEIGHT + 2.0,
align=(Align.CENTER, Align.CENTER, Align.MIN),
)
core = core - port_hole
collar = Pos(0.0, 0.0, CORE_BOTTOM_Z + CORE_HEIGHT - 0.1) * Cylinder(
PORT_COLLAR_OUTER_DIAMETER / 2.0,
PORT_COLLAR_HEIGHT + 0.1,
align=(Align.CENTER, Align.CENTER, Align.MIN),
)
collar = collar - Pos(0.0, 0.0, CORE_BOTTOM_Z + CORE_HEIGHT - 1.0) * Cylinder(
PORT_BORE_DIAMETER / 2.0,
PORT_COLLAR_HEIGHT + 2.0,
align=(Align.CENTER, Align.CENTER, Align.MIN),
)
core = core + collar
core.label = "extruded_cylinder_body"
return core
def _make_end_cap(side: int):
"""End plate with four protruding tie-rod ends and one blind face hole."""
center_x = side * END_CAP_CENTER_X
cap = Pos(center_x, 0.0, 0.0) * Box(
END_CAP_THICKNESS,
END_CAP_WIDTH,
END_CAP_HEIGHT,
align=(Align.CENTER, Align.CENTER, Align.MIN),
)
boss_center_x = side * (
TOTAL_LENGTH / 2.0 + TIE_ROD_END_PROTRUSION / 2.0 - 0.5
)
for y_pos in (-TIE_ROD_Y, TIE_ROD_Y):
for z_pos in TIE_ROD_Z:
cap = cap + _x_cylinder(
TIE_ROD_END_PROTRUSION + 1.0,
TIE_ROD_END_DIAMETER,
boss_center_x,
y_pos,
z_pos,
)
# Blind end-face pilot: overshoot the outside face but stop inside the cap.
hole_center_x = side * (
TOTAL_LENGTH / 2.0 - END_FACE_HOLE_DEPTH / 2.0 + 0.5
)
cap = cap - _x_cylinder(
END_FACE_HOLE_DEPTH + 1.0,
END_FACE_HOLE_DIAMETER,
hole_center_x,
0.0,
END_FACE_HOLE_Z,
)
cap.label = "right_end_cap" if side > 0 else "left_end_cap"
return cap
def gen_step():
"""Return a labeled three-body STEP-ready compound."""
core = _make_core()
left_cap = _make_end_cap(-1)
right_cap = _make_end_cap(1)
model = Compound(children=[core, left_cap, right_cap])
model.label = "compact_guided_cylinder_v1"
return model
@@ -1,149 +0,0 @@
{
"schema_version": "1.0",
"model_spec_kind": "parametric_cad_model",
"model_id": "compact_guided_cylinder",
"units": "mm",
"reconstruction": {
"mode": "native_generator",
"generator": {
"path": "compact_guided_cylinder.py",
"entrypoint": "gen_step"
}
},
"parameters": {
"core_length": {
"value": 116.0,
"unit": "mm",
"role": "main_body_length"
},
"core_width": {
"value": 56.0,
"unit": "mm",
"role": "main_body_width"
},
"core_bottom_z": {
"value": 2.0,
"unit": "mm",
"role": "main_body_base_offset"
},
"core_height": {
"value": 34.0,
"unit": "mm",
"role": "main_body_height"
},
"end_cap_thickness": {
"value": 8.0,
"unit": "mm",
"role": "end_cap_thickness"
},
"end_cap_width": {
"value": 60.0,
"unit": "mm",
"role": "end_cap_width"
},
"end_cap_height": {
"value": 38.0,
"unit": "mm",
"role": "end_cap_height"
},
"side_groove_depth": {
"value": 1.8,
"unit": "mm",
"role": "longitudinal_groove_depth"
},
"side_groove_height": {
"value": 2.0,
"unit": "mm",
"role": "longitudinal_groove_height"
},
"mount_hole_diameter": {
"value": 4.5,
"unit": "mm",
"role": "mounting_hole_diameter"
},
"mount_hole_x": {
"value": 32.0,
"unit": "mm",
"role": "mounting_pattern_half_spacing_x"
},
"mount_hole_y": {
"value": 16.0,
"unit": "mm",
"role": "mounting_pattern_half_spacing_y"
},
"port_bore_diameter": {
"value": 18.0,
"unit": "mm",
"role": "central_port_bore_diameter"
},
"port_collar_outer_diameter": {
"value": 26.0,
"unit": "mm",
"role": "central_port_collar_outer_diameter"
},
"port_collar_height": {
"value": 3.0,
"unit": "mm",
"role": "central_port_collar_height"
},
"tie_rod_end_diameter": {
"value": 12.0,
"unit": "mm",
"role": "tie_rod_end_diameter"
},
"tie_rod_end_protrusion": {
"value": 3.0,
"unit": "mm",
"role": "tie_rod_end_protrusion"
},
"tie_rod_y": {
"value": 24.0,
"unit": "mm",
"role": "tie_rod_pattern_half_spacing_y"
},
"end_face_hole_diameter": {
"value": 5.5,
"unit": "mm",
"role": "end_face_blind_hole_diameter"
},
"end_face_hole_depth": {
"value": 6.0,
"unit": "mm",
"role": "end_face_blind_hole_depth"
},
"end_face_hole_z": {
"value": 14.0,
"unit": "mm",
"role": "end_face_blind_hole_height"
}
},
"feature_groups": [
{
"id": "main_body",
"kind": "prismatic_body"
},
{
"id": "mounting_pattern",
"kind": "repeated_axial_hole_pattern",
"parameters": [
"mount_hole_diameter",
"mount_hole_x",
"mount_hole_y"
]
},
{
"id": "central_port",
"kind": "raised_collar_with_passage",
"parameters": [
"port_bore_diameter",
"port_collar_outer_diameter",
"port_collar_height"
]
}
],
"modifications": [],
"outputs": {
"step": "compact_guided_cylinder.step",
"stl": "compact_guided_cylinder.stl"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 322 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 322 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 322 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 370 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 431 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

@@ -1,37 +0,0 @@
{
"input": "compact_guided_cylinder.step",
"mode": "view",
"outputs": [
{
"path": "review/iso.png",
"camera": "iso"
},
{
"path": "review/iso_opposite.png",
"camera": {
"direction": [
-1,
1,
-0.8
]
}
},
{
"path": "review/top.png",
"camera": "top"
},
{
"path": "review/front.png",
"camera": "front"
}
],
"display": {
"mode": "solid",
"projection": "orthographic"
},
"render": {
"viewLabels": true,
"padding": 0.12,
"sizeProfile": "diagnostic"
}
}
@@ -1,168 +0,0 @@
"""Parametric V1 connecting-rod sample routed to the build123d backend."""
from math import atan2, degrees, hypot
from build123d import (
Align,
Box,
BuildPart,
BuildSketch,
Cylinder,
Location,
Locations,
Mode,
Plane,
SlotOverall,
extrude,
fillet,
)
CENTER_DISTANCE = 120.0
THICKNESS = 14.0
BIG_END_OUTER_DIAMETER = 56.0
BIG_END_BORE_DIAMETER = 36.0
SMALL_END_OUTER_DIAMETER = 36.0
SMALL_END_BORE_DIAMETER = 20.0
WEB_WIDTH = 24.0
POCKET_LENGTH = 72.0
POCKET_WIDTH = 12.0
POCKET_DEPTH = 3.0
VIEWER_SLOT_START = (-28.73179347578467, -0.3844822039559189)
VIEWER_SLOT_END = (24.36043904920138, -0.24367243243227724)
VIEWER_SLOT_SURFACE_Z = THICKNESS - POCKET_DEPTH
VIEWER_SLOT_WIDTH = 2.0
VIEWER_SLOT_BLIND_DEPTH = 2.0
VIEWER_EDGE_E14_FILLET_RADIUS = 1.0
VIEWER_HOLE_CENTER = (-22.122781376227962, -9.435525387895417)
VIEWER_HOLE_DIAMETER = 6.0
VIEWER_HOLE_BLIND_DEPTH = 6.0
VIEWER_HOLE_SURFACE_Z = THICKNESS
VIEWER_HOLE_BOOLEAN_OVERTRAVEL = 0.2
VIEWER_SLOT_CENTER = (
(VIEWER_SLOT_START[0] + VIEWER_SLOT_END[0]) / 2.0,
(VIEWER_SLOT_START[1] + VIEWER_SLOT_END[1]) / 2.0,
)
VIEWER_SLOT_LENGTH = hypot(
VIEWER_SLOT_END[0] - VIEWER_SLOT_START[0],
VIEWER_SLOT_END[1] - VIEWER_SLOT_START[1],
)
VIEWER_SLOT_ROTATION = degrees(
atan2(
VIEWER_SLOT_END[1] - VIEWER_SLOT_START[1],
VIEWER_SLOT_END[0] - VIEWER_SLOT_START[0],
)
)
def _viewer_edge_e14(part):
"""Select the big-end top outer edge selected in CAD Viewer as e14."""
selected_edges = []
for edge in part.edges():
try:
edge_radius = edge.radius
edge_center = edge.arc_center
edge_normal = edge.normal()
except Exception:
continue
if abs(edge_radius - BIG_END_OUTER_DIAMETER / 2.0) > 0.05:
continue
if abs(edge_center.X + CENTER_DISTANCE / 2.0) > 0.05:
continue
if abs(edge_center.Y) > 0.05:
continue
if abs(edge_center.Z - THICKNESS) > 0.05:
continue
if abs(edge_normal.Z) < 1.0 - 1e-4:
continue
selected_edges.append(edge)
if len(selected_edges) != 1:
raise RuntimeError(f"Expected one viewer-selected e14 edge, found {len(selected_edges)}")
return selected_edges
def gen_step():
"""Return a closed, STEP-ready connecting-rod solid in millimeters."""
half_distance = CENTER_DISTANCE / 2.0
with BuildPart() as rod:
with Locations(Location((-half_distance, 0.0, 0.0))):
Cylinder(
radius=BIG_END_OUTER_DIAMETER / 2.0,
height=THICKNESS,
align=(Align.CENTER, Align.CENTER, Align.MIN),
)
with Locations(Location((half_distance, 0.0, 0.0))):
Cylinder(
radius=SMALL_END_OUTER_DIAMETER / 2.0,
height=THICKNESS,
align=(Align.CENTER, Align.CENTER, Align.MIN),
)
Box(
CENTER_DISTANCE,
WEB_WIDTH,
THICKNESS,
align=(Align.CENTER, Align.CENTER, Align.MIN),
)
with Locations(Location((-half_distance, 0.0, -1.0))):
Cylinder(
radius=BIG_END_BORE_DIAMETER / 2.0,
height=THICKNESS + 2.0,
align=(Align.CENTER, Align.CENTER, Align.MIN),
mode=Mode.SUBTRACT,
)
with Locations(Location((half_distance, 0.0, -1.0))):
Cylinder(
radius=SMALL_END_BORE_DIAMETER / 2.0,
height=THICKNESS + 2.0,
align=(Align.CENTER, Align.CENTER, Align.MIN),
mode=Mode.SUBTRACT,
)
with BuildSketch(Plane.XY):
SlotOverall(width=POCKET_LENGTH, height=POCKET_WIDTH)
extrude(amount=POCKET_DEPTH, mode=Mode.SUBTRACT)
with BuildSketch(Plane.XY.offset(THICKNESS - POCKET_DEPTH)):
SlotOverall(width=POCKET_LENGTH, height=POCKET_WIDTH)
extrude(amount=POCKET_DEPTH, mode=Mode.SUBTRACT)
with BuildSketch(Plane.XY.offset(VIEWER_SLOT_SURFACE_Z - VIEWER_SLOT_BLIND_DEPTH)):
with Locations(Location((VIEWER_SLOT_CENTER[0], VIEWER_SLOT_CENTER[1], 0.0))):
SlotOverall(
width=VIEWER_SLOT_LENGTH,
height=VIEWER_SLOT_WIDTH,
rotation=VIEWER_SLOT_ROTATION,
)
extrude(amount=VIEWER_SLOT_BLIND_DEPTH, mode=Mode.SUBTRACT)
with Locations(
Location(
(
VIEWER_HOLE_CENTER[0],
VIEWER_HOLE_CENTER[1],
VIEWER_HOLE_SURFACE_Z - VIEWER_HOLE_BLIND_DEPTH,
)
)
):
Cylinder(
radius=VIEWER_HOLE_DIAMETER / 2.0,
height=VIEWER_HOLE_BLIND_DEPTH + VIEWER_HOLE_BOOLEAN_OVERTRAVEL,
align=(Align.CENTER, Align.CENTER, Align.MIN),
mode=Mode.SUBTRACT,
)
result = rod.part
result = fillet(_viewer_edge_e14(result), radius=VIEWER_EDGE_E14_FILLET_RADIUS)
result.label = "cad_router_v1_connecting_rod"
return result
Binary file not shown.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 410 KiB

@@ -1,106 +0,0 @@
{
"schema_version": "1.0",
"request": "参考图片生成一个8孔圆法兰,中心孔直径20毫米,外径50毫米,厚度4毫米,螺丝孔使用M3;根据 viewer 选中的几何位置添加2x2、直径2毫米、8毫米间距的贯穿孔阵列、一个3毫米贯穿沉头孔,以及一个10x6x1毫米矩形口袋",
"route": {
"selected_backend": "build123d",
"runner_skill": "cad",
"project": "text-to-cad",
"fallback_order": ["simplecadapi", "cadam"],
"workflow_profiles": ["requirement_refinement", "visual_repair", "source_modification"],
"downstream_skills": ["cad-viewer"]
},
"source": {
"path": "flange_8x_m3.py",
"format": "python",
"backend": "build123d"
},
"artifacts": [
{
"path": "flange_8x_m3.step",
"role": "primary"
},
{
"path": "flange_8x_m3.stl",
"role": "secondary"
},
{
"path": ".flange_8x_m3.step.glb",
"role": "viewer_mesh_topology"
}
],
"parameters": {
"outer_diameter_mm": 50.0,
"inner_diameter_mm": 20.0,
"thickness_mm": 4.0,
"bolt_hole_count": 8,
"bolt_hole_diameter_mm": 3.4,
"bolt_circle_diameter_mm": 40.0,
"angular_spacing_deg": 45.0,
"viewer_pattern_center_mm": [8.077088362294017, 15.744119598589815],
"viewer_pattern_hole_diameter_mm": 2.0,
"viewer_pattern_rows": 2,
"viewer_pattern_columns": 2,
"viewer_pattern_pitch_x_mm": 8.0,
"viewer_pattern_pitch_y_mm": 8.0,
"viewer_pattern_depth": "through",
"viewer_pattern_hole_centers_mm": [
[4.077088362294017, 11.744119598589815],
[12.077088362294017, 11.744119598589815],
[4.077088362294017, 19.744119598589815],
[12.077088362294017, 19.744119598589815]
],
"viewer_countersink_center_mm": [-14.6034432889167, -4.110394299469192],
"viewer_countersink_hole_diameter_mm": 3.0,
"viewer_countersink_diameter_mm": 6.0,
"viewer_countersink_angle_deg": 90.0,
"viewer_countersink_depth": "through",
"viewer_pocket_center_mm": [6.197199513379157, -14.374353062530322],
"viewer_pocket_shape": "rectangle",
"viewer_pocket_width_mm": 10.0,
"viewer_pocket_height_mm": 6.0,
"viewer_pocket_depth_mm": 1.0,
"viewer_pocket_bottom_z_mm": 3.0
},
"assumptions": [
"M3螺丝孔按普通间隙通孔处理,孔径采用3.4毫米,不是M3攻丝底孔。",
"未指定分度圆,采用40毫米分度圆,以保持孔到外圆约3.3毫米的最小径向边距。",
"参考图中的车削纹理作为外观参考,不生成削弱4毫米薄法兰的深槽。",
"矩形口袋按 surface_xy 对齐全局 XY,沿选中面法向进入材料,深度1毫米。"
],
"validation": [
{
"path": "validation.json",
"status": "passed",
"checks": {
"step_valid": true,
"solid_count": 1,
"exact_size_mm": [50.0, 50.0, 4.0],
"topology_faces": 24,
"topology_edges": 62,
"m3_clearance_hole_count": 8,
"m3_clearance_hole_diameter_mm": 3.4,
"viewer_pattern_hole_count": 4,
"viewer_pattern_hole_diameter_mm": 2.0,
"viewer_countersink_hole_diameter_mm": 3.0,
"viewer_countersink_diameter_mm": 6.0,
"viewer_countersink_angle_deg": 90.0,
"viewer_pocket_bottom_center_mm": [6.197199513379157, -14.374353062530322, 3.0],
"viewer_pocket_bottom_size_mm": [10.0, 6.0],
"viewer_pocket_depth_mm": 1.0,
"viewer_mesh_topology": ".flange_8x_m3.step.glb",
"visual_review": "passed_viewer_pocket_top"
}
},
{
"path": "review/viewer_pocket_top_20260724T031341Z.png",
"status": "passed",
"checks": {
"snapshot_camera": "top",
"pocket_visible": true
}
}
],
"viewer_links": [
"http://127.0.0.1:5174/?dir=%2FUsers%2Flk%2FProjects%2FcadSet%2Ftext-to-cad%2Fmodels%2Fcad-router-v1%2Fflange_8x_m3&file=flange_8x_m3.step"
]
}
@@ -1,136 +0,0 @@
"""Parametric eight-hole circular flange generated with build123d."""
from math import cos, radians, sin, tan
from build123d import Align, Box, BuildPart, Cone, Cylinder, Location, Locations, Mode
OUTER_DIAMETER_MM = 50.0
INNER_DIAMETER_MM = 20.0
THICKNESS_MM = 4.0
BOLT_HOLE_COUNT = 8
M3_CLEARANCE_DIAMETER_MM = 3.4
BOLT_CIRCLE_DIAMETER_MM = 40.0
M4_THREAD_SPEC = "M4"
M4_TAP_DRILL_DIAMETER_MM = 3.3
M4_THREAD_DEPTH_MM = 6.0
M4_THREAD_HOLE_CENTER_MM = (-6.104359972902419, -13.137483558259564)
M4_THREAD_HOLE_FACE_Z_MM = THICKNESS_MM
M4_THREAD_HOLE_DIRECTION = (0.0, 0.0, -1.0)
VIEWER_PATTERN_CENTER_MM = (8.077088362294017, 15.744119598589815)
VIEWER_PATTERN_HOLE_DIAMETER_MM = 2.0
VIEWER_PATTERN_ROWS = 2
VIEWER_PATTERN_COLUMNS = 2
VIEWER_PATTERN_PITCH_X_MM = 8.0
VIEWER_PATTERN_PITCH_Y_MM = 8.0
VIEWER_PATTERN_FACE_Z_MM = THICKNESS_MM
VIEWER_PATTERN_DIRECTION = (0.0, 0.0, -1.0)
VIEWER_COUNTERSINK_CENTER_MM = (-14.6034432889167, -4.110394299469192)
VIEWER_COUNTERSINK_HOLE_DIAMETER_MM = 3.0
VIEWER_COUNTERSINK_DIAMETER_MM = 6.0
VIEWER_COUNTERSINK_ANGLE_DEG = 90.0
VIEWER_COUNTERSINK_FACE_Z_MM = THICKNESS_MM
VIEWER_COUNTERSINK_DIRECTION = (0.0, 0.0, -1.0)
VIEWER_POCKET_CENTER_MM = (6.197199513379157, -14.374353062530322)
VIEWER_POCKET_WIDTH_MM = 10.0
VIEWER_POCKET_HEIGHT_MM = 6.0
VIEWER_POCKET_DEPTH_MM = 1.0
VIEWER_POCKET_FACE_Z_MM = THICKNESS_MM
VIEWER_POCKET_DIRECTION = (0.0, 0.0, -1.0)
def polar_point(radius: float, angle_degrees: float) -> tuple[float, float]:
angle = radians(angle_degrees)
return radius * cos(angle), radius * sin(angle)
def gen_step():
"""Return one STEP-ready flange solid in millimeters."""
with BuildPart() as flange:
Cylinder(
radius=OUTER_DIAMETER_MM / 2.0,
height=THICKNESS_MM,
align=(Align.CENTER, Align.CENTER, Align.MIN),
)
with Locations(Location((0.0, 0.0, -1.0))):
Cylinder(
radius=INNER_DIAMETER_MM / 2.0,
height=THICKNESS_MM + 2.0,
align=(Align.CENTER, Align.CENTER, Align.MIN),
mode=Mode.SUBTRACT,
)
for index in range(BOLT_HOLE_COUNT):
angle_degrees = 360.0 * index / BOLT_HOLE_COUNT
x_pos, y_pos = polar_point(BOLT_CIRCLE_DIAMETER_MM / 2.0, angle_degrees)
with Locations(Location((x_pos, y_pos, -1.0))):
Cylinder(
radius=M3_CLEARANCE_DIAMETER_MM / 2.0,
height=THICKNESS_MM + 2.0,
align=(Align.CENTER, Align.CENTER, Align.MIN),
mode=Mode.SUBTRACT,
)
m4_x_pos, m4_y_pos = M4_THREAD_HOLE_CENTER_MM
m4_cut_depth = min(M4_THREAD_DEPTH_MM, THICKNESS_MM)
with Locations(Location((m4_x_pos, m4_y_pos, M4_THREAD_HOLE_FACE_Z_MM - m4_cut_depth))):
Cylinder(
radius=M4_TAP_DRILL_DIAMETER_MM / 2.0,
height=m4_cut_depth + 1.0,
align=(Align.CENTER, Align.CENTER, Align.MIN),
mode=Mode.SUBTRACT,
)
pattern_center_x, pattern_center_y = VIEWER_PATTERN_CENTER_MM
pattern_start_x = pattern_center_x - (VIEWER_PATTERN_COLUMNS - 1) * VIEWER_PATTERN_PITCH_X_MM / 2.0
pattern_start_y = pattern_center_y - (VIEWER_PATTERN_ROWS - 1) * VIEWER_PATTERN_PITCH_Y_MM / 2.0
for row_index in range(VIEWER_PATTERN_ROWS):
for column_index in range(VIEWER_PATTERN_COLUMNS):
hole_x = pattern_start_x + column_index * VIEWER_PATTERN_PITCH_X_MM
hole_y = pattern_start_y + row_index * VIEWER_PATTERN_PITCH_Y_MM
with Locations(Location((hole_x, hole_y, -1.0))):
Cylinder(
radius=VIEWER_PATTERN_HOLE_DIAMETER_MM / 2.0,
height=THICKNESS_MM + 2.0,
align=(Align.CENTER, Align.CENTER, Align.MIN),
mode=Mode.SUBTRACT,
)
countersink_x, countersink_y = VIEWER_COUNTERSINK_CENTER_MM
countersink_radius = VIEWER_COUNTERSINK_DIAMETER_MM / 2.0
countersink_through_radius = VIEWER_COUNTERSINK_HOLE_DIAMETER_MM / 2.0
countersink_depth = (
countersink_radius - countersink_through_radius
) / tan(radians(VIEWER_COUNTERSINK_ANGLE_DEG / 2.0))
with Locations(Location((countersink_x, countersink_y, -1.0))):
Cylinder(
radius=countersink_through_radius,
height=THICKNESS_MM + 2.0,
align=(Align.CENTER, Align.CENTER, Align.MIN),
mode=Mode.SUBTRACT,
)
with Locations(
Location((countersink_x, countersink_y, VIEWER_COUNTERSINK_FACE_Z_MM - countersink_depth))
):
Cone(
countersink_through_radius,
countersink_radius,
countersink_depth + 0.05,
align=(Align.CENTER, Align.CENTER, Align.MIN),
mode=Mode.SUBTRACT,
)
pocket_x, pocket_y = VIEWER_POCKET_CENTER_MM
with Locations(Location((pocket_x, pocket_y, VIEWER_POCKET_FACE_Z_MM - VIEWER_POCKET_DEPTH_MM))):
Box(
VIEWER_POCKET_WIDTH_MM,
VIEWER_POCKET_HEIGHT_MM,
VIEWER_POCKET_DEPTH_MM + 0.05,
align=(Align.CENTER, Align.CENTER, Align.MIN),
mode=Mode.SUBTRACT,
)
part = flange.part
part.label = "flange_8x_m3_clearance_with_m4_tapped_hole_viewer_pattern_countersink_and_pocket"
return part
Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

@@ -1,29 +0,0 @@
{
"input": "models/cad-router-v1/flange_8x_m3/flange_8x_m3.step",
"mode": "view",
"outputs": [
{
"path": "models/cad-router-v1/flange_8x_m3/review/iso.png",
"camera": "iso"
},
{
"path": "models/cad-router-v1/flange_8x_m3/review/iso_opposite.png",
"camera": {
"direction": [-1, 1, -0.8]
}
},
{
"path": "models/cad-router-v1/flange_8x_m3/review/top.png",
"camera": "top"
},
{
"path": "models/cad-router-v1/flange_8x_m3/review/front.png",
"camera": "front"
}
],
"render": {
"viewLabels": true,
"padding": 0.12,
"sizeProfile": "diagnostic"
}
}
@@ -1,68 +0,0 @@
{
"step_valid": true,
"solid_count": 1,
"exact_size_mm": [50.0, 50.0, 4.0],
"topology_counts": {
"faces": 24,
"edges": 62
},
"outer_radius_mm": 25.0,
"inner_radius_mm": 10.0,
"m3_clearance_hole_radius_mm": 1.7,
"m3_clearance_hole_count": 8,
"bolt_circle_radius_mm": 20.0,
"angular_spacing_deg": [45.0, 45.0, 45.0, 45.0, 45.0, 45.0, 45.0, 45.0],
"viewer_edits": {
"hole_pattern": {
"operation": "add_hole_pattern",
"selection_point_model_mm": [8.077088362294017, 15.744119598589815, 4.0],
"hole_diameter_mm": 2.0,
"rows": 2,
"columns": 2,
"pitch_x_mm": 8.0,
"pitch_y_mm": 8.0,
"depth": "through",
"hole_centers_mm": [
[4.077088362294017, 11.744119598589815, 2.0],
[12.077088362294017, 11.744119598589815, 2.0],
[4.077088362294017, 19.744119598589815, 2.0],
[12.077088362294017, 19.744119598589815, 2.0]
],
"verified_hole_count": 4,
"verified_hole_diameter_mm": 2.0,
"verified_through_height_mm": 4.0,
"max_center_error_mm": 0.0
},
"countersink": {
"operation": "add_countersink",
"selection_point_model_mm": [-14.6034432889167, -4.110394299469192, 4.0],
"hole_diameter_mm": 3.0,
"countersink_diameter_mm": 6.0,
"countersink_angle_deg": 90.0,
"countersink_depth_mm": 1.5,
"depth": "through"
},
"pocket": {
"operation": "add_pocket",
"selection_point_model_mm": [6.197199513379157, -14.374353062530322, 4.0],
"shape": "rectangle",
"width_mm": 10.0,
"height_mm": 6.0,
"depth_mm": 1.0,
"bottom_z_mm": 3.0,
"verified_bottom_center_mm": [6.197199513379157, -14.374353062530322, 3.0],
"verified_bottom_size_mm": [10.0, 6.0],
"verified_bottom_face_count": 1
}
},
"viewer_mesh_topology": {
"path": ".flange_8x_m3.step.glb",
"regenerated": true
},
"snapshot_review": {
"status": "passed",
"path": "review/viewer_pocket_top_20260724T031341Z.png",
"camera": "top"
},
"visual_review": "passed_viewer_pocket_top"
}
@@ -1,18 +0,0 @@
{
"task": "Generate an image-inferred flanged hub adapter",
"backend": "build123d",
"source_of_truth": "flanged_hub_adapter.py",
"primary_output": "flanged_hub_adapter.step",
"secondary_outputs": ["flanged_hub_adapter.stl"],
"units": "mm",
"assumptions": {
"base_diameter": 100.0,
"base_thickness": 6.0,
"total_height": 58.0,
"central_bore_diameter": 24.0,
"peripheral_holes": "4 x diameter 5.5 on PCD 82",
"counterbored_holes": "2 x diameter 6.5 through, diameter 12.5 counterbore"
},
"reference": "/var/folders/97/90ckyxns4ndbb96jw9hhs3jw0000gn/T/codex-clipboard-0cc8755c-fb41-449f-b543-808f2fd64cf1.png",
"dimension_status": "inferred from image; not suitable for tolerance-critical manufacture without confirmation"
}
@@ -1,119 +0,0 @@
"""Image-inferred parametric flanged hub adapter generated with build123d.
All dimensions are millimetres. The values are intentionally collected as
named parameters because the reference image contains no dimensions.
"""
from math import cos, radians, sin
from build123d import Align, BuildPart, Cone, Cylinder, Location, Locations, Mode
# Base mounting flange.
BASE_DIAMETER = 100.0
BASE_THICKNESS = 6.0
PERIPHERAL_HOLE_COUNT = 4
PERIPHERAL_HOLE_DIAMETER = 5.5
PERIPHERAL_HOLE_PCD = 82.0
PERIPHERAL_HOLE_START_ANGLE = 45.0
# Raised hub and tapered transition.
LOWER_BOSS_DIAMETER = 62.0
LOWER_BOSS_HEIGHT = 8.0
TAPER_TOP_DIAMETER = 36.0
TAPER_HEIGHT = 10.0
# Hollow upper sleeve.
SLEEVE_OUTER_DIAMETER = 36.0
SLEEVE_INNER_DIAMETER = 24.0
SLEEVE_HEIGHT = 34.0
# Two opposed counterbored mounting holes in the raised region.
COUNTERBORE_HOLE_SPACING = 44.0
COUNTERBORE_THROUGH_DIAMETER = 6.5
COUNTERBORE_DIAMETER = 12.5
COUNTERBORE_FLOOR_Z = 17.0
TOTAL_HEIGHT = BASE_THICKNESS + LOWER_BOSS_HEIGHT + TAPER_HEIGHT + SLEEVE_HEIGHT
def _polar(radius: float, angle_degrees: float) -> tuple[float, float]:
angle = radians(angle_degrees)
return radius * cos(angle), radius * sin(angle)
def gen_step():
"""Return one STEP-ready flanged hub solid."""
with BuildPart() as adapter:
Cylinder(
BASE_DIAMETER / 2.0,
BASE_THICKNESS,
align=(Align.CENTER, Align.CENTER, Align.MIN),
)
with Locations(Location((0.0, 0.0, BASE_THICKNESS - 0.05))):
Cylinder(
LOWER_BOSS_DIAMETER / 2.0,
LOWER_BOSS_HEIGHT + 0.05,
align=(Align.CENTER, Align.CENTER, Align.MIN),
)
taper_z = BASE_THICKNESS + LOWER_BOSS_HEIGHT - 0.05
with Locations(Location((0.0, 0.0, taper_z))):
Cone(
LOWER_BOSS_DIAMETER / 2.0,
TAPER_TOP_DIAMETER / 2.0,
TAPER_HEIGHT + 0.05,
align=(Align.CENTER, Align.CENTER, Align.MIN),
)
sleeve_z = BASE_THICKNESS + LOWER_BOSS_HEIGHT + TAPER_HEIGHT - 0.05
with Locations(Location((0.0, 0.0, sleeve_z))):
Cylinder(
SLEEVE_OUTER_DIAMETER / 2.0,
SLEEVE_HEIGHT + 0.05,
align=(Align.CENTER, Align.CENTER, Align.MIN),
)
# Continuous central bore.
with Locations(Location((0.0, 0.0, -1.0))):
Cylinder(
SLEEVE_INNER_DIAMETER / 2.0,
TOTAL_HEIGHT + 2.0,
align=(Align.CENTER, Align.CENTER, Align.MIN),
mode=Mode.SUBTRACT,
)
# Four outer mounting holes, rotated 45 degrees to match the image.
for index in range(PERIPHERAL_HOLE_COUNT):
angle = PERIPHERAL_HOLE_START_ANGLE + 360.0 * index / PERIPHERAL_HOLE_COUNT
x_pos, y_pos = _polar(PERIPHERAL_HOLE_PCD / 2.0, angle)
with Locations(Location((x_pos, y_pos, -1.0))):
Cylinder(
PERIPHERAL_HOLE_DIAMETER / 2.0,
BASE_THICKNESS + 2.0,
align=(Align.CENTER, Align.CENTER, Align.MIN),
mode=Mode.SUBTRACT,
)
# Opposed through holes with flat-bottom cylindrical counterbores.
for x_pos in (-COUNTERBORE_HOLE_SPACING / 2.0, COUNTERBORE_HOLE_SPACING / 2.0):
with Locations(Location((x_pos, 0.0, -1.0))):
Cylinder(
COUNTERBORE_THROUGH_DIAMETER / 2.0,
TOTAL_HEIGHT + 2.0,
align=(Align.CENTER, Align.CENTER, Align.MIN),
mode=Mode.SUBTRACT,
)
with Locations(Location((x_pos, 0.0, COUNTERBORE_FLOOR_Z))):
Cylinder(
COUNTERBORE_DIAMETER / 2.0,
TOTAL_HEIGHT - COUNTERBORE_FLOOR_Z + 1.0,
align=(Align.CENTER, Align.CENTER, Align.MIN),
mode=Mode.SUBTRACT,
)
part = adapter.part
part.label = "flanged_hub_adapter_v1"
return part
Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 KiB

@@ -1,31 +0,0 @@
{
"input": "models/cad-router-v1/flanged_hub_adapter_v1/flanged_hub_adapter.step",
"mode": "view",
"outputs": [
{
"path": "models/cad-router-v1/flanged_hub_adapter_v1/review/iso.png",
"camera": {"direction": [1, -1, 0.75]}
},
{
"path": "models/cad-router-v1/flanged_hub_adapter_v1/review/iso_opposite.png",
"camera": {"direction": [-1, 1, 0.65]}
},
{
"path": "models/cad-router-v1/flanged_hub_adapter_v1/review/top.png",
"camera": "top"
},
{
"path": "models/cad-router-v1/flanged_hub_adapter_v1/review/front.png",
"camera": "front"
}
],
"render": {
"viewLabels": true,
"padding": 0.12,
"sizeProfile": "diagnostic"
},
"display": {
"mode": "solid",
"projection": "orthographic"
}
}
@@ -1,82 +0,0 @@
{
"schema_version": "1.0",
"request": "生成模数2、20齿、12毫米厚、中心孔12毫米的人字齿轮,导出STEP并保留可重放模型图",
"route": {
"selected_backend": "simplecadapi",
"runner_skill": "simplecadapi",
"confidence": "high",
"fallback_order": [
"build123d",
"cadam"
],
"decision_path": "gear-route-decision.json"
},
"source": {
"path": "herringbone_gear_simplecad.py",
"format": "python",
"backend": "simplecadapi",
"replay_model": "herringbone_gear_simplecad.json"
},
"artifacts": [
{
"path": "herringbone_gear_simplecad.step",
"role": "primary"
},
{
"path": "herringbone_gear_simplecad.stl",
"role": "secondary"
},
{
"path": "herringbone_gear_simplecad_20260722T072647Z.png",
"role": "verification_snapshot"
}
],
"parameters": {
"teeth": 20,
"module_mm": 2.0,
"pressure_angle_deg": 20.0,
"helix_angle_deg": 30.0,
"height_mm": 12.0,
"bore_diameter_mm": 12.0,
"backlash_mm": 0.05
},
"validation": [
{
"check": "SimpleCAD operation graph nodes",
"result": 270,
"status": "pass"
},
{
"check": "volume cubic millimeters",
"result": 13213.684,
"status": "pass"
},
{
"check": "STEP topology",
"result": {
"shape_count": 1,
"face_count": 963,
"edge_count": 2043,
"bounds_mm": [
43.99775,
43.99775,
12.0
],
"warnings": []
},
"status": "pass"
},
{
"check": "isometric snapshot review",
"result": "Twenty double-helical teeth, the center bore, and the herringbone ridge are visibly present.",
"status": "pass"
}
],
"assumptions": [
"This sample validates backend routing and parametric generation; it is not a rated transmission design.",
"Material, heat treatment, profile shift, tolerance class, strength, lubrication, and mating gear checks remain out of scope."
],
"viewer_links": [
"http://127.0.0.1:4178/?dir=%2FUsers%2Fjerry%2Flinkhand%2FCadSet%2Ftext-to-cad%2Fmodels%2Fcad-router-v1&file=herringbone_gear_simplecad.step"
]
}
@@ -1,62 +0,0 @@
{
"schema_version": "1.0",
"request": "生成模数2、20齿、12毫米厚、中心孔12毫米的人字齿轮,导出STEP并保留可重放模型图",
"selected_backend": "simplecadapi",
"runner_skill": "simplecadapi",
"confidence": "high",
"backend_scores": [
{
"backend": "simplecadapi",
"score": 175,
"reasons": [
"+20 specialist mechanical baseline",
"+65 supported standard mechanical family",
"+60 replay, semantic graph, or FreeCAD requirement",
"+30 OCP STEP export requested"
]
},
{
"backend": "build123d",
"score": 78,
"reasons": [
"+35 general STEP-first default",
"+8 can model the family generically",
"+35 editable STEP requested"
]
},
{
"backend": "cadam",
"score": -60,
"reasons": [
"+10 printable CSG baseline",
"-70 no native editable STEP output"
]
}
],
"fallback_order": [
"build123d",
"cadam"
],
"workflow_profiles": [],
"downstream_skills": [
"cad-viewer"
],
"requested_outputs": [
"step"
],
"source_of_truth": "SimpleCADAPI Python generator and model JSON",
"availability": {
"build123d": {
"available": true,
"probe": "python=/Users/jerry/linkhand/CadSet/text-to-cad/.venv/bin/python"
},
"simplecadapi": {
"available": true,
"probe": "python=/Users/jerry/linkhand/CadSet/text-to-cad/.venv/bin/python"
},
"cadam": {
"available": true,
"probe": "/Users/jerry/linkhand/CadSet/CADAM"
}
}
}
@@ -1,172 +0,0 @@
{
"schema_version": "1.0",
"request": "生成一个28齿、厚度4毫米的齿轮,并在 viewer 选中的两个面点位置各添加一个2.0毫米贯穿孔;随后根据 viewer 选中的顶面点 f5 添加一个10x6x1毫米矩形口袋",
"route": {
"selected_backend": "simplecadapi",
"runner_skill": "simplecadapi",
"project": "SimpleCADAPI",
"fallback_order": [
"build123d",
"cadam"
],
"workflow_profiles": [],
"downstream_skills": [
"cad-viewer"
]
},
"source": {
"path": "gear_28t_4mm.py",
"format": "python",
"backend": "simplecadapi"
},
"artifacts": [
{
"path": "gear_28t_4mm.model.json",
"role": "replayable_model"
},
{
"path": "gear_28t_4mm.step",
"role": "primary"
},
{
"path": "gear_28t_4mm.stl",
"role": "secondary"
},
{
"path": ".gear_28t_4mm.step.glb",
"role": "viewer_mesh_topology"
}
],
"parameters": {
"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,
"edit_holes": [
{
"diameter_mm": 2.0,
"center_mm": [
-2.9189440262073063,
5.47686606164935,
4.0
]
},
{
"diameter_mm": 2.0,
"center_mm": [
7.5974463825483305,
-0.8433357012066764,
4.0
]
}
],
"edit_hole_count": 2,
"edit_hole_axis": [
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,
4.0
],
"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
]
}
}
],
"edit_pocket_count": 1
},
"assumptions": [
"未指定模数,V1采用1.0毫米。",
"未指定压力角,采用标准20度。",
"未指定中心孔,采用5.0毫米通孔。",
"未指定齿轮类型,采用直齿渐开线外齿轮。",
"viewer 编辑请求未指定孔径,采用2.0毫米贯穿孔作为可编辑默认值。"
],
"validation": [
{
"path": "validation.json",
"status": "passed",
"checks": {
"step_valid": true,
"solid_count": 1,
"bounds_mm": [
30.0,
30.0,
4.0
],
"pitch_diameter_mm": 28.0,
"edit_holes": [
{
"diameter_mm": 2.0,
"center_mm": [
-2.9189440262073063,
5.47686606164935,
4.0
]
},
{
"diameter_mm": 2.0,
"center_mm": [
7.5974463825483305,
-0.8433357012066764,
4.0
]
}
],
"edit_hole_count": 2,
"edit_pockets": [
{
"shape": "rectangle",
"width_mm": 10.0,
"height_mm": 6.0,
"depth_mm": 1.0,
"center_mm": [
-8.717129036056448,
-0.9462437095981322,
4.0
]
}
],
"edit_pocket_count": 1,
"faces": 182,
"edges": 545,
"outside_diameter_mm": 30.0,
"volume_mm3": 2167.600632,
"viewer_mesh_topology": {
"path": ".gear_28t_4mm.step.glb",
"status": "regenerated",
"face_count": 182,
"edge_count": 545,
"step_hash": "d07ba4428ce372d7dc65ea31c2c8bf636399f38e40e2bd705029789832825267"
},
"visual_review": "not_run"
}
}
],
"viewer_links": [
"http://127.0.0.1:5174/?dir=%2FUsers%2Flk%2FProjects%2FcadSet%2Ftext-to-cad%2Fmodels%2Fcad-router-v1%2Fgear_28t_4mm&file=gear_28t_4mm.step"
]
}
File diff suppressed because one or more lines are too long
@@ -1,270 +0,0 @@
"""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()
@@ -1,133 +0,0 @@
{
"n_teeth": 28,
"pitch_diameter_mm": 28.0,
"outside_diameter_mm": 30.0,
"root_diameter_mm": 25.5,
"thickness_mm": 4.0,
"bore_diameter_mm": 5.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,
"bore_top_chamfer_top_diameter_mm": 11.0,
"edit_holes": [
{
"diameter_mm": 2.0,
"center_mm": [
-2.9189440262073063,
5.47686606164935,
4.0
]
},
{
"diameter_mm": 2.0,
"center_mm": [
7.5974463825483305,
-0.8433357012066764,
4.0
]
}
],
"edit_hole_count": 2,
"edit_hole_axis": [
0.0,
0.0,
1.0
],
"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,
4.0
],
"hole_centers_mm": [
[
-3.7531123399332103,
-12.367405492677905,
4.0
],
[
4.24688766006679,
-12.367405492677905,
4.0
],
[
-3.7531123399332103,
-4.367405492677905,
4.0
],
[
4.24688766006679,
-4.367405492677905,
4.0
]
],
"selected_face": {
"reference_id": "f5",
"selector": "f5",
"face_index": 2785,
"row_index": 4,
"normal": [
0.0,
0.0,
1.0
]
}
}
],
"edit_hole_pattern_count": 1,
"edit_hole_pattern_hole_count": 4,
"edit_pockets": [
{
"shape": "rectangle",
"width_mm": 10.0,
"height_mm": 6.0,
"depth_mm": 1.0,
"center_mm": [
-8.717129036056448,
-0.9462437095981322,
4.0
],
"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
]
}
}
],
"edit_pocket_count": 1,
"volume_mm3": 2128.275635,
"faces": 184,
"edges": 557,
"tags": [
"feature.viewer_edit_hole_pattern",
"feature.viewer_edit_point_hole",
"feature.viewer_edit_rectangular_pocket",
"feature.viewer_selected_edge_chamfer",
"role.power_transmission.gear",
"sketch.gear_28t_m1.id_0",
"sketch_profile.arc_root_0",
"solid.boolean.cut",
"solid.extrusion"
],
"graph_nodes": 359
}
File diff suppressed because one or more lines are too long
@@ -1,50 +0,0 @@
"""SimpleCADAPI specialist-backend smoke test for CAD Router V1."""
from pathlib import Path
import simplecadapi as scad
N_TEETH = 20
MODULE = 2.0
PRESSURE_ANGLE = 20.0
HELIX_ANGLE = 30.0
GEAR_HEIGHT = 12.0
BORE_DIAMETER = 12.0
def generate() -> None:
output_root = Path(__file__).resolve().parent
with scad.GraphSession() as session:
gear = scad.std.gear.make_herringbone_gear_rsolid(
n_teeth=N_TEETH,
module=MODULE,
pressure_angle=PRESSURE_ANGLE,
helix_angle=HELIX_ANGLE,
gear_height=GEAR_HEIGHT,
addendum_factor=1.0,
clearance_factor=0.25,
backlash=0.05,
)
bore = scad.make_cylinder_rsolid(
radius=BORE_DIAMETER / 2.0,
height=GEAR_HEIGHT + 2.0,
bottom_face_center=(0.0, 0.0, -1.0),
axis=(0.0, 0.0, 1.0),
)
gear = scad.cut_rsolid(gear, bore, skip_non_intersecting=False)
gear = scad.apply_tag(shape=gear, tag="role.power_transmission.gear")
model_json = scad.export_model_json(session=session, indent=2)
(output_root / "herringbone_gear_simplecad.json").write_text(model_json, encoding="utf-8")
scad.export_step(shapes=gear, filename=str(output_root / "herringbone_gear_simplecad.step"))
scad.export_stl(shapes=gear, filename=str(output_root / "herringbone_gear_simplecad.stl"))
print("volume_mm3", round(gear.get_volume(), 3))
print("tags", scad.list_tags(shape=gear))
print("graph_nodes", session.graph.node_count)
if __name__ == "__main__":
generate()
Binary file not shown.

Before

Width:  |  Height:  |  Size: 953 KiB

@@ -1,149 +0,0 @@
{
"schema_version": "1.0",
"request": "把明确提供的 015240.step 转换成可修改的 model-spec.json,并保留原始几何作为精确基体",
"route": {
"selected_backend": "build123d",
"runner_skill": "cad",
"project": "text-to-cad",
"fallback_order": [
"simplecadapi",
"cadam"
],
"workflow_profiles": [],
"operation": "modify",
"source_mode": "exact_step_base",
"modification_mode": "model_spec_parameter_edit"
},
"source": {
"path": "source.step",
"format": "step",
"backend": "build123d",
"sha256": "55aee6a0ad74435503a1e7f108b32c9f403ae9838933e2be6728fb5b2f5cfbd4",
"immutable_exact_base": true
},
"artifacts": [
{
"path": "model-spec.json",
"role": "editable_geometry_contract"
},
{
"path": "imported_015240.step",
"role": "primary"
},
{
"path": "imported_015240.stl",
"role": "secondary"
},
{
"path": "source.step",
"role": "immutable_exact_base"
}
],
"parameters": {},
"experience": {
"library": "../../../../cad-experience-library/library.json",
"context_kind": "generalized_cad_experience_query",
"methods_applied": []
},
"assumptions": [
"单位按 STEP 几何和导入工具约定记录为 mm。",
"原 STEP 不包含可可靠恢复的原生草图、约束或特征历史;后续修改通过 model-spec.json 的命名参数和修改特征表达。",
"“选中面厚度增加”按直接建模语义解释为源面 #f22 沿其 +Z 法向外移 1.0 mm。",
"“红圈内的孔缩小”按目标水平板通孔从约 Ø4.8 mm 缩小到 Ø3.6 mm 处理。"
],
"validation": [
{
"check": "exact_base_sha256",
"passed": true,
"value": "55aee6a0ad74435503a1e7f108b32c9f403ae9838933e2be6728fb5b2f5cfbd4"
},
{
"check": "exact_base_geometry_signature",
"passed": true,
"scope": "immutable_source.step",
"size_mm": [
26.200001497,
18.906424738,
28.2
],
"center_mm": [
13.100000748,
7.453212369,
0.0
],
"solid_count": 1,
"face_count": 31,
"edge_count": 87,
"volume_mm3": 2400.466496
},
{
"check": "model_spec_parameterized_rebuild",
"passed": true,
"modified_size_mm": [
26.200001497,
18.906424738,
29.2
],
"modified_center_mm": [
13.100000748,
7.453212369,
0.5
],
"solid_count": 1,
"volume_mm3": 2476.533646
},
{
"check": "selected_face_f22_extension",
"passed": true,
"source_plane_z_mm": 14.1,
"result_plane_z_mm": 15.1,
"extension_mm": 1.0,
"result_face": "#f27"
},
{
"check": "circled_hole_resize",
"passed": true,
"center_mm": [
5.9,
11.006425,
0.0
],
"axis": "Z",
"source_diameter_mm": 4.799996,
"result_diameter_mm": 3.6,
"result_face": "#f22"
},
{
"check": "source_to_modified_cad_diff",
"passed": true,
"geometry_changed": true,
"size_delta_mm": [
0.0,
0.0,
1.0
],
"center_delta_mm": [
0.0,
0.0,
0.5
]
},
{
"check": "cad_inspect_refs_facts_planes_positioning",
"passed": true
},
{
"check": "snapshot_review",
"passed": true,
"views": [
"snapshots/iso_20260723T085707Z.png",
"snapshots/iso_opposite_20260723T085707Z.png",
"snapshots/top_ortho_20260723T085707Z.png",
"snapshots/front_ortho_20260723T085707Z.png"
]
}
],
"viewer_links": [
"http://127.0.0.1:4179/?dir=%2FUsers%2Fjerry%2Flinkhand%2FCadSet%2Ftext-to-cad%2Fmodels%2Fcad-router-v1%2Fimported_015240&file=imported_015240.step"
]
}
@@ -1,110 +0,0 @@
{
"schema_version": "1.0",
"model_spec_kind": "parametric_cad_model",
"model_id": "imported_015240",
"units": "mm",
"reconstruction": {
"mode": "exact_step_base",
"source": {
"path": "source.step",
"sha256": "55aee6a0ad74435503a1e7f108b32c9f403ae9838933e2be6728fb5b2f5cfbd4",
"geometry_signature": {
"size_mm": [
26.200001497,
18.906424738,
28.2
],
"center_mm": [
13.100000748,
7.453212369,
-0.0
],
"solid_count": 1,
"face_count": 31,
"edge_count": 87,
"volume_mm3": 2400.466496
}
},
"history_recovery": {
"status": "not_present_in_step",
"contract": "Preserve the imported B-Rep exactly as the immutable base; represent later edits as named parametric modifications."
}
},
"parameters": {
"selected_face_extension": {
"value": 1.0,
"unit": "mm",
"role": "outward_offset_of_source_face_f22",
"source_face": "#f22",
"direction": "+Z"
},
"target_hole_diameter": {
"value": 3.6,
"unit": "mm",
"role": "diameter_of_circled_horizontal_plate_hole",
"source_diameter_mm": 4.799996,
"axis": "Z"
}
},
"modifications": [
{
"id": "extend_selected_face_f22",
"operation": "add_box",
"source_face": "#f22",
"direction": "+Z",
"center": [
13.1,
-1.0,
{
"parameter": "selected_face_extension",
"scale": 0.5,
"offset": 14.1
}
],
"size": [
22.2,
2.0,
{
"parameter": "selected_face_extension"
}
],
"enabled": true
},
{
"id": "fill_original_circled_hole",
"operation": "add_cylinder",
"axis": "z",
"center": [
5.9,
11.006425,
0.0
],
"diameter": 4.799996,
"length": 4.0,
"enabled": true
},
{
"id": "cut_resized_circled_hole",
"operation": "cut_cylinder",
"axis": "z",
"center": [
5.9,
11.006425,
0.0
],
"diameter": {
"parameter": "target_hole_diameter"
},
"length": 6.0,
"enabled": true
}
],
"outputs": {
"step": "imported_015240.step",
"stl": "imported_015240.stl"
},
"validation": {
"exact_base_required": true,
"geometry_signature_tolerance_mm": 1e-07
}
}
@@ -1,29 +0,0 @@
{
"input": "imported_015240.step",
"mode": "view",
"outputs": [
{
"path": "snapshots/iso.png",
"camera": "iso"
},
{
"path": "snapshots/iso_opposite.png",
"camera": {
"direction": [-1, 1, -0.8]
}
},
{
"path": "snapshots/top_ortho.png",
"camera": "top"
},
{
"path": "snapshots/front_ortho.png",
"camera": "front"
}
],
"render": {
"viewLabels": true,
"padding": 0.12,
"sizeProfile": "diagnostic"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 299 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 329 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

@@ -1,54 +0,0 @@
{
"schema_version": "1.0",
"request": "生成中心距120mm、大头孔36mm、小头孔20mm、厚14mm的发动机连杆,导出STEP和STL,后续可以修改参数",
"selected_backend": "build123d",
"runner_skill": "cad",
"confidence": "high",
"backend_scores": [
{
"backend": "build123d",
"score": 135,
"reasons": [
"+35 general STEP-first default",
"+35 general mechanical part with direct parametric features",
"+25 machining favors STEP-first B-Rep",
"+35 editable STEP requested",
"+5 secondary mesh export is available"
]
},
{
"backend": "simplecadapi",
"score": 78,
"reasons": [
"+20 specialist mechanical baseline",
"+10 general OCP modeling is available",
"+18 OCP STEP geometry suits machining",
"+30 OCP STEP export requested"
]
},
{
"backend": "cadam",
"score": -73,
"reasons": [
"+10 printable CSG baseline",
"-25 mesh/CSG route is not preferred for machining",
"-70 no native editable STEP output",
"+12 print mesh requested"
]
}
],
"fallback_order": [
"simplecadapi",
"cadam"
],
"workflow_profiles": [],
"downstream_skills": [
"cad-viewer"
],
"requested_outputs": [
"step",
"stl"
],
"source_of_truth": "build123d Python generator",
"availability": null
}
@@ -1,24 +0,0 @@
"""Approximate long multi-collar shaft inferred from reference 001957.png."""
from shaft_common import cut_end_bore, cut_side_flat, export_horizontal, stepped_body
SEGMENTS = [
(10.0, 34.0), # reduced drive tip
(14.0, 218.0), # long shaft
(19.0, 18.0), # transition shoulder
(30.0, 4.0),
(25.0, 7.0),
(32.0, 5.0),
(25.0, 8.0),
(31.0, 5.0),
(23.0, 8.0),
(14.0, 30.0), # hollow output nose
]
def gen_step():
body, total = stepped_body(SEGMENTS)
body = cut_side_flat(body, diameter=10.0, z_start=27.0, length=7.0, flat_depth=1.4)
body = cut_end_bore(body, total, diameter=8.0, depth=18.0)
return export_horizontal(body, "shaft_001957_like")
@@ -1,126 +0,0 @@
"""Approximate long cylindrical pin with a shallow axial end recess."""
from math import atan2, degrees, hypot, sqrt
from build123d import Box, Cylinder, Location
from shaft_common import cut_end_bore, export_horizontal, stepped_body
OUTER_DIAMETER = 18.0
LENGTH = 120.0
RECESS_DIAMETER = 6.0
RECESS_DEPTH = 5.0
VIEWER_POCKET_CENTER = (50.72611906534796, 1.4055875192234604, 8.886497233823093)
VIEWER_POCKET_WIDTH = 2.0
VIEWER_POCKET_HEIGHT = 2.0
VIEWER_POCKET_DEPTH = 1.0
VIEWER_POCKET_OVERSHOOT = 0.2
CIRCULAR_POCKET_CENTER = (68.62703575804954, 0.06569140145571417, 8.989927422862593)
CIRCULAR_POCKET_NORMAL = (0.0, -0.156229, -0.987721)
CIRCULAR_POCKET_DIAMETER = 8.0
CIRCULAR_POCKET_DEPTH = 1.0
CIRCULAR_POCKET_OVERSHOOT = 0.2
COUNTERBORE_CENTER = (40.48928144002571, -7.833112445247494, 4.424155112072327)
COUNTERBORE_NORMAL = (0.000061, -0.039505, -0.999219)
COUNTERBORE_HOLE_DIAMETER = 3.0
COUNTERBORE_DIAMETER = 6.0
COUNTERBORE_DEPTH = 2.0
COUNTERBORE_FACE_SELECTOR = {
"reference_id": "f1",
"face_index": 164,
"row_index": 0,
}
COUNTERBORE_OVERSHOOT = 0.2
COUNTERBORE_THROUGH_OVERSHOOT = 2.0
def cut_viewer_rectangular_pocket(body):
x_pos, y_pos, z_pos = VIEWER_POCKET_CENTER
radial_length = hypot(y_pos, z_pos)
normal_y = y_pos / radial_length
normal_z = z_pos / radial_length
rotation_x = degrees(atan2(-normal_y, normal_z))
tool_depth = VIEWER_POCKET_DEPTH + VIEWER_POCKET_OVERSHOOT
tool_center_offset = (VIEWER_POCKET_OVERSHOOT - VIEWER_POCKET_DEPTH) / 2.0
tool_center = (
x_pos,
y_pos + normal_y * tool_center_offset,
z_pos + normal_z * tool_center_offset,
)
tool = Location(tool_center, (rotation_x, 0.0, 0.0)) * Box(
VIEWER_POCKET_WIDTH,
VIEWER_POCKET_HEIGHT,
tool_depth,
)
return body - tool
def cut_viewer_circular_pocket(body):
x_pos, y_pos, z_pos = CIRCULAR_POCKET_CENTER
normal_x, normal_y, normal_z = CIRCULAR_POCKET_NORMAL
normal_length = sqrt(normal_x**2 + normal_y**2 + normal_z**2)
normal_y /= normal_length
normal_z /= normal_length
rotation_x = degrees(atan2(-normal_y, normal_z))
tool_depth = CIRCULAR_POCKET_DEPTH + CIRCULAR_POCKET_OVERSHOOT
tool_center_offset = (CIRCULAR_POCKET_DEPTH - CIRCULAR_POCKET_OVERSHOOT) / 2.0
tool_center = (
x_pos,
y_pos + normal_y * tool_center_offset,
z_pos + normal_z * tool_center_offset,
)
tool = Location(tool_center, (rotation_x, 0.0, 0.0)) * Cylinder(
CIRCULAR_POCKET_DIAMETER / 2.0,
tool_depth,
)
return body - tool
def cut_viewer_counterbore(body):
x_pos, y_pos, z_pos = COUNTERBORE_CENTER
normal_x, normal_y, normal_z = COUNTERBORE_NORMAL
normal_length = sqrt(normal_x**2 + normal_y**2 + normal_z**2)
normal_y /= normal_length
normal_z /= normal_length
rotation_x = degrees(atan2(-normal_y, normal_z))
through_depth = OUTER_DIAMETER + 4.0
through_tool_depth = through_depth + COUNTERBORE_THROUGH_OVERSHOOT
through_center_offset = (through_depth - COUNTERBORE_THROUGH_OVERSHOOT) / 2.0
through_center = (
x_pos,
y_pos + normal_y * through_center_offset,
z_pos + normal_z * through_center_offset,
)
through_tool = Location(through_center, (rotation_x, 0.0, 0.0)) * Cylinder(
COUNTERBORE_HOLE_DIAMETER / 2.0,
through_tool_depth,
)
counterbore_tool_depth = COUNTERBORE_DEPTH + COUNTERBORE_OVERSHOOT
counterbore_center_offset = (COUNTERBORE_DEPTH - COUNTERBORE_OVERSHOOT) / 2.0
counterbore_center = (
x_pos,
y_pos + normal_y * counterbore_center_offset,
z_pos + normal_z * counterbore_center_offset,
)
counterbore_tool = Location(counterbore_center, (rotation_x, 0.0, 0.0)) * Cylinder(
COUNTERBORE_DIAMETER / 2.0,
counterbore_tool_depth,
)
return body - through_tool - counterbore_tool
def gen_step():
body, total = stepped_body([(OUTER_DIAMETER, LENGTH)])
body = cut_end_bore(body, total, RECESS_DIAMETER, RECESS_DEPTH)
result = export_horizontal(body, "pin_004910_like")
result = cut_viewer_rectangular_pocket(result)
result = cut_viewer_circular_pocket(result)
result = cut_viewer_counterbore(result)
result.label = "pin_004910_like"
return result

Some files were not shown because too many files have changed in this diff Show More