cosplay: Touhou/Houjuu Nue #4
|
@ -14,10 +14,15 @@ class Role(Flag):
|
|||
Describes the role of a part
|
||||
"""
|
||||
|
||||
# Externally supplied object
|
||||
FIXTURE = auto()
|
||||
# Parent and child sides of joints
|
||||
PARENT = auto()
|
||||
CHILD = auto()
|
||||
CASING = auto()
|
||||
# Springs, cushions
|
||||
DAMPING = auto()
|
||||
# Main structural support
|
||||
STRUCTURE = auto()
|
||||
DECORATION = auto()
|
||||
ELECTRONIC = auto()
|
||||
|
@ -38,8 +43,10 @@ class Role(Flag):
|
|||
head = next(iter(self))
|
||||
return ROLE_COLOR_MAP[head]
|
||||
|
||||
|
||||
# Maps roles to their colours
|
||||
ROLE_COLOR_MAP = {
|
||||
Role.FIXTURE: _color('black', 0.2),
|
||||
Role.PARENT: _color('blue4', 0.6),
|
||||
Role.CASING: _color('dodgerblue3', 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
|
||||
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):
|
||||
thickness: float = 25.4 / 8
|
||||
width: float = 200.0
|
||||
|
@ -42,6 +81,8 @@ class Harness(Model):
|
|||
hs_joint_axis_cbore_diam: float = 20
|
||||
hs_joint_axis_cbore_depth: float = 3
|
||||
|
||||
mannequin: Mannequin = Mannequin()
|
||||
|
||||
def __post_init__(self):
|
||||
super().__init__(name="harness")
|
||||
|
||||
|
@ -164,22 +205,27 @@ class Harness(Model):
|
|||
@assembly()
|
||||
def assembly(self) -> Cq.Assembly:
|
||||
harness = self.surface()
|
||||
mannequin_z = self.mannequin.shoulder_to_waist * 0.6
|
||||
result = (
|
||||
Cq.Assembly()
|
||||
.addS(harness, name="base",
|
||||
.addS(
|
||||
harness, name="base",
|
||||
material=Material.WOOD_BIRCH,
|
||||
role=Role.STRUCTURE)
|
||||
.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"]:
|
||||
j = self.hs_joint_parent()
|
||||
(
|
||||
result
|
||||
.addS(j, name=name,
|
||||
result.addS(
|
||||
j, name=name,
|
||||
role=Role.PARENT,
|
||||
material=Material.PLASTIC_PLA)
|
||||
#.constrain("base?mount", f"{name}?base", "Axis")
|
||||
)
|
||||
for i in range(4):
|
||||
result.constrain(f"base?{name}_{i}", f"{name}?h{i}", "Point")
|
||||
result.solve()
|
||||
|
|
Loading…
Reference in New Issue