from koko.lib.shapes import *
from math import sqrt

# One cad unit is 1cm
cad.mm_per_unit = 10

# laser kerf is orders of magnitude less than material thickness
# shopbot kerf is same order as material thickness, so joint design needs modification
# Some parameters are size related.  Some of the design is based on how the machinen behaves

# TODO
# Laser version
# 1) Slightly increase size of center pin for better fit
# 2) Add bigger chamfer to end of center pin
# 3) Make center pin base triangular for extra strength
# Shop bot version
# 1) Sort out dogs on slots
# 2) Increase material thickness
# 3) Make slots slightly taller, SB cuts around line so end of tang is currently an 'exact fit', needs some play
# 4) increase length of tang to improve

machine = 'laser'
#machine = 'shopbot'

if machine == 'laser':
    # setup for Epilog Laser and 3mm ply
    k = 0.17/cad.mm_per_unit    # Tool Kerf
    t = 3.0/cad.mm_per_unit     # Material thickness
    c = 0.2/cad.mm_per_unit     # Material Compliance. Estimate of the amount of non-elastic deformation that will occur once on the contact surfaces of the interferance fit
    #sl = 50/cad.mm_per_unit      # Test part length
    #sh = 20/cad.mm_per_unit      # Test part height
    tang_indent = 3
    scale = 53/cad.mm_per_unit # 50 mm major part defining scale
    hingeslotw = 1.5/cad.mm_per_unit
    hingesloth = 50/cad.mm_per_unit # rough guide to expected size of slots
    hingetab = 3/cad.mm_per_unit
elif machine == 'shopbot':
    # setup for shopbot 10mm ply
    # machine setup on vs around vector is also different
    k = 6/cad.mm_per_unit    # Tool Kerf
    t = 12/cad.mm_per_unit #11.2/cad.mm_per_unit     # Material thickness
    c = 0.5/cad.mm_per_unit     # Material Compliance. Estimate of the amount of non-elastic deformation that will occur once on the contact surfaces of the interferance fit
    #sl = 150/cad.mm_per_unit      # Test part length
    #sh = 80/cad.mm_per_unit      # Test part height
    tang_indent = 4
    scale = 200/cad.mm_per_unit # 50 mm major part defining scale
    hingeslotw = 7/cad.mm_per_unit # just over kerfs
    hingesloth = 150/cad.mm_per_unit # rough guide to expected size of slots
    hingetab = 10/cad.mm_per_unit 

# Joint size definitions
j_ph = t # Pin height. All pins / tangs are same height.
if j_ph < (3*k):
    j_ph = (3*k) # Minimum pin height has to allow for a tool cut down the center
j_cpl = t*2 # Center locating pin length beyond edge of material, should be slightly longer than tangs to help ease joint assembly
j_tl = t*1.8 # Tang length beyond edge of material
j_tl2 = j_cpl*tang_indent # Tang length back into material from edge
j_fsh = (j_ph/3)*1.05 #k # Flexure slot height in tang, add a bit to make sure tool fits if j_ph is only 3*k
j_fullh = j_ph*6 # Full joint height, should be sum of parts

# Joint part A - with the tangs
# Origin of joint is half way up join on the boundary edge of the material
# Made by adding a chunk of material and then cutting out tangs.
# Add rect make it overlap by j_cpl*0.1 with existing material to gaurentee no math error gaps.
jointa_add = rectangle(-(j_cpl*0.1), j_cpl, -j_fullh/2, j_fullh/2)
# Remove material all around upper half of center locating pin and upper tang
jointa_remove = (rectangle(-j_tl2,0, (j_ph*2.5)-(k*0.1),(j_ph*2.5)+(k*1)) # thin free movement cut back into material on upper edge of upper tang.  Make slightly bigger than kerf to gaurentee tool fits
                + rectangle(0,t-c, (j_ph*2.5)-(k*0.1),j_fullh/2)
                + triangle(t-c,j_ph*2.5, t-c,j_fullh/2, t+c,j_fullh/2) # preasure fit edge slope on upper tang (take off kerf to aid pressure fit). Need to be careful that tool still fits
                + triangle(j_tl*0.8,j_fullh/2, j_tl,j_fullh/2, j_tl,j_ph*2.0) # chamfer upper side of upper tang
                + rectangle(j_tl,j_cpl, j_ph/2,j_fullh/2) # remove material beyond end of tang
                #+ triangle(-(t*1.5),-(t*1.5), -(t*1.8),-(t*1.5), -(t*1.8),-(t*1.8)) # chamfer lower side of upper tang
                + rectangle(-j_tl2,j_cpl, j_ph*0.5,j_ph*1.5) # remove material between tang and center locating pin
                + triangle(j_cpl*0.9,j_ph*0.5, j_cpl,j_ph*0.5, j_cpl,j_ph*0.4) # chamfer upper side of center locating pin
                + rectangle(-j_tl2,j_tl*0.6, j_ph*2-(j_fsh/2), j_ph*2+(j_fsh/2)) # Flexure slot in middle of tang
                )
# Reflect the above around the line of symetry of the joint
jointa_remove = jointa_remove + reflect_y(jointa_remove, 0)

# Joint part B - the holes
# Must add dogs to the corners of these holes
jointb_remove = (
                rectangle(-t/2, t/2, j_ph*0.9, j_ph*2.7)
                + circle(-t/2, (j_ph*0.9)+k/2, k/2)
                + circle(-t/2, (j_ph*2.7)-k/2, k/2)
                + circle(t/2, (j_ph*0.9)+k/2, k/2)
                + circle(t/2, (j_ph*2.7)-k/2, k/2)

                + rectangle(-t/2, t/2, -(j_ph*0.5), j_ph*0.5)
                + circle(-t/2, -(j_ph*0.5)+k/2, k/2)
                + circle(-t/2, (j_ph*0.5)-k/2, k/2)
                + circle(t/2, -(j_ph*0.5)+k/2, k/2)
                + circle(t/2, (j_ph*0.5)-k/2, k/2)

                + rectangle(-t/2, t/2, -j_ph*2.7, -j_ph*0.9)
                + circle(-t/2, -(j_ph*0.9)-k/2, k/2)
                + circle(-t/2, -(j_ph*2.7)+k/2, k/2)
                + circle(t/2, -(j_ph*0.9)-k/2, k/2)
                + circle(t/2, -(j_ph*2.7)+k/2, k/2)
                )






# Some wall part size defs
ww = scale*2.5 # WallWidth
wh = scale # WallHeight
cw = ww/10 # CrenelWidth





# Make a slot pattern hinge centered on 0,0
def make_hinge(width, height):
    # calc actual height of slots
    ht = math.floor(height / hingesloth)
    print "number of hinge slots", ht
    ht = (height - ((ht+1)*hingetab))/ht
    # set start position
    x = -width/2
    y = -(height/2 + ht/2 - hingetab/2)
    hinge = rectangle(x, x+hingeslotw, y, y+ht) #simple rect to start shape, will get included twice
    while(x < width/2):
        # slot pattern a
        y = -(height/2 + ht/2)
        while(y < height/2):
            hinge += rectangle(x, x+hingeslotw, y, y+ht)
            y += ht+hingetab
        # slot pattern b
        x += hingeslotw*2
        y = -(height/2 - hingetab)
        while(y < height/2):
            hinge += rectangle(x, x+hingeslotw, y, y+ht)
            y += ht+hingetab
        x += hingeslotw*2
    return hinge

# Make a window centered on 0,0
def make_window(width, height):
    window = rectangle(-width/2, width/2, -height/2, height/2)
    window += taper_x_y(rectangle(-width/2, width/2, height/2, height),
                0, height/2, height, 1, 0.2)
    return window

# Make some stone pattern for side of walls
def make_stones(width, height):
    ws = (width/3) * 0.9
    hs = (height/3) * 0.9
    stones = rounded_rectangle(-(width/2), -(width/2-ws), -(height/2), -(height/2-hs), ws*0.2)
    stones += rounded_rectangle(-(width/2), -(width/2-ws), -(hs/2), (hs/2), ws*0.2)
    stones += rounded_rectangle(-(ws/2), (ws/2), -(hs/2), (hs/2), ws*0.2)
    stones += rounded_rectangle(-(ws/2), (ws/2), (height/2-hs), (height/2), ws*0.2)
    stones += rounded_rectangle((width/2-ws), (width/2), -(hs/2), (hs/2), ws*0.2)
    return stones

# Make a piece of wall centered on 0,0
def make_wall_a(width, height, crenelw):
    # Main body of wall
    wall = rectangle(-width/2, width/2, -height/2, height/2)
    # Crenelations
    x = (-ww/2)+cw
    while(x < (ww/2)):
        wall -= rectangle(x, x+cw, (wh/2)-(cw/2), wh/2)
        x += cw*2
    # Add joint parts
    wall += move(jointa_add, width/2, 0)
    wall -= move(jointa_remove, width/2, 0)
    wall += move(reflect_x(jointa_add, 0), -width/2, 0)
    wall -= move(reflect_x(jointa_remove, 0), -width/2, 0)
    # Add some decoration
    wall -= move(make_window(cw/3, cw*2/3), -cw*1.5, cw/2)
    wall -= move(make_stones(cw*2.5, cw*1.5), cw*1.5, 0)
    return wall

def make_wall_b(width, height, crenelw):
    # Main body of wall
    wall = rectangle(-width/2, width/2, -height/2, height/2)
    # Crenelations
    x = (-ww/2)+cw
    while(x < (ww/2)):
        wall -= rectangle(x, x+cw, (wh/2)-(cw/2), wh/2)
        x += cw*2
    # Add joint parts
    wall -= move(jointb_remove, (width/2)*0.9, 0)
    wall -= move(jointb_remove, -(width/2)*0.9, 0)
    # Add some decoration
    wall -= move(make_window(cw/3, cw*2/3), -cw, cw/2)
    wall -= move(make_window(cw/3, cw*2/3), cw, cw/2)
    return wall

# Make a tower section roughly 6 sections wide
# width = a single section
# origin is not at center but on left hand edge
def make_tower(swidth, height, crenelw):
    twidth = swidth*(4+(3*0.6)+0.25)
    # Basic rect for body
    tower = rectangle(0, twidth, -height/2, height/2)
    # Add some hinges
    tower -= move(make_hinge(swidth*0.6, height), swidth*1.3, 0)
    tower -= move(make_hinge(swidth*0.6, height), swidth*2.9, 0)
    tower -= move(make_hinge(swidth*0.6, height), swidth*4.5, 0)
    # Add some crenelations
    x = swidth*0.5 -  cw*1.5
    while(x< swidth):
        tower -= rectangle(x, x+cw, (height/2)-(cw/2), height/2)
        x += cw*2
    x = swidth*2.1 - cw*1.5
    while(x< (swidth*2.6)):
        tower -= rectangle(x, x+cw, (height/2)-(cw/2), height/2)
        x += cw*2
    x = swidth*3.7 - cw*1.5
    while(x< (swidth*4.2)):
        tower -= rectangle(x, x+cw, (height/2)-(cw/2), height/2)
        x += cw*2
    x = swidth*5.3 - cw*1.5
    while(x< (swidth*5.8)):
        tower -= rectangle(x, x+cw, (height/2)-(cw/2), height/2)
        x += cw*2
    # Add joints to form this section into a cuboid
    tower += reflect_x(jointa_add, 0)
    tower -= reflect_x(jointa_remove, 0)
    tower -= move(jointb_remove, swidth*(5.8+0.1), 0)
    # Add some joints for walls
    tower -= move(jointb_remove, swidth*0.5, -(height/2-wh/2))
    tower -= move(jointb_remove, swidth*2.1, -(height/2-wh/2))
    tower -= move(jointb_remove, swidth*3.7, -(height/2-wh/2))
    tower -= move(jointb_remove, swidth*5.3, -(height/2-wh/2))
    # Add some decoration
    tower -= move(make_window(cw/3, cw*2/3), swidth*0.5, (height/2)-cw*3)
    tower -= move(make_window(cw/3, cw*2/3), swidth*2.1, (height/2)-cw*3)
    tower -= move(make_window(cw/3, cw*2/3), swidth*3.7, (height/2)-cw*3)
    tower -= move(make_window(cw/3, cw*2/3), swidth*5.3, (height/2)-cw*3)
    return tower

parts = ( make_tower(scale, scale*2.5, cw)
     #move(make_wall_a(ww, wh, cw), 0, 0)
     #+ move(make_wall_b(ww, wh, cw), ww*1.2, 0)
    )


cad.shape = parts