cosplay: Touhou/Houjuu Nue #4

Open
aniva wants to merge 189 commits from touhou/houjuu-nue into main
8 changed files with 180 additions and 80 deletions
Showing only changes of commit c73675bbe3 - Show all commits

View File

@ -1,30 +1,55 @@
"""
A catalog of material properties
"""
from enum import Enum
from enum import Enum, Flag, auto
from typing import Union, Optional
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 Role(Enum):
class Role(Flag):
"""
Describes the role of a part
"""
# Parent and child components in a load bearing joint
PARENT = _color('blue4', 0.6)
CASING = _color('dodgerblue3', 0.6)
CHILD = _color('darkorange2', 0.6)
DAMPING = _color('springgreen', 0.5)
STRUCTURE = _color('gray', 0.4)
DECORATION = _color('lightseagreen', 0.4)
ELECTRONIC = _color('mediumorchid', 0.5)
MARKER = _color('cyan', 1.0)
PARENT = auto()
CHILD = auto()
CASING = auto()
DAMPING = auto()
STRUCTURE = auto()
DECORATION = auto()
ELECTRONIC = auto()
CONNECTION = auto()
# Parent and child components in a load bearing joint
def color_avg(self) -> Cq.Color:
r, g, b, a = zip(*[ROLE_COLOR_MAP[component].toTuple() for component in self])
def avg(li):
assert li
return sum(li) / len(li)
r, g, b, a = avg(r), avg(g), avg(b), avg(a)
return Cq.Color(r, g, b, a)
def color_head(self) -> Cq.Color:
head = next(iter(self))
return ROLE_COLOR_MAP[head]
# Maps roles to their colours
ROLE_COLOR_MAP = {
Role.PARENT: _color('blue4', 0.6),
Role.CASING: _color('dodgerblue3', 0.6),
Role.CHILD: _color('darkorange2', 0.6),
Role.DAMPING: _color('springgreen', 0.8),
Role.STRUCTURE: _color('gray', 0.4),
Role.DECORATION: _color('lightseagreen', 0.4),
Role.ELECTRONIC: _color('mediumorchid', 0.5),
Role.CONNECTION: _color('steelblue3', 0.8)
}
def __init__(self, color: Cq.Color):
self.color = color
class Material(Enum):
"""
@ -32,11 +57,56 @@ class Material(Enum):
"""
WOOD_BIRCH = 0.8, _color('bisque', 0.9)
PLASTIC_PLA = 0.5, _color('azure3', 0.6)
RESIN_TRANSPARENT = 1.1, _color('cadetblue2', 0.6)
ACRYLIC_BLACK = 0.5, _color('gray50', 0.6)
PLASTIC_PLA = 0.5, _color('mistyrose', 0.8)
RESIN_TRANSPERENT = 1.1, _color('cadetblue2', 0.6)
RESIN_TOUGH_1500 = 1.1, _color('seashell3', 0.7)
ACRYLIC_BLACK = 0.5, _color('gray5', 0.8)
ACRYLIC_TRANSLUSCENT = 0.5, _color('ivory2', 0.8)
ACRYLIC_TRANSPARENT = 0.5, _color('ghostwhite', 0.5)
STEEL_SPRING = 1.0, _color('gray', 0.8)
def __init__(self, density: float, color: Cq.Color):
self.density = density
self.color = color
def add_with_material_role(
self: Cq.Assembly,
obj: Union[Cq.Shape, Cq.Workplane, None],
loc: Optional[Cq.Location] = None,
name: Optional[str] = None,
material: Optional[Material] = None,
role: Optional[Role] = None) -> Cq.Assembly:
"""
Structural add function which allows specifying material and role
"""
metadata = {}
color = None
if material:
metadata["material"] = material
color = material.color
if role:
metadata["role"] = role
color = role.color_avg()
if len(metadata) == 0:
metadata = None
self.add(obj, loc=loc, name=name, color=color, metadata=metadata)
return self
Cq.Assembly.addS = add_with_material_role
def color_by_material(self: Cq.Assembly) -> Cq.Assembly:
for _, a in self.traverse():
if 'material' not in a.metadata:
continue
a.color = a.metadata["material"].color
return self
Cq.Assembly.color_by_material = color_by_material
def color_by_role(self: Cq.Assembly, avg: bool = True) -> Cq.Assembly:
for _, a in self.traverse():
if 'role' not in a.metadata:
continue
role = a.metadata["role"]
a.color = role.color_avg() if avg else role.color_head()
return self
Cq.Assembly.color_by_role = color_by_role

View File

@ -141,8 +141,8 @@ class HirthJoint:
angle = offset * self.tooth_angle
result = (
Cq.Assembly()
.add(obj1, name="obj1", color=Role.PARENT.color)
.add(obj2, name="obj2", color=Role.CHILD.color)
.addS(obj1, name="obj1", role=Role.PARENT)
.addS(obj2, name="obj2", role=Role.CHILD)
.constrain("obj1", "Fixed")
.constrain("obj1?mate", "obj2?mate", "Plane")
.constrain("obj1?dir", "obj2?dir", "Axis", param=angle)
@ -488,9 +488,9 @@ class TorsionJoint:
spring = self.spring()
result = (
Cq.Assembly()
.add(spring, name="spring", color=Role.DAMPING.color)
.add(track, name="track", color=Role.PARENT.color)
.add(rider, name="rider", color=Role.CHILD.color)
.addS(spring, name="spring", role=Role.DAMPING)
.addS(track, name="track", role=Role.PARENT)
.addS(rider, name="rider", role=Role.CHILD)
)
TorsionJoint.add_constraints(
result,

View File

@ -31,7 +31,6 @@ shoulder, elbow, wrist in analogy with human anatomy.
"""
from dataclasses import dataclass, field
import cadquery as Cq
from nhf import Material, Role
from nhf.build import Model, TargetKind, target, assembly
from nhf.parts.joints import HirthJoint, TorsionJoint
from nhf.parts.handle import Handle, BayonetMount
@ -99,9 +98,6 @@ class Parameters(Model):
trident_terminal_hole_diam: float = 24
trident_terminal_bottom_thickness: float = 10
material_panel: Material = Material.ACRYLIC_TRANSPARENT
material_bracket: Material = Material.ACRYLIC_TRANSPARENT
def __post_init__(self):
super().__init__(name="houjuu-nue")
self.harness.hs_hirth_joint = self.hs_hirth_joint

View File

@ -154,14 +154,18 @@ class Harness:
harness = self.surface()
result = (
Cq.Assembly()
.add(harness, name="base", color=Material.WOOD_BIRCH.color)
.addS(harness, name="base",
material=Material.WOOD_BIRCH,
role=Role.STRUCTURE)
.constrain("base", "Fixed")
)
for name in ["l1", "l2", "l3", "r1", "r2", "r3"]:
j = self.hs_joint_parent()
(
result
.add(j, name=name, color=Role.PARENT.color)
.addS(j, name=name,
role=Role.PARENT,
material=Material.PLASTIC_PLA)
#.constrain("base?mount", f"{name}?base", "Axis")
)
for i in range(4):

View File

@ -1,7 +1,7 @@
from dataclasses import dataclass, field
from typing import Optional, Tuple
import cadquery as Cq
from nhf import Role
from nhf import Material, Role
from nhf.build import Model, target, assembly
import nhf.parts.springs as springs
from nhf.parts.joints import TorsionJoint
@ -182,21 +182,23 @@ class ShoulderJoint(Model):
wing_root_wall_thickness: float = 25.4/16,
) -> Cq.Assembly:
directrix = 0
mat = Material.RESIN_TRANSPERENT
mat_spring = Material.STEEL_SPRING
result = (
Cq.Assembly()
.add(self.child(), name="child",
color=Role.CHILD.color)
.addS(self.child(), name="child",
role=Role.CHILD, material=mat)
.constrain("child/core", "Fixed")
.add(self.torsion_joint.spring(), name="spring_top",
color=Role.DAMPING.color)
.add(self.parent(wing_root_wall_thickness),
name="parent_top",
color=Role.PARENT.color)
.add(self.torsion_joint.spring(), name="spring_bot",
color=Role.DAMPING.color)
.add(self.parent(wing_root_wall_thickness),
name="parent_bot",
color=Role.PARENT.color)
.addS(self.torsion_joint.spring(), name="spring_top",
role=Role.DAMPING, material=mat_spring)
.addS(self.parent(wing_root_wall_thickness),
name="parent_top",
role=Role.PARENT, material=mat)
.addS(self.torsion_joint.spring(), name="spring_bot",
role=Role.DAMPING, material=mat_spring)
.addS(self.parent(wing_root_wall_thickness),
name="parent_bot",
role=Role.PARENT, material=mat)
)
TorsionJoint.add_constraints(result,
rider="child/rider_top",
@ -516,9 +518,9 @@ class DiskJoint(Model):
assert 0 <= angle <= self.movement_angle
result = (
Cq.Assembly()
.add(self.disk(), name="disk", color=Role.CHILD.color)
.add(self.housing_lower(), name="housing_lower", color=Role.PARENT.color)
.add(self.housing_upper(), name="housing_upper", color=Role.CASING.color)
.addS(self.disk(), name="disk", role=Role.CHILD)
.addS(self.housing_lower(), name="housing_lower", role=Role.PARENT)
.addS(self.housing_upper(), name="housing_upper", role=Role.CASING)
#.constrain("housing_lower", "Fixed")
)
result = self.add_constraints(
@ -564,6 +566,8 @@ class ElbowJoint:
# Size of the mounting holes
hole_diam: float = 8.0
material: Material = Material.RESIN_TRANSPERENT
def __post_init__(self):
assert self.child_arm_radius > self.disk_joint.radius_housing
assert self.parent_arm_radius > self.disk_joint.radius_housing
@ -638,9 +642,12 @@ class ElbowJoint:
def assembly(self, angle: float = 0) -> Cq.Assembly:
result = (
Cq.Assembly()
.add(self.child_joint(), name="child", color=Role.CHILD.color)
.add(self.parent_joint_lower(), name="parent_lower", color=Role.CASING.color)
.add(self.parent_joint_upper(), name="parent_upper", color=Role.PARENT.color)
.addS(self.child_joint(), name="child",
role=Role.CHILD, material=self.material)
.addS(self.parent_joint_lower(), name="parent_lower",
role=Role.CASING, material=self.material)
.addS(self.parent_joint_upper(), name="parent_upper",
role=Role.PARENT, material=self.material)
#.constrain("child/disk?mate_bot", "Fixed")
)
result = self.disk_joint.add_constraints(

View File

@ -1,6 +1,6 @@
import math
import cadquery as Cq
from nhf import Material
from nhf import Material, Role
from nhf.parts.handle import Handle
def trident_assembly(
@ -16,27 +16,40 @@ def trident_assembly(
.faces(">Z")
.hole(15, terminal_height + handle.insertion_length - 10)
)
mat_i = Material.PLASTIC_PLA
mat_c = Material.PLASTIC_PLA
mat_i = Material.RESIN_TOUGH_1500
mat_s = Material.ACRYLIC_BLACK
role_i = Role.CONNECTION
role_c = Role.CONNECTION
role_s = Role.STRUCTURE
assembly = (
Cq.Assembly()
.add(handle.insertion(), name="i0", color=mat_i.color)
.addS(handle.insertion(), name="i0",
material=mat_i, role=role_i)
.constrain("i0", "Fixed")
.add(segment(), name="s1", color=mat_s.color)
.addS(segment(), name="s1",
material=mat_s, role=role_s)
.constrain("i0?rim", "s1?mate1", "Plane", param=0)
.add(handle.insertion(), name="i1", color=mat_i.color)
.add(handle.connector(), name="c1", color=mat_i.color)
.add(handle.insertion(), name="i2", color=mat_i.color)
.addS(handle.insertion(), name="i1",
material=mat_i, role=role_i)
.addS(handle.connector(), name="c1",
material=mat_c, role=role_c)
.addS(handle.insertion(), name="i2",
material=mat_i, role=role_i)
.constrain("s1?mate2", "i1?rim", "Plane", param=0)
.constrain("i1?mate", "c1?mate1", "Plane")
.constrain("i2?mate", "c1?mate2", "Plane")
.add(segment(), name="s2", color=mat_s.color)
.addS(segment(), name="s2",
material=mat_s, role=role_s)
.constrain("i2?rim", "s2?mate1", "Plane", param=0)
.add(handle.insertion(), name="i3", color=mat_i.color)
.addS(handle.insertion(), name="i3",
material=mat_i, role=role_i)
.constrain("s2?mate2", "i3?rim", "Plane", param=0)
.add(handle.one_side_connector(), name="head", color=mat_i.color)
.addS(handle.one_side_connector(), name="head",
material=mat_c, role=role_c)
.constrain("i3?mate", "head?mate", "Plane")
.add(terminal, name="terminal", color=mat_i.color)
.addS(terminal, name="terminal",
material=mat_c, role=role_c)
.constrain("i0?mate", "terminal?mate", "Plane")
)
return assembly.solve()

View File

@ -63,8 +63,10 @@ class WingProfile(Model):
ring_y: float = 20
ring_radius_inner: float = 22
material_panel: Material = Material.ACRYLIC_TRANSPARENT
material_bracket: Material = Material.ACRYLIC_TRANSPARENT
mat_panel: Material = Material.ACRYLIC_TRANSLUSCENT
mat_bracket: Material = Material.ACRYLIC_TRANSPARENT
mat_hs_joint: Material = Material.PLASTIC_PLA
role_panel: Role = Role.STRUCTURE
def __post_init__(self):
super().__init__(name=self.name)
@ -170,8 +172,10 @@ class WingProfile(Model):
def assembly_s0(self) -> Cq.Assembly:
result = (
Cq.Assembly()
.add(self.surface_s0(top=True), name="bot", color=self.material_panel.color)
.add(self.surface_s0(top=False), name="top", color=self.material_panel.color)
.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)
)
@ -181,7 +185,9 @@ class WingProfile(Model):
]:
(
result
.add(o, name=tag, color=self.material_bracket.color)
.addS(o, name=tag,
role=Role.STRUCTURE | Role.CONNECTION,
material=self.mat_bracket)
.constrain(f"{tag}?bot", f"bot?{tag}", "Plane")
.constrain(f"{tag}?top", f"top?{tag}", "Plane")
.constrain(f"{tag}?dir", f"top?{tag}_dir", "Axis")
@ -189,7 +195,7 @@ class WingProfile(Model):
hirth = self.base_joint.generate()
(
result
.add(hirth, name="hs", color=Role.CHILD.color)
.addS(hirth, name="hs", role=Role.CHILD, material=self.mat_hs_joint)
.constrain("hs@faces@<Z", "base?dir", "Plane")
)
return result.solve()
@ -216,9 +222,11 @@ class WingProfile(Model):
angle = 0
(
a
.add(spacer,
name=point_tag,
color=self.material_bracket.color)
.addS(
spacer,
name=point_tag,
material=self.mat_bracket,
role=self.role_panel)
.constrain(f"{front_tag}?{point_tag}",
f"{point_tag}?{site_front}", "Plane")
.constrain(f"{back_tag}?{point_tag}",
@ -374,11 +382,11 @@ class WingProfile(Model):
def assembly_s1(self) -> Cq.Assembly:
result = (
Cq.Assembly()
.add(self.surface_s1(front=True), name="front",
color=self.material_panel.color)
.addS(self.surface_s1(front=True), name="front",
material=self.mat_panel, role=self.role_panel)
.constrain("front", "Fixed")
.add(self.surface_s1(front=False), name="back",
color=self.material_panel.color)
.addS(self.surface_s1(front=False), name="back",
material=self.mat_panel, role=self.role_panel)
.constrain("front@faces@>Z", "back@faces@<Z", "Point",
param=self.s1_thickness)
)
@ -459,11 +467,11 @@ class WingProfile(Model):
def assembly_s2(self) -> Cq.Assembly:
result = (
Cq.Assembly()
.add(self.surface_s2(front=True), name="front",
color=self.material_panel.color)
.addS(self.surface_s2(front=True), name="front",
material=self.mat_panel, role=self.role_panel)
.constrain("front", "Fixed")
.add(self.surface_s2(front=False), name="back",
color=self.material_panel.color)
.addS(self.surface_s2(front=False), name="back",
material=self.mat_panel, role=self.role_panel)
.constrain("front@faces@>Z", "back@faces@<Z", "Point",
param=self.s1_thickness)
)
@ -516,11 +524,11 @@ class WingProfile(Model):
def assembly_s3(self) -> Cq.Assembly:
result = (
Cq.Assembly()
.add(self.surface_s3(front=True), name="front",
color=self.material_panel.color)
.addS(self.surface_s3(front=True), name="front",
material=self.mat_panel, role=self.role_panel)
.constrain("front", "Fixed")
.add(self.surface_s3(front=False), name="back",
color=self.material_panel.color)
.addS(self.surface_s3(front=False), name="back",
material=self.mat_panel, role=self.role_panel)
.constrain("front@faces@>Z", "back@faces@<Z", "Point",
param=self.s1_thickness)
)

View File

@ -11,6 +11,8 @@ import cadquery as Cq
from nhf import Role
from typing import Union, Tuple, cast
COLOR_MARKER = Cq.Color(0, 1, 1, 1)
# Bug fixes
def _subloc(self, name: str) -> Tuple[Cq.Location, str]:
"""
@ -101,7 +103,7 @@ def to_marker_name(tag: str) -> str:
def mark_point(self: Cq.Assembly,
tag: str,
size: float = 2,
color: Cq.Color = Role.MARKER.color) -> Cq.Assembly:
color: Cq.Color = COLOR_MARKER) -> Cq.Assembly:
"""
Adds a marker to make a point visible
"""
@ -117,7 +119,7 @@ Cq.Assembly.markPoint = mark_point
def mark_plane(self: Cq.Assembly,
tag: str,
size: float = 2,
color: Cq.Color = Role.MARKER.color) -> Cq.Assembly:
color: Cq.Color = COLOR_MARKER) -> Cq.Assembly:
"""
Adds a marker to make a plane visible
"""