Source code for boxes.generators.nightlightbox

# 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 <http://www.gnu.org/licenses/>.

from boxes import *
from boxes.lids import _TopEdge

[docs] class NightLightBox(_TopEdge): """Simple decorative lamp with creatively laser cut plates""" ui_group = "Misc" description = "This is a simple light box with a closed compartment for electronics and the backlighting." def __init__(self) -> None: Boxes.__init__(self) self.addSettingsArgs(edges.FingerJointSettings, surroundingspaces=1) self.addSettingsArgs(edges.StackableSettings) self.addSettingsArgs(edges.HingeSettings, outset=True, pinwidth=0.4, style="flush", axle=2.5) self.argparser.add_argument( "--BoxStyle", action="store", type=str, default="large face", choices=["minimalist", "large face", "extra customizable face"], help="style of the front lock") self.argparser.add_argument( "--PlateVisibleWidth", action="store", type=float, default=150.0, help="width of the window in the front panel in mm") self.argparser.add_argument( "--PlateVisibleHeight", action="store", type=float, default=75.0, help="height of the window in the front panel in mm") self.argparser.add_argument( "--WoodPlatesCount", action="store", type=int, default=3, help="Number of decorative wood plates") self.argparser.add_argument( "--WoodPlateThickness", action="store", type=float, default=5.0, help="Thickness of the wood plates in mm") self.argparser.add_argument( "--DiffuserPlateThickness", action="store", type=float, default=5.0, help="Thickness of the background acrylic diffuser plate in mm") self.argparser.add_argument( "--BackgroundDepth", action="store", type=float, default=40.0, help="Depth of the background zone for the electronics and LEDs in mm") self.argparser.add_argument( "--InterPlateSpacing", action="store", type=float, default=10, help="Space between the decorative plates in mm") self.argparser.add_argument( "--hooks", action="store", type=boolarg, default=False, help="add hooks to decorative plates (allowing one sides plates)") self.argparser.add_argument( "--Margin", action="store", type=float, default=0.5, help="Margin for moving parts in mm") DiffuserPlateLock_group = self.argparser.add_argument_group("Night lightbox diffuser plate lock to prevent unwanted access to the electronics") DiffuserPlateLock_group.add_argument( "--DiffuserPlateTLockScrewDiameter", action="store", type=float, default=3.0, help="Diameter of the background acrylic diffuser plate locking screw hole in mm") DiffuserPlateLock_group.add_argument( "--DiffuserPlateTLockScrewLength", action="store", type=float, default=20.0, help="Length of the background acrylic diffuser plate locking screw in mm") DiffuserPlateLock_group.add_argument( "--DiffuserPlateTLockNutThickness", action="store", type=float, default=2.1, help="Thickness of the background acrylic diffuser plate locking nut in mm") DiffuserPlateLock_group.add_argument( "--DiffuserPlateTLockNutWidth", action="store", type=float, default=5.1, help="Width of the background acrylic diffuser plate locking nut in mm") BackSideOptions_group = self.argparser.add_argument_group("Night lightbox options for the back side (holes for connectors, marking)") BackSideOptions_group.add_argument( "--BackExtraHoles", action="store", type=str, default="R 20 15 11.5 8\nC 11.58 15 3\nC 28.42 15 3", help="extra holes for connectors or buttons ; enter one line per hole ; first parameter chould be R for rectangle or C for circle ; then X and Y position for the center of the hole, and then the X and Y size of the rectangle or the circle diameter, all in mm ; parameters should be separated by spaces") def railSlots(self, xSize, ySize): # to be updated t = self.thickness self.fingerHolesAt(t*1.5, self.InterPlateSpacing - t - self.Margin/2, t*2 + self.DiffuserPlateThickness + (self.InterPlateSpacing + self.WoodPlateThickness) * self.WoodPlatesCount) self.fingerHolesAt(xSize - (t*1.5), self.InterPlateSpacing - t - self.Margin/2, t*2 + self.DiffuserPlateThickness + (self.InterPlateSpacing + self.WoodPlateThickness) * self.WoodPlatesCount) def woodPlate(self, move=None, label=""): t = self.thickness if self.move(self.PlateVisibleWidth + t*(6 if self.BoxStyle == "minimalist" else 10), self.PlateVisibleHeight + t*(4 if self.BoxStyle == "minimalist" else 8), move, True): return # visible zone if self.BoxStyle == "minimalist" : self.rectangularHole(t*3, t*2, self.PlateVisibleWidth, self.PlateVisibleHeight, center_x=False, center_y=False, color=Color.ANNOTATIONS) else : self.rectangularHole(t*5, t*4, self.PlateVisibleWidth, self.PlateVisibleHeight, center_x=False, center_y=False, color=Color.ANNOTATIONS) self.moveTo(t + self.Margin/2, 0, 0) # bottom self.polyline(t - self.Margin, 90, t + self.Margin, -90, t + self.Margin, -90, t + self.Margin, 90, self.PlateVisibleWidth + t*(0 if self.BoxStyle == "minimalist" else 4) - self.Margin, 90, t + self.Margin, -90, t + self.Margin, -90, t + self.Margin, 90, t - self.Margin, 90) # right side self.polyline(self.PlateVisibleHeight + t*(2 if self.BoxStyle == "minimalist" else 6) + self.Margin, -90, t + self.Margin/2) if self.hooks: self.polyline(0, -90, t, 90, 0, (90, t), t, (90, t)) else: self.polyline(0, 90, t*2 - self.Margin*2, 90) # top self.polyline(self.PlateVisibleWidth + t*(6 if self.BoxStyle == "minimalist" else 10)) # left side if self.hooks: self.polyline(0, (90, t), t, (90, t), 0, 90, t, -90) else: self.polyline(0, 90, t*2 - self.Margin*2, 90) self.polyline(t + self.Margin/2, -90, self.PlateVisibleHeight + t*(2 if self.BoxStyle == "minimalist" else 6) + self.Margin, 90) # move plate self.move(self.PlateVisibleWidth + t*(6 if self.BoxStyle == "minimalist" else 10), self.PlateVisibleHeight + t*(4 if self.BoxStyle == "minimalist" else 8), move, label=label) def boltAndScrewHole(self): t = self.thickness self.polyline(0, 90, t, 90, self.DiffuserPlateTLockNutWidth/2 - self.DiffuserPlateTLockScrewDiameter/2, -90, self.DiffuserPlateTLockNutThickness, -90, self.DiffuserPlateTLockNutWidth/2 - self.DiffuserPlateTLockScrewDiameter/2, 90, self.DiffuserPlateTLockScrewLength - self.DiffuserPlateTLockNutThickness - t*2, -90, self.DiffuserPlateTLockScrewDiameter, -90, self.DiffuserPlateTLockScrewLength - self.DiffuserPlateTLockNutThickness - t*2, 90, self.DiffuserPlateTLockNutWidth/2 - self.DiffuserPlateTLockScrewDiameter/2, -90, self.DiffuserPlateTLockNutThickness, -90, self.DiffuserPlateTLockNutWidth/2 - self.DiffuserPlateTLockScrewDiameter/2, 90, t, 90) def diffuserPlate(self, move=None, label=""): t = self.thickness if self.move(self.PlateVisibleWidth + t*(4 if self.BoxStyle == "minimalist" else 8), self.PlateVisibleHeight + t*(4 if self.BoxStyle == "minimalist" else 8), move, True): return # bottom self.polyline(t - self.Margin, 90, t + self.Margin, -90, t + self.Margin, -90, t + self.Margin, 90, self.PlateVisibleWidth + t*(0 if self.BoxStyle == "minimalist" else 4) - self.Margin, 90, t + self.Margin, -90, t + self.Margin, -90, t + self.Margin, 90, t - self.Margin, 90) # right side self.edge(t*6 - self.DiffuserPlateTLockScrewDiameter/2) self.boltAndScrewHole() self.polyline(self.PlateVisibleHeight + t*(-2 if self.BoxStyle == "minimalist" else 2) - self.Margin - self.DiffuserPlateTLockScrewDiameter/2, 90) # top self.polyline(self.PlateVisibleWidth + t*(4 if self.BoxStyle == "minimalist" else 8) - self.Margin, 90) # left side self.edge(self.PlateVisibleHeight + t*(-2 if self.BoxStyle == "minimalist" else 2) - self.Margin - self.DiffuserPlateTLockScrewDiameter/2) self.boltAndScrewHole() self.polyline(t*6 - self.DiffuserPlateTLockScrewDiameter/2, 90) # move plate self.move(self.PlateVisibleWidth + t*(4 if self.BoxStyle == "minimalist" else 8), self.PlateVisibleHeight + t*(4 if self.BoxStyle == "minimalist" else 8), move, label=label) def elecCompartmentTop(self, move=None, label=""): t = self.thickness if self.move(t * 4 + self.PlateVisibleWidth + self.Margin, self.BackgroundDepth - t*2.5 - self.Margin, move, True): return # bottom self.polyline(t * (4 if self.BoxStyle == "minimalist" else 8) + self.PlateVisibleWidth + self.Margin, 90) # right side self.edge(t*1.5) self.edges["f"](self.BackgroundDepth - t*5 - self.Margin) self.corner(90) # top self.polyline(t * (4 if self.BoxStyle == "minimalist" else 8) + self.PlateVisibleWidth + self.Margin, 90) # left side self.edges["f"](self.BackgroundDepth - t*5 - self.Margin) self.polyline(t*1.5, 90) # move plate self.move(t * 4 + self.PlateVisibleWidth + self.Margin, self.BackgroundDepth - t*2.5 - self.Margin, move, label=label) def side(self, ySize, hSize, move=None, label=""): t = self.thickness be = self.edges["s"] # bottom edge if self.move(ySize + t, hSize + t*4, move, True): return # rectangular hole for background guiding if self.BoxStyle == "minimalist" : self.rectangularHole(ySize - self.BackgroundDepth - self.DiffuserPlateThickness - t - self.Margin*1.5, self.PlateVisibleHeight + t*4, t, t, center_x=False, center_y=False) else : self.rectangularHole(ySize - self.BackgroundDepth - self.DiffuserPlateThickness - t - self.Margin*1.5, self.PlateVisibleHeight + t*8, t, t, center_x=False, center_y=False) # round hole for background lock screw self.hole(ySize - self.BackgroundDepth - self.DiffuserPlateThickness/2 - self.Margin/2, t*10, self.DiffuserPlateTLockScrewDiameter/2) # bottom be(ySize) self.corner(90) # right side self.edge(be.endwidth()) self.edges["f"](hSize) self.corner(90) # top self.edges["i"].settings.style = "flush_inset" self.edges["i"](t*5) self.edges["F"](self.BackgroundDepth - t*5 - self.Margin/2) self.polyline(self.DiffuserPlateThickness + self.InterPlateSpacing + self.Margin/2, 90) for i in range(self.WoodPlatesCount): self.polyline(t*2 + self.Margin, -90, self.WoodPlateThickness + self.Margin, -90, t*2 + self.Margin, 90, self.InterPlateSpacing - self.Margin, 90) # left side self.edges["f"](hSize) self.edge(be.startwidth()) self.corner(90) # move plate self.move(ySize + t, hSize + t*8, move, label=label) def rail(self, move=None, label=""): t = self.thickness if self.move(self.WoodPlatesCount * (self.InterPlateSpacing + self.WoodPlateThickness) + self.DiffuserPlateThickness + t*2, t*3, move, True): return # bottom self.edges["f"](t*2 + self.DiffuserPlateThickness + (self.InterPlateSpacing + self.WoodPlateThickness) * self.WoodPlatesCount) self.corner(90) # right side self.polyline(t*2, 90) # top self.polyline(t - self.Margin/2, 90) for i in range(self.WoodPlatesCount): self.polyline(t + self.Margin, -90, self.WoodPlateThickness + self.Margin, -90, t + self.Margin, 90, self.InterPlateSpacing - self.Margin, 90) self.polyline(t + self.Margin, -90, self.DiffuserPlateThickness + self.Margin, -90, t + self.Margin, 90, t - self.Margin/2, 90) # left side self.polyline(t*2, 90) # move plate self.move(self.WoodPlatesCount * (self.InterPlateSpacing + self.WoodPlateThickness) + self.DiffuserPlateThickness + t*2, t*3, move, label=label) def backExtraHoles(self): # for each line, make a hole for line in self.BackExtraHoles.split("\n") : holeParams=line.split(" ") # rectangular hole if line[0] == "R" : self.rectangularHole(float(holeParams[1]), float(holeParams[2]), float(holeParams[3]), float(holeParams[4])) # round hole elif line[0] == "C" : self.hole(float(holeParams[1]), float(holeParams[2]), float(holeParams[3])/2) def render(self): t = self.thickness # define box inner depth y = self.BackgroundDepth + self.DiffuserPlateThickness + (self.WoodPlateThickness + self.InterPlateSpacing) * self.WoodPlatesCount + self.InterPlateSpacing #+ t*2 if self.BoxStyle == "minimalist" : # define box inner width x = t * 4 + self.PlateVisibleWidth + self.Margin # define box inner height h = self.PlateVisibleHeight + t * 4 + self.Margin else : # define box inner width x = t * 8 + self.PlateVisibleWidth + self.Margin # define box inner height h = self.PlateVisibleHeight + t * 8 + self.Margin self.ctx.save() # sides self.side(y, h, move="mirror", label="left") self.side(y, h, move="left up", label="right") #rails self.rail(move="up", label="rail") self.rail(move="up mirror", label="rail") # floor self.rectangularWall(x, y, "ffff", callback=[lambda:self.railSlots(x, y)], move="up", label="bottom") # back self.rectangularWall(x, h, "sFeF", callback=[lambda:self.backExtraHoles()], move="up", label="back") # front and optional customizable front face if self.BoxStyle == "extra customizable face" : self.rectangularWall(x, h, "sFeF", callback=[lambda:self.rectangularHole(self.PlateVisibleWidth/2 + t*4 + self.Margin/2,self.PlateVisibleHeight/2 + t*4,self.PlateVisibleWidth, self.PlateVisibleHeight), lambda:self.rectangularHole(t*1.5, t*1.5, t, t), lambda:self.rectangularHole(self.PlateVisibleWidth/2 + t*4 + self.Margin/2, t*1.5, t, t), lambda:self.rectangularHole(self.PlateVisibleHeight + t*6.5 + self.Margin, t*1.5, t, t)], move="up", label="front") self.rectangularWall(x, h, "EEEE", callback=[lambda:self.rectangularHole(self.PlateVisibleWidth/2 + t*4 + self.Margin/2,self.PlateVisibleHeight/2 + t*4,self.PlateVisibleWidth, self.PlateVisibleHeight, color=Color.ANNOTATIONS), lambda:self.rectangularHole(t*1.5, t*1.5, t, t), lambda:self.rectangularHole(self.PlateVisibleWidth/2 + t*4 + self.Margin/2, t*1.5, t, t), lambda:self.rectangularHole(self.PlateVisibleHeight + t*6.5 + self.Margin, t*1.5, t, t)], move="up", label="customizable face") self.rectangularWall(t*2, t, move="up") self.rectangularWall(t*2, t, move="up") elif self.BoxStyle == "minimalist" : self.rectangularWall(x, h, "sFeF", callback=[lambda:self.rectangularHole(self.PlateVisibleWidth/2 + t*2,self.PlateVisibleHeight/2 + t*2,self.PlateVisibleWidth, self.PlateVisibleHeight)], move="up", label="front") else: self.rectangularWall(x, h, "sFeF", callback=[lambda:self.rectangularHole(self.PlateVisibleWidth/2 + t*4,self.PlateVisibleHeight/2 + t*4,self.PlateVisibleWidth, self.PlateVisibleHeight)], move="up", label="front") # electronics compartment top self.elecCompartmentTop(move="up", label="elec. comp.") # difuser guides self.rectangularWall(t*2, t, "eeee", move="up", label="guide") self.rectangularWall(t*2, t, "eeee", move="up", label="guide") # top / lid self.drawLid(y - t, x, "i") # diffuser plate self.diffuserPlate(move="up", label="Diffuser") # wood plates with horizontal LEDs for i in range(self.WoodPlatesCount): self.woodPlate(move="up", label="Insert cut and\nengraved art here")