gcodetools.py revision a1fe62310a3a0a5fa087bca12901b1716ba042ff
"""
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
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
###
### Gcodetools v 1.6.03
###
gcodetools_current_version = "1.6.03"
import os
import math
import bezmisc
import re
import copy
import sys
import time
import cmath
import numpy
import codecs
import random
import gettext
### Check if inkex has errormsg (0.46 version doesnot have one.) Could be removed later.
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))
################################################################################
###
### Styles and additional parameters
###
################################################################################
straight_tolerance = 0.0001
straight_distance_tolerance = 0.0001
engraving_tolerance = 0.0001
loft_lengths_tolerance = 0.0000001
options = {}
defaults = {
'header': """%
(Header)
(Generated by gcodetools from Inkscape.)
(Using default header. To add your own header create file "header" in the output dir.)
M3
(Header end.)
""",
'footer': """
(Footer)
M5
G00 X0.0000 Y0.0000
M2
(Using default footer. To add your own footer create file "footer" in the output dir.)
(end)
%"""
}
intersection_tolerance = 0.00001
styles = {
"loft_style" : {
'main curve': simplestyle.formatStyle({ 'stroke': '#88f', 'fill': 'none', 'stroke-width':'1', 'marker-end':'url(#Arrow2Mend)' }),
},
"biarc_style" : {
'biarc0': simplestyle.formatStyle({ 'stroke': '#88f', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
'biarc1': simplestyle.formatStyle({ 'stroke': '#8f8', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
'line': simplestyle.formatStyle({ 'stroke': '#f88', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
'area': simplestyle.formatStyle({ 'stroke': '#777', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.1' }),
},
"biarc_style_dark" : {
'biarc0': simplestyle.formatStyle({ 'stroke': '#33a', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
'biarc1': simplestyle.formatStyle({ 'stroke': '#3a3', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
'line': simplestyle.formatStyle({ 'stroke': '#a33', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
'area': simplestyle.formatStyle({ 'stroke': '#222', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
},
"biarc_style_dark_area" : {
'biarc0': simplestyle.formatStyle({ 'stroke': '#33a', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.1' }),
'biarc1': simplestyle.formatStyle({ 'stroke': '#3a3', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.1' }),
'line': simplestyle.formatStyle({ 'stroke': '#a33', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.1' }),
'area': simplestyle.formatStyle({ 'stroke': '#222', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
},
"biarc_style_i" : {
'biarc0': simplestyle.formatStyle({ 'stroke': '#880', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
'biarc1': simplestyle.formatStyle({ 'stroke': '#808', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
'line': simplestyle.formatStyle({ 'stroke': '#088', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
'area': simplestyle.formatStyle({ 'stroke': '#999', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
},
"biarc_style_dark_i" : {
'biarc0': simplestyle.formatStyle({ 'stroke': '#dd5', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
'biarc1': simplestyle.formatStyle({ 'stroke': '#d5d', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
'line': simplestyle.formatStyle({ 'stroke': '#5dd', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }),
'area': simplestyle.formatStyle({ 'stroke': '#aaa', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
},
"biarc_style_lathe_feed" : {
'biarc0': simplestyle.formatStyle({ 'stroke': '#07f', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
'biarc1': simplestyle.formatStyle({ 'stroke': '#0f7', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
'line': simplestyle.formatStyle({ 'stroke': '#f44', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
'area': simplestyle.formatStyle({ 'stroke': '#aaa', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
},
"biarc_style_lathe_passing feed" : {
'biarc0': simplestyle.formatStyle({ 'stroke': '#07f', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
'biarc1': simplestyle.formatStyle({ 'stroke': '#0f7', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
'line': simplestyle.formatStyle({ 'stroke': '#f44', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
'area': simplestyle.formatStyle({ 'stroke': '#aaa', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
},
"biarc_style_lathe_fine feed" : {
'biarc0': simplestyle.formatStyle({ 'stroke': '#7f0', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
'biarc1': simplestyle.formatStyle({ 'stroke': '#f70', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
'line': simplestyle.formatStyle({ 'stroke': '#744', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }),
'area': simplestyle.formatStyle({ 'stroke': '#aaa', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }),
},
"area artefact": simplestyle.formatStyle({ 'stroke': '#ff0000', 'fill': '#ffff00', 'stroke-width':'1' }),
"area artefact arrow": simplestyle.formatStyle({ 'stroke': '#ff0000', 'fill': '#ffff00', 'stroke-width':'1' }),
}
################################################################################
### Cubic Super Path additional functions
################################################################################
def csp_simple_bound(csp):
for p in sp:
min_dist = 1e100
max_dist = 0
for i in range(4) :
for j in range(4) :
# 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 :
return min_dist
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) :
i = 0
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 :
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 += [0.]
dist = d+[1.]
sample_points -= 2
# try to find closes points using Newtons method
for k in range(sample_points) :
for j in range(sample_points) :
i = 0
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)
#draw_pointer(csp_at_t(sp1,sp2,t1))
if F2!=None :
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
return dist
return dist
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])
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)
return dist
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_true_bounds(csp) :
# Finds minx,miny,maxx,maxy of the csp and return their (x,y,i,j,t)
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]))
############################################################################
### 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.
############################################################################
i = 0
if det!=0 :
else: break
i += 1
if a==b :
return
elif depth_a>0 :
elif depth_b>0 :
else : # Both segments have been subdevided enougth. Let's get some intersections :).
if intersection :
if intersection == "Overlap" :
return intersections
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) )
) :
res += [intersection]
return res
# returns a list containning [t1,t2,t3,...,tn], 0<=ti<=1...
tolerance = .0000000001
res = []
for k in range(sample_points) :
i, F = 0, 1e100
try : # some numerical calculation could exceed the limits
t2 = t*t
#slopes...
F1 = (
)
t -= F/F1
except:
break
i += 1
for i in res :
if abs(t-i)<=0.001 :
break
if not abs(t-i)<=0.001 :
return res
tolerance = .0001
F = 0.
i = 0
t = .5
if d != 0 :
Flast = F
F1 = (
)
i+=1
if F1!=0:
t -= F/F1
else:
break
else: break
return t
#curvature = (x'y''-y'x'') / (x'^2+y'^2)^1.5
if d != 0 :
else :
# Use the Lapitals rule to solve 0/0 problem for 2 times...
if depth>0 :
# little hack ;^) hope it wont influence anything...
return 1e100
if c == 0 : return 1e100
else: return 1/c
# special points = curvature == 0
res = []
for i in roots :
i = i.real
return res
def csp_subpath_ccw(subpath):
# Remove all zerro length segments
s = 0
#subpath = subpath[:]
for p in sp1 :
pl = p
return s<0
return [x,y]
total = 0
lengths = []
total += l
def csp_segments(csp):
seg += [ l ]
if l>0 :
return seg,l
# rebuild_csp() adds to csp control points making it's segments looks like segs
if s==None : s, l = csp_segments(csp)
d = None
del segs[d[1]]
if segs[i]<s[j] : break
if s[j]-s[j-1] != 0 :
s = s[:j] + [ s[j-1]*(1-t)+s[j]*t ] + s[j:]
return csp, s
if aa:
coef2=1
else:
coef1=1
roots = cubic_solver(a,b,c,d)
retval = []
for i in roots :
i = i.real
return retval
elif t1 <= 1e-10:
else:
# points are [[i,t]...] where i-segment's number
parts = []
continue
continue
continue
else :
else :
return parts
# 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
return []
result = []
return result
def point_to_arc_distance(p, arc):
### Distance calculattion from point to arc
dist = None
p = P(p)
if r>0 :
i = c + (p-c).unit()*r
if a*alpha<0:
return (p-i).mag(), [i.x, i.y]
else :
else :
n, i = 10, 0
i += 1
for j in range(n+1):
t = float(j)/n
n=n*2
return d1[0]
def csp_simple_bound_to_point_distance(p, csp):
x,y = p
c = 0
for i in range(4):
c +=1
return c%2==0
return 0.
min_dist = 1e100
return min_dist
if x==0 : # Lines are parallel
else:
else: return False
else :
return (
if x==0 : # Lines are parallel
else:
res = []
return res
else: return []
else :
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):
# p1 - point, p2,p3 - line segment
#draw_pointer(p1)
if c1 <= 0 :
return min(
min_dist = 1e100
max_dist = 0.
for i in range(4) :
min_dist = 0.
break
for i in range(4) :
for j in range(4) :
def csp_reverse(csp) :
n = []
for j in csp[i] :
n = [ [j[2][:],j[1][:],j[0][:]] ] + n
csp[i] = n[:]
return csp
if t == 0 :
else :
elif t == 1 :
else :
else :
return [1.,0.]
def csp_concat_subpaths(*s):
else :
if len(s) == 0 : return []
result = s[0]
for s1 in s[1:]:
return result
result = []
s = csp[i]
intersections = []
for s in splitted_s[:] :
for p in csp_true_bounds([s]) :
break
if clip :
splitted_s.remove(s)
result += splitted_s
return result
# Appends subpath with line or polyline.
for p in points :
subpath += [ [p[:],p[:],p[:]] ]
else:
return subpath
def csp_join_subpaths(csp) :
joined_result = []
while done_smf :
del(result[-1])
j = 0
while j<len(joined_result) :
break
break
j += 1
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])
abc = triangle_cross(a,b,c)
abd = triangle_cross(a,b,d)
bcd = triangle_cross(b,c,d)
cad = triangle_cross(c,a,d)
raise ValueError, "csp_segment_convex_hull happend something that shouldnot happen!"
################################################################################
### Bezier additional functions
################################################################################
return [
]
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 bez_to_csp_segment(bez) :
def bez_split(a,t=0.5) :
# returns [d^2,t]
def bez_normalized_slope(bez,t):
################################################################################
### Some vector functions
################################################################################
def normalize((x,y)) :
if l == 0 : return [0.,0.]
else : return [x/l, y/l]
def cross(a,b) :
return a[1] * b[0] - a[0] * b[1]
def dot(a,b) :
return a[0] * b[0] + a[1] * b[1]
def rotate_ccw(d) :
return [-d[1],d[0]]
def vectors_ccw(a,b):
return a[0]*b[1]-b[0]*a[1] < 0
def vector_from_to_length(a,b):
################################################################################
### 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 :
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
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
if det==0: return None
return [
]
def small(a) :
global small_tolerance
return abs(a)<small_tolerance
else :
if style == None :
style = "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;"
'x': str(x),
'y': str(y)
})
for s in text :
{
'x': str(x),
'y': str(+y),
})
y += font_size
if figure == "line" :
s = ""
s+= " %s, %s " %(x[i*2],x[i*2+1])
inkex.etree.SubElement( options.doc_root, inkex.addNS('path','svg'), {"d": "M %s,%s L %s"%(x[0],x[1],s), "style":"fill:none;stroke:%s;stroke-width:%f;"%(color,width),"comment":str(comment)} )
else :
inkex.etree.SubElement( options.doc_root, inkex.addNS('path','svg'), {"d": "m %s,%s l 10,10 -20,-20 10,10 -10,10, 20,-20"%(x[0],x[1]), "style":"fill:none;stroke:%s;stroke-width:%f;"%(color,width),"comment":str(comment)} )
def straight_segments_intersection(a,b, true_intersection = True) : # (True intersection means check ta and tb are in [0,1])
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 :
def between(c,x,y):
return x-straight_tolerance<=c<=y+straight_tolerance or y-straight_tolerance<=c<=x+straight_tolerance
def cubic_solver(a,b,c,d):
if a!=0:
# Monics formula see http://en.wikipedia.org/wiki/Cubic_function#Monic_formula_of_roots
a,b,c = (b/a, c/a, d/a)
m = 2*a**3 - 9*a*b + 27*c
k = a**2 - 3*b
n = m**2 - 4*k**3
if n>=0 :
else :
elif b!=0:
if det>0 :
elif d == 0 :
return [-c/(b*b)]
else :
elif c!=0 :
return [-d/c]
else : return []
################################################################################
### print_ prints any arguments into specified log file
################################################################################
for s in arg :
f.write( s )
f.write("\n")
f.close()
################################################################################
### Point (x,y) operations
################################################################################
class P:
if not y==None:
else:
if isinstance(other, P):
if h: return self / h
else: return P(0,0)
################################################################################
###
### 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
print_("Offset radius %s"% r)
result = []
t.sort()
if t[0]>.00000001 : t = [0.]+t
if (c>1/r and r<0 or c<1/r and r>0) :
else : # This part will be clipped for sure... TODO Optimize it...
if result==[] :
else:
else:
if intersection != [] :
else :
pass # ???
#raise ValueError, "Offset curvature clipping error"
#csp_draw([result])
return result
# See Gernot Hoffmann "Bezier Curves" p.34 -> 7.1 Bezier Offset Curves
if intersection != [] :
break
if _break:break
if _break :
else :
return []
if intersection != [] :
# Offsets do not intersect... will add an arc...
if arc == [] :
else:
# Clip prev by arc
if intersection != [] :
#else : raise ValueError, "Offset curvature clipping error"
# Clip next by arc
if next == [] :
if intersection != [] :
#else : raise ValueError, "Offset curvature clipping error"
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],
)
#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)
else :
t = .5
else :
#csp_draw([[sp1_r,sp2_r]])
#draw_pointer(sp1[1]+sp1_r[1], "#057", "line")
#draw_pointer(sp2[1]+sp2_r[1], "#705", "line")
############################################################################
# Some small definitions
############################################################################
############################################################################
# Prepare the path
############################################################################
# Remove all small segments (segment length < 0.001)
# 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.
############################################################################
# Offset
############################################################################
# Create offsets for all segments in the path. And join them together inside each subpath.
subpath_offset = []
last_offset_len = 0
if subpath_offset == [] :
else :
#csp_draw([prev],"Blue")
#csp_draw([arc],"Magenta")
# 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)
#csp_draw([prev],"Blue")
#csp_draw([arc],"Red")
#csp_draw([next],"Red")
# Collect subpath's offset and save it to unclipped offset list.
unclipped_offset[i] = subpath_offset[:]
#for k,t in intersection[i]:
# draw_pointer(csp_at_t(subpath_offset[k-1], subpath_offset[k], t))
#inkex.etree.SubElement( options.doc_root, inkex.addNS('path','svg'), {"d": cubicsuperpath.formatPath(unclipped_offset), "style":"fill:none;stroke:#0f0;"} )
#for i in range(len(unclipped_offset)):
# csp_draw([unclipped_offset[i]], color = ["Green","Red","Blue"][i%3], width = .1)
#return []
############################################################################
# Now to the clipping.
############################################################################
# First of all find all intersection's between all segments of all offseted subpaths, including self intersections.
#TODO define offset tolerance here
global small_tolerance
small_tolerance = 0.01
summ = 0
summ1 = 0
# If subpath_i==subpath_j we are looking for self intersections, so
# we'll need search intersections only for xrange(i,len(subpath1))
# Find self intersections of a segment
summ +=1
for t in intersections :
summ1 += 1
else :
summ +=1
for t in intersections :
summ1 += 1
#TODO tolerance dependence to cpsp_length(t)
#draw_pointer(csp_at_t(subpath[i-1],subpath[i],t[0]),"#f00")
#print_(t)
#print_(i,j)
########################################################################
# Split unclipped offset by intersection points into splitted_offset
########################################################################
splitted_offset = []
subpath = unclipped_offset[i]
# Close parts list to close path (The first and the last parts are joined together)
else:
splitted_offset += parts[:]
else :
splitted_offset += [subpath[:]]
#for i in range(len(splitted_offset)):
# csp_draw([splitted_offset[i]], color = ["Green","Red","Blue"][i%3])
########################################################################
# Clipping
########################################################################
result = []
if (P(s1[0][1])-P(s2[-1][1])).l2()<0.0001 and ( (subpath_i+1) % len(splitted_offset) != subpath_j ):
break
if (P(s2[0][1])-P(s1[-1][1])).l2()<0.0001 and ( (subpath_j+1) % len(splitted_offset) != subpath_i ):
break
if not clip :
elif options.offset_draw_clippend_path :
(P(csp_at_t(s2[-2],s2[-1],1.))+ P(csp_normalized_normal(s2[-2],s2[-1],1.))*10).to_list(),"Green", "line" )
# Now join all together and check closure and orientation of result
# Check if each subpath from joined_result is closed
#csp_draw(joined_result,color="Green",width=1)
for s in joined_result[:] :
if csp_subpaths_end_to_start_distance2(s,s) > 0.001 :
# Remove open parts
else :
# Remove small parts
########################################################################
# Now to the Dummy cliping: remove parts from splitted offset if their
# centers are closer to the original path than offset radius.
########################################################################
for s in joined_result[:]:
dist = csp_to_point_distance(original_csp, s[int(len(s)/2)][1], dist_bounds = [r1,r2], tolerance = .000001)
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_()
return joined_result
################################################################################
###
### Biarc function
###
### Calculates biarc approximation of cubic super path segment
### splits segment if needed or approximates it with straight line
###
################################################################################
# Both tangents are zerro - line straight
else:
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
# 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
if v.mag()==0:
elif not asmall:
discr = b*b-4*a*c
return None, None
else :
return R, alpha
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]] ]
if d > options.biarc_tolerance and depth<options.biarc_max_split_depth : return biarc_split(sp1, sp2, z1, z2, depth)
else:
return [ [ sp1[1], 'arc', [R1.x,R1.y], a1, [P2.x,P2.y], [z1,zm] ], [ [P2.x,P2.y], 'arc', [R2.x,R2.y], a2, [P4.x,P4.y], [zm,z2] ] ]
else:
return 0
# get first subcurve and ceck it's length
break
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
while lc<l :
if reverse :
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?
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?
if ls != 0 :
else :
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
return res
class Postprocessor():
}
for s in command:
s = s.strip()
if s!="" :
if not r:
else :
self.error("Unrecognized function '%s' while postprocessing.\n(Command: '%s')"%(function,command), "error")
# remap parameters should be like "x->y,y->x"
for s in parameters:
if not r :
if case_sensitive :
else :
gcode = ""
warned = []
plane = "g17"
# get plane selection:
if r :
# Raise warning if scale factors are not the game for G02 and G03
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")
# Transform
for a in axis[i] :
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 :
try:
except:
pass
gcode += s + "\n"
if flip :
planes = []
feeds = {}
coords = []
gcode = ""
# get Planes
if r :
# get Feeds
if r :
#Coordinates
for c in "xyzijka" :
if r :
if c not in coords :
coords += [c]
# Add offset parametrization
for c in coords:
# Add scale parametrization
gcode += "#10 = 1 (Scale factor)\n"
else :
if "g17" in planes :
if "g18" in planes :
if "g19" in planes :
# Add a scale
if "a" in coords:
gcode += "#12 = 1 (A axis scale)\n"
# Add feed parametrization
for f in feeds :
# Parameterize Gcode
#feed replace :
#Coords XYZA replace
for c in "xyza" :
#Coords IJKR replace
for c in "ijkr" :
gcode += s + "\n"
try:
except :
self.error("Bad parameters for round. Round should be an integer! \n(Parameters: '%s')"%(parameters), "error")
gcode = ""
for a in "xyzijkaf" :
if r :
r"(?i)("+a+r")\s*(-?)\s*(\d*\.?\d*)",
s)
gcode += s + "\n"
try :
self.error("Bad parameters for scale. Scale should not be 0 at any axis! \n(Parameters: '%s')"%(parameters), "error")
except :
try :
except :
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")
################################################################################
### Polygon class
################################################################################
class Polygon:
for p in poly :
return b[2]-b[0]
# Polygon is a list of simple polygons
# Surface is a polygon + line y = 0
# Direction is [dx,dy]
centroids = []
sa = 0
a *= 3.
if abs(a)>0 :
cx /= a
cy /= a
for c in centroids :
# Polygon is a list of simple polygons
# Surface is a polygon + line y = 0
# Down means min y (0,-1)
# Get surface top point
# Get polygon bottom point
# 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
# and vice versa just change the sign because vertex now under the edge
#print_(dist, top, bottom)
#self.draw()
else :
def point_inside(self,p) :
if st[0]>end[0] : st, end = end, st # This will be needed to check that edge if open only at rigth end
#print_(c)
if c<0 :
return True
return inside
# Add vertices at all self intersection points.
hull = []
poly_ = []
poly_ += [s]
# Check self intersections
for p in int_ :
poly_ += [p]
# Check self intersections with other polys
for p in int_ :
poly_ += [p]
# Create the dictionary containing all edges in both directions
edges = {}
if (point_to_point_d2(e,s)<0.000001) : continue
for p in edges :
if point_to_point_d2(p,s)<0.000001 :
s = p
if point_to_point_d2(p,e)<0.000001 :
e = p
l = point_to_point_d(s,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 :
break
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 :
break
edges[s] += [ [s,e, l] ]
#draw_pointer(s+e,"red","line")
else :
edges[s] = [ [s,e,l] ]
#draw_pointer(s+e,"green","line")
# 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
# 0 = 2*pi is the largest angle
return False
return True
# Last edge is normalized vector of the last edge.
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))
#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)
next = p
#print_("min_angle=",min_angle)
return next
# Join edges together into new polygon cutting the vertexes inside new polygon
loops = 0
poly = []
loops+=1
# Find left most vertex.
loops1 = 0
loops1 += 1
#draw_pointer(next[0]+next[1],"Green","line", comment=i, width= 1)
#print_(next[0],"-",next[1])
# Remove all edges that are intersects new poly (any vertex inside new poly)
class Arangement_Genetic:
# gene = [fittness, order, rotation, xposition]
# spieces = [gene]*shapes count
# population = [spieces]
self.population = []
specimen = []
for j in order:
# retun distance, each component is normalized
s = 0
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
# 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
t = []
for j in range(20) :
t.sort()
#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]]
genes_order = []
# OMG it's a incest :O!!!
# Damn you bastards!
else :
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 :
#rotation_mutate_param = random.random()/100
#xposition_mutate_param = random.random()/100
specimen[i] = [parent1[i][0], parent1[i][1]*tr+parent2[i][1]*(1-tr),parent1[i][2]*tp+parent2[i][2]*(1-tp)]
j = i
specimen[i] = [parent2[j][0], parent1[i][1]*tr+parent2[i][1]*(1-tr),parent1[i][2]*tp+parent2[i][2]*(1-tp)]
for i in range(random.randint(self.mutation_genes_count[0],self.mutation_genes_count[0]*self.incest_mutation_count_multiplyer )) :
for p in spiece :
return surface
i = 0
for p in spiece[1:] :
i += 1
return surface
#surface.draw()
################################################################################
###
### Gcodetools class
###
################################################################################
f.close()
################################################################################
### Arrangement: arranges paths by givven params
### TODO move it to the bottom
################################################################################
def arrangement(self) :
polygons = []
original_paths = []
#print_("Redused edges count from", sum([len(poly) for poly in polygon.polygon ]) )
original_paths += [path]
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) ) )
# material_width = self.options.arrangement_material_width
# population = Arangement_Genetic(polygons, material_width)
# population.add_random_species(1)
# population.test_population_centroid()
## return
last_champ = []
champions_count = 0
for i in range(population_count):
"""
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)
"""
print_()
print_(x[0])
k = ""
#for j in range(10) :
# k += "%s " % population.population[j][0]
print_()
#print_(k)
#print_()
colors = ["blue"]
champions_count += 1
for p in spiece[1:] :
# poly.draw(color = "Violet",width=4)
# Now we'll need apply transforms to original paths
self.OptionParser.add_option("-d", "--directory", action="store", type="string", dest="directory", default="/home/", help="Directory for gcode file")
self.OptionParser.add_option("-f", "--filename", action="store", type="string", dest="file", default="-1.0", help="File name")
self.OptionParser.add_option("", "--add-numeric-suffix-to-filename", action="store", type="inkbool", dest="add_numeric_suffix_to_filename", default=True,help="Add numeric suffix to filename")
self.OptionParser.add_option("", "--Zscale", action="store", type="float", dest="Zscale", default="1.0", help="Scale factor Z")
self.OptionParser.add_option("", "--Zoffset", action="store", type="float", dest="Zoffset", default="0.0", help="Offset along Z")
self.OptionParser.add_option("-s", "--Zsafe", action="store", type="float", dest="Zsafe", default="0.5", help="Z above all obstacles")
self.OptionParser.add_option("-z", "--Zsurface", action="store", type="float", dest="Zsurface", default="0.0", help="Z of the surface")
self.OptionParser.add_option("-c", "--Zdepth", action="store", type="float", dest="Zdepth", default="-0.125", help="Z depth of cut")
self.OptionParser.add_option("", "--Zstep", action="store", type="float", dest="Zstep", default="-0.125", help="Z step of cutting")
self.OptionParser.add_option("-p", "--feed", action="store", type="float", dest="feed", default="4.0", help="Feed rate in unit/min")
self.OptionParser.add_option("", "--biarc-tolerance", action="store", type="float", dest="biarc_tolerance", default="1", help="Tolerance used when calculating biarc interpolation.")
self.OptionParser.add_option("", "--biarc-max-split-depth", action="store", type="int", dest="biarc_max_split_depth", default="4", help="Defines maximum depth of splitting while approximating using biarcs.")
self.OptionParser.add_option("", "--tool-diameter", action="store", type="float", dest="tool_diameter", default="3", help="Tool diameter used for area cutting")
self.OptionParser.add_option("", "--max-area-curves", action="store", type="int", dest="max_area_curves", default="100", help="Maximum area curves for each area")
self.OptionParser.add_option("", "--area-inkscape-radius", action="store", type="float", dest="area_inkscape_radius", default="-10", help="Radius for preparing curves using inkscape")
self.OptionParser.add_option("", "--unit", action="store", type="string", dest="unit", default="G21 (All units in mm)", help="Units")
self.OptionParser.add_option("", "--active-tab", action="store", type="string", dest="active_tab", default="", help="Defines which tab is active")
self.OptionParser.add_option("", "--area-find-artefacts-diameter",action="store", type="float", dest="area_find_artefacts_diameter", default="1", help="artefacts seeking radius")
self.OptionParser.add_option("", "--area-find-artefacts-action", action="store", type="string", dest="area_find_artefacts_action", default="mark with an arrow", help="artefacts action type")
self.OptionParser.add_option("", "--auto_select_paths", action="store", type="inkbool", dest="auto_select_paths", default=True, help="Select all paths if nothing is selected.")
self.OptionParser.add_option("", "--loft-distances", action="store", type="string", dest="loft_distances", default="10", help="Distances between paths.")
self.OptionParser.add_option("", "--loft-direction", action="store", type="string", dest="loft_direction", default="crosswise", help="Direction of loft's interpolation.")
self.OptionParser.add_option("", "--loft-interpolation-degree", action="store", type="float", dest="loft_interpolation_degree", default="2", help="Which interpolation use to loft the paths smooth interpolation or staright.")
self.OptionParser.add_option("", "--min-arc-radius", action="store", type="float", dest="min_arc_radius", default=".1", help="All arc having radius less than minimum will be considered as straight line")
self.OptionParser.add_option("", "--engraving-sharp-angle-tollerance",action="store", type="float", dest="engraving_sharp_angle_tollerance", default="150", help="All angles thar are less than engraving-sharp-angle-tollerance will be thought sharp")
self.OptionParser.add_option("", "--engraving-max-dist", action="store", type="float", dest="engraving_max_dist", default="10", help="Distanse from original path where engraving is not needed (usualy it's cutting tool diameter)")
self.OptionParser.add_option("", "--engraving-newton-iterations", action="store", type="int", dest="engraving_newton_iterations", default="4", help="Number of sample points used to calculate distance")
self.OptionParser.add_option("", "--engraving-draw-calculation-paths",action="store", type="inkbool", dest="engraving_draw_calculation_paths", default=False, help="Draw additional graphics to debug engraving path")
self.OptionParser.add_option("", "--engraving-cutter-shape-function",action="store", type="string", dest="engraving_cutter_shape_function", default="w", help="Cutter shape function z(w). Ex. cone: w. ")
self.OptionParser.add_option("", "--lathe-width", action="store", type="float", dest="lathe_width", default=10., help="Lathe width")
self.OptionParser.add_option("", "--lathe-fine-cut-width", action="store", type="float", dest="lathe_fine_cut_width", default=1., help="Fine cut width")
self.OptionParser.add_option("", "--lathe-fine-cut-count", action="store", type="int", dest="lathe_fine_cut_count", default=1., help="Fine cut count")
self.OptionParser.add_option("", "--lathe-create-fine-cut-using", action="store", type="string", dest="lathe_create_fine_cut_using", default="Move path", help="Create fine cut using")
self.OptionParser.add_option("", "--lathe-x-axis-remap", action="store", type="string", dest="lathe_x_axis_remap", default="X", help="Lathe X axis remap")
self.OptionParser.add_option("", "--lathe-z-axis-remap", action="store", type="string", dest="lathe_z_axis_remap", default="Z", help="Lathe Z axis remap")
self.OptionParser.add_option("", "--create-log", action="store", type="inkbool", dest="log_create_log", default=False, help="Create log files")
self.OptionParser.add_option("", "--log-filename", action="store", type="string", dest="log_filename", default='', help="Create log files")
self.OptionParser.add_option("", "--orientation-points-count", action="store", type="int", dest="orientation_points_count", default='2', help="Orientation points count")
self.OptionParser.add_option("", "--tools-library-type", action="store", type="string", dest="tools_library_type", default='cylinder cutter', help="Create tools defention")
self.OptionParser.add_option("", "--dxfpoints-action", action="store", type="string", dest="dxfpoints_action", default='replace', help="dxfpoint sign toggle")
self.OptionParser.add_option("", "--help-language", action="store", type="string", dest="help_language", default='http://www.cnc-club.ru/forum/viewtopic.php?f=33&t=35', help="Open help page in webbrowser.")
self.OptionParser.add_option("", "--offset-radius", action="store", type="float", dest="offset_radius", default=10., help="Offset radius")
self.OptionParser.add_option("", "--offset-step", action="store", type="float", dest="offset_step", default=10., help="Offset step")
self.OptionParser.add_option("", "--offset-draw-clippend-path", action="store", type="inkbool", dest="offset_draw_clippend_path", default=False, help="Draw clipped path")
self.OptionParser.add_option("", "--offset-just-get-distance", action="store", type="inkbool", dest="offset_just_get_distance", default=False, help="Don't do offset just get distance")
self.OptionParser.add_option("", "--arrangement-material-width", action="store", type="float", dest="arrangement_material_width", default=500, help="Materials width for arrangement")
self.OptionParser.add_option("", "--arrangement-population-count",action="store", type="int", dest="arrangement_population_count", default=100, help="Genetic algorithm populations count")
self.OptionParser.add_option("", "--postprocessor", action="store", type="string", dest="postprocessor", default='', help="Postprocessor command.")
self.OptionParser.add_option("", "--postprocessor-custom", action="store", type="string", dest="postprocessor_custom", default='', help="Postprocessor custom command.")
self.default_tool = {
"name": "Default tool",
"id": "default tool",
"diameter":10.,
"shape": "10",
"penetration angle":90.,
"penetration feed":100.,
"depth step":1.,
"feed":400.,
"in trajectotry":"",
"out trajectotry":"",
"gcode before path":"",
"gcode after path":"",
"sog":"",
"spinlde rpm":"",
"CW or CCW":"",
"tool change gcode":" ",
"4th axis meaning": " ",
"4th axis scale": 1.,
"4th axis offset": 0.,
"passing feed":"800",
"fine feed":"800",
}
'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",
]
c = []
if len(p)==0 :
return []
### Sort to reduce Rapid distance
keys = [0]
while len(k)>0:
dist = None
del k[dist[1]]
for k in keys:
subpath = p[k]
# 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]) )
return c
# Add marker to defs if it doesnot exists
marker = inkex.etree.SubElement( defs, inkex.addNS("marker","svg"), {"id":"DrawCurveMarker","orient":"auto","refX":"-8","refY":"-2.41063","style":"overflow:visible"})
{ "d":"m -6.55552,-2.41063 0,0 L -13.11104,0 c 1.0473,-1.42323 1.04126,-3.37047 0,-4.82126",
"style": "fill:#000044; fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;" }
)
marker = inkex.etree.SubElement( defs, inkex.addNS("marker","svg"), {"id":"DrawCurveMarker_r","orient":"auto","refX":"8","refY":"-2.41063","style":"overflow:visible"})
{ "d":"m 6.55552,-2.41063 0,0 L 13.11104,0 c -1.0473,-1.42323 -1.04126,-3.37047 0,-4.82126",
"style": "fill:#000044; fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;" }
)
for i in [0,1]:
if group==None:
group = inkex.etree.SubElement( self.layers[min(1,len(self.layers)-1)], inkex.addNS('g','svg'), {"gcodetools": "Preview group"} )
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)
else : reverse_angle = -1
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':
{
"gcodetools": "Preview",
}
)
elif s[1] == 'arc':
arcn += 1
sp = s[0]
c = s[2]
if s[3]*a<0:
if a>0:
else:
{
'style': st,
"gcodetools": "Preview",
})
s = si
else :
f.close()
else:
f.close()
else:
else:
self.error(_("Directory does not exist! Please specify existing directory at Preferences tab!"),"error")
return False
else:
ext = ""
max_n = 0
for s in dir_list :
if r :
try:
f.close()
except:
self.error(_("Can not write to specified file!\n%s"%(self.options.directory+self.options.file)),"error")
return False
return True
################################################################################
###
### Generate Gcode
### Generates Gcode on given curve.
###
### Crve defenitnion [start point, type = {'arc','line','move','end'}, arc center, arc angle, end point, [zstart, zend]]
###
################################################################################
def c(c):
if c[5] == 0 : c[5]=None
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(
try :
self.last_used_tool == None
except :
self.last_used_tool = None
print_("working on curve")
current_a = 0
# Creating Gcode for curve between s=curve[i-1] and si=curve[i] start at s[0] end at s[4]=si[0]
if s[1] == 'move':
lg = 'G00'
elif s[1] == 'end':
lg = 'G00'
elif s[1] == 'line':
a = calculate_angle(a, current_a)
current_a = a
lg = 'G01'
elif s[1] == 'arc':
r = [(s[2][0]-s[0][0]), (s[2][1]-s[0][1])]
if s[3]<0 : # CW
else: #CCW
current_a = a
else : axis4 = ""
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:
lg = 'G02'
else:
a = calculate_angle(a, current_a)
current_a = a
lg = 'G01'
return g
def get_transforms(self,g):
trans = []
while (g!=root):
if 'transform' in g.keys():
t = g.get('transform')
t = simpletransform.parseTransform(t)
g=g.getparent()
return trans
if trans != []:
return csp
break
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")
else :
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 += [ [ [(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]] ] ]
# 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])]
])
[[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()
else :
self.error(_("Orientation points are wrong! (if there are two orientation points they sould not be the same. If there are three orientation points they should not be in a straight line.)"),"wrong_orientation_points")
else :
self.error(_("Orientation points are wrong! (if there are two orientation points they sould not be the same. If there are three orientation points they should not be in a straight line.)"),"wrong_orientation_points")
###self.Zauto_scale[layer] = math.sqrt( (self.transform_matrix[layer][0][0]**2 + self.transform_matrix[layer][1][1]**2)/2 )
### Zautoscale is absolete
if not reverse :
else :
return [t[0][0]*x+t[0][1]*y+t[0][2], t[1][0]*x+t[1][1]*y+t[1][2]]
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_)) ]
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).
################################################################################
notes = "Note "
warnings = """
Warning tools_warning
bad_orientation_points_in_some_layers
more_than_one_orientation_point_groups
more_than_one_tool
orientation_have_not_been_defined
tool_have_not_been_defined
selection_does_not_contain_paths
selection_does_not_contain_paths_will_take_all
selection_is_empty_will_comupe_drawing
selection_contains_objects_that_are_not_paths
"""
errors = """
Error
wrong_orientation_points
area_tools_diameter_error
no_tool_error
active_layer_already_has_tool
active_layer_already_has_orientation_points
"""
print_(s)
print_(s)
print_(s)
else :
print_(s)
################################################################################
### Get defs from svg
################################################################################
def recursive(g) :
for i in g:
for j in i:
recursive(i)
################################################################################
###
### Get Gcodetools info from the svg
###
################################################################################
self.selected_paths = {}
self.orientation_points = {}
self.Zcoordinates = {}
self.transform_matrix = {}
self.Zauto_scale = {}
items = g.getchildren()
for i in items:
if selected:
recursive_search(i,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")
if "gcodetools" not in i.keys() :
self.selected_paths[layer] = self.selected_paths[layer] + [i] if layer in self.selected_paths else [i]
# 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")
def get_orientation_points(self,g):
items = g.getchildren()
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 p==None : return None
points = []
for i in p :
point = [[],[]]
for node in i :
r = re.match(r'(?i)\s*\(\s*(-?\s*\d*(?:,|\.)*\d*)\s*;\s*(-?\s*\d*(?:,|\.)*\d*)\s*;\s*(-?\s*\d*(?:,|\.)*\d*)\s*\)\s*',node.text)
else : return None
tool["self_group"] = g
for i in g:
# Get parameters
key = None
value = None
for j in i:
for k in j :
if k.tag == inkex.addNS('tspan','svg') and k.get("gcodetools") == "Gcodetools tool defention field value":
#print_("Found tool parameter '%s':'%s'" % (key,value))
try :
except :
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 :
self.error(_("Warning! Tool has parameter that default tool has not ( '%s': '%s' ).") % (key, value), "tools_warning" )
return tool
# print_(("index(layer)=",self.layers.index(layer),"set_tool():layer=",layer,"self.tools=",self.tools))
# for l in self.layers:
# print_(("l=",l))
# print_(("processing layer",i))
break
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")
else :
self.error(_("Can not find tool for '%s' layer! Please add one with Tools library tab!") % layer.get(inkex.addNS('label','inkscape')), "no_tool_error")
################################################################################
###
### Path to Gcode
###
################################################################################
def path_to_gcode(self) :
def get_boundaries(points):
out=[[],[],[],[]]
for p in points:
if minx==p[0]:
out[0]+=[p]
minx=p[0]
out[0]=[p]
if miny==p[1]:
out[1]+=[p]
miny=p[1]
out[1]=[p]
if maxx==p[0]:
out[2]+=[p]
maxx=p[0]
out[2]=[p]
if maxy==p[1]:
out[3]+=[p]
maxy=p[1]
out[3]=[p]
return out
def remove_duplicates(points):
i=0
out=[]
for p in points:
if p!=[None,None]: out+=[p]
i+=1
return(out)
def get_way_len(points):
l=0
return l
def sort_dxfpoints(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:
cw=[]
# print_(("tpoints=",tpoints))
# print_(p)
cw+=p
return minimal_way
def print_dxfpoints(points):
gcode=""
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
else :
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_(("processing layer",layer," of layers:",self.layers))
# print_(("layer ",layer, " is in paths:",paths))
p = []
dxfpoints = []
self.error(_("Warning: One or more paths dont have 'd' parameter, try to Ungroup (Ctrl+Shift+G) and Object to Path (Ctrl+Shift+C)!"),"selection_contains_objects_that_are_not_paths")
continue
print_("got dxfpoint (scaled) at (%f,%f)" % (x,y))
dxfpoints += [[x,y]]
else:
p += csp
for step in range( 0, int(math.ceil( abs( (self.Zcoordinates[layer][1]-self.Zcoordinates[layer][0])/self.tools[layer][0]["depth step"] )) ) ):
Zpos = max( self.Zcoordinates[layer][1], self.Zcoordinates[layer][0] - abs(self.tools[layer][0]["depth step"]*(step+1)) )
################################################################################
###
### dxfpoints
###
################################################################################
if self.selected_paths == {}:
self.error(_("Nothing is selected. Please select something to convert to drill point (dxfpoint) or clear point sign."),"warning")
# print_(("processing path",path.get('d')))
# print_("trying to set as dxfpoint")
if r!=None:
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))
# for id, node in self.selected.iteritems():
# print_((id,node,node.attrib))
################################################################################
###
### Artefacts
###
################################################################################
def area_artefacts(self) :
else :
# paths[layer].reverse() # Reverse list of paths to leave their order
self.error(_("Warning: One or more paths dont have 'd' parameter, try to Ungroup (Ctrl+Shift+G) and Object to Path (Ctrl+Shift+C)!"),"selection_contains_objects_that_are_not_paths")
continue
if (bounds[2]-bounds[0])**2+(bounds[3]-bounds[1])**2 < self.options.area_find_artefacts_diameter**2:
{
'd': 'm %s,%s 2.9375,-6.343750000001 0.8125,1.90625 6.843748640396,-6.84374864039 0,0 0.6875,0.6875 -6.84375,6.84375 1.90625,0.812500000001 z' % (subpath[0][1][0],subpath[0][1][1]),
'gcodetools': 'area artefact arrow',
})
inkex.etree.SubElement(parent, inkex.addNS('path','svg'), {'d': cubicsuperpath.formatPath([subpath]), 'style': style, "gcodetools_parameter":"area artefact"})
inkex.etree.SubElement(parent, inkex.addNS('path','svg'), {'d': cubicsuperpath.formatPath([subpath]), 'style': styles["area artefact"]})
else :
inkex.etree.SubElement(parent, inkex.addNS('path','svg'), {'d': cubicsuperpath.formatPath([subpath]), 'style': style})
return
################################################################################
###
### Calculate area curves
###
################################################################################
return
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")
print_(d)
if d==None:
print_("omitting non-path")
continue
# Path is not offset. Preparation will be needed.
# Finding top most point in path (min y value)
# Reverse path if needed.
# Move outline subpath to the begining of csp
j = min_j
# Split by the topmost point and join again
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:
subp = [ [ sp2[1], sp2[1],sp2[2] ] ] + [sp3] + subp[j+1:] + subp[:j-1] + [sp1] + [[ sp2[0], sp2[1],sp2[1] ]]
# reverse path if needed
n = []
for j in csp[i]:
n = [ [j[2][:],j[1][:],j[0][:]] ] + n
csp[i] = n[:]
print_(("original d=",d))
print_(("formatted d=",d))
# scale = sqrt(Xscale**2 + Yscale**2) / sqrt(1**2 + 1**2)
radius = -r
{
})
if radius == -r : break
################################################################################
###
### Engraving
###
################################################################################
return
gcode = ''
####################################################################
### To find center of cutter a system of non linear equations
### will be solved using Newton's method
####################################################################
intersection, t1, t2 = straight_segments_intersection([[x1,y1],[x1+nx1,y1+ny1]],[[fx,fy],[fx+nx2,fy+ny2]], False)
if nx1!=0 :
else :
i = 0
F = [0.,0.,0.]
i+=1
return t+[1e100,i]
if F1!= None :
else: break
cspe =[]
we = []
engraving_group = inkex.etree.SubElement( self.selected_paths[layer][0].getparent(), inkex.addNS('g','svg') )
# Remove zerro length segments
i = 1
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:
del cspi[j][i]
else:
i += 1
# Create list containing normlas and points
nl = []
n, n1 = [], []
# Is following string is nedded or not??? (It makes t depend on form of the curve)
#ti = bezmisc.beziertatlength(bez,ti)
n+=[ [ [x1,y1], [nx,ny], False, False, i] ] # [point coordinates, normal, is an inner corner, is an outer corner, csp's index]
for t in [.0,.25,.75,1.]:
n1 += [ [ [x1,y1], [nx*math.cos(a*t)-ny*math.sin(a*t),nx*math.sin(a*t)+ny*math.cos(a*t)], False, True, i ] ]
if abs(csp[-1][1][0]-csp[0][1][0])<engraving_tolerance and abs(csp[-1][1][1]-csp[0][1][1])<engraving_tolerance :
if ang > 0 and 180-math.acos(nx*nx2+ny*ny2)*180/math.pi < self.options.engraving_sharp_angle_tollerance : # inner angle
elif ang < 0 and 180-math.acos(nx*nx2+ny*ny2)*180/math.pi < self.options.engraving_sharp_angle_tollerance : # outer angle
n1 = []
for t in [.0,.25,.75,1.]:
n1 += [ [ [x1,y1], [nx*math.cos(a*t)-ny*math.sin(a*t),nx*math.sin(a*t)+ny*math.cos(a*t)], False, True, i ] ]
for i in nl:
for p in i:
{
"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 calculation paths"
})
# Calculate offset points
csp_points = []
p = []
# Point is a sharp angle r=0p
r = 0
else :
continue
t = find_cutter_center((x1,y1),(nx,ny), cspi[j][i-1], cspi[j][i], self.tools[layer][0], float(n1)/(self.options.engraving_newton_iterations-1))
print_(t)
print_("!@#!@#!@#!@#!@",t)
t3 = t[2]
ax,ay,bx,by,cx,cy,dx,dy=bezmisc.bezierparameterize((cspi[j][i-1][1],cspi[j][i-1][2],cspi[j][i][0],cspi[j][i][1]))
# d = curvature
if d!=0 :
if d>0:
r = min( d,r) if r!=None else d
else :
else:
if (abs(x1-x2)>engraving_tolerance or abs(y1-y2)>engraving_tolerance ) and (x2*nx - x1*nx + y2*ny - y1*ny) != 0:
{"gcodetools": "Engraving calculation paths", 'style': "fill:#ff00ff; fill-opacity:0.46; stroke:#000000; stroke-width:0.1;", inkex.addNS('cx','sodipodi'): str(x1+nx*r), inkex.addNS('cy','sodipodi'): str(y1+ny*r), inkex.addNS('rx','sodipodi'): str(1), inkex.addNS('ry','sodipodi'): str(1), inkex.addNS('type','sodipodi'): 'arc'})
{"gcodetools": "Engraving calculation paths", 'style': "fill:none; fill-opacity:0.46; stroke:#000000; stroke-width:0.1;", inkex.addNS('cx','sodipodi'): str(x1+nx*r), inkex.addNS('cy','sodipodi'): str(y1+ny*r),inkex.addNS('rx','sodipodi'): str(r), inkex.addNS('ry','sodipodi'): str(r), inkex.addNS('type','sodipodi'): 'arc'})
csp_points += [ p ]
# Splitting path to pieces each of them not further from path more than engraving_max_dist
engraving_path = [ [] ]
for p_ in csp_points :
for p in p_:
else :
for csp_points in engraving_path :
# Create Path that goes through this points
cspm = []
w = []
m = [[0.0, 0.0, 0.0, 1.0], [0.015625, 0.140625, 0.421875, 0.421875], [0.421875, 0.421875, 0.140625, 0.015625], [1.0, 0.0, 0.0, 0.0]]
for p in csp_points:
sp1[2] = c
sp2[0] = b
if l1!=0:
else :
"gcodetools": "Engraving calculation paths",
})
{"gcodetools": "Engraving calculation paths", 'style': "fill:none; fill-opacity:0.46; stroke:#000000; stroke-width:0.1;", inkex.addNS('cx','sodipodi'): str(cspm[i][1][0]), inkex.addNS('cy','sodipodi'): str(cspm[i][1][1]),inkex.addNS('rx','sodipodi'): str(w[i]), inkex.addNS('ry','sodipodi'): str(w[i]), inkex.addNS('type','sodipodi'): 'arc'})
we += [w]
else:
self.error(_("Tool '%s' has no shape!") % self.tools[layer][0]['name'],"engraving_tools_shape_error")
f = lambda w: w
if cspe!=[]:
if gcode!='' :
################################################################################
###
### Orientation
###
################################################################################
print_("entering orientations")
if layer == None :
self.error(_("Active layer already has orientation points! Remove them or select another layer!"),"active_layer_already_has_orientation_points")
orientation_group = inkex.etree.SubElement(layer, inkex.addNS('g','svg'), {"gcodetools":"Gcodetools orientation group"})
doc_height = 1052.3622047
orientation_scale = 3.5433070660
orientation_scale = 90
for i in points :
g = inkex.etree.SubElement(orientation_group, inkex.addNS('g','svg'), {'gcodetools': "Gcodetools orientation point (%s points)" % self.options.orientation_points_count})
{
'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"
})
{
'style': "font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;",
'gcodetools': "Gcodetools orientation point text"
})
################################################################################
###
### Tools library
###
################################################################################
# Add a tool to the drawing
if layer == None :
self.error(_("Active layer already has a tool! Remove it or select another layer!"),"active_layer_already_has_tool")
tool = {
"name": "Cylindrical cutter",
"id": "Cylindrical cutter 0001",
"diameter":10,
"penetration angle":90,
"feed":"400",
"penetration feed":"100",
"depth step":"1",
"tool change gcode":" "
}
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":" "
}
tool = {
"name": "Cone cutter",
"id": "Cone cutter 0001",
"diameter":10,
"shape":"w",
"feed":"400",
"penetration feed":"100",
"depth step":"1",
"tool change gcode":" "
}
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":" "
}
tool = {
"name": "Plasma cutter",
"id": "Plasma cutter 0001",
"diameter":10,
"penetration feed":100,
"feed":400,
"gcode before path":"""G31 Z-100 F500 (find metal)
G92 Z0 (zerro z)
G00 Z10 F500 (going up)
M03 (turn on plasma)
G04 P0.2 (pause)
G01 Z1 (going to cutting z)\n""",
"gcode after path":"M05 (turn off plasma)\n",
}
else :
colors = ["00ff00","0000ff","ff0000","fefe00","00fefe", "fe00fe", "fe7e00", "7efe00", "00fe7e", "007efe", "7e00fe", "fe007e"]
tools_group = inkex.etree.SubElement(layer, inkex.addNS('g','svg'), {'gcodetools': "Gcodetools tool defenition"})
{'style': "fill:#%s;fill-opacity:0.5;stroke:#444444; stroke-width:1px;"%colors[tool_num%len(colors)], "gcodetools":"Gcodetools tool background"})
y = 0
keys = []
g = inkex.etree.SubElement(tools_group, inkex.addNS('g','svg'), {'gcodetools': "Gcodetools tool parameter"})
{
'style': ("font-size:10px;" if key!="name" else "font-size:20px;") + "font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;",
'y': str(y),
'gcodetools': "Gcodetools tool defention field name"
})
{
'style': ("font-size:10px;" if key!="name" else "font-size:20px;") + "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;",
'y': str(y),
'gcodetools': "Gcodetools tool defention field value"
})
for s in v :
{
'y': str(+y),
'gcodetools': "Gcodetools tool defention field value"
})
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):
self.error(_("Selection is empty! Will compute whole drawing."),"selection_is_empty_will_comupe_drawing")
else :
# 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') )
# Add marker to defs if it doesnot exists
marker = inkex.etree.SubElement( defs, inkex.addNS("marker","svg"), {"id":"CheckToolsAndOPMarker","orient":"auto","refX":"-8","refY":"-2.41063","style":"overflow:visible"})
{ "d":"m -6.55552,-2.41063 0,0 L -13.11104,0 c 1.0473,-1.42323 1.04126,-3.37047 0,-4.82126",
"style": "fill:#000044; fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;" }
)
tools_bounds = {}
tools_bounds[layer] = tools_bounds[layer] if layer in tools_bounds else [float("inf"),float("-inf")]
style = "fill:%s; fill-opacity:%s; stroke:#000044; stroke-width:1; marker-mid:url(#CheckToolsAndOPMarker);" % (
trans = simpletransform.composeTransform( trans_, trans if trans != [] else [[1.,0.,0.],[0.,1.,0.]])
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])]
if layer in tools_bounds :
################################################################################
### TODO Launch browser on help tab
################################################################################
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
################################################################################
#csp_draw(self.transform_csp([subpath],layer,True), color = "Orange", width = .1)
c[i-1][4] = c[i][0][:]
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':
elif s[1] == 'arc':
r = [(s[2][0]-s[0][0]), (s[2][1]-s[0][1])]
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:
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
if x not in ["X", "Y", "Z", "x", "y", "z"] or z not in ["X", "Y", "Z", "x", "y", "z"] :
return
return
gcode = ""
self.tool["passing feed"] = float(self.tool["passing feed"] if "passing feed" in self.tool else 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"
# Offset the path if fine cut is defined.
# Close the path to make offset correct
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] ] ])
offsetted_subpath = csp_offset([offsetted_subpath], r if not csp_subpath_ccw(offsetted_subpath) else -r )
#csp_draw(self.transform_csp(offsetted_subpath,layer,True), color = "Green", width = 1)
# Join offsetted_subpath together
# Hope there wont be any cicles
# Create solid object from path and lathe_width
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 %s %f F %f \n" % (x, top_start[0], z, top_start[1], self.tool["passing feed"]) )
intersections = []
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)]
if y > current_width+step :
else :
# full step cut
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
if width == 0 :
else :
else :
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] ] ])
offsetted_subpath = csp_offset([offsetted_subpath], width if not csp_subpath_ccw(offsetted_subpath) else -width )
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 += ("G01 %s %f %s %f F %f \n" % (x, top_start[0], z, top_start[1], self.tool["passing feed"]) )
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") :
if r :
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 :
return
self.error("Can not check the latest version. You can check it manualy at \nhttp://www.cnc-club.ru/gcodetools (English version). \nhttp://www.cnc-club.ru/gcodetools_ru (Russian version). \nCurrent version is Gcodetools %s"%gcodetools_current_version,"Warning")
except :
self.error("Can not check the latest version. You can check it manualy at \nhttp://www.cnc-club.ru/gcodetools (English version). \nhttp://www.cnc-club.ru/gcodetools_ru (Russian version). \nCurrent version is Gcodetools %s"%gcodetools_current_version,"Warning")
################################################################################
###
### Effect
###
### Main function of Gcodetools class
###
################################################################################
global options
# define print_ function
global print_
try :
f.write("Gcodetools log file.\nStarted at %s.\n%s\n" % (time.strftime("%d.%m.%Y %H:%M:%S"),options.log_filename))
f.close()
except :
print_ = lambda *x : None
else : print_ = lambda *x : None
return
elif self.options.active_tab not in ['"dxfpoints"','"path-to-gcode"', '"area"', '"area_artefacts"', '"engraving"', '"orientation"', '"tools_library"', '"lathe"', '"offset"', '"arrangement"', '"update"']:
self.error(_("Select one of the active tabs - Path to Gcode, Area, Engraving, DXF points, Orientation, Offset, Lathe or Tools library."),"error")
else:
# Get all Gcodetools data from the scene.
if self.options.active_tab in ['"dxfpoints"','"path-to-gcode"', '"area"', '"area_artefacts"', '"engraving"', '"lathe"']:
if self.orientation_points == {} :
self.error(_("Orientation points have not been defined! A default set of orientation points has been automatically added."),"warning")
self.error(_("Cutting tool has not been defined! A default tool has been automatically added."),"warning")
else :
csp1, csp2 = cubicsuperpath.parsePath(self.selected_paths[layer][0].get("d")), cubicsuperpath.parsePath(self.selected_paths[layer][1].get("d"))
+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
offsets_count = 0
offsets_count += 1
if offset_ != [] :
#print_(offset_)
else :
break
print_()
print_("-----------------------------------------------------------------------------------")
print_("-----------------------------------------------------------------------------------")
print_("-----------------------------------------------------------------------------------")
print_()
#
e = Gcodetools()
e.affect()