#! /usr/bin/python
#coding=utf-8
"""
	calibrating g-code generator by Setar (C)2013
	converted to Python by tedbeer

	Usage: python setar.py flow|width|temp|suckL|suckV
"""

import math, sys

def xfrange(start, stop=None, step=None):
	"""Like range(), but returns list of floats instead

	All numbers are generated on-demand using generators
	"""

	if stop is None:
		stop = float(start)
		start = 0.0

	if step is None:
		step = 1.0

	cur = float(start)

	while cur <= stop:
		yield cur
		cur += step

fil_dia = 1.75 # диаметр прутка
path_h = 0.25 # высота слоя
path_w = 0.32 # ширина слоя
path_k = 0.875 # коэфициент заполнения прямоугольника при экструзии, KisSlicer =1
temp = 245 # температура
bed_temp = 130 # температура стола
fill_speed = 30 # скорость экструзии
move_speed = 100 # скорость перемещения
max_x = 180. # размер стола
max_y = 180. # размер стола

fil_s = k_s = path_s = 0.0
pos_e = pos_x = pos_y = pos_z = 0.0

# инициализация
def init():
	global fil_s, k_s, path_s

	fil_s = math.pi * fil_dia * fil_dia /4 # площадь сечения прутка
	path_s = path_k * path_w * path_h # площадь слоя укладки
	k_s = path_s / fil_s # отношение площадей прутка и экструзии

# расход прутка для заданной длинны экструзии
def filament_length (path_l):
	return float(k_s*path_l)


def label():
	print ';3Dprinter calibrator v0.0.2 setar@roboforum.ru LGPL 2013'
	print ';Filament Dia = %.3f mm' % fil_dia
	print ';Path heigth = %.3f mm' % path_h
	print ';Path width = %.3f mm' % path_w
	print ';Path filling = %.3f' % path_k
	print ';Temp = %.fC' % temp
	print ';Bed temp = %.fC' % bed_temp
	print ';Fill speed = %.f mm/s' % fill_speed
	print ';Move speed = %.f mm/s' % move_speed
	print ';Max X = %.f mm' % max_x
	print ';Max Y = %.f mm' % max_y
	print ';--- calculated ---'
	print ';Filament S = %.4f mm^2' % fil_s
	print ';Path S = %.4f mm^2' % path_s
	print ';Path S/Filament S = %.4f mm^2' % k_s


def start_g():
	print ';--- start gcode ---'
	print 'G28 ; home'
	print 'G21 ; unit in mm'
	print 'G92 E0 ; set extruder to zero'
	print 'M82 ; use absolute distances'
	print 'M107 ; fan off'
	print 'M104 S%.f; set temp' % temp
	print 'M190 S%.f; wait bed temp' % bed_temp
	print ';--- head clean ---'
	print 'G1 X0 Y0 Z15 F15000;go start positions'
	print 'M109 S%.f; wait heat' % temp
	print 'G1 X0 Y10 Z0.5;go near bed level '
	print 'G1 E5 F100; extruse a bubble'
	print 'G4 S5 ; wait 5 sec'
	print 'G1 Z5'
	print 'G4 S3 ; wait 3 sec'
	print 'G1 F15000'
	print 'G1 X0 Y20 Z%.2f' % path_h
	print 'G1 X0 Y35'
	print ';--- end start gcode ---'

def stop_g():
	print ';--- stop gcode ---'
	print 'M400 ; wait for buffer to clear'
	print 'M104 S0 ; turn off temperature'
	print 'M140 S0 ; turn off bed'
	print 'G0 Y150 Z%.2f F15000 ; Present Part' % (pos_z+5)
	print 'M84 ; disable motors'
	print ''

# линия из текущей позиции в x,y на высоте z со скоростью s (mm/c) и потоком flow (относительно 1)
def fill_line ( x, y, z, s,  flow):
	global pos_e, pos_x, pos_y, pos_z

	len_ = math.sqrt((pos_x-x)*(pos_x-x)+(pos_y-y)*(pos_y-y))
	dest_e = pos_e + flow * filament_length(len_)
	f = s * 60
	print 'G1 X%.2f Y%.2f Z%.2f E%.2f F%.f' % (x,y,z,dest_e,f)
	pos_e = dest_e
	pos_x = x
	pos_y = y
	pos_z = z

# перемещение в точку x,y,z со скоростью s (mm/c)
def move_to ( x, y,  z,  s):
	global pos_x, pos_y, pos_z

	f = float(s) * 60
	print 'G1 X%.2f Y%.2f Z%.2f F%.f' % (x,y,z,f)
	pos_x = x
	pos_y = y
	pos_z = z

def zero_pos_e():
	global pos_e
	print 'G92 E0'
	pos_e = 0

def path_width_adjust():
	global pos_e, pos_x, pos_y, pos_z, path_h, path_k, path_w

	flow = 1.0
	mid_x = max_x / 2
	mid_y = max_y / 2
	pos_z = 3 * path_h

	n = 0
	for wk in xfrange(0.8, 2, 0.1):
		n = n+1
		path_w = path_h * wk
		print ';--- path_w %.3f start ---' % path_w
		for x in xfrange(n*7+(mid_x-50)+5, n*7 + (mid_x-50)+10 - 0.001, 2*path_w):
			move_to(x,(mid_y-50),pos_z,move_speed)
			fill_line(x,(mid_y+50),pos_z,fill_speed,flow)
			move_to(x+path_w,(mid_y+50),pos_z,move_speed)
			fill_line(x+path_w,(mid_y-50),pos_z,fill_speed,flow)
		print ';--- path_w %.3f stop ---' % path_w
		zero_pos_e()

def temp_adjust():
	global pos_e, pos_x, pos_y, pos_z, path_h, path_k, path_w

	flow = 0.0
	pos_z = 3 * path_h
	mid_x = max_x/2
	mid_y = max_y/2
	min_temp = 180.0
	max_temp = 260.0

	n = 0
	for temp in xfrange(min_temp, max_temp, (max_temp-min_temp)/10):
		n=n+1
		print ';--- temp %.2f start ---' % temp
		print 'G1 Z%.f' % (pos_z+5)
		print 'M109 S%.f; wait heat' % temp
		for x in xfrange(n*7+(mid_x-50)+5, n*7+(mid_x-50)+10 - 0.001, 2*path_w):
			move_to(x,mid_y-50,pos_z,move_speed)
			fill_line(x,mid_y+50,pos_z,fill_speed,1)
			move_to(x+path_w,mid_y+50,pos_z,move_speed)
			fill_line(x+path_w,mid_y-50,pos_z,fill_speed,1)
		print ';--- temp %.2f stop ---' % temp
		zero_pos_e()

def path_flow_adjust():
	global pos_e, pos_x, pos_y, pos_z, path_h, path_k, path_w

	flow = 0.0
	pos_z = 3*path_h
	mid_x = max_x/2
	mid_y = max_y/2

	n = 0
	for flow in xfrange(0.2, 2.2 - 0.001, 0.2):
		n=n+1
		print ';--- fill %.2f start ---' % flow
		for x in xfrange(n*7+(mid_x-50)+5, n*7+(mid_x-50)+10 - 0.001, 2*path_w):
			move_to(x,mid_y-50,pos_z,move_speed)
			fill_line(x,mid_y+50,pos_z,fill_speed,flow)
			move_to(x+path_w,mid_y+50,pos_z,move_speed)
			fill_line(x+path_w,mid_y-50,pos_z,fill_speed,flow)
		print ';--- fill %.2f stop ---' % flow
		zero_pos_e()

def do_suck(suck, s):
	global pos_e
	dest_e = pos_e - suck
	f = s * 60
	print 'G1 E%.2f F%.2f' % (dest_e,f)
	pos_e = dest_e

def do_prime(prime, s):
	global pos_e
	dest_e = pos_e + prime
	f = s * 60
	print 'G1 E%.2f F%.2f' % (dest_e,f)
	pos_e = dest_e

def suck_adjust():
	global pos_e, pos_x, pos_y, pos_z, path_h, path_k, path_w

	mid_x = max_x/2
	mid_y = max_y/2
	pos_z = 3*path_h
	suck_speed = 10.0

	n = 0
	for suck in xfrange(0.4, 2, 0.2):
		n=n+1
		print ';--- suck %.2f start ---' % suck
		for x in xfrange(n*10+(mid_x-50)+5, n*10+(mid_x-50)+10 - 0.001, 2*path_w):
			# прямое направление
			move_to(x,(mid_y-50),pos_z,move_speed)
			fill_line(x,(mid_y-30),pos_z,fill_speed,1)
			do_suck(suck,suck_speed)
			move_to(x,(mid_y+30),pos_z,move_speed)
			do_prime(suck,suck_speed)
			fill_line(x,(mid_y+50),pos_z,fill_speed,1)
			# обратное направление
			move_to(x+path_w,(mid_y+50),pos_z,move_speed)
			fill_line(x+path_w,(mid_y+30),pos_z,fill_speed,1)
			do_suck(suck,suck_speed)
			move_to(x+path_w,(mid_y-30),pos_z,move_speed)
			do_prime(suck,suck_speed)
			fill_line(x+path_w,(mid_y-50),pos_z,fill_speed,1)
		print ';--- suck %.2f stop ---' % suck
		zero_pos_e()

def suck_speed_adjust(suck):
	global pos_z

	mid_x = max_x/2
	mid_y = max_y/2
	pos_z = 3*path_h

	n = 0
	for suck_speed in xrange(2, 50, 4):
		n=n+1
		print ';--- suck speed %.2f start ---' % suck_speed
		for x in xfrange(n*7+(mid_x-50), n*7+(mid_x-50)+5 - 0.001, 2*path_w):
			# прямое направление
			move_to(x,(mid_y-50),pos_z,move_speed)
			fill_line(x,(mid_y-30),pos_z,fill_speed,1)
			do_suck(suck,suck_speed)
			move_to(x,(mid_y+30),pos_z,move_speed)
			do_prime(suck,suck_speed)
			fill_line(x,(mid_y+50),pos_z,fill_speed,1)
			# обратное направление
			move_to(x+path_w,(mid_y+50),pos_z,move_speed)
			fill_line(x+path_w,(mid_y+30),pos_z,fill_speed,1)
			do_suck(suck,suck_speed)
			move_to(x+path_w,(mid_y-30),pos_z,move_speed)
			do_prime(suck,suck_speed)
			fill_line(x+path_w,(mid_y-50),pos_z,fill_speed,1)
		print ';--- suck speed %.2f stop ---' % suck_speed
		zero_pos_e()

def runTest(test):
	global pos_e, pos_x, pos_y, pos_z, path_h, path_k, path_w

	init() # инициализация
	label() # печать заголовка
	start_g() # стартовый код
	zero_pos_e() # занулим положение прутка

	x = y = 0.0

	print ';--- raft ---'
	pos_z= 2*path_h

	mid_x = max_x/2
	mid_y = max_y/2

	move_to((mid_x-50)-path_w/2,(mid_y-50)-path_w/2,pos_z,move_speed)
	do_prime(1,1) #якорь
	print 'G4 S3 ; wait 3 sec'
	fill_line((mid_x+50)+path_w/2,(mid_y-50)-path_w/2,pos_z,fill_speed,3)
	fill_line((mid_x+50)+path_w/2,(mid_y+50)+path_w/2,pos_z,fill_speed,3)
	fill_line((mid_x-50)-path_w/2,(mid_y+50)+path_w/2,pos_z,fill_speed,3)
	fill_line((mid_x-50)-path_w/2,(mid_y-50)+path_w/2,pos_z,fill_speed,3)
	move_to((mid_x-50),(mid_y-50),pos_z,move_speed)
	for y in xfrange(mid_y-50, mid_y+50 - 0.001, 2*1):
		fill_line((mid_x+50),y,pos_z,fill_speed,3)
		fill_line((mid_x+50),y+1,pos_z,fill_speed,3)
		fill_line((mid_x-50),y+1,pos_z,fill_speed,3)
		fill_line((mid_x-50),y+2*1,pos_z,fill_speed,3)
	print ';--- end raft ---'
	# из нижеследующих тестов нужно выбрать один сняв ремарку
	if test == 'flow':
		path_flow_adjust() # подбираем поток (при нормально калиброванном экструдере не требуется)
	elif test == 'width':
		path_width_adjust() # подбираем ширину экструзии
	elif test == 'temp':
		temp_adjust() # подбираем температуру печати
	elif test == 'suckL':
		suck_adjust() # подбираем величину отката
	elif test == 'suckV':
		suck_speed_adjust(1) # подбираем скорость отката
	else:
		path_width_adjust()

	stop_g() # код окончания

if __name__ == '__main__':
	if len(sys.argv) < 2:
		print 'Usage: python setar.py flow|width|temp|suckL|suckV'
	else:
		runTest(sys.argv[1])
