cosplay: Touhou/Shiki Eiki #7
|
@ -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
|
||||||
|
|
|
@ -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__':
|
||||||
|
|
|
@ -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
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 |
Loading…
Reference in New Issue