Source code for boxes.generators.coffeecapsulesholder

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2021 Guillaume Collic
#
#   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/>.

import math
from boxes import Boxes, boolarg


[docs]class CoffeeCapsuleHolder(Boxes): """ Coffee capsule holder """ ui_group = "Misc" description = """ You can store your coffee capsule near your expresso machine with this. It works both vertically, or upside down under a shelf. """ def __init__(self): Boxes.__init__(self) self.argparser.add_argument( "--columns", type=int, default=4, help="Number of columns of capsules.", ) self.argparser.add_argument( "--rows", type=int, default=5, help="Number of capsules by columns.", ) self.argparser.add_argument( "--backplate", type=boolarg, default=True, help="True if a backplate should be generated.", ) def render(self): self.lid_size = 37 self.lid_size_with_margin = 39 self.body_size = 30 self.column_spacing = 5 self.corner_radius = 3 self.screw_margin = 6 self.outer_margin = 7 # Add space for the opening. A full row is not necessary for it. self.rows = self.rows + 0.6 self.render_plate(screw_hole=7, hole_renderer=self.render_front_hole) self.render_plate(hole_renderer=self.render_middle_hole) if self.backplate: self.render_plate() def render_plate(self, screw_hole=3.5, hole_renderer=None, move="right"): width = ( self.columns * (self.lid_size_with_margin + self.column_spacing) - self.column_spacing + 2 * self.outer_margin ) height = self.rows * self.lid_size + 2 * self.outer_margin if self.move(width, height, move, True): return with self.saved_context(): self.moveTo(self.corner_radius) self.polyline( width - 2 * self.corner_radius, (90, self.corner_radius), height - 2 * self.corner_radius, (90, self.corner_radius), width - 2 * self.corner_radius, (90, self.corner_radius), height - 2 * self.corner_radius, (90, self.corner_radius), ) if hole_renderer: for col in range(self.columns): with self.saved_context(): self.moveTo( self.outer_margin + col * (self.lid_size_with_margin + self.column_spacing) - self.burn, self.outer_margin + (self.rows - 0.5) * self.lid_size + self.burn, -90, ) hole_renderer() if screw_hole: for x in [self.screw_margin, width - self.screw_margin]: for y in [self.screw_margin, height - self.screw_margin]: self.hole(x, y + self.burn, d=screw_hole) self.move(width, height, move) def render_front_hole(self): radians = math.acos(self.body_size / self.lid_size_with_margin) height_difference = (self.lid_size / 2) * math.sin(radians) degrees = math.degrees(radians) half = [ 0, (degrees, self.lid_size_with_margin / 2), 0, -degrees, (self.rows - 1) * self.lid_size - height_difference, ] path = ( half + [(180, self.body_size / 2)] + list(reversed(half)) + [(180, self.lid_size_with_margin / 2)] ) self.polyline(*path) def render_middle_hole(self): half = [(self.rows - 1) * self.lid_size, (180, self.lid_size_with_margin / 2)] path = half * 2 self.polyline(*path)