first commit
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
"""Example 14: parameterized ball bearing standard assembly.
|
||||
|
||||
This example builds a small radial ball bearing through
|
||||
``scad.std.bearing.make_ball_bearing_rassembly`` and then keeps working inside
|
||||
that assembly by binding a demo shaft to the inner ring and a demo housing to
|
||||
the outer ring. The important bearing semantics are product-level, not just
|
||||
geometry: stable component ids expose the rings and balls, and the inner and
|
||||
outer rings are connected by a revolute constraint.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import simplecadapi as scad
|
||||
from simplecadapi import ql
|
||||
|
||||
|
||||
OUT_DIR = Path("examples/out/ball_bearing_608_demo")
|
||||
|
||||
BORE_DIAMETER = 8.0
|
||||
OUTER_DIAMETER = 22.0
|
||||
BEARING_WIDTH = 5.0
|
||||
BALL_DIAMETER = 3.0
|
||||
BALL_COUNT = 7
|
||||
RACEWAY_CLEARANCE = 0.05
|
||||
EDGE_CHAMFER = 0.08
|
||||
INNER_RING_ANGLE = 35.0
|
||||
|
||||
|
||||
def _axis_part(part_id: str, solid: scad.Solid, name: str) -> scad.Part:
|
||||
part = scad.make_part_rpart(part_id, solid, name=name)
|
||||
top_face = max(
|
||||
solid.get_faces(),
|
||||
key=lambda face: face.get_center().z if face.get_normal_at().z > 0.7 else -999.0,
|
||||
)
|
||||
axis = scad.make_face_connector_rconnector("axis", top_face)
|
||||
return scad.add_connector_rpart(part, axis)
|
||||
|
||||
|
||||
def _make_demo_shaft() -> scad.Part:
|
||||
shaft = scad.make_cylinder_rsolid(
|
||||
radius=BORE_DIAMETER / 2.0 - 0.2,
|
||||
height=BEARING_WIDTH + 4.0,
|
||||
bottom_face_center=(0.0, 0.0, -BEARING_WIDTH / 2.0 - 4.0),
|
||||
axis=(0.0, 0.0, 1.0),
|
||||
)
|
||||
shaft = scad.apply_tag(shaft, "role.demo_shaft")
|
||||
return _axis_part("demo_shaft", shaft, "Demo shaft bound to inner ring")
|
||||
|
||||
|
||||
def _make_demo_housing() -> scad.Part:
|
||||
housing_outer = scad.make_cylinder_rsolid(
|
||||
radius=OUTER_DIAMETER / 2.0 + 3.0,
|
||||
height=BEARING_WIDTH + 0.75,
|
||||
bottom_face_center=(0.0, 0.0, -BEARING_WIDTH / 2.0 - 0.75),
|
||||
axis=(0.0, 0.0, 1.0),
|
||||
)
|
||||
bearing_pocket = scad.make_cylinder_rsolid(
|
||||
radius=OUTER_DIAMETER / 2.0 + 0.25,
|
||||
height=BEARING_WIDTH + 3.5,
|
||||
bottom_face_center=(0.0, 0.0, -BEARING_WIDTH / 2.0 - 1.75),
|
||||
axis=(0.0, 0.0, 1.0),
|
||||
)
|
||||
housing = scad.cut_rsolid(
|
||||
housing_outer,
|
||||
bearing_pocket,
|
||||
skip_non_intersecting=False,
|
||||
)
|
||||
housing = scad.apply_tag(housing, "role.demo_housing")
|
||||
return _axis_part("demo_housing", housing, "Demo housing bound to outer ring")
|
||||
|
||||
|
||||
def build_ball_bearing_demo():
|
||||
with scad.GraphSession() as session:
|
||||
bearing = scad.std.bearing.make_ball_bearing_rassembly(
|
||||
BORE_DIAMETER,
|
||||
OUTER_DIAMETER,
|
||||
BEARING_WIDTH,
|
||||
BALL_DIAMETER,
|
||||
BALL_COUNT,
|
||||
RACEWAY_CLEARANCE,
|
||||
EDGE_CHAMFER,
|
||||
"ball_bearing_608_demo",
|
||||
INNER_RING_ANGLE,
|
||||
)
|
||||
meta = bearing.get_metadata("std.bearing.ball_bearing")
|
||||
|
||||
outer_ring = bearing.get_component("outer_ring").item.body
|
||||
inner_ring = bearing.get_component("inner_ring").item.body
|
||||
print(
|
||||
"bearing_core",
|
||||
f"components={len(bearing.component_ids())}",
|
||||
f"balls={meta['ball_count']}",
|
||||
f"constraint={meta['revolute_constraint_id']}",
|
||||
)
|
||||
print(
|
||||
"ring_geometry",
|
||||
f"outer_faces={len(ql.faces().resolve(outer_ring))}",
|
||||
f"inner_faces={len(ql.faces().resolve(inner_ring))}",
|
||||
f"outer_volume={outer_ring.get_volume():.2f}",
|
||||
f"inner_volume={inner_ring.get_volume():.2f}",
|
||||
)
|
||||
|
||||
bearing = scad.add_component_rassembly(
|
||||
bearing,
|
||||
_make_demo_shaft(),
|
||||
component_id="demo_shaft",
|
||||
placement=scad.identity_placement_rplacement(),
|
||||
)
|
||||
bearing = scad.add_component_rassembly(
|
||||
bearing,
|
||||
_make_demo_housing(),
|
||||
component_id="demo_housing",
|
||||
placement=scad.identity_placement_rplacement(),
|
||||
)
|
||||
bearing = scad.add_fixed_constraint_rassembly(
|
||||
bearing,
|
||||
"shaft_to_inner_ring",
|
||||
scad.make_connector_ref_rconnectorref("inner_ring", "axis"),
|
||||
scad.make_connector_ref_rconnectorref("demo_shaft", "axis"),
|
||||
)
|
||||
bearing = scad.add_fixed_constraint_rassembly(
|
||||
bearing,
|
||||
"housing_to_outer_ring",
|
||||
scad.make_connector_ref_rconnectorref("outer_ring", "axis"),
|
||||
scad.make_connector_ref_rconnectorref("demo_housing", "axis"),
|
||||
)
|
||||
bearing = scad.solve_assembly_constraints_rassembly(bearing)
|
||||
report = scad.inspect_assembly_constraints_rconstraintreport(bearing)
|
||||
preview = scad.make_compound_from_assembly_rcompound(bearing)
|
||||
model_json = scad.export_model_json(session)
|
||||
|
||||
return bearing, report, preview, model_json
|
||||
|
||||
|
||||
def main() -> None:
|
||||
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
assembly, report, preview, model_json = build_ball_bearing_demo()
|
||||
|
||||
model_path = OUT_DIR / "ball_bearing_608_demo.model.json"
|
||||
step_path = OUT_DIR / "ball_bearing_608_demo.step"
|
||||
fcstd_path = OUT_DIR / "ball_bearing_608_demo.FCStd"
|
||||
model_path.write_text(model_json, encoding="utf-8")
|
||||
scad.export_step(preview, str(step_path))
|
||||
|
||||
fcstd_status = str(fcstd_path)
|
||||
try:
|
||||
scad.translator.freecad_translator.translate_model_json_to_fcstd(model_json, str(fcstd_path.resolve()))
|
||||
except Exception as exc: # pragma: no cover - depends on local FreeCAD install
|
||||
fcstd_status = f"skipped ({exc.__class__.__name__})"
|
||||
|
||||
payload = json.loads(model_json)
|
||||
print("assembly", assembly.assembly_id)
|
||||
print("components", assembly.component_ids())
|
||||
print("constraints", assembly.constraint_ids())
|
||||
print("solved", report.solved)
|
||||
print("preview_solids", len(preview.get_solids()))
|
||||
print("preview_volume", round(preview.get_volume(), 2))
|
||||
print("graph_nodes", len(payload["graph"]["nodes"]))
|
||||
print("wrote", model_path)
|
||||
print("wrote", step_path)
|
||||
print("fcstd", fcstd_status)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user