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 = 100.0 height: float = 120.0 inner_gap: float = 3.0 outer_gap: float = 3.0 core_thickness: float = 25.4 / 8 casing_thickness: float = 25.4 / 8 flange_r0: float = 8.0 flange_r1: float = 20.0 flange_y1: float = 12.0 flange_y2: float = 25.0 flange_hole_r: float = 8.0 wing_x1: float = 15.0 wing_x2: float = 24.0 wing_r1: float = 10.0 wing_r2: float = 16.0 tail_r0: float = 8.0 tail_r1: float = 13.0 tail_y1: float = 16.0 tail_y2: float = 29.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 """ yt = 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 ( Cq.Sketch() .ellipse(self.width/2, self.height/2) .boolean(flange, mode="a") .boolean(tail, mode="a") .boolean(self.profile_wing(-1), mode="a") .boolean(self.profile_wing(1), mode="a") ) 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: rx = self.width/2 - self.outer_gap ry = self.height/2 - self.outer_gap return ( self.profile_casing_bot() .ellipse(rx, ry, mode="s") ) 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) ) )