cosplay: Touhou/Houjuu Nue #4
|
@ -14,10 +14,15 @@ class Role(Flag):
|
||||||
Describes the role of a part
|
Describes the role of a part
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Externally supplied object
|
||||||
|
FIXTURE = auto()
|
||||||
|
# Parent and child sides of joints
|
||||||
PARENT = auto()
|
PARENT = auto()
|
||||||
CHILD = auto()
|
CHILD = auto()
|
||||||
CASING = auto()
|
CASING = auto()
|
||||||
|
# Springs, cushions
|
||||||
DAMPING = auto()
|
DAMPING = auto()
|
||||||
|
# Main structural support
|
||||||
STRUCTURE = auto()
|
STRUCTURE = auto()
|
||||||
DECORATION = auto()
|
DECORATION = auto()
|
||||||
ELECTRONIC = auto()
|
ELECTRONIC = auto()
|
||||||
|
@ -38,8 +43,10 @@ class Role(Flag):
|
||||||
head = next(iter(self))
|
head = next(iter(self))
|
||||||
return ROLE_COLOR_MAP[head]
|
return ROLE_COLOR_MAP[head]
|
||||||
|
|
||||||
|
|
||||||
# Maps roles to their colours
|
# Maps roles to their colours
|
||||||
ROLE_COLOR_MAP = {
|
ROLE_COLOR_MAP = {
|
||||||
|
Role.FIXTURE: _color('black', 0.2),
|
||||||
Role.PARENT: _color('blue4', 0.6),
|
Role.PARENT: _color('blue4', 0.6),
|
||||||
Role.CASING: _color('dodgerblue3', 0.6),
|
Role.CASING: _color('dodgerblue3', 0.6),
|
||||||
Role.CHILD: _color('darkorange2', 0.6),
|
Role.CHILD: _color('darkorange2', 0.6),
|
||||||
|
|
|
@ -5,7 +5,46 @@ from nhf import Material, Role
|
||||||
from nhf.build import Model, TargetKind, target, assembly
|
from nhf.build import Model, TargetKind, target, assembly
|
||||||
import nhf.utils
|
import nhf.utils
|
||||||
|
|
||||||
@dataclass
|
@dataclass(frozen=True, kw_only=True)
|
||||||
|
class Mannequin:
|
||||||
|
"""
|
||||||
|
A mannequin for calibration
|
||||||
|
"""
|
||||||
|
|
||||||
|
shoulder_width: float = 400
|
||||||
|
shoulder_to_waist: float = 440
|
||||||
|
waist_width: float = 250
|
||||||
|
head_height: float = 220.0
|
||||||
|
neck_height: float = 105.0
|
||||||
|
neck_diam: float = 140
|
||||||
|
head_diam: float = 210
|
||||||
|
torso_thickness: float = 150
|
||||||
|
|
||||||
|
def generate(self) -> Cq.Workplane:
|
||||||
|
head_neck = (
|
||||||
|
Cq.Workplane("XY")
|
||||||
|
.cylinder(
|
||||||
|
radius=self.neck_diam/2,
|
||||||
|
height=self.neck_height,
|
||||||
|
centered=(True, True, False))
|
||||||
|
.faces(">Z")
|
||||||
|
.workplane()
|
||||||
|
.cylinder(
|
||||||
|
radius=self.head_diam/2,
|
||||||
|
height=self.head_height,
|
||||||
|
combine=True, centered=(True, True, False))
|
||||||
|
)
|
||||||
|
result = (
|
||||||
|
Cq.Workplane("XY")
|
||||||
|
.rect(self.waist_width, self.torso_thickness)
|
||||||
|
.workplane(offset=self.shoulder_to_waist)
|
||||||
|
.rect(self.shoulder_width, self.torso_thickness)
|
||||||
|
.loft(combine=True)
|
||||||
|
.union(head_neck.translate((0, 0, self.shoulder_to_waist)))
|
||||||
|
)
|
||||||
|
return result.translate((0, self.torso_thickness / 2, 0))
|
||||||
|
|
||||||
|
@dataclass(kw_only=True)
|
||||||
class Harness(Model):
|
class Harness(Model):
|
||||||
thickness: float = 25.4 / 8
|
thickness: float = 25.4 / 8
|
||||||
width: float = 200.0
|
width: float = 200.0
|
||||||
|
@ -42,6 +81,8 @@ class Harness(Model):
|
||||||
hs_joint_axis_cbore_diam: float = 20
|
hs_joint_axis_cbore_diam: float = 20
|
||||||
hs_joint_axis_cbore_depth: float = 3
|
hs_joint_axis_cbore_depth: float = 3
|
||||||
|
|
||||||
|
mannequin: Mannequin = Mannequin()
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
super().__init__(name="harness")
|
super().__init__(name="harness")
|
||||||
|
|
||||||
|
@ -164,22 +205,27 @@ class Harness(Model):
|
||||||
@assembly()
|
@assembly()
|
||||||
def assembly(self) -> Cq.Assembly:
|
def assembly(self) -> Cq.Assembly:
|
||||||
harness = self.surface()
|
harness = self.surface()
|
||||||
|
mannequin_z = self.mannequin.shoulder_to_waist * 0.6
|
||||||
result = (
|
result = (
|
||||||
Cq.Assembly()
|
Cq.Assembly()
|
||||||
.addS(harness, name="base",
|
.addS(
|
||||||
|
harness, name="base",
|
||||||
material=Material.WOOD_BIRCH,
|
material=Material.WOOD_BIRCH,
|
||||||
role=Role.STRUCTURE)
|
role=Role.STRUCTURE)
|
||||||
.constrain("base", "Fixed")
|
.constrain("base", "Fixed")
|
||||||
|
.addS(
|
||||||
|
self.mannequin.generate(),
|
||||||
|
name="mannequin",
|
||||||
|
role=Role.FIXTURE,
|
||||||
|
loc=Cq.Location((0, -self.thickness, -mannequin_z), (0, 0, 1), 180))
|
||||||
|
.constrain("mannequin", "Fixed")
|
||||||
)
|
)
|
||||||
for name in ["l1", "l2", "l3", "r1", "r2", "r3"]:
|
for name in ["l1", "l2", "l3", "r1", "r2", "r3"]:
|
||||||
j = self.hs_joint_parent()
|
j = self.hs_joint_parent()
|
||||||
(
|
result.addS(
|
||||||
result
|
j, name=name,
|
||||||
.addS(j, name=name,
|
|
||||||
role=Role.PARENT,
|
role=Role.PARENT,
|
||||||
material=Material.PLASTIC_PLA)
|
material=Material.PLASTIC_PLA)
|
||||||
#.constrain("base?mount", f"{name}?base", "Axis")
|
|
||||||
)
|
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
result.constrain(f"base?{name}_{i}", f"{name}?h{i}", "Point")
|
result.constrain(f"base?{name}_{i}", f"{name}?h{i}", "Point")
|
||||||
result.solve()
|
result.solve()
|
||||||
|
|
Loading…
Reference in New Issue