Cleanup dovetail geometry

This commit is contained in:
Leni Aniva 2025-03-05 09:48:21 -08:00
parent e1893d139f
commit 0991b39d8a
Signed by: aniva
GPG Key ID: 4D9B1C8D10EA4C50
1 changed files with 70 additions and 27 deletions

View File

@ -1,10 +1,17 @@
import math
from dataclasses import dataclass, field
import cadquery as Cq
from nhf import Material, Role
from nhf.build import Model, target, assembly, TargetKind
import nhf.utils
import math
from dataclasses import dataclass, field
from enum import Enum
import cadquery as Cq
class AttachPoint(Enum):
DOVETAIL_IN = 1
DOVETAIL_OUT = 2
NONE = 3
@dataclass
class Crown(Model):
@ -24,6 +31,7 @@ class Crown(Model):
side_guard_channel_height: float = 10
side_guard_hole_height: float = 15.0
side_guard_hole_diam: float = 1.5
side_guard_dovetail_height: float = 30.0
material: Material = Material.METAL_BRASS
material_side: Material = Material.PLASTIC_PLA
@ -365,36 +373,36 @@ class Crown(Model):
dx = self.side_guard_thickness / 2
wire = Cq.Wire.makePolygon([
(dx * 0.5, 0),
(dx * 0.8, dx),
(-dx * 0.8, dx),
(dx * 0.7, dx),
(-dx * 0.7, dx),
(-dx * 0.5, 0),
], close=True)
return Cq.Solid.extrudeLinear(
wire,
[],
(0,0,self.height/3),
)
(0,0,dx + self.side_guard_dovetail_height),
).moved((0, 0, -dx))
def side_guard(self, attach_left: bool = True, attach_right: bool = False) -> Cq.Workplane:
def side_guard(self, attach_left: AttachPoint, attach_right: AttachPoint) -> 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.
"""
angle = 360 / 5
angle_span = 360 / 5
outer = Cq.Solid.makeCone(
radius1=self.radius_lower + self.side_guard_thickness,
radius2=self.radius_upper + self.side_guard_thickness,
height=self.height,
angleDegrees=angle,
angleDegrees=angle_span,
)
inner = Cq.Solid.makeCone(
radius1=self.radius_lower,
radius2=self.radius_upper,
height=self.height,
angleDegrees=angle,
angleDegrees=angle_span,
)
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)
shell = (outer - inner).rotate((0,0,0), (0,0,1), -angle_span/2)
dx = math.sin(math.radians(angle_span / 2)) * (self.radius_middle + self.side_guard_thickness)
profile = (
Cq.Workplane('YZ')
.polyline([
@ -408,16 +416,16 @@ class Crown(Model):
.extrude(self.radius_upper + self.side_guard_thickness)
.val()
)
channel = (
Cq.Solid.makeCylinder(
radius=self.side_guard_channel_radius + 1.0,
height=self.side_guard_channel_height,
) - Cq.Solid.makeCylinder(
radius=self.side_guard_channel_radius,
height=self.side_guard_channel_height,
)
)
result = shell * profile - channel
#channel = (
# Cq.Solid.makeCylinder(
# radius=self.side_guard_channel_radius + 1.0,
# height=self.side_guard_channel_height,
# ) - Cq.Solid.makeCylinder(
# radius=self.side_guard_channel_radius,
# height=self.side_guard_channel_height,
# )
#)
result = shell * profile# - channel
for i in [-2, -1, 0, 1, 2]:
phi = i * (math.pi / 14)
hole = Cq.Solid.makeCylinder(
@ -431,10 +439,45 @@ class Crown(Model):
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)
loc_dovetail_left = Cq.Location.rot2d(angle_span / 2) * Cq.Location(radius_attach, 0, 0, 0, angle_tilt, 0)
loc_dovetail_right = Cq.Location.rot2d(-angle_span / 2) * Cq.Location(radius_attach, 0, 0, 0, angle_tilt, 0)
match attach_left:
case AttachPoint.DOVETAIL_IN:
loc_dovetail_left *= Cq.Location.rot2d(180)
result = result - dovetail.moved(loc_dovetail_left)
case AttachPoint.DOVETAIL_OUT:
result = result + dovetail.moved(loc_dovetail_left)
case AttachPoint.NONE:
pass
match attach_right:
case AttachPoint.DOVETAIL_IN:
result = result - dovetail.moved(loc_dovetail_right)
case AttachPoint.DOVETAIL_OUT:
loc_dovetail_right *= Cq.Location.rot2d(180)
result = result + dovetail.moved(loc_dovetail_right)
case AttachPoint.NONE:
pass
# Remove parts below the horizontal
cut_h = self.radius_lower
result -= Cq.Solid.makeCylinder(
radius=self.radius_lower + self.side_guard_thickness,
height=cut_h).moved((0,0,-cut_h))
return result
@target(name="side_guard_2")
def side_guard_2(self) -> Cq.Workplane:
return self.side_guard(
attach_left=AttachPoint.DOVETAIL_OUT,
attach_right=AttachPoint.DOVETAIL_IN,
)
@target(name="side_guard_3")
def side_guard_3(self) -> Cq.Workplane:
return self.side_guard(
attach_left=AttachPoint.DOVETAIL_IN,
attach_right=AttachPoint.DOVETAIL_IN,
)
def front_surrogate(self) -> Cq.Workplane:
"""
@ -478,7 +521,7 @@ class Crown(Model):
"""
New assembly using conformal mapping on the cone.
"""
side_guard = self.side_guard()
side_guard = self.side_guard_2()
a = Cq.Assembly()
for i in range(1,5):
a = a.addS(