Files
cadSet/text-to-cad/models/robots/tom/v2/parts/v2_variant_common.py
T
2026-07-22 19:38:36 +08:00

143 lines
4.7 KiB
Python

from __future__ import annotations
from contextlib import contextmanager
import copy
import importlib.util
import math
import os
import sys
from pathlib import Path
import build123d
PARTS_DIR = Path(__file__).resolve().parent
V2_DIR = PARTS_DIR.parent
TOM_DIR = V2_DIR.parent
def _env_float(name: str, default: float) -> float:
raw = os.environ.get(name)
if raw is None:
return default
try:
return float(raw)
except ValueError as exc:
raise ValueError(f"{name} must be a floating point number, got {raw!r}") from exc
ALUMINUM_5052_SHEET_THICKNESS_MM = _env_float(
"TOM_V2_ALUMINUM_5052_SHEET_THICKNESS_MM",
25.4 * 0.063,
)
ALUMINUM_5052_YIELD_MPA = _env_float("TOM_V2_ALUMINUM_5052_YIELD_MPA", 193.0)
PRINTABLE_EFFECTIVE_STRENGTH_MPA = _env_float(
"TOM_V2_PRINTABLE_EFFECTIVE_STRENGTH_MPA",
21.449805890625,
)
PRINTABLE_BENDING_STRENGTH_MATCH_THICKNESS_MM = (
ALUMINUM_5052_SHEET_THICKNESS_MM
* math.sqrt(ALUMINUM_5052_YIELD_MPA / PRINTABLE_EFFECTIVE_STRENGTH_MPA)
)
PRINTABLE_EQUIVALENT_THICKNESS_MM = float(
os.environ.get(
"TOM_V2_PRINTABLE_THICKNESS_MM",
f"{PRINTABLE_BENDING_STRENGTH_MATCH_THICKNESS_MM:.9f}",
)
)
PRINTABLE_COLOR = build123d.Color(0.72, 0.74, 0.72, 1.0)
def _module_path(module_name: str) -> Path:
return PARTS_DIR / f"{module_name}.py"
@contextmanager
def loaded_v2_module(
module_name: str,
*,
sheet_thickness_mm: float | None = None,
case_span_centering_offset_mm: float | None = None,
link_bracket_height_mm: float | None = None,
):
old_env = os.environ.get("TOM_V2_SHEET_THICKNESS_MM")
old_case_offset_env = os.environ.get("TOM_V2_CASE_SPAN_CENTERING_OFFSET_MM")
old_link_height_env = os.environ.get("TOM_V2_LINK_BRACKET_OVERALL_HEIGHT_MM")
if sheet_thickness_mm is None:
os.environ.pop("TOM_V2_SHEET_THICKNESS_MM", None)
else:
os.environ["TOM_V2_SHEET_THICKNESS_MM"] = f"{sheet_thickness_mm:.9f}"
if case_span_centering_offset_mm is None:
os.environ.pop("TOM_V2_CASE_SPAN_CENTERING_OFFSET_MM", None)
else:
os.environ["TOM_V2_CASE_SPAN_CENTERING_OFFSET_MM"] = (
f"{case_span_centering_offset_mm:.9f}"
)
if link_bracket_height_mm is None:
os.environ.pop("TOM_V2_LINK_BRACKET_OVERALL_HEIGHT_MM", None)
else:
os.environ["TOM_V2_LINK_BRACKET_OVERALL_HEIGHT_MM"] = (
f"{link_bracket_height_mm:.9f}"
)
stale_modules = {module_name}
if module_name == "link_bracket":
stale_modules.add("link_common")
previous_modules = {name: sys.modules.get(name) for name in stale_modules}
for name in stale_modules:
sys.modules.pop(name, None)
old_sys_path = list(sys.path)
for path in (TOM_DIR, V2_DIR, PARTS_DIR):
if str(path) not in sys.path:
sys.path.insert(0, str(path))
module_file = _module_path(module_name)
synthetic_name = (
f"_tom_v2_variant_{module_name}_"
f"{abs(hash((module_file, sheet_thickness_mm, case_span_centering_offset_mm, link_bracket_height_mm)))}"
)
spec = importlib.util.spec_from_file_location(synthetic_name, module_file)
if spec is None or spec.loader is None:
raise RuntimeError(f"Unable to load {module_file}")
module = importlib.util.module_from_spec(spec)
try:
sys.modules[module_name] = module
sys.modules[synthetic_name] = module
spec.loader.exec_module(module)
yield module
finally:
sys.path[:] = old_sys_path
sys.modules.pop(synthetic_name, None)
for name in stale_modules:
sys.modules.pop(name, None)
previous = previous_modules[name]
if previous is not None:
sys.modules[name] = previous
if old_env is None:
os.environ.pop("TOM_V2_SHEET_THICKNESS_MM", None)
else:
os.environ["TOM_V2_SHEET_THICKNESS_MM"] = old_env
if old_case_offset_env is None:
os.environ.pop("TOM_V2_CASE_SPAN_CENTERING_OFFSET_MM", None)
else:
os.environ["TOM_V2_CASE_SPAN_CENTERING_OFFSET_MM"] = old_case_offset_env
if old_link_height_env is None:
os.environ.pop("TOM_V2_LINK_BRACKET_OVERALL_HEIGHT_MM", None)
else:
os.environ["TOM_V2_LINK_BRACKET_OVERALL_HEIGHT_MM"] = old_link_height_env
def mirror_y(shape: build123d.Shape) -> build123d.Shape:
mirrored = copy.deepcopy(shape)
mirrored = mirrored.mirror(build123d.Plane.XZ)
return mirrored
def finish_part(shape: build123d.Shape, label: str, *, printable: bool = False) -> build123d.Shape:
shape.label = label
if printable:
shape.color = PRINTABLE_COLOR
return shape