diff --git a/boxes/generators/halfbox.py b/boxes/generators/halfbox.py new file mode 100644 index 0000000..83db9d0 --- /dev/null +++ b/boxes/generators/halfbox.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +# Copyright (C) 2013-2016 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 HalfBox(Boxes): + """Configurable half of a box which can be: a bookend, a hanging shelf, an angle clamping jig, ...""" + + description = """This can be used to create: + +* a hanging shelf: +![HalfBox as hanging shelf](static/samples/HalfBox_Shelf_usage.jpg) + +* an angle clamping jig: +![HalfBox as an angle clamping jig](static/samples/HalfBox_AngleJig_usage.jpg) + +* a bookend: +![HalfBox as a bookend](static/samples/HalfBox_Bookend_usage.jpg) + +and many more... + +""" + ui_group = "Box" + + def __init__(self): + Boxes.__init__(self) + + self.addSettingsArgs(edges.FingerJointSettings, finger=2.0,space=2.0) + self.addSettingsArgs(edges.MountingSettings) + self.buildArgParser(x=100, sy="50:50", h=100) + + self.argparser.add_argument("--Clamping", action="store", type=boolarg, default=False, help="add clamping holes") + self.argparser.add_argument("--ClampingSize", action="store", type=float, default=25.0, help="diameter of clamping holes") + self.argparser.add_argument("--Mounting", action="store", type=boolarg, default=False, help="add mounting holes") + self.argparser.add_argument("--Sturdy", action="store", type=boolarg, default=False, help="create sturdy construction (e.g. shelf, clamping jig, ...)") + + def polygonWallExt(self, borders, edge="f", turtle=False, callback=None, move=None): + # extended polygon wall. + # same as polygonWall, but with extended border parameters + # each border dataset consists of + # length + # turn angle + # radius of turn (without radius correction) + # edge type + + for i in range(0, len(borders), 4): + self.cc(callback, i) + length = borders[i] + next_angle = borders[i+1] + next_radius = borders[i+2] + next_edge = borders[i+3] + + e = self.edges.get(next_edge, next_edge) + if i == 0: + self.moveTo(0,e.margin(),0) + e(length) + if self.debug: + self.hole(0, 0, 1, color=Color.ANNOTATIONS) + self.corner(next_angle, tabs=0, radius=next_radius) + + def xHoles(self): + posy = -0.5 * self.thickness + for y in self.sy[:-1]: + posy += y + self.thickness + self.fingerHolesAt(posy, 0, self.x) + + def hHoles(self): + posy = -0.5 * self.thickness + for y in reversed(self.sy[1:]): + posy += y + self.thickness + self.fingerHolesAt(posy, 0, self.h) + + def render(self): + # adjust to the variables you want in the local scope + + x, h = self.x, self.h + d = self.ClampingSize + t = self.thickness + + # triangle with sides: x (horizontal), h (upwards) and l + # angles: 90° between x & h + # b between h & l + # c between l & x + + l = math.sqrt(x * x + h * h) + b = math.degrees(math.asin(x / l)) + c = math.degrees(math.asin(h / l)) + if x > h: + if 90 + b + c < 179: + b = 180 - b + else: + if 90 + b + c < 179: + c = 180 - c + + # small triangle top: 2*t, h1, l1 + h1 = (2*t)/x*h + l1 = (2*t)/x*l + + # small triangle left: x2, 2*t, l2 + x2 = (2*t)/h*x + l2 = (2*t)/h*l + + # render your parts here + + if self.Sturdy: + width = sum(self.sy) + (len(self.sy) - 1) * t + self.rectangularWall(x, width, "fffe", callback=[None, self.xHoles, None, None], move="right", label="bottom") + self.rectangularWall(h, width, "fGfF" if self.Mounting else "fefF", callback=[None, None, None, self.hHoles], move="up", label="back") + self.rectangularWall(x, width, "fffe", callback=[None, self.xHoles, None, None], move="left only", label="invisible") + + for i in range(2): + self.move(x+x2+2*t + self.edges["f"].margin(), h+h1+2*t + self.edges["f"].margin(), "right", True, label="side " + str(i)) + self.polygonWallExt(borders=[x2, 0, 0, "e", x, 0, 0, "h",2*t, 90, 0, "e", 2*t, 0, 0, "e", h, 0, 0, "h",h1, 180-b, 0, "e", l+l1+l2, 180-c, 0, "e"]) + if self.Clamping: + self.hole(0, 0, 1, color=Color.ANNOTATIONS) + self.rectangularHole(x/2+x2,2*t+d/2,dx=d,dy=d,r=d/8) + self.rectangularHole((x+x2+2*t)-2*t-d/2,h/2+2*t,dx=d,dy=d,r=d/8) + self.move(x+x2+2*t + self.edges["f"].margin(), h+h1+2*t + self.edges["f"].margin(), "right", False, label="side " + str(i)) + + if len(self.sy) > 1: + for i in range((len(self.sy) - 1)): + self.move(x + self.edges["f"].margin(), h + self.edges["f"].margin(), "right", True, label="support " + str(i)) + self.polygonWallExt(borders=[x, 90, 0, "f", h, 180-b, 0, "f", l, 180-c, 0, "e"]) + if self.Clamping: + self.rectangularHole(x/2,d/2-t/2,dx=d,dy=d+t,r=d/8) + self.rectangularHole(x-d/2+t/2,h/2,dx=d+t,dy=d,r=d/8) + self.move(x + self.edges["f"].margin(), h + self.edges["f"].margin(), "right", False, label="support " + str(i)) + else: + self.sy.insert(0,0) + self.sy.append(0) + width = sum(self.sy) + (len(self.sy) - 1) * t + self.rectangularWall(x, width, "efee", callback=[None, self.xHoles, None, None], move="right", label="bottom") + self.rectangularWall(h, width, "eGeF" if self.Mounting else "eeeF", callback=[None, None, None, self.hHoles], move="up", label="side") + self.rectangularWall(x, width, "efee", callback=[None, self.xHoles, None, None], move="left only", label="invisible") + + for i in range((len(self.sy) - 1)): + self.move(x + self.edges["f"].margin(), h + self.edges["f"].margin(), "right", True, label="support " + str(i)) + self.polygonWallExt(borders=[x, 90, 0, "f", h, 180-b, 0, "f", l, 180-c, 0, "e"]) + if self.Clamping: + self.rectangularHole(x/2,d/2,dx=d,dy=d,r=d/8) + self.rectangularHole(x-d/2,h/2,dx=d,dy=d,r=d/8) + self.move(x + self.edges["f"].margin(), h + self.edges["f"].margin(), "right", False, label="support " + str(i)) diff --git a/static/samples/HalfBox-thumb.jpg b/static/samples/HalfBox-thumb.jpg new file mode 100644 index 0000000..a74f7c2 Binary files /dev/null and b/static/samples/HalfBox-thumb.jpg differ diff --git a/static/samples/HalfBox.jpg b/static/samples/HalfBox.jpg new file mode 100644 index 0000000..05183dd Binary files /dev/null and b/static/samples/HalfBox.jpg differ diff --git a/static/samples/HalfBox_AngleJig_usage-thumb.jpg b/static/samples/HalfBox_AngleJig_usage-thumb.jpg new file mode 100644 index 0000000..f1c08a1 Binary files /dev/null and b/static/samples/HalfBox_AngleJig_usage-thumb.jpg differ diff --git a/static/samples/HalfBox_AngleJig_usage.jpg b/static/samples/HalfBox_AngleJig_usage.jpg new file mode 100644 index 0000000..e4700da Binary files /dev/null and b/static/samples/HalfBox_AngleJig_usage.jpg differ diff --git a/static/samples/HalfBox_Bookend_usage-thumb.jpg b/static/samples/HalfBox_Bookend_usage-thumb.jpg new file mode 100644 index 0000000..f5ab223 Binary files /dev/null and b/static/samples/HalfBox_Bookend_usage-thumb.jpg differ diff --git a/static/samples/HalfBox_Bookend_usage.jpg b/static/samples/HalfBox_Bookend_usage.jpg new file mode 100644 index 0000000..a03ec4a Binary files /dev/null and b/static/samples/HalfBox_Bookend_usage.jpg differ diff --git a/static/samples/HalfBox_Shelf_usage-thumb.jpg b/static/samples/HalfBox_Shelf_usage-thumb.jpg new file mode 100644 index 0000000..44844a2 Binary files /dev/null and b/static/samples/HalfBox_Shelf_usage-thumb.jpg differ diff --git a/static/samples/HalfBox_Shelf_usage.jpg b/static/samples/HalfBox_Shelf_usage.jpg new file mode 100644 index 0000000..4a5caad Binary files /dev/null and b/static/samples/HalfBox_Shelf_usage.jpg differ diff --git a/static/samples/samples.sha256 b/static/samples/samples.sha256 index 748d0c8..2a5e3c4 100644 --- a/static/samples/samples.sha256 +++ b/static/samples/samples.sha256 @@ -99,3 +99,7 @@ e90b4a90c1dbd2a4a03e4cf50ba82bc7119b721bd5c90c5fdbd0a356c9eabfd3 ../static/samp 0580043276c800c68dfba840d47c27f974ef2d0629751ecd250df2400f03cca8 ../static/samples/CanStorage.jpg bb250512410c007a74f91caee4e25eac817021f5a535987a7f5ff46148a074ca ../static/samples/MagazinFile.jpg 59c29899a7f6cfa1727830b35ba621747bf1fe16b8559884054bf50235559a11 ../static/samples/CoinDisplay.jpg +c21b47963a9de686eec4bcdb04dc84a64fef1e943d9c276f6ecb7d619af22791 ../static/samples/HalfBox_Shelf_usage.jpg +3bdbb6dab2beea4dcdcf84941bf1f763bc9eb60ca9369965c4b003d5bb57f83b ../static/samples/HalfBox_AngleJig_usage.jpg +9a0c0bf1d3b74a1e09f278ad9f89d8b7e59261a870bb60ed547d45117594cf93 ../static/samples/HalfBox.jpg +e1e5001ad1c59e0815a684f2eb2d25bb88113423ec6b582fb81f835c25947127 ../static/samples/HalfBox_Bookend_usage.jpg