Cleanup dovetail geometry
This commit is contained in:
parent
e1893d139f
commit
0991b39d8a
|
@ -1,10 +1,17 @@
|
||||||
import math
|
|
||||||
from dataclasses import dataclass, field
|
|
||||||
import cadquery as Cq
|
|
||||||
from nhf import Material, Role
|
from nhf import Material, Role
|
||||||
from nhf.build import Model, target, assembly, TargetKind
|
from nhf.build import Model, target, assembly, TargetKind
|
||||||
import nhf.utils
|
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
|
@dataclass
|
||||||
class Crown(Model):
|
class Crown(Model):
|
||||||
|
|
||||||
|
@ -24,6 +31,7 @@ class Crown(Model):
|
||||||
side_guard_channel_height: float = 10
|
side_guard_channel_height: float = 10
|
||||||
side_guard_hole_height: float = 15.0
|
side_guard_hole_height: float = 15.0
|
||||||
side_guard_hole_diam: float = 1.5
|
side_guard_hole_diam: float = 1.5
|
||||||
|
side_guard_dovetail_height: float = 30.0
|
||||||
|
|
||||||
material: Material = Material.METAL_BRASS
|
material: Material = Material.METAL_BRASS
|
||||||
material_side: Material = Material.PLASTIC_PLA
|
material_side: Material = Material.PLASTIC_PLA
|
||||||
|
@ -365,36 +373,36 @@ class Crown(Model):
|
||||||
dx = self.side_guard_thickness / 2
|
dx = self.side_guard_thickness / 2
|
||||||
wire = Cq.Wire.makePolygon([
|
wire = Cq.Wire.makePolygon([
|
||||||
(dx * 0.5, 0),
|
(dx * 0.5, 0),
|
||||||
(dx * 0.8, dx),
|
(dx * 0.7, dx),
|
||||||
(-dx * 0.8, dx),
|
(-dx * 0.7, dx),
|
||||||
(-dx * 0.5, 0),
|
(-dx * 0.5, 0),
|
||||||
], close=True)
|
], close=True)
|
||||||
return Cq.Solid.extrudeLinear(
|
return Cq.Solid.extrudeLinear(
|
||||||
wire,
|
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,
|
Constructs the side guard using a cone. Via Gauss's Theorema Egregium,
|
||||||
the surface of the cone can be deformed into a plane.
|
the surface of the cone can be deformed into a plane.
|
||||||
"""
|
"""
|
||||||
angle = 360 / 5
|
angle_span = 360 / 5
|
||||||
outer = Cq.Solid.makeCone(
|
outer = Cq.Solid.makeCone(
|
||||||
radius1=self.radius_lower + self.side_guard_thickness,
|
radius1=self.radius_lower + self.side_guard_thickness,
|
||||||
radius2=self.radius_upper + self.side_guard_thickness,
|
radius2=self.radius_upper + self.side_guard_thickness,
|
||||||
height=self.height,
|
height=self.height,
|
||||||
angleDegrees=angle,
|
angleDegrees=angle_span,
|
||||||
)
|
)
|
||||||
inner = Cq.Solid.makeCone(
|
inner = Cq.Solid.makeCone(
|
||||||
radius1=self.radius_lower,
|
radius1=self.radius_lower,
|
||||||
radius2=self.radius_upper,
|
radius2=self.radius_upper,
|
||||||
height=self.height,
|
height=self.height,
|
||||||
angleDegrees=angle,
|
angleDegrees=angle_span,
|
||||||
)
|
)
|
||||||
shell = (outer - inner).rotate((0,0,0), (0,0,1), -angle/2)
|
shell = (outer - inner).rotate((0,0,0), (0,0,1), -angle_span/2)
|
||||||
dx = math.sin(math.radians(angle / 2)) * (self.radius_middle + self.side_guard_thickness)
|
dx = math.sin(math.radians(angle_span / 2)) * (self.radius_middle + self.side_guard_thickness)
|
||||||
profile = (
|
profile = (
|
||||||
Cq.Workplane('YZ')
|
Cq.Workplane('YZ')
|
||||||
.polyline([
|
.polyline([
|
||||||
|
@ -408,16 +416,16 @@ class Crown(Model):
|
||||||
.extrude(self.radius_upper + self.side_guard_thickness)
|
.extrude(self.radius_upper + self.side_guard_thickness)
|
||||||
.val()
|
.val()
|
||||||
)
|
)
|
||||||
channel = (
|
#channel = (
|
||||||
Cq.Solid.makeCylinder(
|
# Cq.Solid.makeCylinder(
|
||||||
radius=self.side_guard_channel_radius + 1.0,
|
# radius=self.side_guard_channel_radius + 1.0,
|
||||||
height=self.side_guard_channel_height,
|
# height=self.side_guard_channel_height,
|
||||||
) - Cq.Solid.makeCylinder(
|
# ) - Cq.Solid.makeCylinder(
|
||||||
radius=self.side_guard_channel_radius,
|
# radius=self.side_guard_channel_radius,
|
||||||
height=self.side_guard_channel_height,
|
# height=self.side_guard_channel_height,
|
||||||
)
|
# )
|
||||||
)
|
#)
|
||||||
result = shell * profile - channel
|
result = shell * profile# - channel
|
||||||
for i in [-2, -1, 0, 1, 2]:
|
for i in [-2, -1, 0, 1, 2]:
|
||||||
phi = i * (math.pi / 14)
|
phi = i * (math.pi / 14)
|
||||||
hole = Cq.Solid.makeCylinder(
|
hole = Cq.Solid.makeCylinder(
|
||||||
|
@ -431,10 +439,45 @@ class Crown(Model):
|
||||||
radius_attach = self.radius_lower + self.side_guard_thickness / 2
|
radius_attach = self.radius_lower + self.side_guard_thickness / 2
|
||||||
# tilt the dovetail by radius differential
|
# tilt the dovetail by radius differential
|
||||||
angle_tilt = math.degrees(math.atan2(self.radius_middle - self.radius_lower, self.height / 2))
|
angle_tilt = math.degrees(math.atan2(self.radius_middle - self.radius_lower, self.height / 2))
|
||||||
print(angle_tilt)
|
|
||||||
dovetail = self.side_guard_dovetail()
|
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)
|
loc_dovetail_left = Cq.Location.rot2d(angle_span / 2) * Cq.Location(radius_attach, 0, 0, 0, angle_tilt, 0)
|
||||||
return result - dovetail.moved(loc_dovetail)
|
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:
|
def front_surrogate(self) -> Cq.Workplane:
|
||||||
"""
|
"""
|
||||||
|
@ -478,7 +521,7 @@ class Crown(Model):
|
||||||
"""
|
"""
|
||||||
New assembly using conformal mapping on the cone.
|
New assembly using conformal mapping on the cone.
|
||||||
"""
|
"""
|
||||||
side_guard = self.side_guard()
|
side_guard = self.side_guard_2()
|
||||||
a = Cq.Assembly()
|
a = Cq.Assembly()
|
||||||
for i in range(1,5):
|
for i in range(1,5):
|
||||||
a = a.addS(
|
a = a.addS(
|
||||||
|
|
Loading…
Reference in New Issue