diff --git a/boxes/generators/shadowbox.py b/boxes/generators/shadowbox.py new file mode 100644 index 00000000..e985c885 --- /dev/null +++ b/boxes/generators/shadowbox.py @@ -0,0 +1,110 @@ +# Copyright (C) 2024 Oliver Jensen +# +# 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 Shadowbox(Boxes): + """The frame and spacers necessary to display a shadowbox / lightbox.""" + + description = """ +The frame needed to build a shadowbox from paper cutouts. +The cutout used in the photographs can be downloaded [here](https://3axis.co/laser-cut-my-neighbor-totoro-3d-lightbox-lamp-cdr-file/eoxldrxo/). + +See the diagram below for dimensions. + +![diagram](static/samples/Shadowbox-diagram.jpg) + +![backlit](static/samples/Shadowbox-backlit.jpg) +""" + + ui_group = "Misc" + + def __init__(self) -> None: + Boxes.__init__(self) + self.addSettingsArgs(edges.FingerJointSettings) + self.addSettingsArgs(edges.DoveTailSettings, angle=10, depth=1.5, radius=0.1, size=1) + self.buildArgParser(x=200, y=260) + self.argparser.add_argument( + "--layers", action="store", type=int, default=7, + help="the number of paper layers; don't forget the back (blank) layer!") + self.argparser.add_argument( + "--framewidth", action="store", type=float, default=10, + help="the width of the paper layer frames") + self.argparser.add_argument( + "--frameheight", action="store", type=float, default=10, + help="the height of the paper layer frames") + self.argparser.add_argument( + "--extraheight", action="store", type=float, default=20, + help="cumulative height of your paper layers, play between frames, the LED strip, battery/wiring, anything else you want to fit in the case") + self.argparser.add_argument( + "--casejoinery", action="store", type=boolarg, default=True, + help="whether or not to join sides to front plate (disable if doing manual joins on fancy wood)") + + def render(self): + x, y = self.x, self.y + t = self.thickness + extraheight = self.extraheight + frameheight = self.frameheight + framewidth = self.framewidth + casejoinery = self.casejoinery + layers = self.layers + height = layers * t + extraheight + + # inner frames horizontal bars + for _ in range(2*layers): + self.polygonWall([ + x, 90, + frameheight, 90, + framewidth, 0, x - framewidth*2, 0, framewidth, 90, + frameheight, 90], + "eeDeDe", move="up") + + # inner frames vertical bars + for _ in range(2*layers): + self.rectangularWall(y - frameheight*2, framewidth, "eded", move="up") + + # faceplate + hypotenuse = math.sqrt((frameheight+t)**2 + (framewidth+t)**2) + angle = math.degrees(math.acos((framewidth+t) / hypotenuse)) + edgetypes = 'eFeeee' if casejoinery else 'eeeeee' + + vframe_poly = [ + t, 0, y, 0, t, 90+angle, + hypotenuse, 90-angle, + y - frameheight*2, 90-angle, + hypotenuse, 90+angle] + hframe_poly = [ + t, 0, x, 0, t, 90+angle, + hypotenuse, 90-angle, + x - framewidth*2, 90-angle, + hypotenuse, 90+angle] + + self.polygonWall(vframe_poly, edgetypes, move="up") + self.polygonWall(vframe_poly, edgetypes, move="up") + + angle = 90 - angle + self.polygonWall(hframe_poly, edgetypes, move="up") + self.polygonWall(hframe_poly, edgetypes, move="up") + + # case sides + if casejoinery: + top_edge = 'f' + else: + top_edge = 'e' + self.rectangularWall(x, height, f"ef{top_edge}f", move="up") + self.rectangularWall(x, height, f"ef{top_edge}f", move="up") + self.rectangularWall(y, height, f"eF{top_edge}F", move="up") + self.rectangularWall(y, height, f"eF{top_edge}F", move="up") diff --git a/static/samples/Shadowbox-backlit-thumb.jpg b/static/samples/Shadowbox-backlit-thumb.jpg new file mode 100644 index 00000000..3ac05583 Binary files /dev/null and b/static/samples/Shadowbox-backlit-thumb.jpg differ diff --git a/static/samples/Shadowbox-backlit.jpg b/static/samples/Shadowbox-backlit.jpg new file mode 100644 index 00000000..d8805d89 Binary files /dev/null and b/static/samples/Shadowbox-backlit.jpg differ diff --git a/static/samples/Shadowbox-diagram-thumb.jpg b/static/samples/Shadowbox-diagram-thumb.jpg new file mode 100644 index 00000000..a7f5d55c Binary files /dev/null and b/static/samples/Shadowbox-diagram-thumb.jpg differ diff --git a/static/samples/Shadowbox-diagram.jpg b/static/samples/Shadowbox-diagram.jpg new file mode 100644 index 00000000..f7d22d0b Binary files /dev/null and b/static/samples/Shadowbox-diagram.jpg differ diff --git a/static/samples/Shadowbox-thumb.jpg b/static/samples/Shadowbox-thumb.jpg new file mode 100644 index 00000000..ffd2794b Binary files /dev/null and b/static/samples/Shadowbox-thumb.jpg differ diff --git a/static/samples/Shadowbox.jpg b/static/samples/Shadowbox.jpg new file mode 100644 index 00000000..1a7e705e Binary files /dev/null and b/static/samples/Shadowbox.jpg differ