cosplay: Touhou/Houjuu Nue #4

Open
aniva wants to merge 189 commits from touhou/houjuu-nue into main
3 changed files with 61 additions and 45 deletions
Showing only changes of commit 572c39d31f - Show all commits

View File

@ -25,7 +25,7 @@ class Harness(Model):
hs_hirth_joint: HirthJoint = field(default_factory=lambda: HirthJoint( hs_hirth_joint: HirthJoint = field(default_factory=lambda: HirthJoint(
radius=25.0, radius=25.0,
radius_inner=20.0, radius_inner=15.0,
tooth_height=7.0, tooth_height=7.0,
base_height=5.0, base_height=5.0,
n_tooth=24, n_tooth=24,

View File

@ -6,7 +6,7 @@ from nhf import Material, Role
from nhf.build import Model, target, assembly from nhf.build import Model, target, assembly
from nhf.parts.springs import TorsionSpring from nhf.parts.springs import TorsionSpring
from nhf.parts.joints import TorsionJoint from nhf.parts.joints import TorsionJoint
from nhf.parts.box import box_with_centre_holes from nhf.parts.box import Hole, MountingBox, box_with_centre_holes
import nhf.utils import nhf.utils
TOL = 1e-6 TOL = 1e-6
@ -37,16 +37,18 @@ class ShoulderJoint(Model):
# On the parent side, drill vertical holes # On the parent side, drill vertical holes
parent_conn_hole_diam: float = 4.0 parent_conn_hole_diam: float = 6.0
# Position of the holes relative # Position of the holes relative
parent_conn_hole_pos: list[float] = field(default_factory=lambda: [15]) parent_conn_hole_pos: list[Tuple[float, float]] = field(default_factory=lambda: [
(15, 8),
(15, -8),
])
parent_lip_length: float = 25.0 parent_lip_length: float = 25.0
parent_lip_width: float = 30.0 parent_lip_width: float = 30.0
parent_lip_thickness: float = 5.0 parent_lip_thickness: float = 5.0
parent_lip_ext: float = 40.0 parent_lip_ext: float = 40.0
parent_lip_guard_height: float = 8.0 parent_lip_guard_height: float = 8.0
parent_root_wall_thickness: float = 25.4 / 16
# Measured from centre of axle # Measured from centre of axle
child_lip_length: float = 45.0 child_lip_length: float = 45.0
@ -68,7 +70,6 @@ class ShoulderJoint(Model):
def parent(self, top: bool = False) -> Cq.Assembly: def parent(self, top: bool = False) -> Cq.Assembly:
joint = self.torsion_joint joint = self.torsion_joint
# Thickness of the lip connecting this joint to the wing root # Thickness of the lip connecting this joint to the wing root
dz = self.parent_root_wall_thickness
assert self.parent_lip_width <= joint.radius_track * 2 assert self.parent_lip_width <= joint.radius_track * 2
assert self.parent_lip_ext > joint.radius_track assert self.parent_lip_ext > joint.radius_track
@ -77,24 +78,25 @@ class ShoulderJoint(Model):
self.parent_lip_ext, self.parent_lip_ext,
self.parent_lip_width, self.parent_lip_width,
self.parent_lip_guard_height) self.parent_lip_guard_height)
.located(Cq.Location((0, -self.parent_lip_width/2 , dz))) .located(Cq.Location((0, -self.parent_lip_width/2 , 0)))
.cut(Cq.Solid.makeCylinder(joint.radius_track, self.parent_lip_guard_height + dz)) .cut(Cq.Solid.makeCylinder(joint.radius_track, self.parent_lip_guard_height))
) )
lip = box_with_centre_holes( lip = MountingBox(
length=self.parent_lip_length - dz, length=self.parent_lip_length,
width=self.parent_lip_width, width=self.parent_lip_width,
height=self.parent_lip_thickness, thickness=self.parent_lip_thickness,
hole_loc=[ holes=[
self.height / 2 - dz - x Hole(x=self.height / 2 - x, y=y)
for x in self.parent_conn_hole_pos for x, y in self.parent_conn_hole_pos
], ],
hole_diam=self.parent_conn_hole_diam, hole_diam=self.parent_conn_hole_diam,
generate_side_tags=False,
) )
# Flip so the lip's holes point to -X # Flip so the lip's holes point to -X
loc_axis = Cq.Location((0,0,0), (0, 1, 0), -90) loc_axis = Cq.Location((0,0,0), (0, 1, 0), -90)
# so they point to +X # so they point to +X
loc_dir = Cq.Location((0,0,0), (0, 0, 1), 180) loc_dir = Cq.Location((0,0,0), (0, 0, 1), 180)
loc_pos = Cq.Location((self.parent_lip_ext - self.parent_lip_thickness, 0, dz)) loc_pos = Cq.Location((self.parent_lip_ext - self.parent_lip_thickness, 0, 0))
rot = -self.axis_rotate_top if top else self.axis_rotate_bot rot = -self.axis_rotate_top if top else self.axis_rotate_bot
@ -103,7 +105,7 @@ class ShoulderJoint(Model):
.add(joint.track(), name="track", .add(joint.track(), name="track",
loc=Cq.Location((0, 0, 0), (0, 0, 1), rot)) loc=Cq.Location((0, 0, 0), (0, 0, 1), rot))
.add(lip_guard, name="lip_guard") .add(lip_guard, name="lip_guard")
.add(lip, name="lip", loc=loc_pos * loc_dir * loc_axis) .add(lip.generate(), name="lip", loc=loc_pos * loc_dir * loc_axis)
) )
return result return result

View File

@ -21,7 +21,7 @@ class WingProfile(Model):
base_joint: HirthJoint = field(default_factory=lambda: HirthJoint( base_joint: HirthJoint = field(default_factory=lambda: HirthJoint(
radius=25.0, radius=25.0,
radius_inner=20.0, radius_inner=15.0,
tooth_height=7.0, tooth_height=7.0,
base_height=5, base_height=5,
n_tooth=24, n_tooth=24,
@ -38,7 +38,7 @@ class WingProfile(Model):
shoulder_joint: ShoulderJoint = field(default_factory=lambda: ShoulderJoint( shoulder_joint: ShoulderJoint = field(default_factory=lambda: ShoulderJoint(
)) ))
shoulder_width: float = 30.0 shoulder_width: float = 36.0
shoulder_tip_x: float = -200.0 shoulder_tip_x: float = -200.0
shoulder_tip_y: float = 160.0 shoulder_tip_y: float = 160.0
shoulder_mid_x: float = -105.0 shoulder_mid_x: float = -105.0
@ -160,26 +160,42 @@ class WingProfile(Model):
) )
return result return result
def outer_profile_s0(self) -> Cq.Sketch:
"""
The outer boundary of s0, used to produce the curved panel and the
top/bottom slots
"""
tip_x = self.shoulder_tip_x
tip_y = self.shoulder_tip_y
return (
Cq.Sketch()
.spline([
(0, 0),
(-30.0, 80.0),
(tip_x, tip_y)
])
#.segment(
# (tip_x, tip_y),
# (tip_x - 10, tip_y),
#)
)
@target(name="profile-s0", kind=TargetKind.DXF) @target(name="profile-s0", kind=TargetKind.DXF)
def profile_s0(self) -> Cq.Sketch: def profile_s0(self) -> Cq.Sketch:
tip_x = self.shoulder_tip_x tip_x = self.shoulder_tip_x
tip_y = self.shoulder_tip_y tip_y = self.shoulder_tip_y
mid_x = self.shoulder_mid_x mid_x = self.shoulder_mid_x
mid_y = self.shoulder_mid_y mid_y = self.shoulder_mid_y
sw = self.shoulder_width
sketch = ( sketch = (
Cq.Sketch() self.outer_profile_s0()
.segment((-self.base_width, 0), (0, 0)) .segment((-self.base_width, 0), (0, 0))
.spline([
(0, 0),
(-30.0, 80.0),
(tip_x, tip_y)
])
.segment( .segment(
(tip_x, tip_y), (tip_x, tip_y),
(tip_x, tip_y - self.shoulder_width), (tip_x, tip_y - sw),
) )
.segment( .segment(
(tip_x, tip_y - self.shoulder_width), (tip_x, tip_y - sw),
(mid_x, mid_y), (mid_x, mid_y),
) )
.segment( .segment(
@ -191,21 +207,12 @@ class WingProfile(Model):
return sketch return sketch
def outer_shell_s0(self) -> Cq.Workplane: def outer_shell_s0(self) -> Cq.Workplane:
tip_x = self.shoulder_tip_x
tip_y = self.shoulder_tip_y
t = self.panel_thickness t = self.panel_thickness
edge = Cq.Edge.makeSpline([ profile = Cq.Wire.assembleEdges(self.outer_profile_s0().edges().vals())
Cq.Vector(x, y, 0)
for x,y in [
(0, 0),
(-30.0, 80.0),
(tip_x, tip_y)
]
])
result = ( result = (
Cq.Workplane('XZ') Cq.Workplane('XZ')
.rect(t, self.root_height + t*2, centered=(False, False)) .rect(t, self.root_height + t*2, centered=(False, False))
.sweep(edge) .sweep(profile)
) )
plane = result.copyWorkplane(Cq.Workplane('XZ')) plane = result.copyWorkplane(Cq.Workplane('XZ'))
plane.moveTo(0, 0).tagPlane("bot") plane.moveTo(0, 0).tagPlane("bot")
@ -219,15 +226,15 @@ class WingProfile(Model):
""" """
holes = [ holes = [
hole hole
for i, x in enumerate(self.shoulder_joint.parent_conn_hole_pos) for i, (x, y) in enumerate(self.shoulder_joint.parent_conn_hole_pos)
for hole in [ for hole in [
Hole(x=x, tag=f"conn_top{i}"), Hole(x=x, y=y, tag=f"conn_top{i}"),
Hole(x=-x, tag=f"conn_bot{i}"), Hole(x=-x, y=y, tag=f"conn_bot{i}"),
] ]
] ]
return MountingBox( return MountingBox(
length=self.shoulder_joint.height, length=self.shoulder_joint.height,
width=self.shoulder_width, width=self.shoulder_joint.parent_lip_width,
thickness=self.spacer_thickness, thickness=self.spacer_thickness,
holes=holes, holes=holes,
hole_diam=self.shoulder_joint.parent_conn_hole_diam, hole_diam=self.shoulder_joint.parent_conn_hole_diam,
@ -263,8 +270,10 @@ class WingProfile(Model):
def surface_s0(self, top: bool = False) -> Cq.Workplane: def surface_s0(self, top: bool = False) -> Cq.Workplane:
base_dx = -(self.base_width - self.base_plate_width) / 2 base_dx = -(self.base_width - self.base_plate_width) / 2
base_dy = self.base_joint.joint_height base_dy = self.base_joint.joint_height
axle_dist = self.shoulder_joint.parent_lip_ext
tags = [ tags = [
("shoulder", (self.shoulder_tip_x, self.shoulder_tip_y - self.shoulder_width), 0), ("shoulder", (self.shoulder_tip_x + axle_dist, self.shoulder_tip_y - self.shoulder_width), 0),
("base", (base_dx, base_dy), 90), ("base", (base_dx, base_dy), 90),
] ]
result = nhf.utils.extrude_with_markers( result = nhf.utils.extrude_with_markers(
@ -284,9 +293,12 @@ class WingProfile(Model):
.addS(self.surface_s0(top=True), name="bot", .addS(self.surface_s0(top=True), name="bot",
material=self.mat_panel, role=self.role_panel) material=self.mat_panel, role=self.role_panel)
.addS(self.surface_s0(top=False), name="top", .addS(self.surface_s0(top=False), name="top",
material=self.mat_panel, role=self.role_panel) material=self.mat_panel, role=self.role_panel,
.constrain("bot@faces@>Z", "top@faces@<Z", "Point", loc=Cq.Location((0, 0, self.root_height + self.panel_thickness)))
param=self.shoulder_joint.height) .constrain("bot", "Fixed")
.constrain("top", "Fixed")
#.constrain("bot@faces@>Z", "top@faces@<Z", "Point",
# param=self.shoulder_joint.height)
.addS(self.outer_shell_s0(), name="outer_shell", .addS(self.outer_shell_s0(), name="outer_shell",
material=self.mat_panel, role=self.role_panel) material=self.mat_panel, role=self.role_panel)
.constrain("bot?corner", "outer_shell?bot", "Plane", param=0) .constrain("bot?corner", "outer_shell?bot", "Plane", param=0)
@ -647,7 +659,9 @@ class WingProfile(Model):
( (
result result
.constrain(f"s0/shoulder?conn_top0", f"shoulder/parent_{tag_top}/lip?conn0", "Plane") .constrain(f"s0/shoulder?conn_top0", f"shoulder/parent_{tag_top}/lip?conn0", "Plane")
.constrain(f"s0/shoulder?conn_top1", f"shoulder/parent_{tag_top}/lip?conn1", "Plane")
.constrain(f"s0/shoulder?conn_bot0", f"shoulder/parent_{tag_bot}/lip?conn0", "Plane") .constrain(f"s0/shoulder?conn_bot0", f"shoulder/parent_{tag_bot}/lip?conn0", "Plane")
.constrain(f"s0/shoulder?conn_bot1", f"shoulder/parent_{tag_bot}/lip?conn1", "Plane")
) )
if "s1" in parts: if "s1" in parts:
result.add(self.assembly_s1(), name="s1") result.add(self.assembly_s1(), name="s1")