187 lines
6.1 KiB
Python
187 lines
6.1 KiB
Python
from dataclasses import dataclass, field
|
|
import cadquery as Cq
|
|
from nhf.build import Model, TargetKind, target, assembly, submodel
|
|
from nhf.materials import Role, Material
|
|
import nhf.touhou.yasaka_kanako.onbashira as MO
|
|
import nhf.utils
|
|
|
|
@dataclass
|
|
class Mirror(Model):
|
|
"""
|
|
Kanako's mirror, made of three levels.
|
|
|
|
The mirror suface is sandwiched between two layers of wood. As such, its
|
|
dimensions have to sit in between that of the aperature on the surface, and
|
|
the outer walls. The width/height here refers to the outer edge's width and height
|
|
"""
|
|
width: float = 50.0
|
|
height: float = 60.0
|
|
|
|
inner_gap: float = 3.0
|
|
outer_gap: float = 3.0
|
|
|
|
core_thickness: float = 25.4 / 8
|
|
casing_thickness: float = 25.4 / 16
|
|
|
|
flange_r0: float = 5.0
|
|
flange_r1: float = 15.0
|
|
flange_y1: float = 12.0
|
|
flange_y2: float = 25.0
|
|
flange_hole_r: float = 8.0
|
|
wing_x1: float = 12.0
|
|
wing_x2: float = 20.0
|
|
wing_r1: float = 6.0
|
|
wing_r2: float = 12.0
|
|
tail_r0: float = 5.0
|
|
tail_r1: float = 10.0
|
|
tail_y1: float = 12.0
|
|
tail_y2: float = 25.0
|
|
|
|
# Necklace hole
|
|
hole_diam: float = 5.0
|
|
|
|
material_mirror: Material = Material.ACRYLIC_TRANSPARENT
|
|
material_casing: Material = Material.WOOD_BIRCH
|
|
|
|
@target(name="core", kind=TargetKind.DXF)
|
|
def profile_core(self) -> Cq.Sketch:
|
|
rx = self.width/2 - self.outer_gap
|
|
ry = self.height/2 - self.outer_gap
|
|
return Cq.Sketch().ellipse(rx, ry)
|
|
|
|
def core(self) -> Cq.Workplane:
|
|
return (
|
|
Cq.Workplane()
|
|
.placeSketch(self.profile_core())
|
|
.extrude(self.core_thickness)
|
|
)
|
|
|
|
@target(name="casing-bot", kind=TargetKind.DXF)
|
|
def profile_casing_bot(self) -> Cq.Sketch:
|
|
"""
|
|
Base of the casing with no holes carved out
|
|
"""
|
|
return (
|
|
Cq.Sketch()
|
|
.ellipse(self.width/2, self.height/2)
|
|
)
|
|
def casing_bot(self) -> Cq.Workplane:
|
|
return (
|
|
Cq.Workplane()
|
|
.placeSketch(self.profile_casing_bot())
|
|
.extrude(self.casing_thickness)
|
|
)
|
|
def profile_wing(self, sign: float=1) -> Cq.Sketch:
|
|
xt = self.width / 2 - self.outer_gap
|
|
return (
|
|
Cq.Sketch()
|
|
.polygon([
|
|
(sign*xt, self.wing_r1),
|
|
(sign*(xt+self.wing_x1), self.wing_r1),
|
|
(sign*(xt+self.wing_x1), self.wing_r2),
|
|
(sign*(xt+self.wing_x2), self.wing_r2),
|
|
(sign*(xt+self.wing_x2), -self.wing_r2),
|
|
(sign*(xt+self.wing_x1), -self.wing_r2),
|
|
(sign*(xt+self.wing_x1), -self.wing_r1),
|
|
(sign*xt, -self.wing_r1),
|
|
])
|
|
)
|
|
@target(name="casing-mid", kind=TargetKind.DXF)
|
|
def profile_casing_mid(self) -> Cq.Sketch:
|
|
yt = self.height / 2 - self.outer_gap
|
|
rx = self.width/2 - self.outer_gap
|
|
ry = self.height/2 - self.outer_gap
|
|
yh = (self.flange_y1 + self.flange_y2) / 2
|
|
flange = (
|
|
Cq.Sketch()
|
|
.polygon([
|
|
(self.flange_r0, yt),
|
|
(self.flange_r0, yt + self.flange_y1),
|
|
(self.flange_r1, yt + self.flange_y1),
|
|
(self.flange_r1, yt + self.flange_y2),
|
|
(-self.flange_r1, yt + self.flange_y2),
|
|
(-self.flange_r1, yt + self.flange_y1),
|
|
(-self.flange_r0, yt + self.flange_y1),
|
|
(-self.flange_r0, yt),
|
|
])
|
|
.push([
|
|
(self.flange_hole_r, yt+yh),
|
|
(-self.flange_hole_r, yt+yh),
|
|
])
|
|
.circle(self.hole_diam/2, mode="s")
|
|
)
|
|
tail = (
|
|
Cq.Sketch()
|
|
.polygon([
|
|
(+self.tail_r0, -yt),
|
|
(+self.tail_r0, -yt - self.tail_y1),
|
|
(+self.tail_r1, -yt - self.tail_y1),
|
|
(+self.tail_r1, -yt - self.tail_y2),
|
|
(-self.tail_r1, -yt - self.tail_y2),
|
|
(-self.tail_r1, -yt - self.tail_y1),
|
|
(-self.tail_r0, -yt - self.tail_y1),
|
|
(-self.tail_r0, -yt),
|
|
])
|
|
)
|
|
return (
|
|
self.profile_casing_bot()
|
|
.ellipse(rx, ry, mode="s")
|
|
.boolean(flange, mode="a")
|
|
.boolean(tail, mode="a")
|
|
.boolean(self.profile_wing(-1), mode="a")
|
|
.boolean(self.profile_wing(1), mode="a")
|
|
)
|
|
def casing_mid(self) -> Cq.Workplane:
|
|
return (
|
|
Cq.Workplane()
|
|
.placeSketch(self.profile_casing_mid())
|
|
.extrude(self.core_thickness)
|
|
)
|
|
@target(name="casing-top", kind=TargetKind.DXF)
|
|
def profile_casing_top(self) -> Cq.Sketch:
|
|
rx = self.width/2 - self.outer_gap - self.inner_gap
|
|
ry = self.height/2 - self.outer_gap - self.inner_gap
|
|
return (
|
|
self.profile_casing_bot()
|
|
.ellipse(rx, ry, mode="s")
|
|
)
|
|
def casing_top(self) -> Cq.Workplane:
|
|
return (
|
|
Cq.Workplane()
|
|
.placeSketch(self.profile_casing_top())
|
|
.extrude(self.casing_thickness)
|
|
)
|
|
|
|
@assembly()
|
|
def assembly(self) -> Cq.Assembly:
|
|
return (
|
|
Cq.Assembly()
|
|
.addS(
|
|
self.core(),
|
|
name="core",
|
|
material=self.material_mirror,
|
|
role=Role.DECORATION,
|
|
loc=Cq.Location(0, 0, self.casing_thickness)
|
|
)
|
|
.addS(
|
|
self.casing_bot(),
|
|
name="casing_bot",
|
|
material=self.material_casing,
|
|
role=Role.CASING,
|
|
)
|
|
.addS(
|
|
self.casing_mid(),
|
|
name="casing_mid",
|
|
material=self.material_casing,
|
|
role=Role.CASING,
|
|
loc=Cq.Location(0, 0, self.casing_thickness)
|
|
)
|
|
.addS(
|
|
self.casing_top(),
|
|
name="casing_top",
|
|
material=self.material_casing,
|
|
role=Role.CASING,
|
|
loc=Cq.Location(0, 0, self.core_thickness + self.casing_thickness)
|
|
)
|
|
)
|