feat: Movement span on disk joint

This commit is contained in:
Leni Aniva 2024-07-11 08:42:13 -07:00
parent d8a62d3352
commit 2aeeaae061
Signed by: aniva
GPG Key ID: 4D9B1C8D10EA4C50
3 changed files with 73 additions and 15 deletions

View File

@ -15,6 +15,7 @@ class Role(Enum):
# Parent and child components in a load bearing joint
PARENT = _color('blue4', 0.6)
CASING = _color('dodgerblue3', 0.6)
CHILD = _color('darkorange2', 0.6)
DAMPING = _color('springgreen', 0.5)
STRUCTURE = _color('gray', 0.4)

View File

@ -1,4 +1,5 @@
from dataclasses import dataclass
from typing import Optional, Tuple
import cadquery as Cq
from nhf import Role
from nhf.build import Model, target
@ -25,8 +26,12 @@ class DiskJoint(Model):
spring_thickness: float = 1.3
spring_height: float = 6.5
spring_tail_length: float = 45.0
spring_angle: float = 90.0
spring_angle_shift: float = 0
# Spring angle at 0 degrees of movement
spring_angle: float = 30.0
# Angle at which the spring exerts no torque
spring_angle_neutral: float = 90.0
spring_angle_shift: float = 30
wall_inset: float = 2.0
# Angular span of movement
@ -55,15 +60,22 @@ class DiskJoint(Model):
)
@property
def total_thickness(self):
def neutral_movement_angle(self) -> Optional[float]:
a = self.spring_angle_neutral - self.spring_angle
if 0 <= a and a <= self.movement_angle:
return a
return None
@property
def total_thickness(self) -> float:
return self.housing_thickness * 2 + self.disk_thickness
@property
def opening_span(self):
def opening_span(self) -> float:
return self.movement_angle + self.tongue_span
@property
def housing_upper_carve_offset(self):
def housing_upper_carve_offset(self) -> float:
return self.housing_thickness + self.disk_thickness - self.spring_height
@property
@ -147,8 +159,7 @@ class DiskJoint(Model):
result = result.cut(
self
.wall()
.mirror("XY")
.located(Cq.Location((0, 0, self.housing_thickness + self.disk_thickness)))
.located(Cq.Location((0, 0, self.disk_thickness - self.wall_inset)))
#.rotate((0, 0, 0), (1, 0, 0), 180)
#.located(Cq.Location((0, 0, self.disk_thickness + self.housing_thickness)))
)
@ -165,7 +176,7 @@ class DiskJoint(Model):
width=self.spring_thickness,
height=self.housing_thickness
).located(Cq.Location((0, self.radius_spring_internal, 0))))
).rotate((0, 0, 0), (0, 0, 1), self.spring_angle - self.spring_angle_shift)
).rotate((0, 0, 0), (0, 0, 1), 180 + self.spring_angle - self.spring_angle_shift)
result = (
Cq.Workplane('XY')
.cylinder(
@ -192,7 +203,8 @@ class DiskJoint(Model):
result = result.union(tube)
wall = (
self.wall()
.rotate((0, 0, 0), (1, 0, 0), 180)
.rotate((0, 0, 0), (0, 0, 1), self.tongue_span)
.mirror("XY")
.located(Cq.Location((0, 0, self.disk_thickness + self.housing_thickness + self.wall_inset)))
)
result = (
@ -202,18 +214,47 @@ class DiskJoint(Model):
)
return result
def add_constraints(self,
assembly: Cq.Assembly,
housing_lower: str,
housing_upper: str,
disk: str,
angle: Tuple[float, float, float] = (0, 0, 0),
) -> Cq.Assembly:
"""
The angle supplied must be perpendicular to the disk normal.
"""
(
assembly
.constrain(f"{disk}?mate_bot", f"{housing_lower}?mate", "Plane")
.constrain(f"{disk}?mate_top", f"{housing_upper}?mate", "Plane")
.constrain(f"{housing_lower}?dir", f"{housing_upper}?dir", "Axis")
.constrain(f"{disk}?dir", "FixedRotation", angle)
)
def assembly(self) -> Cq.Assembly:
def assembly(self, angle: Optional[float] = 0) -> Cq.Assembly:
if angle is None:
angle = self.movement_angle
if angle is None:
angle = 0
else:
assert 0 <= angle <= self.movement_angle
result = (
Cq.Assembly()
.add(self.disk(), name="disk", color=Role.CHILD.color)
.add(self.housing_lower(), name="housing_lower", color=Role.PARENT.color)
.add(self.housing_upper(), name="housing_upper", color=Role.PARENT.color)
.constrain("disk?mate_bot", "housing_lower?mate", "Plane")
.constrain("disk?mate_top", "housing_upper?mate", "Plane")
.solve()
.add(self.housing_upper(), name="housing_upper", color=Role.CASING.color)
.constrain("housing_lower", "Fixed")
)
return result
self.add_constraints(
result,
housing_lower="housing_lower",
housing_upper="housing_upper",
disk="disk",
angle=(0, 0, angle),
)
return result.solve()
if __name__ == '__main__':
p = DiskJoint()

View File

@ -1,8 +1,24 @@
import unittest
import cadquery as Cq
import nhf.touhou.houjuu_nue as M
import nhf.touhou.houjuu_nue.parts as MP
from nhf.checks import pairwise_intersection
class TestDiskJoint(unittest.TestCase):
def test_collision_0(self):
j = MP.DiskJoint()
assembly = j.assembly(angle=0)
self.assertEqual(pairwise_intersection(assembly), [])
def test_collision_mid(self):
j = MP.DiskJoint()
assembly = j.assembly(angle=j.movement_angle / 2)
self.assertEqual(pairwise_intersection(assembly), [])
def test_collision_max(self):
j = MP.DiskJoint()
assembly = j.assembly(angle=j.movement_angle)
self.assertEqual(pairwise_intersection(assembly), [])
class Test(unittest.TestCase):
def test_hs_joint_parent(self):