# ##### BEGIN GPL LICENSE BLOCK ##### # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # ##### END GPL LICENSE BLOCK ##### """ Release note by migius (DXF support maintainer) 2011.01.02: Script supports only a small part of DXF specification: - imports LINE, ARC, CIRCLE, ELLIPSE, SOLID, TRACE, POLYLINE, LWPOLYLINE - imports TEXT, MTEXT - supports 3d-rotation of entities (210 group) - supports THICKNESS for SOLID, TRACE, LINE, ARC, CIRCLE, ELLIPSE - ignores WIDTH, THICKNESS, BULGE in POLYLINE/LWPOLYLINE - ignores face-data in POLYFACE / POLYMESH - ignores TEXT 2d-rotation - ignores hierarchies (BLOCK, INSERT, GROUP) - ignores LAYER - ignores COLOR, LINEWIDTH, LINESTYLE This script is a temporary solution. Probably no more improvements will be done to this script. The full-feature importer script from 2.49 will be back in 2.6 release. Installation: Place this file to Blender addons directory (on Windows it is %Blender_directory%\2.53\scripts\addons\) You must activate the script in the "Add-Ons" tab (user preferences). Access it from File > Import menu. History: ver 0.1.3 - 2011.01.02 by migius - added draw curves as sequence for "Draw_as_Curve" - added toggle "Draw as one" as user preset in UI - added draw POINT as mesh-vertex - added draw_THICKNESS for LINE, ARC, CIRCLE, ELLIPSE, LWPOLYLINE and POLYLINE - added draw_THICKNESS for SOLID, TRACE ver 0.1.2 - 2010.12.27 by migius - added draw() for TRACE - fixed wrong vertex order in SOLID - added CIRCLE resolution as user preset in UI - added closing segment for circular LWPOLYLINE and POLYLINE - fixed registering for 2.55beta ver 0.1.1 - 2010.09.07 by migius - fixed dxf-file names recognition limited to ".dxf" - fixed registering for 2.53beta ver 0.1 - 2010.06.10 by Thomas Larsson """ bl_addon_info = { 'name': 'Import Autocad DXF (.dxf)', 'author': 'Thomas Larsson', 'version': (0,1,3), 'blender': (2, 5, 6), 'api': 32738, 'location': 'File > Import', 'description': 'Import files in the Autocad DXF format (.dxf)', 'warning': 'supporting only a sub-set of DXF specification', 'wiki_url': 'http://wiki.blender.org/index.php/Extensions:2.5/Py/Scripts/Import-Export/DXF_Importer', 'tracker_url': 'https://projects.blender.org/tracker/index.php?func=detail&aid=23480&group_id=153&atid=469', 'category': 'Import-Export'} __version__ = '.'.join([str(s) for s in bl_addon_info['version']]) import os import codecs import math from math import sin, cos, radians import bpy import mathutils from mathutils import Vector, Matrix # # Global flags # T_Merge = 0x01 T_NewScene = 0x02 T_Curves = 0x04 T_DrawOne = 0x08 T_Debug = 0x10 T_Verbose = 0x20 T_ThicON = 0x40 toggle = T_Merge | T_NewScene | T_DrawOne | T_ThicON theCircleRes = 32 theMergeLimit = 1e-5 # # class CSection: # class CSection: type = None def __init__(self): self.data = [] def display(self): print("Section", self.type) for datum in self.data: datum.display() # # class CTable: # class CTable: def __init__(self): self.type = None self.name = None self.handle = None self.owner = None self.subclass = None self.nEntries = 0 def display(self): print("Table %s %s %s %s %s %d" % (self.type, self.name, self.handle, self.owner, self.subclass, self.nEntries)) # # class CEntity: # class CEntity: def __init__(self, typ, drawtype): self.type = typ self.drawtype = drawtype self.handle = None self.owner = None self.subclass = None self.layer = 0 self.color = 0 self.invisible = 0 self.linetype_name = '' self.linetype_scale = 1.0 self.paperspace = 0 #self.normal = Vector((0,0,1)) def display(self): print("Entity %s %s %s %s %s %s %x" % (self.type, self.handle, self.owner, self.subclass, self.layer, self.color, self.invisible)) def build(self, vn=0): global toggle if toggle & T_Debug: raise NameError("Warning: can not build - unsupported entity type: %s" % self.type) return(([], [], [], vn)) def draw(self): global toggle if toggle & T_Debug: raise NameError("Warning: can not draw - unsupported entity type: %s" % self.type) return DxfCommonAttributes = { 5 : 'handle', 6 : 'linetype_name', 8 : 'layer', 48 : 'linetype_scale', 60 : 'invisible', 62 : 'color', 67 : 'paperspace', 100 : 'subclass', 330 : 'owner', 360 : 'owner', } # # class C3dFace(CEntity): # 10 : 'point0.x', 20 : 'point0.y', 30 : 'point0.z', # 11 : 'point1.x', 21 : 'point1.y', 31 : 'point1.z', # 12 : 'point2.x', 22 : 'point2.y', 32 : 'point2.z', # 13 : 'point3.x', 23 : 'point3.y', 33 : 'point3.z', # 70 : 'flags', # class C3dFace(CEntity): def __init__(self): CEntity.__init__(self, '3DFACE', 'Mesh') self.point0 = Vector() self.point1 = Vector() self.point2 = Vector() self.point3 = Vector() def display(self): CEntity.display(self) print(self.point0) print(self.point1) print(self.point2) print(self.point3) def build(self, vn=0): verts = [self.point0, self.point1, self.point2] if self.point3 == Vector((0,0,0)) or self.point2 == self.point3: faces = [(vn+0, vn+1, vn+2)] vn += 3 else: verts.append( self.point3 ) faces = [(vn+0, vn+1, vn+2, vn+3)] vn += 4 return((verts, [], faces, vn)) # # class C3dSolid(CEntity): # 1 : 'data', 3 : 'more', 70 : 'version', # class C3dSolid(CEntity): def __init__(self): CEntity.__init__(self, '3DSOLID', 'Mesh') self.data = None self.more = None self.version = 0 # # class CAcadProxyEntity(CEntity): # 70 : 'format', # 90 : 'id', 91 : 'class', 92 : 'graphics_size', 93 : 'entity_size', 95: 'format', # 310 : 'data', 330 : 'id1', 340 : 'id2', 350 : 'id3', 360 : 'id4', # class CAcadProxyEntity(CEntity): def __init__(self): CEntity.__init__(self, 'ACAD_PROXY_ENTITY', None) # # class CArc(CEntity): # 10 : 'center.x', 20 : 'center.y', 30 : 'center.z', # 40 : 'radius', # 50 : 'start_angle', 51 : 'end_angle' # class CArc(CEntity): def __init__(self): CEntity.__init__(self, 'ARC', 'Mesh') self.center = Vector() self.radius = 0.0 self.start_angle = 0.0 self.end_angle = 0.0 self.thickness = 0.0 self.normal = Vector((0,0,1)) def display(self): CEntity.display(self) print(self.center) print("%.4f %.4f %.4f " % (self.radius, self.start_angle, self.end_angle)) def build(self, vn=0): start, end = self.start_angle, self.end_angle if end > 360: end = end % 360.0 if end < start: end +=360.0 angle = end - start deg2rad = math.pi/180.0 start *= deg2rad end *= deg2rad dphi = end - start phi0 = start w = dphi/theCircleRes r = self.radius center = self.center v0 = vn points = [] edges, faces = [], [] for n in range(theCircleRes): s = math.sin(n*w + phi0) c = math.cos(n*w + phi0) v = center + Vector((r*c, r*s, 0.0)) points.append(v) pn = len(points) thic = self.thickness t_vector = Vector((0, 0, thic)) if thic != 0 and (toggle & T_ThicON): thic_points = [v + t_vector for v in points] if thic < 0.0: thic_points.extend(points) points = thic_points else: points.extend(thic_points) faces = [(v0+nr+0,v0+nr+1,v0+pn+nr+1,v0+pn+nr+0) for nr in range(pn)] faces.pop() self.drawtype = 'Mesh' vn += 2*pn else: edges = [(v0+nr+0,v0+nr+1) for nr in range(pn)] edges.pop() vn += pn if self.normal!=Vector((0,0,1)): ma = getOCS(self.normal) if ma: #ma.invert() points = [v * ma for v in points] #print ('arc vn=', vn) #print ('faces=', len(faces)) return ((points, edges, faces, vn)) # # class CArcAlignedText(CEntity): # 1 : 'text', 2 : 'font', 3 : 'bigfont', 7 : 'style', # 10 : 'center.x', 20 : 'center.y', 30 : 'center.z', # 40 : 'radius', 41 : 'width', 42 : 'height', 43 : 'spacing', # 44 : 'offset', 45 : 'right_offset', 46 : 'left_offset', # 50 : 'start_angle', 51 : 'end_angle', # 70 : 'order', 71 : 'direction', 72 : 'alignment', 73 : 'side', # 74 : 'bold', 75 : 'italic', 76 : 'underline', # 77 : 'character_set', 78 : 'pitch', 79 'fonttype', # 90 : 'color', # 280 : 'wizard', 330 : 'id' # class CArcAlignedText(CEntity): def __init__(self): CEntity.__init__(self, 'ARCALIGNEDTEXT', 'Mesh') self.text = "" self.style = "" self.center = Vector() self.radius = 0.0 self.width = 1.0 self.height = 1.0 self.spacing = 1.0 self.offset = 0.0 self.right_offset = 0.0 self.left_offset = 0.0 self.start_angle = 0.0 self.end_angle = 0.0 self.order = 0 self.directions = 0 self.alignment = 0 self.side = 0 self.bold = 0 self.italic = 0 self.underline = 0 self.character_set = 0 self.pitch = 0 self.fonttype = 0 self.color = 0 self.wizard = None self.id = None self.normal = Vector((0,0,1)) # # class CAttdef(CEntity): # 1 : 'text', 2 : 'tag', 3 : 'prompt', 7 : 'style', # 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', # 11 : 'alignment_point.x', 21 : 'alignment_point.y', 31 : 'alignment_point.z', # 40 : 'height', 41 : 'x_scale', # 50 : 'rotation_angle', 51 : 'oblique_angle', # 70 : 'flags', 71 : 'text_generation_flags', # 72 : 'horizontal_justification', 74 : 'vertical_justification', # class CAttdef(CEntity): def __init__(self): CEntity.__init__(self, 'ATTDEF', None) self.value = "" self.tag = "" self.prompt = "" self.style = "" self.insertion_point = Vector() self.alignment_point = Vector() self.height = 1.0 self.x_scale = 1.0 self.rotation_angle = 0.0 self.oblique_angle = 0.0 self.flags = 0 self.text_generation_flags = 0 self.horizontal_justification = 0.0 self.vertical_justification = 0.0 self.normal = Vector((0,0,1)) def draw(self): drawText(self.text, self.insertion_point, self.height, self.x_scale, self.rotation_angle, self.oblique_angle, self.normal) return # # class CAttrib(CEntity): # 1 : 'text', 2 : 'tag', 3 : 'prompt', 7 : 'style', # 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', # 11 : 'alignment_point.x', 21 : 'alignment_point.y', 31 : 'alignment_point.z', # 40 : 'height', 41 : 'x_scale', # 50 : 'rotation_angle', 51 : 'oblique_angle', # 70 : 'flags', 73 : 'length', # 71 : 'text_generation_flags', 72 : 'horizontal_justification', 74 : 'vertical_justification', # class CAttrib(CEntity): def __init__(self): CEntity.__init__(self, 'ATTRIB', None) self.text = "" self.tag = "" self.prompt = "" self.style = "" self.insertion_point = Vector() self.alignment_point = Vector() self.height = 1.0 self.x_scale = 1.0 self.rotation_angle = 0.0 self.oblique_angle = 0.0 self.flags = 0 self.length = 1.0 self.text_generation_flags = 0 self.horizontal_justification = 0.0 self.vertical_justification = 0.0 self.normal = Vector((0,0,1)) def draw(self): drawText(self.text, self.insertion_point, self.height, self.x_scale, self.rotation_angle, self.oblique_angle, self.normal) return # # class CBlock(CEntity): # 1 : 'xref', 2 : 'name', 3 : 'also_name', # 10 : 'base_point.x', 20 : 'base_point.y', 30 : 'base_point.z', # 40 : 'size', 41 : 'x_scale', # 50 : 'rotation_angle', 51 : 'oblique_angle', # 70 : 'flags', # class CBlock(CEntity): def __init__(self): CEntity.__init__(self, 'BLOCK', None) self.xref = "" self.name = "" self.also_name = "" self.base_point = Vector() self.size = 1.0 self.x_scale = 1.0 self.rotation_angle = 0.0 self.oblique_angle = 0.0 self.flags = 0 self.normal = Vector((0,0,1)) def display(self): CEntity.display(self) print("%s %s %s " % (self.xref, self.name, self.also_name)) print(self.base_point) def draw(self): # Todo return # # class CCircle(CEntity): # 10 : 'center.x', 20 : 'center.y', 30 : 'center.z', # 40 : 'radius' # class CCircle(CEntity): def __init__(self): CEntity.__init__(self, 'CIRCLE', 'Mesh') self.center = Vector() self.radius = 0.0 self.thickness = 0.0 self.normal = Vector((0,0,1)) def display(self): CEntity.display(self) print(self.center) print("%.4f" % self.radius) def build(self, vn=0): w = 2*math.pi/theCircleRes r = self.radius center = self.center points = [] edges, faces = [], [] v0 = vn for n in range(theCircleRes): s = math.sin(n*w) c = math.cos(n*w) v = center + Vector((r*c, r*s, 0)) points.append(v) pn = len(points) thic = self.thickness t_vector = Vector((0, 0, thic)) if thic != 0 and (toggle & T_ThicON): thic_points = [v + t_vector for v in points] if thic < 0.0: thic_points.extend(points) points = thic_points else: points.extend(thic_points) faces = [(v0+nr,v0+nr+1,pn+v0+nr+1,pn+v0+nr) for nr in range(pn)] nr = pn -1 faces[-1] = (v0+nr,v0,pn+v0,pn+v0+nr) self.drawtype = 'Mesh' vn += 2*pn else: edges = [(v0+nr,v0+nr+1) for nr in range(pn)] nr = pn -1 edges[-1] = (v0+nr,v0) vn += pn if self.normal!=Vector((0,0,1)): ma = getOCS(self.normal) if ma: #ma.invert() points = [v * ma for v in points] #print ('cir vn=', vn) #print ('faces=',len(faces)) return( (points, edges, faces, vn) ) # # class CDimension(CEntity): # 1 : 'text', 2 : 'name', 3 : 'style', # 10 : 'def_point.x', 20 : 'def_point.y', 30 : 'def_point.z', # 11 : 'mid_point.x', 21 : 'mid_point.y', 31 : 'mid_point.z', # 12 : 'vector.x', 22 : 'vector.y', 32 : 'vector.z', # 13 : 'def_point2.x', 23 : 'def_point2.y', 33 : 'def_point2.z', # 14 : 'vector2.x', 24 : 'vector2.y', 34 : 'vector2.z', # 15 : 'vector3.x', 25 : 'vector3.y', 35 : 'vector3.z', # 16 : 'vector4.x', 26 : 'vector4.y', 36 : 'vector4.z', # 70 : 'dimtype', # class CDimension(CEntity): def __init__(self): CEntity.__init__(self, 'DIMENSION', None) self.text = "" self.name = "" self.style = "" self.def_point = Vector() self.mid_point = Vector() self.vector = Vector() self.def_point2 = Vector() self.vector2 = Vector() self.vector3 = Vector() self.vector4 = Vector() self.dimtype = 0 self.normal = Vector((0,0,1)) def draw(self): return # # class CEllipse(CEntity): # 10 : 'center.x', 20 : 'center.y', 30 : 'center.z', # 11 : 'end_point.x', 21 : 'end_point.y', 31 : 'end_point.z', # 40 : 'ratio', 41 : 'start', 42 : 'end', # class CEllipse(CEntity): def __init__(self): CEntity.__init__(self, 'ELLIPSE', 'Mesh') self.center = Vector() self.end_point = Vector() self.ratio = 1.0 self.start = 0.0 self.end = 2*math.pi self.thickness = 0.0 self.normal = Vector((0,0,1)) def display(self): CEntity.display(self) print(self.center) print("%.4f" % self.ratio) def build(self, vn=0): dphi = (self.end - self.start) phi0 = self.start w = dphi/theCircleRes r = self.end_point.length f = self.ratio a = self.end_point.x/r b = self.end_point.y/r center = self.center v0 = vn points = [] edges, faces = [], [] for n in range(theCircleRes): x = r*math.sin(n*w + phi0) y = f*r*math.cos(n*w + phi0) v = (center.x - a*x + b*y, center.y - a*y - b*x, center.z) points.append(v) pn = len(points) thic = self.thickness t_vector = Vector((0, 0, thic)) if thic != 0 and (toggle & T_ThicON): thic_points = [v + t_vector for v in points] if thic < 0.0: thic_points.extend(points) points = thic_points else: points.extend(thic_points) faces = [(v0+nr,v0+nr+1,pn+v0+nr+1,pn+v0+nr) for nr in range(pn)] nr = pn -1 faces[-1] = (v0+nr,v0,pn+v0,pn+v0+nr) #self.drawtype = 'Mesh' vn += 2*pn else: edges = [(v0+nr,v0+nr+1) for nr in range(pn)] nr = pn -1 edges[-1] = (v0+nr,v0) vn += pn if thic != 0 and (toggle & T_ThicON): pass if self.normal!=Vector((0,0,1)): ma = getOCS(self.normal) if ma: #ma.invert() points = [v * ma for v in points] return ((points, edges, faces, vn)) # # class CHatch(CEntity): # 2 : 'pattern', # 10 : 'point.x', 20 : 'point.y', 30 : 'point.z', # 41 : 'scale', 47 : 'pixelsize', 52 : 'angle', # 70 : 'fill', 71 : 'associativity', 75: 'style', 77 : 'double', # 78 : 'numlines', 91 : 'numpaths', 98 : 'numseeds', # class CHatch(CEntity): def __init__(self): CEntity.__init__(self, 'HATCH', None) self.pattern = 0 self.point = Vector() self.scale = 1.0 self.pixelsize = 1.0 self.angle = 0.0 self.fill = 0 self.associativity = 0 self.style = 0 self.double = 0 self.numlines = 0 self.numpaths = 0 self.numseeds = 0 self.normal = Vector((0,0,1)) # class CImage(CEntity): # 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', # 11 : 'u_vector.x', 21 : 'u_vector.y', 31 : 'u_vector.z', # 12 : 'v_vector.x', 22 : 'v_vector.y', 32 : 'v_vector.z', # 13 : 'size.x', 23 : 'size.y', 33 : 'size.z', # 14 : 'clip.x', 24 : 'clip.y', 34 : 'clip.z', # 70 : 'display', 71 : 'cliptype', # 90 : 'version', # 280 : 'clipstate', 281 : 'brightness', 282 : 'contrast', 283 : 'fade', # 340 : 'image', 360 : 'reactor' # class CImage(CEntity): def __init__(self): CEntity.__init__(self, 'IMAGE', None) self.insertion_point = Vector() self.u_vector = Vector() self.v_vector = Vector() self.size = Vector() self.clip = Vector() self.display = 0 self.cliptype = 0 self.version = 1 self.clipstate = 0 self.brightness = 0 self.constrast = 0 self.fade = 0 self.image = None self.reactor = None self.normal = Vector((0,0,1)) # # class CInsert(CEntity): # 1 : 'attributes_follow', 2 : 'name', # 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', # 41 : 'x_scale', 42 : 'y_scale', 43 : 'z_scale', # 44 : 'column_spacing', 45 : 'row_spacing', # 50 : 'rotation_angle', 66 : 'attributes_follow', # 70 : 'column_count', 71 : 'row_count', # class CInsert(CEntity): def __init__(self): CEntity.__init__(self, 'INSERT', None) self.attributes_follow = 1 self.name = "" self.insertion_point = Vector() self.x_scale = 1.0 self.y_scale = 1.0 self.z_scale = 1.0 self.column_spacing = 1.0 self.row_spacing = 1.0 self.rotation_angle = 0.0 self.column_count = 1 self.row_count = 1 self.attributes_follow = 0 self.normal = Vector((0,0,1)) def display(self): CEntity.display(self) print(self.insertion_point) def draw(self): # Todo return # # class CLeader(CEntity): # 3 : 'style', # 10 : ['new_vertex(data)'], 20 : 'vertex.y', 30 : 'vertex.z', # 40 : 'height', 41 : 'width', # 71 : 'arrowhead', 72 : 'pathtype', 73 : 'creation', # 74 : 'hookdir', 75 : 'hookline', 76 : 'numverts', 77 : 'color', # 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', # 211 : 'horizon.x', 221 : 'horizon.y', 231 : 'horizon.z', # 212 : 'offset_ins.x', 222 : 'offset_ins.y', 232 : 'offset_ins.z', # 213 : 'offset_ann.x', 223 : 'offset_ann.y', 233 : 'offset_ann.z', # class CLeader(CEntity): def __init__(self): CEntity.__init__(self, 'LEADER', 'Mesh') self.style = "" self.vertex = None self.verts = [] self.height = 1.0 self.width = 1.0 self.arrowhead = 0 self.pathtype = 0 self.creation = 0 self.hookdir = 0 self.hookline = 0 self.numverts = 0 self.color = 0 self.normal = Vector((0,0,1)) self.horizon = Vector() self.offset_ins = Vector() self.offset_ann = Vector() def new_vertex(self, data): self.vertex = Vector() self.vertex.x = data self.verts.append(self.vertex) def build(self, vn=0): edges = [] for v in self.verts: edges.append((vn, vn+1)) vn += 1 edges.pop() return (self.verts, edges, [], vn) # class CLwPolyLine(CEntity): # 10 : ['new_vertex(data)'], 20 : 'vertex.y', 30 : 'vertex.z', # 38 : 'elevation', 39 : 'thickness', # 40 : 'start_width', 41 : 'end_width', 42 : 'bulge', 43 : 'constant_width', # 70 : 'flags', 90 : 'numverts' # class CLWPolyLine(CEntity): def __init__(self): CEntity.__init__(self, 'LWPOLYLINE', None) self.vertex = None self.verts = [] self.elevation = 0 self.thickness = 0.0 self.start_width = 0.0 self.end_width = 0.0 self.bulge = 0.0 self.constant_width = 0.0 self.flags = 0 self.numverts = 0 self.normal = Vector((0,0,1)) def new_vertex(self, data): self.vertex = Vector() self.vertex.x = data self.verts.append(self.vertex) def build(self, vn=0): edges = [] v_start = vn for v in self.verts: edges.append((vn, vn+1)) vn += 1 if self.flags & PL_CLOSED: edges[-1] = (vn-1, v_start) else: edges.pop() verts = self.verts if self.normal!=Vector((0,0,1)): ma = getOCS(self.normal) if ma: #ma.invert() verts = [v * ma for v in verts] return (verts, edges, [], vn-1) # # class CLine(CEntity): # 10 : 'start_point.x', 20 : 'start_point.y', 30 : 'start_point.z', # 11 : 'end_point.x', 21 : 'end_point.y', 31 : 'end_point.z', # 39 : 'thickness', # class CLine(CEntity): def __init__(self): CEntity.__init__(self, 'LINE', 'Mesh') self.start_point = Vector() self.end_point = Vector() self.thickness = 0.0 self.normal = Vector((0,0,1)) def display(self): CEntity.display(self) print(self.start_point) print(self.end_point) def build(self, vn=0): points = [self.start_point, self.end_point] faces, edges = [], [] n = vn thic = self.thickness if thic != 0 and (toggle & T_ThicON): t_vector = thic * self.normal #print 'deb:thic_vector: ', t_vector #--------------------- points.extend([v + t_vector for v in points]) faces = [[0+n, 1+n, 3+n, 2+n]] self.drawtype = 'Mesh' else: edges = [[0+n, 1+n]] vn +=2 return((points, edges, faces, vn)) # class CMLine(CEntity): # 10 : 'start_point.x', 20 : 'start_point.y', 30 : 'start_point.z', # 11 : ['new_vertex(data)'], 21 : 'vertex.y', 31 : 'vertex.z', # 12 : ['new_seg_dir(data)'], 22 : 'seg_dir.y', 32 : 'seg_dir.z', # 13 : ['new_miter_dir(data)'], 23 : 'miter_dir.y', 33 : 'miter_dir.z', # 40 : 'scale', 41 : 'elem_param', 42 : 'fill_param', # 70 : 'justification', 71 : 'flags' # 72 : 'numverts', 73 : 'numelems', 74 : 'numparam', 75 : 'numfills', # 340 : 'id' # class CMLine(CEntity): def __init__(self): CEntity.__init__(self, 'MLINE', None) self.start_point = Vector() self.vertex = None self.seg_dir = None self.miter_dir = None self.verts = [] self.seg_dirs = [] self.miter_dirs = [] self.scale = 1.0 self.elem_param = 0 self.fill_param = 0 self.justification = 0 self.flags = 0 self.numverts = 0 self.numelems = 0 self.numparam = 0 self.numfills = 0 self.id = 0 self.normal = Vector((0,0,1)) def new_vertex(self, data): self.vertex = Vector() self.vertex.x = data self.verts.append(self.vertex) def new_seg_dir(self, data): self.seg_dir = Vector() self.seg_dir.x = data self.seg_dirs.append(self.seg_dir) def new_miter_dir(self, data): self.miter_dir = Vector() self.miter_dir.x = data self.miter_dirs.append(self.miter_dir) # # class CMText(CText): # 1 : 'text', 3: 'more_text', 7 : 'style', # 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', # 11 : 'alignment_point.x', 21 : 'alignment_point.y', 31 : 'alignment_point.z', # 40 : 'nominal_height', 41 : 'reference_width', 42: 'width', 43 : 'height', 44 : 'line_spacing', # 50 : 'rotation_angle', # 71 : 'attachment_point', 72 : 'drawing_direction', 73 : 'spacing_style', # class CMText(CEntity): def __init__(self): CEntity.__init__(self, 'MTEXT', 'Text') self.text = "" self.more_text = "" self.style = "" self.insertion_point = Vector() self.alignment_point = Vector() self.nominal_height = 1.0 self.reference_width = 1.0 self.width = 1.0 self.height = 1.0 self.rotation_angle = 0.0 self.attachment_point = 0 self.drawing_direction = 0 self.spacing_style = 0 self.normal = Vector((0,0,1)) def display(self): CEntity.display(self) print("%s %s" % (self.text, self.style)) print('MTEXTinsertion_point=',self.insertion_point) print('MTEXTalignment_point=',self.alignment_point) def draw(self): drawText(self.text, self.insertion_point, self.height, self.width, self.rotation_angle, 0.0, self.normal) return # # class CPoint(CEntity): # 10 : 'point.x', 20 : 'point.y', 30 : 'point.z', # 39 : 'thickness', 50 : 'orientation' # class CPoint(CEntity): def __init__(self): CEntity.__init__(self, 'POINT', 'Mesh') self.point = Vector() self.thickness = 0.0 self.orientation = 0.0 def display(self): CEntity.display(self) print(self.point) print("%.4f" % self.orientation) def build(self, vn=0): # draw as mesh-vertex verts = [self.point] return((verts, [], [], vn+1)) def draw(self): #todo # draw as empty-object loc = self.point #bpy.ops.object.new('DXFpoint') # # class CPolyLine(CEntity): # 1 : 'verts_follow', 2 : 'name', # 10 : 'elevation.x', 20 : 'elevation.y', 30 : 'elevation.z', # 40 : 'start_width', 41 : 'end_width', # 66 : 'verts_follow_flag', # 70 : 'flags', 71 : 'row_count', 72 : 'column_count', # 73 : 'row_density', 74 : 'column_density', 75 : 'linetype', # class CPolyLine(CEntity): def __init__(self): CEntity.__init__(self, 'POLYLINE', 'Mesh') self.verts = [] self.verts_follow = 1 self.name = "" self.elevation = Vector() self.thickness = 0.0 self.start_width = 0.0 self.end_width = 0.0 self.verts_follow_flags = 0 self.flags = 0 self.row_count = 1 self.column_count = 1 self.row_density = 1.0 self.column_density = 1.0 self.linetype = 1 self.normal = Vector((0,0,1)) def display(self): CEntity.display(self) print("VERTS") for v in self.verts: print(v.location) print("END VERTS") def build(self, vn=0): verts = [] lines = [] v_start = vn for vert in self.verts: verts.append(vert.location) lines.append((vn, vn+1)) vn += 1 if self.flags & PL_CLOSED: lines[-1] = (vn-1, v_start) else: lines.pop() if self.normal!=Vector((0,0,1)): ma = getOCS(self.normal) if ma: verts = [v * ma for v in verts] return((verts, lines, [], vn-1)) # # class CShape(CEntity): # 2 : 'name', # 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', # 39 : 'thickness', # 40 : 'size', 41 : 'x_scale', # 50 : 'rotation_angle', 51 : 'oblique_angle', # class CShape(CEntity): def __init__(self): CEntity.__init__(self, 'SHAPE', None) self.name = "" self.insertion_point = Vector() self.thickness = 0.0 self.size = 1.0 self.x_scale = 1.0 self.rotation_angle = 0.0 self.oblique_angle = 0.0 def display(self): CEntity.display(self) print("%s" % (self.name)) print(self.insertion_point) # # class CSpline(CEntity): # 10 : ['new_control_point(data)'], 20 : 'control_point.y', 30 : 'control_point.z', # 11 : ['new_fit_point(data)'], 21 : 'fit_point.y', 31 : 'fit_point.z', # 40 : ['new_knot_value(data)'], # 12 : 'start_tangent.x', 22 : 'start_tangent.y', 32 : 'start_tangent.z', # 13 : 'end_tangent.x', 23 : 'end_tangent.y', 33 : 'end_tangent.z', # 41 : 'weight', 42 : 'knot_tol', 43 : 'control_point_tol', 44 : 'fit_tol', # 70 : 'flag', 71 : 'degree', # 72 : 'num_knots', 73 : 'num_control_points', 74 : 'num_fit_points', # 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', # class CSpline(CEntity): def __init__(self): CEntity.__init__(self, 'SPLINE', 'Mesh') self.control_points = [] self.fit_points = [] self.knot_values = [] self.control_point = None self.fit_point = None self.knot_value = None self.start_tangent = Vector() self.end_tangent = Vector() self.weight = 1.0 self.knot_tol = 1e-6 self.control_point_tol = 1e-6 self.fit_tol = 1e-6 self.flag = 0 self.degree = 3 self.num_knots = 0 self.num_control_points = 0 self.num_fit_points = 0 self.thickness = 0.0 self.normal = Vector((0,0,1)) def new_control_point(self, data): self.control_point = Vector() self.control_point.x = data self.control_points.append(self.control_point) def new_fit_point(self, data): self.fit_point = Vector() self.fit_point.x = data self.fit_points.append(self.fit_point) def new_knot_value(self, data): self.knot_value = data self.knot_values.append(self.knot_value) def display(self): #not testet yet (migius) CEntity.display(self) print("CONTROL") for p in self.control_points: print(p) print("FIT") for p in self.fit_points: print(p) print("KNOT") for v in self.knot_values: print(v) def build(self, vn=0): verts = [] lines = [] for vert in self.control_points: verts.append(vert) lines.append((vn, vn+1)) vn += 1 lines.pop() return((verts, lines, [], vn)) # # class CSolid(CEntity): # 10 : 'point0.x', 20 : 'point0.y', 30 : 'point0.z', # 11 : 'point1.x', 21 : 'point1.y', 31 : 'point1.z', # 12 : 'point2.x', 22 : 'point2.y', 32 : 'point2.z', # 13 : 'point3.x', 23 : 'point3.y', 33 : 'point3.z', # 39 : 'thickness', # class CSolid(CEntity): def __init__(self): CEntity.__init__(self, 'SOLID', 'Mesh') self.point0 = Vector() self.point1 = Vector() self.point2 = Vector() self.point3 = Vector() self.normal = Vector((0,0,1)) self.thickness = 0.0 def display(self): CEntity.display(self) print(self.point0) print(self.point1) print(self.point2) print(self.point3) def build(self, vn=0): points, edges, faces = [],[],[] if self.point2 == self.point3: points = [self.point0, self.point1, self.point2] else: points = [self.point0, self.point1, self.point2, self.point3] pn = len(points) v0 = vn thic = self.thickness t_vector = Vector((0, 0, thic)) if thic != 0 and (toggle & T_ThicON): thic_points = [v + t_vector for v in points] if thic < 0.0: thic_points.extend(points) points = thic_points else: points.extend(thic_points) if pn == 4: faces = [[0,1,3,2], [4,6,7,5], [0,4,5,1], [1,5,7,3], [3,7,6,2], [2,6,4,0]] elif pn == 3: faces = [[0,1,2], [3,5,4], [0,3,4,1], [1,4,5,2], [2,5,3,0]] elif pn == 2: faces = [[0,1,3,2]] vn += 2*pn else: if pn == 4: faces = [[0,2,3,1]] elif pn == 3: faces = [[0,2,1]] elif pn == 2: edges = [[0,1]] self.drawtype = 'Mesh' vn += pn if self.normal!=Vector((0,0,1)): ma = getOCS(self.normal) if ma: points = [v * ma for v in points] return((points, edges, faces, vn)) # # class CText(CEntity): # 1 : 'text', 7 : 'style', # 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', # 11 : 'alignment_point.x', 21 : 'alignment_point.y', 31 : 'alignment_point.z', # 40 : 'height', 41 : 'x_scale', # 50 : 'rotation_angle', 51 : 'oblique_angle', # 71 : 'flags', 72 : 'horizontal_justification', 73 : 'vertical_justification', # class CText(CEntity): def __init__(self): CEntity.__init__(self, 'TEXT', 'Text') self.text = "" self.style = "" self.insertion_point = Vector() self.alignment_point = Vector() self.height = 1.0 self.x_scale = 1.0 self.rotation_angle = 0.0 self.oblique_angle = 0.0 self.flags = 0 self.horizontal_justification = 0.0 self.vertical_justification = 0.0 self.thickness = 0.0 self.normal = Vector((0,0,1)) def display(self): CEntity.display(self) print("%s %s" % (self.text, self.style)) print(self.insertion_point) print(self.alignment_point) def draw(self): drawText(self.text, self.insertion_point, self.height, self.x_scale, self.rotation_angle, self.oblique_angle, self.normal) return def drawText(text, loc, size, spacing, angle, shear, normal=Vector((0,0,1))): #print('angle_deg=',angle) bpy.ops.object.text_add( view_align=False, enter_editmode=False, location= loc, #rotation=(0, 0, angle), #need radians here ) cu = bpy.context.object.data cu.body = text cu.size = size #up 2.56 cu.space_word = spacing #up 2.56 cu.shear = shear if angle!=0.0 or normal!=Vector((0,0,1)): obj = bpy.context.object transform(normal, angle, obj) return # # class CTolerance(CEntity): # 3 : 'style', # 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', # 11 : 'direction.x', 21 : 'direction.y', 31 : 'direction.z', # class CTolerance(CEntity): def __init__(self): CEntity.__init__(self, 'TOLERANCE', None) self.stype = "" self.insertion_point = Vector() self.direction = Vector() # # class CTrace(CEntity): # 10 : 'point0.x', 20 : 'point0.y', 30 : 'point0.z', # 11 : 'point1.x', 21 : 'point1.y', 31 : 'point1.z', # 12 : 'point2.x', 22 : 'point2.y', 32 : 'point2.z', # 13 : 'point3.x', 23 : 'point3.y', 33 : 'point3.z', # 39 : 'thickness', # class CTrace(CEntity): def __init__(self): CEntity.__init__(self, 'TRACE', 'Mesh') self.point0 = Vector() self.point1 = Vector() self.point2 = Vector() self.point3 = Vector() self.normal = Vector((0,0,1)) self.thickness = 0.0 def display(self): CEntity.display(self) print(self.point0) print(self.point1) print(self.point2) print(self.point3) def build(self, vn=0): points, edges, faces = [],[],[] if self.point2 == self.point3: points = [self.point0, self.point2, self.point1] else: points = [self.point0, self.point2, self.point1, self.point3] pn = len(points) v0 = vn thic = self.thickness t_vector = Vector((0, 0, thic)) if thic != 0 and (toggle & T_ThicON): thic_points = [v + t_vector for v in points] if thic < 0.0: thic_points.extend(points) points = thic_points else: points.extend(thic_points) if pn == 4: faces = [[0,1,3,2], [4,6,7,5], [0,4,5,1], [1,5,7,3], [3,7,6,2], [2,6,4,0]] elif pn == 3: faces = [[0,1,2], [3,5,4], [0,3,4,1], [1,4,5,2], [2,5,3,0]] elif pn == 2: faces = [[0,1,3,2]] vn += 2*pn else: if pn == 4: faces = [[0,2,3,1]] elif pn == 3: faces = [[0,2,1]] elif pn == 2: edges = [[0,1]] self.drawtype = 'Mesh' if self.normal!=Vector((0,0,1)): ma = getOCS(self.normal) if ma: points = [v * ma for v in points] return ((points, edges, faces, vn)) # # class CVertex(CEntity): # 10 : 'location.x', 20 : 'location.y', 30 : 'location.z', # 40 : 'start_width', 41 : 'end_width', 42 : 'bulge', # 50 : 'tangent', # 70 : 'flags', # 71 : 'index1', 72 : 'index2', 73 : 'index3', 74 : 'index4', # class CVertex(CEntity): def __init__(self): CEntity.__init__(self, 'VERTEX', None) self.location = Vector() self.start_width = 0.0 self.end_width = 0.0 self.bulge = 0.0 self.tangent = 0.0 self.flags = 0 def display(self): return def draw(self): return # # class CViewPort(CEntity): # 10 : 'center.x', 20 : 'center.y', 30 : 'center.z', # 12 : 'view_center.x', 22 : 'view_center.y', 32 : 'view_center.z', # 13 : 'snap_base.x', 23 : 'snap_base.y', 33 : 'snap_base.z', # 14 : 'snap_spacing.x', 24 : 'snap_spacing.y', 34 : 'snap_spacing.z', # 15 : 'grid_spacing.x', 25 : 'grid_spacing.y', 35 : 'grid_spacing.z', # 16 : 'view_direction.x', 26 : 'view_direction.y', 36 : 'view_direction.z', # 40 : 'width', 41 : 'height', # 68 : 'status', 69 : 'id', # class CViewPort(CEntity): def __init__(self): CEntity.__init__(self, 'VIEWPORT', None) self.center = Vector() self.view_center = Vector() self.snap_base = Vector() self.snap_spacing = Vector() self.grid_spacing = Vector() self.view_direction = Vector() self.width = 1.0 self.height = 1.0 self.status = 0 self.id = 0 def draw(self): # Todo return # # class CWipeOut(CEntity): # 10 : 'point.x', 20 : 'point.y', 30 : 'point.z', # 11 : 'direction.x', 21 : 'direction.y', 31 : 'direction.z', # class CWipeOut(CEntity): def __init__(self): CEntity.__init__(self, 'WIPEOUT', None) self.point = Vector() self.direction = Vector() # # # WORLDX = Vector((1.0,0.0,0.0)) WORLDY = Vector((0.0,1.0,0.0)) WORLDZ = Vector((0.0,0.0,1.0)) def getOCS(az): #----------------------------------------------------------------- """An implimentation of the Arbitrary Axis Algorithm. """ #decide if we need to transform our coords #if az[0] == 0 and az[1] == 0: if abs(az.x) < 0.00001 and abs(az.y) < 0.00001: if az.z > 0.0: return False elif az.z < 0.0: return Matrix(-WORLDX, WORLDY*1, -WORLDZ) cap = 0.015625 # square polar cap value (1/64.0) if abs(az.x) < cap and abs(az.y) < cap: ax = WORLDY.cross(az) else: ax = WORLDZ.cross(az) ax = ax.normalize() ay = az.cross(ax) ay = ay.normalize() return Matrix(ax, ay, az) def transform(normal, rotation, obj): #-------------------------------------------- """Use the calculated ocs to determine the objects location/orientation in space. """ ma = Matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]) o = Vector(obj.location) ma_new = getOCS(normal) if ma_new: ma = ma_new.resize4x4() o = o * ma #.copy().invert() if rotation != 0: g = radians(-rotation) rmat = Matrix([cos(g), -sin(g), 0], [sin(g), cos(g), 0], [0, 0, 1]) ma = ma * rmat.resize4x4() obj.matrix_world = ma #must be matrix4x4 obj.location = o DxfEntityAttributes = { '3DFACE' : { 10 : 'point0.x', 20 : 'point0.y', 30 : 'point0.z', 11 : 'point1.x', 21 : 'point1.y', 31 : 'point1.z', 12 : 'point2.x', 22 : 'point2.y', 32 : 'point2.z', 13 : 'point3.x', 23 : 'point3.y', 33 : 'point3.z', 70 : 'flags', }, '3DSOLID' : { 1 : 'data', 3 : 'more', 70 : 'version', }, 'ACAD_PROXY_ENTITY' : { 70 : 'format', 90 : 'id', 91 : 'class', 92 : 'graphics_size', 93 : 'entity_size', 95: 'format', 310 : 'data', 330 : 'id1', 340 : 'id2', 350 : 'id3', 360 : 'id4', }, 'ARC' : { 10 : 'center.x', 20 : 'center.y', 30 : 'center.z', 40 : 'radius', 50 : 'start_angle', 51 : 'end_angle', 39 : 'thickness', 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', }, 'ARCALIGNEDTEXT' : { 1 : 'text', 2 : 'font', 3 : 'bigfont', 7 : 'style', 10 : 'center.x', 20 : 'center.y', 30 : 'center.z', 40 : 'radius', 41 : 'width', 42 : 'height', 43 : 'spacing', 44 : 'offset', 45 : 'right_offset', 46 : 'left_offset', 50 : 'start_angle', 51 : 'end_angle', 70 : 'order', 71 : 'direction', 72 : 'alignment', 73 : 'side', 74 : 'bold', 75 : 'italic', 76 : 'underline', 77 : 'character_set', 78 : 'pitch', 79 : 'fonttype', 90 : 'color', 280 : 'wizard', 330 : 'id' }, 'ATTDEF' : { 1 : 'text', 2 : 'tag', 3 : 'prompt', 7 : 'style', 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', 11 : 'alignment_point.x', 21 : 'alignment_point.y', 31 : 'alignment_point.z', 40 : 'height', 41 : 'x_scale', 50 : 'rotation_angle', 51 : 'oblique_angle', 70 : 'flags', 71 : 'text_generation_flags', 72 : 'horizontal_justification', 74 : 'vertical_justification', }, 'ATTRIB' : { 1 : 'text', 2 : 'tag', 3 : 'prompt', 7 : 'style', 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', 11 : 'alignment_point.x', 21 : 'alignment_point.y', 31 : 'alignment_point.z', 40 : 'height', 41 : 'x_scale', 50 : 'rotation_angle', 51 : 'oblique_angle', 70 : 'flags', 73 : 'length', 71 : 'text_generation_flags', 72 : 'horizontal_justification', 74 : 'vertical_justification', }, 'BLOCK' : { 1 : 'xref', 2 : 'name', 3 : 'also_name', 10 : 'base_point.x', 20 : 'base_point.y', 30 : 'base_point.z', 40 : 'size', 41 : 'x_scale', 50 : 'rotation_angle', 51 : 'oblique_angle', 70 : 'flags', }, 'CIRCLE' : { 10 : 'center.x', 20 : 'center.y', 30 : 'center.z', 40 : 'radius', 39 : 'thickness', 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', }, 'DIMENSION' : { 1 : 'text', 2 : 'name', 3 : 'style', 10 : 'def_point.x', 20 : 'def_point.y', 30 : 'def_point.z', 11 : 'mid_point.x', 21 : 'mid_point.y', 31 : 'mid_point.z', 12 : 'vector.x', 22 : 'vector.y', 32 : 'vector.z', 13 : 'def_point2.x', 23 : 'def_point2.y', 33 : 'def_point2.z', 14 : 'vector2.x', 24 : 'vector2.y', 34 : 'vector2.z', 15 : 'vector3.x', 25 : 'vector3.y', 35 : 'vector3.z', 16 : 'vector4.x', 26 : 'vector4.y', 36 : 'vector4.z', 70 : 'dimtype', }, 'ELLIPSE' : { 10 : 'center.x', 20 : 'center.y', 30 : 'center.z', 11 : 'end_point.x', 21 : 'end_point.y', 31 : 'end_point.z', 40 : 'ratio', 41 : 'start', 42 : 'end', 39 : 'thickness', 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', }, 'HATCH' : { 2 : 'pattern', 10 : 'point.x', 20 : 'point.y', 30 : 'point.z', 41 : 'scale', 47 : 'pixelsize', 52 : 'angle', 70 : 'fill', 71 : 'associativity', 75: 'style', 77 : 'double', 78 : 'numlines', 91 : 'numpaths', 98 : 'numseeds', 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', }, 'IMAGE' : { 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', 11 : 'u_vector.x', 21 : 'u_vector.y', 31 : 'u_vector.z', 12 : 'v_vector.x', 22 : 'v_vector.y', 32 : 'v_vector.z', 13 : 'size.x', 23 : 'size.y', 33 : 'size.z', 14 : 'clip.x', 24 : 'clip.y', 34 : 'clip.z', 70 : 'display', 71 : 'cliptype', 90 : 'version', 280 : 'clipstate', 281 : 'brightness', 282 : 'contrast', 283 : 'fade', 340 : 'image', 360 : 'reactor', }, 'INSERT' : { 1 : 'attributes_follow', 2 : 'name', 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', 41 : 'x_scale', 42 : 'y_scale', 43 : 'z_scale', 44 : 'column_spacing', 45 : 'row_spacing', 50 : 'rotation_angle', 66 : 'attributes_follow', 70 : 'column_count', 71 : 'row_count', 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', }, 'LEADER' : { 3 : 'style', 10 : ['new_vertex(data)'], 20 : 'vertex.y', 30 : 'vertex.z', 40 : 'height', 41 : 'width', 71 : 'arrowhead', 72 : 'pathtype', 73 : 'creation', 74 : 'hookdir', 75 : 'hookline', 76 : 'numverts', 77 : 'color', 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', 211 : 'horizon.x', 221 : 'horizon.y', 231 : 'horizon.z', 212 : 'offset_ins.x', 222 : 'offset_ins.y', 232 : 'offset_ins.z', 213 : 'offset_ann.x', 223 : 'offset_ann.y', 233 : 'offset_ann.z', }, 'LINE' : { 10 : 'start_point.x', 20 : 'start_point.y', 30 : 'start_point.z', 11 : 'end_point.x', 21 : 'end_point.y', 31 : 'end_point.z', 39 : 'thickness', 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', }, 'LWPOLYLINE' : { 10 : ['new_vertex(data)'], 20 : 'vertex.y', 30 : 'vertex.z', 38 : 'elevation', 39 : 'thickness', 40 : 'start_width', 41 : 'end_width', 42 : 'bulge', 43 : 'constant_width', 70 : 'flags', 90 : 'numverts', 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', }, 'MLINE' : { 10 : 'start_point.x', 20 : 'start_point.y', 30 : 'start_point.z', 11 : ['new_vertex(data)'], 21 : 'vertex.y', 31 : 'vertex.z', 12 : ['new_seg_dir(data)'], 22 : 'seg_dir.y', 32 : 'seg_dir.z', 13 : ['new_miter_dir(data)'], 23 : 'miter_dir.y', 33 : 'miter_dir.z', 39 : 'thickness', 40 : 'scale', 41 : 'elem_param', 42 : 'fill_param', 70 : 'justification', 71 : 'flags', 72 : 'numverts', 73 : 'numelems', 74 : 'numparam', 75 : 'numfills', 340 : 'id', 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', }, 'MTEXT' : { 1 : 'text', 3: 'more_text', 7 : 'style', 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', 11 : 'alignment_point.x', 21 : 'alignment_point.y', 31 : 'alignment_point.z', 40 : 'nominal_height', 41 : 'reference_width', 42: 'width', 43 : 'height', 44 : 'line_spacing', 50 : 'rotation_angle', 71 : 'attachment_point', 72 : 'drawing_direction', 73 : 'spacing_style', 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', }, 'POINT' : { 10 : 'point.x', 20 : 'point.y', 30 : 'point.z', 39 : 'thickness', 50 : 'orientation', }, 'POLYLINE' : { 1 : 'verts_follow', 2 : 'name', 10 : 'elevation.x', 20 : 'elevation.y', 30 : 'elevation.z', 39 : 'thickness', 40 : 'start_width', 41 : 'end_width', 66 : 'verts_follow_flag', 70 : 'flags', 71 : 'row_count', 72 : 'column_count', 73 : 'row_density', 74 : 'column_density', 75 : 'linetype', 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', }, 'RAY' : { 10 : 'point.x', 20 : 'point.y', 30 : 'point.z', 11 : 'direction.x', 21 : 'direction.y', 31 : 'direction.z', }, 'RTEXT' : { 1 : 'text', 7 : 'style', 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', 39 : 'thickness', 40 : 'height', 50 : 'rotation_angle', 70 : 'flags', 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', }, 'SHAPE' : { 2 : 'name', 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', 39 : 'thickness', 40 : 'size', 41 : 'x_scale', 50 : 'rotation_angle', 51 : 'oblique_angle', 39 : 'thickness', }, 'SOLID' : { 10 : 'point0.x', 20 : 'point0.y', 30 : 'point0.z', 11 : 'point1.x', 21 : 'point1.y', 31 : 'point1.z', 12 : 'point2.x', 22 : 'point2.y', 32 : 'point2.z', 13 : 'point3.x', 23 : 'point3.y', 33 : 'point3.z', 39 : 'thickness', 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', }, 'SPLINE' : { 10 : ['new_control_point(data)'], 20 : 'control_point.y', 30 : 'control_point.z', 11 : ['new_fit_point(data)'], 21 : 'fit_point.y', 31 : 'fit_point.z', 40 : ['new_knot_value(data)'], 12 : 'start_tangent.x', 22 : 'start_tangent.y', 32 : 'start_tangent.z', 13 : 'end_tangent.x', 23 : 'end_tangent.y', 33 : 'end_tangent.z', 39 : 'thickness', 41 : 'weight', 42 : 'knot_tol', 43 : 'control_point_tol', 44 : 'fit_tol', 70 : 'flag', 71 : 'degree', 72 : 'num_knots', 73 : 'num_control_points', 74 : 'num_fit_points', 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', }, 'TEXT' : { 1 : 'text', 7 : 'style', 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', 11 : 'alignment_point.x', 21 : 'alignment_point.y', 31 : 'alignment_point.z', 40 : 'height', 41 : 'x_scale', 50 : 'rotation_angle', 51 : 'oblique_angle', 71 : 'flags', 72 : 'horizontal_justification', 73 : 'vertical_justification', 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', }, 'TOLERANCE' : { 3 : 'style', 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z', 11 : 'direction.x', 21 : 'direction.y', 31 : 'direction.z', }, 'TRACE' : { 10 : 'point0.x', 20 : 'point0.y', 30 : 'point0.z', 11 : 'point1.x', 21 : 'point1.y', 31 : 'point1.z', 12 : 'point2.x', 22 : 'point2.y', 32 : 'point2.z', 13 : 'point3.x', 23 : 'point3.y', 33 : 'point3.z', 39 : 'thickness', 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z', }, 'VERTEX' : { 10 : 'location.x', 20 : 'location.y', 30 : 'location.z', 40 : 'start_width', 41 : 'end_width', 42 : 'bulge', 50 : 'tangent', 70 : 'flags', 71 : 'index1', 72 : 'index2', 73 : 'index3', 74 : 'index4', }, 'VIEWPORT' : { 10 : 'center.x', 20 : 'center.y', 30 : 'center.z', 12 : 'view_center.x', 22 : 'view_center.y', 32 : 'view_center.z', 13 : 'snap_base.x', 23 : 'snap_base.y', 33 : 'snap_base.z', 14 : 'snap_spacing.x', 24 : 'snap_spacing.y', 34 : 'snap_spacing.z', 15 : 'grid_spacing.x', 25 : 'grid_spacing.y', 35 : 'grid_spacing.z', 16 : 'view_direction.x', 26 : 'view_direction.y', 36 : 'view_direction.z', 40 : 'width', 41 : 'height', 68 : 'status', 69 : 'id', }, 'WIPEOUT' : { 10 : 'point.x', 20 : 'point.y', 30 : 'point.z', 11 : 'direction.x', 21 : 'direction.y', 31 : 'direction.z', }, } # # Flags # # Polyline flags PL_CLOSED = 0x01 PL_CURVE_FIT_VERTS = 0x02 PL_SPLINE_FIT_VERTS = 0x04 PL_3D_POLYLINE = 0x08 PL_3D_POLYGON_MESH = 0x10 PL_CLOSED_IN_N_DIR = 0x20 PL_POLYFACE_MESH = 0x40 PL_CONTINUOUS = 0x80 # Vertex flags VX_EXTRA_FLAG_CREATED = 0x01 VX_CURVE_FIT_TANGENT_DEFINED = 0x02 VX_SPLINE_VERTEX_CREATED = 0x08 VX_SPLINE_FRAME_CONTROL_POINT = 0x10 VX_3D_POLYLINE_VERTEX = 0x20 VX_3D_POLYGON_MESH_VERTEX = 0x40 VX_POLYFACE_MESH_VERTEX = 0x80 # 3DFACE flags F3D_EDGE0_INVISIBLE = 0x01 F3D_EDGE1_INVISIBLE = 0x02 F3D_EDGE2_INVISIBLE = 0x04 F3D_EDGE3_INVISIBLE = 0x08 # # readDxfFile(filePath): # def readDxfFile(fileName): global toggle, theCodec print( "Opening DXF file "+ fileName ) # fp= open(fileName, "rU") fp = codecs.open(fileName, "r", encoding=theCodec) first = True statements = [] no = 0 for line in fp: word = line.strip() no += 1 if first: if word: code = int(word) first = False else: if toggle & T_Verbose: print("%4d: %4d %s" % (no, code, word)) if code < 10: data = word elif code < 60: data = float(word) elif code < 100: data = int(word) elif code < 140: data = word elif code < 150: data = float(word) elif code < 200: data = int(word) elif code < 300: data = float(word) elif code < 370: data = word elif code < 390: data = int(word) elif code < 400: data = word elif code < 410: data = int(word) elif code < 1010: data = word elif code < 1060: data = float(word) elif code < 1080: data = int(word) statements.append((code,data)) first = True fp.close() statements.reverse() sections = {} handles = {} while statements: (code,data) = statements.pop() if code == 0: if data == 'SECTION': section = CSection() elif code == 2: section.type = data if data == 'HEADER': parseHeader(section, statements, handles) known = False elif data == 'CLASSES': parseClasses(section, statements, handles) known = False elif data == 'TABLES': parseTables(section, statements, handles) known = False elif data == 'BLOCKS': parseBlocks(section, statements, handles) known = False elif data == 'ENTITIES': parseEntities(section, statements, handles) known = False elif data == 'OBJECTS': parseObjects(section, statements, handles) sections[data] = section elif code == 999: pass else: raise NameError("Unexpected code in SECTION context: %d %s" % (code,data)) if toggle & T_Verbose: for (typ,section) in sections.items(): section.display() return sections # # 0 # SECTION # 2 # HEADER # # 9 # $ # # # # 0 # ENDSEC def parseHeader(section, statements, handles): while statements: (code,data) = statements.pop() if code == 0: if data == 'ENDSEC': return return # 0 # SECTION # 2 # CLASSES # # 0 # CLASS # 1 # # 2 # # 3 # # 90 # # 280 # # 281 # # # 0 # ENDSEC def parseClasses(section, statements, handles): while statements: (code,data) = statements.pop() if code == 0: if data == 'ENDSEC': return return # 0 # SECTION # 2 # TABLES # # 0 # TABLE # 2 # # 5 # # 100 # AcDbSymbolTable # 70 # # # 0 #
# 5 # # 100 # AcDbSymbolTableRecord # . # . # . # # 0 # ENDTAB # # 0 # ENDSEC # # APPID (application identification table) # # BLOCK_RECORD (block reference table) # # DIMSTYLE (dimension style table) # # LAYER (layer table) # # LTYPE (linetype table) # # STYLE (text style table) # # UCS (User Coordinate System table) # # VIEW (view table) # # VPORT (viewport configuration table) def parseTables(section, statements, handles): tables = [] section.data = tables while statements: (code,data) = statements.pop() if code == 0: if data == 'ENDSEC': return ''' known = False elif data == 'TABLE': table = CTable() tables.append(table) known = False elif data == 'ENDTAB': pass known = False elif data == table.type: parseTableType table = CTable() tables.append(table) table.type = word elif code == 2: table.type = word elif code == 5: table.handle = word handles[word] = table elif code == 330: table.owner = word elif code == 100: table.subclass = word elif code == 70: table.nEntries = int(word) ''' return # 0 # SECTION # 2 # BLOCKS # # 0 # BLOCK # 5 # # 100 # AcDbEntity # 8 # # 100 # AcDbBlockBegin # 2 # # 70 # # 10 # # 20 # # 30 # # 3 # # 1 # # # 0 # # . # . # . # # 0 # ENDBLK # 5 # # 100 # AcDbBlockEnd # # 0 # ENDSEC def parseBlocks(section, statements, handles): while statements: (code,data) = statements.pop() if code == 0: if data == 'ENDSEC': return return # 0 # SECTION # 2 # ENTITIES # # 0 # # 5 # # 330 # # 100 # AcDbEntity # 8 # # 100 # AcDb # . # . # . # # 0 # ENDSEC Ignorables = ['DIMENSION', 'TEXT', 'VIEWPORT'] ClassCreators = { '3DFACE': 'C3dFace()', '3DSOLID': 'C3dSolid()', 'ACAD_PROXY_ENTITY': 'CAcadProxyEntity()', 'ACAD_ZOMBIE_ENTITY': 0, 'ARC': 'CArc()', 'ARCALIGNEDTEXT': 'CArcAlignedText()', 'ATTDEF': 'CAttdef()', 'ATTRIB': 'CAttrib()', 'BODY': 0, 'CIRCLE': 'CCircle()', 'DIMENSION': 'CDimension()', 'ELLIPSE': 'CEllipse()', 'HATCH': 'CHatch()', 'IMAGE': 'CImage()', 'INSERT': 'CInsert()', 'LEADER': 'CLeader()', 'LINE': 'CLine()', 'LWPOLYLINE': 'CLWPolyLine()', 'MLINE': 'CMLine()', 'MTEXT': 'CMText()', 'OLEFRAME': 0, 'OLE2FRAME': 0, 'POINT': 'CPoint()', 'POLYLINE': 'CPolyLine()', 'RAY': 'CRay()', 'REGION': 0, 'RTEXT': 'CRText', 'SEQEND': 0, 'SHAPE': 'CShape()', 'SOLID': 'CSolid()', 'SPLINE': 'CSpline()', 'TEXT': 'CText()', 'TOLERANCE': 'CTolerance()', 'TRACE': 'CTrace()', 'VERTEX': 'CVertex()', 'VIEWPORT': 'CViewPort()', 'WIPEOUT': 'CWipeOut()', 'XLINE': 'CXLine()', } def parseEntities(section, statements, handles): entities = [] section.data = entities while statements: (code,data) = statements.pop() if toggle & T_Verbose: print("ent", code,data) if code == 0: known = True if data in Ignorables: ignore = True else: ignore = False try: creator = ClassCreators[data] except: creator = None if creator: entity = eval(creator) elif data == 'ENDSEC': return else: known = False if data == 'POLYLINE': verts = entity.verts elif data == 'VERTEX': verts.append(entity) if data == 'SEQEND': attributes = [] known = False elif creator == 0: ignore = True elif known: entities.append(entity) attributes = DxfEntityAttributes[data] else: raise NameError("Unknown data %s" % data) elif not known: pass else: expr = getAttribute(attributes, code) if expr: exec(expr) else: expr = getAttribute(DxfCommonAttributes, code) if expr: exec(expr) elif code >= 1000 or ignore: pass elif toggle & T_Debug: raise NameError("Unknown code %d for %s" % (code, entity.type)) return def getAttribute(attributes, code): try: ext = attributes[code] if type(ext) == str: expr = "entity.%s = data" % ext else: name = ext[0] expr = "entity.%s" % name except: expr = None return expr # 0 # SECTION # 2 # OBJECTS # # 0 # DICTIONARY # 5 # # 100 # AcDbDictionary # # 3 # # 350 # # # 0 # # . # . # . # # 0 # ENDSEC def parseObjects(data, statements, handles): while statements: (code,data) = statements.pop() if code == 0: if data == 'ENDSEC': return return # # buildGeometry(entities): # addMesh(name, verts, edges, faces): # def buildGeometry(entities): try: bpy.ops.object.mode_set(mode='OBJECT') except: pass v_verts = [] v_vn = 0 e_verts = [] e_edges = [] e_vn = 0 f_verts = [] f_edges = [] f_faces = [] f_vn = 0 for ent in entities: if ent.drawtype in ('Mesh','Curve'): (verts, edges, faces, vn) = ent.build() if not toggle & T_DrawOne: drawGeometry(verts, edges, faces) else: if verts: if faces: for i,f in enumerate(faces): #print ('face=', f) faces[i] = tuple(it+f_vn for it in f) for i,e in enumerate(edges): edges[i] = tuple(it+f_vn for it in e) f_verts.extend(verts) f_edges.extend(edges) f_faces.extend(faces) f_vn += len(verts) elif edges: for i,e in enumerate(edges): edges[i] = tuple(it+e_vn for it in e) e_verts.extend(verts) e_edges.extend(edges) e_vn += len(verts) else: v_verts.extend(verts) v_vn += len(verts) else: ent.draw() if toggle & T_DrawOne: drawGeometry(f_verts, f_edges, f_faces) drawGeometry(e_verts, e_edges) drawGeometry(v_verts) def drawGeometry(verts, edges=[], faces=[]): if verts: if edges and (toggle & T_Curves): print ('draw Curve') cu = bpy.data.curves.new('DXFLines', 'CURVE') cu.dimensions = '3D' buildSplines(cu, verts, edges) ob = addObject('DXFLines', cu) else: #for v in verts: print(v) #print ('draw Mesh with %s vertices' %(len(verts))) #for e in edges: print(e) #print ('draw Mesh with %s edges' %(len(edges))) #for f in faces: print(f) #print ('draw Mesh with %s faces' %(len(faces))) me = bpy.data.meshes.new('DXFmesh') me.from_pydata(verts, edges, faces) ob = addObject('DXFmesh', me) removeDoubles(ob) return def buildSplines(cu, verts, edges): if edges: point_list = [] (v0,v1) = edges.pop() v1_old = v1 newPoints = [tuple(verts[v0]),tuple(verts[v1])] for (v0,v1) in edges: if v0==v1_old: newPoints.append(tuple(verts[v1])) else: #print ('newPoints=', newPoints) point_list.append(newPoints) newPoints = [tuple(verts[v0]),tuple(verts[v1])] v1_old = v1 point_list.append(newPoints) for points in point_list: #spline = cu.splines.new('BEZIER') spline = cu.splines.new('POLY') #spline.endpoint_u = True #spline.order_u = 2 #spline.resolution_u = 1 #spline.bezier_points.add(2) spline.points.add(len(points)-1) #spline.points.foreach_set('co', points) for i,p in enumerate(points): spline.points[i].co = (p[0],p[1],p[2],0) print ('spline.type=', spline.type) print ('cu spline number=', len(cu.splines)) def addObject(name, data): ob = bpy.data.objects.new(name, data) scn = bpy.context.scene scn.objects.link(ob) return ob def removeDoubles(ob): global theMergeLimit if toggle & T_Merge: scn = bpy.context.scene scn.objects.active = ob bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.remove_doubles(limit=theMergeLimit) bpy.ops.object.mode_set(mode='OBJECT') # # clearScene(context): # def clearScene(): global toggle scn = bpy.context.scene print("clearScene %s %s" % (toggle & T_NewScene, scn)) if not toggle & T_NewScene: return scn for ob in scn.objects: if ob.type in ["MESH", "CURVE", "TEXT"]: scn.objects.active = ob bpy.ops.object.mode_set(mode='OBJECT') scn.objects.unlink(ob) del ob return scn # # readAndBuildDxfFile(filepath): # def readAndBuildDxfFile(filepath): fileName = os.path.expanduser(filepath) if fileName: (shortName, ext) = os.path.splitext(fileName) #print("filepath: ", filepath) #print("fileName: ", fileName) #print("shortName: ", shortName) if ext.lower() != ".dxf": print("Error: Not a dxf file: " + fileName) return if toggle & T_NewScene: clearScene() if 0: # how to switch to the new scene?? (migius) new_scn = bpy.data.scenes.new(shortName[-20:]) #new_scn.layers = (1<<20) -1 new_scn_name = new_scn.name bpy.data.screens.scene = new_scn #print("newScene: %s" % (new_scn)) sections = readDxfFile(fileName) print("Building geometry") buildGeometry(sections['ENTITIES'].data) print("Done") return print("Error: Not a dxf file: " + filepath) return # # User interface # DEBUG= False from bpy.props import * def tripleList(list1): list3 = [] for elt in list1: list3.append((elt,elt,elt)) return list3 class IMPORT_OT_autocad_dxf(bpy.types.Operator): '''Import from DXF file format (.dxf)''' bl_idname = "import_scene.autocad_dxf" bl_description = 'Import from DXF file format (.dxf)' bl_label = "Import DXF" +' v.'+ __version__ bl_space_type = "PROPERTIES" bl_region_type = "WINDOW" filepath = StringProperty(name="File Path", description="Filepath used for importing the DXF file", maxlen= 1024, default= "") new_scene = BoolProperty(name="Replace scene", description="Replace scene", default=toggle&T_NewScene) #new_scene = BoolProperty(name="New scene", description="Create new scene", default=toggle&T_NewScene) curves = BoolProperty(name="Draw curves", description="Draw entities as curves", default=toggle&T_Curves) thic_on = BoolProperty(name="Thic ON", description="Support THICKNESS", default=toggle&T_ThicON) merge = BoolProperty(name="Remove doubles", description="Merge coincident vertices", default=toggle&T_Merge) mergeLimit = FloatProperty(name="Limit", description="Merge limit", default = theMergeLimit*1e4,min=1.0, soft_min=1.0, max=100.0, soft_max=100.0) draw_one = BoolProperty(name="Merge all", description="Draw all into one mesh-object", default=toggle&T_DrawOne) circleResolution = IntProperty(name="Circle resolution", description="Circle/Arc are aproximated will this factor", default = theCircleRes, min=4, soft_min=4, max=360, soft_max=360) codecs = tripleList(['iso-8859-15', 'utf-8', 'ascii']) codec = EnumProperty(name="Codec", description="Codec", items=codecs, default = 'ascii') debug = BoolProperty(name="Debug", description="Unknown DXF-codes generate errors", default=toggle&T_Debug) verbose = BoolProperty(name="Verbose", description="Print debug info", default=toggle&T_Verbose) ##### DRAW ##### def draw(self, context): layout0 = self.layout #layout0.enabled = False #col = layout0.column_flow(2,align=True) layout = layout0.box() col = layout.column() #col.prop(self, 'KnotType') waits for more knottypes #col.label(text="import Parameters") #col.prop(self, 'replace') col.prop(self, 'new_scene') row = layout.row(align=True) row.prop(self, 'curves') row.prop(self, 'circleResolution') row = layout.row(align=True) row.prop(self, 'merge') if self.merge: row.prop(self, 'mergeLimit') row = layout.row(align=True) #row.label('na') row.prop(self, 'draw_one') row.prop(self, 'thic_on') col = layout.column() col.prop(self, 'codec') row = layout.row(align=True) row.prop(self, 'debug') if self.debug: row.prop(self, 'verbose') def execute(self, context): global toggle, theMergeLimit, theCodec, theCircleRes O_Merge = T_Merge if self.properties.merge else 0 #O_Replace = T_Replace if self.properties.replace else 0 O_NewScene = T_NewScene if self.properties.new_scene else 0 O_Curves = T_Curves if self.properties.curves else 0 O_ThicON = T_ThicON if self.properties.thic_on else 0 O_DrawOne = T_DrawOne if self.properties.draw_one else 0 O_Debug = T_Debug if self.properties.debug else 0 O_Verbose = T_Verbose if self.properties.verbose else 0 toggle = O_Merge | O_DrawOne | O_NewScene | O_Curves | O_ThicON | O_Debug | O_Verbose theMergeLimit = self.properties.mergeLimit*1e-4 theCircleRes = self.properties.circleResolution theCodec = self.properties.codec readAndBuildDxfFile(self.properties.filepath) return {'FINISHED'} def invoke(self, context, event): wm = context.window_manager wm.fileselect_add(self) return {'RUNNING_MODAL'} def menu_func(self, context): self.layout.operator(IMPORT_OT_autocad_dxf.bl_idname, text="Autocad (.dxf)") def register(): bpy.types.INFO_MT_file_import.append(menu_func) def unregister(): bpy.types.INFO_MT_file_import.remove(menu_func) if __name__ == "__main__": register()