# -*- coding: utf-8 -*-
"""
Written by Daniel M. Aukes and CONTRIBUTORS
Email: danaukes<at>asu.edu.
Please see LICENSE for full license.
"""
import ezdxf
import matplotlib.pyplot as plt
#plt.ion()
import numpy
#def read_lines(filename, color = None ,layer = None):
[docs]def read_lines(filename, color = None, layer = None):
'''
Reads a dxf file searching for line objects,
:param filename: the file path of the source dxf
:type filename: string
:param color: optional. if included, this function filters for objects of only this color
:param layer: optional. if included, this function filters for objects of only this layer
:rtype: List of lines consisting of two two-coordinate tuples each.
'''
dwg = ezdxf.readfile(filename)
modelspace = dwg.modelspace()
lines = []
for e in modelspace:
if e.dxftype() == 'LINE':
# red is code 1, gets added to hinge lines
if color is not None:
if e.get_dxf_attrib('color')==color:
lines.append([(e.dxf.start[0],e.dxf.start[1]),(e.dxf.end[0],e.dxf.end[1])])
elif layer is not None:
if e.get_dxf_attrib('layer')==layer:
lines.append([(e.dxf.start[0],e.dxf.start[1]),(e.dxf.end[0],e.dxf.end[1])])
else:
lines.append([(e.dxf.start[0],e.dxf.start[1]),(e.dxf.end[0],e.dxf.end[1])])
return lines
#def read_lwpolylines(filename,color = None,layer = None):
[docs]def read_lwpolylines(filename,color = None,layer = None,arc_approx = 0):
'''
Reads a dxf file searching for lwpolyline objects, approximating arc elements in an lwpolyline with an n-segement set of lines
:param filename: the file path of the source dxf
:type filename: string
:param color: optional. if included, this function filters for objects of only this color
:param layer: optional. if included, this function filters for objects of only this layer
:param arc_approx: number of interior points to approximate an arc with
:type arc_approx: int
:rtype: List of lines consisting of two two-coordinate tuples each.
'''
dwg = ezdxf.readfile(filename)
modelspace = dwg.modelspace()
lines = []
for e in modelspace:
if e.dxftype() == 'LWPOLYLINE':
if color is not None:
if e.get_dxf_attrib('color')==color:
line = numpy.array(list(e.get_points()))
line_out = []
for ii in range(len(line)):
if line[ii,4]!=0:
line_out.extend(calc_circle(line[ii,:2],line[ii+1,:2],line[ii,4],arc_approx))
else:
line_out.append(line[ii,:2].tolist())
lines.append(line_out)
elif layer is not None:
if e.get_dxf_attrib('layer')==layer:
line = numpy.array(list(e.get_points()))
line_out = []
for ii in range(len(line)):
if line[ii,4]!=0:
line_out.extend(calc_circle(line[ii,:2],line[ii+1,:2],line[ii,4],arc_approx))
else:
line_out.append(line[ii,:2].tolist())
lines.append(line_out)
else:
line = numpy.array(list(e.get_points()))
line_out = []
for ii in range(len(line)):
if line[ii,4]!=0:
line_out.extend(calc_circle(line[ii,:2],line[ii+1,:2],line[ii,4],arc_approx))
else:
line_out.append(line[ii,:2].tolist())
lines.append(line_out)
return lines
[docs]def read_circles(filename,color = None,layer = None):
'''
Reads a dxf file searching for circle objects, approximating arc elements in an lwpolyline with an n-segement set of lines
:param filename: the file path of the source dxf
:type filename: string
:param color: optional. if included, this function filters for objects of only this color
:param layer: optional. if included, this function filters for objects of only this layer
:rtype: List of tuples consisting (center and radius) representing each circle.
'''
dwg = ezdxf.readfile(filename)
modelspace = dwg.modelspace()
circles= []
for e in modelspace:
if e.dxftype() == 'CIRCLE':
if color is not None:
if e.get_dxf_attrib('color')==color:
center = e.get_dxf_attrib('center')
radius = e.get_dxf_attrib('radius')
circles.append((center,radius))
elif layer is not None:
if e.get_dxf_attrib('layer')==layer:
center = e.get_dxf_attrib('center')
radius = e.get_dxf_attrib('radius')
circles.append((center,radius))
else:
center = e.get_dxf_attrib('center')
radius = e.get_dxf_attrib('radius')
circles.append((center,radius))
return circles
[docs]def read_text(filename,color=None,layer=None):
'''
Reads a dxf file searching for text objects,
:param filename: the file path of the source dxf
:type filename: string
:param color: optional. if included, this function filters for objects of only this color
:param layer: optional. if included, this function filters for objects of only this layer
:rtype: List of tuples consisting ((x,y),text,height, and rotation) representing each text element.
'''
dwg = ezdxf.readfile(filename)
modelspace = dwg.modelspace()
elements = []
for item in modelspace:
if item.dxftype() == 'TEXT':
if color is not None:
if e.get_dxf_attrib('color')==color:
h = item.get_dxf_attrib('height')
r = item.get_dxf_attrib('rotation')
x,y,z = item.get_pos()[1]
text = item.get_dxf_attrib('text')
elements.append(((x,y),text,h,r))
elif layer is not None:
if e.get_dxf_attrib('layer')==layer:
h = item.get_dxf_attrib('height')
r = item.get_dxf_attrib('rotation')
x,y,z = item.get_pos()[1]
text = item.get_dxf_attrib('text')
elements.append(((x,y),text,h,r))
else:
h = item.get_dxf_attrib('height')
r = item.get_dxf_attrib('rotation')
x,y,z = item.get_pos()[1]
text = item.get_dxf_attrib('text')
elements.append(((x,y),text,h,r))
return elements
[docs]def calc_circle(p1,p2,bulge,arc_approx=0):
'''
Approximates an arc betweem two points using a "bulge value".
:param p1: the starting point.
:type p1: tuple of floats
:param p2: the ending point.
:type p2: tuple of floats
:param bulge: the bulge value. Positive bulge is right of the segment, negative is left.
:type bulge: int
:param arc_approx: number of interior points to approximate an arc with
:type arc_approx: int
:rtype: List of two-coordinate tuples.
'''
import math
from foldable_robotics.layer import Layer
v = p2 - p1
l = ((v*v)**.5).sum()
n =v/l
R = numpy.array([[0,-1],[1,0]])
n_p = R.dot(n)
p3 = p1+v/2+n_p*-bulge*l/2
x1_0 = p1[0]
x1_1 = p1[1]
x2_0 = p2[0]
x2_1 = p2[1]
x3_0 = p3[0]
x3_1 = p3[1]
p = numpy.array([ x1_0/2 + x3_0/2 + (x1_1 - x3_1)*((x1_0 - x2_0)*(x2_0 - x3_0) + (x1_1 - x2_1)*(x2_1 - x3_1))/(2*((x1_0 - x3_0)*(x2_1 - x3_1) - (x1_1 - x3_1)*(x2_0 - x3_0))),x1_1/2 + x3_1/2 + (-x1_0 + x3_0)*((x1_0 - x2_0)*(x2_0 - x3_0) + (x1_1 - x2_1)*(x2_1 - x3_1))/(2*((x1_0 - x3_0)*(x2_1 - x3_1) - (x1_1 - x3_1)*(x2_0 - x3_0)))])
v = p-p1
r = (v.dot(v))**.5
v1=(p1-p)
v2=(p2-p)
t1 = math.atan2(v1[1],v1[0])
t2 = math.atan2(v2[1],v2[0])
if bulge<0:
if t2>t1:
t2 = t2 - 2* math.pi
t = numpy.r_[t1:t2:(arc_approx+2)*1j]
points = r*numpy.c_[numpy.cos(t),numpy.sin(t)] +p
return [p1]+points[1:-1].tolist()
[docs]def list_attrib(filename,attrib):
'''
list the attributes of all the items in the dxf. use a string like 'color' or 'layer'
:param filename: path to the dxf.
:type filename: string
:param attrib: attribute you wish to search.
:type attrib: string
'''
dwg = ezdxf.readfile(filename)
modelspace = dwg.modelspace()
attrib_list =[]
for item in modelspace:
try:
attrib_list.append(item.get_dxf_attrib(attrib))
except AttributeError:
attrib_list.append(None)
return attrib_list
[docs]def get_types(filename,model_type):
'''
return all of the dxf items of type "type"
:param filename: path to the dxf.
:type filename: string
:param model_type: model type you are looking for. ex: 'LWPOLYLINE'
:type model_type: string
'''
dwg = ezdxf.readfile(filename)
modelspace = dwg.modelspace()
items = list(modelspace.query(model_type))
return items
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 29 14:39:05 2018
@author: daukes
"""
mapping = []
mapping.append((0,(0x000000)))
mapping.append((1,(0xFF0000)))
mapping.append((2,(0xFFFF00)))
mapping.append((3,(0x00FF00)))
mapping.append((4,(0x00FFFF)))
mapping.append((5,(0x0000FF)))
mapping.append((6,(0xFF00FF)))
mapping.append((7,(0xFFFFFF)))
mapping.append((8,(0x414141)))
mapping.append((9,(0x808080)))
mapping.append((10,(0xFF0000)))
mapping.append((11,(0xFFAAAA)))
mapping.append((12,(0xBD0000)))
mapping.append((13,(0xBD7E7E)))
mapping.append((14,(0x810000)))
mapping.append((15,(0x815656)))
mapping.append((16,(0x680000)))
mapping.append((17,(0x684545)))
mapping.append((18,(0x4F0000)))
mapping.append((19,(0x4F3535)))
mapping.append((20,(0xFF3F00)))
mapping.append((21,(0xFFBFAA)))
mapping.append((22,(0xBD2E00)))
mapping.append((23,(0xBD8D7E)))
mapping.append((24,(0x811F00)))
mapping.append((25,(0x816056)))
mapping.append((26,(0x681900)))
mapping.append((27,(0x684E45)))
mapping.append((28,(0x4F1300)))
mapping.append((29,(0x4F3B35)))
mapping.append((30,(0xFF7F00)))
mapping.append((31,(0xFFD4AA)))
mapping.append((32,(0xBD5E00)))
mapping.append((33,(0xBD9D7E)))
mapping.append((34,(0x814000)))
mapping.append((35,(0x816B56)))
mapping.append((36,(0x683400)))
mapping.append((37,(0x685645)))
mapping.append((38,(0x4F2700)))
mapping.append((39,(0x4F4235)))
mapping.append((40,(0xFFBF00)))
mapping.append((41,(0xFFEAAA)))
mapping.append((42,(0xBD8D00)))
mapping.append((43,(0xBDAD7E)))
mapping.append((44,(0x816000)))
mapping.append((45,(0x817656)))
mapping.append((46,(0x684E00)))
mapping.append((47,(0x685F45)))
mapping.append((48,(0x4F3B00)))
mapping.append((49,(0x4F4935)))
mapping.append((50,(0xFFFF00)))
mapping.append((51,(0xFFFFAA)))
mapping.append((52,(0xBDBD00)))
mapping.append((53,(0xBDBD7E)))
mapping.append((54,(0x818100)))
mapping.append((55,(0x818156)))
mapping.append((56,(0x686800)))
mapping.append((57,(0x686845)))
mapping.append((58,(0x4F4F00)))
mapping.append((59,(0x4F4F35)))
mapping.append((60,(0xBFFF00)))
mapping.append((61,(0xEAFFAA)))
mapping.append((62,(0x8DBD00)))
mapping.append((63,(0xADBD7E)))
mapping.append((64,(0x608100)))
mapping.append((65,(0x768156)))
mapping.append((66,(0x4E6800)))
mapping.append((67,(0x5F6845)))
mapping.append((68,(0x3B4F00)))
mapping.append((69,(0x494F35)))
mapping.append((70,(0x7FFF00)))
mapping.append((71,(0xD4FFAA)))
mapping.append((72,(0x5EBD00)))
mapping.append((73,(0x9DBD7E)))
mapping.append((74,(0x408100)))
mapping.append((75,(0x6B8156)))
mapping.append((76,(0x346800)))
mapping.append((77,(0x566845)))
mapping.append((78,(0x274F00)))
mapping.append((79,(0x424F35)))
mapping.append((80,(0x3FFF00)))
mapping.append((81,(0xBFFFAA)))
mapping.append((82,(0x2EBD00)))
mapping.append((83,(0x8DBD7E)))
mapping.append((84,(0x1F8100)))
mapping.append((85,(0x608156)))
mapping.append((86,(0x196800)))
mapping.append((87,(0x4E6845)))
mapping.append((88,(0x134F00)))
mapping.append((89,(0x3B4F35)))
mapping.append((90,(0x00FF00)))
mapping.append((91,(0xAAFFAA)))
mapping.append((92,(0x00BD00)))
mapping.append((93,(0x7EBD7E)))
mapping.append((94,(0x008100)))
mapping.append((95,(0x568156)))
mapping.append((96,(0x006800)))
mapping.append((97,(0x456845)))
mapping.append((98,(0x004F00)))
mapping.append((99,(0x354F35)))
mapping.append((100,(0x00FF3F)))
mapping.append((101,(0xAAFFBF)))
mapping.append((102,(0x00BD2E)))
mapping.append((103,(0x7EBD8D)))
mapping.append((104,(0x00811F)))
mapping.append((105,(0x568160)))
mapping.append((106,(0x006819)))
mapping.append((107,(0x45684E)))
mapping.append((108,(0x004F13)))
mapping.append((109,(0x354F3B)))
mapping.append((110,(0x00FF7F)))
mapping.append((111,(0xAAFFD4)))
mapping.append((112,(0x00BD5E)))
mapping.append((113,(0x7EBD9D)))
mapping.append((114,(0x008140)))
mapping.append((115,(0x56816B)))
mapping.append((116,(0x006834)))
mapping.append((117,(0x456856)))
mapping.append((118,(0x004F27)))
mapping.append((119,(0x354F42)))
mapping.append((120,(0x00FFBF)))
mapping.append((121,(0xAAFFEA)))
mapping.append((122,(0x00BD8D)))
mapping.append((123,(0x7EBDAD)))
mapping.append((124,(0x008160)))
mapping.append((125,(0x568176)))
mapping.append((126,(0x00684E)))
mapping.append((127,(0x45685F)))
mapping.append((128,(0x004F3B)))
mapping.append((129,(0x354F49)))
mapping.append((130,(0x00FFFF)))
mapping.append((131,(0xAAFFFF)))
mapping.append((132,(0x00BDBD)))
mapping.append((133,(0x7EBDBD)))
mapping.append((134,(0x008181)))
mapping.append((135,(0x568181)))
mapping.append((136,(0x006868)))
mapping.append((137,(0x456868)))
mapping.append((138,(0x004F4F)))
mapping.append((139,(0x354F4F)))
mapping.append((140,(0x00BFFF)))
mapping.append((141,(0xAAEAFF)))
mapping.append((142,(0x008DBD)))
mapping.append((143,(0x7EADBD)))
mapping.append((144,(0x006081)))
mapping.append((145,(0x567681)))
mapping.append((146,(0x004E68)))
mapping.append((147,(0x455F68)))
mapping.append((148,(0x003B4F)))
mapping.append((149,(0x35494F)))
mapping.append((150,(0x007FFF)))
mapping.append((151,(0xAAD4FF)))
mapping.append((152,(0x005EBD)))
mapping.append((153,(0x7E9DBD)))
mapping.append((154,(0x004081)))
mapping.append((155,(0x566B81)))
mapping.append((156,(0x003468)))
mapping.append((157,(0x455668)))
mapping.append((158,(0x00274F)))
mapping.append((159,(0x35424F)))
mapping.append((160,(0x003FFF)))
mapping.append((161,(0xAABFFF)))
mapping.append((162,(0x002EBD)))
mapping.append((163,(0x7E8DBD)))
mapping.append((164,(0x001F81)))
mapping.append((165,(0x566081)))
mapping.append((166,(0x001968)))
mapping.append((167,(0x454E68)))
mapping.append((168,(0x00134F)))
mapping.append((169,(0x353B4F)))
mapping.append((170,(0x0000FF)))
mapping.append((171,(0xAAAAFF)))
mapping.append((172,(0x0000BD)))
mapping.append((173,(0x7E7EBD)))
mapping.append((174,(0x000081)))
mapping.append((175,(0x565681)))
mapping.append((176,(0x000068)))
mapping.append((177,(0x454568)))
mapping.append((178,(0x00004F)))
mapping.append((179,(0x35354F)))
mapping.append((180,(0x3F00FF)))
mapping.append((181,(0xBFAAFF)))
mapping.append((182,(0x2E00BD)))
mapping.append((183,(0x8D7EBD)))
mapping.append((184,(0x1F0081)))
mapping.append((185,(0x605681)))
mapping.append((186,(0x190068)))
mapping.append((187,(0x4E4568)))
mapping.append((188,(0x13004F)))
mapping.append((189,(0x3B354F)))
mapping.append((190,(0x7F00FF)))
mapping.append((191,(0xD4AAFF)))
mapping.append((192,(0x5E00BD)))
mapping.append((193,(0x9D7EBD)))
mapping.append((194,(0x400081)))
mapping.append((195,(0x6B5681)))
mapping.append((196,(0x340068)))
mapping.append((197,(0x564568)))
mapping.append((198,(0x27004F)))
mapping.append((199,(0x42354F)))
mapping.append((200,(0xBF00FF)))
mapping.append((201,(0xEAAAFF)))
mapping.append((202,(0x8D00BD)))
mapping.append((203,(0xAD7EBD)))
mapping.append((204,(0x600081)))
mapping.append((205,(0x765681)))
mapping.append((206,(0x4E0068)))
mapping.append((207,(0x5F4568)))
mapping.append((208,(0x3B004F)))
mapping.append((209,(0x49354F)))
mapping.append((210,(0xFF00FF)))
mapping.append((211,(0xFFAAFF)))
mapping.append((212,(0xBD00BD)))
mapping.append((213,(0xBD7EBD)))
mapping.append((214,(0x810081)))
mapping.append((215,(0x815681)))
mapping.append((216,(0x680068)))
mapping.append((217,(0x684568)))
mapping.append((218,(0x4F004F)))
mapping.append((219,(0x4F354F)))
mapping.append((220,(0xFF00BF)))
mapping.append((221,(0xFFAAEA)))
mapping.append((222,(0xBD008D)))
mapping.append((223,(0xBD7EAD)))
mapping.append((224,(0x810060)))
mapping.append((225,(0x815676)))
mapping.append((226,(0x68004E)))
mapping.append((227,(0x68455F)))
mapping.append((228,(0x4F003B)))
mapping.append((229,(0x4F3549)))
mapping.append((230,(0xFF007F)))
mapping.append((231,(0xFFAAD4)))
mapping.append((232,(0xBD005E)))
mapping.append((233,(0xBD7E9D)))
mapping.append((234,(0x810040)))
mapping.append((235,(0x81566B)))
mapping.append((236,(0x680034)))
mapping.append((237,(0x684556)))
mapping.append((238,(0x4F0027)))
mapping.append((239,(0x4F3542)))
mapping.append((240,(0xFF003F)))
mapping.append((241,(0xFFAABF)))
mapping.append((242,(0xBD002E)))
mapping.append((243,(0xBD7E8D)))
mapping.append((244,(0x81001F)))
mapping.append((245,(0x815660)))
mapping.append((246,(0x680019)))
mapping.append((247,(0x68454E)))
mapping.append((248,(0x4F0013)))
mapping.append((249,(0x4F353B)))
mapping.append((250,(0x333333)))
mapping.append((251,(0x505050)))
mapping.append((252,(0x696969)))
mapping.append((253,(0x828282)))
mapping.append((254,(0xBEBEBE)))
mapping.append((255,(0xFFFFFF)))
from_index = dict([(ii,rgb) for ii,rgb in mapping])
to_index = dict([(rgb,ii) for ii,rgb in mapping])
if __name__=='__main__':
#Here goes the file name of the dxf.
filename ='C:/Users/daukes/code/foldable_robotics/python/foldable_robotics_tests/test2.DXF'
dwg = ezdxf.readfile(filename)
modelspace = dwg.modelspace()
hinge_lines = read_lines(filename)
exteriors = read_lwpolylines(filename,arc_approx=10)
#turn lists into arrays
hinge_lines = numpy.array(hinge_lines)
for item in hinge_lines:
plt.plot(item[:,0],item[:,1],'r--')
for item in exteriors:
item = numpy.array(item)
plt.plot(item[:,0],item[:,1],'k-', linewidth = 3)
plt.axis('equal')
# print(list_attrib(filename,'closed'))
items = get_types(filename,'LWPOLYLINE')
# c = approx_lwpoly(exteriors[0])
# for item in c:
# item.plot()