cosplay: Touhou/Houjuu Nue #4

Open
aniva wants to merge 189 commits from touhou/houjuu-nue into main
3 changed files with 39 additions and 21 deletions
Showing only changes of commit 0cc6100d0e - Show all commits

View File

@ -65,8 +65,6 @@ class Parameters(Model):
shoulder_joint=MJ.ShoulderJoint(
height=100.0,
),
elbow_joint=MJ.ElbowJoint(),
wrist_joint=MJ.ElbowJoint(),
elbow_height=110.0,
))

View File

@ -261,18 +261,22 @@ class Beam:
plane.moveTo(-dx, 0).tagPlane("conn0")
return result
def beam(self) -> Cq.Assembly:
def generate(self, flip: bool = False) -> Cq.Assembly:
beam = (
Cq.Workplane('XZ')
.box(self.spine_length, self.spine_thickness, self.spine_height)
)
h = self.spine_height / 2 + self.foot_height
tag_p, tag_n = "top", "bot"
if flip:
tag_p, tag_n = tag_n, tag_p
result = (
Cq.Assembly()
.add(beam, name="beam")
.add(self.foot(), name="top",
.add(self.foot(), name=tag_p,
loc=Cq.Location((0, h, 0)))
.add(self.foot(), name="bot",
.add(self.foot(), name=tag_n,
loc=Cq.Location((0, -h, 0), (1, 0, 0), 180))
)
return result
@ -301,7 +305,7 @@ class DiskJoint(Model):
#disk_thickness_gap: float = 0.1
# Spring angle at 0 degrees of movement
spring_angle_at_0: float = 30.0
spring_angle_at_0: float = 60.0
spring_slot_offset: float = 15.0
wall_inset: float = 2.0
@ -493,6 +497,7 @@ class DiskJoint(Model):
disk: str,
angle: float = 0.0,
) -> Cq.Assembly:
assert 0 <= angle <= self.movement_angle
deflection = angle - self.neutral_movement_angle
spring_name = disk.replace("/", "__Z") + "_spring"
(
@ -541,7 +546,7 @@ class DiskJoint(Model):
return result.solve()
@dataclass
@dataclass(kw_only=True)
class ElbowJoint:
"""
Creates the elbow and wrist joints.
@ -576,6 +581,9 @@ class ElbowJoint:
material: Material = Material.RESIN_TRANSPERENT
# If true, flip the top and bottom tags
flip: bool = False
def __post_init__(self):
assert self.child_arm_radius > self.disk_joint.radius_housing
assert self.parent_arm_radius > self.disk_joint.radius_housing
@ -605,7 +613,7 @@ class ElbowJoint:
flip_x = Cq.Location((0, 0, 0), (1, 0, 0), 180)
flip_z = Cq.Location((0, 0, 0), (0, 0, 1), 180)
result = (
self.child_beam.beam()
self.child_beam.generate(flip=self.flip)
.add(self.disk_joint.disk(), name="disk",
loc=flip_x * flip_z * Cq.Location((-self.child_arm_radius, 0, -dz), (0, 0, 1), angle))
#.constrain("disk", "Fixed")
@ -641,7 +649,7 @@ class ElbowJoint:
-self.disk_joint.tongue_span / 2
)
result = (
self.parent_beam.beam()
self.parent_beam.generate(flip=self.flip)
.add(housing, name="housing",
loc=axial_offset * housing_loc)
.add(connector, name="connector",

View File

@ -11,10 +11,10 @@ from nhf import Material, Role
from nhf.build import Model, target, assembly
from nhf.parts.box import box_with_centre_holes, MountingBox, Hole
from nhf.parts.joints import HirthJoint
from nhf.touhou.houjuu_nue.joints import ShoulderJoint, ElbowJoint
from nhf.touhou.houjuu_nue.joints import ShoulderJoint, ElbowJoint, DiskJoint
import nhf.utils
@dataclass
@dataclass(kw_only=True)
class WingProfile(Model):
name: str = "wing"
@ -34,7 +34,12 @@ class WingProfile(Model):
s1_thickness: float = 25.0
elbow_joint: ElbowJoint = field(default_factory=lambda: ElbowJoint())
elbow_joint: ElbowJoint = field(default_factory=lambda: ElbowJoint(
disk_joint=DiskJoint(
movement_angle=55,
),
flip=False,
))
elbow_height: float = 100
elbow_x: float = 240
elbow_y: float = 30
@ -43,7 +48,12 @@ class WingProfile(Model):
s2_thickness: float = 25.0
wrist_joint: ElbowJoint = field(default_factory=lambda: ElbowJoint())
wrist_joint: ElbowJoint = field(default_factory=lambda: ElbowJoint(
disk_joint=DiskJoint(
movement_angle=45,
),
flip=True,
))
wrist_height: float = 70
# Bottom point of the wrist
wrist_x: float = 400
@ -548,6 +558,8 @@ class WingProfile(Model):
parts: Optional[list[str]] = None,
angle_elbow_wrist: float = 0.0,
) -> Cq.Assembly():
assert not self.elbow_joint.flip
assert self.wrist_joint.flip
if parts is None:
parts = ["s0", "shoulder", "s1", "elbow", "s2", "wrist", "s3"]
result = (
@ -601,20 +613,20 @@ class WingProfile(Model):
# Mounted backwards to bend in other direction
(
result
.constrain("s2/wrist_top?conn0", "wrist/parent_upper/bot?conn0", "Plane")
.constrain("s2/wrist_top?conn1", "wrist/parent_upper/bot?conn1", "Plane")
.constrain("s2/wrist_bot?conn0", "wrist/parent_upper/top?conn0", "Plane")
.constrain("s2/wrist_bot?conn1", "wrist/parent_upper/top?conn1", "Plane")
.constrain("s2/wrist_top?conn0", "wrist/parent_upper/top?conn0", "Plane")
.constrain("s2/wrist_top?conn1", "wrist/parent_upper/top?conn1", "Plane")
.constrain("s2/wrist_bot?conn0", "wrist/parent_upper/bot?conn0", "Plane")
.constrain("s2/wrist_bot?conn1", "wrist/parent_upper/bot?conn1", "Plane")
)
if "s3" in parts:
result.add(self.assembly_s3(), name="s3")
if "s3" in parts and "wrist" in parts:
(
result
.constrain("s3/wrist_top?conn0", "wrist/child/bot?conn0", "Plane")
.constrain("s3/wrist_top?conn1", "wrist/child/bot?conn1", "Plane")
.constrain("s3/wrist_bot?conn0", "wrist/child/top?conn0", "Plane")
.constrain("s3/wrist_bot?conn1", "wrist/child/top?conn1", "Plane")
.constrain("s3/wrist_top?conn0", "wrist/child/top?conn0", "Plane")
.constrain("s3/wrist_top?conn1", "wrist/child/top?conn1", "Plane")
.constrain("s3/wrist_bot?conn0", "wrist/child/bot?conn0", "Plane")
.constrain("s3/wrist_bot?conn1", "wrist/child/bot?conn1", "Plane")
)
if len(parts) > 1:
result.solve()