k40whisperer_turbo/g_code_library.py

2072 wiersze
86 KiB
Python

#!/usr/bin/python
"""
g_code_library
Copyright (C) <2017> <Scorch>
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 3 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, see <http://www.gnu.org/licenses/>.
"""
import sys
from math import *
import os
import re
import binascii
import getopt
import webbrowser
#################
### START LIB ###
#################
############################################################################
class G_Code_Rip:
def __init__(self):
self.Zero = 0.0000001
self.g_code_data = []
self.scaled_trans = []
self.right_side = []
self.left_side = []
self.probe_gcode = []
self.probe_coords = []
self.arc_angle = 2
self.accuracy = .001
self.units = "in"
################################################################################
# Function for outputting messages to different locations #
# depending on what options are enabled #
################################################################################
def fmessage(self,text,newline=True):
if newline==True:
try:
sys.stdout.write(text)
sys.stdout.write("\n")
except:
pass
else:
try:
sys.stdout.write(text)
except:
pass
def Read_G_Code(self,filename, XYarc2line = False, arc_angle=2, units="in", Accuracy=""):
self.g_code_data = []
self.scaled_trans = []
self.right_side = []
self.left_side = []
self.probe_gcode = []
self.probe_coords = []
self.arc_angle = arc_angle
self.units = units
if Accuracy == "":
if units == "in":
self.accuracy = .001
else:
self.accuracy = .025
else:
self.accuracy = float(Accuracy)
READ_MSG = []
# Try to open file for reading
try:
fin = open(filename,'r')
except:
READ_MSG.append("Unable to open file: %s" %(filename))
return READ_MSG
scale = 1
variables = []
line_number = 0
xind=0
yind=1
zind=2
mode_arc = "incremental" # "absolute"
mode_pos = "absolute" # "incremental"
mvtype = 1 # G0 (Rapid), G1 (linear), G2 (clockwise arc) or G3 (counterclockwise arc).
plane = "17" # G17 (Z-axis, XY-plane), G18 (Y-axis, XZ-plane), or G19 (X-axis, YZ-plane)
pos =['','','']
pos_last=['','','']
POS =[complex(0,1),complex(0,1),complex(0,1)]
feed = 0
spindle = 0
#########################
for line in fin:
line_number = line_number + 1
#print line_number
line = line.replace("\n","")
line = line.replace("\r","")
code_line=[]
#####################
### FIND COMMENTS ###
#####################
if line.find("(") != -1:
s = line.find("(")
while s != -1:
e = line.find(")")
code_line.append([ ";", line[s:e+1] ])
line = self.rm_text(line,s,e)
s = line.find("(")
if line.find(";") != -1:
s = line.find(";")
e = len(line)
code_line.append([ ";", line[s:e] ])
line = self.rm_text(line,s,e)
# If comment exists write it to output
if code_line!= []:
for comment in code_line:
self.g_code_data.append(comment)
code_line=[]
# Switch remaining non comment data to upper case
# and remove spaces
line = line.upper()
line = line.replace(" ","")
#####################################################
# Find # chars and check for a variable definition #
#####################################################
if line.find("#") != -1:
s = line.rfind("#")
while s != -1:
if line[s+1] == '<':
e = s+2
while line[e] != '>' and e <= len(line):
e = e+1
e = e+1
vname = line[s:e].lower()
else:
vname = re.findall(r'[-+]?\d+',line[s:])[0]
e = s + 1 + len(vname)
vname = line[s:e]
DEFINE = False
if e < len(line):
if line[e]=="=":
DEFINE = True
if DEFINE:
try:
vval = "%.4f" %(float(line[e+1:]))
line = ''
except:
try:
vval = self.EXPRESSION_EVAL(line[e+1:])
line = ''
except:
READ_MSG.append(str(sys.exc_info()[1]))
return READ_MSG
variables.append([vname,vval])
line = self.rm_text(line,s,e-1)
else:
line = self.rm_text(line,s,e-1)
VALUE = ''
for V in variables:
if V[0] == vname:
VALUE = V[1]
line = self.insert_text(line,VALUE,s)
s = line.rfind("#")
#########################
### FIND MATH REGIONS ###
#########################
if line.find("[") != -1 and line.find("[") != 0:
############################
s = line.find("[")
while s != -1:
e = s + 1
val = 1
while val > 0:
if e >= len(line):
MSG = "ERROR: Unable to evaluate expression: G-Code Line %d" %(line_number)
raise ValueError(MSG)
if line[e]=="[":
val = val + 1
elif line[e] == "]":
val = val - 1
e = e + 1
new_val = self.EXPRESSION_EVAL(line[s:e])
line = self.rm_text(line,s,e-1)
line = self.insert_text(line,new_val,s)
s = line.find("[")
#############################
####################################
### FIND FULLY UNSUPPORTED CODES ###
####################################
# D Tool radius compensation number
# E ...
# L ...
# O ... Subroutines
# Q Feed increment in G73, G83 canned cycles
# A A axis of machine
# B B axis of machine
# C C axis of machine
# U U axis of machine
# V V axis of machine
# W W axis of machine
UCODES = ("A","B","C","D","E","L","O","Q","U","V","W")
skip = False
for code in UCODES:
if line.find(code) != -1:
READ_MSG.append("Warning: %s Codes are not supported ( G-Code File Line: %d )" %(code,line_number))
skip = True
if skip:
continue
##############################
### FIND ALL CODES ###
##############################
# F Feed rate
# G General function
# I X offset for arcs and G87 canned cycles
# J Y offset for arcs and G87 canned cycles
# K Z offset for arcs and G87 canned cycles. Spindle-Motion Ratio for G33 synchronized movements.
# M Miscellaneous function (See table Modal Groups)
# P Dwell time in canned cycles and with G4. Key used with G10. Used with G2/G3.
# R Arc radius or canned cycle plane
# S Spindle speed
# T Tool selection
# X X axis of machine
# Y Y axis of machine
# Z Z axis of machine
ALL = ("A","B","C","D","E","F","G","H","I","J",\
"K","L","M","N","O","P","Q","R","S","T",\
"U","V","W","X","Y","Z","#","=")
temp = []
line = line.replace(" ","")
for code in ALL:
index=-1
index = line.find(code,index+1)
while index != -1:
temp.append([code,index])
index = line.find(code,index+1)
temp.sort(key=lambda a:a[1])
code_line=[]
if temp != []:
x = 0
while x <= len(temp)-1:
s = temp[x][1]+1
if x == len(temp)-1:
e = len(line)
else:
e = temp[x+1][1]
CODE = temp[x][0]
VALUE = line[s:e]
code_line.append([ CODE, VALUE ])
x = x + 1
#################################
mv_flag = 0
POS_LAST = POS[:]
#CENTER = ['','','']
CENTER = POS_LAST[:]
passthru = ""
for com in code_line:
if com[0] == "G":
Gnum = "%g" %(float(com[1]))
if Gnum == "0" or Gnum == "1":
mvtype = int(Gnum)
elif Gnum == "2" or Gnum == "3":
mvtype = int(Gnum)
#CENTER = POS_LAST[:]
elif Gnum == "17":
plane = Gnum
elif Gnum == "18":
plane = Gnum
elif Gnum == "19":
plane = Gnum
elif Gnum == "20":
if units == "in":
scale = 1
else:
scale = 25.4
elif Gnum == "21":
if units == "mm":
scale = 1
else:
scale = 1.0/25.4
elif Gnum == "81":
READ_MSG.append("Warning: G%s Codes are not supported ( G-Code File Line: %d )" %(Gnum,line_number))
elif Gnum == "90.1":
mode_arc = "absolute"
elif Gnum == "90":
mode_pos = "absolute"
elif Gnum == "91":
mode_pos = "incremental"
elif Gnum == "91.1":
mode_arc = "incremental"
elif Gnum == "92":
#READ_MSG.append("Aborting G-Code Reading: G%s Codes are not supported" %(Gnum))
READ_MSG.append("Warning: G%s Codes are not supported ( G-Code File Line: %d )" %(Gnum,line_number))
#return READ_MSG
elif Gnum == "38.2":
READ_MSG.append("Warning: G%s Codes are not supported ( G-Code File Line: %d )" %(Gnum,line_number))
#READ_MSG.append("Aborting G-Code Reading: G%s Codes are not supported" %(Gnum))
#return READ_MSG
else:
passthru = passthru + "%s%s " %(com[0],com[1])
elif com[0] == "X":
if mode_pos == "absolute":
POS[xind] = float(com[1])*scale
else:
POS[xind] = float(com[1])*scale + POS_LAST[xind]
mv_flag = 1
elif com[0] == "Y":
if mode_pos == "absolute":
POS[yind] = float(com[1])*scale
else:
POS[yind] = float(com[1])*scale + POS_LAST[yind]
mv_flag = 1
elif com[0] == "Z":
if mode_pos == "absolute":
POS[zind] = float(com[1])*scale
else:
POS[zind] = float(com[1])*scale + POS_LAST[zind]
mv_flag = 1
###################
elif com[0] == "I":
if mode_arc == "absolute":
CENTER[xind] = float(com[1])*scale
else:
CENTER[xind] = float(com[1])*scale + POS_LAST[xind]
if (mvtype==2 or mvtype==3):
mv_flag = 1
elif com[0] == "J":
if mode_arc == "absolute":
CENTER[yind] = float(com[1])*scale
else:
CENTER[yind] = float(com[1])*scale + POS_LAST[yind]
if (mvtype==2 or mvtype==3):
mv_flag = 1
elif com[0] == "K":
if mode_arc == "absolute":
CENTER[zind] = float(com[1])*scale
else:
CENTER[zind] = float(com[1])*scale + POS_LAST[zind]
if (mvtype==2 or mvtype==3):
mv_flag = 1
elif com[0] == "R":
Rin= float(com[1])*scale
CENTER = self.get_center(POS,POS_LAST,Rin,mvtype,plane)
###################
elif com[0] == "F":
feed = float(com[1]) * scale
elif com[0] == "S":
spindle = float(com[1])
elif com[0] == ";":
passthru = passthru + "%s " %(com[1])
elif com[0] == "P" and mv_flag == 1 and mvtype > 1:
READ_MSG.append("Aborting G-Code Reading: P word specifying the number of full or partial turns of arc are not supported")
return READ_MSG
elif com[0] == "M":
Mnum = "%g" %(float(com[1]))
if Mnum == "2":
self.g_code_data.append([ "M2", "(END PROGRAM)" ])
passthru = passthru + "%s%s " %(com[0],com[1])
elif com[0] == "N":
pass
#print "Ignoring Line Number %g" %(float(com[1]))
else:
passthru = passthru + "%s%s " %(com[0],com[1])
pos = POS[:]
pos_last = POS_LAST[:]
center = CENTER[:]
# Most command on a line are executed prior to a move so
# we will write the passthru commands on the line before we found them
# only "M0, M1, M2, M30 and M60" are executed after the move commands
# there is a risk that one of these commands could stop the program before
# the move is completed
if passthru != '':
self.g_code_data.append("%s" %(passthru))
###############################################################################
if mv_flag == 1:
if mvtype == 0:
self.g_code_data.append([mvtype,pos_last[:],pos[:]])
if mvtype == 1:
self.g_code_data.append([mvtype,pos_last[:],pos[:],feed,spindle])
if mvtype == 2 or mvtype == 3:
if plane == "17":
if XYarc2line == False:
self.g_code_data.append([mvtype,pos_last[:],pos[:],center[:],feed,spindle])
else:
data = self.arc2lines(pos_last[:],pos[:],center[:], mvtype, plane)
for line in data:
XY=line
self.g_code_data.append([1,XY[:3],XY[3:],feed,spindle])
elif plane == "18":
data = self.arc2lines(pos_last[:],pos[:],center[:], mvtype, plane)
for line in data:
XY=line
self.g_code_data.append([1,XY[:3],XY[3:],feed,spindle])
elif plane == "19":
data = self.arc2lines(pos_last[:],pos[:],center[:], mvtype, plane)
for line in data:
XY=line
self.g_code_data.append([1,XY[:3],XY[3:],feed,spindle])
###############################################################################
#################################
fin.close()
## Post process the g-code data to remove complex numbers
cnt = 0
firstx = complex(0,1)
firsty = complex(0,1)
firstz = complex(0,1)
first_sum = firstx + firsty + firstz
while ((cnt < len(self.g_code_data)) and (isinstance(first_sum, complex))):
line = self.g_code_data[cnt]
if line[0] == 0 or line[0] == 1 or line[0] == 2 or line[0] == 3:
if (isinstance(firstx, complex)): firstx = line[2][0]
if (isinstance(firsty, complex)): firsty = line[2][1]
if (isinstance(firstz, complex)): firstz = line[2][2]
cnt=cnt+1
first_sum = firstx + firsty + firstz
max_cnt = cnt
cnt = 0
ambiguousX = False
ambiguousY = False
ambiguousZ = False
while (cnt < max_cnt):
line = self.g_code_data[cnt]
if line[0] == 1 or line[0] == 2 or line[0] == 3:
# X Values
if (isinstance(line[1][0], complex)):
line[1][0] = firstx
ambiguousX = True
if (isinstance(line[2][0], complex)):
line[2][0] = firstx
ambiguousX = True
# Y values
if (isinstance(line[1][1], complex)):
line[1][1] = firsty
ambiguousY = True
if (isinstance(line[2][1], complex)):
line[2][1] = firsty
ambiguousY = True
# Z values
if (isinstance(line[1][2], complex)):
line[1][2] = firstz
ambiguousZ = True
if (isinstance(line[2][2], complex)):
line[2][2] = firstz
ambiguousZ = True
cnt=cnt+1
#if (ambiguousX or ambiguousY or ambiguousZ):
# MSG = "Ambiguous G-Code start location:\n"
# if (ambiguousX): MSG = MSG + "X position is not set by a G0(rapid) move prior to a G1,G2 or G3 move.\n"
# if (ambiguousY): MSG = MSG + "Y position is not set by a G0(rapid) move prior to a G1,G2 or G3 move.\n"
# if (ambiguousZ): MSG = MSG + "Z position is not set by a G0(rapid) move prior to a G1,G2 or G3 move.\n"
# MSG = MSG + "!! Review output files carefully !!"
# READ_MSG.append(MSG)
return READ_MSG
def get_center(self,POS,POS_LAST,Rin,mvtype,plane="17"):
if plane == "18":
xind=2
yind=0
zind=1
elif plane == "19":
xind=1
yind=2
zind=0
elif plane == "17":
xind=0
yind=1
zind=2
CENTER=["","",""]
cord = sqrt( (POS[xind]-POS_LAST[xind])**2 + (POS[yind]-POS_LAST[yind])**2 )
v1 = cord/2.0
#print "rin=%f v1=%f (Rin**2 - v1**2)=%f" %(Rin,v1,(Rin**2 - v1**2))
v2_sq = Rin**2 - v1**2
if v2_sq<0.0:
v2_sq = 0.0
v2 = sqrt( v2_sq )
theta = self.Get_Angle2(POS[xind]-POS_LAST[xind],POS[yind]-POS_LAST[yind])
if mvtype == 3:
dxc,dyc = self.Transform(-v2,v1,radians(theta-90))
elif mvtype == 2:
dxc,dyc = self.Transform(v2,v1,radians(theta-90))
else:
return "Center Error"
xcenter = POS_LAST[xind] + dxc
ycenter = POS_LAST[yind] + dyc
CENTER[xind] = xcenter
CENTER[yind] = ycenter
CENTER[zind] = POS_LAST[zind]
return CENTER
#######################################
def split_code(self,code2split,shift=[0,0,0],angle=0.0):
xsplit=0.0
mvtype = -1 # G0 (Rapid), G1 (linear), G2 (clockwise arc) or G3 (counterclockwise arc).
passthru = ""
POS =[0,0,0]
feed = 0
spindle = 0
self.right_side = []
self.left_side = []
L = 0
R = 1
for line in code2split:
if line[0] == 1:
mvtype = line[0]
POS_LAST = line[1][:]
POS = line[2][:]
CENTER = ['','','']
feed = line[3]
spindle = line[4]
elif line[0] == 3 or line[0] == 2:
mvtype = line[0]
POS_LAST = line[1][:]
POS = line[2][:]
CENTER = line[3][:]
feed = line[4]
spindle = line[5]
else:
mvtype = -1
passthru = line
###############################################################################
if mvtype >= 1 and mvtype <= 3:
pos = self.coordop(POS,shift,angle)
pos_last = self.coordop(POS_LAST,shift,angle)
if CENTER[0]!='' and CENTER[1]!='':
center = self.coordop(CENTER,shift,angle)
else:
center = CENTER
this=""
other=""
if pos_last[0] > xsplit+self.Zero:
flag_side = R
elif pos_last[0] < xsplit-self.Zero:
flag_side = L
else:
if mvtype == 1:
if pos[0] >= xsplit:
flag_side = R
else:
flag_side = L
elif mvtype == 2:
if abs(pos_last[1]-center[1]) < self.Zero:
if center[0] > xsplit:
flag_side = R
else:
flag_side = L
else:
if pos_last[1] >= center[1]:
flag_side = R
else:
flag_side = L
else: #(mvtype == 3)
if abs(pos_last[1]-center[1]) < self.Zero:
if center[0] > xsplit:
flag_side = R
else:
flag_side = L
else:
if pos_last[1] >= center[1]:
flag_side = L
else:
flag_side = R
if flag_side == R:
this = 1
other = 0
else:
this = 0
other = 1
app=[self.apright, self.apleft]
#############################
if mvtype == 0:
pass
if mvtype == 1:
A = self.coordunop(pos_last[:],shift,angle)
C = self.coordunop(pos[:] ,shift,angle)
cross = self.get_line_intersect(pos_last, pos, xsplit)
if len(cross) > 0: ### Line crosses boundary ###
B = self.coordunop(cross[0] ,shift,angle)
app[this] ( [mvtype,A,B,feed,spindle] )
app[other]( [mvtype,B,C,feed,spindle] )
else:
app[this] ( [mvtype,A,C,feed,spindle] )
if mvtype == 2 or mvtype == 3:
A = self.coordunop(pos_last[:],shift,angle)
C = self.coordunop(pos[:] ,shift,angle)
D = self.coordunop(center ,shift,angle)
cross = self.get_arc_intersects(pos_last[:], pos[:], xsplit, center[:], "G%d" %(mvtype))
if len(cross) > 0: ### Arc crosses boundary at least once ###
B = self.coordunop(cross[0] ,shift,angle)
#Check length of arc before writing
if sqrt((A[0]-B[0])**2 + (A[1]-B[1])**2) > self.accuracy:
app[this]( [mvtype,A,B,D,feed,spindle])
if len(cross) == 1: ### Arc crosses boundary only once ###
#Check length of arc before writing
if sqrt((B[0]-C[0])**2 + (B[1]-C[1])**2) > self.accuracy:
app[other]([ mvtype,B,C,D, feed,spindle] )
if len(cross) == 2: ### Arc crosses boundary twice ###
E = self.coordunop(cross[1],shift,angle)
#Check length of arc before writing
if sqrt((B[0]-E[0])**2 + (B[1]-E[1])**2) > self.accuracy:
app[other]([ mvtype,B,E,D, feed,spindle] )
#Check length of arc before writing
if sqrt((E[0]-C[0])**2 + (E[1]-C[1])**2) > self.accuracy:
app[this] ([ mvtype,E,C,D, feed,spindle] )
else: ### Arc does not cross boundary ###
app[this]([ mvtype,A,C,D, feed,spindle])
###############################################################################
else:
if passthru != '':
self.apboth(passthru)
#######################################
def probe_code(self,code2probe,nX,nY,probe_istep,minx,miny,xPartitionLength,yPartitionLength): #,Xoffset,Yoffset):
#def probe_code(self,code2probe,nX,nY,probe_istep,minx,miny,xPartitionLength,yPartitionLength,Xoffset,Yoffset,Zoffset):
#print "nX,nY =",nX,nY
probe_coords = []
BPN=500
POINT_LIST = [False for i in range(int((nY)*(nX)))]
if code2probe == []:
return
mvtype = -1 # G0 (Rapid), G1 (linear), G2 (clockwise arc) or G3 (counterclockwise arc).
passthru = ""
POS = [0,0,0]
feed = 0
spindle = 0
out = []
min_length = min(xPartitionLength,yPartitionLength) / probe_istep
if (min_length < self.Zero):
min_length = max(xPartitionLength,yPartitionLength) / probe_istep
if (min_length < self.Zero):
min_length = 1
for line in code2probe:
if line[0] == 0 or line[0] == 1:
mvtype = line[0]
POS_LAST = line[1][:]
POS = line[2][:]
CENTER = ['','','']
if line[0] == 1:
feed = line[3]
spindle = line[4]
elif line[0] == 3 or line[0] == 2:
mvtype = line[0]
POS_LAST = line[1][:]
POS = line[2][:]
CENTER = line[3][:]
feed = line[4]
spindle = line[5]
else:
mvtype = -1
passthru = line
###############################################################################
if mvtype >= 0 and mvtype <=3:
pos = POS[:]
pos_last = POS_LAST[:]
center = CENTER[:]
#############################
if mvtype == 0:
out.append( [mvtype,pos_last,pos] )
if mvtype == 1:
dx = pos[0]-pos_last[0]
dy = pos[1]-pos_last[1]
dz = pos[2]-pos_last[2]
length = sqrt(dx*dx + dy*dy)
if (length <= min_length):
out.append( [mvtype,pos_last,pos,feed,spindle] )
else:
Lsteps = max(2,int(ceil(length / min_length)))
xstp0 = float(pos_last[0])
ystp0 = float(pos_last[1])
zstp0 = float(pos_last[2])
for n in range(1,Lsteps+1):
xstp1 = n/float(Lsteps)*dx + pos_last[0]
ystp1 = n/float(Lsteps)*dy + pos_last[1]
zstp1 = n/float(Lsteps)*dz + pos_last[2]
out.append( [mvtype,[xstp0,ystp0,zstp0],[xstp1,ystp1,zstp1],feed,spindle] )
xstp0 = float(xstp1)
ystp0 = float(ystp1)
zstp0 = float(zstp1)
if mvtype == 2 or mvtype == 3:
out.append( [ mvtype,pos_last,pos,center, feed,spindle] )
###############################################################################
else:
if passthru != '':
out.append(passthru)
################################
## Loop through output to ##
## find needed probe points ##
################################
for i in range(len(out)):
line = out[i]
if line[0] == 0 or line[0] == 1:
mvtype = line[0]
POS_LAST = line[1][:]
POS = line[2][:]
CENTER = ['','','']
if line[0] == 1:
feed = line[3]
spindle = line[4]
elif line[0] == 3 or line[0] == 2:
mvtype = line[0]
POS_LAST = line[1][:]
POS = line[2][:]
CENTER = line[3][:]
feed = line[4]
spindle = line[5]
else:
mvtype = -1
passthru = line
if mvtype >= 1 and mvtype <=3:
pos = POS[:]
pos_last = POS_LAST[:]
center = CENTER[:]
#### ADD ADDITIONAL DATA TO POS_LAST DATA ####
i_x,i_y = self.get_ix_iy((pos_last[0]-minx),(pos_last[1]-miny),xPartitionLength,yPartitionLength)
#i_x = i_x+Xoffset
#i_y = i_y+Yoffset
if i_x < 0:
i_x=0
if i_y < 0:
i_y=0
if (i_x+1 >= nX):
i_x = nX-2
#i_x = i_x-1 #commented 02/22
#print "adjust i_x POS_LAST"
i_x2 = i_x+1
if (i_y+1 >= nY):
i_y = nY-2
#i_y = i_y-1 #commented 02/22
#print "adjust i_y POS_LAST"
i_y2 = i_y+1
p_index_A = int(i_y* nX + i_x )
p_index_B = int(i_y2*nX + i_x )
p_index_C = int(i_y *nX + i_x2)
p_index_D = int(i_y2*nX + i_x2)
Xfraction=((pos_last[0]-minx)-(i_x*xPartitionLength))/xPartitionLength
Yfraction=((pos_last[1]-miny)-(i_y*yPartitionLength))/yPartitionLength
if Xfraction>1.0:
#print "ERROR POS_LAST: Xfraction = ", Xfraction
Xfraction = 1.0
if Xfraction <0.0:
#print "ERROR POS_LAST: Xfraction = ", Xfraction
Xfraction = 0.0
if Yfraction > 1.0:
#print "ERROR POS_LAST: Yfraction = ", Yfraction
Yfraction = 1.0
if Yfraction<0.0:
#print "ERROR POS_LAST: Yfraction = ", Yfraction
Yfraction = 0.0
BPN=500
out[i][1].append(p_index_A+BPN)
out[i][1].append(p_index_B+BPN)
out[i][1].append(p_index_C+BPN)
out[i][1].append(p_index_D+BPN)
out[i][1].append(Xfraction)
out[i][1].append(Yfraction)
try:
POINT_LIST[p_index_A ] = True
POINT_LIST[p_index_B ] = True
POINT_LIST[p_index_C ] = True
POINT_LIST[p_index_D ] = True
except:
pass
#### ADD ADDITIONAL DATA TO POS_LAST DATA ####
i_x,i_y = self.get_ix_iy((pos[0]-minx),(pos[1]-miny),xPartitionLength,yPartitionLength)
#i_x = i_x+Xoffset
#i_y = i_y+Yoffset
if i_x < 0:
i_x=0
if i_y < 0:
i_y=0
if (i_x+1 >= nX):
i_x = nX-2
#i_x = i_x-1 #commented 02/22
#print "adjust i_x POS"
i_x2 = i_x+1
if (i_y+1 >= nY):
i_y = nY-2
#i_y = i_y-1#commented 02/22
#print "adjust i_y POS"
i_y2 = i_y+1
p_index_A = int(i_y* nX + i_x )
p_index_B = int(i_y2*nX + i_x )
p_index_C = int(i_y *nX + i_x2)
p_index_D = int(i_y2*nX + i_x2)
Xfraction=((pos[0]-minx)-(i_x*xPartitionLength))/xPartitionLength
Yfraction=((pos[1]-miny)-(i_y*yPartitionLength))/yPartitionLength
if Xfraction>1.0:
Xfraction = 1.0
#print "ERROR POS: Xfraction = ", Xfraction
if Xfraction <0.0:
Xfraction = 0.0
#print "ERROR POS: Xfraction = ", Xfraction
if Yfraction > 1.0:
Yfraction = 1.0
#print "ERROR POS: Yfraction = ", Yfraction
if Yfraction<0.0:
Yfraction = 0.0
#print "ERROR POS: Yfraction = ", Yfraction
out[i][2].append(p_index_A+BPN)
out[i][2].append(p_index_B+BPN)
out[i][2].append(p_index_C+BPN)
out[i][2].append(p_index_D+BPN)
out[i][2].append(Xfraction)
out[i][2].append(Yfraction)
try:
POINT_LIST[p_index_A ] = True
POINT_LIST[p_index_B ] = True
POINT_LIST[p_index_C ] = True
POINT_LIST[p_index_D ] = True
except:
pass
self.probe_gcode = out
#for line in out:
# print line
################################
## Generate Probing Code ##
## For needed points ##
################################
for i in range(len(POINT_LIST)):
i_x = i % nX
i_y = int(i / nX)
xp = i_x * xPartitionLength + minx
yp = i_y * yPartitionLength + miny
probe_coords.append([POINT_LIST[i],i+BPN,xp,yp])
self.probe_coords = probe_coords
return
def get_ix_iy(self,x,y,xPartitionLength,yPartitionLength):
i_x=int(x/xPartitionLength)
i_y=int(y/yPartitionLength)
return i_x,i_y
#######################################
def scale_rotate_code(self,code2scale,scale=[1.0,1.0,1.0,1.0],angle=0.0):
if code2scale == []:
return code2scale,0,0,0,0,0,0
minx = 99999
maxx = -99999
miny = 99999
maxy = -99999
minz = 99999
maxz = -99999
mvtype = -1 # G0 (Rapid), G1 (linear), G2 (clockwise arc) or G3 (counterclockwise arc).
passthru = ""
POS =[0,0,0]
feed = 0
spindle = 0
out = []
L = 0
R = 1
flag_side = 1
for line in code2scale:
if line[0] == 0 or line[0] == 1:
mvtype = line[0]
POS_LAST = line[1][:]
POS = line[2][:]
CENTER = ['','','']
if line[0] == 1:
feed = line[3] * scale[3]
spindle = line[4]
elif line[0] == 3 or line[0] == 2:
mvtype = line[0]
POS_LAST = line[1][:]
POS = line[2][:]
CENTER = line[3][:]
feed = line[4] * scale[3]
spindle = line[5]
else:
mvtype = -1
passthru = line
###############################################################################
if mvtype >= 0 and mvtype <=3:
pos = self.scale_rot_coords(POS,scale,angle)
pos_last = self.scale_rot_coords(POS_LAST,scale,angle)
if CENTER[0]!='' and CENTER[1]!='':
center = self.scale_rot_coords(CENTER,scale,angle)
else:
center = CENTER
#############################
try:
minx = min( minx, min(pos[0],pos_last[0]) )
maxx = max( maxx, max(pos[0],pos_last[0]) )
except:
pass
try:
miny = min( miny, min(pos[1],pos_last[1]) )
maxy = max( maxy, max(pos[1],pos_last[1]) )
except:
pass
try:
minz = min( minz, min(pos[2],pos_last[2]) )
maxz = max( maxz, max(pos[2],pos_last[2]) )
except:
pass
if mvtype == 0:
out.append( [mvtype,pos_last,pos] )
if mvtype == 1:
out.append( [mvtype,pos_last,pos,feed, spindle] )
if mvtype == 2 or mvtype == 3:
out.append( [ mvtype,pos_last,pos,center, feed, spindle] )
if mvtype == 3:
ang1 = self.Get_Angle2(pos_last[0]-center[0],pos_last[1]-center[1])
xtmp,ytmp = self.Transform(pos[0]-center[0],pos[1]-center[1],radians(-ang1))
ang2 = self.Get_Angle2(xtmp,ytmp)
else:
ang1 = self.Get_Angle2(pos[0]-center[0],pos[1]-center[1])
xtmp,ytmp = self.Transform(pos_last[0]-center[0],pos_last[1]-center[1],radians(-ang1))
ang2 = self.Get_Angle2(xtmp,ytmp)
if ang2 == 0:
ang2=359.999
Radius = sqrt( (pos[0]-center[0])**2 +(pos[1]-center[1])**2 )
if ang1 > 270:
da = 270
elif ang1 > 180:
da = 180
elif ang1 > 90:
da = 90
else:
da = 0
for side in [90,180,270,360]:
spd = side + da
if ang2 > (spd-ang1):
if spd > 360:
spd=spd-360
if spd==90:
maxy = max( maxy, center[1]+Radius )
if spd==180:
minx = min( minx, center[0]-Radius)
if spd==270:
miny = min( miny, center[1]-Radius )
if spd==360:
maxx = max( maxx, center[0]+Radius )
###############################################################################
else:
if passthru != '':
out.append(passthru)
return out,minx,maxx,miny,maxy,minz,maxz
#######################################
def scale_translate(self,code2translate,translate=[0.0,0.0,0.0]):
if translate[0]==0 and translate[1]==0 and translate[2]==0:
return code2translate
mvtype = -1 # G0 (Rapid), G1 (linear), G2 (clockwise arc) or G3 (counterclockwise arc).
passthru = ""
POS =[0,0,0]
pos =[0,0,0]
pos_last=[0,0,0]
feed = 0
spindle = 0
out = []
L = 0
R = 1
flag_side = 1
for line in code2translate:
if line[0] == 1 or line[0] == 0:
mvtype = line[0]
POS_LAST = line[1][:]
POS = line[2][:]
CENTER = ['','','']
if line[0] == 1:
feed = line[3]
spindle = line[4]
elif line[0] == 3 or line[0] == 2:
mvtype = line[0]
POS_LAST = line[1][:]
POS = line[2][:]
CENTER = line[3][:]
feed = line[4]
spindle = line[5]
else:
mvtype = -1
passthru = line
###############################################################################
if mvtype >= 0 and mvtype <=3:
pos = self.scale_trans_coords(POS,translate)
pos_last = self.scale_trans_coords(POS_LAST,translate)
if CENTER[0]!='' and CENTER[1]!='':
center = self.scale_trans_coords(CENTER,translate)
else:
center = CENTER[:]
#############################
if mvtype == 0:
out.append( [mvtype,pos_last,pos] )
if mvtype == 1:
out.append( [mvtype,pos_last,pos,feed,spindle] )
if mvtype == 2 or mvtype == 3:
out.append( [ mvtype,pos_last,pos,center, feed,spindle] )
###############################################################################
else:
if passthru != '':
out.append(passthru)
return out
def scale_trans_coords(self,coords,trans):
x = coords[0] - trans[0]
y = coords[1] - trans[1]
z = coords[2] - trans[2]
return [x,y,z]
def scale_rot_coords(self,coords,scale,rot):
x = coords[0] * scale[0]
y = coords[1] * scale[1]
z = coords[2] * scale[2]
x,y = self.Transform(x,y, radians(rot) )
return [x,y,z]
def generategcode(self,side,z_safe=.5,
plunge_feed=10.0,
no_variables=False,
Rstock=0.0,
Wrap="XYZ",
preamble="",
postamble="",
gen_rapids=False,
PLACES_L=4,
PLACES_R=3,
PLACES_F=1,
WriteAll=False,
FSCALE="Scale-Rotary",
Reverse_Rotary = False,
NoComments=False):
g_code = []
sign = 1
if Reverse_Rotary:
sign = -1
self.MODAL_VAL={'X':" ", 'Y':" ", 'Z':" ", 'F':" ", 'A':" ", 'B':" ", 'I':" ", 'J':" "}
LASTX = 0
LASTY = 0
LASTZ = z_safe
g_code.append("( G-Code Modified by G-Code Ripper )")
g_code.append("( by Scorch - 2017 www.scorchworks.com )")
if Wrap == "XYZ":
AXIS=["X" , "Y" , "Z" ]
DECP=[PLACES_L, PLACES_L, PLACES_L]
elif Wrap == "Y2A":
AXIS=["X" , "A" , "Z" ]
DECP=[PLACES_L, PLACES_R, PLACES_L]
WriteAll=False
g_code.append("(G-Code Ripper has mapped the Y-Axis to the A-Axis )")
elif Wrap == "X2B":
AXIS=["B" , "Y" , "Z" ]
DECP=[PLACES_R, PLACES_L, PLACES_L]
WriteAll=False
g_code.append("(G-Code Ripper has mapped the X-Axis to the B-Axis )")
elif Wrap == "Y2B":
AXIS=["X" , "B" , "Z" ]
DECP=[PLACES_L, PLACES_R, PLACES_L]
WriteAll=False
g_code.append("(G-Code Ripper has mapped the Y-Axis to the B-Axis )")
elif Wrap == "X2A":
AXIS=["A" , "Y" , "Z" ]
DECP=[PLACES_R, PLACES_L, PLACES_L]
WriteAll=False
g_code.append("(G-Code Ripper has mapped the X-Axis to the A-Axis )")
if Wrap != "XYZ":
g_code.append("(A nominal stock radius of %f was used. )" %(Rstock))
g_code.append("(Z-axis zero position is the surface of the round stock. )")
g_code.append("(---------------------------------------------------------)")
g_code.append("G90 (set absolute distance mode)")
g_code.append("G90.1 (set absolute distance mode for arc centers)")
g_code.append("G17 (set active plane to XY)")
if self.units == "in":
g_code.append("G20 (set units to inches)")
else:
g_code.append("G21 (set units to mm)")
if no_variables==False:
g_code.append("#<z_safe> = % 5.3f " %(z_safe))
g_code.append("#<plunge_feed> = % 5.0f " %(plunge_feed))
for line in preamble.split('|'):
g_code.append(line)
g_code.append("(---------------------------------------------------------)")
###################
## GCODE WRITING ##
###################
for line in side:
if line[0] == 1 or line[0] == 2 or line[0] == 3 or (line[0] == 0 and gen_rapids == False):
D0 = line[2][0]-line[1][0]
D1 = line[2][1]-line[1][1]
D2 = line[2][2]-line[1][2]
D012 = sqrt((D0+0j).real**2+(D1+0j).real**2+(D2+0j).real**2)
coordA=[ line[1][0], line[1][1], line[1][2] ]
coordB=[ line[2][0], line[2][1], line[2][2] ]
if Wrap == "Y2A" or Wrap == "Y2B":
#if line[1][1].imag == 0:
if (not isinstance(line[1][1], complex)):
coordA[1]=sign*degrees(line[1][1]/Rstock)
#if line[2][1].imag == 0:
if (not isinstance(line[2][1], complex)):
coordB[1]=sign*degrees(line[2][1]/Rstock)
elif Wrap == "X2B" or Wrap == "X2A":
#if line[1][0].imag == 0:
if (not isinstance(line[1][0], complex)):
coordA[0]=sign*degrees(line[1][0]/Rstock)
#if line[2][0].imag == 0:
if (not isinstance(line[2][0], complex)):
coordB[0]=sign*degrees(line[2][0]/Rstock)
dx = coordA[0]-LASTX
dy = coordA[1]-LASTY
dz = coordA[2]-LASTZ
# Check if next point is coincident with the
# current point withing the set accuracy
if sqrt((dx+0j).real**2 + (dy+0j).real**2 + (dz+0j).real**2) > self.accuracy and gen_rapids == True:
### Move tool to safe height (z_safe) ###
if no_variables==False:
g_code.append("G0 %c #<z_safe> " %(AXIS[2]) )
self.MODAL_VAL[AXIS[2]] = z_safe
else:
LINE = "G0"
LINE = self.app_gcode_line(LINE,AXIS[2],z_safe,DECP[2],WriteAll)
if len(LINE) > 2: g_code.append(LINE)
### Move tool to coordinates of next cut ###
LINE = "G0"
LINE = self.app_gcode_line(LINE,AXIS[0],coordA[0],DECP[0],WriteAll)
LINE = self.app_gcode_line(LINE,AXIS[1],coordA[1],DECP[1],WriteAll)
if len(LINE) > 2: g_code.append(LINE)
if float(coordA[2]) < float(z_safe):
if no_variables==False:
LINE = "G1"
LINE = self.app_gcode_line(LINE,AXIS[2],coordA[2],DECP[2],WriteAll)
LINE = LINE + " F #<plunge_feed>"
self.MODAL_VAL["F"] = plunge_feed
if len(LINE) > 2: g_code.append(LINE)
else:
LINE = "G1"
LINE = self.app_gcode_line(LINE,AXIS[2],coordA[2] ,DECP[2] , WriteAll)
LINE = self.app_gcode_line(LINE,"F" ,plunge_feed,PLACES_F, WriteAll)
if len(LINE) > 2: g_code.append(LINE)
LASTX = coordB[0]
LASTY = coordB[1]
LASTZ = coordB[2]
if (line[0] == 1) or (line[0] == 2) or (line[0] == 3) or (line[0] == 0 and (gen_rapids == False)):
try: LAST0 = float(self.MODAL_VAL[AXIS[0]])
except: LAST0 = coordB[0]
try: LAST1 = float(self.MODAL_VAL[AXIS[1]])
except: LAST1 = coordB[1]
try: LAST2 = float(self.MODAL_VAL[AXIS[2]])
except: LAST2 = coordB[2]
LINE = "G%d" %(line[0])
LINE = self.app_gcode_line(LINE,AXIS[0],coordB[0],DECP[0],WriteAll)
LINE = self.app_gcode_line(LINE,AXIS[1],coordB[1],DECP[1],WriteAll)
LINE = self.app_gcode_line(LINE,AXIS[2],coordB[2],DECP[2],WriteAll)
if (line[0] == 1):
if ((LINE.find("A") > -1) or (LINE.find("B") > -1)) and (FSCALE == "Scale-Rotary") and (D012>self.Zero):
if (LINE.find("X") > -1) or (LINE.find("Y") > -1) or (LINE.find("Z") > -1):
if Wrap == "Y2A" or Wrap == "Y2B":
Df = sqrt(D0**2 + D2**2)
elif Wrap == "X2B" or Wrap == "X2A":
Df = sqrt(D1**2 + D2**2)
Feed_adj = abs(Df / (D012/line[3]))
else:
if Wrap == "Y2A" or Wrap == "Y2B":
DAf = coordB[1]-LAST1
Feed_adj = abs(DAf / (D012/line[3]))
elif Wrap == "X2B" or Wrap == "X2A":
DAf = coordB[0]-LAST0
Feed_adj = abs(DAf / (D012/line[3]))
else:
Feed_adj = line[3]
LINE = self.app_gcode_line(LINE,"F",Feed_adj ,PLACES_F,WriteAll)
elif (line[0] == 2) or (line[0] == 3):
LINE = self.app_gcode_line(LINE,"I",line[3][0],DECP[0] ,WriteAll)
LINE = self.app_gcode_line(LINE,"J",line[3][1],DECP[1] ,WriteAll)
LINE = self.app_gcode_line(LINE,"F",Feed_adj ,PLACES_F,WriteAll)
if len(LINE) > 2: g_code.append(LINE)
elif (line[0] == 0 and gen_rapids == True):
pass
elif line[0] == ";":
if not NoComments:
g_code.append("%s" %(line[1]))
elif line[0] == "M2":
if gen_rapids == True:
if no_variables==False:
g_code.append("G0 %c #<z_safe> " %(AXIS[2]) )
self.MODAL_VAL[AXIS[2]] = z_safe
else:
LINE = "G0"
LINE = self.app_gcode_line(LINE,AXIS[2],z_safe,DECP[2],WriteAll)
g_code.append(LINE)
for entry in postamble.split('|'):
g_code.append(entry)
#g_code.append(line[0])
else:
g_code.append(line)
########################
## END G-CODE WRITING ##
########################
return g_code
def app_gcode_line(self,LINE,CODE,VALUE,PLACES,WriteAll):
if isinstance(VALUE, complex):
return LINE
#if VALUE.imag != 0:
# return LINE
if CODE == "F":
if (VALUE*10**PLACES) < 1:
# Fix Zero feed rate
VALUE = 1.0/(10**PLACES)
if PLACES > 0:
FORMAT="%% .%df" %(PLACES)
else:
FORMAT="%d"
VAL = FORMAT %(VALUE)
if ( VAL != self.MODAL_VAL[CODE] )\
or ( CODE=="I" ) \
or ( CODE=="J" ) \
or (WriteAll):
LINE = LINE + " %s%s" %(CODE, VAL)
self.MODAL_VAL[CODE] = VAL
return LINE
def get_arc_intersects(self, p1, p2, xsplit, cent, code):
xcross1= xsplit
xcross2= xsplit
R = sqrt( (cent[0]-p1[0])**2 + (cent[1]-p1[1])**2 )
Rt= sqrt( (cent[0]-p2[0])**2 + (cent[1]-p2[1])**2 )
if abs(R-Rt) > self.accuracy: self.fmessage("Radius Warning: R1=%f R2=%f"%(R,Rt))
val = R**2 - (xsplit - cent[0])**2
if val >= 0.0:
root = sqrt( val )
ycross1 = cent[1] - root
ycross2 = cent[1] + root
else:
return []
theta = self.Get_Angle2(p1[0]-cent[0],p1[1]-cent[1])
xbeta,ybeta = self.Transform(p2[0]-cent[0],p2[1]-cent[1],radians(-theta))
beta = self.Get_Angle2(xbeta,ybeta,code)
if abs(beta) <= self.Zero: beta = 360.0
xt,yt = self.Transform(xsplit-cent[0],ycross1-cent[1],radians(-theta))
gt1 = self.Get_Angle2(xt,yt,code)
xt,yt = self.Transform(xsplit-cent[0],ycross2-cent[1],radians(-theta))
gt2 = self.Get_Angle2(xt,yt,code)
if gt1 < gt2:
gamma1 = gt1
gamma2 = gt2
else:
gamma1 = gt2
gamma2 = gt1
temp = ycross1
ycross1 = ycross2
ycross2 = temp
dz = p2[2] - p1[2]
da = beta
mz = dz/da
zcross1 = p1[2] + gamma1 * mz
zcross2 = p1[2] + gamma2 * mz
output=[]
if gamma1 < beta and gamma1 > self.Zero and gamma1 < beta-self.Zero:
output.append([xcross1,ycross1,zcross1])
if gamma2 < beta and gamma1 > self.Zero and gamma2 < beta-self.Zero:
output.append([xcross2,ycross2,zcross2])
#print(" start: x1 =%5.2f y1=%5.2f z1=%5.2f" %(p1[0], p1[1], p1[2]))
#print(" end: x2 =%5.2f y2=%5.2f z2=%5.2f" %(p2[0], p2[1], p2[2]))
#print("center: xc =%5.2f yc=%5.2f xsplit=%5.2f code=%s" %(cent[0],cent[1],xsplit,code))
#print("R = %f" %(R))
#print("theta =%5.2f" %(theta))
#print("beta =%5.2f gamma1=%5.2f gamma2=%5.2f\n" %(beta,gamma1,gamma2))
#cnt=0
#for line in output:
# cnt=cnt+1
# print("arc cross%d: %5.2f, %5.2f, %5.2f" %(cnt, line[0], line[1], line[2]))
#print(output)
#print("----------------------------------------------\n")
return output
def arc2lines(self, p1, p2, cent, code, plane="17"):
if plane == "18":
xind=2
yind=0
zind=1
elif plane == "19":
xind=1
yind=2
zind=0
elif plane == "17":
xind=0
yind=1
zind=2
R = sqrt( (cent[xind]-p1[xind])**2 + (cent[yind]-p1[yind])**2 )
Rt= sqrt( (cent[xind]-p2[xind])**2 + (cent[yind]-p2[yind])**2 )
if abs(R-Rt) > self.accuracy: self.fmessage("Radius Warning: R1=%f R2=%f "%(R,Rt))
if code == 3:
theta = self.Get_Angle2(p1[xind]-cent[xind],p1[yind]-cent[yind])
xbeta,ybeta = self.Transform(p2[xind]-cent[xind],p2[yind]-cent[yind],radians(-theta))
X1 = p1[xind]
Y1 = p1[yind]
Z1 = p1[zind]
zstart = Z1
zend = p2[zind]
if code == 2:
theta = self.Get_Angle2(p2[xind]-cent[xind],p2[yind]-cent[yind])
xbeta,ybeta = self.Transform(p1[xind]-cent[xind],p1[yind]-cent[yind],radians(-theta))
X1 = p2[xind]
Y1 = p2[yind]
Z1 = p2[zind]
zstart = Z1
zend = p1[zind]
beta = self.Get_Angle2(xbeta,ybeta) #,code)
if abs(beta) <= self.Zero: beta = 360.0
##########################################
arc_step=self.arc_angle
my_range=[]
at=arc_step
while at < beta:
my_range.append(at)
at = at+arc_step
my_range.append(beta)
new_lines=[]
for at in my_range:
xt,yt = self.Transform(R,0,radians(theta+at))
X2 = cent[xind] + xt
Y2 = cent[yind] + yt
#Z2 = p1[zind] + at*(p2[zind]-p1[zind])/beta
Z2 = zstart + at*(zend-zstart)/beta
data = ["","","","","",""]
if code == 3:
data[xind]=X1
data[yind]=Y1
data[zind]=Z1
data[3+xind]=X2
data[3+yind]=Y2
data[3+zind]=Z2
new_lines.append(data)
else:
data[xind]=X2
data[yind]=Y2
data[zind]=Z2
data[3+xind]=X1
data[3+yind]=Y1
data[3+zind]=Z1
new_lines.insert(0, data)
X1=X2
Y1=Y2
Z1=Z2
at = at+arc_step
return new_lines
def get_line_intersect(self,p1, p2, xsplit):
dx = p2[0] - p1[0]
dy = p2[1] - p1[1]
dz = p2[2] - p1[2]
xcross = xsplit
try:
my = dy/dx
by = p1[1] - my * p1[0]
ycross = my*xsplit + by
except:
ycross = p1[1]
try:
mz = dz/dx
bz = p1[2] - mz * p1[0]
zcross = mz*xsplit + bz
except:
zcross = p1[2]
output=[]
if xcross > min(p1[0],p2[0])+self.Zero and xcross < max(p1[0],p2[0])-self.Zero:
output.append([xcross,ycross,zcross])
return output
def apleft(self, gtext):
self.left_side.append(gtext)
def apright(self, gtext):
self.right_side.append(gtext)
def apboth(self, gtext):
self.left_side.append(gtext)
self.right_side.append(gtext)
def rm_text(self,line,s,e):
if e == -1:
e = len(line)
temp1 = line[0:s]
temp2 = line[e+1:len(line)]
return temp1+temp2
def insert_text(self,line,itext,s):
temp1 = line[0:s]
temp2 = line[s:len(line)]
return temp1+itext+temp2
def coordop(self,coords,offset,rot):
x = coords[0]
y = coords[1]
z = coords[2]
x = x - offset[0]
y = y - offset[1]
z = z - offset[2]
x,y = self.Transform(x,y, radians(rot) )
return [x,y,z]
def coordunop(self,coords,offset,rot):
x = coords[0]
y = coords[1]
z = coords[2]
x,y = self.Transform(x,y, radians(-rot) )
x = x + offset[0]
y = y + offset[1]
z = z + offset[2]
return [x,y,z]
####################################### #######################################
####################################### #######################################
####################################### #######################################
####################################### #######################################
def FUNCTION_EVAL(self,list):
#list consists of [name,val1,val2]
name = list[0]
val1 = float(list[1])
fval = float(val1)
#############################################
########### G-CODE FUNCTIONS ################
#############################################
# ATAN[Y]/[X] Four quadrant inverse tangent #
# ABS[arg] Absolute value #
# ACOS[arg] Inverse cosine #
# ASIN[arg] Inverse sine #
# COS[arg] Cosine #
# EXP[arg] e raised to the given power #
# FIX[arg] Round down to integer #
# FUP[arg] Round up to integer #
# ROUND[arg] Round to nearest integer #
# LN[arg] Base-e logarithm #
# SIN[arg] Sine #
# SQRT[arg] Square Root #
# TAN[arg] Tangent #
# EXISTS[arg] Check named Parameter #
#############################################
if name == "ATAN":
fval2 = float(list[2])
atan2(fval1,fval2)
if name == "ABS":
return abs(fval)
if name == "ACOS":
return degrees(acos(fval))
if name == "ASIN":
return degrees(asin(fval))
if name == "COS":
return cos(radians(fval))
if name == "EXP":
return exp(fval)
if name == "FIX":
return floor(fval)
if name == "FUP":
return ceil(fval)
if name == "ROUND":
return round(fval)
if name == "LN":
return log(fval)
if name == "SIN":
return sin(radians(fval))
if name == "SQRT":
return sqrt(fval)
if name == "TAN":
return tan(radians(fval))
if name == "EXISTS":
pass
def EXPRESSION_EVAL(self,line):
###################################################
### EVALUATE MATH IN REGION ###
###################################################
line_in = line
P = 0
if P==1: self.fmessage("line=%s" %(line))
if len(line)<2:
MSG = "ERROR EXP-1: Unable to evaluate expression: %s\n" %(line_in)
raise ValueError(MSG)
line = line.replace(" ","")
#################################################
### G-CODE OPPERATORS ###
### In Precedence Order ###
#################################################
## ** #
## * / MOD #
## + - #
## EQ NE GT GE LT LE #
## AND OR XOR #
#################################################
#################################################
### Replace multiple +/- with single operator ###
#################################################
cnt = 1
while cnt > 0:
if (not self.cmp_new(line[cnt],'+')) or (not self.cmp_new(line[cnt],'-')):
sign = 1
span = 0
FLAG = True
while FLAG:
if not self.cmp_new(line[cnt+span],'+'):
span = span + 1
elif not self.cmp_new(line[cnt+span],'-'):
sign = -sign
span = span + 1
else:
FLAG = False
tmp1=line[:(cnt)]
tmp2=line[(cnt+span):]
if sign > 0:
line = tmp1+'+'+tmp2
else:
line = tmp1+'-'+tmp2
cnt=cnt + 1
if cnt >= len(line):
cnt = -1
#########################################
### Replace multi-character operators ###
### with single character identifiers ###
#########################################
line = line.replace("XOR","|")
line = line.replace("AND","&")
line = line.replace("LE","l")
line = line.replace("LT","<")
line = line.replace("GE","g")
line = line.replace("GT",">")
line = line.replace("NE","!")
line = line.replace("EQ","=")
line = line.replace("**","^")
#########################################
### Split the text into a list ###
#########################################
line = re.split( "([\[,\],\^,\*,\/,\%,\+,\-,\| ,\& ,\l ,\< ,\g ,\> ,\! ,\= ])", line)
#########################################
### Remove empty items from the list ###
#########################################
for i in range(line.count('')): line.remove('')
#########################################
### Find the last "[" in the list ###
#########################################
s=-1
for cnt in range(s+1,len(line)):
if line[cnt] == '[':
s = cnt
if s == -1:
MSG = "ERROR EXP-2: Unable to evaluate expression: %s" %(line_in)
#self.fmessage(MSG)
raise ValueError(MSG)
#################################################################
### While there are still brackets "[...]" keep processing ###
#################################################################
while s != -1:
##############################################################
### Find the first occurance of "]" after the current "[" ###
##############################################################
e=-1
for cnt in range(len(line)-1,s,-1):
if line[cnt] == ']':
e = cnt
#############################################
### Find the items between the brackets ###
#############################################
temp = line[s+1:e]
##############################################################
### Fix Some Special Cases ###
##############################################################
### **- *- MOD- ###
##############################################################
for cnt in range(0,len(temp)):
if (not self.cmp_new(temp[cnt],'^')) or \
(not self.cmp_new(temp[cnt],'*')) or \
(not self.cmp_new(temp[cnt],'%')):
if not self.cmp_new(temp[cnt+1],'-'):
temp[cnt+1]=''
temp[cnt+2]= -float(temp[cnt+2])
elif not self.cmp_new(temp[cnt+1],'+'):
temp[cnt+1]=''
temp[cnt+2]= float(temp[cnt+2])
for i in range(temp.count('')): temp.remove('')
#####################################
XOR_operation = self.list_split(temp,"|") #XOR
for iXOR in range(0,len(XOR_operation)):
#####################################
AND_operation = self.list_split(XOR_operation[iXOR],"&") #AND
for iAND in range(0,len(AND_operation)):
#####################################
LE_operation = self.list_split(AND_operation[iAND],"l") #LE
for iLE in range(0,len(LE_operation)):
#####################################
LT_operation = self.list_split(LE_operation[iLE],"<") #LT
for iLT in range(0,len(LT_operation)):
#####################################
GE_operation = self.list_split(LT_operation[iLT],"g") #GE
for iGE in range(0,len(GE_operation)):
#####################################
GT_operation = self.list_split(GE_operation[iGE],">") #GT
for iGT in range(0,len(GT_operation)):
#####################################
NE_operation = self.list_split(GT_operation[iGT],"!") #NE
for iNE in range(0,len(NE_operation)):
#####################################
EQ_operation = self.list_split(NE_operation[iNE],"=") #EQ
for iEQ in range(0,len(EQ_operation)):
#####################################
add = self.list_split(EQ_operation[iEQ],"+")
for cnt in range(1,len(add)):
if add[cnt-1]==[]:
add[cnt-1] = ''
for i in range(add.count('')): add.remove('')
for iadd in range(0,len(add)):
#####################################
subtract = self.list_split(add[iadd],"-")
for cnt in range(1,len(subtract)):
if subtract[cnt-1]==[]:
subtract[cnt-1] = ''
subtract[cnt][0] = -float(subtract[cnt][0])
for i in range(subtract.count('')): subtract.remove('')
for isub in range(0,len(subtract)):
#####################################
multiply = self.list_split(subtract[isub],"*")
for imult in range(0,len(multiply)):
#####################################
divide = self.list_split(multiply[imult],"/")
for idiv in range(0,len(divide)):
#####################################
mod = self.list_split(divide[idiv],"%")
for imod in range(0,len(mod)):
#####################################
power = self.list_split(mod[imod],"^")
for ipow in range(0,len(power)):
if power[ipow]==[]:
MSG = "ERROR EXP-3: Unable to evaluate expression: %s" %(line_in)
raise ValueError(MSG)
if type(power[0]) is list:
power_len = len(power[0])
else:
power_len = 1
if power_len > 1:
power[ipow] = self.FUNCTION_EVAL(power[0])
else:
power[ipow] = float(power[ipow][0])
#####################################
res_power=power[0]
for k in range(1,len(power)):
res_power = res_power**power[k]
if P==True: self.fmessage(" POWER"+str(power)+"="+str(res_power))
mod[imod]=res_power
#####################################
#REVERSE MOD
res_mod=mod[len(mod)-1]
for k in range(len(mod),1,-1):
res_mod = mod[k-2]%res_mod
self.fmessage(" MOD"+str(mod)+"="+str(res_mod))
divide[idiv]=res_mod
#####################################
res_divide=divide[0]
for k in range(1,len(divide),1):
res_divide = res_divide/divide[k]
if P==True: self.fmessage(" DIVIDE"+str(divide)+"="+str(res_divide))
multiply[imult]=res_divide
#####################################
res_multiply=multiply[0]
for k in range(1,len(multiply)):
res_multiply = res_multiply*multiply[k]
if P==True: self.fmessage("MULTIPLY"+str(multiply)+"="+str(res_multiply))
subtract[isub]=res_multiply
#####################################
res_subtract=subtract[0]
for k in range(1,len(subtract)):
res_subtract = res_subtract-subtract[k]
if P==True: self.fmessage("SUBTRACT"+str(subtract)+"="+str(res_subtract))
add[iadd]=res_subtract
#####################################
res_add=add[len(add)-1]
for k in range(len(add),1,-1):
res_add = add[k-2]+res_add
if P==True: self.fmessage(" ADD"+str(add)+"="+str(res_add))
EQ_operation[iEQ]=res_add
#####################
res_EQ=EQ_operation[0]
for k in range(1,len(EQ_operation),1):
if res_EQ == EQ_operation[k]:
res_EQ = 1
else:
res_EQ = 0
if P==True: self.fmessage(" EQ"+str(EQ_operation)+"="+str(res_EQ))
NE_operation[iNE]=res_EQ
#####################
res_NE=NE_operation[0]
for k in range(1,len(NE_operation),1):
if res_NE != NE_operation[k]:
res_NE = 1
else:
res_NE = 0
if P==True: self.fmessage(" NE"+str(NE_operation)+"="+str(res_NE))
GT_operation[iGT]=res_NE
#####################
res_GT=GT_operation[0]
for k in range(1,len(GT_operation),1):
if res_GT > GT_operation[k]:
res_GT = 1
else:
res_GT = 0
if P==True: self.fmessage(" GT"+str(GT_operation),"="+str(res_GT))
GE_operation[iGE]=res_GT
#####################
res_GE=GE_operation[0]
for k in range(1,len(GE_operation),1):
if res_GE >= GE_operation[k]:
res_GE = 1
else:
res_GE = 0
if P==True: self.fmessage(" GE"+str(GE_operation)+"="+str(res_GE))
LT_operation[iLT]=res_GE
#####################
res_LT=LT_operation[0]
for k in range(1,len(LT_operation),1):
if res_LT < LT_operation[k]:
res_LT = 1
else:
res_LT = 0
if P==True: self.fmessage(" LT"+str(LT_operation)+"="+str(res_LT))
LE_operation[iLE]=res_LT
#####################
res_LE=LE_operation[0]
for k in range(1,len(LE_operation),1):
if res_LE <= LE_operation[k]:
res_LE = 1
else:
res_LE = 0
if P==True: self.fmessage(" LE"+str(LE_operation)+"="+str(res_LE))
AND_operation[iAND]=res_LE
#####################
res_AND=AND_operation[0]
for k in range(1,len(AND_operation),1):
if res_AND and AND_operation[k]:
res_AND = 1
else:
res_AND = 0
if P==True: self.fmessage(" AND"+str(AND_operation)+"="+str(res_AND))
XOR_operation[iXOR]=res_AND
#####################
res_XOR=XOR_operation[0]
for k in range(1,len(XOR_operation),1):
if bool(res_XOR) ^ bool(XOR_operation[k]):
res_XOR = 1
else:
res_XOR = 0
if P==True: self.fmessage(" XOR"+str(XOR_operation)+"="+str(res_XOR))
#####################################
### Return NEW VALUE to the list ###
#####################################
for i in range(e,s-1,-1): line.pop(i)
line.insert(int(s),res_XOR)
#############################
# Find Last "[" in the list #
#############################
s=-1
for cnt in range(s+1,len(line)):
if line[cnt] == '[':
s = cnt
#################################################################
### END of While there are still brackets "[...]" ###
#################################################################
if len(line) > 1:
MSG = "ERROR EXP-5: Unable to evaluate expression: %s" %(line_in)
raise ValueError(MSG)
return "%.4f" %(line[0])
def list_split(self,lst,obj):
loc=[]
index = -1
for cnt in range(0,len(lst)):
if not self.cmp_new(lst[cnt],obj):
loc.append( lst[index+1:cnt] )
index=cnt
loc.append( lst[index+1:len(lst)])
return loc
#Define self.cmp_new, cmp replacement for Python 3 compatability
def cmp_new(self,A,B):
if A==B:
return False
else:
return True
############################################################################
# routine takes an x and a y coords and does a cordinate transformation #
# to a new coordinate system at angle from the initial coordinate system #
# Returns new x,y tuple #
############################################################################
def Transform(self,x,y,angle):
newx = x * cos(angle) - y * sin(angle)
newy = x * sin(angle) + y * cos(angle)
return newx,newy
############################################################################
# routine takes an sin and cos and returnss the angle (between 0 and 360) #
############################################################################
def Get_Angle2(self,x,y,code=""):
angle = 90.0-degrees(atan2(x,y))
if angle < 0:
angle = 360 + angle
if code == "G2":
return (360.0 - angle)
else:
return angle
##################################################
### Generate paths for Laser cutter ###
##################################################
def generate_laser_paths(self,side,Rapids=True):
ecoords = []
#################################
xlast = -99999
ylast = -99999
loop = 1
for line in side:
#print line
if line[0] == 1:
feed = line[3]
spindle = line[4]
x1=(line[1][0]+0j).real
y1=(line[1][1]+0j).real
z1=(line[1][2]+0j).real
x2=(line[2][0]+0j).real
y2=(line[2][1]+0j).real
z2=(line[2][2]+0j).real
if xlast!=x1 or ylast!=y1:
loop = loop+1
ecoords.append([x1,y1,loop,feed,spindle])
if x2!=x1 or y2!=y1:
ecoords.append([x2,y2,loop,feed,spindle])
xlast = x2
ylast = y2
######################################
return ecoords
##################################################
### End Generate paths for Laser cutter ###
##################################################
if __name__ == "__main__":
g_rip = G_Code_Rip()
filename="Z:\\text.ngc"
MSG = g_rip.Read_G_Code(filename, XYarc2line = True, arc_angle=2, units="in", Accuracy="")
print(MSG)
ecoords = g_rip.generate_laser_paths(g_rip.g_code_data)
for line in ecoords:
print(line)