diff --git a/nhf/touhou/shiki_eiki/crown.py b/nhf/touhou/shiki_eiki/crown.py index 2dcb300..7e8f7ad 100644 --- a/nhf/touhou/shiki_eiki/crown.py +++ b/nhf/touhou/shiki_eiki/crown.py @@ -22,6 +22,8 @@ class Crown(Model): side_guard_thickness: float = 15.0 side_guard_channel_radius: float = 90 side_guard_channel_height: float = 10 + side_guard_hole_height: float = 15.0 + side_guard_hole_diam: float = 1.5 material: Material = Material.METAL_BRASS material_side: Material = Material.PLASTIC_PLA @@ -356,7 +358,24 @@ class Crown(Model): ) return sketch.assemble() - def side_guard(self) -> Cq.Workplane: + def side_guard_dovetail(self) -> Cq.Solid: + """ + Generates a dovetail coupling for the side guard + """ + dx = self.side_guard_thickness / 2 + wire = Cq.Wire.makePolygon([ + (dx * 0.5, 0), + (dx * 0.8, dx), + (-dx * 0.8, dx), + (-dx * 0.5, 0), + ], close=True) + return Cq.Solid.extrudeLinear( + wire, + [], + (0,0,self.height/3), + ) + + def side_guard(self, attach_left: bool = True, attach_right: bool = False) -> Cq.Workplane: """ Constructs the side guard using a cone. Via Gauss's Theorema Egregium, the surface of the cone can be deformed into a plane. @@ -374,11 +393,8 @@ class Crown(Model): height=self.height, angleDegrees=angle, ) - shell = ( - outer.cut(inner) - .rotate((0,0,0), (0,0,1), -angle/2) - ) - dx = math.sin(math.radians(angle / 2)) * self.radius_middle + shell = (outer - inner).rotate((0,0,0), (0,0,1), -angle/2) + dx = math.sin(math.radians(angle / 2)) * (self.radius_middle + self.side_guard_thickness) profile = ( Cq.Workplane('YZ') .polyline([ @@ -401,7 +417,24 @@ class Crown(Model): height=self.side_guard_channel_height, ) ) - return shell * profile - channel + result = shell * profile - channel + for i in [-2, -1, 0, 1, 2]: + phi = i * (math.pi / 14) + hole = Cq.Solid.makeCylinder( + radius=self.side_guard_hole_diam / 2, + height=self.radius_upper * 2, + pnt=(0, 0, self.side_guard_hole_height), + dir=(math.cos(phi), math.sin(phi), 0), + ) + result = result - hole + + radius_attach = self.radius_lower + self.side_guard_thickness / 2 + # tilt the dovetail by radius differential + angle_tilt = math.degrees(math.atan2(self.radius_middle - self.radius_lower, self.height / 2)) + print(angle_tilt) + dovetail = self.side_guard_dovetail() + loc_dovetail = Cq.Location.rot2d(angle / 2) * Cq.Location(radius_attach, 0, 0, 0, angle_tilt, 0) * Cq.Location.rot2d(180) + return result - dovetail.moved(loc_dovetail) def front_surrogate(self) -> Cq.Workplane: """