#!/usr/bin/env python3
"""
Comments starting "#LT" or "#CLT" are by Chris Lusby Taylor who rewrote the engraving function in 2011.
History of CLT changes to engraving and other functions it uses:
9 May 2011 Changed test of tool diameter to square it
10 May Note that there are many unused functions, including:
      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,
        bez_at_t, bez_to_point_distance, bez_normalized_slope, matrix_mul, transpose
       Fixed csp_point_inside_bound() to work if x outside bounds
20 May Now encoding the bisectors of angles.
23 May Using r/cos(a) instead of normalised normals for bisectors of angles.
23 May Note that Z values generated for engraving are in pixels, not mm.
       Removed the biarc curves - straight lines are better.
24 May Changed Bezier slope calculation to be less sensitive to tiny differences in points.
       Added use of self.options.engraving_newton_iterations to control accuracy
25 May Big restructure and new recursive function.
       Changed the way I treat corners - I now find if the centre of a proposed circle is
                within the area bounded by the line being tested and the two angle bisectors at
            its ends. See get_radius_to_line().
29 May Eliminating redundant points. If A,B,C colinear, drop B
30 May Eliminating redundant lines in divided Beziers. Changed subdivision of lines
  7Jun Try to show engraving in 3D
 8 Jun Displaying in stereo 3D.
       Fixed a bug in bisect - it could go wrong due to rounding errors if
            1+x1.x2+y1.y2<0 which should never happen. BTW, I spotted a non-normalised normal
            returned by csp_normalized_normal. Need to check for that.
 9 Jun Corrected spelling of 'definition' but still match previous 'defention' and    'defenition' if found in file
     Changed get_tool to find 1.6.04 tools or new tools with corrected spelling
10 Jun Put 3D into a separate layer called 3D, created unless it already exists
       Changed csp_normalized_slope to reject lines shorter than 1e-9.
10 Jun Changed all dimensions seen by user to be mm/inch, not pixels. This includes
      tool diameter, maximum engraving distance, tool shape and all Z values.
12 Jun ver 208 Now scales correctly if orientation points moved or stretched.
12 Jun ver 209. Now detect if engraving toolshape not a function of radius
                Graphics now indicate Gcode toolpath, limited by min(tool diameter/2,max-dist)
TODO Change line division to be recursive, depending on what line is touched. See line_divide


engraving() functions (c) 2011 Chris Lusby Taylor, clusbytaylor@enterprise.net
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.7
    # ##


import inkex
import simplestyle
import cubicsuperpath
import simpletransform
import os
import math
import bezmisc
import re
import copy
import sys
import time
import cmath
import numpy
import random
import gettext
_ = gettext.gettext

gcodetools_current_version = "1.7"


    # ## 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"))
    inkex.errormsg = lambda msg: sys.stderr.write(msg)


def bezierslopeatt(xxx, t):
    (
        (bx0, by0),
        (bx1, by1),
        (bx2, by2),
        (bx3, by3)
    ) = xxx
    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)


def isset(variable):
    # VARIABLE NAME SHOULD BE A STRING! Like isset("foobar")
    return variable in locals() or variable in globals()


    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##
    # ##     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

EMC_TOLERANCE_EQUAL = 0.00001

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 = {
        "in_out_path_style" : str(inkex.Style({'stroke': '#0072a7', 'fill': 'none', 'stroke-width':'1', 'marker-mid':'url(#InOutPathMarker)'})),

        "loft_style" : {
                'main curve': str(inkex.Style({'stroke': '#88f', 'fill': 'none', 'stroke-width':'1', 'marker-end':'url(#Arrow2Mend)'})),
           },
        "biarc_style" : {
                'biarc0': str(inkex.Style({'stroke': '#88f', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'1'})),
                'biarc1': str(inkex.Style({'stroke': '#8f8', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'1'})),
                'line': str(inkex.Style({'stroke': '#f88', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'1'})),
                'area': str(inkex.Style({'stroke': '#777', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'0.1'})),
           },
        "biarc_style_dark" : {
                'biarc0': str(inkex.Style({'stroke': '#33a', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'1'})),
                'biarc1': str(inkex.Style({'stroke': '#3a3', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'1'})),
                'line': str(inkex.Style({'stroke': '#a33', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'1'})),
                'area': str(inkex.Style({'stroke': '#222', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'0.3'})),
           },
        "biarc_style_dark_area" : {
                'biarc0': str(inkex.Style({'stroke': '#33a', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'0.1'})),
                'biarc1': str(inkex.Style({'stroke': '#3a3', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'0.1'})),
                'line': str(inkex.Style({'stroke': '#a33', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'0.1'})),
                'area': str(inkex.Style({'stroke': '#222', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'0.3'})),
           },
        "biarc_style_i"  : {
                'biarc0': str(inkex.Style({'stroke': '#880', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'1'})),
                'biarc1': str(inkex.Style({'stroke': '#808', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'1'})),
                'line': str(inkex.Style({'stroke': '#088', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'1'})),
                'area': str(inkex.Style({'stroke': '#999', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'0.3'})),
           },
        "biarc_style_dark_i" : {
                'biarc0': str(inkex.Style({'stroke': '#dd5', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'1'})),
                'biarc1': str(inkex.Style({'stroke': '#d5d', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'1'})),
                'line': str(inkex.Style({'stroke': '#5dd', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'1'})),
                'area': str(inkex.Style({'stroke': '#aaa', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'0.3'})),
           },
        "biarc_style_lathe_feed" : {
                'biarc0': str(inkex.Style({'stroke': '#07f', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'.4'})),
                'biarc1': str(inkex.Style({'stroke': '#0f7', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'.4'})),
                'line': str(inkex.Style({'stroke': '#f44', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'.4'})),
                'area': str(inkex.Style({'stroke': '#aaa', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'0.3'})),
           },
        "biarc_style_lathe_passing feed" : {
                'biarc0': str(inkex.Style({'stroke': '#07f', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'.4'})),
                'biarc1': str(inkex.Style({'stroke': '#0f7', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'.4'})),
                'line': str(inkex.Style({'stroke': '#f44', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'.4'})),
                'area': str(inkex.Style({'stroke': '#aaa', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'0.3'})),
           },
        "biarc_style_lathe_fine feed" : {
                'biarc0': str(inkex.Style({'stroke': '#7f0', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'.4'})),
                'biarc1': str(inkex.Style({'stroke': '#f70', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'.4'})),
                'line': str(inkex.Style({'stroke': '#744', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'.4'})),
                'area': str(inkex.Style({'stroke': '#aaa', 'fill': 'none', "marker-end": "url(#DrawCurveMarker)", 'stroke-width':'0.3'})),
           },
        "area artefact": str(inkex.Style({'stroke': '#ff0000', 'fill': '#ffff00', 'stroke-width':'1'})),
        "area artefact arrow": str(inkex.Style({'stroke': '#ff0000', 'fill': '#ffff00', 'stroke-width':'1'})),
        "dxf_points": str(inkex.Style({"stroke": "#ff0000", "fill": "#ff0000"})),

    }



    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##     Gcode additional functions
    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####

def gcode_comment_str(s, replace_new_line = False):
    if replace_new_line:
        s = re.sub(r"[\n\r]+", ".", s)
    res = ""
    if s[-1] == "\n": s = s[:-1]
    for a in s.split("\n"):
        if a != "":
            res +=  "(" + re.sub(r"[\(\)\\\n\r]", ".", a) + ")\n"
        else:
            res +=  "\n"
    return res


    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##     Cubic Super Path additional functions
    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####


def csp_from_polyline(line) :
    return [ [ [point[:] for k in range(3) ] for point in subline ]  for subline in line ]

def csp_remove_zerro_segments(csp, tolerance = 1e-7):
    res = []
    for subpath in csp:
        if len(subpath) > 0:
            res.append([subpath[0]])
            for sp1,sp2 in zip(subpath,subpath[1:]):
                if point_to_point_d2(sp1[1],sp2[1])<=tolerance and point_to_point_d2(sp1[2],sp2[1])<=tolerance and point_to_point_d2(sp1[1],sp2[0])<=tolerance:
                    res[-1][-1][2] = sp2[2]
                else:
                    res[-1].append(sp2)
    return res


def point_inside_csp(p,csp, on_the_path = True) :
    # we'll do the raytracing and see how many intersections are there on the ray's way.
    # if number of intersections is even then point is outside.
    # ray will be x=p.x and y=>p.y
    # you can assing any value to on_the_path, by dfault if point is on the path
    # function will return thai it's inside the path.
    x,y = p
    ray_intersections_count = 0
    for subpath in csp:

        for i in range(1, len(subpath)):
            sp1, sp2 = subpath[i-1], subpath[i]
            ax,ay,bx,by,cx,cy,dx,dy = csp_parameterize(sp1,sp2)
            if  ax==0 and bx==0 and cx==0 and dx==x:
                #we've got a special case here
                b = csp_true_bounds( [[sp1,sp2]])
                if  b[1][1]<=y<=b[3][1]:
                    # points is on the path
                    return on_the_path
                else:
                    # we can skip this segment because it wont influence the answer.
                    pass
            else:
                for t in csp_line_intersection([x,y],[x,y+5],sp1,sp2):
                    if t == 0 or t == 1:
                        #we've got another special case here
                        x1,y1 = csp_at_t(sp1,sp2,t)
                        if y1==y:
                            # the point is on the path
                            return on_the_path
                        # if t == 0 we sould have considered this case previously.
                        if t == 1:
                            # we have to check the next segmant if it is on the same side of the ray
                            st_d = csp_normalized_slope(sp1,sp2,1)[0]
                            if st_d == 0: st_d = csp_normalized_slope(sp1,sp2,0.99)[0]

                            for j in range(1, len(subpath)+1):
                                if (i+j) % len(subpath) == 0 : continue # skip the closing segment
                                sp11,sp22 = subpath[(i-1+j) % len(subpath)], subpath[(i+j) % len(subpath)]
                                ax1,ay1,bx1,by1,cx1,cy1,dx1,dy1 = csp_parameterize(sp1,sp2)
                                if  ax1==0 and bx1==0 and cx1==0 and dx1==x: continue # this segment parallel to the ray, so skip it
                                en_d = csp_normalized_slope(sp11,sp22,0)[0]
                                if en_d == 0: en_d = csp_normalized_slope(sp11,sp22,0.01)[0]
                                if st_d*en_d <=0:
                                    ray_intersections_count += 1
                                    break
                    else:
                        x1,y1 = csp_at_t(sp1,sp2,t)
                        if y1==y:
                            # the point is on the path
                            return on_the_path
                        else:
                            if y1>y and 3*ax*t**2 + 2*bx*t + cx !=0: # if it's 0 the path only touches the ray
                                ray_intersections_count += 1
    return ray_intersections_count%2 == 1


def csp_close_all_subpaths(csp, tolerance = 0.000001):
    for i in range(len(csp)):
        if point_to_point_d2(csp[i][0][1] , csp[i][-1][1])> tolerance**2:
            csp[i][-1][2] = csp[i][-1][1][:]
            csp[i] += [ [csp[i][0][1][:] for j in range(3)] ]
        else:
            if csp[i][0][1] != csp[i][-1][1]:
                csp[i][-1][1] = csp[i][0][1][:]
    return csp


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 bound_to_bound_distance(sp1,sp2,sp3,sp4) :
    min_dist = 1e100
    max_dist = 0
    points1 = csp_segment_to_bez(sp1,sp2)
    points2 = csp_segment_to_bez(sp3,sp4)
    for i in range(4):
        for j in range(4):
            min_, max_ = line_to_line_min_max_distance_2(points1[i-1], points1[i], points2[j-1], points2[j])
            min_dist = min(min_dist,min_)
            max_dist = max(max_dist,max_)
            print_("bound_to_bound", min_dist, max_dist)
    return min_dist, max_dist


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_curvature_radius_at_t(sp1,sp2,t) :
    c = csp_curvature_at_t(sp1,sp2,t)
    if c == 0: return 1e100
    else: return 1/c


def csp_special_points(sp1,sp2) :
    # special points = curvature == 0
    ax,ay,bx,by,cx,cy,dx,dy = bezmisc.bezierparameterize((sp1[1],sp1[2],sp2[0],sp2[1]))
    a = 3*ax*by-3*ay*bx
    b = 3*ax*cy-3*cx*ay
    c = bx*cy-cx*by
    roots = cubic_solver(0, a, b, c)
    res = []
    for i in roots:
        if type(i) is complex and i.imag==0:
            i = i.real
        if type(i) is not complex and 0<=i<=1:
            res.append(i)
    return res


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_at_length(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_at_t(sp1,sp2,t)


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.01):
    bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
    return bezmisc.bezierlength(bez, tolerance)


def csplength(csp):
    total = 0
    lengths = []
    for sp in csp:
        for i in xrange(1,len(sp)):
            l = cspseglength(sp[i-1],sp[i])
            lengths.append(l)
            total += l
    return lengths, total


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 rebuild_csp (csp, segs, s=None):
    # rebuild_csp() adds to csp control points making it's segments looks like segs
    if s==None: s, l = csp_segments(csp)

    if len(s)>len(segs): return None
    segs = segs[:]
    segs.sort()
    for i in xrange(len(s)):
        d = None
        for j in xrange(len(segs)):
            d = min( [abs(s[i]-segs[j]),j], d) if d!=None else [abs(s[i]-segs[j]),j]
        del segs[d[1]]
    for i in xrange(len(segs)):
        for j in xrange(0,len(s)):
            if segs[i]<s[j]: break
        if s[j]-s[j-1] != 0:
            t = (segs[i] - s[j-1])/(s[j]-s[j-1])
            sp1,sp2,sp3 = csp_split(csp[j-1],csp[j], t)
            csp = csp[:j-1] + [sp1,sp2,sp3] + csp[j+1:]
            s = s[:j] + [ s[j-1]*(1-t)+s[j]*t   ] + s[j:]
    return csp, s


def csp_slope(sp1,sp2,t):
    bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
    return bezmisc.bezierslopeatt(bez,t)


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_seg_split(sp1,sp2, points):
    # points is float=t or list [t1, t2, ..., tn]
    if type(points) is float:
        points = [points]
    points.sort()
    res = [sp1,sp2]
    last_t = 0
    for t in points:
        if 1e-10<t<1.-1e-10:
            sp3,sp4,sp5 = csp_split(res[-2],res[-1], (t-last_t)/(1-last_t))
            last_t = t
            res[-2:] = [sp3,sp4,sp5]
    return res


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 arc_from_s_r_n_l(s,r,n,l) :
    if abs(n[0]**2+n[1]**2 - 1) > 1e-10: n = normalize(n)
    return arc_from_c_s_l([s[0]+n[0]*r, s[1]+n[1]*r],s,l)


def arc_from_c_s_l(c,s,l) :
    r = point_to_point_d(c,s)
    if r == 0: return []
    alpha = l/r
    cos_, sin_ = math.cos(alpha), math.sin(alpha)
    e = [ c[0] + (s[0]-c[0])*cos_ - (s[1]-c[1])*sin_, c[1] + (s[0]-c[0])*sin_ + (s[1]-c[1])*cos_]
    n = [c[0]-s[0],c[1]-s[1]]
    slope = rotate_cw(n) if l>0 else rotate_ccw(n)
    return csp_from_arc(s, e, c, r, slope)


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_simple_bound_to_point_distance(p, 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 math.sqrt(max(minx-p[0],p[0]-maxx,0)**2+max(miny-p[1],p[1]-maxy,0)**2)


def csp_point_inside_bound(sp1, sp2, p):
    bez = [sp1[1],sp1[2],sp2[0],sp2[1]]
    x,y = p
    c = 0
    #CLT added test of x in range
    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 csp_bound_to_point_distance(sp1, sp2, p):
    if csp_point_inside_bound(sp1, sp2, p):
        return 0.
    bez = csp_segment_to_bez(sp1,sp2)
    min_dist = 1e100
    for i in range(0,4):
        d = point_to_line_segment_distance_2(p, bez[i-1],bez[i])
        if d <= min_dist: min_dist = d
    return min_dist


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_reverse(csp) :
    for i in range(len(csp)):
        n = []
        for j in csp[i]:
            n = [  [j[2][:],j[1][:],j[0][:]]  ] + n
        csp[i] = n[:]
    return csp


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: #LT changed this from 1e-20, which caused problems
            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_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, prepend = False) :
    # Appends subpath with line or polyline.
    if len(points)>0:
        if not prepend:
            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] ]
        else:
            if len(subpath)>0:
                subpath[0][0] = subpath[0][1][:]
            if type(points[0]) == type([1,1]):
                for p in points:
                    subpath = [ [p[:],p[:],p[:]] ] + subpath
            else:
                subpath = [ [points,points,points] ] + subpath
    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(xxx,t):
    (x1,y1),(x2,y2) = xxx
    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]]


def bez_at_t(bez,t) :
    return csp_at_t([bez[0],bez[0],bez[1]],[bez[2],bez[3],bez[3]],t)


def bez_to_point_distance(bez,p,needed_dist=[0.,1e100]):
    # returns [d^2,t]
    return csp_seg_to_point_distance(bez_to_csp_segment(bez),p,needed_dist)


def bez_normalized_slope(bez,t):
    return csp_normalized_slope([bez[0],bez[0],bez[1]], [bez[2],bez[3],bez[3]],t)

    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ## Some vector functions
    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####

def normalize(xxx):
    (x,y) = xxx
    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 rotate_cw(d) :
    return [d[1],-d[0]]


def vectors_ccw(a,b):
    return a[0]*b[1]-b[0]*a[1] < 0

def vector_add(a,b) :
    return [a[0]+b[0],a[1]+b[1]]

def vector_mul(a,b) :
    return [a[0]*b,a[1]*b]


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 matrix_mul(a,b) :
    return [ [ sum([a[i][k]*b[k][j] for k in range(len(a[0])) ])   for j in range(len(b[0]))]   for i in range(len(a))]
    try :
        return [ [ sum([a[i][k]*b[k][j] for k in range(len(a[0])) ])   for j in range(len(b[0]))]   for i in range(len(a))]
    except :
        return None


def transpose(a) :
    try :
        return [ [ a[i][j] for i in range(len(a)) ] for j in range(len(a[0])) ]
    except :
        return None


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 get_text(node) :
    value = None
    if node.text!=None: value = value +"\n" + node.text if value != None else node.text
    for k in node:
        if k.tag == inkex.addNS('tspan','svg'):
            if k.text!=None: value = value +"\n" + k.text if value != None else k.text
    return value



def draw_text(text,x,y, group = None, style = None, font_size = 10, gcodetools_tag = None) :
    if style == None:
        style = "font-family:DejaVu Sans;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:DejaVu Sans;fill:#000000;fill-opacity:1;stroke:none;"
    style += "font-size:%fpx;"%font_size
    attributes = {          'x':    str(x),
                            inkex.addNS("space","xml"):"preserve",
                            'y':    str(y),
                            'style' : style
                        }
    if gcodetools_tag!=None:
        attributes["gcodetools"] = str(gcodetools_tag)

    if group == None:
        group = options.doc_root

    t = inkex.etree.SubElement( group, inkex.addNS('text','svg'), attributes)
    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 = str(s)

def draw_csp(csp, stroke = "#f00", fill = "none", comment = "", width = 0.354, group = None, style = None, gcodetools_tag = None) :
    if style == None:
        style = "fill:%s;fill-opacity:1;stroke:%s;stroke-width:%s"%(fill,stroke,width)
    attributes = {          'd':    cubicsuperpath.formatPath(csp),
                            'style' : style
                }
    if comment != '':
        attributes['comment'] = comment
    if group == None:
        group = options.doc_root

    return inkex.etree.SubElement( group, inkex.addNS('path','svg'), attributes)

def draw_pointer(x,color = "#f00", figure = "cross", group = None, comment = "", fill=None, width = .1, size = 10., text = None, font_size=None, pointer_type=None, attrib = None) :
    size = size/2
    if attrib == None: attrib = {}
    if pointer_type == None:
        pointer_type = "Pointer"
    attrib["gcodetools"] = pointer_type
    if group == None:
        group = options.self.current_layer
    if text != None:
        if font_size == None: font_size = 7
        group = inkex.etree.SubElement( group, inkex.addNS('g','svg'), {"gcodetools": pointer_type+" group"})
        draw_text(text,x[0]+size*2.2,x[1]-size, group = group, font_size = font_size)
    if figure  == "line":
        s = ""
        for i in range(1,len(x)/2):
            s+= " %s, %s " %(x[i*2],x[i*2+1])
        attrib.update({"d": "M %s,%s L %s"%(x[0],x[1],s), "style":"fill:none;stroke:%s;stroke-width:%f;"%(color,width),"comment":str(comment)})
        inkex.etree.SubElement( group, inkex.addNS('path','svg'), attrib)
    elif figure == "arrow":
        if fill == None: fill = "#12b3ff"
        fill_opacity = "0.8"
        d = "m %s,%s " % (x[0],x[1]) + re.sub("([0-9\-.e]+)",(lambda match: str(float(match.group(1))*size*2.)), "0.88464,-0.40404 c -0.0987,-0.0162 -0.186549,-0.0589 -0.26147,-0.1173 l 0.357342,-0.35625 c 0.04631,-0.039 0.0031,-0.13174 -0.05665,-0.12164 -0.0029,-1.4e-4 -0.0058,-1.4e-4 -0.0087,0 l -2.2e-5,2e-5 c -0.01189,0.004 -0.02257,0.0119 -0.0305,0.0217 l -0.357342,0.35625 c -0.05818,-0.0743 -0.102813,-0.16338 -0.117662,-0.26067 l -0.409636,0.88193 z")
        attrib.update({"d": d, "style":"fill:%s;stroke:none;fill-opacity:%s;"%(fill,fill_opacity),"comment":str(comment)})
        inkex.etree.SubElement( group, inkex.addNS('path','svg'), attrib)
    else:
        attrib.update({"d": "m %s,%s l %f,%f %f,%f %f,%f %f,%f , %f,%f"%(x[0],x[1], size,size, -2*size,-2*size, size,size, size,-size, -2*size,2*size ), "style":"fill:none;stroke:%s;stroke-width:%f;"%(color,width),"comment":str(comment)})
        inkex.etree.SubElement( group, inkex.addNS('path','svg'), attrib)


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_real(a,b,c,d):
    # returns only real roots of a cubic equation.
    roots = cubic_solver(a,b,c,d)
    res = []
    for root in roots:
        if type(root) is complex:
            if -1e-10<root.imag<1e-10:
                res.append(root.real)
        else:
            res.append(root)
    return res


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


class Arc():
    def __init__(self,st,end,c,a):
        self.st = P(st)
        self.end = P(end)
        self.c = P(c)
        self.r = (P(st)-P(c)).mag()
        self.a = ( (self.st-self.c).angle() - (self.end-self.c).angle() ) % math.pi2
        if a<0: self.a -= math.pi2

    def offset(self, r):
        if self.a>0:
            r += self.r
        else:
            r = self.r - r

        if self.r != 0:
            self.st = self.c + (self.st-self.c)*r/self.r
            self.end = self.c + (self.end-self.c)*r/self.r
            self.r = r

    def length(self):
        return abs(self.a*self.r)


    def draw(self, group, style, layer, transform, num = 0, reverse_angle = 1):
        st = P(gcodetools.transform(self.st.to_list(), layer, True))
        c = P(gcodetools.transform(self.c.to_list(), layer, True))
        a = self.a * reverse_angle
        r = (st-c)
        a_st = (math.atan2(r.x,-r.y) - math.pi/2) % (math.pi*2)
        r = r.mag()
        if a<0:
            a_end = a_st+a
            style = style['biarc%s'%(num%2)]
        else:
            a_end = a_st
            a_st = a_st+a
            style = style['biarc%s_r'%(num%2)]

        attr = {
                'style': style,
                 inkex.addNS('cx','sodipodi'):      str(c.x),
                 inkex.addNS('cy','sodipodi'):      str(c.y),
                 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",
                }
        if transform != []:
            attr["transform"] = transform
        inkex.etree.SubElement( group, inkex.addNS('path','svg'), attr)

    def intersect(self,b) :
        return []


class Line():
    def __init__(self,st,end):
        if st.__class__ == P:
            st = st.to_list()
        if end.__class__ == P:
            end = end.to_list()
        self.st = P(st)
        self.end = P(end)
        self.l = self.length()
        if self.l != 0:
            self.n = ((self.end-self.st)/self.l).ccw()
        else:
            self.n = [0,1]

    def offset(self, r):
        self.st -= self.n*r
        self.end -= self.n*r

    def l2(self): return (self.st-self.end).l2()
    def length(self): return (self.st-self.end).mag()

    def draw(self, group, style, layer, transform, num = 0, reverse_angle = 1):
        st = gcodetools.transform(self.st.to_list(), layer, True)
        end = gcodetools.transform(self.end.to_list(), layer, True)


        attr = {    'style': style['line'],
                    'd':'M %s,%s L %s,%s' % (st[0],st[1],end[0],end[1]),
                    "gcodetools": "Preview",
                }
        if transform != []:
            attr["transform"] = transform
        inkex.etree.SubElement( group, inkex.addNS('path','svg'),  attr)

    def intersect(self,b) :
        if b.__class__ == Line:
            if self.l < 10e-8 or b.l < 10e-8: return []
            v1 = self.end - self.st
            v2 = b.end - b.st
            x = v1.x*v2.y - v2.x*v1.y
            if x == 0:
                # lines are parallel
                res = []

                if (self.st.x-b.st.x)*v1.y - (self.st.y-b.st.y)*v1.x  == 0:
                    # lines are the same
                    if v1.x != 0:
                        if 0<=(self.st.x-b.st.x)/v2.x<=1:  res.append(self.st)
                        if 0<=(self.end.x-b.st.x)/v2.x<=1:  res.append(self.end)
                        if 0<=(b.st.x-self.st.x)/v1.x<=1:  res.append(b.st)
                        if 0<=(b.end.x-b.st.x)/v1.x<=1:  res.append(b.end)
                    else:
                        if 0<=(self.st.y-b.st.y)/v2.y<=1:  res.append(self.st)
                        if 0<=(self.end.y-b.st.y)/v2.y<=1:  res.append(self.end)
                        if 0<=(b.st.y-self.st.y)/v1.y<=1:  res.append(b.st)
                        if 0<=(b.end.y-b.st.y)/v1.y<=1:  res.append(b.end)
                return res
            else:
                t1 = ( -v1.x*(b.end.y-self.end.y) + v1.y*(b.end.x-self.end.x) ) / x
                t2 = ( -v1.y*(self.st.x-b.st.x) + v1.x*(self.st.y-b.st.y) ) / x

                gcodetools.error((x,t1,t2), "warning")
                if 0<=t1<=1 and 0<=t2<=1: return [ self.st+v1*t1 ]
                else: return []
        else: return []




class Biarc:
    def __init__(self, items=None):
        if items == None:
            self.items = []
        else:
            self.items = items

    def l(self) :
        return sum([i.length() for i in items])

    def close(self) :
        for subitems in self.items:
            if (subitems[0].st-subitems[-1].end).l2()>10e-16:
                subitems.append(Line(subitems[-1].end,subitems[0].st))

    def offset(self,r) :
        # offset each element
        self.close()
        for subitems in self.items:
            for item in subitems:
                item.offset(r)
        self.connect(r)

    def connect(self, r) :
        for subitems in self.items:
            for a,b in zip(subitems, subitems[1:]):
                i = a.intersect(b)
                for p in i:
                    draw_pointer(p.to_list())




    def clip_offset(self):
        pass

    def draw(self, layer, group=None, style=styles["biarc_style"]):
        global gcodetools
        gcodetools.set_markers()

        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:
            if "preview_groups" not in dir(options.self):
                gcodetools.preview_groups = { layer: inkex.etree.SubElement( gcodetools.layers[min(1,len(gcodetools.layers)-1)], inkex.addNS('g','svg'), {"gcodetools": "Preview group"} ) }
            elif layer not in gcodetools.preview_groups:
                gcodetools.preview_groups[layer] = inkex.etree.SubElement( gcodetools.layers[min(1,len(gcodetools.layers)-1)], inkex.addNS('g','svg'), {"gcodetools": "Preview group"})
            group = gcodetools.preview_groups[layer]

        transform = gcodetools.get_transforms(group)
        if transform != []:
            transform = gcodetools.reverse_transform(transform)
            transform = simpletransform.formatTransform(transform)

        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 = gcodetools.transform(a, layer, True), gcodetools.transform(b, layer, True), gcodetools.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


        num = 0
        for subitems in self.items:
            for item in subitems:
                num += 1
                #if num>1: break
                item.draw(group, style, layer, transform, num, reverse_angle)

    def from_old_style(self, curve) :
        #Crve defenitnion [start point, type = {'arc','line','move','end'}, arc center, arc angle, end point, [zstart, zend]]
        self.items = []
        for sp in curve:
            print_(sp)
            if sp[1] == 'move':
                self.items.append([])
            if sp[1] == 'arc':
                self.items[-1].append(Arc(sp[0],sp[4],sp[2],sp[3]))
            if sp[1] == 'line':
                self.items[-1].append(Line(sp[0],sp[4]))





    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##
    # ## 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"
        #draw_csp([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:
            #draw_csp([[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)
                #draw_csp([prev],"Blue")
                #draw_csp([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)
        #draw_csp([prev],"Blue")
        #draw_csp([arc],"Red")
        #draw_csp([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)):
    #   draw_csp([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)):
    #   draw_csp([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:
            draw_csp([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
    #draw_csp(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:
                draw_csp([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:
                draw_csp([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**2:
            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))

        l = (P0-P2).l2()
        if  l < EMC_TOLERANCE_EQUAL**2 or l<EMC_TOLERANCE_EQUAL**2 * R1.l2() /100:
            # arc should be straight otherwise it could be threated as full circle
            arc1 = [ sp1[1], 'line', 0, 0, [P2.x,P2.y], [z1,zm] ]
        else:
            arc1 = [ sp1[1], 'arc', [R1.x,R1.y], a1, [P2.x,P2.y], [z1,zm] ]

        l = (P4-P2).l2()
        if  l < EMC_TOLERANCE_EQUAL**2 or l<EMC_TOLERANCE_EQUAL**2 * R2.l2() /100:
            # arc should be straight otherwise it could be threated as full circle
            arc2 = [ [P2.x,P2.y], 'line', 0, 0, [P4.x,P4.y], [zm,z2] ]
        else:
            arc2 = [ [P2.x,P2.y], 'arc', [R2.x,R2.y], a2, [P4.x,P4.y], [zm,z2] ]

        return [ arc1, arc2 ]


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,
                    "regex"         : self.re_sub_on_gcode_lines
                    }


    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, parameters):
        gcode = self.gcode.split("\n")
        self.gcode = ""
        try :
            for line in gcode:
                self.gcode += eval( "re.sub(%s,line)"%parameters) +"\n"

        except Exception as ex :
            self.error("Bad parameters for regexp. They should be as re.sub pattern and replacement parameters! For example: r\"G0(\d)\", r\"G\\1\" \n(Parameters: '%s')\n %s"%(parameters, ex), "error")


    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) :
        self.polygon = [
                [
                    [point[0]*cos - point[1]*sin,point[0]*sin + point[1]*cos] for point in subpoly
                ]
                for subpoly in self.polygon
            ]


    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, group = None) :
        csp = [csp_subpath_line_to([],poly+[poly[0]]) for poly in self.polygon]
        draw_csp( csp, color=color,width=width, group = group)



    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:
                pass
#               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):
        time_ = time.time()
        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( self.polygons[spiece[0][0]].polygon[:])
        poly.rotate(spiece[0][1]*math.pi2)
        surface  = Polygon(poly.polygon)
        for p in spiece[1:]:
            poly = Polygon(self.polygons[p[0]].polygon[:])
            c = surface.centroid()
            surface.move(-c[0],-c[1])
            c1 = poly.centroid()
            poly.move(-c1[0],-c1[1])
            poly.rotate(p[1]*math.pi2+p[2]*math.pi2)
            surface.rotate(p[2]*math.pi2)
            poly.drop_down(surface)
            surface.add(poly)
            surface.rotate(-p[2]*math.pi2)
        return surface


    def test_inline(self) :
        # ##
        # ## Fast test function using weave's from scipy inline function
        # ##
        try :
            converters is None
        except :
            try:
                from scipy import weave
                from scipy.weave import converters
            except:
                options.self.error("For this function Scipy is needed. See http://www.cnc-club.ru/gcodetools for details.","error")

        # Prepare vars
        poly_, subpoly_, points_ = [], [], []
        for  poly in self.polygons:
            p = poly.polygon
            poly_ += [len(subpoly_), len(subpoly_)+len(p)*2]
            for subpoly in p:
                subpoly_ += [len(points_), len(points_)+len(subpoly)*2+2]
                for point in subpoly:
                    points_ += point
                points_ += subpoly[0] # Close subpolygon

        test_ = []
        population_ = []
        for spiece in self.population:
            test_.append( spiece[0] if spiece[0] != None else -1)
            for sp in spiece[1]:
                population_ += sp

        lp_, ls_, l_, lt_ = len(poly_), len(subpoly_), len(points_), len(test_)

        f = open('inline_test.c', 'r')
        code = f.read()
        f.close()

        f = open('inline_test_functions.c', 'r')
        functions = f.read()
        f.close()

        stdout_ = sys.stdout
        s = ''
        sys.stdout = s

        test = weave.inline(
                            code,
                            ['points_','subpoly_','poly_', 'lp_', 'ls_', 'l_', 'lt_','test_', 'population_'],
                            compiler='gcc',
                            support_code = functions,
                           )
        if s!='': options.self.error(s,"warning")
        sys.stdout = stdout_

        for i in range(len(test_)):
            self.population[i][0] = test_[i]




        #surface.draw()


    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##
    # ##     Gcodetools class
    # ##
    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####

class Gcodetools(inkex.Effect):

    def export_gcode(self,gcode, no_headers = False) :
        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)

        if not no_headers:
            postprocessor.gcode = self.header + postprocessor.gcode + self.footer

        f = open(self.options.directory+self.options.file, "w")
        f.write(postprocessor.gcode)
        f.close()


    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##     In/out paths:
    # ##     TODO move it to the bottom
    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    def plasma_prepare_path(self) :

        def add_arc(sp1,sp2,end = False,l=10.,r=10.) :
            if not end:
                n = csp_normalized_normal(sp1,sp2,0.)
                return csp_reverse([arc_from_s_r_n_l(sp1[1],r,n,-l)])[0]
            else:
                n = csp_normalized_normal(sp1,sp2,1.)
                return arc_from_s_r_n_l(sp2[1],r,n,l)

        def add_normal(sp1,sp2,end = False,l=10.,r=10.) :
            # r is needed only for be compatible with add_arc
            if not end:
                n = csp_normalized_normal(sp1,sp2,0.)
                p = [n[0]*l+sp1[1][0],n[1]*l+sp1[1][1]]
                return csp_subpath_line_to([], [p,sp1[1]])
            else:
                n = csp_normalized_normal(sp1,sp2,1.)
                p = [n[0]*l+sp2[1][0],n[1]*l+sp2[1][1]]
                return csp_subpath_line_to([], [sp2[1],p])

        def add_tangent(sp1,sp2,end = False,l=10.,r=10.) :
            # r is needed only for be compatible with add_arc
            if not end:
                n = csp_normalized_slope(sp1,sp2,0.)
                p = [-n[0]*l+sp1[1][0],-n[1]*l+sp1[1][1]]
                return csp_subpath_line_to([], [p,sp1[1]])
            else:
                n = csp_normalized_slope(sp1,sp2,1.)
                p = [n[0]*l+sp2[1][0],n[1]*l+sp2[1][1]]
                return csp_subpath_line_to([], [sp2[1],p])

        if not self.options.in_out_path and not self.options.plasma_prepare_corners and self.options.in_out_path_do_not_add_reference_point:
            self.error("Warning! Extenstion is not said to do anything! Enable one of Create in-out paths or Prepare corners checkboxes or disable Do not add in-out referense point!")
            return

        # Add in-out-reference point if there is no one yet.
        if ( (len(self.in_out_reference_points)==0 and self.options.in_out_path
            or not self.options.in_out_path and not self.options.plasma_prepare_corners)
             and not self.options.in_out_path_do_not_add_reference_point) :
                    self.options.orientation_points_count = "in-out reference point"
                    self.orientation()

        if self.options.in_out_path or self.options.plasma_prepare_corners:
            self.set_markers()
            add_func = {"Round":add_arc, "Perpendicular": add_normal, "Tangent": add_tangent}[self.options.in_out_path_type]
            if self.options.in_out_path_type == "Round" and self.options.in_out_path_len > self.options.in_out_path_radius*3/2*math.pi:
                self.error("In-out len is to big for in-out radius will cropp it to be r*3/2*pi!", "warning")

            if self.selected_paths == {} and self.options.auto_select_paths:
                self.selected_paths = self.paths
                self.error(_("No paths are selected! Trying to work on all available paths."),"warning")

            if self.selected_paths == {}:
                self.error(_("Noting is selected. Please select something."),"warning")
            a = self.options.plasma_prepare_corners_tolerance
            corner_tolerance = cross([1.,0.], [math.cos(a),math.sin(a)])

            for layer in self.layers:
                if layer in self.selected_paths:
                    max_dist =  self.transform_scalar(self.options.in_out_path_point_max_dist, layer, reverse=True)
                    l =         self.transform_scalar(self.options.in_out_path_len, layer, reverse=True)
                    plasma_l =  self.transform_scalar(self.options.plasma_prepare_corners_distance, layer, reverse=True)
                    r =         self.transform_scalar(self.options.in_out_path_radius, layer, reverse=True)
                    l = min(l,r*3/2*math.pi)

                    for path in self.selected_paths[layer]:
                        csp = self.apply_transforms( path, cubicsuperpath.parsePath(path.get("d")))
                        csp = csp_remove_zerro_segments(csp)
                        res = []

                        for subpath in csp:
                        # Find closes point to in-out reference point
                        # If subpath is open skip this step
                            if self.options.in_out_path:
                                # split and reverse path for further add in-out points
                                if point_to_point_d2(subpath[0][1], subpath[-1][1]) < 1.e-10:
                                    d = [1e100,1,1,1.]
                                    for p in self.in_out_reference_points:
                                        d1 = csp_to_point_distance([subpath], p, dist_bounds = [0,max_dist], tolerance=.01)
                                        if d1[0] < d[0]:
                                            d = d1[:]
                                            p_ = p
                                    if d[0] < max_dist**2:
                                        # Lets find is there any angles near this point to put in-out path in
                                        # the angle if it's possible
                                        # remove last node to make iterations easier
                                        subpath[0][0] = subpath[-1][0]
                                        del subpath[-1]
                                        max_cross = [-1e100, None]
                                        for j in range(len(subpath)):
                                            sp1,sp2,sp3 = subpath[j-2],subpath[j-1],subpath[j]
                                            if point_to_point_d2(sp2[1],p_)<max_dist**2:
                                                s1,s2 = csp_normalized_slope(sp1,sp2,1.), csp_normalized_slope(sp2,sp3,0.)
                                                max_cross = max(max_cross,[cross(s1,s2),j-1])
                                        # return back last point
                                        subpath.append(subpath[0])
                                        if max_cross[1] !=None  and max_cross[0]>corner_tolerance:
                                            # there's an angle near the point
                                            j = max_cross[1]
                                            if j<0: j -= 1
                                            if j!=0:
                                                subpath = csp_concat_subpaths(subpath[j:],subpath[:j+1])
                                        else:
                                            # have to cut path's segment
                                            d,i,j,t = d
                                            sp1,sp2,sp3 = csp_split(subpath[j-1],subpath[j],t)
                                            subpath = csp_concat_subpaths([sp2,sp3], subpath[j:], subpath[:j], [sp1,sp2])

                            if self.options.plasma_prepare_corners:
                                # prepare corners
                                # find corners and add some nodes
                                # corner at path's start/end is ignored
                                res_ = [subpath[0]]
                                for sp2, sp3 in zip(subpath[1:],subpath[2:]):
                                    sp1 = res_[-1]
                                    s1,s2 = csp_normalized_slope(sp1,sp2,1.), csp_normalized_slope(sp2,sp3,0.)
                                    if cross(s1,s2) > corner_tolerance:
                                        # got a corner to process
                                        S1,S2 = P(s1),P(s2)
                                        N = (S1-S2).unit()*plasma_l
                                        SP2= P(sp2[1])
                                        P1 = (SP2 + N)
                                        res_ += [
                                                    [sp2[0],sp2[1],  (SP2+S1*plasma_l).to_list() ],
                                                    [ (P1-N.ccw()/2 ).to_list(), P1.to_list(), (P1+N.ccw()/2).to_list()],
                                                    [(SP2-S2*plasma_l).to_list(), sp2[1],sp2[2]]
                                                ]
                                    else:
                                        res_ += [sp2]
                                res_ += [sp3]
                                subpath = res_
                            if self.options.in_out_path:
                                # finally add let's add in-out paths...
                                subpath = csp_concat_subpaths(
                                                    add_func(subpath[0],subpath[1],False,l,r),
                                                    subpath,
                                                    add_func(subpath[-2],subpath[-1],True,l,r)
                                                   )


                            res += [ subpath ]


                        if self.options.in_out_path_replace_original_path:
                            path.set("d", cubicsuperpath.formatPath( self.apply_transforms(path,res,True) ))
                        else:
                            draw_csp(res, width=1, style=styles["in_out_path_style"])

    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##     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 algorithm start at %s"%(time_))
        start_time = time.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 = -1
        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)
            print_("Populate done at %s"%(time.time()-time_))
            """
            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)
            """
            if self.options.arrangement_inline_test:
                population.test_inline()
            else:
                population.test(population.test_spiece_centroid)

            print_("Test done at %s"%(time.time()-time_))
            draw_new_champ = False
            print_()


            if population.population[0][0]!= last_champ:
                draw_new_champ = True
                improve = last_champ-population.population[0][0]
                last_champ = population.population[0][0]*1


            print_("Cicle %s done in %s"%(i,time.time()-time_))
            time_ = time.time()
            print_("%s incests been found"%population.inc)
            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\nSquare improvement = %f\nTime from start = %f"%(i,(b[2]-b[0])*(b[3]-b[1]),improve,time.time()-start_time),x,y-50)
                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.add_option("-d", "--directory",                   action="store", type=str,      dest="directory", default="/home/",                 help="Directory for gcode file")
        self.add_option("-f", "--filename",                    action="store", type=str,      dest="file", default="-1.0",                        help="File name")
        self.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.add_option("",   "--Zscale",                      action="store", type=float,       dest="Zscale", default="1.0",                       help="Scale factor Z")
        self.add_option("",   "--Zoffset",                     action="store", type=float,       dest="Zoffset", default="0.0",                      help="Offset along Z")
        self.add_option("-s", "--Zsafe",                       action="store", type=float,       dest="Zsafe", default="0.5",                        help="Z above all obstacles")
        self.add_option("-z", "--Zsurface",                    action="store", type=float,       dest="Zsurface", default="0.0",                     help="Z of the surface")
        self.add_option("-c", "--Zdepth",                      action="store", type=float,       dest="Zdepth", default="-0.125",                    help="Z depth of cut")
        self.add_option("",   "--Zstep",                       action="store", type=float,       dest="Zstep", default="-0.125",                     help="Z step of cutting")
        self.add_option("-p", "--feed",                        action="store", type=float,       dest="feed", default="4.0",                         help="Feed rate in unit/min")

        self.add_option("",   "--biarc-tolerance",             action="store", type=float,       dest="biarc_tolerance", default="1",                help="Tolerance used when calculating biarc interpolation.")
        self.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.add_option("",   "--path-to-gcode-order",         action="store", type=str,      dest="path_to_gcode_order", default="path by path", help="Defines cutting order path by path or layer by layer.")
        self.add_option("",   "--path-to-gcode-depth-function",action="store", type=str,      dest="path_to_gcode_depth_function", default="zd",  help="Path to gcode depth function.")
        self.add_option("",   "--path-to-gcode-sort-paths",    action="store", type="inkbool",     dest="path_to_gcode_sort_paths", default=True,      help="Sort paths to reduse rapid distance.")
        self.add_option("",   "--comment-gcode",               action="store", type=str,      dest="comment_gcode", default="",                   help="Comment Gcode")
        self.add_option("",   "--comment-gcode-from-properties",action="store", type="inkbool",    dest="comment_gcode_from_properties", default=False,help="Get additional comments from Object Properties")



        self.add_option("",   "--tool-diameter",               action="store", type=float,       dest="tool_diameter", default="3",                  help="Tool diameter used for area cutting")
        self.add_option("",   "--max-area-curves",             action="store", type=int,         dest="max_area_curves", default="100",              help="Maximum area curves for each area")
        self.add_option("",   "--area-inkscape-radius",        action="store", type=float,       dest="area_inkscape_radius", default="0",           help="Area curves overlaping (depends on tool diameter [0,0.9])")
        self.add_option("",   "--area-tool-overlap",           action="store", type=float,       dest="area_tool_overlap", default="-10",            help="Radius for preparing curves using inkscape")
        self.add_option("",   "--unit",                        action="store", type=str,      dest="unit", default="G21 (All units in mm)",       help="Units")
        self.add_option("",   "--active-tab",                  action="store", type=str,      dest="active_tab", default="",                      help="Defines which tab is active")

        self.add_option("",   "--area-fill-angle",             action="store", type=float,       dest="area_fill_angle", default="0",                    help="Fill area with lines heading this angle")
        self.add_option("",   "--area-fill-shift",             action="store", type=float,       dest="area_fill_shift", default="0",                    help="Shift the lines by tool d * shift")
        self.add_option("",   "--area-fill-method",            action="store", type=str,      dest="area_fill_method", default="zig-zag",                 help="Filling method either zig-zag or spiral")

        self.add_option("",   "--area-find-artefacts-diameter",action="store", type=float,       dest="area_find_artefacts_diameter", default="1",                   help="Artefacts seeking radius")
        self.add_option("",   "--area-find-artefacts-action",  action="store", type=str,      dest="area_find_artefacts_action", default="mark with an arrow",    help="Artefacts action type")

        self.add_option("",   "--auto_select_paths",           action="store", type="inkbool",     dest="auto_select_paths", default=True,             help="Select all paths if nothing is selected.")

        self.add_option("",   "--loft-distances",              action="store", type=str,      dest="loft_distances", default="10",                help="Distances between paths.")
        self.add_option("",   "--loft-direction",              action="store", type=str,      dest="loft_direction", default="crosswise",         help="Direction of loft's interpolation.")
        self.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.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.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.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.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.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.add_option("",   "--engraving-cutter-shape-function",action="store", type=str,   dest="engraving_cutter_shape_function", default="w",        help="Cutter shape function z(w). Ex. cone: w. ")

        self.add_option("",   "--lathe-width",                 action="store", type=float,       dest="lathe_width", default=10.,                            help="Lathe width")
        self.add_option("",   "--lathe-fine-cut-width",        action="store", type=float,       dest="lathe_fine_cut_width", default=1.,                    help="Fine cut width")
        self.add_option("",   "--lathe-fine-cut-count",        action="store", type=int,         dest="lathe_fine_cut_count", default=1.,                    help="Fine cut count")
        self.add_option("",   "--lathe-create-fine-cut-using", action="store", type=str,      dest="lathe_create_fine_cut_using", default="Move path",            help="Create fine cut using")
        self.add_option("",   "--lathe-x-axis-remap",          action="store", type=str,      dest="lathe_x_axis_remap", default="X",                     help="Lathe X axis remap")
        self.add_option("",   "--lathe-z-axis-remap",          action="store", type=str,      dest="lathe_z_axis_remap", default="Z",                     help="Lathe Z axis remap")

        self.add_option("",   "--lathe-rectangular-cutter-width",action="store", type=float,     dest="lathe_rectangular_cutter_width", default="4",     help="Rectangular cutter width")

        self.add_option("",   "--create-log",                  action="store", type="inkbool",     dest="log_create_log", default=False,               help="Create log files")
        self.add_option("",   "--log-filename",                action="store", type=str,      dest="log_filename", default='',                    help="Create log files")

        self.add_option("",   "--orientation-points-count",    action="store", type=str,      dest="orientation_points_count", default="2",           help="Orientation points count")
        self.add_option("",   "--tools-library-type",          action="store", type=str,      dest="tools_library_type", default='cylinder cutter',   help="Create tools definition")

        self.add_option("",   "--dxfpoints-action",            action="store", type=str,      dest="dxfpoints_action", default='replace',         help="dxfpoint sign toggle")

        self.add_option("",   "--help-language",               action="store", type=str,      dest="help_language", default='http://www.cnc-club.ru/forum/viewtopic.php?f=33&t=35',   help="Open help page in webbrowser.")

        self.add_option("",   "--offset-radius",               action="store", type=float,       dest="offset_radius", default=10.,      help="Offset radius")
        self.add_option("",   "--offset-step",                 action="store", type=float,       dest="offset_step", default=10.,        help="Offset step")
        self.add_option("",   "--offset-draw-clippend-path",   action="store", type="inkbool",     dest="offset_draw_clippend_path", default=False,        help="Draw clipped path")
        self.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.add_option("",   "--arrangement-material-width",  action="store", type=float,       dest="arrangement_material_width", default=500,     help="Materials width for arrangement")
        self.add_option("",   "--arrangement-population-count",action="store", type=int,         dest="arrangement_population_count", default=100,   help="Genetic algorithm populations count")
        self.add_option("",   "--arrangement-inline-test",     action="store", type="inkbool",     dest="arrangement_inline_test", default=False,  help="Use C-inline test (some additional packets will be needed)")


        self.add_option("",   "--postprocessor",               action="store", type=str,      dest="postprocessor", default='',           help="Postprocessor command.")
        self.add_option("",   "--postprocessor-custom",        action="store", type=str,      dest="postprocessor_custom", default='',    help="Postprocessor custom command.")

        self.add_option("",   "--graffiti-max-seg-length",     action="store", type=float,       dest="graffiti_max_seg_length", default=1., help="Graffiti maximum segment length.")
        self.add_option("",   "--graffiti-min-radius",         action="store", type=float,       dest="graffiti_min_radius", default=10.,    help="Graffiti minimal connector's radius.")
        self.add_option("",   "--graffiti-start-pos",          action="store", type=str,      dest="graffiti_start_pos", default="(0;0)", help="Graffiti Start position (x;y).")
        self.add_option("",   "--graffiti-create-linearization-preview",   action="store", type="inkbool",     dest="graffiti_create_linearization_preview", default=True, help="Graffiti create linearization preview.")
        self.add_option("",   "--graffiti-create-preview",     action="store", type="inkbool",     dest="graffiti_create_preview", default=True,   help="Graffiti create preview.")
        self.add_option("",   "--graffiti-preview-size",       action="store", type=int,         dest="graffiti_preview_size", default=800,  help="Graffiti preview's size.")
        self.add_option("",   "--graffiti-preview-emmit",      action="store", type=int,         dest="graffiti_preview_emmit", default=800, help="Preview's paint emmit (pts/s).")


        self.add_option("",   "--in-out-path",                 action="store", type="inkbool",     dest="in_out_path", default=True,           help="Create in-out paths")
        self.add_option("",   "--in-out-path-do-not-add-reference-point",  action="store", type="inkbool", dest="in_out_path_do_not_add_reference_point", default=False,   help="Just add reference in-out point")
        self.add_option("",   "--in-out-path-point-max-dist",  action="store", type=float,       dest="in_out_path_point_max_dist", default=10., help="In-out path max distance to reference point")
        self.add_option("",   "--in-out-path-type",            action="store", type=str,      dest="in_out_path_type", default="Round",   help="In-out path type")
        self.add_option("",   "--in-out-path-len",             action="store", type=float,       dest="in_out_path_len", default=10.,        help="In-out path length")
        self.add_option("",   "--in-out-path-replace-original-path",action="store", type="inkbool", dest="in_out_path_replace_original_path", default=False,   help="Replace original path")
        self.add_option("",   "--in-out-path-radius",          action="store", type=float,       dest="in_out_path_radius", default=10.,     help="In-out path radius for round path")

        self.add_option("",   "--plasma-prepare-corners",      action="store", type="inkbool",     dest="plasma_prepare_corners", default=True,    help="Prepare corners")
        self.add_option("",   "--plasma-prepare-corners-distance", action="store", type=float,   dest="plasma_prepare_corners_distance", default=10.,help="Stepout distance for corners")
        self.add_option("",   "--plasma-prepare-corners-tolerance", action="store", type=float,  dest="plasma_prepare_corners_tolerance", default=10.,help="Maximum angle for corner (0-180 deg)")

        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


    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##     Draw csp
    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####

    def draw_csp(self, csp, layer=None, group=None, fill='none', stroke='#178ade', width=0.354, style=None):
        if layer!=None:
            csp = self.transform_csp(csp,layer,reverse=True)
        if group==None and layer==None:
            group = self.document.getroot()
        elif group==None and layer!=None:
            group = layer
        csp = self.apply_transforms(group,csp, reverse=True)
        if style!=None:
            return draw_csp(csp, group=group, style=style)
        else:
            return draw_csp(csp, group=group, fill=fill, stroke=stroke, width=width)


    def draw_curve(self, curve, layer, group=None, style=styles["biarc_style"]):
        self.set_markers()

        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:
            if "preview_groups" not in dir(self):
                self.preview_groups = { layer: inkex.etree.SubElement( self.layers[min(1,len(self.layers)-1)], inkex.addNS('g','svg'), {"gcodetools": "Preview group"} ) }
            elif layer not in self.preview_groups:
                self.preview_groups[layer] = inkex.etree.SubElement( self.layers[min(1,len(self.layers)-1)], inkex.addNS('g','svg'), {"gcodetools": "Preview group"})
            group = self.preview_groups[layer]

        s, arcn = '', 0

        transform = self.get_transforms(group)
        if transform != []:
            transform = self.reverse_transform(transform)
            transform = simpletransform.formatTransform(transform)

        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':
                    attr = {    'style': style['line'],
                                'd':'M %s,%s L %s,%s' % (s[0][0], s[0][1], si[0][0], si[0][1]),
                                "gcodetools": "Preview",
                            }
                    if transform != []:
                        attr["transform"] = transform
                    inkex.etree.SubElement( group, inkex.addNS('path','svg'),  attr)
                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)]

                    attr = {
                            '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",
                            }

                    if transform != []:
                        attr["transform"] = transform
                    inkex.etree.SubElement( group, inkex.addNS('path','svg'), attr)
            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 directory: '%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

        if self.options.directory[-1] not in ["/","\\"]:
            if "\\" in self.options.directory:
                self.options.directory += "\\"
            else:
                self.options.directory += "/"

        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.
    # ##
    # ##     Curve definition [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]
        g = ""

        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)

        if tool != self.last_used_tool:
            g += ( "(Change tool to %s)\n" % re.sub("\"'\(\)\\\\"," ",tool["name"]) ) + tool["tool change gcode"] + "\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 +"(Penetrate)\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 + "(Penetrate)\n"
                if (r[0]**2 + r[1]**2)>self.options.min_arc_radius**2:
                    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 reverse_transform(self,transform):
        trans = numpy.array(transform + [[0,0,1]])
        if numpy.linalg.det(trans)!=0:
            trans = numpy.linalg.inv(trans).tolist()[:2]
            return trans
        else:
         return transform


    def apply_transforms(self,g,csp, reverse=False):
        trans = self.get_transforms(g)
        if trans != []:
            if not reverse:
                simpletransform.applyTransformToPath(trans, csp)
            else:
                simpletransform.applyTransformToPath(self.reverse_transform(trans), csp)
        return csp


    def transform_scalar(self,x,layer,reverse=False):
        return self.transform([x,0],layer,reverse)[0] - self.transform([0,0],layer,reverse)[0]


    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]]
                self.Zcoordinates[layer] = self.Zcoordinates[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 should 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 should 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
                        orientation_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
                        Continue
                        """
        errors = """
                        Error
                        wrong_orientation_points
                        area_tools_diameter_error
                        no_tool_error
                        active_layer_already_has_tool
                        active_layer_already_has_orientation_points
                    """
        s = str(s)
        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()


    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##     Set markers
    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    def set_markers(self) :
        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":"-4","refY":"-1.687441","style":"overflow:visible"})
            inkex.etree.SubElement( marker, inkex.addNS("path","svg"),

                    {   "d":"   m -4.588864,-1.687441 0.0,0.0 L -9.177728,0.0 c 0.73311,-0.996261 0.728882,-2.359329 0.0,-3.374882",
                        "style": "fill:#000044; fill-rule:evenodd;stroke:none;" }
               )

        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":"-4","refY":"-1.687441","style":"overflow:visible"})
            inkex.etree.SubElement( marker, inkex.addNS("path","svg"),
                    {   "d":"m -4.588864,-1.687441 0.0,0.0 L -9.177728,0.0 c 0.73311,-0.996261 0.728882,-2.359329 0.0,-3.374882",
                        "style": "fill:#000044; fill-rule:evenodd;stroke:none;" }
               )

        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":"4","refY":"-1.687441","style":"overflow:visible"})
            inkex.etree.SubElement( marker, inkex.addNS("path","svg"),
                    {   "d":"m 4.588864,-1.687441 0.0,0.0 L 9.177728,0.0 c -0.73311,-0.996261 -0.728882,-2.359329 0.0,-3.374882",
                        "style": "fill:#000044; fill-rule:evenodd;stroke:none;" }
               )

        if "InOutPathMarker" 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":"InOutPathMarker","orient":"auto","refX":"-4","refY":"-1.687441","style":"overflow:visible"})
            inkex.etree.SubElement( marker, inkex.addNS("path","svg"),
                    {   "d":"m -4.588864,-1.687441 0.0,0.0 L -9.177728,0.0 c 0.73311,-0.996261 0.728882,-2.359329 0.0,-3.374882",
                        "style": "fill:#0072a7; fill-rule:evenodd;stroke:none;" }
               )


    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##     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.graffiti_reference_points = {}
        self.layers = [self.document.getroot()]
        self.Zcoordinates = {}
        self.transform_matrix = {}
        self.transform_matrix_reverse = {}
        self.Zauto_scale = {}
        self.in_out_reference_points = []
        self.my3Dlayer = None

        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':
                    if i.get(inkex.addNS('label','inkscape')) == '3D':
                        self.my3Dlayer=i
                    else:
                        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")

                #Need to recognise old files ver 1.6.04 and earlier
                elif i.get("gcodetools") == "Gcodetools tool definition" or 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.get("gcodetools") == "Gcodetools graffiti reference point":
                    point = self.get_graffiti_reference_points(i)
                    if point != []:
                        self.graffiti_reference_points[layer] = self.graffiti_reference_points[layer]+[point[:]] if layer in self.graffiti_reference_points else [point]
                    else:
                        self.error(_("Warning! Found bad graffiti reference point in '%s' layer. Resulting Gcode could be corrupt!") % layer.get(inkex.addNS('label','inkscape')), "bad_orientation_points_in_some_layers")

                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.svg.selected:
                            self.selected_paths[layer] = self.selected_paths[layer] + [i] if layer in self.selected_paths else [i]

                elif i.get("gcodetools") == "In-out reference point group":
                    items_ = i.getchildren()
                    items_.reverse()
                    for j in items_:
                        if j.get("gcodetools") == "In-out reference point":
                            self.in_out_reference_points.append( self.apply_transforms(j,cubicsuperpath.parsePath(j.get("d")))[0][0][1])


                elif i.tag == inkex.addNS("g",'svg'):
                    recursive_search(i,layer, (i.get("id") in self.svg.selected))

                elif i.get("id") in self.svg.selected:
# xgettext:no-pango-format
                    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())

        if len(self.layers) == 1:
            self.error(_("Document has no layers! Add at least one layer using layers panel (Ctrl+Shift+L)"),"Error")
        root = self.document.getroot()

        if  root in self.selected_paths or root in self.paths:
            self.error(_("Warning! There are some paths in the root of the document, but not in any layer! Using bottom-most layer for them."), "tools_warning")

        if  root in self.selected_paths:
            if self.layers[-1] in self.selected_paths:
                self.selected_paths[self.layers[-1]] += self.selected_paths[root][:]
            else:
                self.selected_paths[self.layers[-1]] = self.selected_paths[root][:]
            del self.selected_paths[root]

        if root in self.paths:
            if self.layers[-1] in self.paths:
                self.paths[self.layers[-1]] += self.paths[root][:]
            else:
                self.paths[self.layers[-1]] = self.paths[root][:]
            del self.paths[root]


    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*',get_text(node))
                    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_graffiti_reference_points(self,g):
            point = [[], '']
            for node in g:
                if node.get('gcodetools') == "Gcodetools graffiti reference point arrow":
                    point[0] = self.apply_transforms(node,cubicsuperpath.parsePath(node.get("d")))[0][0][1]
                if node.get('gcodetools') == "Gcodetools graffiti reference point text":
                    point[1] = get_text(node)
            if point[0]!=[] and point[1]!='': return point
            else: return []


    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:
                    #need to recognise old tools from ver 1.6.04
                    if j.get("gcodetools") == "Gcodetools tool definition field name" or j.get("gcodetools") == "Gcodetools tool defention field name":
                        key = get_text(j)
                    if j.get("gcodetools") == "Gcodetools tool definition field value" or j.get("gcodetools") == "Gcodetools tool defention field value":
                        value = get_text(j)
                        if value == "(None)": value = ""
                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) :
        from functools import partial
        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 sort_lines(lines):
            if len(lines) == 0: return []
            lines = [ [key]+lines[key] for key in range(len(lines))]
            keys = [0]
            end_point = lines[0][3:]
            print_("!!!",lines,"\n",end_point)
            del lines[0]
            while len(lines)>0:
                dist = [ [point_to_point_d2(end_point,lines[i][1:3]),i] for i in range(len(lines))]
                i = min(dist)[1]
                keys.append(lines[i][0])
                end_point = lines[i][3:]
                del lines[i]
            return keys

        def sort_curves(curves):
            lines = []
            for curve in curves:
                lines += [curve[0][0][0] + curve[-1][-1][0]]
            return sort_lines(lines)

        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

        def get_path_properties(node, recursive=True, tags={inkex.addNS('desc','svg'):"Description",inkex.addNS('title','svg'):"Title"} ) :
            res = {}
            done = False
            root = self.document.getroot()
            while not done and node != root :
                for i in node.getchildren():
                    if i.tag in tags:
                        res[tags[i.tag]] = i.text
                    done = True
                node =  node.getparent()
            return res

        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))
        colors = {}
        for layer in self.layers:
            if layer in paths:
                print_(("layer",layer))
                # transform simple path to get all var about orientation
                self.transform_csp([ [ [[0,0],[0,0],[0,0]],  [[0,0],[0,0],[0,0]] ] ], layer)

                self.set_tool(layer)
                curves = []
                dxfpoints = []

                try :
                    depth_func = eval('lambda c,d,s: ' + self.options.path_to_gcode_depth_function.strip('"'))
                except:
                    self.error("Bad depth function! Enter correct function at Path to Gcode tab!")

                for path in paths[layer]:
                    if "d" not in path.keys():
                        self.error(_("Warning: One or more paths do not 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)
                    id_ = path.get("id")

                    def set_comment(match, path):
                        if match.group(1) in path.keys():
                            return path.get(match.group(1))
                        else:
                            return "None"
                    if self.options.comment_gcode != "":
                        comment = re.sub("\[([A-Za-z_\-\:]+)\]", partial(set_comment, path=path), self.options.comment_gcode)
                        comment = comment.replace(":newline:","\n")
                        comment = gcode_comment_str(comment)
                    else:
                        comment = ""
                    if self.options.comment_gcode_from_properties:
                        tags = get_path_properties(path)
                        for tag in tags:
                            comment += gcode_comment_str("%s: %s"%(tag,tags[tag]))

                    style = simplestyle.parseStyle(path.get("style"))
                    colors[id_] = simplestyle.parseColor(style['stroke'] if "stroke"  in style and style['stroke']!='none' else "#000")
                    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:

                        zd,zs = self.Zcoordinates[layer][1],    self.Zcoordinates[layer][0]
                        c = 1. - float(sum(colors[id_]))/255/3
                        curves +=   [
                                         [
                                            [id_, depth_func(c,zd,zs), comment],
                                            [ self.parse_curve([subpath], layer) for subpath in csp  ]
                                         ]
                                    ]
#               for c in curves:
#                   print_(c)
                dxfpoints=sort_dxfpoints(dxfpoints)
                gcode+=print_dxfpoints(dxfpoints)


                for curve in curves:
                    for subcurve in curve[1]:
                        self.draw_curve(subcurve, layer)

                if self.options.path_to_gcode_order == 'subpath by subpath':
                    curves_ = []
                    for curve in curves:
                        curves_ += [ [curve[0],[subcurve]]  for subcurve in curve[1] ]
                    curves = curves_

                    self.options.path_to_gcode_order = 'path by path'

                if self.options.path_to_gcode_order == 'path by path':
                    if self.options.path_to_gcode_sort_paths:
                        keys = sort_curves( [curve[1] for curve in curves])
                    else:
                        keys = range(len(curves))
                    for key in keys:
                        d = curves[key][0][1]
                        for step in range( 0,  int(math.ceil( abs((zs-d)/self.tools[layer][0]["depth step"] )) ) ):
                            z = max(d, zs - abs(self.tools[layer][0]["depth step"]*(step+1)))

                            gcode += gcode_comment_str("\nStart cutting path id: %s"%curves[key][0][0])
                            if curves[key][0][2] != "()":
                                gcode += curves[key][0][2] # add comment

                            for curve in curves[key][1]:
                                gcode += self.generate_gcode(curve, layer, z)

                            gcode += gcode_comment_str("End cutting path id: %s\n\n"%curves[key][0][0])

                else:   # pass by pass
                    mind = min( [curve[0][1] for curve in curves])
                    for step in range( 0,  int(math.ceil( abs((zs-mind)/self.tools[layer][0]["depth step"] )) ) ):
                        z = zs - abs(self.tools[layer][0]["depth step"]*(step))
                        curves_ = []
                        for curve in curves:
                            if curve[0][1]<z:
                                curves_.append(curve)

                        z = zs - abs(self.tools[layer][0]["depth step"]*(step+1))
                        gcode += "\n(Pass at depth %s)\n"%z

                        if self.options.path_to_gcode_sort_paths:
                            keys = sort_curves( [curve[1] for curve in curves_])
                        else:
                            keys = range(len(curves_))
                        for key in keys:

                            gcode += gcode_comment_str("Start cutting path id: %s"%curves[key][0][0])
                            if curves[key][0][2] != "()":
                                gcode += curves[key][0][2] # add comment

                            for subcurve in curves_[key][1]:
                                gcode += self.generate_gcode(subcurve, layer, max(z,curves_[key][0][1]))

                            gcode += gcode_comment_str("End cutting path id: %s\n\n"%curves[key][0][0])


        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 do not 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"))
                    remove = []
                    for i in range(len(csp)):
                        subpath = [ [point[:] for point in points] for points in csp[i]]
                        subpath = self.apply_transforms(path,[subpath])[0]
                        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":
                                arrow =  cubicsuperpath.parsePath( '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]))
                                arrow = self.apply_transforms(path,arrow,True)
                                inkex.etree.SubElement(parent, inkex.addNS('path','svg'),
                                        {
                                            'd': cubicsuperpath.formatPath(arrow),
                                            'style': styles["area artefact arrow"],
                                            'gcodetools': 'area artefact arrow',
                                        })
                            elif self.options.area_find_artefacts_action == "mark with style":
                                inkex.etree.SubElement(parent, inkex.addNS('path','svg'), {'d': cubicsuperpath.formatPath(csp[i]), 'style': styles["area artefact"]})
                                remove.append(i)
                            elif self.options.area_find_artefacts_action == "delete":
                                remove.append(i)
                                print_("Deleted artefact %s" % subpath)
                    remove.reverse()
                    for i in remove:
                        del csp[i]
                    if len(csp) == 0:
                        parent.remove(path)
                    else:
                        path.set("d", cubicsuperpath.formatPath(csp))

            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))

                    # avoiding infinite loops
                    if self.options.area_tool_overlap>0.9: self.options.area_tool_overlap = .9

                    for i in range(self.options.max_area_curves):
                        radius = - tool_d * (i*(1-self.options.area_tool_overlap)+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


    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##
    # ##     Polyline to biarc
    # ##
    # ##     Converts Polyline to Biarc
    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    def polyline_to_biarc(self):



        def biarc(sm, 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**2:
                    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))

                l = (P0-P2).l2()
                if  l < EMC_TOLERANCE_EQUAL**2 or l<EMC_TOLERANCE_EQUAL**2 * R1.l2() /100:
                    # arc should be straight otherwise it could be threated as full circle
                    arc1 = [ sp1[1], 'line', 0, 0, [P2.x,P2.y], [z1,zm] ]
                else:
                    arc1 = [ sp1[1], 'arc', [R1.x,R1.y], a1, [P2.x,P2.y], [z1,zm] ]

                l = (P4-P2).l2()
                if  l < EMC_TOLERANCE_EQUAL**2 or l<EMC_TOLERANCE_EQUAL**2 * R2.l2() /100:
                    # arc should be straight otherwise it could be threated as full circle
                    arc2 = [ [P2.x,P2.y], 'line', 0, 0, [P4.x,P4.y], [zm,z2] ]
                else:
                    arc2 = [ [P2.x,P2.y], 'arc', [R2.x,R2.y], a2, [P4.x,P4.y], [zm,z2] ]

                return [ arc1, arc2 ]





        for layer in self.layers:
            if layer in self.selected_paths:
                for path in self.selected_paths[layer]:
                    d = path.get('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)
                    csp = self.apply_transforms(path, csp)
                    csp = self.transform_csp(csp, layer)

                    # lets pretend that csp is a polyline
                    poly = [ [point[1] for point in subpath] for subpath in csp ]

                    self.draw_csp([ [ [point,point,point] for point in subpoly] for subpoly in poly ],layer)

                    # lets create biarcs
                    for subpoly in poly:
                        # lets split polyline into different smooth parths.

                        if len(subpoly)>2:
                            smooth = [ [subpoly[0],subpoly[1]] ]
                            for p1,p2,p3 in zip(subpoly,subpoly[1:],subpoly[2:]):
                                # normalize p1p2 and p2p3 to get angle
                                s1,s2 = normalize( p1[0]-p2[0], p1[1]-p2[1]), normalize( p3[0]-p2[0], p3[1]-p2[1])
                                if cross(s1,s2) > corner_tolerance:
                                    #it's an angle
                                    smooth += [  [p2,p3]  ]
                                else:
                                    smooth[-1].append(p3)
                            for sm in smooth:
                                smooth_polyline_to_biarc(sm)

    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##
    # ##     Area fill
    # ##
    # ##     Fills area with lines
    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####


    def area_fill(self):
        # convert degrees into rad
        self.options.area_fill_angle = self.options.area_fill_angle * math.pi / 180
        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")
                tool = self.tools[layer][0]
                for path in self.selected_paths[layer]:
                    lines = []
                    print_(("doing path",   path.get("style"), path.get("d")))
                    area_group = inkex.etree.SubElement( path.getparent(), inkex.addNS('g','svg'))
                    d = path.get('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)
                    csp = self.apply_transforms(path, csp)
                    csp = csp_close_all_subpaths(csp)
                    csp = self.transform_csp(csp, layer)
                    #maxx = max([x,y,i,j,root],maxx)

                    # rotate the path to get bounds in defined direction.
                    a = - self.options.area_fill_angle
                    rotated_path = [   [ [ [point[0]*math.cos(a) - point[1]*math.sin(a), point[0]*math.sin(a)+point[1]*math.cos(a)]  for point in sp] for sp in subpath] for subpath in csp  ]
                    bounds =  csp_true_bounds(rotated_path)

                    # Draw the lines
                    # Get path's bounds
                    b = [0.0, 0.0, 0.0, 0.0] # [minx,miny,maxx,maxy]
                    for k in range(4):
                        i, j, t = bounds[k][2], bounds[k][3], bounds[k][4]
                        b[k] = csp_at_t(rotated_path[i][j-1],rotated_path[i][j],t)[k%2]


                    # Zig-zag
                    r = tool['diameter']*(1-self.options.area_tool_overlap)
                    if r<=0:
                        self.error('Tools diameter must be greater than 0!', 'error')
                        return

                    lines += [ [] ]

                    if self.options.area_fill_method == 'zig-zag':
                        i = b[0] - self.options.area_fill_shift*r
                        top = True
                        last_one = True
                        while (i<b[2] or last_one) :
                            if i>=b[2]: last_one = False
                            if lines[-1] == []:
                                lines[-1] += [  [i,b[3]]  ]

                            if top:
                                lines[-1] += [ [i,b[1]],[i+r,b[1]] ]

                            else:
                                    lines[-1] += [ [i,b[3]], [i+r,b[3]] ]

                            top = not top
                            i += r
                    else:

                        w, h  = b[2]-b[0] + self.options.area_fill_shift*r , b[3]-b[1] +  self.options.area_fill_shift*r
                        x,y = b[0] - self.options.area_fill_shift*r, b[1] - self.options.area_fill_shift*r
                        lines[-1] += [  [x,y] ]
                        stage = 0
                        start = True
                        while w>0 and h>0 :
                            stage = (stage+1)%4
                            if   stage == 0:
                                y -= h
                                h -= r
                            elif stage == 1:
                                x += w
                                if not start:
                                    w -= r
                                start = False
                            elif stage == 2:
                                y += h
                                h -= r
                            elif stage == 3:
                                x -= w
                                w -=r

                            lines[-1] += [ [x,y] ]

                        stage = (stage+1)%4
                        if w <= 0 and h>0:
                            y = y-h if stage == 0 else y+h
                        if h <= 0  and w>0:
                            x = x-w if stage == 3 else x+w
                        lines[-1] += [ [x,y] ]
                    # Rotate created paths back
                    a =  self.options.area_fill_angle
                    lines = [ [ [point[0]*math.cos(a) - point[1]*math.sin(a), point[0]*math.sin(a)+point[1]*math.cos(a)] for point in subpath] for subpath in lines  ]

                    # get the intersection points

                    splitted_line = [ [lines[0][0]] ]
                    intersections = {}
                    for l1,l2, in zip(lines[0],lines[0][1:]):
                        ints = []

                        if l1[0]==l2[0] and l1[1]==l2[1]: continue
                        for i in range(len(csp)):
                            for j in range(1,len(csp[i])) :
                                sp1,sp2 = csp[i][j-1], csp[i][j]
                                roots = csp_line_intersection(l1,l2,sp1,sp2)
                                for t in roots:
                                    p = tuple(csp_at_t(sp1,sp2,t))
                                    if l1[0]==l2[0]:
                                        t1 = (p[1]-l1[1])/(l2[1]-l1[1])
                                    else:
                                        t1 = (p[0]-l1[0])/(l2[0]-l1[0])
                                    if 0<=t1<=1:
                                        ints += [[t1, p[0],p[1], i,j,t]]
                                        if p in intersections:
                                            intersections[p]  += [ [i,j,t] ]
                                        else:
                                            intersections[p]  = [ [i,j,t] ]
                                        #p = self.transform(p,layer,True)
                                        #draw_pointer(p)
                        ints.sort()
                        for i in ints:
                            splitted_line[-1] +=[ [ i[1], i[2]] ]
                            splitted_line += [ [ [ i[1], i[2]] ] ]
                        splitted_line[-1] += [  l2  ]
                        i = 0
                    print_(splitted_line)
                    while i < len(splitted_line) :
                        # check if the middle point of the first lines segment is inside the path.
                        # and remove the subline if not.
                        l1,l2 = splitted_line[i][0],splitted_line[i][1]
                        p = [(l1[0]+l2[0])/2, (l1[1]+l2[1])/2]
                        if not point_inside_csp(p, csp):
                            #i +=1
                            del splitted_line[i]
                        else:
                            i += 1



                    # if we've used spiral method we'll try to save the order of cutting
                    do_not_change_order = self.options.area_fill_method == 'spiral'
                    # now let's try connect splitted lines
                    #while len(splitted_line)>0 :
                    #TODO

                    # and apply back transrormations to draw them
                    csp_line = csp_from_polyline(splitted_line)
                    csp_line = self.transform_csp(csp_line, layer, True)

                    self.draw_csp(csp_line, group = area_group)
    #                   draw_csp(lines)

    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##
    # ##     Engraving
    # ##
    #LT Notes to self: See wiki.inkscape.org/wiki/index.php/PythonEffectTutorial
    # To create anything in the Inkscape document, look at the XML editor for
    # details of how such an element looks in XML, then follow this model.
    #layer number n appears in XML as <svg:g id="layern" inkscape:label="layername">
    #
    #to create it, use
    #Mylayer=inkex.etree.SubElement(self.document.getroot(), 'g') #Create a generic element
    #Mylayer.set(inkex.addNS('label', 'inkscape'), "layername")   #Gives it a name
    #Mylayer.set(inkex.addNS('groupmode', 'inkscape'), 'layer')   #Tells Inkscape it's a layer
    #
    #group appears in XML as <svg:g id="gnnnnn"> where nnnnn is a number
    #
    #to create it, use
    #Mygroup=inkex.etree.SubElement(parent, inkex.addNS('g','svg'), {"gcodetools":"My group label"})
    # where parent may be the layer or a parent group. To get the parent group, you can use
    #parent = self.selected_paths[layer][0].getparent()
    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    def engraving(self) :
        #global x1,y1,rx,ry
        global cspm, wl
        global nlLT, i, j
        global gcode_3Dleft ,gcode_3Dright
        global max_dist #minimum of tool radius and user's requested maximum distance
        global eye_dist
        eye_dist = 100 #3D constant. Try varying it for your eyes


        def bisect(xxx) :
            (nx1,ny1),(nx2,ny2) = xxx
            """LT Find angle bisecting the normals n1 and n2

            Parameters: Normalised normals
            Returns: nx - Normal of bisector, normalised to 1/cos(a)
                   ny -
                   sinBis2 - sin(angle turned/2): positive if turning in
            Note that bisect(n1,n2) and bisect(n2,n1) give opposite sinBis2 results
            If sinturn is less than the user's requested angle tolerance, I return 0
            """
            #We can get absolute value of cos(bisector vector)
            #Note: Need to use max in case of rounding errors
            cosBis = math.sqrt(max(0,(1.0+nx1*nx2-ny1*ny2)/2.0))
            #We can get correct sign of the sin, assuming cos is positive
            if (abs(ny1-ny2)< engraving_tolerance)  or (abs(cosBis) < engraving_tolerance):
                if (abs(nx1-nx2)< engraving_tolerance): return(nx1,ny1,0.0)
                sinBis = math.copysign(1,ny1)
            else:
                sinBis = cosBis*(nx2-nx1)/(ny1-ny2)
            #We can correct signs by noting that the dot product
            # of bisector and either normal must be >0
            costurn=cosBis*nx1+sinBis*ny1
            if costurn == 0: return (ny1*100,-nx1*100,1) #Path doubles back on itself
            sinturn=sinBis*nx1-cosBis*ny1
            if costurn<0:  sinturn=-sinturn
            if 0 < sinturn*114.6 < (180-self.options.engraving_sharp_angle_tollerance):
                sinturn=0 #set to zero if less than the user wants to see.
            return (cosBis/costurn,sinBis/costurn, sinturn)
            #end bisect

        def get_radius_to_line(xxx):
            (x1,y1),(nx1,ny1), (nx2,ny2),(x2,y2),(nx23,ny23),(x3,y3),(nx3,ny3) = xxx
            """LT find biggest circle we can engrave here, if constrained by line 2-3

            Parameters:
                x1,y1,nx1,ny1 coordinates and normal of the line we're currently engraving
                nx2,ny2 angle bisector at point 2
                x2,y2 coordinates of first point of line 2-3
                nx23,ny23 normal to the line 2-3
                x3,y3 coordinates of the other end
                nx3,ny3 angle bisector at point 3
            Returns:
                radius or self.options.engraving_max_dist if line doesn't limit radius
            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 centre of the circle tangential to the line 2-3 is outside the
            angle bisectors at its ends, ignore this line.

            # 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
            """

            global max_dist

            #Start by converting coordinates to be relative to x1,y1
            x2,y2= x2-x1, y2-y1
            x3,y3= x3-x1, y3-y1

            #The logic uses vector arithmetic.
            #The dot product of two vectors gives the product of their lengths
            #multiplied by the cos of the angle between them.
            # So, the perpendicular distance from x1y1 to the line 2-3
            # is equal to the dot product of its normal and x2y2 or x3y3
            #It is also equal to the projection of x1y1-xcyc on the line's normal
            # plus the radius. But, as the normal faces inside the path we must negate it.

            #Make sure the line in question is facing x1,y1 and vice versa
            dist=-x2*nx23-y2*ny23
            if dist<0: return max_dist
            denom=1.-nx23*nx1-ny23*ny1
            if denom < engraving_tolerance: return max_dist

            #radius and centre are:
            r=dist/denom
            cx=r*nx1
            cy=r*ny1
            #if c is not between the angle bisectors at the ends of the line, ignore
            #Use vector cross products. Not sure if I need the .0001 safety margins:
            if (x2-cx)*ny2 > (y2-cy)*nx2 +0.0001:
                return max_dist
            if (x3-cx)*ny3 < (y3-cy)*nx3  -0.0001:
                return max_dist
            return min(r, max_dist)
            #end of get_radius_to_line

        def get_radius_to_point(xxx):
            (x1,y1),(nx,ny), (x2,y2) = xxx
            """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.
            """

            global max_dist

            #Start by converting coordinates to be relative to x1,y1
            x2,y2= x2-x1, y2-y1
            denom=nx**2+ny**2-1
            if denom<=engraving_tolerance: #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 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 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 min(r, max_dist)
            #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
            Note that, as simple as this code is, it is mathematically correct.
            Parameters:
                a,b,c and d are each a list of x,y real values
                Bezier end points a and d, control points b and c
            Returns:
                a list of Beziers.
                    Each Bezier is a list with four members,
                        each a list holding a coordinate pair
                Note that the final point of one member is the same as
                the first point of the next, and the control points
                there are smooth and symmetrical. I use this fact later.
            """
            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.hypot(dx,dy)/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 get_biggest(xxx):
            (x1,y1),(nx,ny) = xxx
            """LT Find biggest circle we can draw inside path at point x1,y1 normal nx,ny

            Parameters:
                point - either on a line or at a reflex corner
                normal - normalised to 1 if on a line, to 1/cos(a) at a corner
            Returns:
                tuple (j,i,r)
                ..where j and i are indices of limiting segment, r is radius
            """
            global max_dist, nlLT, i, j
            n1 = nlLT[j][i-1] #current node
            jjmin = -1
            iimin = -1
            r = 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 every subpath of this object
                for ii in xrange(0,len(nlLT[jj])): #for every point and line
                    if nlLT[jj][ii-1][2]: #if a point
                        if jj==j: #except this one
                            if abs(ii-i)<3 or abs(ii-i)>len(nlLT[j])-3: continue
                        t1=get_radius_to_point((x1,y1),(nx,ny),nlLT[jj][ii-1][0])
                        #print_("Try pt   i,ii,t1,x1,y1",i,ii,t1,x1,y1)
                    else: #doing a line
                        if jj==j: #except this one
                            if abs(ii-i)<2 or abs(ii-i)==len(nlLT[j])-1: continue
                            if abs(ii-i)==2  and nlLT[j][(ii+i)/2-1][3]<=0: continue
                            if (abs(ii-i)==len(nlLT[j])-2) and nlLT[j][-1][3]<=0: continue
                        nx2,ny2 = nlLT[jj][ii-2][1]
                        x2,y2 = nlLT[jj][ii-1][0]
                        nx23,ny23 = nlLT[jj][ii-1][1]
                        x3,y3 = nlLT[jj][ii][0]
                        nx3,ny3 = nlLT[jj][ii][1]
                        if nlLT[jj][ii-2][3]>0: #acute, so use normal, not bisector
                            nx2=nx23
                            ny2=ny23
                        if nlLT[jj][ii][3]>0: #acute, so use normal, not bisector
                            nx3=nx23
                            ny3=ny23
                        x23min,x23max=min(x2,x3),max(x2,x3)
                        y23min,y23max=min(y2,y3),max(y2,y3)
                        #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), (nx2,ny2),(x2,y2),(nx23,ny23), (x3,y3),(nx3,ny3))
                        #print_("Try line i,ii,t1,x1,y1",i,ii,t1,x1,y1)
                    if 0<=t1<r:
                        r = t1
                        iimin = ii
                        jjmin = jj
                        xmin, xmax = x1+r*nx-r, x1+r*nx+r
                        ymin, ymax = y1+r*ny-r, y1+r*ny+r
                #next ii
            #next jj
            return (jjmin,iimin,r)
            #end of get_biggest

        def line_divide(xxx, length):
            """LT recursively divide a line as much as necessary

            NOTE: This function is not currently used
            By noting which other path segment is touched by the circles at each end,
            we can see if anything is to be gained by a further subdivision, since
            if they touch the same bit of path we can move linearly between them.
            Also, we can handle points correctly.
            Parameters:
                end points and indices of limiting path, normal, length
            Returns:
                list of toolpath points
                    each a list of 3 reals: x, y coordinates, radius

            """
            (x0, y0) , j0, i0, (x1, y1), j1, i1, (nx, ny) = xxx
            global nlLT, i, j, lmin
            x2=(x0+x1)/2
            y2=(y0+y1)/2
            j2,i2,r2=get_biggest( (x2,y2), (nx,ny))
            if length<lmin: return [ [x2, y2, r2] ]
            if j2==j0 and i2==i0: #Same as left end. Don't subdivide this part any more
                return [ [x2, y2, r2], line_divide((x2,y2),j2,i2,(x1,y1),j1,i1,(nx,ny),length/2)]
            if j2==j1 and i2==i1: #Same as right end. Don't subdivide this part any more
                return [ line_divide((x0,y0),j0,i0,(x2,y2),j2,i2,(nx,ny),length/2), [x2, y2, r2] ]
            return [ line_divide((x0,y0),j0,i0,(x2,y2),j2,i2,(nx,ny),length/2), line_divide((x2,y2),j2,i2,(x1,y1),j1,i1,(nx,ny),length/2)]
            #end of line_divide()

        def save_point(xxx, w, i, j, ii, jj):
            """LT Save this point and delete previous one if linear

            The point is, we generate tons of points but many may be in a straight 3D line.
            There is no benefit in saving the imtermediate points.
            """
            (x,y) = xxx
            global wl, cspm
            x=round(x,4) #round to 4 decimals
            y=round(y,4) #round to 4 decimals
            w=round(w,4) #round to 4 decimals
            if len(cspm)>1:
                xy1a,xy1,xy1b,i1,j1,ii1,jj1=cspm[-1]
                w1=wl[-1]
                if i==i1 and j==j1 and ii==ii1 and jj==jj1: #one match
                    xy1a,xy2,xy1b,i1,j1,ii1,jj1=cspm[-2]
                    w2=wl[-2]
                    if i==i1 and j==j1 and ii==ii1 and jj==jj1: #two matches. Now test linearity
                        length1=math.hypot(xy1[0]-x,xy1[1]-y)
                        length2=math.hypot(xy2[0]-x,xy2[1]-y)
                        length12=math.hypot(xy2[0]-xy1[0],xy2[1]-xy1[1])
                        #get the xy distance of point 1 from the line 0-2
                        if length2>length1 and length2>length12: #point 1 between them
                            xydist=abs( (xy2[0]-x)*(xy1[1]-y)-(xy1[0]-x)*(xy2[1]-y) )/length2
                            if xydist<engraving_tolerance: #so far so good
                                wdist=w2+(w-w2)*length1/length2 -w1
                                if abs(wdist)<engraving_tolerance:
                                    #print_("pop",j,i,xy1)
                                    cspm.pop()
                                    wl.pop()
            cspm+=[ [ [x,y],[x,y],[x,y],i,j,ii,jj ] ]
            wl+=[w]
            #end of save_point

        def draw_point(xxx, w, t):
            """LT Draw this point as a circle with a 1px dot in the middle (x,y)
            and a 3D line from (x0,y0) down to x,y. 3D line thickness should be t/2

            Note that points that are subsequently erased as being unneeded do get
            displayed, but this helps the user see the total area covered.
            """
            (x0, y0), (x, y) = xxx
            global gcode_3Dleft ,gcode_3Dright
            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'})
                #Don't draw zero radius circles
                if w:
                    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(w), inkex.addNS('ry','sodipodi'):       str(w), inkex.addNS('type','sodipodi'): 'arc'})
                    # Find slope direction for shading
                    s=math.atan2(y-y0,x-x0) #-pi to pi
                    # convert to 2 hex digits as a shade of red
                    s2="#{0:x}0000".format(int(101*(1.5-math.sin(s+0.5))))
                    inkex.etree.SubElement( gcode_3Dleft , inkex.addNS('path','svg'),
                    { "d": "M %f,%f L %f,%f" %(x0-eye_dist,y0,x-eye_dist-0.14*w,y),
                        'style': "stroke:" + s2 + "; stroke-opacity:1; stroke-width:" + str(t/2) +" ; fill:none",
                        "gcodetools": "Gcode G1R"
                    })
                    inkex.etree.SubElement( gcode_3Dright , inkex.addNS('path','svg'),
                    { "d": "M %f,%f L %f,%f" %(x0+eye_dist,y0,x+eye_dist+0.14*r,y),
                        'style': "stroke:" + s2 + "; stroke-opacity:1; stroke-width:" + str(t/2) +" ; fill:none",
                        "gcodetools": "Gcode G1L"
                    })
            #end of draw_point

        #end of subfunction definitions. engraving() starts here:
        gcode = ''
        r,w, wmax = 0,0,0 #theoretical and tool-radius-limited radii in pixels
        x1,y1,nx,ny =0,0,0,0
        cspe =[]
        we = []
        if len(self.selected_paths)<=0:
            self.error(_("Please select at least one path to engrave and run again."),"warning")
            return
        if not self.check_dir(): return
        #Find what units the user uses
        unit=" mm"
        if self.options.unit == "G20 (All units in inches)":
            unit=" inches"
        elif self.options.unit != "G21 (All units in mm)":
            self.error(_("Unknown unit selected. mm assumed"),"warning")
        print_("engraving_max_dist mm/inch", self.options.engraving_max_dist)

        #LT See if we can use this parameter for line and Bezier subdivision:
        bitlen=20/self.options.engraving_newton_iterations

        for layer in self.layers:
            if layer in self.selected_paths:
                #Calculate scale in pixels per user unit (mm or inch)
                p1=self.orientation_points[layer][0][0]
                p2=self.orientation_points[layer][0][1]
                ol=math.hypot(p1[0][0]-p2[0][0],p1[0][1]-p2[0][1])
                oluu=math.hypot(p1[1][0]-p2[1][0],p1[1][1]-p2[1][1])
                print_("Orientation2 p1 p2 ol oluu",p1,p2,ol,oluu)
                orientation_scale = ol/oluu

                self.set_tool(layer)
                shape = self.tools[layer][0]['shape']
                if re.search('w', shape):
                    toolshape = eval('lambda w: ' + shape.strip('"'))
                else:
                    self.error(_("Tool '%s' has no shape. 45 degree cone assumed!") % self.tools[layer][0]['name'],"Continue")
                    toolshape = lambda w: w
                #Get tool radius in pixels
                toolr=self.tools[layer][0]['diameter'] * orientation_scale/2
                print_("tool radius in pixels=", toolr)
                #max dist from path to engrave in user's units
                max_distuu = min(self.tools[layer][0]['diameter']/2, self.options.engraving_max_dist)
                max_dist=max_distuu*orientation_scale
                print_("max_dist pixels", max_dist)

                engraving_group = inkex.etree.SubElement( self.selected_paths[layer][0].getparent(), inkex.addNS('g','svg'))
                if self.options.engraving_draw_calculation_paths and (self.my3Dlayer  == None):
                    self.my3Dlayer=inkex.etree.SubElement(self.document.getroot(), 'g') #Create a generic element at root level
                    self.my3Dlayer.set(inkex.addNS('label', 'inkscape'), "3D") #Gives it a name
                    self.my3Dlayer.set(inkex.addNS('groupmode', 'inkscape'), 'layer') #Tells Inkscape it's a layer
                #Create groups for left and right eyes
                if self.options.engraving_draw_calculation_paths:
                    gcode_3Dleft = inkex.etree.SubElement(self.my3Dlayer, inkex.addNS('g','svg'), {"gcodetools":"Gcode 3D L"})
                    gcode_3Dright = inkex.etree.SubElement(self.my3Dlayer, inkex.addNS('g','svg'), {"gcodetools":"Gcode 3D R"})

                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 copies in 3D layer
                            print_("csp is zz ",csp)
                            cspl=[]
                            cspr=[]
                            #create list containing lines and points, starting with a point
                            # 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]
                                if self.options.engraving_draw_calculation_paths:
                                    #Copy it to 3D layer objects
                                    spl=[]
                                    spr=[]
                                    for j in range(0,3):
                                        pl=[sp2[j][0]-eye_dist,sp2[j][1]]
                                        pr=[sp2[j][0]+eye_dist,sp2[j][1]]
                                        spl+=[pl]
                                        spr+=[pr]
                                    cspl+=[spl]
                                    cspr+=[spr]
                                #LT find angle between this and previous segment
                                x0,y0 = sp1[1]
                                nx1,ny1 = csp_normalized_normal(sp1,sp2,0)
                                #I don't trust this function, so test result
                                if abs(1-math.hypot(nx1,ny1))> 0.00001:
                                    print_("csp_normalised_normal error t=0",nx1,ny1,sp1,sp2)
                                    self.error(_("csp_normalised_normal error. See log."),"warning")

                                nx0, ny0 = csp_normalized_normal(sp0,sp1,1)
                                if abs(1-math.hypot(nx0,ny0))> 0.00001:
                                    print_("csp_normalised_normal error t=1",nx0,ny0,sp1,sp2)
                                    self.error(_("csp_normalised_normal error. See log."),"warning")
                                bx,by,s=bisect((nx0,ny0),(nx1,ny1))
                                #record x,y,normal,ifCorner, sin(angle-turned/2)
                                nlLT[-1] += [[ [x0,y0],[bx,by], True, s]]

                                #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. First, recursively cut it up:
                                    nn=bez_divide(sp1[1],sp1[2],sp2[0],sp2[1])
                                    first=True #Flag entry to divided Bezier
                                    for bLT in nn: #save as two line segments
                                        for seg in range(3):
                                            if seg>0 or first:
                                                nx1=bLT[seg][1]-bLT[seg+1][1]
                                                ny1=bLT[seg+1][0]-bLT[seg][0]
                                                l1=math.hypot(nx1,ny1)
                                                if l1<engraving_tolerance:
                                                    continue
                                                nx1=nx1/l1 #normalise them
                                                ny1=ny1/l1
                                                nlLT[-1]+=[[bLT[seg],[nx1,ny1], False,i]]
                                                first=False
                                            if seg<2: #get outgoing bisector
                                                nx0=nx1
                                                ny0=ny1
                                                nx1=bLT[seg+1][1]-bLT[seg+2][1]
                                                ny1=bLT[seg+2][0]-bLT[seg+1][0]
                                                l1=math.hypot(nx1,ny1)
                                                if l1<engraving_tolerance:
                                                    continue
                                                nx1=nx1/l1 #normalise them
                                                ny1=ny1/l1
                                                #bisect
                                                bx,by,s=bisect((nx0,ny0),(nx1,ny1))
                                                nlLT[-1] += [[bLT[seg+1],[bx,by], True, 0.]]
                            #LT for each segment - ends here.
                            print_(("engraving_draw_calculation_paths=",self.options.engraving_draw_calculation_paths))
                            if self.options.engraving_draw_calculation_paths:
                                #Copy complete paths to 3D layer
                                #print_("cspl",cspl)
                                cspl+=[cspl[0]] #Close paths
                                cspr+=[cspr[0]] #Close paths
                                inkex.etree.SubElement( gcode_3Dleft , inkex.addNS('path','svg'),
                                { "d": cubicsuperpath.formatPath([cspl]),
                                'style': "stroke:#808080; stroke-opacity:1; stroke-width:0.6; fill:none",
                                "gcodetools": "G1L outline"
                                })
                                inkex.etree.SubElement( gcode_3Dright , inkex.addNS('path','svg'),
                                { "d": cubicsuperpath.formatPath([cspr]),
                                'style': "stroke:#808080; stroke-opacity:1; stroke-width:0.6; fill:none",
                                "gcodetools": "G1L outline"
                                })

                                for p in nlLT[-1]: #For last sub-path
                                    if p[2]: 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:#f000af; stroke-opacity:0.46; stroke-width:0.1; fill:none",
                                            "gcodetools": "Engraving normals"
                                        })
                                    else: 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 bisectors"
                                        })


                        #LT6a build nlLT[j] for each subpath - ends here
                        #for nnn in nlLT:
                            #print_("nlLT",nnn) #LT debug stuff
                        # Calculate offset points
                        reflex=False
                        for j in xrange(len(nlLT)): #LT6b for each subpath
                            cspm=[] #Will be my output. List of csps.
                            wl=[] #Will be my w output list
                            w = r = 0 #LT initial, as 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
                                #if n1[2] == True and n1[3]==0: # A straight angle
                                    #continue
                                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
                                    lastw=w #Remember w from last line
                                    w = max_dist
                                    if n1[3]>0: #acute. Limit radius
                                        len1=math.hypot( (n0[0][0]-n1[0][0]),( n0[0][1]-n1[0][1]))
                                        if i<(len(nlLT[j])-1):
                                            len2=math.hypot( (nlLT[j][i+1][0][0]-n1[0][0]),(nlLT[j][i+1][0][1]-n1[0][1]))
                                        else:
                                            len2=math.hypot( (nlLT[j][0][0][0]-n1[0][0]),(nlLT[j][0][0][1]-n1[0][1]))
                                        #set initial r value, not to be exceeded
                                        w = math.sqrt(min(len1,len2))/n1[3]
                                else: #line. Cut it up if long.
                                    if n0[3]>0 and not self.options.engraving_draw_calculation_paths:
                                        bit0=r*n0[3] #after acute corner
                                    else: bit0=0.0
                                    length=math.hypot((x1b-x1a),(y1a-y1b))
                                    bit0=(min(length,bit0))
                                    bits=int((length-bit0)/bitlen)
                                    #split excess evenly at both ends
                                    bit0+=(length-bit0-bitlen*bits)/2
                                    #print_("j,i,r,bit0,bits",j,i,w,bit0,bits)
                                for b in xrange(bits): #divide line into bits
                                    x1=x1a+ny*(b*bitlen+bit0)
                                    y1=y1a-nx*(b*bitlen+bit0)
                                    jjmin,iimin,w=get_biggest( (x1,y1), (nx,ny))
                                    print_("i,j,jjmin,iimin,w",i,j,jjmin,iimin,w)
                                    #w = min(r, toolr)
                                    wmax=max(wmax,w)
                                    if reflex: #just after a reflex corner
                                        reflex = False
                                        if w<lastw: #need to adjust it
                                            draw_point((x1,y1),(n0[0][0]+n0[1][0]*w,n0[0][1]+n0[1][1]*w),w, (lastw-w)/2)
                                            save_point((n0[0][0]+n0[1][0]*w,n0[0][1]+n0[1][1]*w),w,i,j,iimin,jjmin)
                                    if n1[2] == True: # We're at a corner
                                        if n1[3]>0: #acute
                                            save_point((x1+nx*w,y1+ny*w),w,i,j,iimin,jjmin)
                                            draw_point((x1,y1),(x1,y1),0,0)
                                            save_point((x1,y1),0,i,j,iimin,jjmin)
                                        elif n1[3]<0 : #reflex
                                            if w>lastw:
                                                draw_point((x1,y1),(x1+nx*lastw,y1+ny*lastw),w, (w-lastw)/2)
                                                wmax=max(wmax,w)
                                                save_point((x1+nx*w,y1+ny*w),w,i,j,iimin,jjmin)
                                    elif b>0 and n2[3]>0 and not self.options.engraving_draw_calculation_paths: #acute corner coming up
                                        if jjmin==j and iimin==i+2: break
                                    draw_point((x1,y1),(x1+nx*w,y1+ny*w),w, bitlen)
                                    save_point((x1+nx*w,y1+ny*w),w,i,j,iimin,jjmin)

                                #LT end of for each bit of this line
                                if n1[2] == True and n1[3]<0: #reflex angle
                                    reflex=True
                                lastw = w #remember this w
                            #LT next i
                            cspm+=[cspm[0]]
                            print_("cspm",cspm)
                            wl+=[wl[0]]
                            print_("wl",wl)
                            #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.

                            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(wl[i]), inkex.addNS('ry','sodipodi'):       str(wl[i]), inkex.addNS('type','sodipodi'): 'arc'})
                            cspe += [cspm]
                            wluu = [] #width list in user units: mm/inches
                            for w in wl:
                                wluu+=[ w / orientation_scale ]
                            print_("wl in pixels",wl)
                            print_("wl in user units",wluu)
                            #LT previously, we was in pixels so gave wrong depth
                            we   += [wluu]
                        #LT6b For each subpath - ends here
                    #LT5 if it is a path - ends here
                    #print_("cspe",cspe)
                    #print_("we",we)
                #LT4 for each selected object in this layer - ends here

                if cspe!=[]:
                    curve = self.parse_curve(cspe, layer, we, toolshape) #convert to lines
                    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.header+="(Tool diameter should be at least "+str(2*wmax/orientation_scale)+unit+ ")\n"
            self.header+="(Depth, as a function of radius w, must be "+ self.tools[layer][0]['shape']+ ")\n"
            self.header+="(Rapid feeds use safe Z="+ str(self.options.Zsafe) + unit + ")\n"
            self.header+="(Material surface at Z="+ str(self.options.Zsurface) + unit + ")\n"
            self.export_gcode(gcode)
        else:  self.error(_("No need to engrave sharp angles."),"warning")


    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##
    # ##     Orientation
    # ##
    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    def orientation(self, layer=None) :

        if layer == None:
            layer = self.current_layer if self.current_layer is not None else self.document.getroot()

        transform = self.get_transforms(layer)
        if transform != []:
            transform = self.reverse_transform(transform)
            transform = simpletransform.formatTransform(transform)

        if self.options.orientation_points_count == "graffiti":
            print_(self.graffiti_reference_points)
            print_("Inserting graffiti points")
            if layer in self.graffiti_reference_points: graffiti_reference_points_count =  len(self.graffiti_reference_points[layer])
            else: graffiti_reference_points_count = 0
            axis = ["X","Y","Z","A"][graffiti_reference_points_count%4]
            attr = {'gcodetools': "Gcodetools graffiti reference point"}
            if  transform != []:
                attr["transform"] = transform
            g = inkex.etree.SubElement(layer, inkex.addNS('g','svg'), attr)
            inkex.etree.SubElement( g, inkex.addNS('path','svg'),
                {
                    'style':    "stroke:none;fill:#00ff00;",
                    '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' % (graffiti_reference_points_count*100, 0),
                    'gcodetools': "Gcodetools graffiti reference point arrow"
                })

            draw_text(axis,graffiti_reference_points_count*100+10,-10, group = g, gcodetools_tag = "Gcodetools graffiti reference point text")

        elif self.options.orientation_points_count == "in-out reference point":
            draw_pointer(group = self.current_layer, x = self.view_center, figure="arrow", pointer_type = "In-out reference point", text = "In-out point")

        else:
            print_("Inserting orientation points")

            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")

            attr = {"gcodetools":"Gcodetools orientation group"}
            if  transform != []:
                attr["transform"] = transform

            orientation_group = inkex.etree.SubElement(layer, inkex.addNS('g','svg'), attr)
            doc_height = inkex.unittouu(self.document.getroot().get('height'))
            if self.document.getroot().get('height') == "100%":
                doc_height = 1052.3622047
                print_("Overruding height from 100 percents 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"
                    })

                draw_text("(%s; %s; %s)" % (i[0],i[1],i[2]), (si[0]+10), (-si[1]-10+doc_height), group = g, gcodetools_tag = "Gcodetools orientation point text")


    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##
    # ##     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 (zero 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",
            }
        elif self.options.tools_library_type == "graffiti":
            tool = {
                "name": "Graffiti",
                "id": "Graffiti 0001",
                "diameter":10,
                "penetration feed":100,
                "feed":400,
                "gcode before path":"""M03 S1(Turn spray on)\n """,
                "gcode after path":"M05 (Turn spray off)\n ",
                "tool change gcode":"(Add G00 here to change sprayer if needed)\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 definition"})
        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"})
            draw_text(key, 0, y, group = g, gcodetools_tag = "Gcodetools tool definition field name", font_size = 10 if key!='name' else 20)
            param = tool[key]
            if type(param)==str and re.match("^\s*$",param): param = "(None)"
            draw_text(param, 150, y, group = g, gcodetools_tag = "Gcodetools tool definition field value", font_size = 10 if key!='name' else 20)
            v = str(param).split("\n")
            y += 15*len(v) if key!='name' else 20*len(v)

        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.set_markers()

        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] ]
        #draw_csp(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**2:
                    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
                            if self.options.lathe_create_fine_cut_using == "Move path":
                                subpath = [ [  [i2[0],i2[1]+r]  for i2 in i1]  for i1 in subpath]
                            else:
                                # 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])
                                #draw_csp(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)

    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##
    # ##     Lathe modify path
    # ##     Modifies path to fit current cutter. As for now straight rect cutter.
    # ##
    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####

    def lathe_modify_path(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 self.layers:
            if layer in paths:
                width = self.options.lathe_rectangular_cutter_width
                #self.set_tool(layer)
                for path in paths[layer]:
                    csp = self.transform_csp(cubicsuperpath.parsePath(path.get("d")),layer)
                    new_csp = []
                    for subpath in csp:
                        orientation = subpath[-1][1][0]>subpath[0][1][0]
                        last_n = None
                        last_o = 0
                        new_subpath = []

                        # Split segment at x' and y' == 0
                        for sp1, sp2 in zip(subpath[:],subpath[1:]):
                            ax,ay,bx,by,cx,cy,dx,dy = csp_parameterize(sp1,sp2)
                            roots = cubic_solver_real(0, 3*ax, 2*bx, cx)
                            roots += cubic_solver_real(0, 3*ay, 2*by, cy)
                            new_subpath = csp_concat_subpaths(new_subpath, csp_seg_split(sp1,sp2,roots))
                        subpath = new_subpath
                        new_subpath = []
                        first_seg = True
                        for sp1, sp2 in zip(subpath[:],subpath[1:]):
                            n = csp_normalized_normal(sp1,sp2,0)
                            a  = math.atan2(n[0],n[1])
                            if a == 0 or a == math.pi:
                                n = csp_normalized_normal(sp1,sp2,1)
                            a  = math.atan2(n[0],n[1])
                            if a!=0 and a!=math.pi:
                                o = 0 if 0<a<=math.pi/2 or -math.pi<a<-math.pi/2 else 1
                                if not orientation: o = 1-o

                                # Add first horisontal straight line if needed
                                if not first_seg and new_subpath==[]: new_subpath = [ [[subpath[0][i][0] - width*o ,subpath[0][i][1]] for i in range(3)] ]

                                new_subpath = csp_concat_subpaths(
                                        new_subpath,
                                        [
                                            [[sp1[i][0] - width*o ,sp1[i][1]] for i in range(3)],
                                            [[sp2[i][0] - width*o ,sp2[i][1]] for i in range(3)]
                                        ]
                                   )
                            first_seg = False

                        # Add last horisontal straigth line if needed
                        if a==0 or a==math.pi:
                            new_subpath +=  [ [[subpath[-1][i][0] - width*o ,subpath[-1][i][1]] for i in range(3)] ]


                    new_csp += [new_subpath]
                    self.draw_csp(new_csp,layer)
    #
    #                               o = (1 if cross(n, [0,1])>0 else -1)*orientation
    #                               new_subpath += [  [sp1[i][0] - width*o,sp1[i][1]] for i in range(3)  ]
    #                           n = csp_normalized_normal(sp1,sp2,1)
    #                           o = (1 if cross(n, [0,1])>0 else -1)*orientation
    #                           new_subpath += [  [sp2[i][0] - width*o,sp2[i][1]] for i in range(3)  ]


    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##
    # ## Update function
    # ##
    # ## Gets file containing version information from the web and compaares it with.
    # ## current version.
    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####

    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")


    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ## Graffiti function generates Gcode for graffiti drawer
    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    def graffiti(self) :
        # Get reference points.

        def get_gcode_coordinates(point,layer):
            gcode = ''
            pos = []
            for ref_point in self.graffiti_reference_points[layer]:
                c = math.sqrt((point[0]-ref_point[0][0])**2 + (point[1]-ref_point[0][1])**2)
                gcode += " %s %f"%(ref_point[1], c)
                pos += [c]
            return pos, gcode


        def graffiti_preview_draw_point(x1,y1,color,radius=.5):
            self.graffiti_preview = self.graffiti_preview
            r,g,b,a_ = color
            for x in range(int(x1-1-math.ceil(radius)), int(x1+1+math.ceil(radius)+1)):
                for y in range(int(y1-1-math.ceil(radius)), int(y1+1+math.ceil(radius)+1)):
                    if x>=0 and y>=0 and y<len(self.graffiti_preview) and x*4<len(self.graffiti_preview[0]):
                        d = math.sqrt( (x1-x)**2 +(y1-y)**2)
                        a = float(a_)*( max(0,(1-(d-radius))) if d>radius else 1 )/256
                        self.graffiti_preview[y][x*4] = int(r*a + (1-a)*self.graffiti_preview[y][x*4])
                        self.graffiti_preview[y][x*4+1] = int(g*a + (1-a)*self.graffiti_preview[y][x*4+1])
                        self.graffiti_preview[y][x*4+2] = int(g*b + (1-a)*self.graffiti_preview[y][x*4+2])
                        self.graffiti_preview[y][x*4+3] = min(255,int(self.graffiti_preview[y][x*4+3]+a*256))

        def graffiti_preview_transform(x,y):
            tr = self.graffiti_preview_transform
            d = max(tr[2]-tr[0]+2,tr[3]-tr[1]+2)
            return  [(x-tr[0]+1)*self.options.graffiti_preview_size/d, self.options.graffiti_preview_size - (y-tr[1]+1)*self.options.graffiti_preview_size/d]


        def draw_graffiti_segment(layer,start,end,feed,color=(0,255,0,40),emmit=1000):
            # Emit = dots per second
            l = math.sqrt(sum([(start[i]-end[i])**2 for i in range(len(start))]))
            time_ = l/feed
            c1,c2 = self.graffiti_reference_points[layer][0][0],self.graffiti_reference_points[layer][1][0]
            d = math.sqrt( (c1[0]-c2[0])**2 + (c1[1]-c2[1])**2)
            if d == 0: raise ValueError("Error! Reference points should not be the same!")
            for i in range(int(time_*emmit+1)):
                t = i/(time_*emmit)
                r1,r2 = start[0]*(1-t) + end[0]*t, start[1]*(1-t) + end[1]*t
                a = (r1**2-r2**2+d**2)/(2*d)
                h = math.sqrt(r1**2 - a**2)
                xa = c1[0] + a*(c2[0]-c1[0])/d
                ya = c1[1] + a*(c2[1]-c1[1])/d

                x1 = xa + h*(c2[1]-c1[1])/d
                x2 = xa - h*(c2[1]-c1[1])/d
                y1 = ya - h*(c2[0]-c1[0])/d
                y2 = ya + h*(c2[0]-c1[0])/d

                x = x1 if y1<y2 else x2
                y = min(y1,y2)
                x,y = graffiti_preview_transform(x,y)
                graffiti_preview_draw_point(x,y,color)

        def create_connector(p1,p2,t1,t2):
            P1,P2 = P(p1), P(p2)
            N1, N2  = P(rotate_ccw(t1)), P(rotate_ccw(t2))
            r = self.options.graffiti_min_radius
            C1,C2 = P1+N1*r, P2+N2*r
            # Get closest possible centers of arcs, also we define that arcs are both ccw or both not.
            dc, N1, N2, m = (
                    (
                        (((P2-N1*r) - (P1-N2*r)).l2(),-N1,-N2, 1)
                             if  vectors_ccw(t1,t2) else
                        (((P2+N1*r) - (P1+N2*r)).l2(), N1, N2,-1)
                   )
                     if vectors_ccw((P1-C1).to_list(),t1) == vectors_ccw((P2-C2).to_list(),t2) else
                    (
                        (((P2+N1*r) - (P1-N2*r)).l2(), N1,-N2, 1)
                             if vectors_ccw(t1,t2) else
                        (((P2-N1*r) - (P1+N2*r)).l2(),-N1, N2, 1)
                   )
               )
            dc = math.sqrt(dc)
            C1,C2 = P1+N1*r, P2+N2*r
            Dc = C2-C1

            if dc == 0:
                # can be joined by one arc
                return csp_from_arc(p1, p2, C1.to_list(), r, t1)

            cos, sin = Dc.x/dc, Dc.y/dc
            #draw_csp(self.transform_csp([[ [[C1.x-r*sin,C1.y+r*cos]]*3,[[C2.x-r*sin,C2.y+r*cos]]*3 ]],layer,reverse=True), color = "#00ff00;")
            #draw_pointer(self.transform(C1.to_list(),layer,reverse=True))
            #draw_pointer(self.transform(C2.to_list(),layer,reverse=True))

            p1_end = [C1.x-r*sin*m,C1.y+r*cos*m]
            p2_st  = [C2.x-r*sin*m,C2.y+r*cos*m]
            if point_to_point_d2(p1,p1_end)<0.0001 and point_to_point_d2(p2,p2_st)<0.0001:
                return ([[p1,p1,p1],[p2,p2,p2]])

            arc1 = csp_from_arc(p1, p1_end, C1.to_list(), r, t1)
            arc2 = csp_from_arc(p2_st, p2, C2.to_list(), r, [cos,sin])
            return csp_concat_subpaths(arc1,arc2)

        if not self.check_dir(): return
        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.tool = []
        gcode = """(Header)
(Generated by gcodetools from Inkscape.)
(Using graffiti extension.)
(Header end.)"""

        minx,miny,maxx,maxy = float("inf"),float("inf"),float("-inf"),float("-inf")

        # Get all reference points and path's bounds to make preview

        for layer in self.layers:
            if layer in paths:
                # Set reference points
                if layer not in self.graffiti_reference_points:
                    reference_points = None
                    for i in range(self.layers.index(layer),-1,-1):
                        if self.layers[i] in self.graffiti_reference_points:
                            reference_points = self.graffiti_reference_points[self.layers[i]]
                            self.graffiti_reference_points[layer] = self.graffiti_reference_points[self.layers[i]]
                            break
                    if reference_points == None:
                        self.error('There are no graffiti reference points for layer %s'%layer,"error")

                # Transform reference points
                for i in range(len(self.graffiti_reference_points[layer])):
                    self.graffiti_reference_points[layer][i][0] = self.transform(self.graffiti_reference_points[layer][i][0], layer)
                    point = self.graffiti_reference_points[layer][i]
                    gcode += "(Reference point %f;%f for %s axis)\n"%(point[0][0],point[0][1],point[1])

                if self.options.graffiti_create_preview:
                    for point in self.graffiti_reference_points[layer]:
                        minx,miny,maxx,maxy = min(minx,point[0][0]), min(miny,point[0][1]), max(maxx,point[0][0]), max(maxy,point[0][1])
                    for path in paths[layer]:
                        csp = cubicsuperpath.parsePath(path.get("d"))
                        csp = self.apply_transforms(path, csp)
                        csp = self.transform_csp(csp, layer)
                        bounds = csp_simple_bound(csp)
                        minx,miny,maxx,maxy = min(minx,bounds[0]), min(miny,bounds[1]), max(maxx,bounds[2]), max(maxy,bounds[3])

        if self.options.graffiti_create_preview:
            self.graffiti_preview = list([ [255]*(4*self.options.graffiti_preview_size) for i in range(self.options.graffiti_preview_size)])
            self.graffiti_preview_transform = [minx,miny,maxx,maxy]

        for layer in self.layers:
            if layer in paths:

                r = re.match("\s*\(\s*([0-9\-,.]+)\s*;\s*([0-9\-,.]+)\s*\)\s*",self.options.graffiti_start_pos)
                if r:
                    start_point = [float(r.group(1)),float(r.group(2))]
                else:
                    start_point = [0.,0.]
                last_sp1 = [[start_point[0],start_point[1]-10] for i in range(3)]
                last_sp2 = [start_point for i in range(3)]

                self.set_tool(layer)
                self.tool = self.tools[layer][0]
                # Change tool every layer. (Probably layer = color so it'll be
                # better to change it even if the tool has not been changed)
                gcode += ( "(Change tool to %s)\n" % re.sub("\"'\(\)\\\\"," ",self.tool["name"]) ) + self.tool["tool change gcode"] + "\n"

                subpaths = []
                for path in paths[layer]:
                    # Rebuild the paths to polyline.
                    csp = cubicsuperpath.parsePath(path.get("d"))
                    csp = self.apply_transforms(path, csp)
                    csp = self.transform_csp(csp, layer)
                    subpaths += csp
                polylines = []
                while len(subpaths)>0:
                    i = min( [( point_to_point_d2(last_sp2[1],subpaths[i][0][1]),i) for i in range(len(subpaths))] )[1]
                    subpath = subpaths[i][:]
                    del subpaths[i]
                    polylines += [
                                    ['connector', create_connector(
                                                    last_sp2[1],
                                                    subpath[0][1],
                                                    csp_normalized_slope(last_sp1,last_sp2,1.),
                                                    csp_normalized_slope(subpath[0],subpath[1],0.),
                                    )]
                                ]
                    polyline = []
                    spl = None

                    #  remove zerro length segments
                    i = 0
                    while i<len(subpath)-1:
                        if  (cspseglength(subpath[i],subpath[i+1])<0.00000001 ):
                            subpath[i][2] = subpath[i+1][2]
                            del subpath[i+1]
                        else:
                            i += 1

                    for sp1, sp2 in zip(subpath,subpath[1:]):
                        if spl != None and abs(cross( csp_normalized_slope(spl,sp1,1.),csp_normalized_slope(sp1,sp2,0.) )) > 0.1: # TODO add coefficient into inx
                            # We've got sharp angle at sp1.
                            polyline += [sp1]
                            polylines += [['draw',polyline[:]]]
                            polylines += [
                                            ['connector', create_connector(
                                                    sp1[1],
                                                    sp1[1],
                                                    csp_normalized_slope(spl,sp1,1.),
                                                    csp_normalized_slope(sp1,sp2,0.),
                                            )]
                                        ]
                            polyline = []
                        # max_segment_length
                        polyline += [ sp1 ]
                        print_(polyline)
                        print_(sp1)

                        spl = sp1
                    polyline += [ sp2 ]
                    polylines += [ ['draw',polyline[:]] ]

                    last_sp1, last_sp2 = sp1,sp2


                # Add return to start_point
                if polylines == []: continue
                polylines += [ ["connect1",  [ [polylines[-1][1][-1][1] for i in range(3)],[start_point for i in range(3)] ] ] ]

                # Make polilynes from polylines. They are still csp.
                for i in range(len(polylines)):
                    polyline = []
                    l = 0
                    print_("polylines",polylines)
                    print_(polylines[i])
                    for sp1,sp2 in zip(polylines[i][1],polylines[i][1][1:]):
                        print_(sp1,sp2)
                        l = cspseglength(sp1,sp2)
                        if l>0.00000001:
                            polyline += [sp1[1]]
                            parts = int(math.ceil(l/self.options.graffiti_max_seg_length))
                            for j in range(1,parts):
                                polyline += [csp_at_length(sp1,sp2,float(j)/parts) ]
                    if l>0.00000001:
                        polyline += [sp2[1]]
                    print_(i)
                    polylines[i][1] = polyline

                t = 0
                last_state = None
                for polyline_ in polylines:
                    polyline = polyline_[1]
                    # Draw linearization
                    if self.options.graffiti_create_linearization_preview:
                        t += 1
                        csp = [ [polyline[i],polyline[i],polyline[i]] for i in range(len(polyline))]
                        draw_csp(self.transform_csp([csp],layer,reverse=True), color = "#00cc00;" if polyline_[0]=='draw' else "#ff5555;")


                # Export polyline to gcode
                # we are making trnsform from XYZA coordinates to R1...Rn
                # where R1...Rn are radius vectors from grafiti reference points
                # to current (x,y) point. Also we need to assign custom feed rate
                # for each segment. And we'll use only G01 gcode.
                    last_real_pos, g = get_gcode_coordinates(polyline[0],layer)
                    last_pos = polyline[0]
                    if polyline_[0] == "draw" and last_state!="draw":
                        gcode += self.tool['gcode before path']+"\n"
                    for point in polyline:
                        real_pos, g = get_gcode_coordinates(point,layer)
                        real_l = sum([(real_pos[i]-last_real_pos[i])**2 for i in range(len(last_real_pos))])
                        l = (last_pos[0]-point[0])**2 + (last_pos[1]-point[1])**2
                        if l!=0:
                            feed = self.tool['feed']*math.sqrt(real_l/l)
                            gcode += "G01 " + g + " F %f\n"%feed
                            if self.options.graffiti_create_preview:
                                draw_graffiti_segment(layer,real_pos,last_real_pos,feed,color=(0,0,255,200) if polyline_[0] == "draw" else (255,0,0,200),emmit=self.options.graffiti_preview_emmit)
                            last_real_pos = real_pos
                            last_pos = point[:]
                    if polyline_[0] == "draw" and last_state!="draw":
                        gcode += self.tool['gcode after path']+"\n"
                    last_state = polyline_[0]
        self.export_gcode(gcode, no_headers=True)
        if self.options.graffiti_create_preview:
            try :
                # Draw reference points
                for layer in self.graffiti_reference_points:
                    for point in self.graffiti_reference_points[layer]:
                        x, y = graffiti_preview_transform(point[0][0],point[0][1])
                        graffiti_preview_draw_point(x,y,(0,255,0,255),radius=5)

                import png
                writer = png.Writer(width=self.options.graffiti_preview_size, height=self.options.graffiti_preview_size, size=None, greyscale=False, alpha=True, bitdepth=8, palette=None, transparent=None, background=None, gamma=None, compression=None, interlace=False, bytes_per_sample=None, planes=None, colormap=None, maxval=None, chunk_limit=1048576)
                f = open(self.options.directory+self.options.file+".png", 'wb')
                writer.write(f, self.graffiti_preview)
                f.close()

            except :
                self.error("Png module have not been found!","warning")


    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    # ##
    # ##     Effect
    # ##
    # ##     Main function of Gcodetools class
    # ##
    # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ####
    def effect(self) :
        start_time = time.time()
        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 == '"about"':
            self.help()
            return

        elif self.options.active_tab ==  '"test"':
            self.test()

        elif self.options.active_tab not in ['"dxfpoints"','"path-to-gcode"', '"area_fill"', '"area"', '"area_artefacts"', '"engraving"', '"orientation"', '"tools_library"', '"lathe"', '"offset"', '"arrangement"', '"update"', '"graffiti"', '"lathe_modify_path"', '"plasma-prepare-path"']:
            self.error(
                _("Select one of the action tabs - Path to Gcode, Area, Engraving, DXF points, Orientation, Offset, Lathe or Tools library.\n Current active tab id is [%s]" % self.options.active_tab),
                "error"
            )
        else:
            # Get all Gcodetools data from the scene.
            self.get_info()
            if self.options.active_tab in ['"dxfpoints"', '"path-to-gcode"', '"area_fill"', '"area"', '"area_artefacts"', '"engraving"', '"lathe"', '"graffiti"', '"plasma-prepare-path"']:
                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_fill"':
                self.area_fill()
            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 == '"graffiti"':
                self.graffiti()
            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 == '"lathe_modify_path"':
                self.lathe_modify_path()
            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 = cubicsuperpath.parsePath(self.selected_paths[layer][0].get("d"))
                            csp2 = 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_:
                                    draw_csp([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()

            elif self.options.active_tab == '"plasma-prepare-path"':
                self.plasma_prepare_path()
            else:

                print_(f"XXXX {self.options.active_tab}")

        print_("------------------------------------------")
        print_("Done in %f seconds" % (time.time() - start_time))
        print_("End at %s." % time.strftime("%d.%m.%Y %H:%M:%S"))


#
gcodetools = Gcodetools()
gcodetools.run()
# ~ gcodetools.load_raw()
gcodetools.effect()

