This repository has been archived on 2023-03-25. You can view files and clone it, but cannot push or open issues or pull requests.
mightyscape-0.92-deprecated/extensions/fablabchemnitz_boxmaker.py
2019-11-14 20:09:28 +01:00

836 lines
40 KiB
Python

#! /usr/bin/env python
"""
Generates Inkscape SVG file containing box components needed to
laser cut a tabbed construction box taking kerf and clearance into account
Copyright (C) 2011 elliot white
Changelog:
19/12/2014 Paul Hutchison:
- Ability to generate 6, 5, 4, 3 or 2-panel cutouts
- Ability to also generate evenly spaced dividers within the box
including tabbed joints to box sides and slots to slot into each other
23/06/2015 by Paul Hutchison:
- Updated for Inkscape's 0.91 breaking change (unittouu)
v0.93 - 15/8/2016 by Paul Hutchison:
- Added Hairline option and fixed open box height bug
v0.94 - 05/01/2017 by Paul Hutchison:
- Added option for keying dividers into walls/floor/none
This program is ugly software: you can clean it up yourself and/or mock it
under the unpublished terms of common civility.
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/>.
"""
__version__ = "0.94" # please report bugs, suggestions etc at
# https://github.com/paulh-rnd/TabbedBoxMaker ###
import math
import os
import inkex
import simplestyle
try:
# This is the typing library for local dev. Can be ignored in production. :)
from typing import Tuple
except ImportError:
pass
inkex.localize()
DEFAULT_LINE_THICKNESS = 1 # default unless overridden by settings
def log(text):
if 'SCHROFF_LOG' in os.environ:
f = open(os.environ.get('SCHROFF_LOG'), 'a')
f.write(text + "\n")
def draw_lines(xy_string): # Draw lines from a list
name = 'part'
style = {'stroke' : '#000000',
'stroke-width': str(DEFAULT_LINE_THICKNESS),
'fill' : 'none'}
drw = {'style' : simplestyle.formatStyle(style),
inkex.addNS('label', 'inkscape'): name, 'd': xy_string}
inkex.etree.SubElement(parent, inkex.addNS('path', 'svg'), drw)
return
# jslee - shamelessly adapted from sample code on below Inkscape wiki page 2015-07-28
# http://wiki.inkscape.org/wiki/index.php/Generating_objects_from_extensions
def draw_circle(r, cx, cy):
log("putting circle at ({},{})".format(cx, cy))
style = {'stroke' : '#000000',
'stroke-width': str(DEFAULT_LINE_THICKNESS),
'fill' : 'none'}
ell_attribs = {'style' : simplestyle.formatStyle(style),
inkex.addNS('cx', 'sodipodi') : str(cx),
inkex.addNS('cy', 'sodipodi') : str(cy),
inkex.addNS('rx', 'sodipodi') : str(r),
inkex.addNS('ry', 'sodipodi') : str(r),
inkex.addNS('start', 'sodipodi'): str(0),
inkex.addNS('end', 'sodipodi') : str(2 * math.pi),
inkex.addNS('open', 'sodipodi') : 'true',
# all ellipse sectors we will draw are open
inkex.addNS('type', 'sodipodi') : 'arc',
'transform' : ''}
inkex.etree.SubElement(parent, inkex.addNS('path', 'svg'), ell_attribs)
def side(root_coord, start_offset_coord, end_offset_coord, tab_vec, length, direction,
is_tab, is_divider, num_dividers, div_spacing, div_offset):
# type: (Tuple[int, int], Tuple[int, int], Tuple[int, int], int, int, Tuple[int, int], bool, bool, int, int, int) -> str
rx, ry = root_coord
sox, soy = start_offset_coord
eox, eoy = end_offset_coord
dir_x, dir_y = direction
divs = int(length / nom_tab) # divisions
if not divs % 2:
divs -= 1 # make divs odd
divs = float(divs)
tabs = (divs - 1) / 2 # tabs for side
if equal_tabs:
gap_width = tab_width = length / divs
else:
tab_width = nom_tab
gap_width = (length - tabs * nom_tab) / (divs - tabs)
if is_tab: # kerf correction
gap_width -= correction
tab_width += correction
first = correction / 2
else:
gap_width += correction
tab_width -= correction
first = -correction / 2
first_vec = 0
second_vec = tab_vec
dirxN = 0 if dir_x else 1 # used to select operation on x or y
diryN = 0 if dir_y else 1
(Vx, Vy) = (rx + sox * thickness, ry + soy * thickness)
s = 'M {},{} '.format(Vx, Vy)
if dirxN:
Vy = ry # set correct line start
if diryN:
Vx = rx
# generate line as tab or hole using:
# last co-ord:Vx,Vy ; tab dir:tab_vec ; direction:dir_x,dir_y ; thickness:thickness
# divisions:divs ; gap width:gap_width ; tab width:tab_width
for n in range(1, int(divs)):
if ((n % 2) ^ (
not is_tab)) and num_dividers > 0 and not is_divider: # draw holes for
# divider
# joints in side walls
w = gap_width if is_tab else tab_width
if n == 1:
w -= sox * thickness
for m in range(1, int(num_dividers) + 1):
Dx = Vx + -dir_y * div_spacing * m
Dy = Vy + dir_x * div_spacing * m
if n == 1:
Dx += sox * thickness
h = 'M {},{} '.format(Dx, Dy)
Dx = Dx + dir_x * w + dirxN * first_vec + first * dir_x
Dy = Dy + dir_y * w + diryN * first_vec + first * dir_y
h += 'L {},{} '.format(Dx, Dy)
Dx += dirxN * second_vec
Dy += diryN * second_vec
h += 'L {},{} '.format(Dx, Dy)
Dx = Dx - (dir_x * w + dirxN * first_vec + first * dir_x)
Dy = Dy - (dir_y * w + diryN * first_vec + first * dir_y)
h += 'L {},{} '.format(Dx, Dy)
Dx -= dirxN * second_vec
Dy -= diryN * second_vec
h += 'L {},{} '.format(Dx, Dy)
draw_lines(h)
if n % 2:
if n == 1 and num_dividers > 0 and is_divider: # draw slots for dividers
# to slot into each other
for m in range(1, int(num_dividers) + 1):
Dx = Vx + -dir_y * (div_spacing * m + div_offset)
Dy = Vy + dir_x * (div_spacing * m - div_offset)
h = 'M {},{} '.format(Dx, Dy)
Dx = Dx + dir_x * (first + length / 2)
Dy = Dy + dir_y * (first + length / 2)
h += 'L {},{} '.format(Dx, Dy)
Dx = Dx + dirxN * thickness
Dy = Dy + diryN * thickness
h += 'L {},{} '.format(Dx, Dy)
Dx = Dx - dir_x * (first + length / 2)
Dy = Dy - dir_y * (first + length / 2)
h += 'L {},{} '.format(Dx, Dy)
Dx = Dx - dirxN * thickness
Dy = Dy - diryN * thickness
h += 'L {},{} '.format(Dx, Dy)
draw_lines(h)
Vx = Vx + dir_x * gap_width + dirxN * first_vec + first * dir_x
Vy = Vy + dir_y * gap_width + diryN * first_vec + first * dir_y
s += 'L {},{} '.format(Vx, Vy)
Vx = Vx + dirxN * second_vec
Vy = Vy + diryN * second_vec
s += 'L {},{} '.format(Vx, Vy)
else:
Vx = Vx + dir_x * tab_width + dirxN * first_vec
Vy = Vy + dir_y * tab_width + diryN * first_vec
s += 'L {},{} '.format(Vx, Vy)
Vx = Vx + dirxN * second_vec
Vy = Vy + diryN * second_vec
s += 'L {},{} '.format(Vx, Vy)
(second_vec, first_vec) = (-second_vec, -first_vec) # swap tab direction
first = 0
# finish the line off
s += 'L {},{} '.format(rx + eox * thickness + dir_x * length,
ry + eoy * thickness + dir_y * length)
if is_tab and num_dividers > 0 and not is_divider: # draw last for divider joints
# in side walls
for m in range(1, int(num_dividers) + 1):
Dx = Vx
Dy = Vy + dir_x * div_spacing * m
h = 'M {},{} '.format(Dx, Dy)
Dx = rx + eox * thickness + dir_x * length
Dy = Dy + dir_y * tab_width + diryN * first_vec + first * dir_y
h += 'L {},{} '.format(Dx, Dy)
Dx = Dx + dirxN * second_vec
Dy = Dy + diryN * second_vec
h += 'L {},{} '.format(Dx, Dy)
Dx = Vx
Dy = Dy - (dir_y * tab_width + diryN * first_vec + first * dir_y)
h += 'L {},{} '.format(Dx, Dy)
Dx = Dx - dirxN * second_vec
Dy = Dy - diryN * second_vec
h += 'L {},{} '.format(Dx, Dy)
draw_lines(h)
return s
class BoxMaker(inkex.Effect):
def __init__(self):
# Call the base class constructor.
# We are not using super because as of Inkscape 0.92 inkex.Effect is still an
# Old-Style python class that doesn't inherit from `object`
inkex.Effect.__init__(self)
# Define options
self.OptionParser.add_option('--schroff', action='store', type='int',
dest='schroff', default=0,
help='Enable Schroff mode')
self.OptionParser.add_option('--rail_height', action='store', type='float',
dest='rail_height', default=10.0,
help='Height of rail')
self.OptionParser.add_option('--rail_mount_depth', action='store', type='float',
dest='rail_mount_depth', default=17.4,
help='Depth at which to place hole for rail mount '
'bolt')
self.OptionParser.add_option('--rail_mount_centre_offset', action='store',
type='float',
dest='rail_mount_centre_offset', default=0.0,
help='How far toward row centreline to offset rail '
'mount bolt (from rail centreline)')
self.OptionParser.add_option('--rows', action='store', type='int',
dest='rows', default=0,
help='Number of Schroff rows')
self.OptionParser.add_option('--hp', action='store', type='int',
dest='hp', default=0,
help='Width (TE/HP units) of Schroff rows')
self.OptionParser.add_option('--row_spacing', action='store', type='float',
dest='row_spacing', default=10.0,
help='Height of rail')
self.OptionParser.add_option('--unit', action='store', type='string',
dest='unit', default='mm', help='Measure Units')
self.OptionParser.add_option('--inside', action='store', type='int',
dest='inside', default=0, help='Int/Ext Dimension')
self.OptionParser.add_option('--length', action='store', type='float',
dest='length', default=100, help='Length of Box')
self.OptionParser.add_option('--width', action='store', type='float',
dest='width', default=100, help='Width of Box')
self.OptionParser.add_option('--depth', action='store', type='float',
dest='height', default=100, help='Height of Box')
self.OptionParser.add_option('--tab', action='store', type='float',
dest='tab', default=25, help='Nominal Tab Width')
self.OptionParser.add_option('--equal', action='store', type='int',
dest='equal', default=0, help='Equal/Prop Tabs')
self.OptionParser.add_option('--hairline', action='store', type='int',
dest='hairline', default=0, help='Line Thickness')
self.OptionParser.add_option('--thickness', action='store', type='float',
dest='thickness', default=10,
help='Thickness of Material')
self.OptionParser.add_option('--kerf', action='store', type='float',
dest='kerf', default=0.5, help='Kerf (width) of cut')
self.OptionParser.add_option('--clearance', action='store', type='float',
dest='clearance', default=0.01,
help='Clearance of joints')
self.OptionParser.add_option('--style', action='store', type='int',
dest='style', default=25, help='Layout/Style')
self.OptionParser.add_option('--spacing', action='store', type='float',
dest='spacing', default=25, help='Part Spacing')
self.OptionParser.add_option('--boxtype', action='store', type='int',
dest='boxtype', default=25, help='Box type')
self.OptionParser.add_option('--div_l', action='store', type='int',
dest='div_l', default=25,
help='Dividers (Length axis)')
self.OptionParser.add_option('--div_w', action='store', type='int',
dest='div_w', default=25,
help='Dividers (Width axis)')
self.OptionParser.add_option('--keydiv', action='store', type='int',
dest='keydiv', default=3,
help='Key dividers into walls/floor')
def effect(self):
global parent, nom_tab, equal_tabs, thickness, correction, div_x, div_y, \
hairline, DEFAULT_LINE_THICKNESS, key_div_walls, key_div_floor
# Get access to main SVG document element and get its dimensions.
svg = self.document.getroot()
# Get the attributes:
width_doc = self.unittouu(svg.get('width'))
height_doc = self.unittouu(svg.get('height'))
# Create a new layer.
layer = inkex.etree.SubElement(svg, 'g')
layer.set(inkex.addNS('label', 'inkscape'), 'newlayer')
layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer')
parent = self.current_layer
# Get script's option values.
hairline = self.options.hairline
unit = self.options.unit
inside = self.options.inside
schroff = self.options.schroff
# Set the line thickness
if hairline:
DEFAULT_LINE_THICKNESS = self.unittouu('0.002in')
else:
DEFAULT_LINE_THICKNESS = 1
if schroff:
hp = self.options.hp
rows = self.options.rows
rail_height = self.unittouu(str(self.options.rail_height) + unit)
row_centre_spacing = self.unittouu(str(122.5) + unit)
row_spacing = self.unittouu(str(self.options.row_spacing) + unit)
rail_mount_depth = self.unittouu(str(self.options.rail_mount_depth) + unit)
rail_mount_centre_offset = self.unittouu(
str(self.options.rail_mount_centre_offset) + unit)
rail_mount_radius = self.unittouu(str(2.5) + unit)
# minimally different behaviour for schroffmaker.inx vs. boxmaker.inx
# essentially schroffmaker.inx is just an alternate interface with different
# default settings, some options removed, and a tiny amount of extra logic
if schroff:
# schroffmaker.inx
x = self.unittouu(str(self.options.hp * 5.08) + unit)
# 122.5mm vertical distance between mounting hole centres of 3U Schroff panels
row_height = rows * (row_centre_spacing + rail_height)
# rail spacing in between rows but never between rows and case panels
row_spacing_total = (rows - 1) * row_spacing
y = row_height + row_spacing_total
else:
# boxmaker.inx
x = self.unittouu(str(self.options.length) + unit)
y = self.unittouu(str(self.options.width) + unit)
z = self.unittouu(str(self.options.height) + unit)
thickness = self.unittouu(str(self.options.thickness) + unit)
nom_tab = self.unittouu(str(self.options.tab) + unit)
equal_tabs = self.options.equal
kerf = self.unittouu(str(self.options.kerf) + unit)
clearance = self.unittouu(str(self.options.clearance) + unit)
layout = self.options.style
spacing = self.unittouu(str(self.options.spacing) + unit)
box_type = self.options.boxtype
div_x = self.options.div_l
div_y = self.options.div_w
key_div_walls = 0 if self.options.keydiv == 3 or self.options.keydiv == 1 else 1
key_div_floor = 0 if self.options.keydiv == 3 or self.options.keydiv == 2 else 1
div_offset = key_div_walls * thickness
if inside: # if inside dimension selected correct values to outside dimension
x += thickness * 2
y += thickness * 2
z += thickness * 2
correction = kerf - clearance
# check input values mainly to avoid python errors
# TODO restrict values to *correct* solutions
# TODO restrict divisions to logical values
error = 0
if min(x, y, z) == 0:
inkex.errormsg('Error: Dimensions must be non zero')
error = 1
if max(x, y, z) > max(width_doc, height_doc) * 10: # crude test
inkex.errormsg('Error: Dimensions Too Large')
error = 1
if min(x, y, z) < 3 * nom_tab:
inkex.errormsg('Error: Tab size too large')
error = 1
if nom_tab < thickness:
inkex.errormsg('Error: Tab size too small')
error = 1
if thickness == 0:
inkex.errormsg('Error: Thickness is zero')
error = 1
if thickness > min(x, y, z) / 3: # crude test
inkex.errormsg('Error: Material too thick')
error = 1
if correction > min(x, y, z) / 3: # crude test
inkex.errormsg('Error: Kerf/Clearance too large')
error = 1
if spacing > max(x, y, z) * 10: # crude test
inkex.errormsg('Error: Spacing too large')
error = 1
if spacing < kerf:
inkex.errormsg('Error: Spacing too small')
error = 1
if error:
exit()
# layout format:
# (root_x), (root_y), X_length, Y_length, tabInfo, tabbed, pieceType
#
# root = (spacing,x,y,z) * values in multiples of dimension of top left corner
# eg. (3, 1, 0, 1) means x position = 3*spacing + 1*x dimension + 1*z dimension
#
# tabInfo= <abcd> 0=holes 1=tabs
# tabbed= <abcd> 0=no tabs 1=tabs on this side
# (sides: a=top, b=right, c=bottom, d=left)
#
# pieceType: 1=XY, 2=XZ, 3=ZY
# note first two pieces in each set are the x-divider template and y-divider
# template respectively
if box_type == 2: # One side open (x,y)
if layout == 1: # Diagrammatic Layout
pieces = [[(2, 0, 0, 1), (3, 0, 1, 1), x, z, 0b1010, 0b1101, 2],
[(1, 0, 0, 0), (2, 0, 0, 1), z, y, 0b1111, 0b1110, 3],
[(2, 0, 0, 1), (2, 0, 0, 1), x, y, 0b0000, 0b1111, 1],
[(3, 1, 0, 1), (2, 0, 0, 1), z, y, 0b1111, 0b1011, 3],
[(4, 1, 0, 2), (2, 0, 0, 1), x, y, 0b0000, 0b0000, 1],
[(2, 0, 0, 1), (1, 0, 0, 0), x, z, 0b1010, 0b0111, 2]]
elif layout == 2: # 3 Piece Layout
pieces = [[(2, 0, 0, 1), (2, 0, 1, 0), x, z, 0b1010, 0b1101, 2],
[(1, 0, 0, 0), (1, 0, 0, 0), z, y, 0b1111, 0b1110, 3],
[(2, 0, 0, 1), (1, 0, 0, 0), x, y, 0b0000, 0b1111, 1]]
elif layout == 3: # Inline(compact) Layout
pieces = [[(5, 2, 0, 2), (1, 0, 0, 0), x, z, 0b1111, 0b1101, 2],
[(3, 2, 0, 0), (1, 0, 0, 0), z, y, 0b0101, 0b1110, 3],
[(4, 2, 0, 1), (1, 0, 0, 0), z, y, 0b0101, 0b1011, 3],
[(2, 1, 0, 0), (1, 0, 0, 0), x, y, 0b0000, 0b1111, 1],
[(6, 3, 0, 2), (1, 0, 0, 0), x, z, 0b1111, 0b0111, 2]]
elif layout == 4: # Diagrammatic Layout with Alternate Tab Arrangement
pieces = [[(2, 0, 0, 1), (3, 0, 1, 1), x, z, 0b1001, 0b1101, 2],
[(1, 0, 0, 0), (2, 0, 0, 1), z, y, 0b1100, 0b1110, 3],
[(2, 0, 0, 1), (2, 0, 0, 1), x, y, 0b1100, 0b1111, 1],
[(3, 1, 0, 1), (2, 0, 0, 1), z, y, 0b0110, 0b1011, 3],
[(4, 1, 0, 2), (2, 0, 0, 1), x, y, 0b0110, 0b0000, 1],
[(2, 0, 0, 1), (1, 0, 0, 0), x, z, 0b1100, 0b0111, 2]]
elif box_type == 3: # Two sides open (x,y and x,z)
if layout == 1: # Diagrammatic Layout
pieces = [[(2, 0, 0, 1), (1, 0, 0, 0), x, z, 0b1010, 0b0111, 2],
[(1, 0, 0, 0), (2, 0, 0, 1), z, y, 0b1111, 0b1100, 3],
[(2, 0, 0, 1), (2, 0, 0, 1), x, y, 0b0010, 0b1101, 1],
[(3, 1, 0, 1), (2, 0, 0, 1), z, y, 0b1111, 0b1001, 3]]
elif layout == 2: # 3 Piece Layout
pieces = [[(2, 0, 0, 1), (1, 0, 0, 0), x, z, 0b1010, 0b0111, 2],
[(1, 0, 0, 0), (2, 0, 0, 1), z, y, 0b1111, 0b1100, 3],
[(2, 0, 0, 1), (2, 0, 0, 1), x, y, 0b0010, 0b1101, 1]]
elif layout == 3: # Inline(compact) Layout
pieces = [[(2, 2, 0, 2), (1, 0, 0, 0), x, z, 0b1010, 0b0111, 2],
[(3, 2, 0, 0), (1, 0, 0, 0), z, y, 0b1111, 0b1100, 3],
[(2, 1, 0, 0), (1, 0, 0, 0), x, y, 0b0010, 0b1101, 1],
[(4, 2, 0, 1), (1, 0, 0, 0), z, y, 0b1111, 0b1001, 3]]
elif layout == 4: # Diagrammatic Layout with Alternate Tab Arrangement
pieces = [[(2, 0, 0, 1), (1, 0, 0, 0), x, z, 0b1100, 0b0111, 2],
[(1, 0, 0, 0), (2, 0, 0, 1), z, y, 0b1111, 0b1100, 3],
[(2, 0, 0, 1), (2, 0, 0, 1), x, y, 0b1110, 0b1101, 1],
[(3, 1, 0, 1), (2, 0, 0, 1), z, y, 0b0110, 0b1001, 3]]
elif box_type == 4: # Three sides open (x,y, x,z and z,y)
if layout == 2: # 3 Piece Layout
pieces = [[(2, 2, 0, 0), (2, 0, 1, 0), x, z, 0b1111, 0b1001, 2],
[(1, 0, 0, 0), (1, 0, 0, 0), z, y, 0b1111, 0b0110, 3],
[(2, 2, 0, 0), (1, 0, 0, 0), x, y, 0b1100, 0b0011, 1]]
else:
pieces = [[(3, 3, 0, 0), (1, 0, 0, 0), x, z, 0b1110, 0b1001, 2],
[(1, 0, 0, 0), (1, 0, 0, 0), z, y, 0b1111, 0b0110, 3],
[(2, 2, 0, 0), (1, 0, 0, 0), x, y, 0b1100, 0b0011, 1]]
elif box_type == 5: # Opposite ends open (x,y)
if layout == 1: # Diagrammatic Layout
pieces = [[(2, 0, 0, 1), (3, 0, 1, 1), x, z, 0b1010, 0b0101, 2],
[(3, 1, 0, 1), (2, 0, 0, 1), z, y, 0b1111, 0b1010, 3],
[(2, 0, 0, 1), (1, 0, 0, 0), x, z, 0b1010, 0b0101, 2],
[(1, 0, 0, 0), (2, 0, 0, 1), z, y, 0b1111, 0b1010, 3]]
elif layout == 2: # 2 Piece Layout
pieces = [[(1, 0, 0, 1), (1, 0, 1, 1), x, z, 0b1010, 0b0101, 2],
[(2, 1, 0, 1), (1, 0, 0, 1), z, y, 0b1111, 0b1010, 3]]
elif layout == 3: # Inline(compact) Layout
pieces = [[(1, 0, 0, 0), (1, 0, 0, 0), x, z, 0b1010, 0b0101, 2],
[(3, 2, 0, 0), (1, 0, 0, 0), z, y, 0b1111, 0b1010, 3],
[(2, 1, 0, 0), (1, 0, 0, 0), x, z, 0b1010, 0b0101, 2],
[(4, 2, 0, 1), (2, 0, 0, 0), z, y, 0b1111, 0b1010, 3]]
elif layout == 4: # Diagrammatic Layout with Alternate Tab Arrangement
pieces = [[(2, 0, 0, 1), (3, 0, 1, 1), x, z, 0b1011, 0b0101, 2],
[(3, 1, 0, 1), (2, 0, 0, 1), z, y, 0b0111, 0b1010, 3],
[(2, 0, 0, 1), (1, 0, 0, 0), x, z, 0b1110, 0b0101, 2],
[(1, 0, 0, 0), (2, 0, 0, 1), z, y, 0b1101, 0b1010, 3]]
elif box_type == 6: # 2 panels jointed (x,y and z,y joined along y)
pieces = [[(1, 0, 0, 0), (1, 0, 0, 0), x, y, 0b1011, 0b0100, 1],
[(2, 1, 0, 0), (1, 0, 0, 0), z, y, 0b1111, 0b0001, 3]]
else: # Fully enclosed
if layout == 1: # Diagrammatic Layout
pieces = [[(2, 0, 0, 1), (3, 0, 1, 1), x, z, 0b1010, 0b1111, 2],
[(1, 0, 0, 0), (2, 0, 0, 1), z, y, 0b1111, 0b1111, 3],
[(2, 0, 0, 1), (2, 0, 0, 1), x, y, 0b0000, 0b1111, 1],
[(3, 1, 0, 1), (2, 0, 0, 1), z, y, 0b1111, 0b1111, 3],
[(4, 1, 0, 2), (2, 0, 0, 1), x, y, 0b0000, 0b1111, 1],
[(2, 0, 0, 1), (1, 0, 0, 0), x, z, 0b1010, 0b1111, 2]]
elif layout == 2: # 3 Piece Layout
pieces = [[(2, 0, 0, 1), (2, 0, 1, 0), x, z, 0b1010, 0b1111, 2],
[(1, 0, 0, 0), (1, 0, 0, 0), z, y, 0b1111, 0b1111, 3],
[(2, 0, 0, 1), (1, 0, 0, 0), x, y, 0b0000, 0b1111, 1]]
elif layout == 3: # Inline(compact) Layout
pieces = [[(5, 2, 0, 2), (1, 0, 0, 0), x, z, 0b1111, 0b1111, 2],
[(3, 2, 0, 0), (1, 0, 0, 0), z, y, 0b0101, 0b1111, 3],
[(6, 3, 0, 2), (1, 0, 0, 0), x, z, 0b1111, 0b1111, 2],
[(4, 2, 0, 1), (1, 0, 0, 0), z, y, 0b0101, 0b1111, 3],
[(2, 1, 0, 0), (1, 0, 0, 0), x, y, 0b0000, 0b1111, 1],
[(1, 0, 0, 0), (1, 0, 0, 0), x, y, 0b0000, 0b1111, 1]]
elif layout == 4: # Diagrammatic Layout with Alternate Tab Arrangement
pieces = [[(2, 0, 0, 1), (3, 0, 1, 1), x, z, 0b1001, 0b1111, 2],
[(1, 0, 0, 0), (2, 0, 0, 1), z, y, 0b1100, 0b1111, 3],
[(2, 0, 0, 1), (2, 0, 0, 1), x, y, 0b1100, 0b1111, 1],
[(3, 1, 0, 1), (2, 0, 0, 1), z, y, 0b0110, 0b1111, 3],
[(4, 1, 0, 2), (2, 0, 0, 1), x, y, 0b0110, 0b1111, 1],
[(2, 0, 0, 1), (1, 0, 0, 0), x, z, 0b1100, 0b1111, 2]]
for idx, piece in enumerate(pieces): # generate and draw each piece of the box
(xs, xx, xy, xz) = piece[0]
(ys, yx, yy, yz) = piece[1]
x_ = xs * spacing + xx * x + xy * y + xz * z # root x co-ord for piece
y_ = ys * spacing + yx * x + yy * y + yz * z # root y co-ord for piece
dx = piece[2]
dy = piece[3]
tabs = piece[4]
a = tabs >> 3 & 1
b = tabs >> 2 & 1
c = tabs >> 1 & 1
d = tabs & 1 # extract tab status for each side
tabbed = piece[5]
a_tabs = tabbed >> 3 & 1
b_tabs = tabbed >> 2 & 1
c_tabs = tabbed >> 1 & 1
d_tabs = tabbed & 1 # extract tabbed flag for each side
x_spacing = (x - thickness) / (div_y + 1)
y_spacing = (y - thickness) / (div_x + 1)
x_holes = 1 if piece[6] < 3 else 0 # 3 is a YZ piece
y_holes = 1 if piece[6] != 2 else 0 # 2 is an XZ piece
wall = 1 if piece[6] > 1 else 0
floor = 1 if piece[6] == 1 else 0 # 1 is an XY piece
rail_holes = 1 if piece[6] == 3 else 0
if schroff and rail_holes:
log("rail holes enabled on piece {} at ({}, {})".format(idx,
x_ + thickness,
y_ + thickness))
log("abcd = ({},{},{},{})".format(a, b, c, d))
log("dxdy = ({},{})".format(dx, dy))
rhx_offset = rail_mount_depth + thickness
if idx == 1:
rhx = x_ + rhx_offset
elif idx == 3:
rhx = x_ - rhx_offset + dx
else:
rhx = 0
log("rhx_offset = {}, rhx= {}".format(rhx_offset, rhx))
ry_start = y_ + (rail_height / 2) + thickness
if rows == 1:
log("just one row this time, ry_start = {}".format(ry_start))
rh1y = ry_start + rail_mount_centre_offset
rh2y = rh1y + (row_centre_spacing - rail_mount_centre_offset)
draw_circle(rail_mount_radius, rhx, rh1y)
draw_circle(rail_mount_radius, rhx, rh2y)
else:
for n in range(0, rows):
log("drawing row {}, ry_start = {}".format(n + 1, ry_start))
# if holes are offset (eg. Vector T-strut rails), they should
# be offset
# toward each other, ie. toward the centreline of the Schroff row
rh1y = ry_start + rail_mount_centre_offset
rh2y = rh1y + row_centre_spacing - rail_mount_centre_offset
draw_circle(rail_mount_radius, rhx, rh1y)
draw_circle(rail_mount_radius, rhx, rh2y)
ry_start += row_centre_spacing + row_spacing + rail_height
# generate and draw the sides of each piece
side_a = side(root_coord=(x_, y_),
start_offset_coord=(d, a),
end_offset_coord=(-b, a),
tab_vec=a_tabs * (-thickness if a else thickness),
length=dx,
direction=(1, 0),
is_tab=a,
is_divider=False,
num_dividers=(key_div_floor | wall) * (
key_div_walls | floor) * div_x * y_holes * a_tabs,
div_spacing=y_spacing,
div_offset=div_offset)
side_b = side(root_coord=(x_ + dx, y_),
start_offset_coord=(-b, a),
end_offset_coord=(-b, -c),
tab_vec=b_tabs * (thickness if b else -thickness),
length=dy,
direction=(0, 1),
is_tab=b,
is_divider=False,
num_dividers=(key_div_floor | wall) * (
key_div_walls | floor) * div_y * x_holes * b_tabs,
div_spacing=x_spacing,
div_offset=div_offset)
if a_tabs:
side_c = side(root_coord=(x_ + dx, y_ + dy),
start_offset_coord=(-b, -c),
end_offset_coord=(d, -c),
tab_vec=c_tabs * (thickness if c else -thickness),
length=dx,
direction=(-1, 0),
is_tab=c,
is_divider=False,
num_dividers=0,
div_spacing=0,
div_offset=div_offset)
else:
side_c = side(root_coord=(x_ + dx, y_ + dy),
start_offset_coord=(-b, -c),
end_offset_coord=(d, -c),
tab_vec=c_tabs * (thickness if c else -thickness),
length=dx,
direction=(-1, 0),
is_tab=c,
is_divider=False,
num_dividers=(key_div_floor | wall) * (
key_div_walls | floor) * div_x * y_holes *
c_tabs,
div_spacing=y_spacing,
div_offset=div_offset)
if b_tabs:
side_d = side(root_coord=(x_, y_ + dy),
start_offset_coord=(d, -c),
end_offset_coord=(d, a),
tab_vec=d_tabs * (-thickness if d else thickness),
length=dy,
direction=(0, -1),
is_tab=d,
is_divider=False,
num_dividers=0,
div_spacing=0,
div_offset=div_offset)
else:
side_d = side(root_coord=(x_, y_ + dy),
start_offset_coord=(d, -c),
end_offset_coord=(d, a),
tab_vec=d_tabs * (-thickness if d else thickness),
length=dy,
direction=(0, -1),
is_tab=d,
is_divider=False,
num_dividers=(key_div_floor | wall) * (
key_div_walls | floor) * div_y * x_holes *
d_tabs,
div_spacing=x_spacing,
div_offset=div_offset)
draw_lines(side_a)
draw_lines(side_b)
draw_lines(side_c)
draw_lines(side_d)
if idx == 0:
if not key_div_walls:
a = 1
b = 1
c = 1
d = 1
a_tabs = 0
b_tabs = 0
c_tabs = 0
d_tabs = 0
y_ = 4 * spacing + 1 * y + 2 * z # root y co-ord for piece
for n in range(0, div_x): # generate x dividers
x_ = n * (spacing + x) # root x co-ord for piece
side_a = side(root_coord=(x_, y_),
start_offset_coord=(d, a),
end_offset_coord=(-b, a),
tab_vec=key_div_floor * a_tabs * (
-thickness if a else thickness),
length=dx,
direction=(1, 0),
is_tab=a,
is_divider=True,
num_dividers=0,
div_spacing=0,
div_offset=div_offset)
side_b = side(root_coord=(x_ + dx, y_),
start_offset_coord=(-b, a),
end_offset_coord=(-b, -c),
tab_vec=key_div_walls * b_tabs * (
thickness if key_div_walls * b else -thickness),
length=dy,
direction=(0, 1),
is_tab=b,
is_divider=True,
num_dividers=div_y * x_holes,
div_spacing=x_spacing,
div_offset=div_offset)
side_c = side(root_coord=(x_ + dx, y_ + dy),
start_offset_coord=(-b, -c),
end_offset_coord=(d, -c),
tab_vec=key_div_floor * c_tabs * (
thickness if c else -thickness),
length=dx,
direction=(-1, 0),
is_tab=c,
is_divider=True,
num_dividers=0,
div_spacing=0,
div_offset=div_offset)
side_d = side(root_coord=(x_, y_ + dy),
start_offset_coord=(d, -c),
end_offset_coord=(d, a),
tab_vec=key_div_walls * d_tabs * (
-thickness if d else thickness),
length=dy,
direction=(0, -1),
is_tab=d,
is_divider=True,
num_dividers=0,
div_spacing=0,
div_offset=div_offset)
draw_lines(side_a)
draw_lines(side_b)
draw_lines(side_c)
draw_lines(side_d)
elif idx == 1:
y_ = 5 * spacing + 1 * y + 3 * z # root y co-ord for piece
for n in range(0, div_y): # generate y dividers
x_ = n * (spacing + z) # root x co-ord for piece
side_a = side(root_coord=(x_, y_),
start_offset_coord=(d, a),
end_offset_coord=(-b, a),
tab_vec=key_div_walls * a_tabs * (
-thickness if a else thickness),
length=dx,
direction=(1, 0),
is_tab=a,
is_divider=True,
num_dividers=div_x * y_holes,
div_spacing=y_spacing,
div_offset=thickness)
side_b = side(root_coord=(x_ + dx, y_),
start_offset_coord=(-b, a),
end_offset_coord=(-b, -c),
tab_vec=key_div_floor * b_tabs * (
thickness if b else -thickness),
length=dy,
direction=(0, 1),
is_tab=b,
is_divider=True,
num_dividers=0,
div_spacing=0,
div_offset=thickness)
side_c = side(root_coord=(x_ + dx, y_ + dy),
start_offset_coord=(-b, -c),
end_offset_coord=(d, -c),
tab_vec=key_div_walls * c_tabs * (
thickness if c else -thickness),
length=dx,
direction=(-1, 0),
is_tab=c,
is_divider=True,
num_dividers=0,
div_spacing=0,
div_offset=thickness)
side_d = side(root_coord=(x_, y_ + dy),
start_offset_coord=(d, -c),
end_offset_coord=(d, a),
tab_vec=key_div_floor * d_tabs * (
-thickness if d else thickness),
length=dy,
direction=(0, -1),
is_tab=d,
is_divider=True,
num_dividers=0,
div_spacing=0,
div_offset=thickness)
draw_lines(side_a)
draw_lines(side_b)
draw_lines(side_c)
draw_lines(side_d)
# Create effect instance and apply it.
effect = BoxMaker()
effect.affect()