cosplay: Touhou/Houjuu Nue #4
|
@ -36,6 +36,10 @@ class HirthJoint:
|
|||
def total_height(self):
|
||||
return self.base_height + self.tooth_height
|
||||
|
||||
@property
|
||||
def joint_height(self):
|
||||
return 2 * self.base_height + self.tooth_height
|
||||
|
||||
|
||||
def generate(self, is_mated=False, tol=0.01):
|
||||
"""
|
||||
|
|
|
@ -49,14 +49,6 @@ class Parameters(Model):
|
|||
# Harness
|
||||
harness: MH.Harness = field(default_factory=lambda: MH.Harness())
|
||||
|
||||
hs_hirth_joint: HirthJoint = field(default_factory=lambda: HirthJoint(
|
||||
radius=30,
|
||||
radius_inner=20,
|
||||
tooth_height=10,
|
||||
base_height=5,
|
||||
n_tooth=24
|
||||
))
|
||||
|
||||
wing_r1: MW.WingR = field(default_factory=lambda: MW.WingR(name="r1"))
|
||||
wing_r2: MW.WingR = field(default_factory=lambda: MW.WingR(name="r2"))
|
||||
wing_r3: MW.WingR = field(default_factory=lambda: MW.WingR(name="r3"))
|
||||
|
@ -77,10 +69,19 @@ class Parameters(Model):
|
|||
|
||||
def __post_init__(self):
|
||||
super().__init__(name="houjuu-nue")
|
||||
self.harness.hs_hirth_joint = self.hs_hirth_joint
|
||||
self.wing_r1.base_joint = self.hs_hirth_joint
|
||||
self.wing_r2.base_joint = self.hs_hirth_joint
|
||||
self.wing_r3.base_joint = self.hs_hirth_joint
|
||||
self.wing_r1.base_joint = self.harness.hs_hirth_joint
|
||||
self.wing_r2.base_joint = self.harness.hs_hirth_joint
|
||||
self.wing_r3.base_joint = self.harness.hs_hirth_joint
|
||||
self.wing_l1.base_joint = self.harness.hs_hirth_joint
|
||||
self.wing_l2.base_joint = self.harness.hs_hirth_joint
|
||||
self.wing_l3.base_joint = self.harness.hs_hirth_joint
|
||||
|
||||
assert self.wing_r1.hs_joint_axis_diam == self.harness.hs_joint_axis_diam
|
||||
assert self.wing_r2.hs_joint_axis_diam == self.harness.hs_joint_axis_diam
|
||||
assert self.wing_r3.hs_joint_axis_diam == self.harness.hs_joint_axis_diam
|
||||
assert self.wing_l1.hs_joint_axis_diam == self.harness.hs_joint_axis_diam
|
||||
assert self.wing_l2.hs_joint_axis_diam == self.harness.hs_joint_axis_diam
|
||||
assert self.wing_l3.hs_joint_axis_diam == self.harness.hs_joint_axis_diam
|
||||
|
||||
@submodel(name="harness")
|
||||
def submodel_harness(self) -> Model:
|
||||
|
@ -120,12 +121,12 @@ class Parameters(Model):
|
|||
.add(self.wing_l2.assembly(parts), name="wing_l2")
|
||||
.add(self.wing_l3.assembly(parts), name="wing_l3")
|
||||
)
|
||||
self.hs_hirth_joint.add_constraints(result, "harness/r1", "wing_r1/s0/hs", offset=11)
|
||||
self.hs_hirth_joint.add_constraints(result, "harness/r2", "wing_r2/s0/hs", offset=10)
|
||||
self.hs_hirth_joint.add_constraints(result, "harness/r3", "wing_r3/s0/hs", offset=9)
|
||||
self.hs_hirth_joint.add_constraints(result, "harness/l1", "wing_l1/s0/hs", offset=6)
|
||||
self.hs_hirth_joint.add_constraints(result, "harness/l2", "wing_l2/s0/hs", offset=7)
|
||||
self.hs_hirth_joint.add_constraints(result, "harness/l3", "wing_l3/s0/hs", offset=8)
|
||||
for tag, offset in [("r1", 10), ("r2", 8), ("r3", 6), ("l1", 6), ("l2", 7), ("l3", 8)]:
|
||||
self.harness.hs_hirth_joint.add_constraints(
|
||||
result,
|
||||
f"harness/{tag}",
|
||||
f"wing_{tag}/s0/hs",
|
||||
offset=offset)
|
||||
return result.solve()
|
||||
|
||||
@submodel(name="trident")
|
||||
|
|
|
@ -8,26 +8,27 @@ import nhf.utils
|
|||
@dataclass
|
||||
class Harness(Model):
|
||||
thickness: float = 25.4 / 8
|
||||
width: float = 300.0
|
||||
height: float = 400.0
|
||||
width: float = 200.0
|
||||
height: float = 300.0
|
||||
fillet: float = 10.0
|
||||
|
||||
wing_base_pos: list[tuple[str, float, float]] = field(default_factory=lambda: [
|
||||
("r1", 70, 150),
|
||||
("l1", -70, 150),
|
||||
("r2", 100, 0),
|
||||
("l2", -100, 0),
|
||||
("r3", 70, -150),
|
||||
("l3", -70, -150),
|
||||
("r1", 55, 90),
|
||||
("l1", -55, 90),
|
||||
("r2", 60, 0),
|
||||
("l2", -60, 0),
|
||||
("r3", 55, -90),
|
||||
("l3", -55, -90),
|
||||
])
|
||||
# Holes drilled onto harness for attachment with HS joint
|
||||
harness_to_root_conn_diam: float = 6
|
||||
|
||||
hs_hirth_joint: HirthJoint = field(default_factory=lambda: HirthJoint(
|
||||
radius=30,
|
||||
radius_inner=20,
|
||||
tooth_height=10,
|
||||
base_height=5
|
||||
radius=25.0,
|
||||
radius_inner=20.0,
|
||||
tooth_height=7.0,
|
||||
base_height=5.0,
|
||||
n_tooth=24,
|
||||
))
|
||||
|
||||
hs_joint_base_width: float = 85
|
||||
|
@ -37,7 +38,7 @@ class Harness(Model):
|
|||
hs_joint_corner_cbore_depth: float = 2
|
||||
hs_joint_corner_inset: float = 12
|
||||
|
||||
hs_joint_axis_diam: float = 12
|
||||
hs_joint_axis_diam: float = 12.0
|
||||
hs_joint_axis_cbore_diam: float = 20
|
||||
hs_joint_axis_cbore_depth: float = 3
|
||||
|
||||
|
@ -53,12 +54,16 @@ class Harness(Model):
|
|||
sketch = (
|
||||
Cq.Sketch()
|
||||
.polygon([
|
||||
(0.7 * w, h),
|
||||
(w, 0),
|
||||
(0.7 * w, -h),
|
||||
(0.7 * -w, -h),
|
||||
(-w, 0),
|
||||
(0.7 * -w, h),
|
||||
(w, h),
|
||||
(w, -h),
|
||||
(-w, -h),
|
||||
(-w, h),
|
||||
#(0.7 * w, h),
|
||||
#(w, 0),
|
||||
#(0.7 * w, -h),
|
||||
#(0.7 * -w, -h),
|
||||
#(-w, 0),
|
||||
#(0.7 * -w, h),
|
||||
])
|
||||
#.rect(self.harness_width, self.harness_height)
|
||||
.vertices()
|
||||
|
|
|
@ -20,12 +20,18 @@ class WingProfile(Model):
|
|||
name: str = "wing"
|
||||
|
||||
base_joint: HirthJoint = field(default_factory=lambda: HirthJoint(
|
||||
radius=30.0,
|
||||
radius=25.0,
|
||||
radius_inner=20.0,
|
||||
tooth_height=7.0,
|
||||
base_height=5,
|
||||
n_tooth=24,
|
||||
))
|
||||
root_width: float = 80.0
|
||||
hs_joint_corner_dx: float = 30.0
|
||||
base_width: float = 80.0
|
||||
hs_joint_corner_dx: float = 17.0
|
||||
hs_joint_corner_dz: float = 24.0
|
||||
hs_joint_corner_hole_diam: float = 6.0
|
||||
hs_joint_axis_diam: float = 12.0
|
||||
base_plate_width: float = 50.0
|
||||
|
||||
panel_thickness: float = 25.4 / 16
|
||||
spacer_thickness: float = 25.4 / 8
|
||||
|
@ -36,6 +42,8 @@ class WingProfile(Model):
|
|||
shoulder_width: float = 30.0
|
||||
shoulder_tip_x: float = -200.0
|
||||
shoulder_tip_y: float = 160.0
|
||||
shoulder_mid_x: float = -105.0
|
||||
shoulder_mid_y: float = 75.0
|
||||
|
||||
s1_thickness: float = 25.0
|
||||
|
||||
|
@ -94,13 +102,64 @@ class WingProfile(Model):
|
|||
def shoulder_height(self) -> float:
|
||||
return self.shoulder_joint.height
|
||||
|
||||
@target(name="base-hs-joint")
|
||||
def base_hs_joint(self) -> Cq.Workplane:
|
||||
"""
|
||||
Parent part of the Houjuu-Scarlett joint, which is composed of a Hirth
|
||||
coupling, a cylindrical base, and a mounting base.
|
||||
"""
|
||||
hirth = self.base_joint.generate(is_mated=True)
|
||||
dy = self.hs_joint_corner_dx
|
||||
dx = self.hs_joint_corner_dz
|
||||
conn = [
|
||||
(-dx, -dy),
|
||||
(dx, -dy),
|
||||
(dx, dy),
|
||||
(-dx, dy),
|
||||
]
|
||||
result = (
|
||||
Cq.Workplane('XY')
|
||||
.box(
|
||||
self.root_height,
|
||||
self.base_plate_width,
|
||||
self.base_joint.base_height,
|
||||
centered=(True, True, False))
|
||||
#.translate((0, 0, -self.base_joint.base_height))
|
||||
#.edges("|Z")
|
||||
#.fillet(self.hs_joint_corner_fillet)
|
||||
.faces(">Z")
|
||||
.workplane()
|
||||
.pushPoints(conn)
|
||||
.hole(self.hs_joint_corner_hole_diam)
|
||||
)
|
||||
# Creates a plane parallel to the holes but shifted to the base
|
||||
plane = result.faces(">Z").workplane(offset=-self.base_joint.base_height)
|
||||
|
||||
for i, (px, py) in enumerate(conn):
|
||||
plane.moveTo(px, py).tagPlane(f"conn{i}")
|
||||
result = (
|
||||
result
|
||||
.faces(">Z")
|
||||
.workplane()
|
||||
.union(hirth, tol=0.1)
|
||||
.clean()
|
||||
)
|
||||
result = (
|
||||
result.faces("<Z")
|
||||
.workplane()
|
||||
.hole(self.hs_joint_axis_diam)
|
||||
)
|
||||
return result
|
||||
|
||||
@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
|
||||
sketch = (
|
||||
Cq.Sketch()
|
||||
.segment((-self.root_width, 0), (0, 0))
|
||||
.segment((-self.base_width, 0), (0, 0))
|
||||
.spline([
|
||||
(0, 0),
|
||||
(-30.0, 80.0),
|
||||
|
@ -108,16 +167,42 @@ class WingProfile(Model):
|
|||
])
|
||||
.segment(
|
||||
(tip_x, tip_y),
|
||||
(tip_x, tip_y - self.shoulder_width)
|
||||
(tip_x, tip_y - self.shoulder_width),
|
||||
)
|
||||
.segment(
|
||||
(tip_x, tip_y - self.shoulder_width),
|
||||
(-self.root_width, 0)
|
||||
(mid_x, mid_y),
|
||||
)
|
||||
.segment(
|
||||
(mid_x, mid_y),
|
||||
(-self.base_width, 0),
|
||||
)
|
||||
.assemble()
|
||||
)
|
||||
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)
|
||||
]
|
||||
])
|
||||
result = (
|
||||
Cq.Workplane('XZ')
|
||||
.rect(t, self.root_height + t*2, centered=(False, False))
|
||||
.sweep(edge)
|
||||
)
|
||||
plane = result.copyWorkplane(Cq.Workplane('XZ'))
|
||||
plane.moveTo(0, 0).tagPlane("bot")
|
||||
plane.moveTo(0, self.root_height + t*2).tagPlane("top")
|
||||
return result
|
||||
|
||||
@submodel(name="spacer-s0-shoulder")
|
||||
def spacer_s0_shoulder(self) -> MountingBox:
|
||||
"""
|
||||
|
@ -145,16 +230,20 @@ class WingProfile(Model):
|
|||
"""
|
||||
Should be cut
|
||||
"""
|
||||
dx = self.hs_joint_corner_dx
|
||||
assert self.base_plate_width < self.base_width
|
||||
assert self.hs_joint_corner_dx * 2 < self.base_width
|
||||
assert self.hs_joint_corner_dz * 2 < self.root_height
|
||||
dy = self.hs_joint_corner_dx
|
||||
dx = self.hs_joint_corner_dz
|
||||
holes = [
|
||||
Hole(x=-dx, y=-dx),
|
||||
Hole(x=dx, y=-dx),
|
||||
Hole(x=dx, y=dx),
|
||||
Hole(x=-dx, y=dx),
|
||||
Hole(x=-dx, y=-dy),
|
||||
Hole(x=dx, y=-dy),
|
||||
Hole(x=dx, y=dy),
|
||||
Hole(x=-dx, y=dy),
|
||||
]
|
||||
return MountingBox(
|
||||
length=self.root_height,
|
||||
width=self.root_width,
|
||||
width=self.base_plate_width,
|
||||
thickness=self.spacer_thickness,
|
||||
holes=holes,
|
||||
hole_diam=self.hs_joint_corner_hole_diam,
|
||||
|
@ -163,16 +252,21 @@ 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
|
||||
tags = [
|
||||
("shoulder", (self.shoulder_tip_x, self.shoulder_tip_y - self.shoulder_width), 0),
|
||||
("base", (0, 0), 90),
|
||||
("base", (base_dx, base_dy), 90),
|
||||
]
|
||||
return nhf.utils.extrude_with_markers(
|
||||
result = nhf.utils.extrude_with_markers(
|
||||
self.profile_s0(),
|
||||
self.panel_thickness,
|
||||
tags,
|
||||
reverse=not top,
|
||||
)
|
||||
h = self.panel_thickness if top else 0
|
||||
result.copyWorkplane(Cq.Workplane('XZ')).moveTo(0, h).tagPlane("corner")
|
||||
return result
|
||||
|
||||
@assembly()
|
||||
def assembly_s0(self) -> Cq.Assembly:
|
||||
|
@ -184,6 +278,10 @@ class WingProfile(Model):
|
|||
material=self.mat_panel, role=self.role_panel)
|
||||
.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)
|
||||
.constrain("top?corner", "outer_shell?top", "Plane", param=0)
|
||||
)
|
||||
for o, tag in [
|
||||
(self.spacer_s0_shoulder().generate(), "shoulder"),
|
||||
|
@ -201,11 +299,13 @@ class WingProfile(Model):
|
|||
.constrain(f"{tag}?{top_tag}", f"top?{tag}", "Plane")
|
||||
.constrain(f"{tag}?dir", f"top?{tag}_dir", "Axis")
|
||||
)
|
||||
hirth = self.base_joint.generate(is_mated=True)
|
||||
hs_joint = self.base_hs_joint()
|
||||
(
|
||||
result
|
||||
.addS(hirth, name="hs", role=Role.CHILD, material=self.mat_hs_joint)
|
||||
.constrain("hs@faces@<Z", "base?dir", "Plane")
|
||||
.addS(hs_joint, name="hs", role=Role.CHILD, material=self.mat_hs_joint)
|
||||
.constrain("hs?conn0", "base?conn0", "Plane", param=0)
|
||||
.constrain("hs?conn1", "base?conn1", "Plane", param=0)
|
||||
.constrain("hs?conn2", "base?conn2", "Plane", param=0)
|
||||
)
|
||||
return result.solve()
|
||||
|
||||
|
|
Loading…
Reference in New Issue