#!/usr/bin/env python 
"""
LT comments are by Chris Lusby Taylor
History:
Changed several for t in (0,.25.;75,1) to include .5, exclude duplicate endpoints
Changed test of tool diameter to square it
Removed everything to do with find_cutter_center. The only way I now test is 
intersection of circle with point - no attempt to match its slope.
5 May changed outer angle refinement to [.2,.4,.6,.8]:
10 May removed unused functions: bound_to_bound_distance, csp_curvature_radius_at_t,
       csp_special_points, csplength, rebuild_csp, csp_slope,
       csp_simple_bound_to_point_distance, csp_bound_to_point_distance, csp_reverse,
       bez_at_t, bez_to_point_distance, bez_normalized_slope, matrix_mul, transpose
      Started to add function to find max radius bounded by a given line and tangent
13 May Started to add bezier_divide function
14 May changed ti to use all four values. Didn't seem to make any difference
       test if csp_point_inside_bound actually works if x not in range. It doesn't
       but I fixed it. It now works.
       Got as far as adding nlLT list of normals. One per straight line, one per
       divided Bezier. Should that be 4, i.e. use the control points?
16 May 
18 May Great success, especially with large objects, so probably need to reduce Bez divisions
19 May New thought - store Bez as a series of points with normals, not lines
       as we don't want to give impression that the radius near an apparent corner needs to be small.
Each Bez is the gap between two csp points, but it is the points that we need
not the line between them. The normal should be stored as the bisector of the
control point vectors.
20 May 11:45ish Successfully coded the bisection of angles without using any trig functions.
   ver 17 adds reflex angle code for both entering and leaving a reflex corner.
 22 May Start even more sophisticated code. See VCarveCornerStuff4LT.svg and 5
 23 May ver 18: Using r/cos(a) instead of normalised normals for bisectors of angles.
 23 May ver 19: Investigating why Z values too big. Are they in pixels?
                First try at removing the biarc curves etc. Abandoning existing code that creates
                cubics that approximate to the toolpath, then base biarcs on that. I prefer straight
                lines.
 24 May ver 20. Removed the original csp_points and other structures, as no longer needed.
                Changed bounds testing to allow non-normalised normals at corners.
TODO: Add some means to vary the accuracy/complexity of the output.
 24 May ver 20. Changed Bezier slope calculation to be less sensitive to tiny differences in points.
                Added use of self.options.engraving_newton_iterations to control accuracy


Copyright (C) 2009 Nick Drobchenko, nick@cnc-club.ru
based on gcode.py (C) 2007 hugomatic... 
based on addnodes.py (C) 2005,2007 Aaron Spike, aaron@ekips.org
based on dots.py (C) 2005 Aaron Spike, aaron@ekips.org
based on interp.py (C) 2005 Aaron Spike, aaron@ekips.org
based on bezmisc.py (C) 2005 Aaron Spike, aaron@ekips.org
based on cubicsuperpath.py (C) 2005 Aaron Spike, aaron@ekips.org

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
"""

###
###		Gcodetools v 1.6.04 
###
gcodetools_current_version = "1.6.04"

import inkex, simplestyle, simplepath
import cubicsuperpath, simpletransform, bezmisc

import os
import math
import bezmisc
import re
import copy
import sys
import time
import cmath
import numpy
import codecs
import random
import gettext
_ = gettext.gettext

 
### Check if inkex has errormsg (0.46 version does not have one.) Could be removed later.
if "errormsg" not in dir(inkex):
	inkex.errormsg = lambda msg: sys.stderr.write((unicode(msg) + "\n").encode("UTF-8"))


def bezierslopeatt(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)),t):
	ax,ay,bx,by,cx,cy,x0,y0=bezmisc.bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
	dx=3*ax*(t**2)+2*bx*t+cx
	dy=3*ay*(t**2)+2*by*t+cy
	if dx==dy==0 : 
		dx = 6*ax*t+2*bx
		dy = 6*ay*t+2*by
		if dx==dy==0 : 
			dx = 6*ax
			dy = 6*ay
			if dx==dy==0 : 
				print_("Slope error x = %s*t^3+%s*t^2+%s*t+%s, y = %s*t^3+%s*t^2+%s*t+%s,  t = %s, dx==dy==0" % (ax,bx,cx,dx,ay,by,cy,dy,t))
				print_(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
				dx, dy = 1, 1
				
	return dx,dy
bezmisc.bezierslopeatt = bezierslopeatt


def ireplace(self,old,new,count=0):
	pattern = re.compile(re.escape(old),re.I)
	return re.sub(pattern,new,self,count) 

################################################################################
###
###		Styles and additional parameters
###
################################################################################

math.pi2 = math.pi*2
straight_tolerance = 0.0001
straight_distance_tolerance = 0.0001
engraving_tolerance = 0.0001
loft_lengths_tolerance = 0.0000001
options = {}
defaults = {
'header': """%
(Header)
(Generated by gcodetools from Inkscape.)
(Using default header. To add your own header create file "header" in the output dir.)
M3
(Header end.)
""",
'footer': """
(Footer)
M5
G00 X0.0000 Y0.0000
M2
(Using default footer. To add your own footer create file "footer" in the output dir.)
(end)
%"""
}

intersection_recursion_depth = 10
intersection_tolerance = 0.00001

styles = {
		"loft_style" : {
				'main curve':	simplestyle.formatStyle({ 'stroke': '#88f', 'fill': 'none', 'stroke-width':'1', 'marker-end':'url(#Arrow2Mend)' }),
			},
		"biarc_style" : {
				'biarc0':	simplestyle.formatStyle({ 'stroke': '#88f', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
				'biarc1':	simplestyle.formatStyle({ 'stroke': '#8f8', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
				'line':		simplestyle.formatStyle({ 'stroke': '#f88', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
				'area':		simplestyle.formatStyle({ 'stroke': '#777', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.1' }),
			},
		"biarc_style_dark" : {
				'biarc0':	simplestyle.formatStyle({ 'stroke': '#33a', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
				'biarc1':	simplestyle.formatStyle({ 'stroke': '#3a3', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
				'line':		simplestyle.formatStyle({ 'stroke': '#a33', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
				'area':		simplestyle.formatStyle({ 'stroke': '#222', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
			},
		"biarc_style_dark_area" : {
				'biarc0':	simplestyle.formatStyle({ 'stroke': '#33a', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.1' }),
				'biarc1':	simplestyle.formatStyle({ 'stroke': '#3a3', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.1' }),
				'line':		simplestyle.formatStyle({ 'stroke': '#a33', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.1' }),
				'area':		simplestyle.formatStyle({ 'stroke': '#222', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
			},
		"biarc_style_i"  : {
				'biarc0':	simplestyle.formatStyle({ 'stroke': '#880', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
				'biarc1':	simplestyle.formatStyle({ 'stroke': '#808', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
				'line':		simplestyle.formatStyle({ 'stroke': '#088', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
				'area':		simplestyle.formatStyle({ 'stroke': '#999', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
			},
		"biarc_style_dark_i" : {
				'biarc0':	simplestyle.formatStyle({ 'stroke': '#dd5', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
				'biarc1':	simplestyle.formatStyle({ 'stroke': '#d5d', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
				'line':		simplestyle.formatStyle({ 'stroke': '#5dd', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
				'area':		simplestyle.formatStyle({ 'stroke': '#aaa', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
			},
		"biarc_style_lathe_feed" : {
				'biarc0':	simplestyle.formatStyle({ 'stroke': '#07f', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
				'biarc1':	simplestyle.formatStyle({ 'stroke': '#0f7', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
				'line':		simplestyle.formatStyle({ 'stroke': '#f44', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
				'area':		simplestyle.formatStyle({ 'stroke': '#aaa', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
			},
		"biarc_style_lathe_passing feed" : {
				'biarc0':	simplestyle.formatStyle({ 'stroke': '#07f', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
				'biarc1':	simplestyle.formatStyle({ 'stroke': '#0f7', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
				'line':		simplestyle.formatStyle({ 'stroke': '#f44', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
				'area':		simplestyle.formatStyle({ 'stroke': '#aaa', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
			},
		"biarc_style_lathe_fine feed" : {
				'biarc0':	simplestyle.formatStyle({ 'stroke': '#7f0', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
				'biarc1':	simplestyle.formatStyle({ 'stroke': '#f70', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
				'line':		simplestyle.formatStyle({ 'stroke': '#744', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
				'area':		simplestyle.formatStyle({ 'stroke': '#aaa', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
			},
		"area artefact": 		simplestyle.formatStyle({ 'stroke': '#ff0000', 'fill': '#ffff00', 'stroke-width':'1' }),
		"area artefact arrow":	simplestyle.formatStyle({ 'stroke': '#ff0000', 'fill': '#ffff00', 'stroke-width':'1' }),
		"dxf_points":		 	simplestyle.formatStyle({ "stroke": "#ff0000", "fill": "#ff0000"}),
		
	}


################################################################################
###		Cubic Super Path additional functions
################################################################################

def csp_simple_bound(csp):
	minx,miny,maxx,maxy = None,None,None,None
	for subpath in csp:
		for sp in subpath : 
			for p in sp:
				minx = min(minx,p[0]) if minx!=None else p[0]
				miny = min(miny,p[1]) if miny!=None else p[1]
				maxx = max(maxx,p[0]) if maxx!=None else p[0]
				maxy = max(maxy,p[1]) if maxy!=None else p[1]
	return minx,miny,maxx,maxy		


def csp_segment_to_bez(sp1,sp2) :
	return sp1[1:]+sp2[:2]


def csp_to_point_distance(csp, p, dist_bounds = [0,1e100], tolerance=.01) :
	min_dist = [1e100,0,0,0]
	for j in range(len(csp)) :
		for i in range(1,len(csp[j])) :
			d = csp_seg_to_point_distance(csp[j][i-1],csp[j][i],p,sample_points = 5, tolerance = .01)
			if d[0] < dist_bounds[0] : 
#				draw_pointer( list(csp_at_t(subpath[dist[2]-1],subpath[dist[2]],dist[3]))
#					+list(csp_at_t(csp[dist[4]][dist[5]-1],csp[dist[4]][dist[5]],dist[6])),"red","line", comment = math.sqrt(dist[0]))
				return [d[0],j,i,d[1]]
			else : 
				if d[0] < min_dist[0] : min_dist = [d[0],j,i,d[1]]
	return min_dist
			
def csp_seg_to_point_distance(sp1,sp2,p,sample_points = 5, tolerance = .01) :
	ax,ay,bx,by,cx,cy,dx,dy = csp_parameterize(sp1,sp2)
	dx, dy = dx-p[0], dy-p[1]
	if sample_points < 2 : sample_points = 2
	d = min( [(p[0]-sp1[1][0])**2 + (p[1]-sp1[1][1])**2,0.], [(p[0]-sp2[1][0])**2 + (p[1]-sp2[1][1])**2,1.]	)	
	for k in range(sample_points) :
		t = float(k)/(sample_points-1)
		i = 0
		while i==0 or abs(f)>0.000001 and i<20 : 
			t2,t3 = t**2,t**3
			f = (ax*t3+bx*t2+cx*t+dx)*(3*ax*t2+2*bx*t+cx) + (ay*t3+by*t2+cy*t+dy)*(3*ay*t2+2*by*t+cy)
			df = (6*ax*t+2*bx)*(ax*t3+bx*t2+cx*t+dx) + (3*ax*t2+2*bx*t+cx)**2 + (6*ay*t+2*by)*(ay*t3+by*t2+cy*t+dy) + (3*ay*t2+2*by*t+cy)**2
			if df!=0 :
				t = t - f/df
			else :	
				break
			i += 1	
		if 0<=t<=1 : 
			p1 = csp_at_t(sp1,sp2,t)
			d1 = (p1[0]-p[0])**2 + (p1[1]-p[1])**2
			if d1 < d[0] :
				d = [d1,t]
	return d	


def csp_seg_to_csp_seg_distance(sp1,sp2,sp3,sp4, dist_bounds = [0,1e100], sample_points = 5, tolerance=.01) : 
	# check the ending points first
	dist =	csp_seg_to_point_distance(sp1,sp2,sp3[1],sample_points, tolerance)
	dist += [0.]
	if dist[0] <= dist_bounds[0] : return dist
	d = csp_seg_to_point_distance(sp1,sp2,sp4[1],sample_points, tolerance)
	if d[0]<dist[0] :
		dist = d+[1.]
		if dist[0] <= dist_bounds[0] : return dist
	d =	csp_seg_to_point_distance(sp3,sp4,sp1[1],sample_points, tolerance)
	if d[0]<dist[0] :
		dist = [d[0],0.,d[1]]
		if dist[0] <= dist_bounds[0] : return dist
	d =	csp_seg_to_point_distance(sp3,sp4,sp2[1],sample_points, tolerance)
	if d[0]<dist[0] :
		dist = [d[0],1.,d[1]]
		if dist[0] <= dist_bounds[0] : return dist
	sample_points -= 2
	if sample_points < 1 : sample_points = 1
	ax1,ay1,bx1,by1,cx1,cy1,dx1,dy1 = csp_parameterize(sp1,sp2)
	ax2,ay2,bx2,by2,cx2,cy2,dx2,dy2 = csp_parameterize(sp3,sp4)
	#	try to find closes points using Newtons method
	for k in range(sample_points) :
		for j in range(sample_points) : 
			t1,t2 = float(k+1)/(sample_points+1), float(j)/(sample_points+1)
			t12, t13, t22, t23 = t1*t1, t1*t1*t1, t2*t2, t2*t2*t2
			i = 0
			F1, F2, F = [0,0], [[0,0],[0,0]], 1e100
			x,y   = ax1*t13+bx1*t12+cx1*t1+dx1 - (ax2*t23+bx2*t22+cx2*t2+dx2), ay1*t13+by1*t12+cy1*t1+dy1 - (ay2*t23+by2*t22+cy2*t2+dy2)			
			while i<2 or abs(F-Flast)>tolerance and i<30 :
				#draw_pointer(csp_at_t(sp1,sp2,t1))
				f1x = 3*ax1*t12+2*bx1*t1+cx1
				f1y = 3*ay1*t12+2*by1*t1+cy1
				f2x = 3*ax2*t22+2*bx2*t2+cx2
				f2y = 3*ay2*t22+2*by2*t2+cy2
				F1[0] = 2*f1x*x +  2*f1y*y
				F1[1] = -2*f2x*x -  2*f2y*y
				F2[0][0] =  2*(6*ax1*t1+2*bx1)*x + 2*f1x*f1x + 2*(6*ay1*t1+2*by1)*y +2*f1y*f1y
				F2[0][1] = -2*f1x*f2x - 2*f1y*f2y
				F2[1][0] = -2*f2x*f1x - 2*f2y*f1y 
				F2[1][1] = -2*(6*ax2*t2+2*bx2)*x + 2*f2x*f2x - 2*(6*ay2*t2+2*by2)*y + 2*f2y*f2y
				F2 = inv_2x2(F2)
				if F2!=None :
					t1 -= ( F2[0][0]*F1[0] + F2[0][1]*F1[1] )
					t2 -= ( F2[1][0]*F1[0] + F2[1][1]*F1[1] )
					t12, t13, t22, t23 = t1*t1, t1*t1*t1, t2*t2, t2*t2*t2
					x,y   = ax1*t13+bx1*t12+cx1*t1+dx1 - (ax2*t23+bx2*t22+cx2*t2+dx2), ay1*t13+by1*t12+cy1*t1+dy1 - (ay2*t23+by2*t22+cy2*t2+dy2)
					Flast = F
					F = x*x+y*y
				else : 
					break
				i += 1
			if F < dist[0] and 0<=t1<=1 and 0<=t2<=1:
				dist = [F,t1,t2]
				if dist[0] <= dist_bounds[0] : 
					return dist
	return dist			


def csp_to_csp_distance(csp1,csp2, dist_bounds = [0,1e100], tolerance=.01) : 
	dist = [1e100,0,0,0,0,0,0]
	for i1 in range(len(csp1)) : 
		for j1 in range(1,len(csp1[i1])) :
			for i2 in range(len(csp2)) :
				for j2 in range(1,len(csp2[i2])) :
					d = csp_seg_bound_to_csp_seg_bound_max_min_distance(csp1[i1][j1-1],csp1[i1][j1],csp2[i2][j2-1],csp2[i2][j2])
					if d[0] >= dist_bounds[1] : continue
					if  d[1] < dist_bounds[0] : return [d[1],i1,j1,1,i2,j2,1]
					d = csp_seg_to_csp_seg_distance(csp1[i1][j1-1],csp1[i1][j1],csp2[i2][j2-1],csp2[i2][j2], dist_bounds, tolerance=tolerance)
					if d[0] < dist[0] :
						dist = [d[0], i1,j1,d[1], i2,j2,d[2]]
					if dist[0] <= dist_bounds[0] :	
						return dist
			if dist[0] >= dist_bounds[1] :	
				return dist
	return dist
#	draw_pointer( list(csp_at_t(csp1[dist[1]][dist[2]-1],csp1[dist[1]][dist[2]],dist[3]))
#				+ list(csp_at_t(csp2[dist[4]][dist[5]-1],csp2[dist[4]][dist[5]],dist[6])), "#507","line")
					
					
def csp_split(sp1,sp2,t=.5) :
	[x1,y1],[x2,y2],[x3,y3],[x4,y4] = sp1[1], sp1[2], sp2[0], sp2[1] 
	x12 = x1+(x2-x1)*t
	y12 = y1+(y2-y1)*t
	x23 = x2+(x3-x2)*t
	y23 = y2+(y3-y2)*t
	x34 = x3+(x4-x3)*t
	y34 = y3+(y4-y3)*t
	x1223 = x12+(x23-x12)*t
	y1223 = y12+(y23-y12)*t
	x2334 = x23+(x34-x23)*t
	y2334 = y23+(y34-y23)*t
	x = x1223+(x2334-x1223)*t
	y = y1223+(y2334-y1223)*t
	return [sp1[0],sp1[1],[x12,y12]], [[x1223,y1223],[x,y],[x2334,y2334]], [[x34,y34],sp2[1],sp2[2]]
	
def csp_true_bounds(csp) :
	# Finds minx,miny,maxx,maxy of the csp and return their (x,y,i,j,t) 
	minx = [float("inf"), 0, 0, 0]																																																																																																								
	maxx = [float("-inf"), 0, 0, 0]
	miny = [float("inf"), 0, 0, 0]
	maxy = [float("-inf"), 0, 0, 0]
	for i in range(len(csp)):
		for j in range(1,len(csp[i])):
			ax,ay,bx,by,cx,cy,x0,y0 = bezmisc.bezierparameterize((csp[i][j-1][1],csp[i][j-1][2],csp[i][j][0],csp[i][j][1]))
			roots = cubic_solver(0, 3*ax, 2*bx, cx)	 + [0,1]
			for root in roots :
				if type(root) is complex and abs(root.imag)<1e-10:
					root = root.real
				if type(root) is not complex and 0<=root<=1:
					y = ay*(root**3)+by*(root**2)+cy*root+y0  
					x = ax*(root**3)+bx*(root**2)+cx*root+x0  
					maxx = max([x,y,i,j,root],maxx)
					minx = min([x,y,i,j,root],minx)

			roots = cubic_solver(0, 3*ay, 2*by, cy)	 + [0,1]
			for root in roots :
				if type(root) is complex and root.imag==0:
					root = root.real
				if type(root) is not complex and 0<=root<=1:
					y = ay*(root**3)+by*(root**2)+cy*root+y0  
					x = ax*(root**3)+bx*(root**2)+cx*root+x0  
					maxy = max([y,x,i,j,root],maxy)
					miny = min([y,x,i,j,root],miny)
	maxy[0],maxy[1] = maxy[1],maxy[0]
	miny[0],miny[1] = miny[1],miny[0]

	return minx,miny,maxx,maxy


############################################################################
### csp_segments_intersection(sp1,sp2,sp3,sp4)
###
### Returns array containig all intersections between two segmets of cubic 
### super path. Results are [ta,tb], or [ta0, ta1, tb0, tb1, "Overlap"] 
### where ta, tb are values of t for the intersection point.
############################################################################
def csp_segments_intersection(sp1,sp2,sp3,sp4) :
	a, b = csp_segment_to_bez(sp1,sp2), csp_segment_to_bez(sp3,sp4)

	def polish_intersection(a,b,ta,tb, tolerance = intersection_tolerance) :
		ax,ay,bx,by,cx,cy,dx,dy			= bezmisc.bezierparameterize(a)
		ax1,ay1,bx1,by1,cx1,cy1,dx1,dy1	= bezmisc.bezierparameterize(b)
		i = 0
		F, F1 =  [.0,.0], [[.0,.0],[.0,.0]]
		while i==0 or (abs(F[0])**2+abs(F[1])**2 > tolerance and i<10):
			ta3, ta2, tb3, tb2 = ta**3, ta**2, tb**3, tb**2
			F[0] = ax*ta3+bx*ta2+cx*ta+dx-ax1*tb3-bx1*tb2-cx1*tb-dx1
			F[1] = ay*ta3+by*ta2+cy*ta+dy-ay1*tb3-by1*tb2-cy1*tb-dy1
			F1[0][0] =  3*ax *ta2 + 2*bx *ta + cx
			F1[0][1] = -3*ax1*tb2 - 2*bx1*tb - cx1
			F1[1][0] =  3*ay *ta2 + 2*by *ta + cy
			F1[1][1] = -3*ay1*tb2 - 2*by1*tb - cy1	
			det = F1[0][0]*F1[1][1] - F1[0][1]*F1[1][0]
			if det!=0 :
				F1 = [	[ F1[1][1]/det, -F1[0][1]/det],	[-F1[1][0]/det,  F1[0][0]/det] ]
				ta = ta - ( F1[0][0]*F[0] + F1[0][1]*F[1] )
				tb = tb - ( F1[1][0]*F[0] + F1[1][1]*F[1] )
			else: break	
			i += 1

		return ta, tb 			


	def recursion(a,b, ta0,ta1,tb0,tb1, depth_a,depth_b) :
		global bezier_intersection_recursive_result
		if a==b : 
			bezier_intersection_recursive_result += [[ta0,tb0,ta1,tb1,"Overlap"]]
			return 
		tam, tbm = (ta0+ta1)/2, (tb0+tb1)/2
		if depth_a>0 and depth_b>0 : 
			a1,a2 = bez_split(a,0.5)
			b1,b2 = bez_split(b,0.5)
			if bez_bounds_intersect(a1,b1) : recursion(a1,b1, ta0,tam,tb0,tbm, depth_a-1,depth_b-1) 
			if bez_bounds_intersect(a2,b1) : recursion(a2,b1, tam,ta1,tb0,tbm, depth_a-1,depth_b-1) 
			if bez_bounds_intersect(a1,b2) : recursion(a1,b2, ta0,tam,tbm,tb1, depth_a-1,depth_b-1) 
			if bez_bounds_intersect(a2,b2) : recursion(a2,b2, tam,ta1,tbm,tb1, depth_a-1,depth_b-1) 
		elif depth_a>0  : 
			a1,a2 = bez_split(a,0.5)
			if bez_bounds_intersect(a1,b) : recursion(a1,b, ta0,tam,tb0,tb1, depth_a-1,depth_b) 
			if bez_bounds_intersect(a2,b) : recursion(a2,b, tam,ta1,tb0,tb1, depth_a-1,depth_b) 
		elif depth_b>0  : 
			b1,b2 = bez_split(b,0.5)
			if bez_bounds_intersect(a,b1) : recursion(a,b1, ta0,ta1,tb0,tbm, depth_a,depth_b-1) 
			if bez_bounds_intersect(a,b2) : recursion(a,b2, ta0,ta1,tbm,tb1, depth_a,depth_b-1) 
		else : # Both segments have been subdevided enougth. Let's get some intersections :).
			intersection, t1, t2 =  straight_segments_intersection([a[0]]+[a[3]],[b[0]]+[b[3]])
			if intersection :
				if intersection == "Overlap" :
					t1 = ( max(0,min(1,t1[0]))+max(0,min(1,t1[1])) )/2
					t2 = ( max(0,min(1,t2[0]))+max(0,min(1,t2[1])) )/2
				bezier_intersection_recursive_result += [[ta0+t1*(ta1-ta0),tb0+t2*(tb1-tb0)]]

	global bezier_intersection_recursive_result
	bezier_intersection_recursive_result = []
	recursion(a,b,0.,1.,0.,1.,intersection_recursion_depth,intersection_recursion_depth)
	intersections = bezier_intersection_recursive_result
	for i in range(len(intersections)) :			
		if len(intersections[i])<5 or intersections[i][4] != "Overlap" :
			intersections[i] = polish_intersection(a,b,intersections[i][0],intersections[i][1])
	return intersections


def csp_segments_true_intersection(sp1,sp2,sp3,sp4) :
	intersections = csp_segments_intersection(sp1,sp2,sp3,sp4)
	res = []
	for intersection in intersections :
		if  (
				(len(intersection)==5 and intersection[4] == "Overlap" and (0<=intersection[0]<=1 or 0<=intersection[1]<=1) and (0<=intersection[2]<=1 or 0<=intersection[3]<=1) ) 
			 or ( 0<=intersection[0]<=1 and 0<=intersection[1]<=1 )
			) :
			res += [intersection]
	return res


def csp_get_t_at_curvature(sp1,sp2,c, sample_points = 16):
	# returns a list containning [t1,t2,t3,...,tn],  0<=ti<=1...
	if sample_points < 2 : sample_points = 2
	tolerance = .0000000001
	res = []
	ax,ay,bx,by,cx,cy,dx,dy = csp_parameterize(sp1,sp2)
	for k in range(sample_points) :
		t = float(k)/(sample_points-1)
		i, F = 0, 1e100
		while i<2 or abs(F)>tolerance and i<17 :
			try : # some numerical calculation could exceed the limits 
				t2 = t*t
				#slopes...
				f1x = 3*ax*t2+2*bx*t+cx
				f1y = 3*ay*t2+2*by*t+cy
				f2x = 6*ax*t+2*bx
				f2y = 6*ay*t+2*by
				f3x = 6*ax
				f3y = 6*ay
				d = (f1x**2+f1y**2)**1.5
				F1 = (
						 (	(f1x*f3y-f3x*f1y)*d - (f1x*f2y-f2x*f1y)*3.*(f2x*f1x+f2y*f1y)*((f1x**2+f1y**2)**.5) )	/ 
				 				((f1x**2+f1y**2)**3)
					 )
				F = (f1x*f2y-f1y*f2x)/d - c
				t -= F/F1
			except:
				break
			i += 1
		if 0<=t<=1 and F<=tolerance:
			if len(res) == 0 :
				res.append(t)
			for i in res : 
				if abs(t-i)<=0.001 :
					break
			if not abs(t-i)<=0.001 :
				res.append(t)
	return res	
		
	
def csp_max_curvature(sp1,sp2):
	ax,ay,bx,by,cx,cy,dx,dy = csp_parameterize(sp1,sp2)
	tolerance = .0001
	F = 0.
	i = 0
	while i<2 or F-Flast<tolerance and i<10 :
		t = .5
		f1x = 3*ax*t**2 + 2*bx*t + cx
		f1y = 3*ay*t**2 + 2*by*t + cy
		f2x = 6*ax*t + 2*bx
		f2y = 6*ay*t + 2*by
		f3x = 6*ax
		f3y = 6*ay
		d = pow(f1x**2+f1y**2,1.5)
		if d != 0 :
			Flast = F
			F = (f1x*f2y-f1y*f2x)/d
			F1 = 	(
						 (	d*(f1x*f3y-f3x*f1y) - (f1x*f2y-f2x*f1y)*3.*(f2x*f1x+f2y*f1y)*pow(f1x**2+f1y**2,.5) )	/ 
				 				(f1x**2+f1y**2)**3
					)
			i+=1	
			if F1!=0:
				t -= F/F1
			else:
				break
		else: break
	return t			
	

def csp_curvature_at_t(sp1,sp2,t, depth = 3) :
	ax,ay,bx,by,cx,cy,dx,dy = bezmisc.bezierparameterize(csp_segment_to_bez(sp1,sp2))
	
	#curvature = (x'y''-y'x'') / (x'^2+y'^2)^1.5 
	
	f1x = 3*ax*t**2 + 2*bx*t + cx
	f1y = 3*ay*t**2 + 2*by*t + cy
	f2x = 6*ax*t + 2*bx
	f2y = 6*ay*t + 2*by
	d = (f1x**2+f1y**2)**1.5
	if d != 0 :
		return (f1x*f2y-f1y*f2x)/d
	else :
		t1 = f1x*f2y-f1y*f2x
		if t1 > 0 : return 1e100
		if t1 < 0 : return -1e100
		# Use the Lapitals rule to solve 0/0 problem for 2 times...
		t1 = 2*(bx*ay-ax*by)*t+(ay*cx-ax*cy)
		if t1 > 0 : return 1e100
		if t1 < 0 : return -1e100
		t1 = bx*ay-ax*by
		if t1 > 0 : return 1e100
		if t1 < 0 : return -1e100
		if depth>0 :
			# little hack ;^) hope it wont influence anything...
			return csp_curvature_at_t(sp1,sp2,t*1.004, depth-1)
		return 1e100

	 	
def csp_subpath_ccw(subpath):
	# Remove all zerro length segments
	s = 0
	#subpath = subpath[:]
	if (P(subpath[-1][1])-P(subpath[0][1])).l2() > 1e-10 :
		subpath[-1][2] = subpath[-1][1]
		subpath[0][0] = subpath[0][1]
		subpath += [ [subpath[0][1],subpath[0][1],subpath[0][1]]  ]
	pl = subpath[-1][2]
	for sp1 in subpath:
		for p in sp1 :
			s += (p[0]-pl[0])*(p[1]+pl[1])
			pl = p
	return s<0


def csp_at_t(sp1,sp2,t):
	ax,bx,cx,dx = sp1[1][0], sp1[2][0], sp2[0][0], sp2[1][0]
	ay,by,cy,dy = sp1[1][1], sp1[2][1], sp2[0][1], sp2[1][1]

	x1, y1 = ax+(bx-ax)*t, ay+(by-ay)*t	
	x2, y2 = bx+(cx-bx)*t, by+(cy-by)*t	
	x3, y3 = cx+(dx-cx)*t, cy+(dy-cy)*t	
	
	x4,y4 = x1+(x2-x1)*t, y1+(y2-y1)*t 
	x5,y5 = x2+(x3-x2)*t, y2+(y3-y2)*t 
	
	x,y = x4+(x5-x4)*t, y4+(y5-y4)*t 
	return [x,y]


def csp_splitatlength(sp1, sp2, l = 0.5, tolerance = 0.01):
	bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
	t = bezmisc.beziertatlength(bez, l, tolerance)
	return csp_split(sp1, sp2, t)	

	
def cspseglength(sp1,sp2, tolerance = 0.001):
	bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
	return bezmisc.bezierlength(bez, tolerance)	


def csp_segments(csp):
	l, seg = 0, [0]
	for sp in csp:
		for i in xrange(1,len(sp)):
			l += cspseglength(sp[i-1],sp[i])
			seg += [ l ] 

	if l>0 :
		seg = [seg[i]/l for i in xrange(len(seg))]
	return seg,l

def csp_line_intersection(l1,l2,sp1,sp2):
	dd=l1[0]
	cc=l2[0]-l1[0]
	bb=l1[1]
	aa=l2[1]-l1[1]
	if aa==cc==0 : return []
	if aa:
		coef1=cc/aa
		coef2=1
	else:
		coef1=1
		coef2=aa/cc
	bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
	ax,ay,bx,by,cx,cy,x0,y0=bezmisc.bezierparameterize(bez)
	a=coef1*ay-coef2*ax
	b=coef1*by-coef2*bx
	c=coef1*cy-coef2*cx
	d=coef1*(y0-bb)-coef2*(x0-dd)
	roots = cubic_solver(a,b,c,d)
	retval = []
	for i in roots :
		if type(i) is complex and abs(i.imag)<1e-7:
			i = i.real
		if type(i) is not complex and -1e-10<=i<=1.+1e-10:
			retval.append(i)
	return retval


def csp_split_by_two_points(sp1,sp2,t1,t2) :
	if t1>t2 : t1, t2 = t2, t1
	if t1 == t2 : 
		sp1,sp2,sp3 =  csp_split(sp1,sp2,t)
		return [sp1,sp2,sp2,sp3]
	elif t1 <= 1e-10 and t2 >= 1.-1e-10 :
		return [sp1,sp1,sp2,sp2]
	elif t1 <= 1e-10:	
		sp1,sp2,sp3 = csp_split(sp1,sp2,t2)
		return [sp1,sp1,sp2,sp3]
	elif t2 >= 1.-1e-10 : 
		sp1,sp2,sp3 = csp_split(sp1,sp2,t1)
		return [sp1,sp2,sp3,sp3]
	else:
		sp1,sp2,sp3 = csp_split(sp1,sp2,t1)
		sp2,sp3,sp4 = csp_split(sp2,sp3,(t2-t1)/(1-t1) )
		return [sp1,sp2,sp3,sp4]


def csp_subpath_split_by_points(subpath, points) :
	# points are [[i,t]...] where i-segment's number
	points.sort()
	points = [[1,0.]] + points + [[len(subpath)-1,1.]]
	parts = []
	for int1,int2 in zip(points,points[1:]) : 
		if int1==int2 :
			continue
		if int1[1] == 1. :
			int1[0] += 1
			int1[1] = 0.
		if int1==int2 :
			continue
		if int2[1] == 0. :
			int2[0] -= 1
			int2[1] = 1.
		if int1[0] == 0 and int2[0]==len(subpath)-1:# and small(int1[1]) and small(int2[1]-1) :
			continue
		if int1[0]==int2[0] :	# same segment
			sp = csp_split_by_two_points(subpath[int1[0]-1],subpath[int1[0]],int1[1], int2[1])
			if sp[1]!=sp[2] :
				parts += [   [sp[1],sp[2]]     ]
		else :
			sp5,sp1,sp2 = csp_split(subpath[int1[0]-1],subpath[int1[0]],int1[1])
			sp3,sp4,sp5 = csp_split(subpath[int2[0]-1],subpath[int2[0]],int2[1])
			if int1[0]==int2[0]-1 :
				parts += [	[sp1, [sp2[0],sp2[1],sp3[2]], sp4]  ]
			else :
				parts += [  [sp1,sp2]+subpath[int1[0]+1:int2[0]-1]+[sp3,sp4]  ]
	return parts


def csp_from_arc(start, end, center, r, slope_st) : 
	# Creates csp that approximise specified arc
	r = abs(r)
	alpha = (atan2(end[0]-center[0],end[1]-center[1]) - atan2(start[0]-center[0],start[1]-center[1])) % math.pi2

	sectors = int(abs(alpha)*2/math.pi)+1
	alpha_start = atan2(start[0]-center[0],start[1]-center[1])
	cos_,sin_ = math.cos(alpha_start), math.sin(alpha_start)
	k = (4.*math.tan(alpha/sectors/4.)/3.)
	if dot(slope_st , [- sin_*k*r, cos_*k*r]) < 0 :
		if alpha>0 : alpha -= math.pi2
		else: alpha += math.pi2
	if abs(alpha*r)<0.001 : 
		return []

	sectors = int(abs(alpha)*2/math.pi)+1
	k = (4.*math.tan(alpha/sectors/4.)/3.)
	result = []
	for i in range(sectors+1) :
		cos_,sin_ = math.cos(alpha_start + alpha*i/sectors), math.sin(alpha_start + alpha*i/sectors)
		sp = [ [], [center[0] + cos_*r, center[1] + sin_*r], [] ]
		sp[0] = [sp[1][0] + sin_*k*r, sp[1][1] - cos_*k*r ]
		sp[2] = [sp[1][0] - sin_*k*r, sp[1][1] + cos_*k*r ]
		result += [sp]
	result[0][0] = result[0][1][:]
	result[-1][2] = result[-1][1]
		
	return result


def point_to_arc_distance(p, arc):
	###		Distance calculattion from point to arc
	P0,P2,c,a = arc
	dist = None
	p = P(p)
	r = (P0-c).mag()
	if r>0 :
		i = c + (p-c).unit()*r
		alpha = ((i-c).angle() - (P0-c).angle())
		if a*alpha<0: 
			if alpha>0:	alpha = alpha-math.pi2
			else: alpha = math.pi2+alpha
		if between(alpha,0,a) or min(abs(alpha),abs(alpha-a))<straight_tolerance : 
			return (p-i).mag(), [i.x, i.y]
		else : 
			d1, d2 = (p-P0).mag(), (p-P2).mag()
			if d1<d2 : 
				return (d1, [P0.x,P0.y])
			else :
				return (d2, [P2.x,P2.y])


def csp_to_arc_distance(sp1,sp2, arc1, arc2, tolerance = 0.01 ): # arc = [start,end,center,alpha]
	n, i = 10, 0
	d, d1, dl = (0,(0,0)), (0,(0,0)), 0
	while i<1 or (abs(d1[0]-dl[0])>tolerance and i<4):
		i += 1
		dl = d1*1	
		for j in range(n+1):
			t = float(j)/n
			p = csp_at_t(sp1,sp2,t) 
			d = min(point_to_arc_distance(p,arc1), point_to_arc_distance(p,arc2))
			d1 = max(d1,d)
		n=n*2
	return d1[0]


def csp_point_inside_bound(sp1, sp2, p):
	bez = [sp1[1],sp1[2],sp2[0],sp2[1]]
	x,y = p
	c = 0
	#LT added test of x in rangezzzz
	xmin=1e100
	xmax=-1e100
	for i in range(4):
		[x0,y0], [x1,y1] = bez[i-1], bez[i]
		xmin=min(xmin,x0)
		xmax=max(xmax,x0)
		if x0-x1!=0 and (y-y0)*(x1-x0)>=(x-x0)*(y1-y0) and x>min(x0,x1) and x<=max(x0,x1) :
			c +=1
	return xmin<=x<=xmax and c%2==0	


def line_line_intersect(p1,p2,p3,p4) : # Return only true intersection. 
	if (p1[0]==p2[0] and p1[1]==p2[1]) or (p3[0]==p4[0] and p3[1]==p4[1]) : return False
	x = (p2[0]-p1[0])*(p4[1]-p3[1]) - (p2[1]-p1[1])*(p4[0]-p3[0])
	if x==0 : # Lines are parallel
		if (p3[0]-p1[0])*(p2[1]-p1[1]) == (p3[1]-p1[1])*(p2[0]-p1[0]) :
			if p3[0]!=p4[0] :
				t11 = (p1[0]-p3[0])/(p4[0]-p3[0]) 
				t12 = (p2[0]-p3[0])/(p4[0]-p3[0]) 
				t21 = (p3[0]-p1[0])/(p2[0]-p1[0])
				t22 = (p4[0]-p1[0])/(p2[0]-p1[0])
			else:
				t11 = (p1[1]-p3[1])/(p4[1]-p3[1]) 
				t12 = (p2[1]-p3[1])/(p4[1]-p3[1]) 
				t21 = (p3[1]-p1[1])/(p2[1]-p1[1])
				t22 = (p4[1]-p1[1])/(p2[1]-p1[1])
			return ("Overlap" if (0<=t11<=1 or 0<=t12<=1) and (0<=t21<=1 or  0<=t22<=1) else False)
		else: return False	
	else :
		return (
					0<=((p4[0]-p3[0])*(p1[1]-p3[1]) - (p4[1]-p3[1])*(p1[0]-p3[0]))/x<=1 and
					0<=((p2[0]-p1[0])*(p1[1]-p3[1]) - (p2[1]-p1[1])*(p1[0]-p3[0]))/x<=1 )
					
					
def line_line_intersection_points(p1,p2,p3,p4) : # Return only points [ (x,y) ] 
	if (p1[0]==p2[0] and p1[1]==p2[1]) or (p3[0]==p4[0] and p3[1]==p4[1]) : return []
	x = (p2[0]-p1[0])*(p4[1]-p3[1]) - (p2[1]-p1[1])*(p4[0]-p3[0])
	if x==0 : # Lines are parallel
		if (p3[0]-p1[0])*(p2[1]-p1[1]) == (p3[1]-p1[1])*(p2[0]-p1[0]) :
			if p3[0]!=p4[0] :
				t11 = (p1[0]-p3[0])/(p4[0]-p3[0]) 
				t12 = (p2[0]-p3[0])/(p4[0]-p3[0]) 
				t21 = (p3[0]-p1[0])/(p2[0]-p1[0])
				t22 = (p4[0]-p1[0])/(p2[0]-p1[0])
			else:
				t11 = (p1[1]-p3[1])/(p4[1]-p3[1]) 
				t12 = (p2[1]-p3[1])/(p4[1]-p3[1]) 
				t21 = (p3[1]-p1[1])/(p2[1]-p1[1])
				t22 = (p4[1]-p1[1])/(p2[1]-p1[1])
			res = [] 
			if (0<=t11<=1 or 0<=t12<=1) and (0<=t21<=1 or  0<=t22<=1) :
				if 0<=t11<=1 : res += [p1]	
				if 0<=t12<=1 : res += [p2]	
				if 0<=t21<=1 : res += [p3]	
				if 0<=t22<=1 : res += [p4]	
			return res
		else: return []
	else :
		t1 = ((p4[0]-p3[0])*(p1[1]-p3[1]) - (p4[1]-p3[1])*(p1[0]-p3[0]))/x
		t2 = ((p2[0]-p1[0])*(p1[1]-p3[1]) - (p2[1]-p1[1])*(p1[0]-p3[0]))/x
		if 0<=t1<=1 and 0<=t2<=1 : return [ [p1[0]*(1-t1)+p2[0]*t1, p1[1]*(1-t1)+p2[1]*t1] ]
		else : return []					


def point_to_point_d2(a,b):
	return (a[0]-b[0])**2 + (a[1]-b[1])**2


def point_to_point_d(a,b):
	return math.sqrt((a[0]-b[0])**2 + (a[1]-b[1])**2)


def point_to_line_segment_distance_2(p1, p2,p3) :
	# p1 - point, p2,p3 - line segment
	#draw_pointer(p1)
	w0 = [p1[0]-p2[0], p1[1]-p2[1]]
	v = [p3[0]-p2[0], p3[1]-p2[1]]
	c1 = w0[0]*v[0] + w0[1]*v[1]
	if c1 <= 0 :
		return w0[0]*w0[0]+w0[1]*w0[1]
	c2 = v[0]*v[0] + v[1]*v[1]
	if c2 <= c1 :
		return  (p1[0]-p3[0])**2 + (p1[1]-p3[1])**2
	return (p1[0]- p2[0]-v[0]*c1/c2)**2 + (p1[1]- p2[1]-v[1]*c1/c2)


def line_to_line_distance_2(p1,p2,p3,p4):
	if line_line_intersect(p1,p2,p3,p4) : return 0
	return min(
			point_to_line_segment_distance_2(p1,p3,p4),
			point_to_line_segment_distance_2(p2,p3,p4),
			point_to_line_segment_distance_2(p3,p1,p2),
			point_to_line_segment_distance_2(p4,p1,p2))


def csp_seg_bound_to_csp_seg_bound_max_min_distance(sp1,sp2,sp3,sp4) :
	bez1 = csp_segment_to_bez(sp1,sp2)
	bez2 = csp_segment_to_bez(sp3,sp4) 
	min_dist = 1e100
	max_dist = 0.
	for i in range(4) :
		if csp_point_inside_bound(sp1, sp2, bez2[i]) or csp_point_inside_bound(sp3, sp4, bez1[i]) :
			min_dist = 0.
			break	
	for i in range(4) : 
		for j in range(4) : 
			d = line_to_line_distance_2(bez1[i-1],bez1[i],bez2[j-1],bez2[j])
			if d < min_dist : min_dist = d
			d = (bez2[j][0]-bez1[i][0])**2 + (bez2[j][1]-bez1[i][1])**2 
			if max_dist < d  : max_dist = d
	return min_dist, max_dist


def csp_normalized_slope(sp1,sp2,t) :
	ax,ay,bx,by,cx,cy,dx,dy=bezmisc.bezierparameterize((sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:]))
	if sp1[1]==sp2[1]==sp1[2]==sp2[0] : return [1.,0.]
	f1x = 3*ax*t*t+2*bx*t+cx
	f1y = 3*ay*t*t+2*by*t+cy
	if abs(f1x*f1x+f1y*f1y) > 1e-9 : #LT changed this from 1e-20, which caused problems
		l = math.sqrt(f1x*f1x+f1y*f1y)
		return [f1x/l, f1y/l]

	if t == 0 :
		f1x = sp2[0][0]-sp1[1][0]
		f1y = sp2[0][1]-sp1[1][1]
		if abs(f1x*f1x+f1y*f1y) > 1e-9 :
			l = math.sqrt(f1x*f1x+f1y*f1y)
			return [f1x/l, f1y/l]
		else :
			f1x = sp2[1][0]-sp1[1][0]
			f1y = sp2[1][1]-sp1[1][1]
			if f1x*f1x+f1y*f1y != 0 :
				l = math.sqrt(f1x*f1x+f1y*f1y)
				return [f1x/l, f1y/l]
	elif t == 1 :
		f1x = sp2[1][0]-sp1[2][0]
		f1y = sp2[1][1]-sp1[2][1]
		if abs(f1x*f1x+f1y*f1y) > 1e-9 :
			l = math.sqrt(f1x*f1x+f1y*f1y)
			return [f1x/l, f1y/l]
		else :
			f1x = sp2[1][0]-sp1[1][0]
			f1y = sp2[1][1]-sp1[1][1]
			if f1x*f1x+f1y*f1y != 0 :
				l = math.sqrt(f1x*f1x+f1y*f1y)
				return [f1x/l, f1y/l]
	else :
		return [1.,0.]

				
def csp_normalized_normal(sp1,sp2,t) :
	nx,ny = csp_normalized_slope(sp1,sp2,t)
	return [-ny, nx]


def csp_parameterize(sp1,sp2):
	return bezmisc.bezierparameterize(csp_segment_to_bez(sp1,sp2))


def csp_concat_subpaths(*s):
	
	def concat(s1,s2) :
		if s1 == [] : return s2
		if s2 == [] : return s1
		if (s1[-1][1][0]-s2[0][1][0])**2 + (s1[-1][1][1]-s2[0][1][1])**2 > 0.00001 :
	 		return s1[:-1]+[ [s1[-1][0],s1[-1][1],s1[-1][1]],  [s2[0][1],s2[0][1],s2[0][2]] ] + s2[1:]		
	 	else :
	 		return s1[:-1]+[ [s1[-1][0],s2[0][1],s2[0][2]] ] + s2[1:]		
	 		
	if len(s) == 0 : return []
	if len(s) ==1 : return s[0]
	result = s[0]
	for s1 in s[1:]:
		result = concat(result,s1)
	return result


def csp_draw(csp, color="#05f", group = None, style="fill:none;", width = .1, comment = "") :
	if csp!=[] and csp!=[[]] :
		if group == None : group = options.doc_root 
		style += "stroke:"+color+";"+ "stroke-width:%0.4fpx;"%width
		args = {"d": cubicsuperpath.formatPath(csp), "style":style}
		if comment!="" : args["comment"] = str(comment)
		inkex.etree.SubElement( group, inkex.addNS('path','svg'), args )							

	
def csp_subpaths_end_to_start_distance2(s1,s2):
	return (s1[-1][1][0]-s2[0][1][0])**2 + (s1[-1][1][1]-s2[0][1][1])**2


def csp_clip_by_line(csp,l1,l2) :
	result = []
	for i in range(len(csp)):
		s = csp[i]
		intersections = []
		for j in range(1,len(s)) :
			intersections += [  [j,int_] for int_ in csp_line_intersection(l1,l2,s[j-1],s[j])]
		splitted_s = csp_subpath_split_by_points(s, intersections)
		for s in splitted_s[:] :
			clip = False
			for p in csp_true_bounds([s]) :
				if (l1[1]-l2[1])*p[0] + (l2[0]-l1[0])*p[1] + (l1[0]*l2[1]-l2[0]*l1[1])<-0.01 : 
					clip = True
					break
			if clip :
				splitted_s.remove(s)
		result += splitted_s
	return result


def csp_subpath_line_to(subpath, points) :
	# Appends subpath with line or polyline.
	if len(points)>0 :
		if len(subpath)>0:
			subpath[-1][2] = subpath[-1][1][:]
		if type(points[0]) == type([1,1]) :
			for p in points :
				subpath += [ [p[:],p[:],p[:]] ]
		else: 
			subpath += [ [points,points,points] ]
	return subpath

	
def csp_join_subpaths(csp) :
	result = csp[:]
	done_smf = True
	joined_result = []
	while done_smf :
		done_smf = False
		while len(result)>0:
			s1 = result[-1][:]
			del(result[-1])
			j = 0
			joined_smf = False
			while j<len(joined_result) :
				if csp_subpaths_end_to_start_distance2(joined_result[j],s1) <0.000001 :
					joined_result[j] = csp_concat_subpaths(joined_result[j],s1)
					done_smf = True
					joined_smf = True
					break				
				if csp_subpaths_end_to_start_distance2(s1,joined_result[j]) <0.000001 :
					joined_result[j] = csp_concat_subpaths(s1,joined_result[j])
					done_smf = True
					joined_smf = True
					break				
				j += 1
			if not joined_smf : joined_result += [s1[:]]
		if done_smf : 
			result = joined_result[:]
			joined_result = []
	return joined_result


def triangle_cross(a,b,c):
	return (a[0]-b[0])*(c[1]-b[1]) - (c[0]-b[0])*(a[1]-b[1])
	

def csp_segment_convex_hull(sp1,sp2):
	a,b,c,d = sp1[1][:], sp1[2][:], sp2[0][:], sp2[1][:]
	
	abc = triangle_cross(a,b,c)
	abd = triangle_cross(a,b,d)
	bcd = triangle_cross(b,c,d)
	cad = triangle_cross(c,a,d)
	if abc == 0 and abd == 0 : return [min(a,b,c,d), max(a,b,c,d)]
	if abc == 0 : return [d, min(a,b,c), max(a,b,c)]
	if abd == 0 : return [c, min(a,b,d), max(a,b,d)]
	if bcd == 0 : return [a, min(b,c,d), max(b,c,d)]
	if cad == 0 : return [b, min(c,a,d), max(c,a,d)]
	
	m1, m2, m3  =  abc*abd>0, abc*bcd>0, abc*cad>0
	if m1 and m2 and m3 : return [a,b,c]
	if     m1 and     m2 and not m3 : return [a,b,c,d]
	if     m1 and not m2 and     m3 : return [a,b,d,c]
	if not m1 and     m2 and     m3 : return [a,d,b,c]
	if m1 and not (m2 and m3) : return [a,b,d]
	if not (m1 and m2) and m3 : return [c,a,d]
	if not (m1 and m3) and m2 : return [b,c,d]
	
	raise ValueError, "csp_segment_convex_hull happend something that shouldnot happen!"	

	
################################################################################
###		Bezier additional functions
################################################################################

def bez_bounds_intersect(bez1, bez2) :
	return bounds_intersect(bez_bound(bez2), bez_bound(bez1))


def bez_bound(bez) :
	return [
				min(bez[0][0], bez[1][0], bez[2][0], bez[3][0]),
				min(bez[0][1], bez[1][1], bez[2][1], bez[3][1]),
				max(bez[0][0], bez[1][0], bez[2][0], bez[3][0]),
				max(bez[0][1], bez[1][1], bez[2][1], bez[3][1]),
			]


def bounds_intersect(a, b) :
	return not ( (a[0]>b[2]) or (b[0]>a[2]) or (a[1]>b[3]) or (b[1]>a[3]) )


def tpoint((x1,y1),(x2,y2),t):
	return [x1+t*(x2-x1),y1+t*(y2-y1)]


def bez_to_csp_segment(bez) :
	return [bez[0],bez[0],bez[1]], [bez[2],bez[3],bez[3]]


def bez_split(a,t=0.5) :
	 a1 = tpoint(a[0],a[1],t)
	 at = tpoint(a[1],a[2],t)
	 b2 = tpoint(a[2],a[3],t)
	 a2 = tpoint(a1,at,t)
	 b1 = tpoint(b2,at,t)
	 a3 = tpoint(a2,b1,t)
	 return [a[0],a1,a2,a3], [a3,b1,b2,a[3]]

	

################################################################################
###	Some vector functions
################################################################################
	
def normalize((x,y)) :
	l = math.sqrt(x**2+y**2)
	if l == 0 : return [0.,0.]
	else : 		return [x/l, y/l]


def cross(a,b) :
	return a[1] * b[0] - a[0] * b[1]


def dot(a,b) :
	return a[0] * b[0] + a[1] * b[1]


def rotate_ccw(d) :
	return [-d[1],d[0]]


def vectors_ccw(a,b):
	return a[0]*b[1]-b[0]*a[1] < 0


def vector_from_to_length(a,b):
	return math.sqrt((a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]))

################################################################################
###	Common functions
################################################################################

def det_3x3(a):
	return  float(
		a[0][0]*a[1][1]*a[2][2] + a[0][1]*a[1][2]*a[2][0] + a[1][0]*a[2][1]*a[0][2]
		- a[0][2]*a[1][1]*a[2][0] - a[0][0]*a[2][1]*a[1][2] - a[0][1]*a[2][2]*a[1][0]
		)

def inv_3x3(a): # invert matrix 3x3
	det = det_3x3(a)
	if det==0: return None
	return	[  
		[  (a[1][1]*a[2][2] - a[2][1]*a[1][2])/det,  -(a[0][1]*a[2][2] - a[2][1]*a[0][2])/det,  (a[0][1]*a[1][2] - a[1][1]*a[0][2])/det ], 
		[ -(a[1][0]*a[2][2] - a[2][0]*a[1][2])/det,   (a[0][0]*a[2][2] - a[2][0]*a[0][2])/det, -(a[0][0]*a[1][2] - a[1][0]*a[0][2])/det ], 
		[  (a[1][0]*a[2][1] - a[2][0]*a[1][1])/det,  -(a[0][0]*a[2][1] - a[2][0]*a[0][1])/det,  (a[0][0]*a[1][1] - a[1][0]*a[0][1])/det ]
	]


def inv_2x2(a): # invert matrix 2x2
	det = a[0][0]*a[1][1] - a[1][0]*a[0][1]
	if det==0: return None
	return [
			[a[1][1]/det, -a[0][1]/det],
			[-a[1][0]/det, a[0][0]/det]
			]


def small(a) :
	global small_tolerance
	return abs(a)<small_tolerance

					
def atan2(*arg):	
	if len(arg)==1 and ( type(arg[0]) == type([0.,0.]) or type(arg[0])==type((0.,0.)) ) :
		return (math.pi/2 - math.atan2(arg[0][0], arg[0][1]) ) % math.pi2
	elif len(arg)==2 :
		
		return (math.pi/2 - math.atan2(arg[0],arg[1]) ) % math.pi2
	else :
		raise ValueError, "Bad argumets for atan! (%s)" % arg  


def draw_text(text,x,y,style = None, font_size = 20) :
	if style == None : 
		style = "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;"
	style += "font-size:%fpx;"%font_size
	t = inkex.etree.SubElement(	options.doc_root, inkex.addNS('text','svg'), {	
							'x':	str(x),
							inkex.addNS("space","xml"):"preserve",
							'y':	str(y)
						})
	text = str(text).split("\n")
	for s in text :
		span = inkex.etree.SubElement( t, inkex.addNS('tspan','svg'), 
						{
							'x':	str(x),
							'y':	str(+y),
							inkex.addNS("role","sodipodi"):"line",
						})					
		y += font_size
		span.text = s
			

def draw_pointer(x,color = "#f00", figure = "cross", comment = "", width = .1) :
	if figure ==  "line" :
		s = ""
		for i in range(1,len(x)/2) :
			s+= " %s, %s " %(x[i*2],x[i*2+1])
		inkex.etree.SubElement( options.doc_root, inkex.addNS('path','svg'), {"d": "M %s,%s L %s"%(x[0],x[1],s), "style":"fill:none;stroke:%s;stroke-width:%f;"%(color,width),"comment":str(comment)} )
	else :
		inkex.etree.SubElement( options.doc_root, inkex.addNS('path','svg'), {"d": "m %s,%s l 10,10 -20,-20 10,10 -10,10, 20,-20"%(x[0],x[1]), "style":"fill:none;stroke:%s;stroke-width:%f;"%(color,width),"comment":str(comment)} )


def straight_segments_intersection(a,b, true_intersection = True) : # (True intersection means check ta and tb are in [0,1])
 	ax,bx,cx,dx, ay,by,cy,dy = a[0][0],a[1][0],b[0][0],b[1][0], a[0][1],a[1][1],b[0][1],b[1][1] 
	if (ax==bx and ay==by) or (cx==dx and cy==dy) : return False, 0, 0
	if (bx-ax)*(dy-cy)-(by-ay)*(dx-cx)==0 :	# Lines are parallel
		ta = (ax-cx)/(dx-cx) if cx!=dx else (ay-cy)/(dy-cy)
		tb = (bx-cx)/(dx-cx) if cx!=dx else (by-cy)/(dy-cy)
		tc = (cx-ax)/(bx-ax) if ax!=bx else (cy-ay)/(by-ay)
		td = (dx-ax)/(bx-ax) if ax!=bx else (dy-ay)/(by-ay)
		return ("Overlap" if 0<=ta<=1 or 0<=tb<=1 or  0<=tc<=1 or  0<=td<=1 or not true_intersection else False), (ta,tb), (tc,td)
	else :
		ta = ( (ay-cy)*(dx-cx)-(ax-cx)*(dy-cy) ) / ( (bx-ax)*(dy-cy)-(by-ay)*(dx-cx) )
		tb = ( ax-cx+ta*(bx-ax) ) / (dx-cx) if dx!=cx else ( ay-cy+ta*(by-ay) ) / (dy-cy)
		return (0<=ta<=1 and 0<=tb<=1 or not true_intersection), ta, tb
	
	

def isnan(x): return type(x) is float and x != x

def isinf(x): inf = 1e5000; return x == inf or x == -inf

def between(c,x,y):
		return x-straight_tolerance<=c<=y+straight_tolerance or y-straight_tolerance<=c<=x+straight_tolerance


def cubic_solver(a,b,c,d):	
	if a!=0:
		#	Monics formula see http://en.wikipedia.org/wiki/Cubic_function#Monic_formula_of_roots
		a,b,c = (b/a, c/a, d/a)
		m = 2*a**3 - 9*a*b + 27*c
		k = a**2 - 3*b
		n = m**2 - 4*k**3
		w1 = -.5 + .5*cmath.sqrt(3)*1j
		w2 = -.5 - .5*cmath.sqrt(3)*1j
		if n>=0 :
			t = m+math.sqrt(n)
			m1 = pow(t/2,1./3) if t>=0 else -pow(-t/2,1./3)
			t = m-math.sqrt(n)
			n1 = pow(t/2,1./3) if t>=0 else -pow(-t/2,1./3)
		else :
			m1 = pow(complex((m+cmath.sqrt(n))/2),1./3)
			n1 = pow(complex((m-cmath.sqrt(n))/2),1./3)
		x1 = -1./3 * (a + m1 + n1)
		x2 = -1./3 * (a + w1*m1 + w2*n1)
		x3 = -1./3 * (a + w2*m1 + w1*n1)
		return [x1,x2,x3]
	elif b!=0:
		det = c**2-4*b*d
		if det>0 :
			return [(-c+math.sqrt(det))/(2*b),(-c-math.sqrt(det))/(2*b)]
		elif d == 0 :
			return [-c/(b*b)] 	
		else :
			return [(-c+cmath.sqrt(det))/(2*b),(-c-cmath.sqrt(det))/(2*b)]
	elif c!=0 :
		return [-d/c]
	else : return []


################################################################################
###		print_ prints any arguments into specified log file
################################################################################

def print_(*arg):
	f = open(options.log_filename,"a")
	for s in arg :
		s = str(unicode(s).encode('unicode_escape'))+" "
		f.write( s )
	f.write("\n")
	f.close()


################################################################################
###		Point (x,y) operations
################################################################################
class P:
	def __init__(self, x, y=None):
		if not y==None:
			self.x, self.y = float(x), float(y)
		else:
			self.x, self.y = float(x[0]), float(x[1])
	def __add__(self, other): return P(self.x + other.x, self.y + other.y)
	def __sub__(self, other): return P(self.x - other.x, self.y - other.y)
	def __neg__(self): return P(-self.x, -self.y)
	def __mul__(self, other):
		if isinstance(other, P):
			return self.x * other.x + self.y * other.y
		return P(self.x * other, self.y * other)
	__rmul__ = __mul__
	def __div__(self, other): return P(self.x / other, self.y / other)
	def mag(self): return math.hypot(self.x, self.y)
	def unit(self):
		h = self.mag()
		if h: return self / h
		else: return P(0,0)
	def dot(self, other): return self.x * other.x + self.y * other.y
	def rot(self, theta):
		c = math.cos(theta)
		s = math.sin(theta)
		return P(self.x * c - self.y * s,  self.x * s + self.y * c)
	def angle(self): return math.atan2(self.y, self.x)
	def __repr__(self): return '%f,%f' % (self.x, self.y)
	def pr(self): return "%.2f,%.2f" % (self.x, self.y)
	def to_list(self): return [self.x, self.y]	
	def ccw(self): return P(-self.y,self.x)
	def l2(self): return self.x*self.x + self.y*self.y
	
################################################################################
###
### Offset function 
###
### This function offsets given cubic super path.  
### It's based on src/livarot/PathOutline.cpp from Inkscape's source code.
###
###
################################################################################
def csp_offset(csp, r) :
	offset_tolerance = 0.05
	offset_subdivision_depth = 10
	time_ = time.time()
	time_start  = time_
	print_("Offset start at %s"% time_)
	print_("Offset radius %s"% r)
	
	
	def csp_offset_segment(sp1,sp2,r) :
		result = []
		t = csp_get_t_at_curvature(sp1,sp2,1/r)
		if len(t) == 0 : t =[0.,1.]
		t.sort()
		if t[0]>.00000001 : t = [0.]+t 
		if t[-1]<.99999999 : t.append(1.) 
		for st,end in zip(t,t[1:]) :	
			c = csp_curvature_at_t(sp1,sp2,(st+end)/2)
			sp = csp_split_by_two_points(sp1,sp2,st,end)
			if sp[1]!=sp[2]:
				if (c>1/r and r<0 or c<1/r and r>0) :
					offset = offset_segment_recursion(sp[1],sp[2],r, offset_subdivision_depth, offset_tolerance) 
				else : # This part will be clipped for sure... TODO Optimize it...
					offset = offset_segment_recursion(sp[1],sp[2],r, offset_subdivision_depth, offset_tolerance) 
					
				if result==[] :
					result = offset[:]
				else: 
					if csp_subpaths_end_to_start_distance2(result,offset)<0.0001 :
						result = csp_concat_subpaths(result,offset)
					else:
						
						intersection = csp_get_subapths_last_first_intersection(result,offset)
						if intersection != [] :
							i,t1,j,t2 = intersection
							sp1_,sp2_,sp3_ = csp_split(result[i-1],result[i],t1)
							result = result[:i-1] + [ sp1_, sp2_ ]
							sp1_,sp2_,sp3_ = csp_split(offset[j-1],offset[j],t2)
							result = csp_concat_subpaths( result, [sp2_,sp3_] + offset[j+1:] )
						else : 
							pass # ???						
							#raise ValueError, "Offset curvature clipping error"
		#csp_draw([result])							
		return result					
	
						
	def create_offset_segment(sp1,sp2,r) :
		# See	Gernot Hoffmann "Bezier Curves"  p.34 -> 7.1 Bezier Offset Curves
		p0,p1,p2,p3 = P(sp1[1]),P(sp1[2]),P(sp2[0]),P(sp2[1])
		s0,s1,s3 = p1-p0,p2-p1,p3-p2
		n0 = s0.ccw().unit() if s0.l2()!=0 else P(csp_normalized_normal(sp1,sp2,0))
		n3 = s3.ccw().unit() if s3.l2()!=0 else P(csp_normalized_normal(sp1,sp2,1))
		n1 = s1.ccw().unit() if s1.l2()!=0 else (n0.unit()+n3.unit()).unit()

		q0,q3 = p0+r*n0, p3+r*n3
		c = csp_curvature_at_t(sp1,sp2,0)
		q1 = q0 + (p1-p0)*(1- (r*c if abs(c)<100 else 0) )
		c = csp_curvature_at_t(sp1,sp2,1)
		q2 = q3 + (p2-p3)*(1- (r*c if abs(c)<100 else 0) ) 

		
		return [[q0.to_list(), q0.to_list(), q1.to_list()],[q2.to_list(), q3.to_list(), q3.to_list()]]
	
	
	def csp_get_subapths_last_first_intersection(s1,s2):
		_break = False
		for i in range(1,len(s1)) :
			sp11, sp12 = s1[-i-1], s1[-i]
			for j in range(1,len(s2)) :
				sp21,sp22 = s2[j-1], s2[j] 
				intersection = csp_segments_true_intersection(sp11,sp12,sp21,sp22)
				if intersection != [] :
					_break = True
					break 
			if _break:break
		if _break :
			intersection = max(intersection)
			return [len(s1)-i,intersection[0], j,intersection[1]]
		else : 
			return []
	
		
	def csp_join_offsets(prev,next,sp1,sp2,sp1_l,sp2_l,r):
		if len(next)>1 :
			if (P(prev[-1][1])-P(next[0][1])).l2()<0.001 : 
				return prev,[],next
			intersection = csp_get_subapths_last_first_intersection(prev,next)
			if intersection != [] :
				i,t1,j,t2 = intersection
				sp1_,sp2_,sp3_ = csp_split(prev[i-1],prev[i],t1)
				sp3_,sp4_,sp5_ = csp_split(next[j-1], next[j],t2)
				return prev[:i-1] + [ sp1_, sp2_ ], [], [sp4_,sp5_] + next[j+1:] 
			
		# Offsets do not intersect... will add an arc...
		start = (P(csp_at_t(sp1_l,sp2_l,1.)) + r*P(csp_normalized_normal(sp1_l,sp2_l,1.))).to_list()
		end   = (P(csp_at_t(sp1,sp2,0.)) + r*P(csp_normalized_normal(sp1,sp2,0.))).to_list()
		arc = csp_from_arc(start, end, sp1[1], r, csp_normalized_slope(sp1_l,sp2_l,1.) )
		if arc == [] :
			return prev,[],next
		else:
			# Clip prev by arc
			if csp_subpaths_end_to_start_distance2(prev,arc)>0.00001 :
				intersection = csp_get_subapths_last_first_intersection(prev,arc)
				if intersection != [] :
					i,t1,j,t2 = intersection
					sp1_,sp2_,sp3_ = csp_split(prev[i-1],prev[i],t1)
					sp3_,sp4_,sp5_ = csp_split(arc[j-1],arc[j],t2)
					prev = prev[:i-1] + [ sp1_, sp2_ ]
					arc = [sp4_,sp5_] + arc[j+1:] 
				#else : raise ValueError, "Offset curvature clipping error"
			# Clip next by arc
			if next == [] :
				return prev,[],arc
			if csp_subpaths_end_to_start_distance2(arc,next)>0.00001 :
				intersection = csp_get_subapths_last_first_intersection(arc,next)
				if intersection != [] :
					i,t1,j,t2 = intersection
					sp1_,sp2_,sp3_ = csp_split(arc[i-1],arc[i],t1)
					sp3_,sp4_,sp5_ = csp_split(next[j-1],next[j],t2)
					arc = arc[:i-1] + [ sp1_, sp2_ ]
					next = [sp4_,sp5_] + next[j+1:] 
				#else : raise ValueError, "Offset curvature clipping error"

			return prev,arc,next
		
		
	def offset_segment_recursion(sp1,sp2,r, depth, tolerance) :
		sp1_r,sp2_r = create_offset_segment(sp1,sp2,r)
		err = max(
				csp_seg_to_point_distance(sp1_r,sp2_r, (P(csp_at_t(sp1,sp2,.25)) + P(csp_normalized_normal(sp1,sp2,.25))*r).to_list())[0], 
				csp_seg_to_point_distance(sp1_r,sp2_r, (P(csp_at_t(sp1,sp2,.50)) + P(csp_normalized_normal(sp1,sp2,.50))*r).to_list())[0],
				csp_seg_to_point_distance(sp1_r,sp2_r, (P(csp_at_t(sp1,sp2,.75)) + P(csp_normalized_normal(sp1,sp2,.75))*r).to_list())[0],
				)

		if  err>tolerance**2 and depth>0:
			#print_(csp_seg_to_point_distance(sp1_r,sp2_r, (P(csp_at_t(sp1,sp2,.25)) + P(csp_normalized_normal(sp1,sp2,.25))*r).to_list())[0], tolerance)
			if depth > offset_subdivision_depth-2 :
				t = csp_max_curvature(sp1,sp2)
				t = max(.1,min(.9 ,t))
			else :
				t = .5
			sp3,sp4,sp5 = csp_split(sp1,sp2,t)
			r1 = offset_segment_recursion(sp3,sp4,r, depth-1, tolerance)
			r2 = offset_segment_recursion(sp4,sp5,r, depth-1, tolerance)
			return r1[:-1]+ [[r1[-1][0],r1[-1][1],r2[0][2]]] + r2[1:]
		else :
			#csp_draw([[sp1_r,sp2_r]])
			#draw_pointer(sp1[1]+sp1_r[1], "#057", "line")
			#draw_pointer(sp2[1]+sp2_r[1], "#705", "line")
			return [sp1_r,sp2_r]
		

	############################################################################
	# Some small definitions
	############################################################################
	csp_len = len(csp)

	############################################################################
	# Prepare the path
	############################################################################
	# Remove all small segments (segment length < 0.001)

	for i in xrange(len(csp)) :
		for j in xrange(len(csp[i])) :
			sp = csp[i][j]
			if (P(sp[1])-P(sp[0])).mag() < 0.001 :
				csp[i][j][0] = sp[1]
			if (P(sp[2])-P(sp[0])).mag() < 0.001 :
				csp[i][j][2] = sp[1]
	for i in xrange(len(csp)) :
		for j in xrange(1,len(csp[i])) :
			if cspseglength(csp[i][j-1], csp[i][j])<0.001 : 
				csp[i] = csp[i][:j] + csp[i][j+1:]
		if cspseglength(csp[i][-1],csp[i][0])>0.001 : 
			csp[i][-1][2] = csp[i][-1][1]
			csp[i]+= [ [csp[i][0][1],csp[i][0][1],csp[i][0][1]] ]
	
	# TODO Get rid of self intersections.

	original_csp = csp[:]
	# Clip segments which has curvature>1/r. Because their offset will be selfintersecting and very nasty.
					
	print_("Offset prepared the path in %s"%(time.time()-time_))
	print_("Path length = %s"% sum([len(i)for i in csp] ) )
	time_ = time.time()

	############################################################################
	# Offset
	############################################################################
	# Create offsets for all segments in the path. And join them together inside each subpath. 		
	unclipped_offset = [[] for i in xrange(csp_len)]
	offsets_original = [[] for i in xrange(csp_len)]
	join_points = [[] for i in xrange(csp_len)]
	intersection = [[] for i in xrange(csp_len)]
	for i in xrange(csp_len) :
		subpath = csp[i]
		subpath_offset = []
		last_offset_len = 0
		for sp1,sp2 in zip(subpath, subpath[1:]) : 
			segment_offset = csp_offset_segment(sp1,sp2,r)
			if subpath_offset == [] :
				subpath_offset = segment_offset
				
				prev_l = len(subpath_offset)
			else : 
				prev, arc, next = csp_join_offsets(subpath_offset[-prev_l:],segment_offset,sp1,sp2,sp1_l,sp2_l,r)
				#csp_draw([prev],"Blue")
				#csp_draw([arc],"Magenta")
				subpath_offset = csp_concat_subpaths(subpath_offset[:-prev_l+1],prev,arc,next)
				prev_l = len(next)				
			sp1_l, sp2_l = sp1[:], sp2[:]
						
		# Join last and first offsets togother to close the curve
		
		prev, arc, next = csp_join_offsets(subpath_offset[-prev_l:], subpath_offset[:2], subpath[0], subpath[1], sp1_l,sp2_l, r)
		subpath_offset[:2] = next[:]
		subpath_offset = csp_concat_subpaths(subpath_offset[:-prev_l+1],prev,arc)
		#csp_draw([prev],"Blue")
		#csp_draw([arc],"Red")
		#csp_draw([next],"Red")

		# Collect subpath's offset and save it to unclipped offset list. 	
		unclipped_offset[i] = subpath_offset[:]	

		#for k,t in intersection[i]:
		#	draw_pointer(csp_at_t(subpath_offset[k-1], subpath_offset[k], t))
			
	#inkex.etree.SubElement( options.doc_root, inkex.addNS('path','svg'), {"d": cubicsuperpath.formatPath(unclipped_offset), "style":"fill:none;stroke:#0f0;"} )	
	print_("Offsetted path in %s"%(time.time()-time_))
	time_ = time.time()
	
	#for i in range(len(unclipped_offset)):
	#	csp_draw([unclipped_offset[i]], color = ["Green","Red","Blue"][i%3], width = .1)
	#return []
	############################################################################
	# Now to the clipping. 
	############################################################################
	# First of all find all intersection's between all segments of all offseted subpaths, including self intersections.

	#TODO define offset tolerance here
	global small_tolerance
	small_tolerance = 0.01
	summ = 0
	summ1 = 0 	 
	for subpath_i in xrange(csp_len) :
		for subpath_j in xrange(subpath_i,csp_len) :
			subpath = unclipped_offset[subpath_i]
			subpath1 = unclipped_offset[subpath_j]
			for i in xrange(1,len(subpath)) :
				# If subpath_i==subpath_j we are looking for self intersections, so 
				# we'll need search intersections only for xrange(i,len(subpath1))
				for j in ( xrange(i,len(subpath1)) if subpath_i==subpath_j else xrange(len(subpath1))) :
					if subpath_i==subpath_j and j==i :
						# Find self intersections of a segment
						sp1,sp2,sp3 = csp_split(subpath[i-1],subpath[i],.5)
						intersections = csp_segments_intersection(sp1,sp2,sp2,sp3)
						summ +=1 
						for t in intersections :
							summ1 += 1
							if not ( small(t[0]-1) and small(t[1]) ) and 0<=t[0]<=1 and 0<=t[1]<=1 :
								intersection[subpath_i] += [ [i,t[0]/2],[j,t[1]/2+.5] ]
					else :
						intersections = csp_segments_intersection(subpath[i-1],subpath[i],subpath1[j-1],subpath1[j])
						summ +=1 
						for t in intersections :
							summ1 += 1
							#TODO tolerance dependence to cpsp_length(t)
							if len(t) == 2 and 0<=t[0]<=1 and 0<=t[1]<=1 and not (
									subpath_i==subpath_j and (
									(j-i-1) % (len(subpath)-1) == 0 and small(t[0]-1) and small(t[1]) or 
									(i-j-1) % (len(subpath)-1) == 0 and small(t[1]-1) and small(t[0]) )  ) :
								intersection[subpath_i] += [ [i,t[0]] ]
								intersection[subpath_j] += [ [j,t[1]] ]	
								#draw_pointer(csp_at_t(subpath[i-1],subpath[i],t[0]),"#f00")
								#print_(t)
								#print_(i,j)
							elif len(t)==5 and t[4]=="Overlap":	
								intersection[subpath_i] += [ [i,t[0]], [i,t[1]] ]
								intersection[subpath_j] += [ [j,t[1]], [j,t[3]] ]

	print_("Intersections found in %s"%(time.time()-time_))
	print_("Examined %s segments"%(summ))
	print_("found %s intersections"%(summ1))
	time_ = time.time()
								
	########################################################################
	# Split unclipped offset by intersection points into splitted_offset
	########################################################################
	splitted_offset = []
	for i in xrange(csp_len) :
		subpath = unclipped_offset[i]
		if len(intersection[i]) > 0 :
			parts = csp_subpath_split_by_points(subpath, intersection[i])
			# Close	parts list to close path (The first and the last parts are joined together)		
			if  [1,0.] not in intersection[i] : 
				parts[0][0][0] = parts[-1][-1][0]
				parts[0] = csp_concat_subpaths(parts[-1], parts[0])
				splitted_offset += parts[:-1]
			else: 
				splitted_offset += parts[:]
		else :
			splitted_offset += [subpath[:]]
	
	#for i in range(len(splitted_offset)):
	#	csp_draw([splitted_offset[i]], color = ["Green","Red","Blue"][i%3])
	print_("Splitted in %s"%(time.time()-time_))
	time_ = time.time()

	
	########################################################################
	# Clipping
	########################################################################		
	result = []
	for subpath_i in range(len(splitted_offset)):
		clip = False
		s1 = splitted_offset[subpath_i]
		for subpath_j in range(len(splitted_offset)):
			s2 = splitted_offset[subpath_j]
			if (P(s1[0][1])-P(s2[-1][1])).l2()<0.0001 and ( (subpath_i+1) % len(splitted_offset) != subpath_j ): 
				if dot(csp_normalized_normal(s2[-2],s2[-1],1.),csp_normalized_slope(s1[0],s1[1],0.))*r<-0.0001 :
					clip = True
					break
			if (P(s2[0][1])-P(s1[-1][1])).l2()<0.0001 and ( (subpath_j+1) % len(splitted_offset) != subpath_i ):
				if dot(csp_normalized_normal(s2[0],s2[1],0.),csp_normalized_slope(s1[-2],s1[-1],1.))*r>0.0001 :
					clip = True
					break
			
		if not clip :
			result += [s1[:]]
		elif options.offset_draw_clippend_path :
			csp_draw([s1],color="Red",width=.1)
			draw_pointer( csp_at_t(s2[-2],s2[-1],1.)+
				(P(csp_at_t(s2[-2],s2[-1],1.))+ P(csp_normalized_normal(s2[-2],s2[-1],1.))*10).to_list(),"Green", "line"  )
			draw_pointer( csp_at_t(s1[0],s1[1],0.)+
				(P(csp_at_t(s1[0],s1[1],0.))+ P(csp_normalized_slope(s1[0],s1[1],0.))*10).to_list(),"Red", "line"  )
				
	# Now join all together and check closure and orientation of result
	joined_result = csp_join_subpaths(result)
	# Check if each subpath from joined_result is closed
	#csp_draw(joined_result,color="Green",width=1)

	
	for s in joined_result[:] :
		if csp_subpaths_end_to_start_distance2(s,s) > 0.001 :
			# Remove open parts
			if options.offset_draw_clippend_path:
				csp_draw([s],color="Orange",width=1)
				draw_pointer(s[0][1], comment= csp_subpaths_end_to_start_distance2(s,s))
				draw_pointer(s[-1][1], comment = csp_subpaths_end_to_start_distance2(s,s))
			joined_result.remove(s)
		else : 			
			# Remove small parts
			minx,miny,maxx,maxy = csp_true_bounds([s])
			if (minx[0]-maxx[0])**2 + (miny[1]-maxy[1])**2 < 0.1 :
				joined_result.remove(s)
	print_("Clipped and joined path in %s"%(time.time()-time_))
	time_ = time.time()
			
	########################################################################
	# Now to the Dummy cliping: remove parts from splitted offset if their 
	# centers are  closer to the original path than offset radius. 
	########################################################################		
	
	r1,r2 = ( (0.99*r)**2, (1.01*r)**2 ) if abs(r*.01)<1 else  ((abs(r)-1)**2, (abs(r)+1)**2)
	for s in joined_result[:]:
		dist = csp_to_point_distance(original_csp, s[int(len(s)/2)][1], dist_bounds = [r1,r2], tolerance = .000001)
		if not r1 < dist[0] < r2 : 
			joined_result.remove(s)
			if options.offset_draw_clippend_path:
				csp_draw([s], comment = math.sqrt(dist[0]))
				draw_pointer(csp_at_t(csp[dist[1]][dist[2]-1],csp[dist[1]][dist[2]],dist[3])+s[int(len(s)/2)][1],"blue", "line", comment = [math.sqrt(dist[0]),i,j,sp]  )

	print_("-----------------------------")
	print_("Total offset time %s"%(time.time()-time_start))
	print_()
	return joined_result
	
	
		


################################################################################
###
###		Biarc function
###
###		Calculates biarc approximation of cubic super path segment
###		splits segment if needed or approximates it with straight line
###
################################################################################
def biarc(sp1, sp2, z1, z2, depth=0):
	def biarc_split(sp1,sp2, z1, z2, depth): 
		if depth<options.biarc_max_split_depth:
			sp1,sp2,sp3 = csp_split(sp1,sp2)
			l1, l2 = cspseglength(sp1,sp2), cspseglength(sp2,sp3)
			if l1+l2 == 0 : zm = z1
			else : zm = z1+(z2-z1)*l1/(l1+l2)
			return biarc(sp1,sp2,z1,zm,depth+1)+biarc(sp2,sp3,zm,z2,depth+1)
		else: return [ [sp1[1],'line', 0, 0, sp2[1], [z1,z2]] ]

	P0, P4 = P(sp1[1]), P(sp2[1])
	TS, TE, v = (P(sp1[2])-P0), -(P(sp2[0])-P4), P0 - P4
	tsa, tea, va = TS.angle(), TE.angle(), v.angle()
	if TE.mag()<straight_distance_tolerance and TS.mag()<straight_distance_tolerance:	
		# Both tangents are zerro - line straight
		return [ [sp1[1],'line', 0, 0, sp2[1], [z1,z2]] ]
	if TE.mag() < straight_distance_tolerance:
		TE = -(TS+v).unit()
		r = TS.mag()/v.mag()*2
	elif TS.mag() < straight_distance_tolerance:
		TS = -(TE+v).unit()
		r = 1/( TE.mag()/v.mag()*2 )
	else:	
		r=TS.mag()/TE.mag()
	TS, TE = TS.unit(), TE.unit()
	tang_are_parallel = ((tsa-tea)%math.pi<straight_tolerance or math.pi-(tsa-tea)%math.pi<straight_tolerance )
	if ( tang_are_parallel  and 
				((v.mag()<straight_distance_tolerance or TE.mag()<straight_distance_tolerance or TS.mag()<straight_distance_tolerance) or
					1-abs(TS*v/(TS.mag()*v.mag()))<straight_tolerance)	):
				# Both tangents are parallel and start and end are the same - line straight
				# or one of tangents still smaller then tollerance

				# Both tangents and v are parallel - line straight
		return [ [sp1[1],'line', 0, 0, sp2[1], [z1,z2]] ]

	c,b,a = v*v, 2*v*(r*TS+TE), 2*r*(TS*TE-1)
	if v.mag()==0:
		return biarc_split(sp1, sp2, z1, z2, depth)
	asmall, bsmall, csmall = abs(a)<10**-10,abs(b)<10**-10,abs(c)<10**-10 
	if 		asmall and b!=0:	beta = -c/b
	elif 	csmall and a!=0:	beta = -b/a 
	elif not asmall:	 
		discr = b*b-4*a*c
		if discr < 0:	raise ValueError, (a,b,c,discr)
		disq = discr**.5
		beta1 = (-b - disq) / 2 / a
		beta2 = (-b + disq) / 2 / a
		if beta1*beta2 > 0 :	raise ValueError, (a,b,c,disq,beta1,beta2)
		beta = max(beta1, beta2)
	elif	asmall and bsmall:	
		return biarc_split(sp1, sp2, z1, z2, depth)
	alpha = beta * r
	ab = alpha + beta 
	P1 = P0 + alpha * TS
	P3 = P4 - beta * TE
	P2 = (beta / ab)  * P1 + (alpha / ab) * P3


	def calculate_arc_params(P0,P1,P2):
		D = (P0+P2)/2
		if (D-P1).mag()==0: return None, None
		R = D - ( (D-P0).mag()**2/(D-P1).mag() )*(P1-D).unit()
		p0a, p1a, p2a = (P0-R).angle()%(2*math.pi), (P1-R).angle()%(2*math.pi), (P2-R).angle()%(2*math.pi)
		alpha =  (p2a - p0a) % (2*math.pi)					
		if (p0a<p2a and  (p1a<p0a or p2a<p1a))	or	(p2a<p1a<p0a) : 
			alpha = -2*math.pi+alpha 
		if abs(R.x)>1000000 or abs(R.y)>1000000  or (R-P0).mag<options.min_arc_radius :
			return None, None
		else :	
			return  R, alpha
	R1,a1 = calculate_arc_params(P0,P1,P2)
	R2,a2 = calculate_arc_params(P2,P3,P4)
	if R1==None or R2==None or (R1-P0).mag()<straight_tolerance or (R2-P2).mag()<straight_tolerance	: return [ [sp1[1],'line', 0, 0, sp2[1], [z1,z2]] ]
	
	d = csp_to_arc_distance(sp1,sp2, [P0,P2,R1,a1],[P2,P4,R2,a2])
	if d > options.biarc_tolerance and depth<options.biarc_max_split_depth	 : return biarc_split(sp1, sp2, z1, z2, depth)
	else:
		if R2.mag()*a2 == 0 : zm = z2
		else : zm  = z1 + (z2-z1)*(abs(R1.mag()*a1))/(abs(R2.mag()*a2)+abs(R1.mag()*a1)) 
		return [	[ sp1[1], 'arc', [R1.x,R1.y], a1, [P2.x,P2.y], [z1,zm] ], [ [P2.x,P2.y], 'arc', [R2.x,R2.y], a2, [P4.x,P4.y], [zm,z2] ]		]


def biarc_curve_segment_length(seg):
	if seg[1] == "arc" :
		return math.sqrt((seg[0][0]-seg[2][0])**2+(seg[0][1]-seg[2][1])**2)*seg[3]
	elif seg[1] == "line" :	
		return math.sqrt((seg[0][0]-seg[4][0])**2+(seg[0][1]-seg[4][1])**2)
	else: 
		return 0	


def biarc_curve_clip_at_l(curve, l, clip_type = "strict") :
	# get first subcurve and ceck it's length  
	subcurve, subcurve_l, moved = [], 0, False
	for seg in curve:
		if seg[1] == "move" and moved or seg[1] == "end" :	
			break
		if seg[1] == "move" : moved = True 
		subcurve_l += biarc_curve_segment_length(seg)
		if seg[1] == "arc" or seg[1] == "line" : 
			subcurve += [seg]

	if subcurve_l < l and clip_type == "strict" : return []	
	lc = 0
	if (subcurve[-1][4][0]-subcurve[0][0][0])**2 + (subcurve[-1][4][1]-subcurve[0][0][1])**2 < 10**-7 : subcurve_closed = True
	i = 0
	reverse = False
	while lc<l :
		seg = subcurve[i]
		if reverse :  
			if seg[1] == "line" :
				seg = [seg[4], "line", 0 , 0, seg[0], seg[5]] # Hmmm... Do we have to swap seg[5][0] and seg[5][1] (zstart and zend) or not?
			elif seg[1] == "arc" :
				seg = [seg[4], "arc", seg[2] , -seg[3], seg[0], seg[5]] # Hmmm... Do we have to swap seg[5][0] and seg[5][1] (zstart and zend) or not?
		ls = biarc_curve_segment_length(seg)
		if ls != 0 :
			if l-lc>ls :
				res += [seg]
			else :
				if seg[1] == "arc" :
					r  = math.sqrt((seg[0][0]-seg[2][0])**2+(seg[0][1]-seg[2][1])**2)
					x,y = seg[0][0]-seg[2][0], seg[0][1]-seg[2][1]
					a = seg[3]/ls*(l-lc)
					x,y = x*math.cos(a) - y*math.sin(a),  x*math.sin(a) + y*math.cos(a)
					x,y = x+seg[2][0], y+seg[2][1]
					res += [[ seg[0], "arc",  seg[2], a, [x,y], [seg[5][0],seg[5][1]/ls*(l-lc)]  ]]
				if seg[1] == "line" :
					res += [[ seg[0], "line",  0, 0, [(seg[4][0]-seg[0][0])/ls*(l-lc),(seg[4][1]-seg[0][1])/ls*(l-lc)], [seg[5][0],seg[5][1]/ls*(l-lc)]  ]]
		i += 1 
		if i >= len(subcurve) and not subcurve_closed: 
			reverse = not reverse
		i = i%len(subcurve)
	return res	

	
	
class Postprocessor():
	def __init__(self, error_function_handler):	
		self.error = error_function_handler 
		self.functions = {
					"remap"		: self.remap,
					"remapi"	: self.remapi ,
					"scale"		: self.scale,
					"move"		: self.move,
					"flip"		: self.flip_axis,
					"flip_axis"	: self.flip_axis,
					"round"		: self.round_coordinates,
					"parameterize"		: self.parameterize,
					}
	
			
	def process(self,command):
		command = re.sub(r"\\\\",":#:#:slash:#:#:",command)
		command = re.sub(r"\\;",":#:#:semicolon:#:#:",command)
		command = command.split(";")
		for s in command: 
			s = re.sub(":#:#:slash:#:#:","\\\\",s)
			s = re.sub(":#:#:semicolon:#:#:","\\;",s)
			s = s.strip()
			if s!="" :
				self.parse_command(s)		
			
	
	def parse_command(self,command):
		r = re.match(r"([A-Za-z0-9_]+)\s*\(\s*(.*)\)",command)
		if not r:
			self.error("Parse error while postprocessing.\n(Command: '%s')"%(command), "error")
		function, parameters = r.group(1).lower(),r.group(2)
		if function in self.functions :
			print_("Postprocessor: executing function %s(%s)"%(function,parameters))
			self.functions[function](parameters)
		else : 
			self.error("Unrecognized function '%s' while postprocessing.\n(Command: '%s')"%(function,command), "error")
	
	
	def re_sub_on_gcode_lines(self, pattern,replacemant):
		gcode = self.gcode.split("\n")
		self.gcode = ""
		for i in range(len(gcode)) :
			self.gcode += re.sub(pattern,replacement,gcode[i])
		
	
	def remapi(self,parameters):
		self.remap(parameters, case_sensitive = True)
	
	
	def remap(self,parameters, case_sensitive = False):
		# remap parameters should be like "x->y,y->x"
		parameters = parameters.replace("\,",":#:#:coma:#:#:")
		parameters = parameters.split(",")
		pattern, remap = [], []
		for s in parameters:
			s = s.replace(":#:#:coma:#:#:","\,")
			r = re.match("""\s*(\'|\")(.*)\\1\s*->\s*(\'|\")(.*)\\3\s*""",s)
			if not r :
				self.error("Bad parameters for remap.\n(Parameters: '%s')"%(parameters), "error")
			pattern +=[r.group(2)]	
			remap +=[r.group(4)]	
		
		
		
		for i in range(len(pattern)) :
			if case_sensitive :
				self.gcode = ireplace(self.gcode, pattern[i], ":#:#:remap_pattern%s:#:#:"%i )
			else :
				self.gcode = self.gcode.replace(pattern[i], ":#:#:remap_pattern%s:#:#:"%i)
			
		for i in range(len(remap)) :
			self.gcode = self.gcode.replace(":#:#:remap_pattern%s:#:#:"%i, remap[i])
	
	
	def transform(self, move, scale):
		axis = ["xi","yj","zk","a"]
		flip = scale[0]*scale[1]*scale[2] < 0 
		gcode = ""
		warned = []
		r_scale = scale[0]
		plane = "g17"
		for s in self.gcode.split("\n"):
			# get plane selection: 
			s_wo_comments = re.sub(r"\([^\)]*\)","",s)
			r = re.search(r"(?i)(G17|G18|G19)", s_wo_comments)
			if r :
				plane = r.group(1).lower()
				if plane == "g17" : r_scale = scale[0] # plane XY -> scale x
				if plane == "g18" : r_scale = scale[0] # plane XZ -> scale x
				if plane == "g19" : r_scale = scale[1] # plane YZ -> scale y
			# Raise warning if scale factors are not the game for G02 and G03	
			if plane not in warned:
				r = re.search(r"(?i)(G02|G03)", s_wo_comments)
				if r :
					if plane == "g17" and scale[0]!=scale[1]: self.error("Post-processor: Scale factors for X and Y axis are not the same. G02 and G03 codes will be corrupted.","warning") 
					if plane == "g18" and scale[0]!=scale[2]: self.error("Post-processor: Scale factors for X and Z axis are not the same. G02 and G03 codes will be corrupted.","warning") 
					if plane == "g19" and scale[1]!=scale[2]: self.error("Post-processor: Scale factors for Y and Z axis are not the same. G02 and G03 codes will be corrupted.","warning") 
					warned += [plane]
			# Transform		
			for i in range(len(axis)) :
				if move[i] != 0 or scale[i] != 1:
					for a in axis[i] :
						r = re.search(r"(?i)("+a+r")\s*(-?)\s*(\d*\.?\d*)", s)
						if r and r.group(3)!="":
							s = re.sub(r"(?i)("+a+r")\s*(-?)\s*(\d*\.?\d*)", r"\1 %f"%(float(r.group(2)+r.group(3))*scale[i]+(move[i] if a not in ["i","j","k"] else 0) ), s)
			#scale radius R
			if r_scale != 1 :
				r = re.search(r"(?i)(r)\s*(-?\s*(\d*\.?\d*))", s)
				if r and r.group(3)!="":
					try:
						s = re.sub(r"(?i)(r)\s*(-?)\s*(\d*\.?\d*)", r"\1 %f"%( float(r.group(2)+r.group(3))*r_scale ), s)
					except:
						pass	

			gcode += s + "\n"
			
		self.gcode = gcode
		if flip : 
			self.remapi("'G02'->'G03', 'G03'->'G02'")


	def parameterize(self,parameters) :
		planes = []
		feeds = {}
		coords = []
		gcode = ""
		coords_def = {"x":"x","y":"y","z":"z","i":"x","j":"y","k":"z","a":"a"}
		for s in self.gcode.split("\n"):
			s_wo_comments = re.sub(r"\([^\)]*\)","",s)
			# get Planes
			r = re.search(r"(?i)(G17|G18|G19)", s_wo_comments)
			if r :
				plane = r.group(1).lower()
				if plane not in planes : 
					planes += [plane]
			# get Feeds
			r = re.search(r"(?i)(F)\s*(-?)\s*(\d*\.?\d*)", s_wo_comments)
			if r :
				feed  = float (r.group(2)+r.group(3))
				if feed not in feeds :
					feeds[feed] = "#"+str(len(feeds)+20)
					
			#Coordinates
			for c in "xyzijka" :
				r = re.search(r"(?i)("+c+r")\s*(-?)\s*(\d*\.?\d*)", s_wo_comments)
				if r :
					c = coords_def[r.group(1).lower()]
					if c not in coords :
						coords += [c]
		# Add offset parametrization
		offset = {"x":"#6","y":"#7","z":"#8","a":"#9"}
		for c in coords:
			gcode += "%s  = 0 (%s axis offset)\n" %  (offset[c],c.upper())
			
		# Add scale parametrization
		if planes == [] : planes = ["g17"]
		if len(planes)>1 :  # have G02 and G03 in several planes scale_x = scale_y = scale_z required
			gcode += "#10 = 1 (Scale factor)\n"
			scale = {"x":"#10","i":"#10","y":"#10","j":"#10","z":"#10","k":"#10","r":"#10"}
		else :
			gcode += "#10 = 1 (%s Scale factor)\n" % ({"g17":"XY","g18":"XZ","g19":"YZ"}[planes[0]])
			gcode += "#11 = 1 (%s Scale factor)\n" % ({"g17":"Z","g18":"Y","g19":"X"}[planes[0]])
			scale = {"x":"#10","i":"#10","y":"#10","j":"#10","z":"#10","k":"#10","r":"#10"}
			if "g17" in planes :
				scale["z"] = "#11"				
				scale["k"] = "#11"				
			if "g18" in planes :
				scale["y"] = "#11"				
				scale["j"] = "#11"				
			if "g19" in planes :
				scale["x"] = "#11"				
				scale["i"] = "#11"				
		# Add a scale 
		if "a" in coords:
			gcode += "#12  = 1 (A axis scale)\n" 
			scale["a"] = "#12"
		
		# Add feed parametrization 
		for f in feeds :
			gcode += "%s = %f (Feed definition)\n" % (feeds[f],f)

		# Parameterize Gcode		
		for s in self.gcode.split("\n"):
			#feed replace :
			r = re.search(r"(?i)(F)\s*(-?)\s*(\d*\.?\d*)", s)
			if r and len(r.group(3))>0:
				s = re.sub(r"(?i)(F)\s*(-?)\s*(\d*\.?\d*)", "F [%s]"%feeds[float(r.group(2)+r.group(3))], s)
			#Coords XYZA replace
			for c in "xyza" :
				r = re.search(r"(?i)(("+c+r")\s*(-?)\s*(\d*\.?\d*))", s)
				if r and len(r.group(4))>0:
					s = re.sub(r"(?i)("+c+r")\s*((-?)\s*(\d*\.?\d*))", r"\1[\2*%s+%s]"%(scale[c],offset[c]), s)

			#Coords IJKR replace
			for c in "ijkr" :
				r = re.search(r"(?i)(("+c+r")\s*(-?)\s*(\d*\.?\d*))", s)
				if r and len(r.group(4))>0:
					s = re.sub(r"(?i)("+c+r")\s*((-?)\s*(\d*\.?\d*))", r"\1[\2*%s]"%scale[c], s)

			gcode += s + "\n"
	
		self.gcode = gcode	

	
	def round_coordinates(self,parameters) :
		try: 
			round_ = int(parameters)
		except :	
			self.error("Bad parameters for round. Round should be an integer! \n(Parameters: '%s')"%(parameters), "error")		
		gcode = ""
		for s in self.gcode.split("\n"):
			for a in "xyzijkaf" :
				r = re.search(r"(?i)("+a+r")\s*(-?\s*(\d*\.?\d*))", s)
				if r : 
					
					if r.group(2)!="":
						s = re.sub(
									r"(?i)("+a+r")\s*(-?)\s*(\d*\.?\d*)", 
									(r"\1 %0."+str(round_)+"f" if round_>0 else r"\1 %d")%round(float(r.group(2)),round_),
									s)
			gcode += s + "\n"
		self.gcode = gcode
	

	def scale(self, parameters):
		parameters = parameters.split(",")
		scale = [1.,1.,1.,1.]
		try :
			for i in range(len(parameters)) :
				if float(parameters[i])==0 : 
					self.error("Bad parameters for scale. Scale should not be 0 at any axis! \n(Parameters: '%s')"%(parameters), "error")		
				scale[i] = float(parameters[i])
		except :
			self.error("Bad parameters for scale.\n(Parameters: '%s')"%(parameters), "error")
		self.transform([0,0,0,0],scale)		

	
	def move(self, parameters):
		parameters = parameters.split(",")
		move = [0.,0.,0.,0.]
		try :
			for i in range(len(parameters)) :
				move[i] = float(parameters[i])
		except :
			self.error("Bad parameters for move.\n(Parameters: '%s')"%(parameters), "error")
		self.transform(move,[1.,1.,1.,1.])		


	def flip_axis(self, parameters):
		parameters = parameters.lower()
		axis = {"x":1.,"y":1.,"z":1.,"a":1.}	
		for p in parameters: 
			if p in [","," ","	","\r","'",'"'] : continue
			if p not in ["x","y","z","a"] : 
				self.error("Bad parameters for flip_axis. Parameter should be string consists of 'xyza' \n(Parameters: '%s')"%(parameters), "error")
			axis[p] = -axis[p]
		self.scale("%f,%f,%f,%f"%(axis["x"],axis["y"],axis["z"],axis["a"]))	

	
			
################################################################################
###		Polygon class
################################################################################
class Polygon:
	def __init__(self, polygon=None):
		self.polygon = [] if polygon==None else polygon[:]
	
	
	def move(self, x, y) :
		for i in range(len(self.polygon)) :
			for j in range(len(self.polygon[i])) :
				self.polygon[i][j][0] += x
				self.polygon[i][j][1] += y
	
	
	def bounds(self) : 
		minx,miny,maxx,maxy = 1e400, 1e400, -1e400, -1e400
		for poly in self.polygon :
			for p in poly :
				if minx > p[0] : minx = p[0]
				if miny > p[1] : miny = p[1]
				if maxx < p[0] : maxx = p[0]
				if maxy < p[1] : maxy = p[1]
		return minx*1,miny*1,maxx*1,maxy*1		
	
	
	def width(self):
		b = self.bounds()
		return b[2]-b[0]
	
	
	def rotate_(self,sin,cos) :
		for i in range(len(self.polygon)) :
			for j in range(len(self.polygon[i])) :
				x,y = self.polygon[i][j][0], self.polygon[i][j][1] 
				self.polygon[i][j][0] = x*cos - y*sin
				self.polygon[i][j][1] = x*sin + y*cos
		
	
	def rotate(self, a):
		cos, sin = math.cos(a), math.sin(a)
		self.rotate_(sin,cos)
	
			
	def drop_into_direction(self, direction, surface) :
		# Polygon is a list of simple polygons
		# Surface is a polygon + line y = 0 
		# Direction is [dx,dy]  
		if len(self.polygon) == 0 or len(self.polygon[0])==0 : return
		if direction[0]**2 + direction[1]**2 <1e-10 : return
		direction = normalize(direction)
		sin,cos = direction[0], -direction[1]
		self.rotate_(-sin,cos)
		surface.rotate_(-sin,cos)
		self.drop_down(surface, zerro_plane = False)
		self.rotate_(sin,cos)
		surface.rotate_(sin,cos)
		
			
	def centroid(self):
		centroids = []
		sa = 0
		for poly in self.polygon:
			cx,cy,a = 0,0,0
			for i in range(len(poly)):
				[x1,y1],[x2,y2] = poly[i-1],poly[i]
				cx += (x1+x2)*(x1*y2-x2*y1)
				cy += (y1+y2)*(x1*y2-x2*y1)
				a  += (x1*y2-x2*y1)
			a *= 3.
			if abs(a)>0 :
				cx /= a
				cy /= a
				sa += abs(a)
				centroids += [ [cx,cy,a] ]
		if sa == 0 : return	[0.,0.]
		cx,cy = 0.,0.
		for c in centroids :
			cx += c[0]*c[2]
			cy += c[1]*c[2]
		cx /= sa
		cy /= sa
		return [cx,cy]

			
	def drop_down(self, surface, zerro_plane = True) :
		# Polygon is a list of simple polygons
		# Surface is a polygon + line y = 0 
		# Down means min y (0,-1)  
		if len(self.polygon) == 0 or len(self.polygon[0])==0 : return
		# Get surface top point
		top = surface.bounds()[3]
		if zerro_plane : top = max(0, top)
		# Get polygon bottom point
		bottom = self.bounds()[1]
		self.move(0, top - bottom + 10)		
		# Now get shortest distance from surface to polygon in positive x=0 direction
		# Such distance = min(distance(vertex, edge)...)  where edge from surface and 
		# vertex from polygon and vice versa...
		dist = 1e300
		for poly in surface.polygon :
			for i in range(len(poly)) :
				for poly1 in self.polygon :
					for i1 in range(len(poly1)) :
						st,end = poly[i-1], poly[i] 
						vertex = poly1[i1]
						if st[0]<=vertex[0]<= end[0] or end[0]<=vertex[0]<=st[0] :
							if st[0]==end[0] : d = min(vertex[1]-st[1],vertex[1]-end[1])
							else : d = vertex[1] - st[1] - (end[1]-st[1])*(vertex[0]-st[0])/(end[0]-st[0]) 
							if dist > d  : dist = d
						# and vice versa just change the sign because vertex now under the edge
						st,end = poly1[i1-1], poly1[i1] 
						vertex = poly[i]
						if st[0]<=vertex[0]<=end[0] or end[0]<=vertex[0]<=st[0] :
							if st[0]==end[0] : d = min(- vertex[1]+st[1],-vertex[1]+end[1])
							else : d =  - vertex[1] + st[1] + (end[1]-st[1])*(vertex[0]-st[0])/(end[0]-st[0]) 
							if dist > d  : dist = d
		
		if zerro_plane and dist > 10 + top : dist = 10 + top 
		#print_(dist, top, bottom)
		#self.draw()
		self.move(0, -dist)		
		
					
	def draw(self,color="#075",width=.1) :
		for poly in self.polygon :
			csp_draw( [csp_subpath_line_to([],poly+[poly[0]])], color=color,width=width )
			
	
	def add(self, add) :
		if type(add) == type([]) :
			self.polygon += add[:]
		else :	
			self.polygon += add.polygon[:]

	
	def point_inside(self,p) :
		inside = False
		for poly in self.polygon :
			for i in range(len(poly)):
				st,end = poly[i-1], poly[i]
				if p==st or p==end : return True # point is a vertex = point is on the edge
				if st[0]>end[0] : st, end = end, st # This will be needed to check that edge if open only at rigth end
				c = (p[1]-st[1])*(end[0]-st[0])-(end[1]-st[1])*(p[0]-st[0])
				#print_(c)
				if st[0]<=p[0]<end[0] : 
					if c<0 : 
						inside = not inside
					elif c == 0 : return True # point is on the edge
				elif st[0]==end[0]==p[0] and (st[1]<=p[1]<=end[1] or end[1]<=p[1]<=st[1]) : # point is on the edge
					return True
		return inside			

	
	def hull(self) :
		# Add vertices at all self intersection points. 
		hull = []
		for i1 in range(len(self.polygon)):
			poly1 = self.polygon[i1]
			poly_ = []
			for j1 in range(len(poly1)):
				s, e = poly1[j1-1],poly1[j1]
				poly_ += [s]
				
				# Check self intersections 
				for j2 in range(j1+1,len(poly1)):
					s1, e1 = poly1[j2-1],poly1[j2]
					int_ = line_line_intersection_points(s,e,s1,e1)
					for p in int_ :
						if point_to_point_d2(p,s)>0.000001 and point_to_point_d2(p,e)>0.000001 : 
							poly_ += [p]
				# Check self intersections with other polys  
				for i2 in range(len(self.polygon)):
					if i1==i2 : continue
					poly2 = self.polygon[i2]
					for j2 in range(len(poly2)):
						s1, e1 = poly2[j2-1],poly2[j2]
						int_ = line_line_intersection_points(s,e,s1,e1)
						for p in int_ :
							if point_to_point_d2(p,s)>0.000001 and point_to_point_d2(p,e)>0.000001 : 
								poly_ += [p]
			hull += [poly_]
		# Create the dictionary containing all edges in both directions
		edges = {}
		for poly in self.polygon :
			for i in range(len(poly)):
				s,e = tuple(poly[i-1]), tuple(poly[i])
				if (point_to_point_d2(e,s)<0.000001) : continue
				break_s, break_e = False, False
				for p in edges :
					if point_to_point_d2(p,s)<0.000001 : 
						break_s = True
						s = p
					if point_to_point_d2(p,e)<0.000001 : 
						break_e = True
						e = p
					if break_s and break_e : break
				l = point_to_point_d(s,e)
				if not break_s and not break_e : 
					edges[s] = [ [s,e,l] ]
					edges[e] = [ [e,s,l] ]
					#draw_pointer(s+e,"red","line")
					#draw_pointer(s+e,"red","line")
				else : 
					if e in edges :	
						for edge in edges[e] :	
							if point_to_point_d2(edge[1],s)<0.000001 :
								break
						if point_to_point_d2(edge[1],s)>0.000001 :
							edges[e] += [ [e,s,l] ]
							#draw_pointer(s+e,"red","line")
							
					else : 
						edges[e] = [ [e,s,l] ]
						#draw_pointer(s+e,"green","line")
					if s in edges :	
						for edge in edges[s] :	
							if  point_to_point_d2(edge[1],e)<0.000001 :
								break
						if point_to_point_d2(edge[1],e)>0.000001 :
							edges[s] += [ [s,e, l] ]
							#draw_pointer(s+e,"red","line")
					else : 
						edges[s] = [ [s,e,l] ]
						#draw_pointer(s+e,"green","line")

		
		def angle_quadrant(sin,cos):
			# quadrants are (0,pi/2], (pi/2,pi], (pi,3*pi/2], (3*pi/2, 2*pi], i.e. 0 is in the 4-th quadrant
			if sin>0 and cos>=0 : return 1
			if sin>=0 and cos<0 : return 2
			if sin<0 and cos<=0 : return 3
			if sin<=0 and cos>0 : return 4
			
		
		def angle_is_less(sin,cos,sin1,cos1):
			# 0 = 2*pi is the largest angle
			if [sin1, cos1] == [0,1] : return True
			if [sin, cos] == [0,1] : return False
			if angle_quadrant(sin,cos)>angle_quadrant(sin1,cos1) : 
				return False
			if angle_quadrant(sin,cos)<angle_quadrant(sin1,cos1) : 
				return True
			if sin>=0 and cos>0 : return sin<sin1
			if sin>0 and cos<=0 : return sin>sin1
			if sin<=0 and cos<0 : return sin>sin1
			if sin<0 and cos>=0 : return sin<sin1

			
		def get_closes_edge_by_angle(edges, last):
			# Last edge is normalized vector of the last edge.
			min_angle = [0,1]
			next = last
			last_edge = [(last[0][0]-last[1][0])/last[2], (last[0][1]-last[1][1])/last[2]]
			for p in edges:
				#draw_pointer(list(p[0])+[p[0][0]+last_edge[0]*40,p[0][1]+last_edge[1]*40], "Red", "line", width=1)
				#print_("len(edges)=",len(edges))
				cur = [(p[1][0]-p[0][0])/p[2],(p[1][1]-p[0][1])/p[2]]
				cos, sin = dot(cur,last_edge),  cross(cur,last_edge)
				#draw_pointer(list(p[0])+[p[0][0]+cur[0]*40,p[0][1]+cur[1]*40], "Orange", "line", width=1, comment = [sin,cos])
				#print_("cos, sin=",cos,sin)
				#print_("min_angle_before=",min_angle)

				if 	angle_is_less(sin,cos,min_angle[0],min_angle[1]) : 
					min_angle = [sin,cos]
					next = p
				#print_("min_angle=",min_angle)

			return next		
			
		# Join edges together into new polygon cutting the vertexes inside new polygon
		self.polygon = []
		len_edges = sum([len(edges[p]) for p in edges]) 
		loops = 0 
		
		while len(edges)>0 :
			poly = []
			if loops > len_edges  : raise ValueError, "Hull error"
			loops+=1
			# Find left most vertex.
			start = (1e100,1)
			for edge in edges : 
				start = min(start, min(edges[edge])) 
			last = [(start[0][0]-1,start[0][1]),start[0],1]
			first_run = True
			loops1 = 0
			while (last[1]!=start[0] or first_run) : 	
				first_run = False
				if loops1 > len_edges  : raise ValueError, "Hull error"
				loops1 += 1
				next = get_closes_edge_by_angle(edges[last[1]],last)
				#draw_pointer(next[0]+next[1],"Green","line", comment=i, width= 1)
				#print_(next[0],"-",next[1]) 

				last = next
				poly += [ list(last[0]) ]				
			self.polygon += [ poly ]
			# Remove all edges that are intersects new poly (any vertex inside new poly)
			poly_ = Polygon([poly])
			for p in edges.keys()[:] : 
				if poly_.point_inside(list(p)) : del edges[p]
		self.draw(color="Green", width=1)	


class Arangement_Genetic:
	# gene = [fittness, order, rotation, xposition]
	# spieces = [gene]*shapes count
	# population = [spieces]
	def __init__(self, polygons, material_width):
		self.population = []
		self.genes_count = len(polygons)
		self.polygons = polygons
		self.width = material_width
		self.mutation_factor = 0.1
		self.order_mutate_factor = 1.
		self.move_mutate_factor = 1.

	
	def add_random_species(self,count):
		for i in range(count):
			specimen = []
			order = range(self.genes_count)
			random.shuffle(order)
			for j in order:
				specimen += [ [j, random.random(), random.random()] ]
			self.population += [ [None,specimen] ]

	
	def species_distance2(self,sp1,sp2) :
		# retun distance, each component is normalized
		s = 0
		for j in range(self.genes_count) :
			s += ((sp1[j][0]-sp2[j][0])/self.genes_count)**2 + (( sp1[j][1]-sp2[j][1]))**2 + ((sp1[j][2]-sp2[j][2]))**2
		return s

	
	def similarity(self,sp1,top) :
		# Define similarity as a simple distance between two points in len(gene)*len(spiece) -th dimentions
		# for sp2 in top_spieces sum(|sp1-sp2|)/top_count
		sim = 0
		for sp2 in top : 
			sim += math.sqrt(species_distance2(sp1,sp2[1]))
		return sim/len(top)
		
	
	def leave_top_species(self,count):
		self.population.sort()
		res = [  copy.deepcopy(self.population[0]) ]
		del self.population[0]
		for i in range(count-1) :
			t = []
			for j in range(20) : 
				i1 = random.randint(0,len(self.population)-1) 
				t += [ [self.population[i1][0],i1] ] 
			t.sort()
			res += [  copy.deepcopy(self.population[t[0][1]]) ]
			del self.population[t[0][1]]
		self.population = res		
		#del self.population[0]
		#for c in range(count-1) :
		#	rank = []
		#	for i in range(len(self.population)) :	
		#		sim = self.similarity(self.population[i][1],res)
		#		rank += [ [self.population[i][0] / sim if sim>0 else 1e100,i] ]
		#	rank.sort()
		#	res += [  copy.deepcopy(self.population[rank[0][1]]) ]
		#	print_(rank[0],self.population[rank[0][1]][0])
		#	print_(res[-1])
		#	del self.population[rank[0][1]]
			
		self.population = res
			
			
	def populate_species(self,count, parent_count):
		self.population.sort()
		self.inc = 0
		for c in range(count):
			parent1 = random.randint(0,parent_count-1)
			parent2 = random.randint(0,parent_count-1)
			if parent1==parent2 : parent2 = (parent2+1) % parent_count
			parent1, parent2 = self.population[parent1][1], self.population[parent2][1]
			i1,i2 = 0, 0
			genes_order = []
			specimen = [ [0,0.,0.] for i in range(self.genes_count) ]
			
			self.incest_mutation_multiplyer = 1.
			self.incest_mutation_count_multiplyer = 1.

			if self.species_distance2(parent1, parent2) <= .01/self.genes_count :
				# OMG it's a incest :O!!!
				# Damn you bastards!
				self.inc +=1
				self.incest_mutation_multiplyer = 2. 
				self.incest_mutation_count_multiplyer = 2. 
			else :
				if random.random()<.01 : print_(self.species_distance2(parent1, parent2))	
			start_gene = random.randint(0,self.genes_count)
			end_gene = (max(1,random.randint(0,self.genes_count),int(self.genes_count/4))+start_gene) % self.genes_count
			if end_gene<start_gene : 
				end_gene, start_gene = start_gene, end_gene
				parent1, parent2 = parent2, parent1
			for i in range(start_gene,end_gene) : 
				#rotation_mutate_param = random.random()/100
				#xposition_mutate_param = random.random()/100
				tr = 1. #- rotation_mutate_param
				tp = 1. #- xposition_mutate_param
				specimen[i] = [parent1[i][0], parent1[i][1]*tr+parent2[i][1]*(1-tr),parent1[i][2]*tp+parent2[i][2]*(1-tp)]
				genes_order += [ parent1[i][0] ]

			for i in range(0,start_gene)+range(end_gene,self.genes_count) : 
				tr = 0. #rotation_mutate_param
				tp = 0. #xposition_mutate_param
				j = i 
				while parent2[j][0] in genes_order :
					j = (j+1)%self.genes_count
				specimen[i] = [parent2[j][0], parent1[i][1]*tr+parent2[i][1]*(1-tr),parent1[i][2]*tp+parent2[i][2]*(1-tp)]
				genes_order += [ parent2[j][0] ]						
				

			for i in range(random.randint(self.mutation_genes_count[0],self.mutation_genes_count[0]*self.incest_mutation_count_multiplyer )) :
				if random.random() < self.order_mutate_factor * self.incest_mutation_multiplyer : 
					i1,i2 = random.randint(0,self.genes_count-1),random.randint(0,self.genes_count-1)
					specimen[i1][0], specimen[i2][0] = specimen[i2][0], specimen[i1][0]
				if random.random() < self.move_mutation_factor * self.incest_mutation_multiplyer: 
					i1 = random.randint(0,self.genes_count-1)
					specimen[i1][1] =  (specimen[i1][1]+random.random()*math.pi2*self.move_mutation_multiplier)%1.
					specimen[i1][2] =  (specimen[i1][2]+random.random()*self.move_mutation_multiplier)%1.
			self.population += [ [None,specimen] ]	

	
	def test_spiece_drop_down(self,spiece) : 
		surface = Polygon()
		for p in spiece :
			time_ = time.time()
			poly = Polygon(copy.deepcopy(self.polygons[p[0]].polygon))
			poly.rotate(p[1]*math.pi2)
			w = poly.width()
			left = poly.bounds()[0]
			poly.move( -left + (self.width-w)*p[2],0)
			poly.drop_down(surface)
			surface.add(poly)
		return surface

	
	def test(self,test_function): 
		for i in range(len(self.population)) :
			if self.population[i][0] == None :
				surface = test_function(self.population[i][1])
				b = surface.bounds()
				self.population[i][0] = (b[3]-b[1])*(b[2]-b[0])
		self.population.sort() 				


	def test_spiece_centroid(self,spiece) : 
		poly = Polygon(copy.deepcopy(self.polygons[spiece[0][0]].polygon))
		poly.rotate(spiece[0][2]*math.pi2)
		surface  = Polygon(poly.polygon)
		i = 0
		for p in spiece[1:] :
			i += 1
			poly = Polygon(copy.deepcopy(self.polygons[p[0]].polygon))
			poly.rotate(p[2]*math.pi2)
			c = surface.centroid()
			c1 = poly.centroid()
			direction = [math.cos(p[1]*math.pi2), -math.sin(p[1]*math.pi2)]
			poly.move(c[0]-c1[0]-direction[0]*100,c[1]-c1[1]-direction[1]*100)
			poly.drop_into_direction(direction,surface)
			surface.add(poly)
		return surface
		
		
		
		#surface.draw()

		
################################################################################
###
###		Gcodetools class
###
################################################################################

class Gcodetools(inkex.Effect):

	def export_gcode(self,gcode) :
		if self.options.postprocessor != ""  or self.options.postprocessor_custom != "" :
			postprocessor = Postprocessor(self.error)
			postprocessor.gcode = gcode
			if self.options.postprocessor != "" :
				postprocessor.process(self.options.postprocessor)
			if self.options.postprocessor_custom != "" :
				postprocessor.process(self.options.postprocessor_custom)
		postprocessor.gcode = self.header + postprocessor.gcode + self.footer
		f = open(self.options.directory+self.options.file, "w")	
		f.write(postprocessor.gcode)
		f.close()							


################################################################################
###		Arrangement: arranges paths by givven params
###		TODO move it to the bottom
################################################################################
	def arrangement(self) :
		paths = self.selected_paths
		surface = Polygon()
		polygons = []
		time_ = time.time()
		print_("Arrangement start at %s"%(time_))
		original_paths = []
		for layer in self.layers :
			if layer in paths :
				for path in paths[layer] :
					csp = cubicsuperpath.parsePath(path.get("d"))
					polygon = Polygon()
					for subpath in csp :
						for sp1, sp2 in zip(subpath,subpath[1:]) :
							polygon.add([csp_segment_convex_hull(sp1,sp2)])
					#print_("Redused edges count from", sum([len(poly) for poly in polygon.polygon ]) )
					polygon.hull()
					original_paths += [path]
					polygons += [polygon]
					
		print_("Paths hull computed in %s sec."%(time.time()-time_))
		print_("Got %s polygons having average %s edges each."% ( len(polygons), float(sum([ sum([len(poly) for poly in polygon.polygon]) for polygon in polygons ])) / len(polygons) ) )
		time_ = time.time()
		
#		material_width = self.options.arrangement_material_width
#		population = Arangement_Genetic(polygons, material_width)
#		population.add_random_species(1)
#		population.test_population_centroid()
##		return
		material_width = self.options.arrangement_material_width
		population = Arangement_Genetic(polygons, material_width)
		
		
		print_("Genetic alhorithm start at %s"%(time_))
		time_ = time.time()
		
	

		population.add_random_species(50)
		population.test(population.test_spiece_centroid)
		print_("Initial population done in %s"%(time.time()-time_))
		time_ = time.time()
		pop = copy.deepcopy(population)
		population_count = self.options.arrangement_population_count
		last_champ = []
		champions_count = 0
		
		
		
		
		for i in range(population_count):
			population.leave_top_species(20)
			population.move_mutation_multiplier = random.random()/2
			
			population.order_mutation_factor = .2
			population.move_mutation_factor = 1.
			population.mutation_genes_count = [1,2]
			population.populate_species(250, 20)
			"""
			randomize = i%100 < 40
			if 	i%100 < 40 : 
				population.add_random_species(250)
			if  40<= i%100 < 100 : 
				population.mutation_genes_count = [1,max(2,int(population.genes_count/4))]  #[1,max(2,int(population.genes_count/2))] if 40<=i%100<60 else [1,max(2,int(population.genes_count/10))]
				population.move_mutation_multiplier = 1. if 40<=i%100<80 else .1
				population.move_mutation_factor = (-(i%100)/30+10/3) if 50<=i%100<100 else .5
				population.order_mutation_factor = 1./(i%100-79) if 80<=i%100<100 else 1.
				population.populate_species(250, 10)
			"""
			population.test(population.test_spiece_centroid)
			draw_new_champ = False
			print_()
			for x in population.population[:10]:
				print_(x[0])
			
			if population.population[0][0]!= last_champ : 
				draw_new_champ = True
				last_champ = population.population[0][0]*1
			

			k = ""			
			#for j in range(10) :
			#	k += "%s   " % population.population[j][0]
			print_("Cicle %s done in %s"%(i,time.time()-time_))
			time_ = time.time()
			print_("%s incests been found"%population.inc)
			print_()
			#print_(k)
			#print_()
			if i == 0  or i == population_count-1 or draw_new_champ :
				colors = ["blue"]
				
				surface = population.test_spiece_centroid(population.population[0][1])
				b = surface.bounds()
				x,y = 400* (champions_count%10), 700*int(champions_count/10)
				surface.move(x-b[0],y-b[1])
				surface.draw(width=2, color=colors[0])
				draw_text("Step = %s\nSquare = %f"%(i,(b[2]-b[0])*(b[3]-b[1])),x,y-40)
				champions_count += 1

				spiece = population.population[0][1]
				poly = Polygon(copy.deepcopy(population.polygons[spiece[0][0]].polygon))
				poly.rotate(spiece[0][2]*math.pi2)
				surface  = Polygon(poly.polygon)
				poly.draw(width = 2, color= "Violet")
				for p in spiece[1:] :
					poly = Polygon(copy.deepcopy(population.polygons[p[0]].polygon))
					poly.rotate(p[2]*math.pi2)
					direction = [math.cos(p[1]*math.pi2), -math.sin(p[1]*math.pi2)]
					normalize(direction)
					c = surface.centroid()
					c1 = poly.centroid()
					poly.move(c[0]-c1[0]-direction[0]*400,c[1]-c1[1]-direction[1]*400)
					c = surface.centroid()
					c1 = poly.centroid()
					poly.draw(width = 5, color= "Violet")
					draw_pointer(c+c1,"Green","line")
					direction = normalize(direction)
					
					
					sin,cos = direction[0], direction[1]
					poly.rotate_(-sin,cos)
					surface.rotate_(-sin,cos)
#					poly.draw(color = "Violet",width=4)					
					surface.draw(color = "Orange",width=4)					
					poly.rotate_(sin,cos)
					surface.rotate_(sin,cos)


					poly.drop_into_direction(direction,surface)
					surface.add(poly)
				
				
		# Now we'll need apply transforms to original paths
		
		
	def __init__(self):
		inkex.Effect.__init__(self)
		self.OptionParser.add_option("-d", "--directory",					action="store", type="string", 		dest="directory", default="C:\\Users\\Chris\\GCode",					help="Directory for gcode file")
		self.OptionParser.add_option("-f", "--filename",					action="store", type="string", 		dest="file", default="-1.0",						help="File name")			
		self.OptionParser.add_option("",   "--add-numeric-suffix-to-filename", action="store", type="inkbool",	dest="add_numeric_suffix_to_filename", default=True,help="Add numeric suffix to filename")			
		self.OptionParser.add_option("",   "--Zscale",						action="store", type="float", 		dest="Zscale", default="1.0",						help="Scale factor Z")				
		self.OptionParser.add_option("",   "--Zoffset",						action="store", type="float", 		dest="Zoffset", default="0.0",						help="Offset along Z")
		self.OptionParser.add_option("-s", "--Zsafe",						action="store", type="float", 		dest="Zsafe", default="0.5",						help="Z above all obstacles")
		self.OptionParser.add_option("-z", "--Zsurface",					action="store", type="float", 		dest="Zsurface", default="0.0",						help="Z of the surface")
		self.OptionParser.add_option("-c", "--Zdepth",						action="store", type="float", 		dest="Zdepth", default="-0.125",					help="Z depth of cut")
		self.OptionParser.add_option("",   "--Zstep",						action="store", type="float", 		dest="Zstep", default="-0.125",						help="Z step of cutting")		
		self.OptionParser.add_option("-p", "--feed",						action="store", type="float", 		dest="feed", default="4.0",							help="Feed rate in unit/min")

		self.OptionParser.add_option("",   "--biarc-tolerance",				action="store", type="float", 		dest="biarc_tolerance", default="1",				help="Tolerance used when calculating biarc interpolation.")				
		self.OptionParser.add_option("",   "--biarc-max-split-depth",		action="store", type="int", 		dest="biarc_max_split_depth", default="4",			help="Defines maximum depth of splitting while approximating using biarcs.")				

		self.OptionParser.add_option("",   "--tool-diameter",				action="store", type="float", 		dest="tool_diameter", default="3",					help="Tool diameter used for area cutting")		
		self.OptionParser.add_option("",   "--max-area-curves",				action="store", type="int", 		dest="max_area_curves", default="100",				help="Maximum area curves for each area")
		self.OptionParser.add_option("",   "--area-inkscape-radius",		action="store", type="float", 		dest="area_inkscape_radius", default="-10",			help="Radius for preparing curves using inkscape")
		self.OptionParser.add_option("",   "--unit",						action="store", type="string", 		dest="unit", default="G21 (All units in mm)",		help="Units")
		self.OptionParser.add_option("",   "--active-tab",					action="store", type="string", 		dest="active_tab", default="",						help="Defines which tab is active")

		self.OptionParser.add_option("",   "--area-find-artefacts-diameter",action="store", type="float", 		dest="area_find_artefacts_diameter", default="1",					help="artefacts seeking radius")
		self.OptionParser.add_option("",   "--area-find-artefacts-action",	action="store", type="string",	 	dest="area_find_artefacts_action", default="mark with an arrow",	help="artefacts action type")

		self.OptionParser.add_option("",   "--auto_select_paths",			action="store", type="inkbool",		dest="auto_select_paths", default=True,				help="Select all paths if nothing is selected.")		

		self.OptionParser.add_option("",   "--loft-distances",				action="store", type="string", 		dest="loft_distances", default="10",				help="Distances between paths.")
		self.OptionParser.add_option("",   "--loft-direction",				action="store", type="string", 		dest="loft_direction", default="crosswise",			help="Direction of loft's interpolation.")
		self.OptionParser.add_option("",   "--loft-interpolation-degree",	action="store", type="float",		dest="loft_interpolation_degree", default="2",		help="Which interpolation use to loft the paths smooth interpolation or staright.")

		self.OptionParser.add_option("",   "--min-arc-radius",				action="store", type="float", 		dest="min_arc_radius", default=".1",				help="All arc having radius less than minimum will be considered as straight line")		

		self.OptionParser.add_option("",   "--engraving-sharp-angle-tollerance",action="store", type="float",	dest="engraving_sharp_angle_tollerance", default="150",		help="All angles thar are less than engraving-sharp-angle-tollerance will be thought sharp")		
		self.OptionParser.add_option("",   "--engraving-max-dist",			action="store", type="float", 		dest="engraving_max_dist", default="10",					help="Distanse from original path where engraving is not needed (usualy it's cutting tool diameter)")		
		self.OptionParser.add_option("",   "--engraving-newton-iterations", action="store", type="int", 		dest="engraving_newton_iterations", default="4",			help="Number of sample points used to calculate distance")		
		self.OptionParser.add_option("",   "--engraving-draw-calculation-paths",action="store", type="inkbool",	dest="engraving_draw_calculation_paths", default=False,		help="Draw additional graphics to debug engraving path")		
		self.OptionParser.add_option("",   "--engraving-cutter-shape-function",action="store", type="string", 	dest="engraving_cutter_shape_function", default="w",		help="Cutter shape function z(w). Ex. cone: w. ")

		self.OptionParser.add_option("",   "--lathe-width",					action="store", type="float", 		dest="lathe_width", default=10.,							help="Lathe width")
		self.OptionParser.add_option("",   "--lathe-fine-cut-width",		action="store", type="float", 		dest="lathe_fine_cut_width", default=1.,					help="Fine cut width")
		self.OptionParser.add_option("",   "--lathe-fine-cut-count",		action="store", type="int", 		dest="lathe_fine_cut_count", default=1.,					help="Fine cut count")
		self.OptionParser.add_option("",   "--lathe-create-fine-cut-using",	action="store", type="string",		dest="lathe_create_fine_cut_using", default="Move path",			help="Create fine cut using")
		self.OptionParser.add_option("",   "--lathe-x-axis-remap",			action="store", type="string", 		dest="lathe_x_axis_remap", default="X",						help="Lathe X axis remap")
		self.OptionParser.add_option("",   "--lathe-z-axis-remap",			action="store", type="string", 		dest="lathe_z_axis_remap", default="Z",						help="Lathe Z axis remap")

		self.OptionParser.add_option("",   "--create-log",					action="store", type="inkbool", 	dest="log_create_log", default=False,				help="Create log files")
		self.OptionParser.add_option("",   "--log-filename",				action="store", type="string", 		dest="log_filename", default='',					help="Create log files")

		self.OptionParser.add_option("",   "--orientation-points-count",	action="store", type="int", 		dest="orientation_points_count", default='2',			help="Orientation points count")
		self.OptionParser.add_option("",   "--tools-library-type",			action="store", type="string", 		dest="tools_library_type", default='cylinder cutter',	help="Create tools defention")

		self.OptionParser.add_option("",   "--dxfpoints-action",			action="store", type="string", 		dest="dxfpoints_action", default='replace',			help="dxfpoint sign toggle")
																										  
		self.OptionParser.add_option("",   "--help-language",				action="store", type="string", 		dest="help_language", default='http://www.cnc-club.ru/forum/viewtopic.php?f=33&t=35',	help="Open help page in webbrowser.")

		self.OptionParser.add_option("",   "--offset-radius",				action="store", type="float", 		dest="offset_radius", default=10.,		help="Offset radius")
		self.OptionParser.add_option("",   "--offset-step",					action="store", type="float", 		dest="offset_step", default=10.,		help="Offset step")
		self.OptionParser.add_option("",   "--offset-draw-clippend-path",	action="store", type="inkbool",		dest="offset_draw_clippend_path", default=False,		help="Draw clipped path")		
		self.OptionParser.add_option("",   "--offset-just-get-distance",	action="store", type="inkbool",		dest="offset_just_get_distance", default=False,		help="Don't do offset just get distance")		
	
		self.OptionParser.add_option("",   "--arrangement-material-width",	action="store", type="float",		dest="arrangement_material_width", default=500,		help="Materials width for arrangement")		
		self.OptionParser.add_option("",   "--arrangement-population-count",action="store", type="int",			dest="arrangement_population_count", default=100,	help="Genetic algorithm populations count")		

		self.OptionParser.add_option("",   "--postprocessor",				action="store", type="string", 		dest="postprocessor", default='',			help="Postprocessor command.")
		self.OptionParser.add_option("",   "--postprocessor-custom",		action="store", type="string", 		dest="postprocessor_custom", default='',	help="Postprocessor custom command.")
	
		

		self.default_tool = {
					"name": "Default tool",
					"id": "default tool",
					"diameter":10.,
					"shape": "10",
					"penetration angle":90.,
					"penetration feed":100.,
					"depth step":1.,
					"feed":400.,
					"in trajectotry":"",
					"out trajectotry":"",
					"gcode before path":"",
					"gcode after path":"",
					"sog":"",
					"spinlde rpm":"",
					"CW or CCW":"",
					"tool change gcode":" ",
					"4th axis meaning": " ",
					"4th axis scale": 1.,
					"4th axis offset": 0.,
					"passing feed":"800",					
					"fine feed":"800",					
				}			
		self.tools_field_order = [
					'name',
					'id',
					'diameter',
					'feed',
					'shape',
					'penetration angle',
					'penetration feed',
					"passing feed",
					'depth step',
					"in trajectotry",
					"out trajectotry",
					"gcode before path",
					"gcode after path",
					"sog",
					"spinlde rpm",
					"CW or CCW",
					"tool change gcode",
				]


	def parse_curve(self, p, layer, w = None, f = None):
			c = []
			if len(p)==0 : 
				return []
			p = self.transform_csp(p, layer)
			

			### Sort to reduce Rapid distance	
			k = range(1,len(p))
			keys = [0]
			while len(k)>0:
				end = p[keys[-1]][-1][1]
				dist = None
				for i in range(len(k)):
					start = p[k[i]][0][1]
					dist = max(   ( -( ( end[0]-start[0])**2+(end[1]-start[1])**2 ) ,i)	,   dist )
				keys += [k[dist[1]]]
				del k[dist[1]]
			for k in keys:
				subpath = p[k]
				c += [ [	[subpath[0][1][0],subpath[0][1][1]]   , 'move', 0, 0] ]
				for i in range(1,len(subpath)):
					sp1 = [  [subpath[i-1][j][0], subpath[i-1][j][1]] for j in range(3)]
					sp2 = [  [subpath[i  ][j][0], subpath[i  ][j][1]] for j in range(3)]
					c += biarc(sp1,sp2,0,0) if w==None else biarc(sp1,sp2,-f(w[k][i-1]),-f(w[k][i]))
#					l1 = biarc(sp1,sp2,0,0) if w==None else biarc(sp1,sp2,-f(w[k][i-1]),-f(w[k][i]))
#					print_((-f(w[k][i-1]),-f(w[k][i]), [i1[5] for i1 in l1]) )
				c += [ [ [subpath[-1][1][0],subpath[-1][1][1]]  ,'end',0,0] ]
			return c


	def draw_curve(self, curve, layer, group=None, style=styles["biarc_style"]):
	
		self.get_defs()
		# Add marker to defs if it doesnot exists
		if "DrawCurveMarker" not in self.defs : 
			defs = inkex.etree.SubElement( self.document.getroot(), inkex.addNS("defs","svg"))
			marker = inkex.etree.SubElement( defs, inkex.addNS("marker","svg"), {"id":"DrawCurveMarker","orient":"auto","refX":"-8","refY":"-2.41063","style":"overflow:visible"})
			inkex.etree.SubElement( marker, inkex.addNS("path","svg"), 
					{	"d":"m -6.55552,-2.41063 0,0 L -13.11104,0 c 1.0473,-1.42323 1.04126,-3.37047 0,-4.82126",
						"style": "fill:#000044; fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"	}
				)
		if "DrawCurveMarker_r" not in self.defs : 
			defs = inkex.etree.SubElement( self.document.getroot(), inkex.addNS("defs","svg"))
			marker = inkex.etree.SubElement( defs, inkex.addNS("marker","svg"), {"id":"DrawCurveMarker_r","orient":"auto","refX":"8","refY":"-2.41063","style":"overflow:visible"})
			inkex.etree.SubElement( marker, inkex.addNS("path","svg"), 
					{	"d":"m 6.55552,-2.41063 0,0 L 13.11104,0 c -1.0473,-1.42323 -1.04126,-3.37047 0,-4.82126",
						"style": "fill:#000044; fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"	}
				)
		for i in [0,1]:
			style['biarc%s_r'%i] = simplestyle.parseStyle(style['biarc%s'%i])
			style['biarc%s_r'%i]["marker-start"] = "url(#DrawCurveMarker_r)"
			del(style['biarc%s_r'%i]["marker-end"])
			style['biarc%s_r'%i] = simplestyle.formatStyle(style['biarc%s_r'%i])
		
		if group==None:
			group = inkex.etree.SubElement( self.layers[min(1,len(self.layers)-1)], inkex.addNS('g','svg'), {"gcodetools": "Preview group"} )
		s, arcn = '', 0
		
		
		a,b,c = [0.,0.], [1.,0.], [0.,1.]
		k = (b[0]-a[0])*(c[1]-a[1])-(c[0]-a[0])*(b[1]-a[1])
		a,b,c = self.transform(a, layer, True), self.transform(b, layer, True), self.transform(c, layer, True)
		if ((b[0]-a[0])*(c[1]-a[1])-(c[0]-a[0])*(b[1]-a[1]))*k > 0 : reverse_angle = 1
		else : reverse_angle = -1 
		for sk in curve:
			si = sk[:]
			si[0], si[2] = self.transform(si[0], layer, True), (self.transform(si[2], layer, True) if type(si[2])==type([]) and len(si[2])==2 else si[2])
			
			if s!='':
				if s[1] == 'line':
					inkex.etree.SubElement(	group, inkex.addNS('path','svg'), 
							{
								'style': style['line'],
								'd':'M %s,%s L %s,%s' % (s[0][0], s[0][1], si[0][0], si[0][1]),
								"gcodetools": "Preview",
							}
						)
				elif s[1] == 'arc':
					arcn += 1
					sp = s[0]
					c = s[2]
					s[3] = s[3]*reverse_angle
						
					a =  ( (P(si[0])-P(c)).angle() - (P(s[0])-P(c)).angle() )%math.pi2 #s[3]
					if s[3]*a<0: 
							if a>0:	a = a-math.pi2
							else: a = math.pi2+a
					r = math.sqrt( (sp[0]-c[0])**2 + (sp[1]-c[1])**2 )
					a_st = ( math.atan2(sp[0]-c[0],- (sp[1]-c[1])) - math.pi/2 ) % (math.pi*2)
					st = style['biarc%s' % (arcn%2)][:]
					if a>0:
						a_end = a_st+a
						st = style['biarc%s'%(arcn%2)]
					else: 
						a_end = a_st*1
						a_st = a_st+a
						st = style['biarc%s_r'%(arcn%2)]
					inkex.etree.SubElement(	group, inkex.addNS('path','svg'), 
						 {
							'style': st,
							 inkex.addNS('cx','sodipodi'):		str(c[0]),
							 inkex.addNS('cy','sodipodi'):		str(c[1]),
							 inkex.addNS('rx','sodipodi'):		str(r),
							 inkex.addNS('ry','sodipodi'):		str(r),
							 inkex.addNS('start','sodipodi'):	str(a_st),
							 inkex.addNS('end','sodipodi'):		str(a_end),
							 inkex.addNS('open','sodipodi'):	'true',
							 inkex.addNS('type','sodipodi'):	'arc',
							"gcodetools": "Preview",
						})
			s = si
	

	def check_dir(self):
		if self.options.directory[-1] not in ["/","\\"]:
			if "\\" in self.options.directory :
				self.options.directory += "\\"
			else :
				self.options.directory += "/"
		print_("Checking direcrory: '%s'"%self.options.directory)
		if (os.path.isdir(self.options.directory)):
			if (os.path.isfile(self.options.directory+'header')):
				f = open(self.options.directory+'header', 'r')
				self.header = f.read()
				f.close()
			else:
				self.header = defaults['header']
			if (os.path.isfile(self.options.directory+'footer')):
				f = open(self.options.directory+'footer','r')
				self.footer = f.read()
				f.close()
			else:
				self.footer = defaults['footer']
			self.header += self.options.unit + "\n" 
		else: 
			self.error(_("Directory does not exist! Please specify existing directory at Preferences tab!"),"error")
			return False

		if self.options.add_numeric_suffix_to_filename :
			dir_list = os.listdir(self.options.directory)
			if "." in self.options.file : 
				r = re.match(r"^(.*)(\..*)$",self.options.file)
				ext = r.group(2)
				name = r.group(1)
			else: 	
				ext = ""
				name = self.options.file
			max_n = 0
			for s in dir_list :
				r = re.match(r"^%s_0*(\d+)%s$"%(re.escape(name),re.escape(ext) ), s)
				if r :
					max_n = max(max_n,int(r.group(1)))
			filename = name + "_" + ( "0"*(4-len(str(max_n+1))) + str(max_n+1) ) + ext
			self.options.file = filename
		
		print_("Testing writing rights on '%s'"%(self.options.directory+self.options.file))
		try: 	
			f = open(self.options.directory+self.options.file, "w")	
			f.close()							
		except:
			self.error(_("Can not write to specified file!\n%s"%(self.options.directory+self.options.file)),"error")
			return False
		return True
			


################################################################################
###
###		Generate Gcode
###		Generates Gcode on given curve.
###
###		Crve defenitnion [start point, type = {'arc','line','move','end'}, arc center, arc angle, end point, [zstart, zend]]		
###
################################################################################
	def generate_gcode(self, curve, layer, depth):
		Zauto_scale = self.Zauto_scale[layer]
		tool = self.tools[layer][0]

		def c(c):
			c = [c[i] if i<len(c) else None for i in range(6)]
			if c[5] == 0 : c[5]=None
			s,s1 = [" X", " Y", " Z", " I", " J", " K"], ["","","","","",""]
			m,a = [1,1,self.options.Zscale*Zauto_scale,1,1,self.options.Zscale*Zauto_scale], [0,0,self.options.Zoffset,0,0,0]
			r = ''	
			for i in range(6):
				if c[i]!=None:
					r += s[i] + ("%f" % (c[i]*m[i]+a[i])) + s1[i]
			return r

		def calculate_angle(a, current_a):
			return  min(					
						[abs(a-current_a%math.pi2+math.pi2), a+current_a-current_a%math.pi2+math.pi2],
						[abs(a-current_a%math.pi2-math.pi2), a+current_a-current_a%math.pi2-math.pi2],
						[abs(a-current_a%math.pi2),			 a+current_a-current_a%math.pi2])[1]
		if len(curve)==0 : return ""	
				
		try :
			self.last_used_tool == None
		except :
			self.last_used_tool = None
		print_("working on curve")
		print_(curve)
		g = tool['tool change gcode'] +"\n" if tool != self.last_used_tool else "\n"
		
		lg, zs, f =  'G00', self.options.Zsafe, " F%f"%tool['feed'] 
		current_a = 0
		go_to_safe_distance = "G00" + c([None,None,zs]) + "\n" 
		penetration_feed = " F%s"%tool['penetration feed'] 
		for i in range(1,len(curve)):
		#	Creating Gcode for curve between s=curve[i-1] and si=curve[i] start at s[0] end at s[4]=si[0]
			s, si = curve[i-1], curve[i]
			feed = f if lg not in ['G01','G02','G03'] else ''
			if s[1]	== 'move':
				g += go_to_safe_distance + "G00" + c(si[0]) + "\n" + tool['gcode before path'] + "\n"
				lg = 'G00'
			elif s[1] == 'end':
				g += go_to_safe_distance + tool['gcode after path'] + "\n"
				lg = 'G00'
			elif s[1] == 'line':
				if tool['4th axis meaning'] == "tangent knife" : 
					a = atan2(si[0][0]-s[0][0],si[0][1]-s[0][1])
					a = calculate_angle(a, current_a)
					g+="G01 A%s\n" % (a*tool['4th axis scale']+tool['4th axis offset'])
					current_a = a
				if lg=="G00": g += "G01" + c([None,None,s[5][0]+depth]) + penetration_feed +"\n"	
				g += "G01" +c(si[0]+[s[5][1]+depth]) + feed + "\n"
				lg = 'G01'
			elif s[1] == 'arc':
				r = [(s[2][0]-s[0][0]), (s[2][1]-s[0][1])]
				if tool['4th axis meaning'] == "tangent knife" : 
					if s[3]<0 : # CW
						a1 = atan2(s[2][1]-s[0][1],-s[2][0]+s[0][0]) + math.pi 
					else: #CCW
						a1 = atan2(-s[2][1]+s[0][1],s[2][0]-s[0][0]) + math.pi
					a = calculate_angle(a1, current_a)
					g+="G01 A%s\n" % (a*tool['4th axis scale']+tool['4th axis offset'])
					current_a = a
					axis4 = " A%s"%((current_a+s[3])*tool['4th axis scale']+tool['4th axis offset'])
					current_a = current_a+s[3]
				else : axis4 = ""
				if lg=="G00": g += "G01" + c([None,None,s[5][0]+depth]) + penetration_feed + "\n"				
				if (r[0]**2 + r[1]**2)>self.options.min_arc_radius:
					r1, r2 = (P(s[0])-P(s[2])), (P(si[0])-P(s[2]))
					if abs(r1.mag()-r2.mag()) < 0.001 :
						g += ("G02" if s[3]<0 else "G03") + c(si[0]+[ s[5][1]+depth, (s[2][0]-s[0][0]),(s[2][1]-s[0][1])  ]) + feed + axis4 + "\n"
					else:
						r = (r1.mag()+r2.mag())/2
						g += ("G02" if s[3]<0 else "G03") + c(si[0]+[s[5][1]+depth]) + " R%f" % (r) + feed  + axis4 + "\n"
					lg = 'G02'
				else:
					if tool['4th axis meaning'] == "tangent knife" : 
						a = atan2(si[0][0]-s[0][0],si[0][1]-s[0][1]) + math.pi
						a = calculate_angle(a, current_a)
						g+="G01 A%s\n" % (a*tool['4th axis scale']+tool['4th axis offset'])
						current_a = a
					g += "G01" +c(si[0]+[s[5][1]+depth]) + feed + "\n"
					lg = 'G01'
		if si[1] == 'end':
			g += go_to_safe_distance + tool['gcode after path'] + "\n"
		return g


	def get_transforms(self,g):
		root = self.document.getroot()
		trans = []
		while (g!=root):
			if 'transform' in g.keys():
				t = g.get('transform')
				t = simpletransform.parseTransform(t)
				trans = simpletransform.composeTransform(t,trans) if trans != [] else t
				print_(trans)
			g=g.getparent()
		return trans 
		

	def apply_transforms(self,g,csp):
		trans = self.get_transforms(g)
		if trans != []:
			simpletransform.applyTransformToPath(trans, csp)
		return csp


	def transform(self,source_point, layer, reverse=False):
		if layer not in self.transform_matrix:
			for i in range(self.layers.index(layer),-1,-1):
				if self.layers[i] in self.orientation_points : 
					break
			if self.layers[i] not in self.orientation_points :
				self.error(_("Orientation points for '%s' layer have not been found! Please add orientation points using Orientation tab!") % layer.get(inkex.addNS('label','inkscape')),"no_orientation_points")
			elif self.layers[i] in self.transform_matrix :
				self.transform_matrix[layer] = self.transform_matrix[self.layers[i]]
			else :
				orientation_layer = self.layers[i]
				if len(self.orientation_points[orientation_layer])>1 : 
					self.error(_("There are more than one orientation point groups in '%s' layer") % orientation_layer.get(inkex.addNS('label','inkscape')),"more_than_one_orientation_point_groups")
				points = self.orientation_points[orientation_layer][0]
				if len(points)==2:
					points += [ [ [(points[1][0][1]-points[0][0][1])+points[0][0][0], -(points[1][0][0]-points[0][0][0])+points[0][0][1]], [-(points[1][1][1]-points[0][1][1])+points[0][1][0], points[1][1][0]-points[0][1][0]+points[0][1][1]] ] ]
				if len(points)==3:
					print_("Layer '%s' Orientation points: " % orientation_layer.get(inkex.addNS('label','inkscape')))
					for point in points:
						print_(point)
					#	Zcoordinates definition taken from Orientatnion point 1 and 2 
					self.Zcoordinates[layer] = [max(points[0][1][2],points[1][1][2]), min(points[0][1][2],points[1][1][2])]
					matrix = numpy.array([
								[points[0][0][0], points[0][0][1], 1, 0, 0, 0, 0, 0, 0],
								[0, 0, 0, points[0][0][0], points[0][0][1], 1, 0, 0, 0],
								[0, 0, 0, 0, 0, 0, points[0][0][0], points[0][0][1], 1],
								[points[1][0][0], points[1][0][1], 1, 0, 0, 0, 0, 0, 0],
								[0, 0, 0, points[1][0][0], points[1][0][1], 1, 0, 0, 0],
								[0, 0, 0, 0, 0, 0, points[1][0][0], points[1][0][1], 1],
								[points[2][0][0], points[2][0][1], 1, 0, 0, 0, 0, 0, 0],
								[0, 0, 0, points[2][0][0], points[2][0][1], 1, 0, 0, 0],
								[0, 0, 0, 0, 0, 0, points[2][0][0], points[2][0][1], 1]
							])
								
					if numpy.linalg.det(matrix)!=0 :
						m = numpy.linalg.solve(matrix,
							numpy.array(
								[[points[0][1][0]], [points[0][1][1]], [1], [points[1][1][0]], [points[1][1][1]], [1], [points[2][1][0]], [points[2][1][1]], [1]]	
										)
							).tolist()
						self.transform_matrix[layer] = [[m[j*3+i][0] for i in range(3)] for j in range(3)]
					
					else :
						self.error(_("Orientation points are wrong! (if there are two orientation points they sould not be the same. If there are three orientation points they should not be in a straight line.)"),"wrong_orientation_points")
				else :
					self.error(_("Orientation points are wrong! (if there are two orientation points they sould not be the same. If there are three orientation points they should not be in a straight line.)"),"wrong_orientation_points")

			self.transform_matrix_reverse[layer] = numpy.linalg.inv(self.transform_matrix[layer]).tolist()		
			print_("\n Layer '%s' transformation matrixes:" % layer.get(inkex.addNS('label','inkscape')) )
			print_(self.transform_matrix)
			print_(self.transform_matrix_reverse)

			###self.Zauto_scale[layer]  = math.sqrt( (self.transform_matrix[layer][0][0]**2 + self.transform_matrix[layer][1][1]**2)/2 )
			### Zautoscale is absolete
			self.Zauto_scale[layer] = 1
			print_("Z automatic scale = %s (computed according orientation points)" % self.Zauto_scale[layer])

		x,y = source_point[0], source_point[1]
		if not reverse :
			t = self.transform_matrix[layer]
		else :
			t = self.transform_matrix_reverse[layer]
		return [t[0][0]*x+t[0][1]*y+t[0][2], t[1][0]*x+t[1][1]*y+t[1][2]]


	def transform_csp(self, csp_, layer, reverse = False):
		csp = [  [ [csp_[i][j][0][:],csp_[i][j][1][:],csp_[i][j][2][:]]  for j in range(len(csp_[i])) ]   for i in range(len(csp_)) ]
		for i in xrange(len(csp)):
			for j in xrange(len(csp[i])): 
				for k in xrange(len(csp[i][j])): 
					csp[i][j][k] = self.transform(csp[i][j][k],layer, reverse)
		return csp
	
		
################################################################################
###		Errors handling function, notes are just printed into Logfile, 
###		warnings are printed into log file and warning message is displayed but
###		extension continues working, errors causes log and execution is halted
###		Notes, warnings adn errors could be assigned to space or comma or dot 
###		sepparated strings (case is ignoreg).
################################################################################
	def error(self, s, type_= "Warning"):
		notes = "Note "
		warnings = """
						Warning tools_warning
						bad_orientation_points_in_some_layers
						more_than_one_orientation_point_groups
						more_than_one_tool
						orientation_have_not_been_defined
						tool_have_not_been_defined
						selection_does_not_contain_paths
						selection_does_not_contain_paths_will_take_all
						selection_is_empty_will_comupe_drawing
						selection_contains_objects_that_are_not_paths
						"""
		errors = """
						Error 	
						wrong_orientation_points	
						area_tools_diameter_error
						no_tool_error
						active_layer_already_has_tool
						active_layer_already_has_orientation_points
					"""
		if type_.lower() in re.split("[\s\n,\.]+", errors.lower()) :
			print_(s)
			inkex.errormsg(s+"\n")		
			sys.exit()
		elif type_.lower() in re.split("[\s\n,\.]+", warnings.lower()) :
			print_(s)
			inkex.errormsg(s+"\n")		
		elif type_.lower() in re.split("[\s\n,\.]+", notes.lower()) :
			print_(s)
		else :
			print_(s)
			inkex.errormsg(s)		
			sys.exit()
	
	
################################################################################
###		Get defs from svg
################################################################################
	def get_defs(self) :
		self.defs = {}
		def recursive(g) :
			for i in g:
				if i.tag == inkex.addNS("defs","svg") : 
					for j in i: 
						self.defs[j.get("id")] = i
				if i.tag ==inkex.addNS("g",'svg') :
					recursive(i)
		recursive(self.document.getroot())


################################################################################
###
###		Get Gcodetools info from the svg
###
################################################################################
	def get_info(self):
		self.selected_paths = {}
		self.paths = {}		
		self.tools = {}
		self.orientation_points = {}
		self.layers = [self.document.getroot()]
		self.Zcoordinates = {}
		self.transform_matrix = {}
		self.transform_matrix_reverse = {}
		self.Zauto_scale = {}
		
		def recursive_search(g, layer, selected=False):
			items = g.getchildren()
			items.reverse()
			for i in items:
				if selected:
					self.selected[i.get("id")] = i
				if i.tag == inkex.addNS("g",'svg') and i.get(inkex.addNS('groupmode','inkscape')) == 'layer':
					self.layers += [i]
					recursive_search(i,i)
				elif i.get('gcodetools') == "Gcodetools orientation group" :
					points = self.get_orientation_points(i)
					if points != None :
						self.orientation_points[layer] = self.orientation_points[layer]+[points[:]] if layer in self.orientation_points else [points[:]]
						print_("Found orientation points in '%s' layer: %s" % (layer.get(inkex.addNS('label','inkscape')), points))
					else :
						self.error(_("Warning! Found bad orientation points in '%s' layer. Resulting Gcode could be corrupt!") % layer.get(inkex.addNS('label','inkscape')), "bad_orientation_points_in_some_layers") 
				elif i.get("gcodetools") == "Gcodetools tool defenition" :
					tool = self.get_tool(i)
					self.tools[layer] = self.tools[layer] + [tool.copy()] if layer in self.tools else [tool.copy()]
					print_("Found tool in '%s' layer: %s" % (layer.get(inkex.addNS('label','inkscape')), tool))
				elif i.tag == inkex.addNS('path','svg'):
					if "gcodetools"  not in i.keys() :
						self.paths[layer] = self.paths[layer] + [i] if layer in self.paths else [i]  
						if i.get("id") in self.selected :
							self.selected_paths[layer] = self.selected_paths[layer] + [i] if layer in self.selected_paths else [i]  
				elif i.tag == inkex.addNS("g",'svg'):
					recursive_search(i,layer, (i.get("id") in self.selected) )
				elif i.get("id") in self.selected :
					self.error(_("This extension works with Paths and Dynamic Offsets and groups of them only! All other objects will be ignored!\nSolution 1: press Path->Object to path or Shift+Ctrl+C.\nSolution 2: Path->Dynamic offset or Ctrl+J.\nSolution 3: export all contours to PostScript level 2 (File->Save As->.ps) and File->Import this file."),"selection_contains_objects_that_are_not_paths")
				
					
		recursive_search(self.document.getroot(),self.document.getroot())


	def get_orientation_points(self,g):
		items = g.getchildren()
		items.reverse()
		p2, p3 = [], []
		p = None
		for i in items:
			if i.tag == inkex.addNS("g",'svg') and i.get("gcodetools") == "Gcodetools orientation point (2 points)":
				p2 += [i]
			if i.tag == inkex.addNS("g",'svg') and i.get("gcodetools") == "Gcodetools orientation point (3 points)":
				p3 += [i]
		if len(p2)==2 : p=p2 
		elif len(p3)==3 : p=p3 
		if p==None : return None
		points = []
		for i in p :	
			point = [[],[]]	
			for  node in i :
				if node.get('gcodetools') == "Gcodetools orientation point arrow":
					point[0] = self.apply_transforms(node,cubicsuperpath.parsePath(node.get("d")))[0][0][1]
				if node.get('gcodetools') == "Gcodetools orientation point text":
					r = re.match(r'(?i)\s*\(\s*(-?\s*\d*(?:,|\.)*\d*)\s*;\s*(-?\s*\d*(?:,|\.)*\d*)\s*;\s*(-?\s*\d*(?:,|\.)*\d*)\s*\)\s*',node.text)
					point[1] = [float(r.group(1)),float(r.group(2)),float(r.group(3))]
			if point[0]!=[] and point[1]!=[]:	points += [point]
		if len(points)==len(p2)==2 or len(points)==len(p3)==3 : return points
		else : return None


	def get_tool(self, g):
		tool = self.default_tool.copy()
		tool["self_group"] = g 
		for i in g:
			#	Get parameters
			if i.get("gcodetools") == "Gcodetools tool background" : 
				tool["style"] = simplestyle.parseStyle(i.get("style"))
			elif i.get("gcodetools") == "Gcodetools tool parameter" :
				key = None
				value = None
				for j in i:
					if j.get("gcodetools") == "Gcodetools tool defention field name":
						key = j.text
					if j.get("gcodetools") == "Gcodetools tool defention field value":
						for k in j :
							if k.tag == inkex.addNS('tspan','svg') and k.get("gcodetools") == "Gcodetools tool defention field value":
								if k.text!=None : value = value +"\n" + k.text if value != None else k.text
				if value == None or key == None: continue
				#print_("Found tool parameter '%s':'%s'" % (key,value))
				if key in self.default_tool.keys() :
					 try :
						tool[key] = type(self.default_tool[key])(value)
					 except :
						tool[key] = self.default_tool[key]
						self.error(_("Warning! Tool's and default tool's parameter's (%s) types are not the same ( type('%s') != type('%s') ).") % (key, value, self.default_tool[key]), "tools_warning")
				else :
					tool[key] = value
					self.error(_("Warning! Tool has parameter that default tool has not ( '%s': '%s' ).") % (key, value), "tools_warning" )
		return tool
		
		
	def set_tool(self,layer):
#		print_(("index(layer)=",self.layers.index(layer),"set_tool():layer=",layer,"self.tools=",self.tools))
#		for l in self.layers:
#			print_(("l=",l))
		for i in range(self.layers.index(layer),-1,-1):
#			print_(("processing layer",i))
			if self.layers[i] in self.tools : 
				break
		if self.layers[i] in self.tools :
			if self.layers[i] != layer : self.tools[layer] = self.tools[self.layers[i]]
			if len(self.tools[layer])>1 : self.error(_("Layer '%s' contains more than one tool!") % self.layers[i].get(inkex.addNS('label','inkscape')), "more_than_one_tool")
			return self.tools[layer]
		else :
			self.error(_("Can not find tool for '%s' layer! Please add one with Tools library tab!") % layer.get(inkex.addNS('label','inkscape')), "no_tool_error")


################################################################################
###
###		Path to Gcode
###
################################################################################
	def path_to_gcode(self) :

		def get_boundaries(points):
			minx,miny,maxx,maxy=None,None,None,None
			out=[[],[],[],[]]
			for p in points:
				if minx==p[0]:
					out[0]+=[p]
				if minx==None or p[0]<minx: 
					minx=p[0]
					out[0]=[p]

				if miny==p[1]:
					out[1]+=[p]
				if miny==None or p[1]<miny: 
					miny=p[1]
					out[1]=[p]

				if maxx==p[0]:
					out[2]+=[p]
				if maxx==None or p[0]>maxx: 
					maxx=p[0]
					out[2]=[p]

				if maxy==p[1]:
					out[3]+=[p]
				if maxy==None or p[1]>maxy: 
					maxy=p[1]
					out[3]=[p]
			return out


		def remove_duplicates(points):
			i=0		
			out=[]
			for p in points:
				for j in xrange(i,len(points)):
					if p==points[j]: points[j]=[None,None]	
				if p!=[None,None]: out+=[p]
			i+=1
			return(out)
	
	
		def get_way_len(points):
			l=0
			for i in xrange(1,len(points)):
				l+=math.sqrt((points[i][0]-points[i-1][0])**2 + (points[i][1]-points[i-1][1])**2)
			return l

	
		def sort_dxfpoints(points):
			points=remove_duplicates(points)
#			print_(get_boundaries(get_boundaries(points)[2])[1])
			ways=[
						  # l=0, d=1, r=2, u=3
			 [3,0], # ul
			 [3,2], # ur
			 [1,0], # dl
			 [1,2], # dr
			 [0,3], # lu
			 [0,1], # ld
			 [2,3], # ru
			 [2,1], # rd
			]
#			print_(("points=",points))
			minimal_way=[]
			minimal_len=None
			minimal_way_type=None
			for w in ways:
				tpoints=points[:]
				cw=[]
#				print_(("tpoints=",tpoints))
				for j in xrange(0,len(points)):
					p=get_boundaries(get_boundaries(tpoints)[w[0]])[w[1]]
#					print_(p)
					tpoints.remove(p[0])
					cw+=p
				curlen = get_way_len(cw)
				if minimal_len==None or curlen < minimal_len: 
					minimal_len=curlen
					minimal_way=cw
					minimal_way_type=w
			
			return minimal_way

		
		def print_dxfpoints(points):
			gcode=""
			for point in points:
				gcode +="(drilling dxfpoint)\nG00 Z%f\nG00 X%f Y%f\nG01 Z%f F%f\nG04 P%f\nG00 Z%f\n" % (self.options.Zsafe,point[0],point[1],self.Zcoordinates[layer][1],self.tools[layer][0]["penetration feed"],0.2,self.options.Zsafe) 
#			print_(("got dxfpoints array=",points))
			return gcode
			
		if self.selected_paths == {} and self.options.auto_select_paths:
			paths=self.paths
			self.error(_("No paths are selected! Trying to work on all available paths."),"warning")
		else :
			paths = self.selected_paths
		self.check_dir() 
		gcode = ""

		biarc_group = inkex.etree.SubElement( self.selected_paths.keys()[0] if len(self.selected_paths.keys())>0 else self.layers[0], inkex.addNS('g','svg') )
		print_(("self.layers=",self.layers))
		print_(("paths=",paths))
		for layer in self.layers :
#			print_(("processing layer",layer," of layers:",self.layers))
			if layer in paths :
#				print_(("layer ",layer, " is in paths:",paths))
				print_(("layer",layer))
				self.set_tool(layer)
				p = []	
				dxfpoints = []
				for path in paths[layer] :
					if "d" not in path.keys() : 
						self.error(_("Warning: One or more paths dont have 'd' parameter, try to Ungroup (Ctrl+Shift+G) and Object to Path (Ctrl+Shift+C)!"),"selection_contains_objects_that_are_not_paths")
						continue					
					csp = cubicsuperpath.parsePath(path.get("d"))
					csp = self.apply_transforms(path, csp)
					if path.get("dxfpoint") == "1":
						tmp_curve=self.transform_csp(csp, layer)
						x=tmp_curve[0][0][0][0]
						y=tmp_curve[0][0][0][1]
						print_("got dxfpoint (scaled) at (%f,%f)" % (x,y))
						dxfpoints += [[x,y]]
					else:
						p += csp
				dxfpoints=sort_dxfpoints(dxfpoints)
				gcode+=print_dxfpoints(dxfpoints)
				curve = self.parse_curve(p, layer)
				self.draw_curve(curve, layer, biarc_group)
				if self.tools[layer][0]["depth step"] == 0 : self.tools[layer][0]["depth step"] = 1
				for step in range( 0,  int(math.ceil( abs( (self.Zcoordinates[layer][1]-self.Zcoordinates[layer][0])/self.tools[layer][0]["depth step"] )) ) ):
					Zpos = max(		self.Zcoordinates[layer][1],		 self.Zcoordinates[layer][0] - abs(self.tools[layer][0]["depth step"]*(step+1))	)
					gcode += self.generate_gcode(curve, layer, Zpos)
			
		self.export_gcode(gcode)
	
################################################################################
###
###		dxfpoints
###
################################################################################
	def dxfpoints(self):
		if self.selected_paths == {}:
			self.error(_("Noting is selected. Please select something to convert to drill point (dxfpoint) or clear point sign."),"warning")
		for layer in self.layers :
			if layer in self.selected_paths :
				for path in self.selected_paths[layer]:
#					print_(("processing path",path.get('d')))
					if self.options.dxfpoints_action == 'replace':
#						print_("trying to set as dxfpoint")
						
						path.set("dxfpoint","1")
						r = re.match("^\s*.\s*(\S+)",path.get("d"))
						if r!=None:
							print_(("got path=",r.group(1)))
							path.set("d","m %s 2.9375,-6.343750000001 0.8125,1.90625 6.843748640396,-6.84374864039 0,0 0.6875,0.6875 -6.84375,6.84375 1.90625,0.812500000001 z" % r.group(1))
							path.set("style",styles["dxf_points"])

					if self.options.dxfpoints_action == 'save':
						path.set("dxfpoint","1")

					if self.options.dxfpoints_action == 'clear' and path.get("dxfpoint") == "1":
						path.set("dxfpoint","0")
#						for id, node in self.selected.iteritems():
#							print_((id,node,node.attrib))


################################################################################
###
###		Artefacts
###
################################################################################
	def area_artefacts(self) :
			if self.selected_paths == {} and self.options.auto_select_paths:
				paths=self.paths
				self.error(_("No paths are selected! Trying to work on all available paths."),"warning")
			else :
				paths = self.selected_paths
			for layer in paths :
#				paths[layer].reverse() # Reverse list of paths to leave their order 
				for path in paths[layer] :
					parent = path.getparent()
					style = path.get("style") if "style" in path.keys() else ""
					if "d" not in path.keys() : 
						self.error(_("Warning: One or more paths dont have 'd' parameter, try to Ungroup (Ctrl+Shift+G) and Object to Path (Ctrl+Shift+C)!"),"selection_contains_objects_that_are_not_paths")
						continue		
					csp = cubicsuperpath.parsePath(path.get("d"))
					csp = self.apply_transforms(path, csp)
					for subpath in csp :
						bounds = csp_simple_bound([subpath])
						if  (bounds[2]-bounds[0])**2+(bounds[3]-bounds[1])**2 < self.options.area_find_artefacts_diameter**2:
							if self.options.area_find_artefacts_action == "mark with an arrow" :
								inkex.etree.SubElement(parent, inkex.addNS('path','svg'), 
										{
											'd': 'm %s,%s 2.9375,-6.343750000001 0.8125,1.90625 6.843748640396,-6.84374864039 0,0 0.6875,0.6875 -6.84375,6.84375 1.90625,0.812500000001 z' % (subpath[0][1][0],subpath[0][1][1]),
											'style': styles["area artefact arrow"],
											'gcodetools': 'area artefact arrow',
										})
								inkex.etree.SubElement(parent, inkex.addNS('path','svg'), {'d': cubicsuperpath.formatPath([subpath]), 'style': style, "gcodetools_parameter":"area artefact"})		
							elif self.options.area_find_artefacts_action == "mark with style" :
								inkex.etree.SubElement(parent, inkex.addNS('path','svg'), {'d': cubicsuperpath.formatPath([subpath]), 'style': styles["area artefact"]})
							elif self.options.area_find_artefacts_action == "delete" :
								print_("Deleted artifact %s" % subpath )
						else :
							inkex.etree.SubElement(parent, inkex.addNS('path','svg'), {'d': cubicsuperpath.formatPath([subpath]), 'style': style})
					parent.remove(path)
			return
			

################################################################################
###
###		Calculate area curves
###
################################################################################
	def area(self) :
		if len(self.selected_paths)<=0:
			self.error(_("This extension requires at least one selected path."),"warning")
			return
		for layer in self.layers :
			if layer in self.selected_paths :
				self.set_tool(layer)
				if self.tools[layer][0]['diameter']<=0 : 
					self.error(_("Tool diameter must be > 0 but tool's diameter on '%s' layer is not!") % layer.get(inkex.addNS('label','inkscape')),"area_tools_diameter_error")
	
				for path in self.selected_paths[layer]:
					print_(("doing path",	path.get("style"), path.get("d")))

					area_group = inkex.etree.SubElement( path.getparent(), inkex.addNS('g','svg') )
				
					d = path.get('d')
					print_(d)
					if d==None:
						print_("omitting non-path")
						self.error(_("Warning: omitting non-path"),"selection_contains_objects_that_are_not_paths")
						continue
					csp = cubicsuperpath.parsePath(d)
				
					if path.get(inkex.addNS('type','sodipodi'))!="inkscape:offset":
						print_("Path %s is not an offset. Preparation started." % path.get("id"))
						# Path is not offset. Preparation will be needed.
						# Finding top most point in path (min y value)
						
						min_x,min_y,min_i,min_j,min_t = csp_true_bounds(csp)[1]
						
						# Reverse path if needed.
						if min_y!=float("-inf") :
							# Move outline subpath to the begining of csp
	 					 	subp = csp[min_i]
	 					 	del csp[min_i]
	 					 	j = min_j
	 					 	# Split by the topmost point and join again
	 					 	if min_t in [0,1]:
	 					 		if min_t == 0: j=j-1
		 					 	subp[-1][2], subp[0][0] = subp[-1][1], subp[0][1]
	 					 		subp = [ [subp[j][1], subp[j][1], subp[j][2]] ] + subp[j+1:] + subp[:j] + [ [subp[j][0], subp[j][1], subp[j][1]] ]
							else: 					 		
		 						sp1,sp2,sp3 = csp_split(subp[j-1],subp[j],min_t)
		 						subp[-1][2], subp[0][0] = subp[-1][1], subp[0][1]
								subp = [ [ sp2[1], sp2[1],sp2[2] ] ] + [sp3] + subp[j+1:] + subp[:j-1] + [sp1] + [[ sp2[0], sp2[1],sp2[1] ]] 					 	  
	 					 	csp = [subp] + csp
							# reverse path if needed
							if csp_subpath_ccw(csp[0]) :
								for i in range(len(csp)):
								 	n = []
								 	for j in csp[i]:
								 		n = [  [j[2][:],j[1][:],j[0][:]]  ] + n
								 	csp[i] = n[:]

	 					 	
						d = cubicsuperpath.formatPath(csp)
						print_(("original  d=",d))
						d = re.sub(r'(?i)(m[^mz]+)',r'\1 Z ',d)
						d = re.sub(r'(?i)\s*z\s*z\s*',r' Z ',d)
						d = re.sub(r'(?i)\s*([A-Za-z])\s*',r' \1 ',d)
						print_(("formatted d=",d))
					# scale = sqrt(Xscale**2 + Yscale**2) / sqrt(1**2 + 1**2)
					p0 = self.transform([0,0],layer)
					p1 = self.transform([0,1],layer)
					scale = (P(p0)-P(p1)).mag()
					if scale == 0 : scale = 1. 
					else : scale = 1./scale
					print_(scale)
					tool_d = self.tools[layer][0]['diameter']*scale
					r = self.options.area_inkscape_radius * scale
					sign=1 if r>0 else -1
					print_("Tool diameter = %s, r = %s" % (tool_d, r))

					for i in range(self.options.max_area_curves):
						radius = - tool_d * (i+0.5) * sign
						if abs(radius)>abs(r): 
							radius = -r
						
						inkex.etree.SubElement(	area_group, inkex.addNS('path','svg'), 
										{
											 inkex.addNS('type','sodipodi'):	'inkscape:offset',
											 inkex.addNS('radius','inkscape'):	str(radius),
											 inkex.addNS('original','inkscape'):	d,
											'style': styles["biarc_style_i"]['area']
										})
						print_(("adding curve",area_group,d,styles["biarc_style_i"]['area']))
						if radius == -r : break 


################################################################################
###
###		Engraving
###
################################################################################
	r,w = 0,0
	x1,y1,nx,ny =0,0,0,0
	def engraving(self) :
		global x1,y1,rx,ry,r,w
		global LTcspOut, LTw
		#LT See if we can use this parameter for line and Bezier subdivision
		bitlen=50/self.options.engraving_newton_iterations

		if len(self.selected_paths)<=0:
			self.error(_("This extension requires at least one selected path."),"warning")
			return
		if not self.check_dir() : return
		gcode = ''


		#LT removed def find_cutter_center((x1,y1),(nx1,ny1), sp1,sp2, tool, t3 = .5):

		def get_radius_to_line((x1,y1),(nx1,ny1), (x2,y2),(nx2,ny2), (x3,y3)):
			"""LT find biggest circle we can engrave here, constrained by line 2-3

			This function can be used in three ways:
			- With nx1=ny1=0 it finds circle centred at x1,y1
			- with nx1,ny1 normalised, it finds circle tangential at x1,y1
			- with nx1,ny1 scaled by 1/cos(a) it finds circle centred on an angle bisector
				 where a is the angle between the bisector and the previous/next normals

			If the circle tangential to the line 2-3 touches it outside the
			limits x2,y2 to x3,y3 we find the biggest circle at the nearer point

			# Note that I wrote this to replace find_cutter_centre. It is less
			# sophisticated in that it doesn't use the full cubic form of Beziers
			# but, I hope, far faster.
			# Note that it handles corners in the conventional manner of letter cutting
			# by mitering, not rounding.
			# Algorithm uses dot products of normals to find radius
			# and hence coordinates of centre
			"""
			#Start by converting coordinates to be relative to x1,y1
			#print_("getRadius",x1,y1,nx1,ny1,x2,y2,nx2,ny2,x3,y3)
			x2,y2= x2-x1, y2-y1
			x3,y3= x3-x1, y3-y1

			#Then make sure the line in question is facing x1,y1
			if x2*nx2+y2*ny2>0 : return self.options.engraving_max_dist
			denom=nx2*nx1+ny2*ny1-1.0
			if denom > -0.0001 : return self.options.engraving_max_dist #no convergence

			#radius and centre are:
			r=(nx2*x2+ny2*y2)/denom
			bx=r*(nx1-nx2)
			by=r*(ny1-ny2)
			#if b is between points 1 and 2 we are on the line, so exit
			if (x2*by-y2*bx)*(x3*by-y3*bx)<0 : return r
			# otherwise find smaller circle touching an end point
			r2=get_radius_to_point((x1,y1),(nx1,ny1), (x1+x2,y1+y2))	
			r3=get_radius_to_point((x1,y1),(nx1,ny1), (x1+x3,y1+y3))
			return min(r2,r3)	
			#end of get_radius_to_line

		def get_radius_to_point((x1,y1),(nx,ny), (x2,y2)):
			"""LT find biggest circle we can engrave here, constrained by point x2,y2

			This function can be used in three ways:
			- With nx=ny=0 it finds circle centred at x1,y1
			- with nx,ny normalised, it finds circle tangential at x1,y1
			- with nx,ny scaled by 1/cos(a) it finds circle centred on an angle bisector
				 where a is the angle between the bisector and the previous/next normals

			Note that I wrote this to replace find_cutter_centre. It is far less
			sophisticated but, I hope, far faster.
			It turns out that finding a circle touching a point is harder than a circle
			touching a line.
			"""
			#Start by converting coordinates to be relative to x1,y1
			x2,y2= x2-x1, y2-y1
			denom=nx**2+ny**2-1
			if denom<=0.00001 : #Not a corner bisector
				if denom==-1 : #Find circle centre x1,y1
					return math.sqrt(x2**2+y2**2)
				#if x2,y2 not in front of the normal...
				if x2*nx+y2*ny <=0 : return self.options.engraving_max_dist
				#print_("Straight",x1,y1,nx,ny,x2,y2)
				return (x2**2+y2**2)/(2*(x2*nx+y2*ny) )
			#It is a corner bisector, so..
			discriminator = (x2*nx+y2*ny)**2 - denom*(x2**2+y2**2)
			if discriminator < 0 :
				return self.options.engraving_max_dist #this part irrelevant
			r=(x2*nx+y2*ny -math.sqrt(discriminator))/denom
			#print_("Corner",x1,y1,nx,ny,x1+x2,y1+y2,discriminator,r)
			return r
			#end of get_radius_to_point

		def bez_divide(a,b,c,d):
			"""LT recursively divide a Bezier.

			Divides until difference between each
			part and a straight line is less than some limit
			Each parameter is a list containing two reals, the coordinates of a point
			Returned value is a list of Beziers.
			Each Bezier is a list with has four members,
			each a list holding a coordinate pair
			"""
			bx=b[0]-a[0]
			by=b[1]-a[1]
			cx=c[0]-a[0]
			cy=c[1]-a[1]
			dx=d[0]-a[0]
			dy=d[1]-a[1]
			limit=8*math.sqrt(dx**2+dy**2)/self.options.engraving_newton_iterations
			#LT This is the only limit we get from the user currently
			if abs(dx*by-bx*dy)<limit and abs(dx*cy-cx*dy)<limit :
				return [[a,b,c,d]]
			abx=(a[0]+b[0])/2.0
			aby=(a[1]+b[1])/2.0
			bcx=(b[0]+c[0])/2.0
			bcy=(b[1]+c[1])/2.0
			cdx=(c[0]+d[0])/2.0
			cdy=(c[1]+d[1])/2.0
			abcx=(abx+bcx)/2.0
			abcy=(aby+bcy)/2.0
			bcdx=(bcx+cdx)/2.0
			bcdy=(bcy+cdy)/2.0
			m=[(abcx+bcdx)/2.0,(abcy+bcdy)/2.0]
			return bez_divide(a,[abx,aby],[abcx,abcy],m) + bez_divide(m,[bcdx,bcdy],[cdx,cdy],d)
			#end of bez_divide

		def save_point((x,y),r,w,i): #LT added i for debugging
			global LTw, LTcspOut
			LTcspOut+=[ [ [x,y],[x,y],[x,y] ] ]
			LTw+=[w]
			#end of save_point

		def draw_point((x,y),r):
			if self.options.engraving_draw_calculation_paths :
				inkex.etree.SubElement(	engraving_group, inkex.addNS('path','svg'), 
						{"gcodetools": "Engraving calculation toolpath", 'style':	"fill:#ff00ff; fill-opacity:0.46; stroke:#000000; stroke-width:0.1;", inkex.addNS('cx','sodipodi'):		str(x), inkex.addNS('cy','sodipodi'):		str(y), inkex.addNS('rx','sodipodi'):	str(1), inkex.addNS('ry','sodipodi'): str(1), inkex.addNS('type','sodipodi'):	'arc'})	
				inkex.etree.SubElement(	engraving_group, inkex.addNS('path','svg'), 
						{"gcodetools": "Engraving calculation paths", 'style':	"fill:none; fill-opacity:0.46; stroke:#000000; stroke-width:0.1;", inkex.addNS('cx','sodipodi'):		str(x),  inkex.addNS('cy','sodipodi'):		str(y),inkex.addNS('rx','sodipodi'):		str(r), inkex.addNS('ry','sodipodi'):		str(r), inkex.addNS('type','sodipodi'):	'arc'})
			#end of draw_point

		#end of subfunction definitions. engraving() starts here:
		print_("self.options.engraving_max_dist ", self.options.engraving_max_dist )
		bitlen=20/self.options.engraving_newton_iterations
		cspe =[]
		we = []
		for layer in self.layers :
			if layer in self.selected_paths : 
				self.set_tool(layer)
				engraving_group = inkex.etree.SubElement( self.selected_paths[layer][0].getparent(), inkex.addNS('g','svg') )
				for node in self.selected_paths[layer] :	
					if node.tag == inkex.addNS('path','svg'):
						cspi = cubicsuperpath.parsePath(node.get('d'))

						#LT: Create my own list n1LT[j] is for subpath j
						nlLT = []
						for j in xrange(len(cspi)): #LT For each subpath...
							# Remove zero length segments, assume closed path
							i = 0 #LT was from i=1
							while i<len(cspi[j]):
								if abs(cspi[j][i-1][1][0]-cspi[j][i][1][0])<engraving_tolerance and abs(cspi[j][i-1][1][1]-cspi[j][i][1][1])<engraving_tolerance:
									cspi[j][i-1][2] = cspi[j][i][2]
									del cspi[j][i]
								else:
									i += 1
						for csp in cspi: #LT6a For each subpath...
							#create list containing lines and points
							# line members: [x,y],[nx,ny],False,i
							# x,y is start of line. Normal on engraved side.
							# Normal is normalised (unit length)
							#Note that Y axis increases down the page
							# corner members: [x,y],[nx,ny],True,sin(halfangle)
							# if halfangle>0: radius 0 here. normal is bisector
							# if halfangle<0. reflex angle. normal is bisector
							# corner normals are divided by cos(halfangle)
							#so that they will engrave correctly
							print_("csp is",csp)
							nlLT.append ([])
							for i in range(0,len(csp)): #LT for each point
								#n = []
								sp0, sp1, sp2 = csp[i-2], csp[i-1], csp[i]
								#LT find angle between this and previous segment
								x0,y0 = sp1[1]
								nx1,ny1 = csp_normalized_normal(sp1,sp2,0)
								nx0, ny0 = csp_normalized_normal(sp0,sp1,1)
								sinAng = ny1*nx0-ny0*nx1 #Positive if turning inwards
								cosBis = math.sqrt((1.0+nx0*nx1-ny0*ny1)/2.0)
								if ny0==ny1 :
									if nx0==nx1 : sinBis=ny0
									else : sinBis = math.copysign(1,ny0)
								else :
									sinBis = cosBis*(nx1-nx0)/(ny0-ny1)
									#dot product of bisector and a normal >0
									if cosBis*nx0+sinBis*ny0 < 0 :
										cosBis=-cosBis
										sinBis=-sinBis
								#register if turning left or turning right more than limit angle
			 					if sinAng < -0.0001  or sinAng > math.sin((180-self.options.engraving_sharp_angle_tollerance)*math.pi/180) :
									#record x,y,normal,ifCorner, sin half angle turned
									#Get cos(half angle turned)
									cosBis2=cosBis*nx0+sinBis*ny0
									b= [[ [x0,y0],[cosBis/cosBis2,sinBis/cosBis2], True, sinBis*nx0-cosBis*ny0]]
									nlLT[-1] += b
								#LT now do the line
								if sp1[1]==sp1[2] and sp2[0]==sp2[1] : #straightline
									nlLT[-1]+=[[sp1[1],[nx1,ny1],False,i]]
								else : #Bezier
									nn=bez_divide(sp1[1],sp1[2],sp2[0],sp2[1])
									for bLT in nn : #save as three line segments
										nx=bLT[1][0]-bLT[0][0]
										ny=bLT[1][1]-bLT[0][1]
										l=math.sqrt(nx**2+ny**2)
										if l>0.0001 : 
											nlLT[-1]+=[[bLT[0],[-ny/l,nx/l], False,i]]
										nx=bLT[2][0]-bLT[1][0]
										ny=bLT[2][1]-bLT[1][1]
										l=math.sqrt(nx**2+ny**2)
										if l>0.0001 : 
											nlLT[-1]+=[[bLT[1],[-ny/l,nx/l], False,i]]
										nx=bLT[3][0]-bLT[2][0]
										ny=bLT[3][1]-bLT[2][1]
										l=math.sqrt(nx**2+ny**2)
										if l>0.0001 : 
											nlLT[-1]+=[[bLT[2],[-ny/l,nx/l], False,i]]
							#LT for each segment - ends here
							print_(("engraving_draw_calculation_paths=",self.options.engraving_draw_calculation_paths))
							if self.options.engraving_draw_calculation_paths:
								for p in nlLT[-1]: #For last sub-path
									inkex.etree.SubElement(	engraving_group, inkex.addNS('path','svg'),
										{ "d":	"M %f,%f L %f,%f" %(p[0][0],p[0][1],p[0][0]+p[1][0]*10,p[0][1]+p[1][1]*10),
											'style':	"stroke:#0000ff; stroke-opacity:0.46; stroke-width:0.1; fill:none",
											"gcodetools": "Engraving normals"
										})				


						#LT6a build nlLT[j] for each subpath - ends here
				 		# Calculate offset points
						#print_("nlLT",nlLT) #LT debug stuff
						reflex=False
						for j in xrange(len(nlLT)): #LT6b for each subpath
							LTcspOut=[] #Will be my output. List of csps.
							LTw=[] #Will be my w output list
							r = 0 #LT initial value in case first point is an angle
							for i in xrange(len(nlLT[j])) : #LT for each node
								#LT Note: Python enables wrapping of array indices
								# backwards to -1, -2, but not forwards. Hence:
								n0 = nlLT[j][i-2] #previous node
								n1 = nlLT[j][i-1] #current node
								n2 = nlLT[j][i] #next node
								x1a,y1a = n1[0] #this point/start of this line
								nx,ny = n1[1]
								x1b,y1b = n2[0] #next point/end of this line
								if n1[2] == True : # We're at a corner
									bits=1
									bit0=0
									lastr=r #Remember r from last line
									if n1[3]>0 : #acute. Limit radius
										len1=(n0[0][0]-n1[0][0])**2 + (n0[0][1]-n1[0][1])**2
										len2=(n2[0][0]-n1[0][0])**2 + (n2[0][1]-n1[0][1])**2
										#set initial r value, not to be exceeded
										r = math.sqrt(min(len1,len2))/n1[3]
								else: #line. Cut it up if long.
									rbits=math.sqrt((x1b-x1a)**2+(y1a-y1b)**2)/bitlen
									bits=max(1,int(rbits+0.5))
									bit0=(rbits-bits+1)/2
									r = self.options.engraving_max_dist
								for b in xrange(bits) : #divide line into bits
									x1=x1a+ny*(b+bit0)*bitlen
									y1=y1a-nx*(b+bit0)*bitlen
										
									#set a maximum distance
									if b>0 : r = self.options.engraving_max_dist
									# set limits within which to look for lines
									xmin, xmax = x1+r*nx-r, x1+r*nx+r
									ymin, ymax = y1+r*ny-r, y1+r*ny+r
									for jj in xrange(0,len(nlLT)):
										for ii in xrange(0,len(nlLT[jj])):
											if ii==i and jj==j: continue
											#LT ignore corners for now
											if nlLT[jj][ii-1][2] : continue
											x2,y2 = nlLT[jj][ii-1][0]
											nx2,ny2 = nlLT[jj][ii-1][1]
											x3,y3 = nlLT[jj][ii][0]
											x23min,x23max=min(x2,x3),max(x2,x3)
											y23min,y23max=min(y2,y3),max(y2,y3)
											#LT see if line in range
											if n1[2]==False and (x23max<xmin or x23min>xmax or y23max<ymin or y23min>ymax) : continue
											t1=get_radius_to_line((x1,y1),(nx,ny), (x2,y2),(nx2,ny2), (x3,y3))
											if t1>=0 :
												r = min(t1,r)
												xmin, xmax = x1+r*nx-r, x1+r*nx+r
												ymin, ymax = y1+r*ny-r, y1+r*ny+r
										#next ii
									#next jj
									#here, we've found optimum r for this node
									w = min(r, self.tools[layer][0]['diameter']/2)
									if reflex : #just after a reflex corner
										reflex = False
										if r<lastr : #need to adjust it
											draw_point((n0[0][0]+n0[1][0]*r,n0[0][1]+n0[1][1]*r),r)
											save_point((n0[0][0]+n0[1][0]*w,n0[0][1]+n0[1][1]*w),r,w,i)
									if n1[2] == True : # We're at a corner
										if n1[3]>0 : #acute
											#print_("Acute x,y,nx,ny,w,r",x1,y1,nx,ny,w,r)
											save_point((x1+nx*w,y1+ny*w),r,w,i)
											draw_point((x1,y1),0)
											save_point((x1,y1),0,0,i)
										else : #reflex
											if r>lastr :
												draw_point((x1+nx*lastr,y1+ny*lastr),lastr)
												w = min(lastr, self.tools[layer][0]['diameter']/2)
												save_point((x1+nx*w,y1+ny*w),r,w,i)
									draw_point((x1+nx*r,y1+ny*r),r)
									save_point((x1+nx*w,y1+ny*w),r,w,i)
								#LT end of for each bit of this line
								if n1[2] == True and n1[3]<0 : #reflex angle
									reflex=True
								lastr=r #remember this r
							#LT next i
							LTcspOut+=[LTcspOut[0]]
							#print_("LTcspOut",LTcspOut)
							LTw+=[LTw[0]]
							#print_("LTw",LTw)
							#Note: Original csp_points was a list, each element
							#being 4 points, with the first being the same as the
							#last of the previous set.
							#Each point is a list of [cx,cy,r,w]
							#I have flattened it to a flat list of points.
					
							cspm=LTcspOut
							w=LTw
							if self.options.engraving_draw_calculation_paths==True:
								node =  inkex.etree.SubElement(	engraving_group, inkex.addNS('path','svg'), 										{
														 "d":	 cubicsuperpath.formatPath([cspm]),
														'style':	styles["biarc_style_i"]['biarc1'],
														"gcodetools": "Engraving calculation paths",
													})
								for i in xrange(len(cspm)):
									inkex.etree.SubElement(	engraving_group, inkex.addNS('path','svg'), 
											{"gcodetools": "Engraving calculation paths", 'style':	"fill:none; fill-opacity:0.46; stroke:#000000; stroke-width:0.1;", inkex.addNS('cx','sodipodi'):		str(cspm[i][1][0]),  inkex.addNS('cy','sodipodi'):		str(cspm[i][1][1]),inkex.addNS('rx','sodipodi'):		str(w[i]), inkex.addNS('ry','sodipodi'):		str(w[i]), inkex.addNS('type','sodipodi'):	'arc'})
							cspe += [cspm]
							we   +=	[w]
						#LT6b For each subpath - ends here			
					#LT5 if it is a path - ends here
				#LT4 for each selected object in this layer - ends here
				if self.tools[layer][0]['shape'] != "":
					f = eval('lambda w: ' + self.tools[layer][0]['shape'].strip('"'))
				else: 
					self.error(_("Tool '%s' has no shape!") % self.tools[layer][0]['name'],"engraving_tools_shape_error")
					f = lambda w: w
		
				if cspe!=[]:
					curve = self.parse_curve(cspe, layer, we, f) #convert to biarcs
					self.draw_curve(curve, layer, engraving_group)
					gcode += self.generate_gcode(curve, layer, self.options.Zsurface)
				
			#LT3 for layers loop ends here
		if gcode!='' :
			self.export_gcode(gcode)
		else : 	self.error(_("No need to engrave sharp angles."),"warning")


################################################################################
###
###		Orientation
###
################################################################################
	def orientation(self, layer=None) :
		print_("entering orientations")
		if layer == None :
			layer = self.current_layer if self.current_layer is not None else self.document.getroot()
		if layer in self.orientation_points:
			self.error(_("Active layer already has orientation points! Remove them or select another layer!"),"active_layer_already_has_orientation_points")
		
		orientation_group = inkex.etree.SubElement(layer, inkex.addNS('g','svg'), {"gcodetools":"Gcodetools orientation group"})
		doc_height = inkex.unittouu(self.document.getroot().get('height'))
		if self.document.getroot().get('height') == "100%" :
			doc_height = 1052.3622047
			print_("Overriding height from 100 percent to %s" % doc_height)
		if self.options.unit == "G21 (All units in mm)" : 
			points = [[0.,0.,self.options.Zsurface],[100.,0.,self.options.Zdepth],[0.,100.,0.]]
			orientation_scale = 3.5433070660
			print_("orientation_scale < 0 ===> switching to mm units=%0.10f"%orientation_scale )
		elif self.options.unit == "G20 (All units in inches)" :
			points = [[0.,0.,self.options.Zsurface],[5.,0.,self.options.Zdepth],[0.,5.,0.]]
			orientation_scale = 90
			print_("orientation_scale < 0 ===> switching to inches units=%0.10f"%orientation_scale )
		if self.options.orientation_points_count == 2 :
			points = points[:2]
		print_(("using orientation scale",orientation_scale,"i=",points))
		for i in points :
			si = [i[0]*orientation_scale, i[1]*orientation_scale]
			g = inkex.etree.SubElement(orientation_group, inkex.addNS('g','svg'), {'gcodetools': "Gcodetools orientation point (%s points)" % self.options.orientation_points_count})
			inkex.etree.SubElement(	g, inkex.addNS('path','svg'), 
				{
					'style':	"stroke:none;fill:#000000;", 	
					'd':'m %s,%s 2.9375,-6.343750000001 0.8125,1.90625 6.843748640396,-6.84374864039 0,0 0.6875,0.6875 -6.84375,6.84375 1.90625,0.812500000001 z z' % (si[0], -si[1]+doc_height),
					'gcodetools': "Gcodetools orientation point arrow"
				})
			t = inkex.etree.SubElement(	g, inkex.addNS('text','svg'), 
				{
					'style':	"font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;",
					inkex.addNS("space","xml"):"preserve",
					'x':	str(si[0]+10),
					'y':	str(-si[1]-10+doc_height),
					'gcodetools': "Gcodetools orientation point text"
				})
			t.text = "(%s; %s; %s)" % (i[0],i[1],i[2])
	
		
################################################################################
###
###		Tools library
###
################################################################################
	def tools_library(self, layer=None) :
		# Add a tool to the drawing
		if layer == None :
			layer = self.current_layer if self.current_layer is not None else self.document.getroot()
		if layer in self.tools:
			self.error(_("Active layer already has a tool! Remove it or select another layer!"),"active_layer_already_has_tool")

		if self.options.tools_library_type == "cylinder cutter" :
			tool = {
					"name": "Cylindrical cutter",
					"id": "Cylindrical cutter 0001",
					"diameter":10,
					"penetration angle":90,
					"feed":"400",
					"penetration feed":"100",
					"depth step":"1",
					"tool change gcode":" "
			}
		elif self.options.tools_library_type == "lathe cutter" :
			tool = {
					"name": "Lathe cutter",
					"id": "Lathe cutter 0001",
					"diameter":10,
					"penetration angle":90,
					"feed":"400",
					"passing feed":"800",
					"fine feed":"100",
					"penetration feed":"100",
					"depth step":"1",
					"tool change gcode":" "
			}
		elif self.options.tools_library_type == "cone cutter":	
			tool = {
					"name": "Cone cutter",
					"id": "Cone cutter 0001",
					"diameter":10,
					"shape":"w",
					"feed":"400",
					"penetration feed":"100",
					"depth step":"1",
					"tool change gcode":" "
			}
		elif self.options.tools_library_type == "tangent knife":	
			tool = {
					"name": "Tangent knife",
					"id": "Tangent knife 0001",
					"feed":"400",
					"penetration feed":"100",
					"depth step":"100",
					"4th axis meaning": "tangent knife",
					"4th axis scale": 1.,
					"4th axis offset": 0,
					"tool change gcode":" "
			}
			
		elif self.options.tools_library_type == "plasma cutter":	
			tool = {
				"name": "Plasma cutter",
				"id": "Plasma cutter 0001",
				"diameter":10,
				"penetration feed":100,
				"feed":400,
				"gcode before path":"""G31 Z-100 F500 (find metal)
G92 Z0 (zerro z)
G00 Z10 F500 (going up)
M03 (turn on plasma)
G04 P0.2 (pause)
G01 Z1 (going to cutting z)\n""",
				"gcode after path":"M05 (turn off plasma)\n",
			}
		else :
			tool = self.default_tool
		
		tool_num = sum([len(self.tools[i]) for i in self.tools])
		colors = ["00ff00","0000ff","ff0000","fefe00","00fefe", "fe00fe", "fe7e00", "7efe00", "00fe7e", "007efe", "7e00fe", "fe007e"]
		
		tools_group = inkex.etree.SubElement(layer, inkex.addNS('g','svg'), {'gcodetools': "Gcodetools tool defenition"})
		bg = inkex.etree.SubElement(	tools_group, inkex.addNS('path','svg'), 
					{'style':	"fill:#%s;fill-opacity:0.5;stroke:#444444; stroke-width:1px;"%colors[tool_num%len(colors)], "gcodetools":"Gcodetools tool background"})

		y = 0
		keys = []
		for key in self.tools_field_order:
			if key in tool: keys += [key]
		for key in tool:
			if key not in keys: keys += [key]
		for key in keys :
			g = inkex.etree.SubElement(tools_group, inkex.addNS('g','svg'), {'gcodetools': "Gcodetools tool parameter"})
		
			t = inkex.etree.SubElement(	g, inkex.addNS('text','svg'), 
					{
						'style':	("font-size:10px;" if key!="name" else "font-size:20px;") +	"font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;",
						inkex.addNS("space","xml"):"preserve",							
						'x':	str(0),
						'y':	str(y),
						'gcodetools': "Gcodetools tool defention field name"
					})
			t.text = str(key)
			v = str(tool[key]).split("\n")
			t = inkex.etree.SubElement(	g, inkex.addNS('text','svg'), 
					{
						'style':	("font-size:10px;" if key!="name" else "font-size:20px;") + "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;",
						'x':	str(150),
						inkex.addNS("space","xml"):"preserve",
						'y':	str(y),
						'gcodetools': "Gcodetools tool defention field value"
					})
			for s in v :
				span = inkex.etree.SubElement( t, inkex.addNS('tspan','svg'), 
					{
						'x':	str(150),
						'y':	str(+y),
						inkex.addNS("role","sodipodi"):"line",
						'gcodetools': "Gcodetools tool defention field value"
					})					
				y += 15 if key!='name' else 20
				span.text = s
		bg.set('d',"m -20,-20 l 400,0 0,%f -400,0 z " % (y+50))
		tool = []
		tools_group.set("transform", simpletransform.formatTransform([ [1,0,self.view_center[0]-150 ], [0,1,self.view_center[1]] ] ))


################################################################################
###
###		Check tools and OP asignment
###
################################################################################
	def check_tools_and_op(self):
		if len(self.selected)<=0 :
			self.error(_("Selection is empty! Will compute whole drawing."),"selection_is_empty_will_comupe_drawing")
			paths = self.paths
		else :
			paths = self.selected_paths
		#	Set group
		group = inkex.etree.SubElement( self.selected_paths.keys()[0] if len(self.selected_paths.keys())>0 else self.layers[0], inkex.addNS('g','svg') )
		trans_ = [[1,0.3,0],[0,0.5,0]]	
		self.get_defs()
		# Add marker to defs if it doesnot exists
		if "CheckToolsAndOPMarker" not in self.defs : 
			defs = inkex.etree.SubElement( self.document.getroot(), inkex.addNS("defs","svg"))
			marker = inkex.etree.SubElement( defs, inkex.addNS("marker","svg"), {"id":"CheckToolsAndOPMarker","orient":"auto","refX":"-8","refY":"-2.41063","style":"overflow:visible"})
			inkex.etree.SubElement( marker, inkex.addNS("path","svg"), 
					{	"d":"m -6.55552,-2.41063 0,0 L -13.11104,0 c 1.0473,-1.42323 1.04126,-3.37047 0,-4.82126",
						"style": "fill:#000044; fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"	}
				)
		bounds = [float('inf'),float('inf'),float('-inf'),float('-inf')]
		tools_bounds = {}
		for layer in self.layers :
			if layer in paths :
				self.set_tool(layer)
				tool = self.tools[layer][0]
				tools_bounds[layer] = tools_bounds[layer] if layer in tools_bounds else [float("inf"),float("-inf")]
				style = simplestyle.formatStyle(tool["style"])
				for path in paths[layer] :
					style = "fill:%s; fill-opacity:%s; stroke:#000044; stroke-width:1; marker-mid:url(#CheckToolsAndOPMarker);" % (
					tool["style"]["fill"] if "fill" in tool["style"] else "#00ff00", 
					tool["style"]["fill-opacity"] if "fill-opacity" in tool["style"] else "0.5")
					group.insert( 0, inkex.etree.Element(path.tag, path.attrib))
					new = group.getchildren()[0]
					new.set("style", style)
					
					trans = self.get_transforms(path)
					trans = simpletransform.composeTransform( trans_, trans if trans != [] else [[1.,0.,0.],[0.,1.,0.]])
					csp = cubicsuperpath.parsePath(path.get("d"))
					simpletransform.applyTransformToPath(trans,csp)
					path_bounds = csp_simple_bound(csp)
					trans = simpletransform.formatTransform(trans)
					bounds = [min(bounds[0],path_bounds[0]), min(bounds[1],path_bounds[1]), max(bounds[2],path_bounds[2]), max(bounds[3],path_bounds[3])]
					tools_bounds[layer] = [min(tools_bounds[layer][0], path_bounds[1]), max(tools_bounds[layer][1], path_bounds[3])] 

					new.set("transform", trans) 
					trans_[1][2] += 20
				trans_[1][2] += 100

		for layer in self.layers :
			if layer in self.tools :
				if layer in tools_bounds :
					tool = self.tools[layer][0]
					g = copy.deepcopy(tool["self_group"])
					g.attrib["gcodetools"] = "Check tools and OP asignment"
					trans = [[1,0.3,bounds[2]],[0,0.5,tools_bounds[layer][0]]]	
					g.set("transform",simpletransform.formatTransform(trans))
					group.insert( 0, g )


################################################################################
###		TODO Launch browser on help tab
################################################################################
	def help(self):
		self.error(_("""Tutorials, manuals and support can be found at\nEnglish support forum:\n	http://www.cnc-club.ru/gcodetools\nand Russian support forum:\n	http://www.cnc-club.ru/gcodetoolsru"""),"warning")
		return


################################################################################
###		Lathe
################################################################################
	def generate_lathe_gcode(self, subpath, layer, feed_type) :
		if len(subpath) <2 : return ""
		feed = " F %f" % self.tool[feed_type] 
		x,z = self.options.lathe_x_axis_remap, self.options.lathe_z_axis_remap
		flip_angle = -1 if x.lower()+z.lower() in ["xz", "yx", "zy"] else 1
		alias = {"X":"I", "Y":"J", "Z":"K", "x":"i", "y":"j", "z":"k"} 
		i_, k_ = alias[x], alias[z]
		c = [ [subpath[0][1], "move", 0, 0, 0] ]
		#csp_draw(self.transform_csp([subpath],layer,True), color = "Orange", width = .1)
		for sp1,sp2 in zip(subpath,subpath[1:]) :
			c += biarc(sp1,sp2,0,0)
		for i in range(1,len(c)) : # Just in case check end point of each segment
			c[i-1][4] = c[i][0][:]
		c += [ [subpath[-1][1], "end", 0, 0, 0] ]			
		self.draw_curve(c, layer, style = styles["biarc_style_lathe_%s" % feed_type])
		
		gcode = ("G01 %s %f %s %f" % (x, c[0][4][0], z, c[0][4][1]) ) + feed + "\n" # Just in case move to the start...
		for s in c :
			if s[1] == 'line':
				gcode += ("G01 %s %f %s %f" % (x, s[4][0], z, s[4][1]) ) + feed + "\n"
			elif s[1] == 'arc':
				r = [(s[2][0]-s[0][0]), (s[2][1]-s[0][1])]
				if (r[0]**2 + r[1]**2)>self.options.min_arc_radius:
					r1, r2 = (P(s[0])-P(s[2])), (P(s[4])-P(s[2]))
					if abs(r1.mag()-r2.mag()) < 0.001 :
						gcode += ("G02" if s[3]*flip_angle<0 else "G03") + (" %s %f %s %f %s %f %s %f" % (x,s[4][0],z,s[4][1],i_,(s[2][0]-s[0][0]), k_, (s[2][1]-s[0][1]) ) ) + feed + "\n"
					else:
						r = (r1.mag()+r2.mag())/2
						gcode += ("G02" if s[3]*flip_angle<0 else "G03") + (" %s %f %s %f" % (x,s[4][0],z,y[4][1]) ) + " R%f"%r + feed + "\n"
		return gcode


	def lathe(self):
		if not self.check_dir() : return
		x,z = self.options.lathe_x_axis_remap, self.options.lathe_z_axis_remap
		x = re.sub("^\s*([XYZxyz])\s*$",r"\1",x) 
		z = re.sub("^\s*([XYZxyz])\s*$",r"\1",z)
		if x not in ["X", "Y", "Z", "x", "y", "z"] or z not in ["X", "Y", "Z", "x", "y", "z"] :
			self.error(_("Lathe X and Z axis remap should be 'X', 'Y' or 'Z'. Exiting..."),"warning") 
			return
		if x.lower() == z.lower() :
			self.error(_("Lathe X and Z axis remap should be the same. Exiting..."),"warning") 
			return
		if 	x.lower()+z.lower() in ["xy","yx"] : gcode_plane_selection = "G17 (Using XY plane)\n"
		if 	x.lower()+z.lower() in ["xz","zx"] : gcode_plane_selection = "G18 (Using XZ plane)\n"
		if 	x.lower()+z.lower() in ["zy","yz"] : gcode_plane_selection = "G19 (Using YZ plane)\n"
		self.options.lathe_x_axis_remap, self.options.lathe_z_axis_remap = x, z
	
		paths = self.selected_paths
		self.tool = []
		gcode = ""
		for layer in self.layers :
			if layer in paths :
				self.set_tool(layer)
				if self.tool != self.tools[layer][0] :
					self.tool = self.tools[layer][0]
					self.tool["passing feed"]	= float(self.tool["passing feed"] if "passing feed" in self.tool else self.tool["feed"])
					self.tool["feed"]			= float(self.tool["feed"])
					self.tool["fine feed"]		= float(self.tool["fine feed"] if "fine feed" in self.tool else self.tool["feed"]) 
					
					gcode += ( "(Change tool to %s)\n" % re.sub("\"'\(\)\\\\"," ",self.tool["name"]) ) + self.tool["tool change gcode"] + "\n"
					
				for path in paths[layer]:
					csp = self.transform_csp(cubicsuperpath.parsePath(path.get("d")),layer)
					
					for subpath in csp :
						# Offset the path if fine cut is defined.
						fine_cut = subpath[:]
						if self.options.lathe_fine_cut_width>0 :
							r = self.options.lathe_fine_cut_width
							# Close the path to make offset correct 
							bound = csp_simple_bound([subpath])
							minx,miny,maxx,maxy = csp_true_bounds([subpath])
							offsetted_subpath = csp_subpath_line_to(subpath[:], [ [subpath[-1][1][0], miny[1]-r*10 ], [subpath[0][1][0], miny[1]-r*10 ], [subpath[0][1][0], subpath[0][1][1] ]  ])
							left,right = subpath[-1][1][0], subpath[0][1][0]
							if left>right : left, right = right,left
							offsetted_subpath = csp_offset([offsetted_subpath], r if not csp_subpath_ccw(offsetted_subpath) else -r ) 
							offsetted_subpath = csp_clip_by_line(offsetted_subpath,  [left,10], [left,0] )
							offsetted_subpath = csp_clip_by_line(offsetted_subpath,  [right,0], [right,10] )
							offsetted_subpath = csp_clip_by_line(offsetted_subpath,  [0, miny[1]-r], [10, miny[1]-r] )
							#csp_draw(self.transform_csp(offsetted_subpath,layer,True), color = "Green", width = 1)
							# Join offsetted_subpath together 
							# Hope there wont be any cicles
							subpath = csp_join_subpaths(offsetted_subpath)[0]
							
						# Create solid object from path and lathe_width 
						bound = csp_simple_bound([subpath])
						top_start, top_end = [subpath[0][1][0], self.options.lathe_width+self.options.Zsafe+self.options.lathe_fine_cut_width], [subpath[-1][1][0], self.options.lathe_width+self.options.Zsafe+self.options.lathe_fine_cut_width]

						gcode += ("G01 %s %f F %f \n" % (z, top_start[1], self.tool["passing feed"]) )
						gcode += ("G01 %s %f %s %f F %f \n" % (x, top_start[0], z, top_start[1], self.tool["passing feed"]) )

						subpath = csp_concat_subpaths(csp_subpath_line_to([],[top_start,subpath[0][1]]), subpath)
						subpath = csp_subpath_line_to(subpath,[top_end,top_start])
	
						
						width = max(0, self.options.lathe_width - max(0, bound[1]) )
						step = self.tool['depth step']
						steps = int(math.ceil(width/step))
						for i in range(steps+1):
							current_width = self.options.lathe_width - step*i
							intersections = []
							for j in range(1,len(subpath)) :
								sp1,sp2 = subpath[j-1], subpath[j]
								intersections += [[j,k] for k in csp_line_intersection([bound[0]-10,current_width], [bound[2]+10,current_width], sp1, sp2)]
								intersections += [[j,k] for k in csp_line_intersection([bound[0]-10,current_width+step], [bound[2]+10,current_width+step], sp1, sp2)]
							parts = csp_subpath_split_by_points(subpath,intersections)
							for part in parts :
								minx,miny,maxx,maxy = csp_true_bounds([part])
								y = (maxy[1]+miny[1])/2
								if  y > current_width+step :
									gcode += self.generate_lathe_gcode(part,layer,"passing feed")
								elif current_width <= y <= current_width+step :
									gcode += self.generate_lathe_gcode(part,layer,"feed")
								else :
									# full step cut
									part = csp_subpath_line_to([], [part[0][1], part[-1][1]] )
									gcode += self.generate_lathe_gcode(part,layer,"feed")
									
						top_start, top_end = [fine_cut[0][1][0], self.options.lathe_width+self.options.Zsafe+self.options.lathe_fine_cut_width], [fine_cut[-1][1][0], self.options.lathe_width+self.options.Zsafe+self.options.lathe_fine_cut_width]
						gcode += "\n(Fine cutting start)\n(Calculating fine cut using %s)\n"%self.options.lathe_create_fine_cut_using
						for i in range(self.options.lathe_fine_cut_count) :
							width = self.options.lathe_fine_cut_width*(1-float(i+1)/self.options.lathe_fine_cut_count ) 
							if width == 0 : 
								current_pass = fine_cut							
							else :	
								if self.options.lathe_create_fine_cut_using == "Move path" :
									current_pass = [ [  [i2[0],i2[1]+width]  for i2 in i1]  for i1 in fine_cut]
								else :
									minx,miny,maxx,maxy = csp_true_bounds([fine_cut])
									offsetted_subpath = csp_subpath_line_to(fine_cut[:], [ [fine_cut[-1][1][0], miny[1]-r*10 ], [fine_cut[0][1][0], miny[1]-r*10 ], [fine_cut[0][1][0], fine_cut[0][1][1] ]  ])
									left,right = fine_cut[-1][1][0], fine_cut[0][1][0]
									if left>right : left, right = right,left
									offsetted_subpath = csp_offset([offsetted_subpath], width if not csp_subpath_ccw(offsetted_subpath) else -width ) 
									offsetted_subpath = csp_clip_by_line(offsetted_subpath,  [left,10], [left,0] )
									offsetted_subpath = csp_clip_by_line(offsetted_subpath,  [right,0], [right,10] )
									offsetted_subpath = csp_clip_by_line(offsetted_subpath,  [0, miny[1]-r], [10, miny[1]-r] )
									current_pass = csp_join_subpaths(offsetted_subpath)[0]


							gcode += "\n(Fine cut %i-th cicle start)\n"%(i+1)					
							gcode += ("G01 %s %f %s %f F %f \n" % (x, top_start[0], z, top_start[1], self.tool["passing feed"]) )
							gcode += ("G01 %s %f %s %f F %f \n" % (x, current_pass[0][1][0], z, current_pass[0][1][1]+self.options.lathe_fine_cut_width, self.tool["passing feed"]) )
							gcode += ("G01 %s %f %s %f F %f \n" % (x, current_pass[0][1][0], z, current_pass[0][1][1], self.tool["fine feed"]) )
						
							gcode += self.generate_lathe_gcode(current_pass,layer,"fine feed")
							gcode += ("G01 %s %f F %f \n" % (z, top_start[1], self.tool["passing feed"]) )
							gcode += ("G01 %s %f %s %f F %f \n" % (x, top_start[0], z, top_start[1], self.tool["passing feed"]) )
	
		
		
		self.export_gcode(gcode)

	
	def update(self) :
		try :
			import urllib
			f = urllib.urlopen("http://www.cnc-club.ru/gcodetools_latest_version", proxies = urllib.getproxies())
			a = f.read()
			for s in a.split("\n") :
				r = re.search(r"Gcodetools\s+latest\s+version\s*=\s*(.*)",s)
				if r : 
					ver = r.group(1).strip()
					if ver != gcodetools_current_version :
						self.error("There is a newer version of Gcodetools you can get it at: \nhttp://www.cnc-club.ru/gcodetools (English version). \nhttp://www.cnc-club.ru/gcodetools_ru (Russian version). ","Warning")					
					else :
						self.error("You are currently using latest stable version of Gcodetools.","Warning")					
					return 
			self.error("Can not check the latest version. You can check it manualy at \nhttp://www.cnc-club.ru/gcodetools (English version). \nhttp://www.cnc-club.ru/gcodetools_ru (Russian version). \nCurrent version is Gcodetools %s"%gcodetools_current_version,"Warning")					
		except :
			self.error("Can not check the latest version. You can check it manualy at \nhttp://www.cnc-club.ru/gcodetools (English version). \nhttp://www.cnc-club.ru/gcodetools_ru (Russian version). \nCurrent version is Gcodetools %s"%gcodetools_current_version,"Warning")					
				
										
################################################################################
###
###		Effect
###
###		Main function of Gcodetools class
###
################################################################################
	def effect(self) :
		global options
		options = self.options
		options.self = self
		options.doc_root = self.document.getroot()

		# define print_ function 
		global print_
		if self.options.log_create_log :
			try :
				if os.path.isfile(self.options.log_filename) : os.remove(self.options.log_filename)
				f = open(self.options.log_filename,"a")
				f.write("Gcodetools log file.\nStarted at %s.\n%s\n" % (time.strftime("%d.%m.%Y %H:%M:%S"),options.log_filename))
				f.write("%s tab is active.\n" % self.options.active_tab)
				f.close()
			except :
				print_  = lambda *x : None 
		else : print_  = lambda *x : None 
		if self.options.active_tab == '"help"' :
			self.help()
			return
		elif self.options.active_tab not in ['"dxfpoints"','"path-to-gcode"', '"area"', '"area_artefacts"', '"engraving"', '"orientation"', '"tools_library"', '"lathe"', '"offset"', '"arrangement"', '"update"']:
			self.error(_("Select one of the active tabs - Path to Gcode, Area, Engraving, DXF points, Orientation, Offset, Lathe or Tools library."),"error")
		else:
			# Get all Gcodetools data from the scene.
			self.get_info()
			if self.options.active_tab in ['"dxfpoints"','"path-to-gcode"', '"area"', '"area_artefacts"', '"engraving"', '"lathe"']:
				if self.orientation_points == {} :
					self.error(_("Orientation points have not been defined! A default set of orientation points has been automatically added."),"warning")
					self.orientation( self.layers[min(1,len(self.layers)-1)] )		
					self.get_info()
				if self.tools == {} :
					self.error(_("Cutting tool has not been defined! A default tool has been automatically added."),"warning")
					self.options.tools_library_type = "default"
					self.tools_library( self.layers[min(1,len(self.layers)-1)] )
					self.get_info()
			if self.options.active_tab == '"path-to-gcode"': 
				self.path_to_gcode()		
			elif self.options.active_tab == '"area"': 
				self.area()		
			elif self.options.active_tab == '"area_artefacts"': 
				self.area_artefacts()		
			elif self.options.active_tab == '"dxfpoints"': 
				self.dxfpoints()		
			elif self.options.active_tab == '"engraving"': 
				self.engraving()		
			elif self.options.active_tab == '"orientation"': 
				self.orientation()		
			elif self.options.active_tab == '"tools_library"': 
				if self.options.tools_library_type != "check":
					self.tools_library()
				else :	
					self.check_tools_and_op()
			elif self.options.active_tab == '"lathe"': 
				self.lathe()
			elif self.options.active_tab == '"update"': 
				self.update()
			elif self.options.active_tab == '"offset"': 
				if self.options.offset_just_get_distance :
					for layer in self.selected_paths :
						if len(self.selected_paths[layer]) == 2 :
							csp1, csp2 = cubicsuperpath.parsePath(self.selected_paths[layer][0].get("d")), cubicsuperpath.parsePath(self.selected_paths[layer][1].get("d"))
							dist = csp_to_csp_distance(csp1,csp2)
							print_(dist)
							draw_pointer( list(csp_at_t(csp1[dist[1]][dist[2]-1],csp1[dist[1]][dist[2]],dist[3]))
										+list(csp_at_t(csp2[dist[4]][dist[5]-1],csp2[dist[4]][dist[5]],dist[6])),"red","line", comment = math.sqrt(dist[0]))
					return	
				if self.options.offset_step == 0 : self.options.offset_step = self.options.offset_radius
				if self.options.offset_step*self.options.offset_radius <0 : self.options.offset_step *= -1
				time_ = time.time()
				offsets_count = 0
				for layer in self.selected_paths :
					for path in self.selected_paths[layer] :
										
						offset = self.options.offset_step/2
						while abs(offset) <= abs(self.options.offset_radius) :
							offset_ = csp_offset(cubicsuperpath.parsePath(path.get("d")), offset)				
							offsets_count += 1
							if offset_ != [] : 
								for iii in offset_ :
									csp_draw([iii], color="Green", width=1)		
									#print_(offset_)
							else :
								print_("------------Reached empty offset at radius %s"% offset )
								break
							offset += self.options.offset_step
				print_()
				print_("-----------------------------------------------------------------------------------")				
				print_("-----------------------------------------------------------------------------------")				
				print_("-----------------------------------------------------------------------------------")				
				print_()
				print_("Done in %s"%(time.time()-time_))				
				print_("Total offsets count %s"%offsets_count)				
			elif self.options.active_tab == '"arrangement"': 
				self.arrangement()
#						
e = Gcodetools()
e.affect()					

