#!/usr/bin/env python3 # # honeyrack.py - Generate laser cut parts for honeycomb style shelf # import argparse import re import math import sys parser = argparse.ArgumentParser('Generate parts for honeycomb style shelf') parser.add_argument('x', type=int, help='Number of cells in bottom row') parser.add_argument('y', type=int, default=3, help='Number of rows') parser.add_argument('--side', default='5cm', help='Length of side') parser.add_argument('--depth', default='10cm', help='Depth') parser.add_argument('--tab', default='1cm', help='Length of connective tabs') parser.add_argument('--kerf', default='.2mm', help='Amount of kerf adjustment') parser.add_argument('--fringe', default='1cm', help='Space around tabs') parser.add_argument('--stem', default='2cm', help='Width of connectors') parser.add_argument('--disc', default='2cm', help='Radius of auxiliary discs') parser.add_argument('--num_discs', default='2', help='Number of auxiliary discs') parser.add_argument('--thickness', default='.125in', help='Material thickness') args = parser.parse_args() DIMENSION = re.compile(r'(\-?\d*(?:\.\d*)?)\s*(cm|mm|m|in)') def to_mm(length): m = DIMENSION.fullmatch(length) if m == None: abort("{} should be a length with an unit (m, cm, mm, in)".format(length)) v = float(m.group(1)) u = m.group(2) if u == 'mm': return v elif u == 'cm': return v*10 elif u == 'm': return v*1000 elif u == 'in': return v*25.4 args.side = to_mm(args.side) args.depth = to_mm(args.depth) args.tab = to_mm(args.tab) args.kerf = to_mm(args.kerf) args.fringe = to_mm(args.fringe) args.stem = to_mm(args.stem) args.disc = to_mm(args.disc) args.thickness = to_mm(args.thickness) def compute_notch(): global args if 'notch' in args: return depth = args.disc - (args.thickness+args.kerf)*0.25*math.sqrt(3) # Half of the height of equilateral triangle args.notch = 0.5*(depth-args.kerf) def disc(x, y): compute_notch() global args cut = args.thickness+args.kerf cone = math.asin(0.5*cut/args.disc) cx = x+args.disc cy = y+args.disc t0 = -cone x0 = cx+math.cos(t0)*args.disc y0 = cy-math.sin(t0)*args.disc print('<path fill="none" stroke="red" d="M {},{} h {} v {} h {} '.format(x0, y0, -args.notch, -cut, args.notch)) r120 = (2.0/3.0)*math.pi t1 = r120-cone x1 = cx+math.cos(t1)*args.disc y1 = cy-math.sin(t1)*args.disc dx1 = args.notch*math.cos(r120) dy1 = args.notch*math.sin(r120) dx1a = cut*math.cos(r120+0.5*math.pi) dy1a = cut*math.sin(r120+0.5*math.pi) print('A {},{} 0,0,0 {},{} l {},{} {},{} {},{} '.format(args.disc, args.disc, x1,y1, -dx1,dy1, dx1a,-dy1a, dx1,-dy1)) r240 = (4.0/3.0)*math.pi t2 = r240-cone x2 = cx+math.cos(t2)*args.disc y2 = cy-math.sin(t2)*args.disc dx2 = args.notch*math.cos(r240) dy2 = args.notch*math.sin(r240) dx2a = cut*math.cos(r240+0.5*math.pi) dy2a = cut*math.sin(r240+0.5*math.pi) print('A {},{} 0,0,0 {},{} l {},{} {},{} {},{} '.format(args.disc, args.disc, x2,y2, -dx2,dy2, dx2a,-dy2a, dx2,-dy2)) print('A {},{} 0,0,0 {},{}" />'.format(args.disc, args.disc, x0, y0)) print('<svg viewBox="0 0 500 500" width="500mm" height="500mm" xmlns="http://www.w3.org/2000/svg">') disc(50, 50) print('</svg>')