import math from typing import Optional from dataclasses import dataclass import cadquery as Cq from nhf import Item, Role @dataclass(frozen=True) class TorsionSpring(Item): """ A torsion spring with abridged geometry (since sweep is slow) """ # Outer radius radius: float = 12.0 height: float = 20.0 thickness: float = 2.0 # Angle (in degrees) between the two legs at neutral position angle_neutral: float = 90.0 tail_length: float = 25.0 right_handed: bool = False torsion_rate: Optional[float] = None @property def name(self) -> str: return f"TorsionSpring-{int(self.radius)}-{int(self.height)}" @property def radius_inner(self) -> float: return self.radius - self.thickness def torque_at(self, theta: float) -> float: return self.torsion_rate * theta def generate(self, deflection: float = 0) -> Cq.Workplane: omega = self.angle_neutral + deflection omega = -omega if self.right_handed else omega base = ( Cq.Workplane('XY') .cylinder(height=self.height, radius=self.radius, centered=(True, True, False)) ) base.faces(">Z").tag("top") base.faces("