#
# spiral.py
# test out different spiral styles.
#

from math import *
import sys
from string import *


HUGE = 1e10

def startNewShape():
	xpath.append([])
	ypath.append([])
	

def addPoint(x, y):	
	xpath[-1].append(x)	
	ypath[-1].append(y)

def addPointB(x, y):	
	xpath[-1].insert(0, x)
	ypath[-1].insert(0, y)


def boxEm(minX, maxX, minY, maxY, padding):
	startNewShape()
	addPoint(minX-padding, minY-padding)
	addPoint(minX-padding, maxY+padding)
	addPoint(maxX+padding, maxY+padding)
	addPoint(maxX+padding, minY-padding)
	addPoint(minX-padding, minY-padding)
		


def addSpiralPoints(originX, originY, innerD, outerD, angle):
	addPoint(originX + cos(angle)*outerD, originY + sin(angle)*outerD)
	addPointB(originX + cos(angle)*innerD, originY + sin(angle)*innerD)

RIGHT = 0
DOWN = 1
LEFT = 2
UP = 3
OVER_DOWN = 4

def spiralRow(originX, originY, traceWidth, blankWidth, centerSize, width, clockwise, endingDirection, tailLength, capEnd, numSpirals, padding):
	startNewShape()
	addPoint(originX - 0.5*width - 0.5*padding, originY - 0.7*width)
	addPoint(originX - 0.5*width - 0.5*padding, originY + 0.7*width) 
	for i in range(0, numSpirals):
		spiral(originX, originY, traceWidth, blankWidth, centerSize, width, clockwise, endingDirection, tailLength, capEnd)
		#line for peeling better
		startNewShape()
		addPoint(originX + 0.5*width + 0.5*padding, originY - 0.7*width)
		addPoint(originX + 0.5*width + 0.5*padding, originY + 0.7*width) 
		originX = originX + width + padding

def dividerRow(originX, originY, traceWidth, blankWidth, centerSize, width, clockwise, endingDirection, tailLength, capEnd, center, edge, alwaysHoleDirection, numSpirals, padding):
	for i in range(0, numSpirals):
		divider(originX, originY, traceWidth, blankWidth, centerSize, width, clockwise, endingDirection, tailLength, capEnd, center, edge, alwaysHoleDirection)
		originX = originX + width + padding
	boxEm(centerX - 0.5* spiralDiameter, centerX + 0.5* spiralDiameter + padding + (numSpirals-1)*(width+padding), centerY-0.5* spiralDiameter, centerY+0.5* spiralDiameter, 0.2)
	
	
def curve(centerX, centerY, radius, startingAngle, endingAngle, clockwise, close):
	if(clockwise):
		if(startingAngle > endingAngle):
			angleTraversed = endingAngle - startingAngle 
		else:
			angleTraversed = endingAngle - startingAngle  - 2*pi
	else:
		if(startingAngle < endingAngle):
			angleTraversed = endingAngle - startingAngle
		else:
			angleTraversed = endingAngle - startingAngle + 2*pi
	angleSteps = int(fabs(angleTraversed/(2*pi) * 30))
	angleStep = angleTraversed/angleSteps
	angle = startingAngle
	print angle, angleStep, angleSteps, angleTraversed
	for i in range(0, angleSteps+1):
		addPoint(centerX + cos(angle)*radius, centerY + sin(angle)*radius)
		angle = angle + angleStep
		if(angle < 0):
			angle = 2*pi + angle
		if(angle > 2*pi):
			angle = angle - 2*pi
	if(close):
		addPoint(centerX + cos(startingAngle)*radius, centerY + sin(startingAngle)*radius)



def divider(originX, originY, traceWidth, blankWidth, centerSize, width, clockwise, endingDirection, tailLength, capEnd, center, edge, alwaysHoleDirection):
	if(center):
		#boxEm(originX - centerSize/2.2, originX + centerSize/2.2, originY, originY + centerSize/2.5, centerSize * 0.1)
		startNewShape()
		curve(originX, originY - centerSize*0.1, centerSize/2.0 + blankWidth, 0, pi, False, True)

	spiral(originX, originY, traceWidth, blankWidth, centerSize, width, clockwise, alwaysHoleDirection, tailLength, False)
	spx = xpath.pop()
	spy = ypath.pop()
	innerX = spx[1]
	outerX = spx[-1]
	innerY = spy[1]
	outerY = spy[-1]
	if(innerX < outerX):
		minX = innerX
		maxX = outerX
	else:
		minX = outerX
		maxX = innerX
	if(innerY < outerY):
		minY = innerY
		maxY = outerY
	else:
		minY = outerY
		maxY = innerY
	dist = maxX - minX + maxY - minY
	
	if(alwaysHoleDirection == RIGHT):
		boxEm(maxX - dist/4.0, maxX, minY, maxY, dist*0.25)
	elif(alwaysHoleDirection == DOWN or alwaysHoleDirection == OVER_DOWN):
		boxEm(minX, maxX, maxY, maxY + dist/4.0, dist*0.25)
	elif(alwaysHoleDirection == LEFT):
		boxEm(maxX, maxX + dist/4.0, minY, maxY, dist*0.25)
	elif(alwaysHoleDirection == UP):
		boxEm(minX, maxX, maxY - dist/4.0, maxY, dist*0.25)

	
	if(not edge):
		return
	spiral(originX, originY, traceWidth, blankWidth, centerSize, width, clockwise, endingDirection, tailLength, False)
	spx = xpath.pop()
	spy = ypath.pop()
	innerX = spx[1]
	outerX = spx[-1]
	innerY = spy[1]
	outerY = spy[-1]
	if(innerX < outerX):
		minX = innerX
		maxX = outerX
	else:
		minX = outerX
		maxX = innerX
	if(innerY < outerY):
		minY = innerY
		maxY = outerY
	else:
		minY = outerY
		maxY = innerY
	dist = maxX - minX + maxY - minY
	
	if(endingDirection == RIGHT):
		boxEm(maxX - dist/4.0, maxX, minY, maxY, dist*0.25)
	elif(endingDirection == DOWN or endingDirection == OVER_DOWN):
		boxEm(minX, maxX, maxY, maxY + dist/4.0, dist*0.25)
	elif(endingDirection == LEFT):
		boxEm(maxX, maxX + dist/4.0, minY, maxY, dist*0.25)
	elif(endingDirection == UP):
		boxEm(minX, maxX, maxY - dist/4.0, maxY, dist*0.25)


#0 is right.  half circle covers centertop.
def spiral(originX, originY, traceWidth, blankWidth, centerSize, width, clockwise, endingDirection, tailLength, capEnd):
	
	#numSteps = 720.0
	numSteps = 45.0
	totalSteps = 0
	if(endingDirection == RIGHT):
		endingAngle = 0
	elif(endingDirection == DOWN):
		endingAngle = 1.5*pi + pi/180.0 * 10
	elif(endingDirection == LEFT):
		endingAngle = pi
	elif(endingDirection == UP):
		endingAngle = 0.5*pi
	elif(endingDirection == OVER_DOWN):
		endingAngle = 1.5*pi - pi/180.0 * 25
		
	startNewShape()
	angleStep = (2*pi)/numSteps
	if(clockwise):
		angleStep = -angleStep
	angle = 0
	if(clockwise):
		angle = pi
	dirMod = -1
	if(clockwise):
		dirMod = 1
	innerD = centerSize/2.0 - traceWidth
	
	while (clockwise and angle > 0) or (not clockwise and angle < pi):
		addPoint(originX + cos(angle)*(innerD+traceWidth), originY + sin(angle)*(innerD+traceWidth))
		angle = angle + angleStep
		innerD = innerD + (traceWidth + blankWidth) / numSteps
	
	if(angle < 0):
		angle = 2*pi - angle
	if(angle > 2*pi):
		angle = angle - 2*pi
	
	while(not (fabs(endingAngle-angle)<(2*pi/numSteps) and ((innerD+traceWidth)>(0.5*width) or (innerD+traceWidth)>(0.5*width)))):
		addSpiralPoints(originX, originY, innerD, innerD+traceWidth, angle)
		angle = angle + angleStep
		if(angle < 0):
			angle = 2*pi + angle
		if(angle > 2*pi):
			angle = angle - 2*pi
		innerD = innerD + (traceWidth + blankWidth) / numSteps
		totalSteps = totalSteps + 1
		#print "NOT (", fabs(endingDirection-angle), "<", (1/numSteps), ") AND (", fabs(originX-(innerD+traceWidth)), ">", 0.5*width, ")"
	print totalSteps / numSteps, " Loops"
	
	#extend inner for connection
	for i in range(1,int(ceil(traceWidth*3.5/(innerD*pi*2/numSteps)))+1):
		addPointB(originX + cos(angle)*(innerD), originY + sin(angle)*(innerD))
		angle = angle + angleStep
		if(angle < 0):
			angle = 2*pi + angle
		if(angle > 2*pi):
			angle = angle - 2*pi
		innerD = innerD + (traceWidth + blankWidth) / numSteps
	
	xInner = xpath[-1][0]
	yInner = ypath[-1][0]
	xOuter = xpath[-1][-1]
	yOuter = ypath[-1][-1]

	
	if(endingDirection == RIGHT):
		xOuter = xOuter + tailLength
		xInner = xInner + tailLength + traceWidth
		yInner = yInner - dirMod*(0.06 - traceWidth)
		yOuter = yOuter - dirMod*(0.03 - traceWidth)
	elif(endingDirection == DOWN or endingDirection == OVER_DOWN):
		yOuter = yOuter - tailLength
		yInner = yInner - tailLength - traceWidth
		xInner = xInner - dirMod*(0.06 - traceWidth)
		xOuter = xOuter - dirMod*(0.03 - traceWidth)
	elif(endingDirection == LEFT):
		xOuter = xOuter - tailLength
		xInner = xInner - tailLength - traceWidth
		yInner = yInner + dirMod*(0.06 - traceWidth)
		yOuter = yOuter + dirMod*(0.03 - traceWidth)
	elif(endingDirection == UP):
		yOuter = yOuter + tailLength
		yInner = yInner + tailLength + traceWidth
		xInner = xInner + dirMod*(0.06 - traceWidth)
		xOuter = xOuter + dirMod*(0.03 - traceWidth)
	addPoint(xOuter, yOuter)
	addPointB(xInner, yInner)

	
	
	if(capEnd):
		addPoint(xInner, yInner)
		
	#add cut for helpful peeling
	
	dx = xpath[-1][0] - xpath[-1][1]
	dy = ypath[-1][0] - ypath[-1][1]
	
	addPointB(xInner + dx, yInner+dy)
	
	


#origin is minX, minY.
def squareSpiral(originX, originY, traceWidth, blankWidth, centerSize, width, clockwise, endingDirection, tailLength, capEnd):
	xpath.append([])
	ypath.append([])

	dirMod = 1
	if(not clockwise):
		dirMod = -1
		
	innerLength = centerSize + blankWidth - traceWidth
	centerSizeY = (innerLength + (traceWidth + blankWidth) / 2.0) - blankWidth * 2

	#draw middle. come out top
	xpath[-1].append(originX - dirMod*0.5*centerSize)	
	ypath[-1].append(originY + 0.5*centerSizeY)
	
	xpath[-1].append(originX - dirMod*0.5*centerSize)	
	ypath[-1].append(originY - 0.5*centerSizeY)
	
	xpath[-1].append(originX + dirMod*0.5*centerSize)	
	ypath[-1].append(originY - 0.5*centerSizeY)
	
	xpath[-1].append(originX + dirMod*0.5*centerSize)	
	ypath[-1].append(originY + 0.5*centerSizeY)
	
	xpath[-1].append(originX - dirMod*(0.5*centerSize - traceWidth))
	ypath[-1].append(originY + 0.5*centerSizeY)
	
	
	#first short chunk
	xInner = originX - dirMod*(0.5*centerSize - traceWidth)
	yInner = originY + 0.5*centerSizeY + blankWidth
	xpath[-1].append(xInner)
	ypath[-1].append(yInner)
	
	xOuter = originX - dirMod*(0.5*centerSize)
	yOuter = originY + 0.5*centerSizeY + blankWidth + traceWidth
	xpath[-1].insert(0, xOuter)
	ypath[-1].insert(0, yOuter)
 
	numsegments = 0
	

	direction = -1;
	while(not (endingDirection == direction and (fabs(originX-xOuter) > 0.5*width or fabs(originY-yOuter) > 0.5*width))):
		direction = (direction + 1) % 4
	
		if(direction == 0): #right
			xInner = xInner + dirMod*innerLength
			xOuter = xOuter + dirMod*(innerLength + 2*traceWidth)
		elif(direction == 1): #down
			yInner = yInner - innerLength
			yOuter = yOuter - innerLength - 2*traceWidth
		elif(direction == 2): #left
			xInner = xInner - dirMod*innerLength
			xOuter = xOuter - dirMod*(innerLength + 2*traceWidth)
		elif(direction == 3): #up
			yInner = yInner + innerLength
			yOuter = yOuter + innerLength + 2*traceWidth
		xpath[-1].append(xInner)
		ypath[-1].append(yInner)
	
		xpath[-1].insert(0, xOuter)
		ypath[-1].insert(0, yOuter)
		
		innerLength += (traceWidth + blankWidth) / 2.0
		numsegments = numsegments + 1
	
	print (numsegments/4), "turns."
	
	if(endingDirection == 0): #right
		xOuter = xOuter + tailLength
		xInner = xInner + tailLength + traceWidth
		yInner = yInner + dirMod*(0.018 - traceWidth)
	elif(endingDirection == 1): #down
		yOuter = yOuter - tailLength
		yInner = yInner - tailLength - traceWidth
		xInner = xInner - dirMod*(0.018 - traceWidth)
	elif(endingDirection == 2): #left
		xOuter = xOuter - tailLength
		xInner = xInner - tailLength - traceWidth
		yInner = yInner - dirMod*(0.018 - traceWidth)
	elif(endingDirection == 3): #up
		yOuter = yOuter + tailLength
		yInner = yInner + tailLength + traceWidth
		xInner = xInner + dirMod*(0.018 - traceWidth)
		
	xpath[-1].append(xInner)
	ypath[-1].append(yInner)

	xpath[-1].insert(0, xOuter)
	ypath[-1].insert(0, yOuter)
	
	if(capEnd):
		 xpath[-1].append(xOuter)
		 ypath[-1].append(yOuter)




def svgwrite(xpath,ypath,filename):
	xmin = HUGE
	ymin = HUGE
	xmax = -HUGE
	ymax = -HUGE
	for piece in range(len(xpath)):
		for point in range(len(xpath[piece])):
			x = xpath[piece][point]
			y = ypath[piece][point]
			if (x < xmin): xmin = x
			if (x > xmax): xmax = x
			if (y < ymin): ymin = y
			if (y > ymax): ymax = y
	outfile = open(filename,"w")
	outfile.write('<?xml version="1.0" encoding="UTF-8"?>\n')
	outfile.write('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">\n')
	outfile.write('<svg width="%fin" height="%fin" viewBox="%f %f %f %f">\n'\
		%(xmax-xmin,ymax-ymin,xmin,ymin,xmax-xmin,ymax-ymin))
	outfile.write('<g style="stroke:rgb(0,0,0);fill:none">\n')
	for piece in range(len(xpath)):
		outfile.write('<polyline points="')
		for point in range(len(xpath[piece])):
			x = xpath[piece][point]
			y = ypath[piece][point]
			outfile.write('%f,%f '%(x,y))
		x = xpath[piece][-1]
		y = ypath[piece][-1]
		outfile.write('%f,%f" '%(x,y))
		outfile.write('style="fill:none"/>\n')
	outfile.write('</g>\n')
	outfile.write('</svg>\n')
	outfile.close()

x = 0
y = 0

xpath = []
ypath = []


def testIt():
	originX = 0
	originY = 0

		
outfile = "out.svg"
copper_width = 0.02
space_width = 0.02 #0.15 #.022
spiralDiameter = 0.8
middleSize = 0.15 #0.1
tailLength = 0.1
endingDirection = DOWN
clockwise = True
cap = True
centerX = 0
centerY = 0
centerHole = True
edgeHole = True
spiralPadding = 0.07

numBottomRow = 0
if(numBottomRow > 0):
	endingDirection = DOWN
	clockwise = True
	spiralRow(centerX, centerY, copper_width, space_width, middleSize, spiralDiameter, clockwise, endingDirection, tailLength, cap, numBottomRow, spiralPadding)
	
numBottomDivider = 0
if(numBottomDivider > 0):
	endingDirection = DOWN
	clockwise = True
	centerHole = True
	edgeHole = False
	dividerRow(centerX, centerY, copper_width, space_width, middleSize, spiralDiameter, clockwise, endingDirection, tailLength, cap, centerHole, edgeHole, DOWN, numBottomDivider, spiralPadding)
	
numSecondRow = 0
if(numSecondRow > 0):
	endingDirection = UP
	clockwise = False
	spiralRow(centerX, centerY, copper_width, space_width, middleSize, spiralDiameter, clockwise, endingDirection, tailLength, cap, numSecondRow, spiralPadding)

numSecondDivider = 0
if(numSecondDivider > 0):
	endingDirection = UP
	clockwise = False
	centerHole = False
	edgeHole = True
	dividerRow(centerX, centerY, copper_width, space_width, middleSize, spiralDiameter, clockwise, endingDirection, tailLength, cap, centerHole, edgeHole, DOWN, numSecondDivider, spiralPadding)

numThirdRow = 0
if(numThirdRow > 0):
	endingDirection = UP
	clockwise = True
	spiralRow(centerX, centerY, copper_width, space_width, middleSize, spiralDiameter, clockwise, endingDirection, tailLength, cap, numThirdRow, spiralPadding)

numThirdDivider = 0
if(numThirdDivider > 0):
	endingDirection = UP
	clockwise = True
	centerHole = True
	edgeHole = False
	dividerRow(centerX, centerY, copper_width, space_width, middleSize, spiralDiameter, clockwise, endingDirection, tailLength, cap, centerHole, edgeHole, DOWN, numThirdDivider, spiralPadding)

numTopRow = 0
if(numTopRow > 0):
	endingDirection = OVER_DOWN
	clockwise = False
	spiralRow(centerX, centerY, copper_width, space_width, middleSize, spiralDiameter, clockwise, endingDirection, tailLength, cap, numTopRow, spiralPadding)

numTopDivider = 0
if(numTopDivider > 0):
	endingDirection = OVER_DOWN
	clockwise = False
	centerHole = False
	edgeHole = True
	dividerRow(centerX, centerY, copper_width, space_width, middleSize, spiralDiameter, clockwise, endingDirection, tailLength, cap, centerHole, edgeHole, DOWN, numTopDivider, spiralPadding)


squareSpiral(0, 0, copper_width, space_width, middleSize, spiralDiameter, clockwise, endingDirection, tailLength, cap)
#spiral(centerX, centerY, copper_width, space_width, middleSize, spiralDiameter, clockwise, endingDirection, tailLength, cap)
#endingDirection = UP
#spiral(centerX, centerY, copper_width, space_width, middleSize, spiralDiameter, clockwise, endingDirection, tailLength, cap)
#divider(centerX, centerY, copper_width, space_width, middleSize, spiralDiameter, clockwise, endingDirection, tailLength, cap, centerHole, edgeHole, DOWN)
#padding = 0.05
#boxEm(centerX - 0.5* spiralDiameter, centerX + 0.5* spiralDiameter, centerY-0.5* spiralDiameter - 0.1, centerY+0.5* spiralDiameter + 0.1, padding)


svgwrite(xpath,ypath,"out.svg")

print "Spirals written to out.svg"