k40whisperer_turbo/dxf.py

1406 wiersze
48 KiB
Python

#!/usr/bin/python
"""
DXF Utilities
Copyright (C) <2018> <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/>.
"""
from math import *
Zero = 0.00001
####################################################
## PointClass from dxf2gcode_b02_point.py ##
####################################################
class PointClass:
def __init__(self,x=0,y=0):
self.x=x
self.y=y
def __str__(self):
return ('X ->%6.3f Y ->%6.3f' %(self.x,self.y))
####################################################
## Begin Excerpts from dxf2gcode_b02_nurbs_calc ##
####################################################
class NURBSClass:
def __init__(self,degree=0,Knots=[],Weights=None,CPoints=None):
self.degree=degree #Spline degree
self.Knots=Knots #Knot Vector
self.CPoints=CPoints #Control points of splines [2D]
self.Weights=Weights #Weighting of the individual points
#Initializing calculated variables
self.HCPts=[] #Homogeneous points vectors [3D]
#Convert Points in Homogeneous points
self.CPts_2_HCPts()
#Creating the BSplineKlasse to calculate the homogeneous points
self.BSpline=BSplineClass(degree=self.degree,\
Knots=self.Knots,\
CPts=self.HCPts)
#Calculate a number points using error limiting
def calc_curve(self,n=0, lin_tol=.001):
#Initial values for step and u
u=0; Points=[]
i=1
while self.Knots[i]==0:
i=i+1
step=self.Knots[i]/3
Pt1=self.NURBS_evaluate(n=n,u=0.0)
Points.append(Pt1)
while u<self.Knots[-1]:
if (u+step > self.Knots[-1]):
step = self.Knots[-1]-u
Pt2=self.NURBS_evaluate(n=n,u=u+step)
Pt_test=self.NURBS_evaluate(n=n,u=u + step/2)
###
DX = Pt2.x-Pt1.x
DY = Pt2.y-Pt1.y
cord = sqrt(DX*DX + DY*DY)
DXtest = Pt_test.x-(Pt1.x+Pt2.x)/2.0
DYtest = Pt_test.y-(Pt1.y+Pt2.y)/2.0
t = sqrt(DXtest*DXtest + DYtest*DYtest)
if t > lin_tol:
step = step/2
else:
u+=step
Points.append(Pt2)
step = step*2
Pt1=Pt2
return Points
#Calculate a point of NURBS
def NURBS_evaluate(self,n=0,u=0):
#Calculate the homogeneous points to the n th derivative
HPt=self.BSpline.bspline_ders_evaluate(n=n,u=u)
#Point back to normal coordinates transform
Point=self.HPt_2_Pt(HPt[0])
return Point
#Convert the NURBS control points and weight in a homogeneous vector
def CPts_2_HCPts(self):
for P_nr in range(len(self.CPoints)):
HCPtVec=[self.CPoints[P_nr].x*self.Weights[P_nr],\
self.CPoints[P_nr].y*self.Weights[P_nr],\
self.Weights[P_nr]]
self.HCPts.append(HCPtVec[:])
#Convert a homogeneous vector point in a point
def HPt_2_Pt(self,HPt):
return PointClass(x=HPt[0]/HPt[-1],y=HPt[1]/HPt[-1])
class BSplineClass:
def __init__(self,degree=0,Knots=[],CPts=[]):
self.degree=degree
self.Knots=Knots
self.CPts=CPts
self.Knots_len=len(self.Knots)
self.CPt_len=len(self.CPts[0])
self.CPts_len=len(self.CPts)
# Incoming inspection, fit the upper node number, etc.
if self.Knots_len< self.degree+1:
raise Exception("SPLINE: degree greater than number of control points.")
if self.Knots_len != (self.CPts_len + self.degree+1):
raise Exception("SPLINE: Knot/Control Point/degree number error.")
#Modified Version of Algorithm A3.2 from "THE NURBS BOOK" pg.93
def bspline_ders_evaluate(self,n=0,u=0):
#Calculating the position of the node vector
span=self.findspan(u)
#Compute the basis function up to the n th derivative at the point u
dN=self.ders_basis_functions(span,u,n)
p=self.degree
du=min(n,p)
CK=[]
dPts=[]
for i in range(self.CPt_len):
dPts.append(0.0)
for k in range(n+1):
CK.append(dPts[:])
for k in range(du+1):
for j in range(p+1):
for i in range(self.CPt_len):
CK[k][i]+=dN[k][j]*self.CPts[span-p+j][i]
return CK
#Algorithm A2.1 from "THE NURBS BOOK" pg.68
def findspan(self,u):
#Special case when the value is == Endpoint
if(u==self.Knots[-1]):
return self.Knots_len-self.degree-2
# Binary search
# (The interval from high to low is always halved by
# [mid: mi +1] value lies between the interval of Knots)
low=self.degree
high=self.Knots_len
mid=int((low+high)/2)
while ((u<self.Knots[mid])or(u>=self.Knots[mid+1])):
if (u<self.Knots[mid]):
high=mid
else:
low=mid
mid=int((low+high)/2)
if low==high: #new
break #new
return mid
#Algorithm A2.3 from "THE NURBS BOOK" pg.72
def ders_basis_functions(self,span,u,n):
d=self.degree
#Initialize the a matrix
a=[]
zeile=[]
for j in range(d+1):
zeile.append(0.0)
a.append(zeile[:]); a.append(zeile[:])
#Initialize the ndu matrix
ndu=[]
zeile=[]
for i in range(d+1):
zeile.append(0.0)
for j in range(d+1):
ndu.append(zeile[:])
#Initialize the ders matrix
ders=[]
zeile=[]
for i in range(d+1):
zeile.append(0.0)
for j in range(n+1):
ders.append(zeile[:])
ndu[0][0]=1.0
left=[0]
right=[0]
for j in range(1,d+1):
left.append(u-self.Knots[span+1-j])
right.append(self.Knots[span+j]-u)
saved=0.0
for r in range(j):
#Lower Triangle
ndu[j][r]=right[r+1]+left[j-r]
temp=ndu[r][j-1]/ndu[j][r]
#Upper Triangle
ndu[r][j]=saved+right[r+1]*temp
saved=left[j-r]*temp
ndu[j][j]=saved
#Load the basis functions
for j in range(d+1):
ders[0][j]=ndu[j][d]
#This section computes the derivatives (Eq. [2.9])
for r in range(d+1): #Loop over function index
s1=0; s2=1 #Alternate rows in array a
a[0][0]=1.0
for k in range(1,n+1):
der=0.0
rk=r-k; pk=d-k
if(r>=k):
a[s2][0]=a[s1][0]/ndu[pk+1][rk]
der=a[s2][0]*ndu[rk][pk]
if (rk>=-1):
j1=1
else:
j1=-rk
if (r-1<=pk):
j2=k-1
else:
j2=d-r
#Here he is not in the first derivative of pure
for j in range(j1,j2+1):
a[s2][j]=(a[s1][j]-a[s1][j-1])/ndu[pk+1][rk+j]
der+=a[s2][j]*ndu[rk+j][pk]
if(r<=pk):
a[s2][k]=-a[s1][k-1]/ndu[pk+1][r]
der+=a[s2][k]*ndu[r][pk]
ders[k][r]=der
j=s1; s1=s2; s2=j #Switch rows
#Multiply through by the the correct factors
r=d
for k in range(1,n+1):
for j in range(d+1):
ders[k][j] *=r
r*=(d-k)
return ders
####################################################
## End Excerpts from dxf2gcode_b02_nurbs_calc.py ##
####################################################
class Header:
def __init__(self):
self.variables = dict()
self.last_var = None
def new_var(self, kw):
self.variables.update({kw: dict()})
self.last_var = self.variables[kw]
def new_val(self, val):
self.last_var.update({ str(val[0]) : val[1] })
class Entity:
def __init__(self, _type):
self.type = _type
self.data = dict()
def update(self, value):
key = str(value[0])
val = value[1]
if key in self.data:
if type(self.data[key]) != list:
self.data[key] = [self.data[key]]
self.data[key].append(val)
else:
self.data.update({key:val})
class Entities:
def __init__(self):
self.entities = []
self.last = None
def new_entity(self, _type):
e = Entity(_type)
self.entities.append(e)
self.last = e
def update(self, value):
self.last.update(value)
class Layer:
def __init__(self):
self.data = dict()
def update(self, value):
key = str(value[0])
val = value[1]
if key in self.data:
if type(self.data[key]) != list:
self.data[key] = [self.data[key]]
self.data[key].append(val)
else:
self.data.update({key:val})
class Layers:
def __init__(self):
self.layers = []
self.last = None
def new_layer(self):
e = Layer()
self.layers.append(e)
self.last = e
def update(self, value):
self.last.update(value)
class Block:
def __init__(self, master):
self.master = master
self.data = dict()
self.entities = []
self.le = None
def new_entity(self, value):
self.le = Entity(value)
self.entities.append(self.le)
def update(self, value):
if self.le == None:
val = str(value[0])
self.data.update({val:value[1]})
if val == "2":
self.master.blocks[value[1]] = self
else:
self.le.update(value)
class Blocks:
def __init__(self):
self.blocks = dict()
self.last_var = None
def new_block(self):
b = Block(self)
self.last_block = b
self.last_var = b
def new_entity(self, value):
self.last_block.new_entity(value)
def update(self, value):
self.last_block.update(value)
class DXF_CLASS:
def __init__(self):
self.units = 0
self.dxf_messages = ""
self.coords = []
self.cut_coords = []
self.eng_coords = []
strings = []
floats = []
ints = []
self.layer_color=dict()
strings += list(range(0, 10)) #String (255 characters maximum; less for Unicode strings)
floats += list(range(10, 60)) #Double precision 3D point
ints += list(range(60, 80)) #16-bit integer value
ints += list(range(90,100)) #32-bit integer value
strings += [100] #String (255 characters maximum; less for Unicode strings)
strings += [102] #String (255 characters maximum; less for Unicode strings
strings += [105] #String representing hexadecimal (hex) handle value
floats += list(range(140, 148)) #Double precision scalar floating-point value
ints += list(range(170, 176)) #16-bit integer value
ints += list(range(280, 290)) #8-bit integer value
strings += list(range(300, 310)) #Arbitrary text string
strings += list(range(310, 320)) #String representing hex value of binary chunk
strings += list(range(320, 330)) #String representing hex handle value
strings += list(range(330, 369)) #String representing hex object IDs
strings += [999] #Comment (string)
strings += list(range(1000, 1010))#String (255 characters maximum; less for Unicode strings)
floats += list(range(1010, 1060)) #Floating-point value
ints += list(range(1060, 1071)) #16-bit integer value
ints += [1071] #32-bit integer value
self.funs = []
for i in range(0,1072):
self.funs.append(self.read_none)
for i in strings:
self.funs[i] = self.read_string
for i in floats:
self.funs[i] = self.read_float
for i in ints:
self.funs[i] = self.read_int
self.unit_vals = ["Unitless",
"Inches",
"Feet",
"Miles",
"Millimeters",
"Centimeters",
"Meters",
"Kilometers",
"Microinches",
"Mils"]
self.POLY_FLAG = None
self.POLY_CLOSED = None
def dxf_message(self,text):
self.dxf_messages = self.dxf_messages + "\n" + text
def read_int(self,data):
return int(float(data))
def read_float(self,data):
return float(data)
def read_string(self,data):
return str(data)
def read_none(self,data):
return None
### def read_dxf_file(self, name, data):
### fd = file(name)
### Skip = True
### for line in fd:
### group_code = int(line)
###
### value = fd.next().replace('\r', '')
### value = value.replace('\n', '')
### value = value.lstrip(' ')
### value = value.rstrip(' ')
### value = self.funs[group_code](value)
### if (value != "SECTION") and Skip:
### continue
### else:
### Skip = False
### data.append((group_code, value))
### fd.close()
def read_dxf_data(self, fd, data):
self.comment="None"
Skip = True
fd_iter = iter(fd)
for line in fd_iter:
try:
group_code = int(line)
value = next(fd_iter).replace('\r', '')
value = value.replace('\n', '')
value = value.lstrip(' ')
value = value.rstrip(' ')
value = self.funs[group_code](value)
if (value != "SECTION") and Skip:
if group_code==999:
self.comment=value
continue
else:
Skip = False
data.append((group_code, value))
except:
pass
##########################################################################
# routine takes an sin and cos and returns the angle (between 0 and 360) #
##########################################################################
def Get_Angle(self,y,x):
angle = 90.0-degrees(atan2(x,y))
if angle < 0:
angle = 360 + angle
return angle
############################################################################
# routine takes an x and a y coords and does a coordinate 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
def bulge_coords(self,x0,y0,x1,y1,bulge,lin_tol=.001):
global Zero
bcoords=[]
if bulge < 0.0:
sign = 1
bulge=abs(bulge)
else:
sign = -1
dx = x1-x0
dy = y1-y0
c = sqrt(dx**2 + dy**2)
alpha = 2.0 * (atan(bulge))
R = c / (2*sin(alpha))
L = R * cos(alpha)
if (lin_tol < R):
step_deg = 2*acos((R-lin_tol)/R)*180/pi
else:
step_deg = 45
steps = ceil(2*alpha / radians(step_deg))
if abs(c) < Zero:
phi = 0
bcoords.append([x0,y0,x1,y1])
return bcoords
seg_sin = dy/c
seg_cos = dx/c
phi = self.Get_Angle(seg_sin,seg_cos)
d_theta = 2*alpha / steps
theta = alpha - d_theta
xa = x0
ya = y0
for i in range(1,int(steps)):
xp = c/2 - R*sin(theta)
yp = R*cos(theta) - L
xb,yb = self.Transform(xp,yp*sign,radians(phi))
xb=xb+x0
yb=yb+y0
bcoords.append([xa,ya,xb,yb])
xa = xb
ya = yb
theta = theta -d_theta
bcoords.append([xa,ya,x1,y1])
return bcoords
def add_coords(self,line,offset,scale,rotate,color=None,layer=None):
slcolor = 0
if(type(layer)!=list):
if layer in self.layer_color:
slcolor = self.layer_color[layer]
else:
for layer_item in layer:
if layer_item in self.layer_color:
slcolor = self.layer_color[layer_item]
# Now test for Hidden layer IE Color < 0
if ( slcolor != None) and (slcolor < 0):
return
if (color == None) or (color == 256): # 256 is ColorByLayer
# default to layer color
color = slcolor
if ( color != None) and (color < 0):
return
x0s = line[0]*scale[0]
y0s = line[1]*scale[1]
x1s = line[2]*scale[0]
y1s = line[3]*scale[1]
if abs(rotate) > Zero:
rad = radians(rotate)
x0r = x0s*cos(rad) - y0s*sin(rad)
y0r = x0s*sin(rad) + y0s*cos(rad)
x1r = x1s*cos(rad) - y1s*sin(rad)
y1r = x1s*sin(rad) + y1s*cos(rad)
else:
x0r = x0s
y0r = y0s
x1r = x1s
y1r = y1s
x0 = x0r + offset[0]
y0 = y0r + offset[1]
x1 = x1r + offset[0]
y1 = y1r + offset[1]
# Check if line is blue
Color_Blue = (color == 5) or (color >= 140 and color <=180)
try:
Layer_Engrave = str.find(layer.upper(),'ENGRAVE') != -1
except:
Layer_Engrave = False
try:
for lay in layer:
Layer_Engrave = (str.find(lay.upper(),'ENGRAVE') != -1) or Layer_Engrave
except:
pass
if Color_Blue or Layer_Engrave:
self.eng_coords.append([x0,y0,x1,y1])
else: #if (color >= 10 and color <=28) or (color >= 230 and color <=249): #red
self.cut_coords.append([x0,y0,x1,y1])
self.coords.append([x0,y0,x1,y1])
def eval_entity(self,e,bl,lin_tol=.001,offset=[0,0],scale=[1,1],rotate=0):
try:
color = e.data["62"]
except:
color = None
if ( color != None) and (color < 0):
return
try:
layer = e.data["8"]
except:
layer = 0
slcolor = 0
if(type(layer)!=list):
if layer in self.layer_color:
slcolor = self.layer_color[layer]
else:
for layer_item in layer:
if layer_item in self.layer_color:
slcolor = self.layer_color[layer_item]
# Now test for Hidden layer IE Color < 0
if ( slcolor != None) and (slcolor < 0):
return
############# LINE ############
if e.type == "LINE":
x0 = e.data["10"]
y0 = e.data["20"]
x1 = e.data["11"]
y1 = e.data["21"]
self.add_coords([x0,y0,x1,y1],offset,scale,rotate,color,layer)
############# ARC #############
elif e.type == "ARC":
x = e.data["10"]
y = e.data["20"]
r = e.data["40"]
start = e.data["50"]
end = e.data["51"]
if end < start:
end=end+360.0
delta = end-start
if (lin_tol < r):
step_deg = 2*acos((r-lin_tol)/r)*180/pi
else:
step_deg = 45
angle_steps = max(floor(delta/step_deg),2)
start_r = radians(start)
end_r = radians(end)
step_phi = radians( delta/angle_steps )
x0 = x + r * cos(start_r)
y0 = y + r * sin(start_r)
pcnt = 1
while pcnt < angle_steps+1:
phi = start_r + pcnt*step_phi
x1 = x + r * cos(phi)
y1 = y + r * sin(phi)
self.add_coords([x0,y0,x1,y1],offset,scale,rotate,color,layer)
x0=x1
y0=y1
pcnt += 1
######### LWPOLYLINE ##########
elif e.type == "LWPOLYLINE":
flag=0
lpcnt=-1
try:
xy_data = zip(e.data["10"], e.data["20"])
except:
try:
xy_data = [[e.data["10"], e.data["20"]]]
except:
self.dxf_message("DXF Import zero length %s Ignored" %(e.type))
xy_data = []
for x,y in xy_data:
x1 = x
y1 = y
lpcnt=lpcnt+1
try:
bulge1 = e.data["42"][lpcnt]
except:
bulge1 = 0
if flag==0:
x0=x1
y0=y1
bulge0=bulge1
flag=1
else:
if bulge0 != 0:
bcoords = self.bulge_coords(x0,y0,x1,y1,bulge0,lin_tol=lin_tol)
for line in bcoords:
self.add_coords(line,offset,scale,rotate,color,layer)
else:
self.add_coords([x0,y0,x1,y1],offset,scale,rotate,color,layer)
x0 = x1
y0 = y1
bulge0 = bulge1
if (e.data["70"] & 1): #check if bit-code 1 is set for closed polygon
try:
x1 = e.data["10"][0]
y1 = e.data["20"][0]
except:
x1 = e.data["10"]
y1 = e.data["20"]
if bulge0 != 0:
bcoords = self.bulge_coords(x0,y0,x1,y1,bulge1,lin_tol=lin_tol)
for line in bcoords:
self.add_coords(line,offset,scale,rotate,color,layer)
else:
self.add_coords([x0,y0,x1,y1],offset,scale,rotate,color,layer)
########### CIRCLE ############
elif e.type == "CIRCLE":
x = e.data["10"]
y = e.data["20"]
r = e.data["40"]
start = 0
end = 360
if end < start:
end=end+360.0
delta = end-start
if (lin_tol < r):
step_deg = 2*acos((r-lin_tol)/r)*180/pi
else:
step_deg = 45
angle_steps = max(floor(delta/step_deg),2)
start_r = radians( start )
end_r = radians( end )
step_phi = radians( delta/angle_steps)
x0 = x + r * cos(start_r)
y0 = y + r * sin(start_r)
pcnt = 1
while pcnt < angle_steps+1:
phi = start_r + pcnt*step_phi
x1 = x + r * cos(phi)
y1 = y + r * sin(phi)
self.add_coords([x0,y0,x1,y1],offset,scale,rotate,color,layer)
x0=x1
y0=y1
pcnt += 1
############ SPLINE ###########
elif e.type == "SPLINE":
self.Spline_flag=[]
self.degree=1
self.Knots=[]
self.Weights=[]
self.CPoints=[]
self.Spline_flag = int(e.data["70"])
self.degree = int(e.data["71"])
self.Knots = e.data["40"]
try:
self.Weights = e.data["41"]
except:
for K in self.Knots:
self.Weights.append(1)
pass
kmin = min(self.Knots)
kmax = max(self.Knots)
for i in range(len(self.Knots)):
self.Knots[i] = (self.Knots[i]-kmin)/(kmax-kmin)
try:
xy_data = zip(e.data["10"], e.data["20"])
except:
self.dxf_message("DXF Import zero length %s Ignored" %(e.type))
xy_data = []
if xy_data!=[]:
for x,y in xy_data:
self.CPoints.append(PointClass(float(x), float(y)))
self.MYNURBS=NURBSClass(degree=self.degree, \
Knots=self.Knots, \
Weights=self.Weights,\
CPoints=self.CPoints)
mypoints=self.MYNURBS.calc_curve(n=0, lin_tol=lin_tol)
flag = 0
for XY in mypoints:
x1 = XY.x
y1 = XY.y
if flag==0:
x0=x1
y0=y1
flag=1
else:
self.add_coords([x0,y0,x1,y1],offset,scale,rotate,color,layer)
x0=x1
y0=y1
########### ELLIPSE ###########
elif e.type == "ELLIPSE":
#X and Y center points
xcp = e.data["10"]
ycp = e.data["20"]
#X and Y of major axis end point
xma = e.data["11"]
yma = e.data["21"]
#Ratio of minor axis to major axis
ratio = e.data["40"]
#Start and end angles (in radians 0 and 2pi for full ellipse)
start = degrees( e.data["41"] )
end = degrees( e.data["42"] )
rotation = atan2(yma, xma)
a = sqrt(xma**2 + yma**2)
b = a * ratio
##################
if end < start:
end=end+360.0
delta = end-start
start_r = radians( start )
end_r = radians( end )
tol = radians(2)
phi = start_r
x1 = xcp + ( a*cos(phi) * cos(rotation) - b*sin(phi) * sin(rotation) );
y1 = ycp + ( a*cos(phi) * sin(rotation) + b*sin(phi) * cos(rotation) );
step=tol
while phi < end_r:
if (phi+step > end_r):
step = end_r-phi
x2 = xcp + ( a*cos(phi+step) * cos(rotation) - b*sin(phi+step) * sin(rotation) );
y2 = ycp + ( a*cos(phi+step) * sin(rotation) + b*sin(phi+step) * cos(rotation) );
x_test = xcp + ( a*cos(phi+step/2) * cos(rotation) - b*sin(phi+step/2) * sin(rotation) );
y_test = ycp + ( a*cos(phi+step/2) * sin(rotation) + b*sin(phi+step/2) * cos(rotation) );
x_mid = (x1+x2)/2
y_mid = (y1+y2)/2
dx_mid = x_mid-x_test
dy_mid = y_mid-y_test
delta = sqrt(dx_mid*dx_mid + dy_mid*dy_mid)
if delta > lin_tol:
step = step/2
else:
phi+=step
self.add_coords([x1,y1,x2,y2],offset,scale,rotate,color,layer)
step = step*2
x1=x2
y1=y2
########### LEADER ###########
elif e.type == "LEADER":
flag=0
try:
xy_data = zip(e.data["10"], e.data["20"])
except:
self.dxf_message("DXF Import zero length %s Ignored" %(e.type))
xy_data = []
for x,y in xy_data:
x1 = x
y1 = y
if flag==0:
x0=x1
y0=y1
flag=1
else:
self.add_coords([x0,y0,x1,y1],offset,scale,rotate,color,layer)
x0=x1
y0=y1
########### POLYLINE ###########
elif e.type == "POLYLINE":
self.POLY_CLOSED = 0
self.POLY_FLAG = -1
try:
TYPE=e.data["70"]
if TYPE >=128:
#print "#128 = The linetype pattern is generated continuously around the vertices of this polyline."
TYPE=TYPE-128
if TYPE >=64:
#print "#64 = The polyline is a polyface mesh."
TYPE=TYPE-64
if TYPE >=32:
#print "#32 = The polygon mesh is closed in the N direction."
TYPE=TYPE-32
if TYPE >=16:
#print "#16 = This is a 3D polygon mesh."
TYPE=TYPE-16
if TYPE >=8:
#print "#8 = This is a 3D polyline."
TYPE=TYPE-8
if TYPE >=4:
#print "#4 = Spline-fit vertices have been added."
TYPE=TYPE-4
if TYPE >=2:
#print "#2 = Curve-fit vertices have been added."
TYPE=TYPE-2
if TYPE >=1:
#print "#1 = This is a closed polyline (or a polygon mesh closed in the M direction)."
self.POLY_CLOSED=1
TYPE=TYPE-1
except:
pass
########### SEQEND ###########
elif e.type == "SEQEND":
if (self.POLY_FLAG == 1): # None):
self.POLY_FLAG=None
if (self.POLY_CLOSED==1):
self.POLY_CLOSED==0
x0 = self.PX
y0 = self.PY
x1 = self.PX0
y1 = self.PY0
if self.bulge != 0:
bcoords = self.bulge_coords(x0,y0,x1,y1,self.bulge,lin_tol=lin_tol)
for line in bcoords:
self.add_coords(line,offset,scale,rotate,color,layer)
else:
self.add_coords([x0,y0,x1,y1],offset,scale,rotate,color,layer)
else:
self.dxf_message("DXF Import Ignored: - %s - Entity" %(e.type))
########### VERTEX ###########
elif e.type == "VERTEX":
SKIP=False
try:
TYPE=e.data["70"]
#print "TYPE=",TYPE
#if (TYPE==0 or TYPE==8):
# pass
#elif (TYPE==1):
# self.POLY_CLOSED=1
if TYPE >=128:
#print "128 = Polyface mesh vertex"
TYPE=TYPE-128
if TYPE >=64:
#print "64 = 3D polygon mesh"
TYPE=TYPE-64
if TYPE >=32:
#print "32 = 3D polyline vertex"
TYPE=TYPE-32
if TYPE >=16:
#print "16 = Spline frame control point"
TYPE=TYPE-16
SKIP=True
if TYPE >=8:
#print "8 = Spline vertex created by spline-fitting"
TYPE=TYPE-8
if TYPE >=4:
#print "4 = Not used"
TYPE=TYPE-4
if TYPE >=2:
#print "2 = Curve-fit tangent defined for this vertex. A curve-fit tangent direction of 0 may be omitted from DXF output but is significant if this bit is set."
TYPE=TYPE-2
if TYPE >=1:
#print "1 = Extra vertex created by curve-fitting"
TYPE=TYPE-1
except:
pass
if (self.POLY_FLAG == 1 and not SKIP):
x0 = self.PX
y0 = self.PY
x1 = e.data["10"]
y1 = e.data["20"]
self.PX=x1
self.PY=y1
if self.bulge != 0:
bcoords = self.bulge_coords(x0,y0,x1,y1,self.bulge,lin_tol=lin_tol)
for line in bcoords:
self.add_coords(line,offset,scale,rotate,color,layer)
else:
self.add_coords([x0,y0,x1,y1],offset,scale,rotate,color,layer)
try:
self.bulge = e.data["42"]
except:
self.bulge = 0
elif (self.POLY_FLAG == -1 and not SKIP):
self.PX = e.data["10"]
self.PY = e.data["20"]
self.PX0 = self.PX
self.PY0 = self.PY
try:
self.bulge = e.data["42"]
except:
self.bulge = 0
self.POLY_FLAG = 1
else:
self.dxf_message("DXF Import Ignored: - %s - Entity" %(e.type))
########### END VERTEX ###########
########### INSERT ###########
elif e.type == "INSERT":
key = e.data["2"]
xoff = e.data["10"]+offset[0]
yoff = e.data["20"]+offset[1]
try:
xscale = e.data["41"]
except:
xscale = 1
try:
yscale = e.data["42"]
except:
yscale = 1
try:
rotate = e.data["50"]
except:
rotate = 0
try:
x_block_ref = bl.blocks[key].data.get("10")
y_block_ref = bl.blocks[key].data.get("20")
except:
x_block_ref = 0
y_block_ref = 0
xoff = xoff - x_block_ref
yoff = yoff - y_block_ref
for e in bl.blocks[key].entities:
self.eval_entity(e,bl,lin_tol,offset=[xoff,yoff],scale=[xscale,yscale],rotate=rotate)
########### END INSERT ###########
elif e.type == "SOLID":
x0 = e.data["10"]
y0 = e.data["20"]
x1 = e.data["11"]
y1 = e.data["21"]
x2 = e.data["12"]
y2 = e.data["22"]
try:
x3 = e.data["13"]
y3 = e.data["23"]
except:
x3 = x2
y3 = y2
self.add_coords([x0,y0,x1,y1],offset,scale,rotate,color,layer)
self.add_coords([x1,y1,x3,y3],offset,scale,rotate,color,layer)
self.add_coords([x3,y3,x2,y2],offset,scale,rotate,color,layer)
self.add_coords([x2,y2,x0,y0],offset,scale,rotate,color,layer)
elif e.type == "HATCH":
#quietly ignore HATCH
pass
else:
self.dxf_message("DXF Import Ignored: %s Entity" %(e.type))
pass
def GET_DXF_DATA(self,fd, lin_tol=.001,get_units=False,units=None):
data = []
try:
self.read_dxf_data(fd, data)
except:
self.dxf_message("\nUnable to read input DXF data!")
return 1
data = iter(data)
g_code, value = None, None
sections = dict()
he = Header()
bl = Blocks()
la = Layers()
while value != "EOF":
g_code, value = next(data)
if value == "SECTION":
g_code, value = next(data)
sections[value] = []
while value != "ENDSEC":
if value == "HEADER":
while True:
g_code, value = next(data)
if value == "ENDSEC":
break
elif g_code == 9:
he.new_var(value)
else:
he.new_val((g_code, value))
elif value == "BLOCKS":
while True:
g_code, value = next(data)
if value == "ENDSEC":
break
elif value == "ENDBLK":
continue
elif value == "BLOCK":
bl.new_block()
elif g_code == 0 and value != "BLOCK":
bl.new_entity(value)
else:
bl.update((g_code, value))
elif value == "ENTITIES":
TYPE=""
en = Entities()
while True:
g_code, value = next(data)
###################################
if g_code==0:
TYPE = value
if TYPE == "LWPOLYLINE" and g_code==10 and g_code_last==20:
# Add missing code 42
en.update((42, 0.0))
g_code_last = g_code
###################################
if value == "ENDSEC":
break
elif g_code == 0 and value != "ENDSEC":
en.new_entity(value)
else:
en.update((g_code, value))
#------------------------------------------------------------------
elif value == "TABLE":
while True:
g_code, value = next(data)
if value == "AcDbLayerTableRecord" or value == "LAYER":
la.new_layer()
while True:
g_code, value = next(data)
if g_code==0:
if value == "AcDbLayerTableRecord" or value == "LAYER":
la.new_layer()
else:
break
la.update((g_code, value))
if value == "ENDTAB":
break
try:
g_code, value = next(data)
except:
break
#Process Units
try:
unit_val = he.variables.get("$INSUNITS").get("70")
self.units = self.unit_vals[int(unit_val)]
except:
self.units = self.unit_vals[0]
if get_units:
return
#Process Layers
for l in la.layers:
try:
color = l.data["62"]
except:
color = None
try:
name = l.data["2"]
except:
name = None
self.layer_color[name]=color
#Process Entities
for e in en.entities:
self.eval_entity(e,bl,lin_tol)
def DXF_COORDS_GET(self,new_origin=True):
if (new_origin==True):
ymin=99999
xmin=99999
for line in self.coords:
XY=line
if XY[0] < xmin:
xmin = XY[0]
if XY[1] < ymin:
ymin = XY[1]
if XY[2] < xmin:
xmin = XY[2]
if XY[3] < ymin:
ymin = XY[3]
else:
xmin=0
ymin=0
coords_out=[]
for line in self.coords:
XY=line
coords_out.append([XY[0]-xmin, XY[1]-ymin, XY[2]-xmin, XY[3]-ymin])
return coords_out
def DXF_COORDS_GET_TYPE(self,engrave=True,new_origin=True):
if engrave==True:
coords = self.eng_coords
else:
coords = self.cut_coords
if (new_origin==True):
ymin=99999
xmin=99999
for line in coords:
XY=line
if XY[0] < xmin:
xmin = XY[0]
if XY[1] < ymin:
ymin = XY[1]
if XY[2] < xmin:
xmin = XY[2]
if XY[3] < ymin:
ymin = XY[3]
else:
xmin=0
ymin=0
coords_out=[]
for line in coords:
XY=line
coords_out.append([XY[0]-xmin, XY[1]-ymin, XY[2]-xmin, XY[3]-ymin])
return coords_out
##################################################
### Begin Dxf_Write G-Code Writing Function ###
##################################################
def WriteDXF(self,close_loops=False):
if close_loops:
self.V_Carve_It(clean_flag=0,DXF_FLAG = close_loops)
dxf_code = []
# Create a header section just in case the reading software needs it
dxf_code.append("999")
dxf_code.append("DXF created by dxf library <by Scorch, www.scorchworks.com>")
dxf_code.append("0")
dxf_code.append("SECTION")
dxf_code.append("2")
dxf_code.append("HEADER")
dxf_code.append("0")
dxf_code.append("ENDSEC")
#
#Tables Section
#These can be used to specify predefined constants, line styles, text styles, view
#tables, user coordinate systems, etc. We will only use tables to define some layers
#for use later on. Note: not all programs that support DXF import will support
#layers and those that do usually insist on the layers being defined before use
#
# The following will initialise layers 1 and 2 for use with moves and rapid moves.
dxf_code.append("0")
dxf_code.append("SECTION")
dxf_code.append("2")
dxf_code.append("TABLES")
dxf_code.append("0")
dxf_code.append("TABLE")
dxf_code.append("2")
dxf_code.append("LTYPE")
dxf_code.append("70")
dxf_code.append("1")
dxf_code.append("0")
dxf_code.append("LTYPE")
dxf_code.append("2")
dxf_code.append("CONTINUOUS")
dxf_code.append("70")
dxf_code.append("64")
dxf_code.append("3")
dxf_code.append("Solid line")
dxf_code.append("72")
dxf_code.append("65")
dxf_code.append("73")
dxf_code.append("0")
dxf_code.append("40")
dxf_code.append("0.000000")
dxf_code.append("0")
dxf_code.append("ENDTAB")
dxf_code.append("0")
dxf_code.append("TABLE")
dxf_code.append("2")
dxf_code.append("LAYER")
dxf_code.append("70")
dxf_code.append("6")
dxf_code.append("0")
dxf_code.append("LAYER")
dxf_code.append("2")
dxf_code.append("1")
dxf_code.append("70")
dxf_code.append("64")
dxf_code.append("62")
dxf_code.append("7")
dxf_code.append("6")
dxf_code.append("CONTINUOUS")
dxf_code.append("0")
dxf_code.append("LAYER")
dxf_code.append("2")
dxf_code.append("2")
dxf_code.append("70")
dxf_code.append("64")
dxf_code.append("62")
dxf_code.append("7")
dxf_code.append("6")
dxf_code.append("CONTINUOUS")
dxf_code.append("0")
dxf_code.append("ENDTAB")
dxf_code.append("0")
dxf_code.append("TABLE")
dxf_code.append("2")
dxf_code.append("STYLE")
dxf_code.append("70")
dxf_code.append("0")
dxf_code.append("0")
dxf_code.append("ENDTAB")
dxf_code.append("0")
dxf_code.append("ENDSEC")
#This block section is not necessary but apperantly it's good form to include one anyway.
#The following is an empty block section.
dxf_code.append("0")
dxf_code.append("SECTION")
dxf_code.append("2")
dxf_code.append("BLOCKS")
dxf_code.append("0")
dxf_code.append("ENDSEC")
# Start entities section
dxf_code.append("0")
dxf_code.append("SECTION")
dxf_code.append("2")
dxf_code.append("ENTITIES")
dxf_code.append(" 0")
#################################
## GCODE WRITING for Dxf_Write ##
#################################
#for line in side:
for line in self.coords:
XY = line
#if line[0] == 1 or (line[0] == 0 and Rapids):
dxf_code.append("LINE")
dxf_code.append(" 5")
dxf_code.append("30")
dxf_code.append("100")
dxf_code.append("AcDbEntity")
dxf_code.append(" 8") #layer Code #dxf_code.append("0")
##########################
#if line[0] == 1:
# dxf_code.append("1")
#else:
# dxf_code.append("2")
#dxf_code.append(" 62") #color code
#if line[0] == 1:
# dxf_code.append("10")
#else:
# dxf_code.append("150")
dxf_code.append("1")
dxf_code.append(" 62") #color code
dxf_code.append("150")
###########################
dxf_code.append("100")
dxf_code.append("AcDbLine")
dxf_code.append(" 10")
dxf_code.append("%.4f" %(line[0])) #x1 coord
dxf_code.append(" 20")
dxf_code.append("%.4f" %(line[1])) #y1 coord
dxf_code.append(" 30")
dxf_code.append("%.4f" %(0)) #z1 coord
dxf_code.append(" 11")
dxf_code.append("%.4f" %(line[2])) #x2 coord
dxf_code.append(" 21")
dxf_code.append("%.4f" %(line[3])) #y2 coord
dxf_code.append(" 31")
dxf_code.append("%.4f" %(0)) #z2 coord
dxf_code.append(" 0")
dxf_code.append("ENDSEC")
dxf_code.append("0")
dxf_code.append("EOF")
######################################
## END G-CODE WRITING for Dxf_Write ##
######################################
return dxf_code