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(
radius=25.0,
radius_inner=20.0,
radius_inner=15.0,
tooth_height=7.0,
base_height=5.0,
n_tooth=24,

View File

@ -6,7 +6,7 @@ from nhf import Material, Role
from nhf.build import Model, target, assembly
from nhf.parts.springs import TorsionSpring
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
TOL = 1e-6
@ -37,16 +37,18 @@ class ShoulderJoint(Model):
# 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
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_width: float = 30.0
parent_lip_thickness: float = 5.0
parent_lip_ext: float = 40.0
parent_lip_guard_height: float = 8.0
parent_root_wall_thickness: float = 25.4 / 16
# Measured from centre of axle
child_lip_length: float = 45.0
@ -68,7 +70,6 @@ class ShoulderJoint(Model):
def parent(self, top: bool = False) -> Cq.Assembly:
joint = self.torsion_joint
# 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_ext > joint.radius_track
@ -77,24 +78,25 @@ class ShoulderJoint(Model):
self.parent_lip_ext,
self.parent_lip_width,
self.parent_lip_guard_height)
.located(Cq.Location((0, -self.parent_lip_width/2 , dz)))
.cut(Cq.Solid.makeCylinder(joint.radius_track, self.parent_lip_guard_height + dz))
.located(Cq.Location((0, -self.parent_lip_width/2 , 0)))
.cut(Cq.Solid.makeCylinder(joint.radius_track, self.parent_lip_guard_height))
)
lip = box_with_centre_holes(
length=self.parent_lip_length - dz,
lip = MountingBox(
length=self.parent_lip_length,
width=self.parent_lip_width,
height=self.parent_lip_thickness,
hole_loc=[
self.height / 2 - dz - x
for x in self.parent_conn_hole_pos
thickness=self.parent_lip_thickness,
holes=[
Hole(x=self.height / 2 - x, y=y)
for x, y in self.parent_conn_hole_pos
],
hole_diam=self.parent_conn_hole_diam,
generate_side_tags=False,
)
# Flip so the lip's holes point to -X
loc_axis = Cq.Location((0,0,0), (0, 1, 0), -90)
# so they point to +X
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
@ -103,7 +105,7 @@ class ShoulderJoint(Model):
.add(joint.track(), name="track",
loc=Cq.Location((0, 0, 0), (0, 0, 1), rot))
.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

View File

@ -21,7 +21,7 @@ class WingProfile(Model):
base_joint: HirthJoint = field(default_factory=lambda: HirthJoint(
radius=25.0,
radius_inner=20.0,
radius_inner=15.0,
tooth_height=7.0,
base_height=5,
n_tooth=24,
@ -38,7 +38,7 @@ class WingProfile(Model):
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_y: float = 160.0
shoulder_mid_x: float = -105.0
@ -160,26 +160,42 @@ class WingProfile(Model):
)
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)
def profile_s0(self) -> Cq.Sketch:
tip_x = self.shoulder_tip_x
tip_y = self.shoulder_tip_y
mid_x = self.shoulder_mid_x
mid_y = self.shoulder_mid_y
sw = self.shoulder_width
sketch = (
Cq.Sketch()
self.outer_profile_s0()
.segment((-self.base_width, 0), (0, 0))
.spline([
(0, 0),
(-30.0, 80.0),
(tip_x, tip_y)
])
.segment(
(tip_x, tip_y),
(tip_x, tip_y - self.shoulder_width),
(tip_x, tip_y - sw),
)
.segment(
(tip_x, tip_y - self.shoulder_width),
(tip_x, tip_y - sw),
(mid_x, mid_y),
)
.segment(
@ -191,21 +207,12 @@ class WingProfile(Model):
return sketch
def outer_shell_s0(self) -> Cq.Workplane:
tip_x = self.shoulder_tip_x
tip_y = self.shoulder_tip_y
t = self.panel_thickness
edge = Cq.Edge.makeSpline([
Cq.Vector(x, y, 0)
for x,y in [
(0, 0),
(-30.0, 80.0),
(tip_x, tip_y)
]
])
profile = Cq.Wire.assembleEdges(self.outer_profile_s0().edges().vals())
result = (
Cq.Workplane('XZ')
.rect(t, self.root_height + t*2, centered=(False, False))
.sweep(edge)
.sweep(profile)
)
plane = result.copyWorkplane(Cq.Workplane('XZ'))
plane.moveTo(0, 0).tagPlane("bot")
@ -219,15 +226,15 @@ class WingProfile(Model):
"""
holes = [
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 [
Hole(x=x, tag=f"conn_top{i}"),
Hole(x=-x, tag=f"conn_bot{i}"),
Hole(x=x, y=y, tag=f"conn_top{i}"),
Hole(x=-x, y=y, tag=f"conn_bot{i}"),
]
]
return MountingBox(
length=self.shoulder_joint.height,
width=self.shoulder_width,
width=self.shoulder_joint.parent_lip_width,
thickness=self.spacer_thickness,
holes=holes,
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:
base_dx = -(self.base_width - self.base_plate_width) / 2
base_dy = self.base_joint.joint_height
axle_dist = self.shoulder_joint.parent_lip_ext
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),
]
result = nhf.utils.extrude_with_markers(
@ -284,9 +293,12 @@ class WingProfile(Model):
.addS(self.surface_s0(top=True), name="bot",
material=self.mat_panel, role=self.role_panel)
.addS(self.surface_s0(top=False), name="top",
material=self.mat_panel, role=self.role_panel)
.constrain("bot@faces@>Z", "top@faces@<Z", "Point",
param=self.shoulder_joint.height)
material=self.mat_panel, role=self.role_panel,
loc=Cq.Location((0, 0, self.root_height + self.panel_thickness)))
.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",
material=self.mat_panel, role=self.role_panel)
.constrain("bot?corner", "outer_shell?bot", "Plane", param=0)
@ -647,7 +659,9 @@ class WingProfile(Model):
(
result
.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_bot1", f"shoulder/parent_{tag_bot}/lip?conn1", "Plane")
)
if "s1" in parts:
result.add(self.assembly_s1(), name="s1")