diff --git a/boxes/generators/compartmentbox.py b/boxes/generators/compartmentbox.py new file mode 100644 index 0000000..c2672a7 --- /dev/null +++ b/boxes/generators/compartmentbox.py @@ -0,0 +1,288 @@ +#!/usr/bin/env python3 +# Copyright (C) 2013-2014 Florian Festi +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from boxes import * + +class CompartmentBox(Boxes): + """Type tray variation with sliding lid""" + + description = """Sliding lid rests on inner walls, + so will not work if no inner walls are present. + Suggested to place walls close to both sides for maximum stability.""" + + ui_group = "Unstable" + + def __init__(self) -> None: + Boxes.__init__(self) + self.buildArgParser("sx", "sy", "h", "outside", "bottom_edge") + self.argparser.add_argument( + "--handle", action="store", type=str, default="lip", + choices={"none","lip","hole"}, + help="how to grab the lid to remove") + self.argparser.add_argument( + "--radius", action="store", type=float, default=10, + dest="radius", help="radius of the grip hole in mm") + self.argparser.add_argument( + "--holes", action="store", type=str, + default="70", + help="width of hole(s) in percentage of maximum hole width") + + + + + def xSlots(self): + posx = -0.5 * self.thickness + for x in self.sx[:-1]: + posx += x + self.thickness + posy = 0 + for y in self.sy: + self.fingerHolesAt(posx, posy, y) + posy += y + self.thickness + + def ySlots(self): + posy = -0.5 * self.thickness + for y in self.sy[:-1]: + posy += y + self.thickness + posx = 0 + for x in reversed(self.sx): + self.fingerHolesAt(posy, posx, x) + posx += x + self.thickness + + def xHoles(self): + posx = -0.5 * self.thickness + for x in self.sx[:-1]: + posx += x + self.thickness + self.fingerHolesAt(posx, 0, self.h) + + def yHoles(self): + posy = -0.5 * self.thickness + for y in self.sy[:-1]: + posy += y + self.thickness + self.fingerHolesAt(posy, 0, self.h) + + def render(self): + t = self.thickness + if self.outside: + self.sx = self.adjustSize(self.sx) + self.sy = self.adjustSize(self.sy) + self.h = self.adjustSize(self.h) - 2 * t + + + x = sum(self.sx) + self.thickness * (len(self.sx) - 1) + y = sum(self.sy) + self.thickness * (len(self.sy) - 1) + h = self.h + + + # Create new Edges here if needed E.g.: + s = edges.FingerJointSettings(self.thickness, relative=False, + style = "rectangular") + p = edges.FingerJointEdge(self, s) + p.char = "a" # 'a', 'A', 'b' and 'B' is reserved for beeing used within generators + self.addPart(p) + + # outer walls + b = self.bottom_edge + tl, tb, tr, tf = "FEFe" + tl, tb, tr, tf = "ŠSŠe" if b == "s" else "FEFe" + + + # x sides + + self.ctx.save() + + # outer walls - front/back + hb = h+t * (3 if tb == "S" else 1) + self.rectangularWall(x, hb, [b, "F", tb, "F"], + callback=[self.xHoles], + ignore_widths=[1,2,5,6], + move="up", label="back") + + self.rectangularWall(x, h, [b, "F", tf, "F"], + callback=[self.mirrorX(self.xHoles, x)], + ignore_widths=[1,6], + move="up", label="front") + + # floor + if b != "e": + self.rectangularWall(x, y, "ffff", callback=[self.xSlots, self.ySlots], move="up", label="bottom") + + # Inner walls + + be = "f" if b != "e" else "e" + + for i in range(len(self.sy) - 1): + e = [edges.SlottedEdge(self, self.sx, be), "f", + edges.SlottedEdge(self, self.sx[::-1], "e", slots=0.5 * h), "f"] + self.rectangularWall(x, h, e, move="up", label=f"inner x {i+1}") + + # top / lid + handle = self.handle + if handle == "lip": + self.rectangularWall(x, y, "feee", move="up", label="lid") + self.rectangularWall(x, t * (2 if b == "s" else 1), "fe" + ("S" if b == "s" else "e") + "e", move="up", label="lid lip") + if handle == "hole": + self.rectangularWall(x, y + t, move="up", label="lid", callback=[self.gripHole]) + if handle == "none": + self.rectangularWall(x, y + t, move="up", label="lid") + + + + self.ctx.restore() + self.rectangularWall(x, h, "ffff", move="right only") + + # y walls + + # outer walls - left/right + self.sideWall( + y, h+t, "left", [b, "f", tl, "f"], callback=[self.yHoles, ], + move="up", label="left side") + + self.sideWall( + y, h+t, "right", [b, "f", tr, "f"], + callback=[self.mirrorX(self.yHoles, y), ], + move="up", label="right side") + + # inner walls + for i in range(len(self.sx) - 1): + e = [edges.SlottedEdge(self, self.sy, be, slots=0.5 * h), + "f", "e", "f"] + self.rectangularWall(y, h, e, move="up", label=f"inner y {i+1}") + + lipy = y-t if self.handle == "lip" else y + self.rectangularWall(lipy, t, "eefe", move="up", label="Lip Left") + self.rectangularWall(lipy, t, "feee", move="up", label="Lip Right") + + def sideWall(self, x, y, side, edges="eeee", + holesMargin=None, holesSettings=None, + bedBolts=None, bedBoltSettings=None, + callback=None, + move=None, + label=""): + + if len(edges) != 4: + raise ValueError("four edges required") + if side not in {"left", "right"}: + raise ValueError("side must be left or right") + b = edges[0] + edges = [self.edges.get(e, e) for e in edges] + edges += edges # append for wrapping around + overallwidth = x + edges[-1].spacing() + edges[1].spacing() + overallheight = y + edges[0].spacing() + edges[2].spacing() + t = self.thickness + + if self.move(overallwidth, overallheight, move, before=True): + return + + self.moveTo(edges[-1].spacing(), edges[0].margin()) + + for i, l in enumerate((x, y, x, y)): + self.cc(callback, i, y=edges[i].startwidth() + self.burn) + e1, e2 = edges[i], edges[i + 1] + + if i == 3 and side == "right": + l -= t + self.edges.get('e')(t) + l += edges[i+1].startwidth() + e2 = self.edges["e"] + edges[i](l, + bedBolts=self.getEntry(bedBolts, i), + bedBoltSettings=self.getEntry(bedBoltSettings, i)) + elif i == 1 and side == "left": + l -= t + l += edges[i-1].startwidth() + edges[i](l, + bedBolts=self.getEntry(bedBolts, i), + bedBoltSettings=self.getEntry(bedBoltSettings, i)) + self.edges.get('e')(t) + else: + if i == 3 and side == "left": + l += edges[i+1].startwidth() + edges[i-1].startwidth() + e2 = self.edges["e"] + if i == 1 and side == "right": + l += edges[i+1].startwidth() + edges[i-1].startwidth() + e2 = self.edges["e"] + + if i == 2 and self.handle == "lip": + if b != "s": + l -= t + print(b) + if side == "left": + self.edges.get('e')(t) + edges[i](l, + bedBolts=self.getEntry(bedBolts, i), + bedBoltSettings=self.getEntry(bedBoltSettings, i)) + elif side == "right": + edges[i](l, + bedBolts=self.getEntry(bedBolts, i), + bedBoltSettings=self.getEntry(bedBoltSettings, i)) + self.edges.get('e')(t) + else: + self.edges.get('S')(l) + self.fingerHolesAt(0 if side == "left" else -t, 1.5*t, l-t, angle=180) + else: + edges[i](l, + bedBolts=self.getEntry(bedBolts, i), + bedBoltSettings=self.getEntry(bedBoltSettings, i)) + + if i == 2 and side == "left": + e1 = self.edges["e"] + if i == 0 and side == "right": + e1 = self.edges["e"] + if i == 0 and side == "left": + e1 = self.edges["e"] + + + self.edgeCorner(e1, e2, 90) + + if holesMargin is not None: + self.moveTo(holesMargin, + holesMargin + edges[0].startwidth()) + self.hexHolesRectangle(x - 2 * holesMargin, y - 2 * holesMargin, settings=holesSettings) + + self.move(overallwidth, overallheight, move, label=label) + + def gripHole(self): + if not self.radius: + return + radius = self.radius + t = self.thickness + widths = argparseSections(self.holes) + + x = sum(self.sx) + self.thickness * (len(self.sx) - 1) + + if sum(widths) > 0: + if sum(widths) < 100: + slot_offset = ((1 - sum(widths) / 100) * (x - (len(widths) + 1) * self.thickness)) / (len(widths) * 2) + else: + slot_offset = 0 + + slot_height = 2* radius # (self.settings.height - 2 * self.thickness) * self.settings.hole_height / 100 + slot_x = self.thickness + slot_offset + + for w in widths: + if sum(widths) > 100: + slotwidth = w / sum(widths) * (x - (len(widths) + 1) * self.thickness) + else: + slotwidth = w / 100 * (x - (len(widths) + 1) * self.thickness) + slot_x += slotwidth / 2 + + with self.saved_context(): + #self.moveTo(20, slot_x, 0) + self.rectangularHole(slot_x,radius+t,slotwidth,slot_height,radius,True,True) + slot_x += slotwidth / 2 + slot_offset + self.thickness + slot_offset + + +#todo stackable top/bottom \ No newline at end of file