#!/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>')