cosplay: Touhou/Shiki Eiki #7

Open
aniva wants to merge 11 commits from touhou/shiki-eiki into main
8 changed files with 4140 additions and 8 deletions
Showing only changes of commit 3ac342a65d - Show all commits

View File

@ -84,6 +84,7 @@ class Material(Enum):
ACRYLIC_TRANSLUSCENT = 1.18, _color('ivory2', 0.8) ACRYLIC_TRANSLUSCENT = 1.18, _color('ivory2', 0.8)
ACRYLIC_TRANSPARENT = 1.18, _color('ghostwhite', 0.5) ACRYLIC_TRANSPARENT = 1.18, _color('ghostwhite', 0.5)
STEEL_SPRING = 7.8, _color('gray', 0.8) STEEL_SPRING = 7.8, _color('gray', 0.8)
METAL_BRASS = 8.5, _color('gold1', 0.8)
def __init__(self, density: float, color: Cq.Color): def __init__(self, density: float, color: Cq.Color):
self.density = density self.density = density
@ -116,6 +117,9 @@ def add_with_material_role(
Cq.Assembly.addS = add_with_material_role Cq.Assembly.addS = add_with_material_role
def color_by_material(self: Cq.Assembly) -> Cq.Assembly: def color_by_material(self: Cq.Assembly) -> Cq.Assembly:
"""
Set colours in an assembly by material
"""
for _, a in self.traverse(): for _, a in self.traverse():
if KEY_MATERIAL not in a.metadata: if KEY_MATERIAL not in a.metadata:
continue continue
@ -123,6 +127,9 @@ def color_by_material(self: Cq.Assembly) -> Cq.Assembly:
return self return self
Cq.Assembly.color_by_material = color_by_material Cq.Assembly.color_by_material = color_by_material
def color_by_role(self: Cq.Assembly, avg: bool = True) -> Cq.Assembly: def color_by_role(self: Cq.Assembly, avg: bool = True) -> Cq.Assembly:
"""
Set colours in an assembly by role
"""
for _, a in self.traverse(): for _, a in self.traverse():
if KEY_ROLE not in a.metadata: if KEY_ROLE not in a.metadata:
continue continue

View File

@ -11,7 +11,8 @@ class Parameters(Model):
rod: MR.Rod = field(default_factory=lambda: MR.Rod()) rod: MR.Rod = field(default_factory=lambda: MR.Rod())
crown: MC.Crown = field(default_factory=lambda: MC.Crown()) crown: MC.Crown = field(default_factory=lambda: MC.Crown())
epaulette: ME.Epaulette = field(default_factory=lambda: ME.Epaulette()) epaulette_ze: ME.Epaulette = field(default_factory=lambda: ME.Epaulette(side="ze"))
epaulette_hi: ME.Epaulette = field(default_factory=lambda: ME.Epaulette(side="hi"))
def __post_init__(self): def __post_init__(self):
super().__init__(name="shiki-eiki") super().__init__(name="shiki-eiki")
@ -22,9 +23,12 @@ class Parameters(Model):
@submodel(name="crown") @submodel(name="crown")
def submodel_crown(self) -> Model: def submodel_crown(self) -> Model:
return self.crown return self.crown
@submodel(name="epaulette") @submodel(name="epaulette_ze")
def submodel_epaulette(self) -> Model: def submodel_epaulette_ze(self) -> Model:
return self.epaulette return self.epaulette_ze
@submodel(name="epaulette_hi")
def submodel_epaulette_hi(self) -> Model:
return self.epaulette_hi
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -17,6 +17,10 @@ class Crown(Model):
margin: float = 10.0 margin: float = 10.0
thickness: float = 0.4 # 26 Gauge
material: Material = Material.METAL_BRASS
def __post_init__(self): def __post_init__(self):
super().__init__(name="crown") super().__init__(name="crown")
@ -30,7 +34,7 @@ class Crown(Model):
return self.tilt_circ / self.facets return self.tilt_circ / self.facets
@target(name="side") @target(name="side")
def profile_base(self) -> Cq.Sketch: def profile_side(self) -> Cq.Sketch:
# Generate the pentagonal shape # Generate the pentagonal shape
dx_l = self.facet_width_lower dx_l = self.facet_width_lower
@ -204,7 +208,7 @@ class Crown(Model):
) )
return ( return (
self.profile_base() self.profile_side()
.boolean(window.moved(window_p1), mode='s') .boolean(window.moved(window_p1), mode='s')
.boolean(window.moved(window_p1.flip_x()), mode='s') .boolean(window.moved(window_p1.flip_x()), mode='s')
.boolean(window.moved(window_p2), mode='s') .boolean(window.moved(window_p2), mode='s')
@ -292,3 +296,49 @@ class Crown(Model):
.bezier([p.flip_x().to2d_pos() for p in bezier_group]) .bezier([p.flip_x().to2d_pos() for p in bezier_group])
) )
return sketch.assemble() return sketch.assemble()
def assembly(self) -> Cq.Assembly:
front = (
Cq.Workplane('XY')
.placeSketch(self.profile_front())
.extrude(self.thickness)
)
side = (
Cq.Workplane('XY')
.placeSketch(self.profile_side())
.extrude(self.thickness)
)
side_guard = (
Cq.Workplane('XY')
.placeSketch(self.profile_side_guard())
.extrude(self.thickness)
)
assembly = (
Cq.Assembly()
.addS(
front,
name="front",
material=self.material,
role=Role.DECORATION,
)
)
for i, pos in enumerate([-2, -1, 1, 2]):
x = self.facet_width_upper * pos
assembly = (
assembly
.addS(
side,
name=f"side{i}",
material=self.material,
role=Role.DECORATION,
loc=Cq.Location.from2d(x, 0),
)
.addS(
side_guard,
name=f"guard{i}",
material=self.material,
role=Role.DECORATION,
loc=Cq.Location(x, 0, self.thickness),
)
)
return assembly

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
import math import math
from dataclasses import dataclass, field from dataclasses import dataclass, field
from pathlib import Path
import cadquery as Cq import cadquery as Cq
from nhf import Material, Role from nhf import Material, Role
from nhf.build import Model, target, assembly from nhf.build import Model, target, assembly
@ -8,5 +9,28 @@ import nhf.utils
@dataclass @dataclass
class Epaulette(Model): class Epaulette(Model):
side: str
diam: float = 100.0
thickness_brass: float = 0.4 # 26 Gauge
thickness_fabric: float = 0.3
material: Material = Material.METAL_BRASS
def __post_init__(self): def __post_init__(self):
super().__init__(name="epaulette") super().__init__(name=f"epaulette-{self.side}")
def surface(self) -> Cq.Solid:
path = Path(__file__).resolve().parent / f"epaulette-{self.side}.dxf"
return (
Cq.importers.importDXF(path).wires().toPending().extrude(self.thickness_brass)
)
def assembly(self) -> Cq.Assembly:
assembly = (
Cq.Assembly()
.addS(
self.surface(),
name="surface",
material=self.material,
role=Role.DECORATION,
)
)
return assembly

View File

@ -14,6 +14,9 @@ class Rod(Model):
width_tail: float = 60.0 width_tail: float = 60.0
margin: float = 10.0 margin: float = 10.0
thickness_top: float = 25.4 / 4
thickness_side: float = 25.4 / 8
# counted from middle to the bottom # counted from middle to the bottom
fac_bar_top: float = 0.1 fac_bar_top: float = 0.1
# counted from bottom to top # counted from bottom to top
@ -23,6 +26,8 @@ class Rod(Model):
fac_window_footer_bot: float = 0.33 fac_window_footer_bot: float = 0.33
fac_window_footer_top: float = 0.59 fac_window_footer_top: float = 0.59
material_shell: Material = Material.WOOD_BIRCH
def __post_init__(self): def __post_init__(self):
super().__init__(name="rod") super().__init__(name="rod")
self.loc_core = Cq.Location.from2d(self.length - self.length_tip, 0) self.loc_core = Cq.Location.from2d(self.length - self.length_tip, 0)
@ -279,7 +284,7 @@ class Rod(Model):
@target(name="surface") @target(name="surface")
def top_profile(self) -> Cq.Sketch: def profile_top(self) -> Cq.Sketch:
sketch = ( sketch = (
Cq.Sketch() Cq.Sketch()
.polygon([ .polygon([
@ -302,9 +307,22 @@ class Rod(Model):
) )
return sketch return sketch
def surface_top(self) -> Cq.Workplane:
return (
Cq.Workplane('XZ')
.placeSketch(self.profile_top())
.extrude(self.thickness_top)
)
@assembly() @assembly()
def assembly(self) -> Cq.Assembly: def assembly(self) -> Cq.Assembly:
a = ( a = (
Cq.Assembly() Cq.Assembly()
.addS(
self.surface_top(),
name="top",
material=self.material_shell,
role=Role.STRUCTURE | Role.DECORATION
)
) )
return a return a

View File

@ -0,0 +1,139 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="100mm"
height="100mm"
viewBox="0 0 100 100"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
sodipodi:docname="zehi.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="1.8706489"
inkscape:cx="171.86549"
inkscape:cy="207.68194"
inkscape:window-width="1640"
inkscape:window-height="962"
inkscape:window-x="20"
inkscape:window-y="40"
inkscape:window-maximized="0"
inkscape:current-layer="layer3"
showguides="true">
<sodipodi:guide
position="50,90.756846"
orientation="-1,0"
id="guide1"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,134,229)" />
<sodipodi:guide
position="32.08421,55"
orientation="0,1"
id="guide2"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,134,229)" />
<sodipodi:guide
position="60,78.19709"
orientation="-1,0"
id="guide3"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,134,229)" />
<sodipodi:guide
position="40,74.842796"
orientation="-1,0"
id="guide4"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,134,229)" />
<sodipodi:guide
position="4.9999993,79.999999"
orientation="0,1"
id="guide5"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,134,229)" />
<sodipodi:guide
position="-9.7833569,45"
orientation="0,1"
id="guide6"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,134,229)" />
</sodipodi:namedview>
<defs
id="defs1" />
<g
inkscape:label="Outline"
inkscape:groupmode="layer"
id="layer1">
<path
id="path1"
style="fill:none;stroke:#000000;stroke-width:0.264453;stroke-opacity:1;-inkscape-stroke:none"
inkscape:label="outer"
d="M 50.000049 0.13229167 A 49.867775 49.867775 0 0 0 0.13229167 50.000049 A 49.867775 49.867775 0 0 0 50.000049 99.867806 A 49.867775 49.867775 0 0 0 99.867806 50.000049 A 49.867775 49.867775 0 0 0 50.000049 0.13229167 z M 50.000049 5.1190674 A 44.880997 44.880997 0 0 1 94.88103 50.000049 A 44.880997 44.880997 0 0 1 50.000049 94.88103 A 44.880997 44.880997 0 0 1 5.1190674 50.000049 A 44.880997 44.880997 0 0 1 50.000049 5.1190674 z " />
</g>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="Cut"
style="display:none">
<circle
style="fill:none;stroke:#000000;stroke-width:0.264453;stroke-opacity:1;-inkscape-stroke:none"
id="circle14"
cx="50"
cy="50"
inkscape:label="outer"
r="49.867775" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Ze"
style="display:inline">
<path
id="path10"
style="fill:none;stroke:#144e16;stroke-width:0.290227;stroke-opacity:1;-inkscape-stroke:none"
d="M 50.000049,12.645223 A 37.354885,37.354885 0 0 0 13.002824,44.999837 h 2.546614 2.469617 63.965088 1.438155 3.574976 A 37.354885,37.354885 0 0 0 50.000049,12.645223 Z m 0,4.980575 a 32.374233,32.374233 0 0 1 22.160404,8.817549 H 27.842745 A 32.374233,32.374233 0 0 1 50.000049,17.625798 Z M 23.725167,31.201713 h 52.552864 a 32.374233,32.374233 0 0 1 4.547526,9.039758 H 19.177641 a 32.374233,32.374233 0 0 1 4.547526,-9.039758 z"
inkscape:label="top" />
<path
style="fill:none;stroke:#144e16;stroke-width:0.261252;stroke-opacity:1;-inkscape-stroke:none"
d="m 30.468424,65.042542 -8.764322,8.764322 a 37.141727,37.141731 0 0 0 28.295947,13.12168 37.141727,37.141731 0 0 0 23.236308,-8.258411 L 70.147139,75.252771 C 64.43218,79.841996 57.3295,82.357002 50.000049,82.386702 42.031806,82.356509 34.403936,79.387593 28.529008,74.129842 l 5.513359,-5.513358 z"
id="path14" />
<path
style="fill:none;stroke:#144e16;stroke-width:0.261252;stroke-opacity:1;-inkscape-stroke:none"
d="m 53.049475,54.972872 v 0.02687 H 13.231234 a 37.141727,37.141731 0 0 0 1.076937,5.000211 H 53.049475 V 75.366976 H 58.10343 V 67.69716 H 73.684908 V 62.643205 H 58.10343 v -2.64325 h 27.588497 a 37.141727,37.141731 0 0 0 1.076937,-5.000211 H 58.10343 v -0.02687 z"
id="path11" />
</g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Hi"
style="display:inline">
<path
id="rect6"
style="fill:none;stroke:#053efb;stroke-width:0.264583;stroke-opacity:1;-inkscape-stroke:none"
d="m 54.786837,19.999813 v 59.999955 h 5.213118 v -8.94364 H 79.70883 V 62.775496 H 59.999955 V 54.140365 H 79.70883 V 45.859733 H 59.999955 V 37.224601 H 79.70883 V 28.94397 H 59.999955 v -8.944157 z"
inkscape:label="right" />
<path
id="path9"
style="fill:none;stroke:#053efb;stroke-width:0.264583;stroke-opacity:1;-inkscape-stroke:none"
d="M 45.245359,79.999977 V 20.000022 h -5.213118 v 8.94364 H 20.323366 v 8.280632 h 19.708875 v 8.635131 H 20.323366 v 8.280632 h 19.708875 v 8.635132 H 20.323366 v 8.280631 h 19.708875 v 8.944157 z"
inkscape:label="left" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.6 KiB