Adding Grooved Edge (z, Z), example use in UnevenHeightBox

This commit is contained in:
Marcin Zukowski 2020-09-28 14:45:54 -07:00 committed by Florian Festi
parent f38819307b
commit dfc2f075d9
3 changed files with 154 additions and 9 deletions

View File

@ -541,6 +541,9 @@ class Boxes:
# Rounded Triangle Edge
edges.RoundedTriangleEdgeSettings(self.thickness, True,
**self.edgesettings.get("RoundedTriangleEdge", {})).edgeObjects(self)
# Grooved Edge
edges.GroovedSettings(self.thickness, True,
**self.edgesettings.get("Grooved", {})).edgeObjects(self)
# HexHoles
self.hexHolesSettings = HexHolesSettings(self.thickness, True,

View File

@ -342,6 +342,137 @@ class OutSetEdge(Edge):
return self.boxes.thickness
#############################################################################
#### GroovedEdge
#############################################################################
class GroovedSettings(Settings):
"""Settings for Grooved Edge
Values:
* absolute_params
* style : "arc" : the style of grooves
* tri_angle : 30 : the angle of triangular cuts
* arc_angle : 120 : the angle of arc cuts
* width : 0.2 : the width of each groove (fraction of the edge length)
* gap : 0.1 : the gap between grooves (fraction of the edge length)
* margin : 0.3 : minimum space left and right without grooves (fraction of the edge length)
* inverse : False : invert the groove directions
* interleave : False : alternate the direction of grooves
"""
PARAM_ARC = "arc"
PARAM_FLAT = "flat"
PARAM_SOFTARC = "softarc"
PARAM_TRIANGLE = "triangle"
absolute_params = {
"style": (PARAM_ARC, PARAM_FLAT, PARAM_TRIANGLE, PARAM_SOFTARC),
"tri_angle": 30,
"arc_angle": 120,
"width": 0.2,
"gap": 0.1,
"margin": 0.3,
"inverse": False,
"interleave": False,
}
def edgeObjects(self, boxes, chars="zZ", add=True):
edges = [GroovedEdge(boxes, self),
GroovedEdgeCounterPart(boxes, self)]
return self._edgeObjects(edges, boxes, chars, add)
class GroovedEdgeBase(BaseEdge):
def is_inverse(self):
return self.settings.inverse != self.inverse
def __call__(self, length, **kw):
if length == 0.0:
return
def check_bounds(val, mn, mx, name):
if not mn <= val <= mx:
raise ValueError(f"{name} needs to be in [{mn}, {mx}] but is {val}")
style = self.settings.style
width = self.settings.width
margin = self.settings.margin
gap = self.settings.gap
interleave = self.settings.interleave
check_bounds(width, 0, 1, "width")
check_bounds(margin, 0, 0.5, "margin")
check_bounds(gap, 0, 1, "gap")
# Check how many grooves fit
count = max(0, int((1 - 2 * margin + gap) / (width + gap)))
inside_width = max(0, count * (width + gap) - gap)
margin = (1 - inside_width) / 2
# Convert to actual length
margin = length * margin
gap = length * gap
width = length * width
# Determine the initial inversion
inv = 1 if self.is_inverse() else -1
if interleave and self.inverse and count % 2 == 0:
inv = -inv
# The edge until the first groove
self.edge(margin, tabs=1)
# Grooves
for i in range(count):
if i > 0:
self.edge(gap)
if interleave:
inv = -inv
if style == GroovedSettings.PARAM_FLAT:
self.edge(width)
elif style == GroovedSettings.PARAM_ARC:
angle = self.settings.arc_angle / 2
side_length = width / math.sin(math.radians(angle)) / 2
self.corner(inv * -angle)
self.corner(inv * angle, side_length)
self.corner(inv * angle, side_length)
self.corner(inv * -angle)
elif style == GroovedSettings.PARAM_SOFTARC:
angle = self.settings.arc_angle / 2
side_length = width / math.sin(math.radians(angle)) / 4
self.corner(inv * -angle, side_length)
self.corner(inv * angle, side_length)
self.corner(inv * angle, side_length)
self.corner(inv * -angle, side_length)
elif style == GroovedSettings.PARAM_TRIANGLE:
angle = self.settings.tri_angle
side_length = width / math.cos(math.radians(angle)) / 2
self.corner(inv * -angle)
self.edge(side_length)
self.corner(inv * 2 * angle)
self.edge(side_length)
self.corner(inv * -angle)
else:
raise ValueError("Unknown GroovedEdge style: %s)" % style)
# The final edge
self.edge(margin, tabs=1)
class GroovedEdge(GroovedEdgeBase):
description = """Edge with grooves"""
char = 'z'
inverse = False
class GroovedEdgeCounterPart(GroovedEdgeBase):
description = """Edge with grooves (opposing side)"""
char = 'Z'
inverse = True
#############################################################################
#### Gripping Edge
#############################################################################

View File

@ -25,6 +25,7 @@ class UnevenHeightBox(Boxes):
def __init__(self):
Boxes.__init__(self)
self.addSettingsArgs(edges.FingerJointSettings)
self.addSettingsArgs(edges.GroovedSettings)
self.buildArgParser("x", "y", "outside", bottom_edge="F")
self.argparser.add_argument(
"--height0", action="store", type=float, default=50,
@ -44,12 +45,19 @@ class UnevenHeightBox(Boxes):
self.argparser.add_argument(
"--lid_height", action="store", type=float, default=0,
help="additional height of the lid")
self.argparser.add_argument(
"--edge_types", action="store", type=str, default="eeee",
help="which edges are flat (e) or grooved (z,Z), counter-clockwise from the front")
def render(self):
x, y = self.x, self.y
heights = [self.height0, self.height1, self.height2, self.height3]
edge_types = self.edge_types
if len(edge_types) != 4 or any(et not in "ezZ" for et in edge_types):
raise ValueError("Wrong edge_types style: %s)" % edge_types)
if self.outside:
x = self.adjustSize(x)
y = self.adjustSize(y)
@ -61,10 +69,10 @@ class UnevenHeightBox(Boxes):
h0, h1, h2, h3 = heights
b = self.bottom_edge
self.trapezoidWall(x, h0, h1, [b, "F", "e", "F"], move="right")
self.trapezoidWall(y, h1, h2, [b, "f", "e", "f"], move="right")
self.trapezoidWall(x, h2, h3, [b, "F", "e", "F"], move="right")
self.trapezoidWall(y, h3, h0, [b, "f", "e", "f"], move="right")
self.trapezoidWall(x, h0, h1, [b, "F", edge_types[0], "F"], move="right")
self.trapezoidWall(y, h1, h2, [b, "f", edge_types[1], "f"], move="right")
self.trapezoidWall(x, h2, h3, [b, "F", edge_types[2], "F"], move="right")
self.trapezoidWall(y, h3, h0, [b, "f", edge_types[3], "f"], move="right")
with self.saved_context():
if b != "e":
@ -79,14 +87,17 @@ class UnevenHeightBox(Boxes):
self.rectangularWall(x, y, edges, move="up")
if self.lid:
self.moveTo(0, maxh+self.lid_height+self.edges["F"].spacing()+self.edges[b].spacing()+3*self.spacing, 180)
self.trapezoidWall(y, h0, h3, "Ffef", move="right" +
self.moveTo(0, maxh+self.lid_height+self.edges["F"].spacing()+self.edges[b].spacing()+1*self.spacing, 180)
edge_inverse = {"e": "e", "z": "Z", "Z": "z"}
edge_types = [edge_inverse[et] for et in edge_types]
self.trapezoidWall(y, h0, h3, "Ff" + edge_types[3] + "f", move="right" +
(" only" if h0 == h3 == 0.0 else ""))
self.trapezoidWall(x, h3, h2, "FFeF", move="right" +
self.trapezoidWall(x, h3, h2, "FF" + edge_types[2] + "F", move="right" +
(" only" if h3 == h2 == 0.0 else ""))
self.trapezoidWall(y, h2, h1, "Ffef", move="right" +
self.trapezoidWall(y, h2, h1, "Ff" + edge_types[1] + "f", move="right" +
(" only" if h2 == h1 == 0.0 else ""))
self.trapezoidWall(x, h1, h0, "FFeF", move="right" +
self.trapezoidWall(x, h1, h0, "FF" + edge_types[0] + "F", move="right" +
(" only" if h1 == h0 == 0.0 else ""))