# 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 <http://www.gnu.org/licenses/>.
from boxes import *
[docs]
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.


"""
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, 180-angle,
hypotenuse, angle,
x - framewidth*2, angle,
hypotenuse, 180-angle]
self.polygonWall(vframe_poly, edgetypes, move="up")
self.polygonWall(vframe_poly, edgetypes, move="up")
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")
# led strip holder
self.rectangularWall(x - 2*t, 10, "efef", move="up")
self.rectangularWall(x - 2*t, 10, "efef", move="up")
self.rectangularWall(y - 2*t, 10, "eFeF", move="up")
self.rectangularWall(y - 2*t, 10, "eFeF", move="up")