cosplay: Touhou/Houjuu Nue #1

Closed
aniva wants to merge 37 commits from touhou/houjuu-nue into main
4 changed files with 155 additions and 19 deletions
Showing only changes of commit eb8a48fe77 - Show all commits

View File

@ -0,0 +1 @@
from nhf.materials import Material

18
nhf/materials.py Normal file
View File

@ -0,0 +1,18 @@
"""
A catalog of material properties
"""
from enum import Enum
import cadquery as Cq
def _color(name: str, alpha: float) -> Cq.Color:
r, g, b, _ = Cq.Color(name).toTuple()
return Cq.Color(r, g, b, alpha)
class Material(Enum):
WOOD_BIRCH = 0.8, _color('bisque', 0.9)
PLASTIC_PLA = 0.5, _color('azure3', 0.6)
def __init__(self, density: float, color: Cq.Color):
self.density = density
self.color = color

View File

@ -2,6 +2,7 @@ from dataclasses import dataclass
import unittest import unittest
import cadquery as Cq import cadquery as Cq
import nhf.joints import nhf.joints
from nhf import Material
@dataclass(frozen=True) @dataclass(frozen=True)
class Parameters: class Parameters:
@ -11,8 +12,39 @@ class Parameters:
""" """
panel_thickness: float = 25.4 / 16 panel_thickness: float = 25.4 / 16
# Harness
harness_thickness: float = 25.4 / 8
harness_width = 300
harness_height = 400
harness_fillet = 10
harness_wing_base_pos = [
("r1", 70, 150),
("l1", -70, 150),
("r2", 100, 0),
("l2", -100, 0),
("r3", 70, -150),
("l3", -70, -150),
]
# Holes drilled onto harness for attachment with HS joint
harness_to_wing_base_hole_diam = 6
# Wing root properties # Wing root properties
""" """
The Houjuu-Scarlett joint mechanism at the base of the wing
"""
hs_joint_base_width = 85
hs_joint_base_thickness = 10
hs_joint_ring_thickness = 5
hs_joint_tooth_height = 10
hs_joint_radius = 30
hs_joint_radius_inner = 20
hs_joint_corner_fillet = 5
hs_joint_corner_cbore_diam = 12
hs_joint_corner_cbore_depth = 12
hs_joint_corner_inset = 15
"""
Radius of the mounting mechanism of the wing root. This is constrained by Radius of the mounting mechanism of the wing root. This is constrained by
the size of the harness. the size of the harness.
""" """
@ -26,26 +58,77 @@ class Parameters:
wing_r2_height = 100 wing_r2_height = 100
wing_r3_height = 100 wing_r3_height = 100
"""
The Houjuu-Scarlett joint mechanism at the base of the wing
"""
hs_joint_base_width = 85
hs_joint_base_thickness = 10
hs_joint_ring_thickness = 10
hs_joint_tooth_height = 10
hs_joint_radius = 30
hs_joint_radius_inner = 20
hs_joint_corner_fillet = 5
hs_joint_corner_cbore_diam = 12
hs_joint_corner_cbore_depth = 12
hs_joint_corner_diam = 15
hs_joint_corner_inset = 15
def print_geometries(self): def print_geometries(self):
return [ return [
self.hs_joint_parent() self.hs_joint_parent()
] ]
def harness_profile(self) -> Cq.Sketch:
"""
Creates the harness shape
"""
w, h = self.harness_width / 2, self.harness_height / 2
sketch = (
Cq.Sketch()
.polygon([
(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()
.fillet(self.harness_fillet)
)
for tag, x, y in self.harness_wing_base_pos:
conn = [(px + x, py + y) for px, py in self.hs_joint_harness_conn()]
sketch = (
sketch
.push(conn)
.tag(tag)
.circle(self.harness_to_wing_base_hole_diam / 2, mode='s')
.reset()
)
return sketch
def harness(self) -> Cq.Shape:
"""
Creates the harness shape
"""
result = (
Cq.Workplane('XZ')
.placeSketch(self.harness_profile())
.extrude(self.harness_thickness)
)
result.faces(">Y").tag("mount")
plane = result.faces(">Y").workplane()
for tag, x, y in self.harness_wing_base_pos:
conn = [(px + x, py + y) for px, py in self.hs_joint_harness_conn()]
for i, (px, py) in enumerate(conn):
(
plane
.moveTo(px, py)
.circle(1, forConstruction='True')
.edges()
.tag(f"{tag}_{i}")
)
return result
def hs_joint_harness_conn(self) -> list[tuple[int, int]]:
"""
Generates a set of points corresponding to the connectorss
"""
dx = self.hs_joint_base_width / 2 - self.hs_joint_corner_inset
return [
(dx, dx),
(dx, -dx),
(-dx, -dx),
(-dx, dx),
]
def hs_joint_parent(self): def hs_joint_parent(self):
""" """
Parent part of the Houjuu-Scarlett joint, which is composed of a Hirth Parent part of the Houjuu-Scarlett joint, which is composed of a Hirth
@ -56,7 +139,6 @@ class Parameters:
radius_inner=self.hs_joint_radius_inner, radius_inner=self.hs_joint_radius_inner,
tooth_height=self.hs_joint_tooth_height, tooth_height=self.hs_joint_tooth_height,
base_height=self.hs_joint_ring_thickness) base_height=self.hs_joint_ring_thickness)
hole_rect_width = self.hs_joint_base_width - 2 * self.hs_joint_corner_inset
hirth = ( hirth = (
hirth hirth
.faces("<Z") .faces("<Z")
@ -69,6 +151,7 @@ class Parameters:
.hole(5) .hole(5)
.val() .val()
) )
conn = self.hs_joint_harness_conn()
result = ( result = (
Cq.Workplane('XY') Cq.Workplane('XY')
.box( .box(
@ -80,17 +163,29 @@ class Parameters:
.fillet(self.hs_joint_corner_fillet) .fillet(self.hs_joint_corner_fillet)
.faces(">Z") .faces(">Z")
.workplane() .workplane()
.rect(hole_rect_width, hole_rect_width, forConstruction=True) .pushPoints(conn)
.vertices()
.cboreHole( .cboreHole(
diameter=self.hs_joint_corner_diam, diameter=self.harness_to_wing_base_hole_diam,
cboreDiameter=self.hs_joint_corner_cbore_diam, cboreDiameter=self.hs_joint_corner_cbore_diam,
cboreDepth=self.hs_joint_corner_cbore_depth) cboreDepth=self.hs_joint_corner_cbore_depth)
)
plane = result.faces(">Z").workplane(offset=-self.hs_joint_base_thickness)
for i, (px, py) in enumerate(conn):
(
plane
.moveTo(px, py)
.circle(1, forConstruction='True')
.edges()
.tag(f"h{i}")
)
result = (
result
.faces(">Z") .faces(">Z")
.workplane() .workplane()
.union(hirth.move((0, 0, self.hs_joint_base_thickness)), tol=0.1) .union(hirth.move(Cq.Location((0, 0, self.hs_joint_base_thickness))), tol=0.1)
.clean() .clean()
) )
result.faces("<Z").tag("base")
return result return result
@ -152,3 +247,22 @@ class Parameters:
) )
return result return result
def harness_assembly(self):
harness = self.harness()
result = (
Cq.Assembly()
.add(harness, name="harness", color=Material.WOOD_BIRCH.color)
.constrain("harness", "Fixed")
)
for name in ["l1", "l2", "l3", "r1", "r2", "r3"]:
j = self.hs_joint_parent()
(
result
.add(j, name=f"hs_{name}p", color=Material.PLASTIC_PLA.color)
#.constrain(f"harness?{name}", f"hs_{name}p?mate", "Point")
.constrain("harness?mount", f"hs_{name}p?base", "Axis")
)
for i in range(4):
result.constrain(f"harness?{name}_{i}", f"hs_{name}p?h{i}", "Point")
result.solve()
return result

View File

@ -9,6 +9,9 @@ class Test(unittest.TestCase):
def test_wings(self): def test_wings(self):
p = M.Parameters() p = M.Parameters()
p.wing_r1() p.wing_r1()
def test_harness(self):
p = M.Parameters()
p.harness_assembly()
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()