sheet_bend 的一个文件
This commit is contained in:
@@ -355,6 +355,111 @@ class ThreadSpec:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class BendLeg:
|
||||||
|
"""One straight wing of a bent sheet-metal chain (runtime-neutral).
|
||||||
|
|
||||||
|
``leg_mm`` is the straight mid-plane distance from the previous fold vertex
|
||||||
|
to the fold vertex leaving this wing (the unfolded chord length between the
|
||||||
|
two surrounding fold vertices). When the wing has a following wing,
|
||||||
|
``bend_angle_deg`` is the required *interior* angle between the two wings
|
||||||
|
(0 < angle < 180, 90 = a right-angle bend), ``inner_radius_mm`` the inner
|
||||||
|
bend-surface fillet radius (>= 0; the outer radius is always
|
||||||
|
``inner_radius_mm + thickness_mm``) and ``side`` the fold direction
|
||||||
|
(+1 / -1). A trailing wing carries no fold; stray fold fields on the last
|
||||||
|
wing are ignored for tolerance.
|
||||||
|
"""
|
||||||
|
|
||||||
|
leg_mm: float
|
||||||
|
bend_angle_deg: float | None = None
|
||||||
|
inner_radius_mm: float = 0.0
|
||||||
|
side: int = 1
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class BendSpec:
|
||||||
|
"""Runtime-neutral definition of a sheet-metal bend (``bend_add``).
|
||||||
|
|
||||||
|
The part is described by its mid-plane centreline: ``chain`` lists the
|
||||||
|
straight wings joined by equal-thickness bend corners. ``thickness_mm``
|
||||||
|
and ``width_mm`` are the sheet thickness and the full length along the fold
|
||||||
|
(width) axis. ``frame.origin_mm`` anchors the start of the first wing's
|
||||||
|
mid-plane path, ``frame.x_dir`` is the fold/width axis and
|
||||||
|
``frame.normal`` is the mid-plane normal of the first wing; the first wing
|
||||||
|
extends along ``normal x x_dir``.
|
||||||
|
|
||||||
|
The spec deliberately contains no OCC planes or shapes. The adapter turns
|
||||||
|
this definition into a bent solid keeping source-contract parsing separate
|
||||||
|
from B-rep work (same pattern as :class:`ThreadSpec`).
|
||||||
|
"""
|
||||||
|
|
||||||
|
thickness_mm: float
|
||||||
|
width_mm: float
|
||||||
|
frame: PlaneSpec
|
||||||
|
chain: tuple[BendLeg, ...]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_feature(cls, params: dict[str, Any]) -> "BendSpec":
|
||||||
|
try:
|
||||||
|
thickness = float(params.get("thickness_mm") or 0.0)
|
||||||
|
width = float(params.get("width_mm") or 0.0)
|
||||||
|
except (TypeError, ValueError) as error:
|
||||||
|
raise ValueError("bend thickness/width must be numeric") from error
|
||||||
|
if thickness <= 0 or width <= 0:
|
||||||
|
raise ValueError("bend requires positive thickness_mm and width_mm in millimetres")
|
||||||
|
raw_chain = params.get("chain")
|
||||||
|
if not isinstance(raw_chain, (list, tuple)) or not raw_chain:
|
||||||
|
raise ValueError("bend requires a non-empty chain of wing segments")
|
||||||
|
chain: list[BendLeg] = []
|
||||||
|
for index, raw_leg in enumerate(raw_chain):
|
||||||
|
if not isinstance(raw_leg, dict):
|
||||||
|
raise ValueError(f"bend chain[{index}] must be an object with leg_mm")
|
||||||
|
try:
|
||||||
|
leg = float(raw_leg.get("leg_mm") or 0.0)
|
||||||
|
except (TypeError, ValueError) as error:
|
||||||
|
raise ValueError(f"bend chain[{index}].leg_mm must be numeric") from error
|
||||||
|
if leg <= 0:
|
||||||
|
raise ValueError(f"bend chain[{index}].leg_mm must be positive")
|
||||||
|
bend_angle: float | None = None
|
||||||
|
if index < len(raw_chain) - 1:
|
||||||
|
raw_angle = raw_leg.get("bend_angle_deg")
|
||||||
|
if raw_angle is None:
|
||||||
|
raise ValueError(
|
||||||
|
f"bend chain[{index}] needs bend_angle_deg for the fold towards the next wing"
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
bend_angle = float(raw_angle)
|
||||||
|
except (TypeError, ValueError) as error:
|
||||||
|
raise ValueError(f"bend chain[{index}].bend_angle_deg must be numeric") from error
|
||||||
|
if not 0 < bend_angle < 180:
|
||||||
|
raise ValueError("bend interior angle must be between 0 and 180 degrees")
|
||||||
|
radius = float(raw_leg.get("inner_radius_mm") or 0.0)
|
||||||
|
raw_side = raw_leg.get("side")
|
||||||
|
side = 1 if raw_side is None else int(raw_side)
|
||||||
|
if radius < 0:
|
||||||
|
raise ValueError(f"bend chain[{index}].inner_radius_mm must be non-negative")
|
||||||
|
if side not in (1, -1):
|
||||||
|
raise ValueError(f"bend chain[{index}].side must be +1 or -1")
|
||||||
|
chain.append(BendLeg(
|
||||||
|
leg_mm=leg,
|
||||||
|
bend_angle_deg=bend_angle,
|
||||||
|
inner_radius_mm=radius,
|
||||||
|
side=side,
|
||||||
|
))
|
||||||
|
raw_frame = params.get("frame")
|
||||||
|
if isinstance(raw_frame, dict):
|
||||||
|
frame = PlaneSpec.from_mapping(raw_frame)
|
||||||
|
else:
|
||||||
|
# frame 缺省:首翼沿世界 +X 延伸、厚度沿 +Y、折痕沿 +Z(贴 XY 平面)。
|
||||||
|
frame = PlaneSpec(
|
||||||
|
origin_mm=(0.0, 0.0, 0.0),
|
||||||
|
x_dir=(0.0, 0.0, 1.0),
|
||||||
|
y_dir=(1.0, 0.0, 0.0),
|
||||||
|
normal=(0.0, 1.0, 0.0),
|
||||||
|
)
|
||||||
|
return cls(thickness_mm=thickness, width_mm=width, frame=frame, chain=tuple(chain))
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class RuntimeDiagnostic:
|
class RuntimeDiagnostic:
|
||||||
code: str
|
code: str
|
||||||
|
|||||||
Reference in New Issue
Block a user