Fix T38788: zero area faces raised exception with overhang test
[blender-addons.git] / io_import_scene_dxf.py
blob432e9cda064a0f7be2204ca2e818548bb268f640
1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
19 bl_info = {
20 "name": "Import Autocad DXF Format (.dxf)",
21 "author": "Thomas Larsson, Remigiusz Fiedler",
22 "version": (0, 1, 6),
23 "blender": (2, 63, 0),
24 "location": "File > Import > Autocad (.dxf)",
25 "description": "Import files in the Autocad DXF format (.dxf)",
26 "warning": "Under construction! Visit Wiki for details.",
27 "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
28 "Scripts/Import-Export/DXF_Importer",
29 "tracker_url": "https://developer.blender.org/T23480",
30 "support": "OFFICIAL",
31 "category": "Import-Export",
34 """
35 Release note by migius (DXF support maintainer) 2011.01.02:
36 Script supports only a small part of DXF specification:
37 - imports LINE, ARC, CIRCLE, ELLIPSE, SOLID, TRACE, POLYLINE, LWPOLYLINE
38 - imports TEXT, MTEXT
39 - supports 3d-rotation of entities (210 group)
40 - supports THICKNESS for SOLID, TRACE, LINE, ARC, CIRCLE, ELLIPSE
41 - ignores WIDTH, THICKNESS, BULGE in POLYLINE/LWPOLYLINE
42 - ignores face-data in POLYFACE / POLYMESH
43 - ignores TEXT 2d-rotation
44 - ignores hierarchies (BLOCK, INSERT, GROUP)
45 - ignores LAYER
46 - ignores COLOR, LINEWIDTH, LINESTYLE
48 This script is a temporary solution.
49 No functionality improvements are planed for this version.
50 The advanced importer from 2.49 will replace it in the future.
52 Installation:
53 Place this file to Blender addons directory
54 (on Windows it is %Blender_directory%\2.53\scripts\addons\)
55 The script must be activated in "Addons" tab (user preferences).
56 Access it from File > Import menu.
58 History:
59 ver 0.1.6 - 2012.01.03 by migius and trumanblending for r.42615
60 - modified for recent changes to matrix indexing
61 ver 0.1.5 - 2011.02.05 by migius for r.34661
62 - changed support level to OFFICIAL
63 - fixed missing last point at building Mesh-ARCs (by pildanovak)
64 - fixed for changes in API and mathutils by campbell
65 ver 0.1.4 - 2011.01.13 by migius
66 - modified for latest API in rev.34300 (by Filiciss Muhgue)
67 ver 0.1.3 - 2011.01.02 by migius
68 - added draw curves as sequence for "Draw_as_Curve"
69 - added toggle "Draw as one" as user preset in UI
70 - added draw POINT as mesh-vertex
71 - added draw_THICKNESS for LINE, ARC, CIRCLE, ELLIPSE, LWPOLYLINE and POLYLINE
72 - added draw_THICKNESS for SOLID, TRACE
73 ver 0.1.2 - 2010.12.27 by migius
74 - added draw() for TRACE
75 - fixed wrong vertex order in SOLID
76 - added CIRCLE resolution as user preset in UI
77 - added closing segment for circular LWPOLYLINE and POLYLINE
78 - fixed registering for 2.55beta
79 ver 0.1.1 - 2010.09.07 by migius
80 - fixed dxf-file names recognition limited to ".dxf"
81 - fixed registering for 2.53beta
82 ver 0.1 - 2010.06.10 by Thomas Larsson
83 """
85 __version__ = '.'.join([str(s) for s in bl_info['version']])
87 import os
88 import codecs
89 import math
90 from math import sin, cos, radians
91 import bpy
92 from mathutils import Vector, Matrix
95 # Global flags
98 T_Merge = 0x01
99 T_NewScene = 0x02
100 T_Curves = 0x04
101 T_DrawOne = 0x08
102 T_Debug = 0x10
103 T_Verbose = 0x20
104 T_ThicON = 0x40
106 toggle = T_Merge | T_NewScene | T_DrawOne | T_ThicON
107 theCircleRes = 32
108 theMergeLimit = 1e-4
111 # class CSection:
114 class CSection:
115 type = None
117 def __init__(self):
118 self.data = []
120 def display(self):
121 print("Section", self.type)
122 for datum in self.data:
123 datum.display()
126 # class CTable:
129 class CTable:
130 def __init__(self):
131 self.type = None
132 self.name = None
133 self.handle = None
134 self.owner = None
135 self.subclass = None
136 self.nEntries = 0
137 def display(self):
138 print("Table %s %s %s %s %s %d" % (self.type, self.name, self.handle, self.owner, self.subclass, self.nEntries))
141 # class CEntity:
143 class CEntity:
144 def __init__(self, typ, drawtype):
145 self.type = typ
146 self.drawtype = drawtype
147 self.handle = None
148 self.owner = None
149 self.subclass = None
150 self.layer = 0
151 self.color = 0
152 self.invisible = 0
153 self.linetype_name = ''
154 self.linetype_scale = 1.0
155 self.paperspace = 0
156 #self.normal = Vector((0,0,1))
158 def display(self):
159 print("Entity %s %s %s %s %s %s %x" %
160 (self.type, self.handle, self.owner, self.subclass, self.layer, self.color, self.invisible))
162 def build(self, vn=0):
163 global toggle
164 if toggle & T_Debug:
165 raise NameError("Warning: can not build - unsupported entity type: %s" % self.type)
166 return(([], [], [], vn))
168 def draw(self):
169 global toggle
170 if toggle & T_Debug:
171 raise NameError("Warning: can not draw - unsupported entity type: %s" % self.type)
172 return
175 DxfCommonAttributes = {
176 5 : 'handle',
177 6 : 'linetype_name',
178 8 : 'layer',
179 48 : 'linetype_scale',
180 60 : 'invisible',
181 62 : 'color',
182 67 : 'paperspace',
183 100 : 'subclass',
184 330 : 'owner',
185 360 : 'owner',
189 # class C3dFace(CEntity):
190 # 10 : 'point0.x', 20 : 'point0.y', 30 : 'point0.z',
191 # 11 : 'point1.x', 21 : 'point1.y', 31 : 'point1.z',
192 # 12 : 'point2.x', 22 : 'point2.y', 32 : 'point2.z',
193 # 13 : 'point3.x', 23 : 'point3.y', 33 : 'point3.z',
194 # 70 : 'flags',
197 class C3dFace(CEntity):
198 def __init__(self):
199 CEntity.__init__(self, '3DFACE', 'Mesh')
200 self.point0 = Vector()
201 self.point1 = Vector()
202 self.point2 = Vector()
203 self.point3 = Vector()
205 def display(self):
206 CEntity.display(self)
207 print(self.point0)
208 print(self.point1)
209 print(self.point2)
210 print(self.point3)
212 def build(self, vn=0):
213 verts = [self.point0, self.point1, self.point2]
214 if self.point3 == Vector((0,0,0)) or self.point2 == self.point3:
215 faces = [(vn+0, vn+1, vn+2)]
216 vn += 3
217 else:
218 verts.append( self.point3 )
219 faces = [(vn+0, vn+1, vn+2, vn+3)]
220 vn += 4
221 return((verts, [], faces, vn))
224 # class C3dSolid(CEntity):
225 # 1 : 'data', 3 : 'more', 70 : 'version',
228 class C3dSolid(CEntity):
229 def __init__(self):
230 CEntity.__init__(self, '3DSOLID', 'Mesh')
231 self.data = None
232 self.more = None
233 self.version = 0
236 # class CAcadProxyEntity(CEntity):
237 # 70 : 'format',
238 # 90 : 'id', 91 : 'class', 92 : 'graphics_size', 93 : 'entity_size', 95: 'format',
239 # 310 : 'data', 330 : 'id1', 340 : 'id2', 350 : 'id3', 360 : 'id4',
242 class CAcadProxyEntity(CEntity):
243 def __init__(self):
244 CEntity.__init__(self, 'ACAD_PROXY_ENTITY', None)
248 # class CArc(CEntity):
249 # 10 : 'center.x', 20 : 'center.y', 30 : 'center.z',
250 # 40 : 'radius',
251 # 50 : 'start_angle', 51 : 'end_angle'
254 class CArc(CEntity):
255 def __init__(self):
256 CEntity.__init__(self, 'ARC', 'Mesh')
257 self.center = Vector()
258 self.radius = 0.0
259 self.start_angle = 0.0
260 self.end_angle = 0.0
261 self.thickness = 0.0
262 self.normal = Vector((0,0,1))
264 def display(self):
265 CEntity.display(self)
266 print(self.center)
267 print("%.4f %.4f %.4f " % (self.radius, self.start_angle, self.end_angle))
269 def build(self, vn=0):
270 start, end = self.start_angle, self.end_angle
271 if end > 360: end = end % 360.0
272 if end < start: end +=360.0
273 # angle = end - start # UNUSED
275 deg2rad = math.pi/180.0
276 start *= deg2rad
277 end *= deg2rad
278 dphi = end - start
279 phi0 = start
280 w = dphi/theCircleRes
281 r = self.radius
282 center = self.center
283 v0 = vn
284 points = []
285 edges, faces = [], []
286 for n in range(theCircleRes + 1):
287 s = math.sin(n*w + phi0)
288 c = math.cos(n*w + phi0)
289 v = center + Vector((r*c, r*s, 0.0))
290 points.append(v)
291 pn = len(points)
292 thic = self.thickness
293 t_vector = Vector((0, 0, thic))
294 if thic != 0 and (toggle & T_ThicON):
295 thic_points = [v + t_vector for v in points]
296 if thic < 0.0:
297 thic_points.extend(points)
298 points = thic_points
299 else:
300 points.extend(thic_points)
301 faces = [(v0+nr+0,v0+nr+1,v0+pn+nr+1,v0+pn+nr+0) for nr in range(pn)]
302 faces.pop()
303 self.drawtype = 'Mesh'
304 vn += 2*pn
305 else:
306 edges = [(v0+nr+0,v0+nr+1) for nr in range(pn)]
307 edges.pop()
308 vn += pn
310 if self.normal!=Vector((0,0,1)):
311 ma = getOCS(self.normal)
312 if ma:
313 #ma.invert()
314 points = [ma * v for v in points]
315 #print ('arc vn=', vn)
316 #print ('faces=', len(faces))
317 return ((points, edges, faces, vn))
320 # class CArcAlignedText(CEntity):
321 # 1 : 'text', 2 : 'font', 3 : 'bigfont', 7 : 'style',
322 # 10 : 'center.x', 20 : 'center.y', 30 : 'center.z',
323 # 40 : 'radius', 41 : 'width', 42 : 'height', 43 : 'spacing',
324 # 44 : 'offset', 45 : 'right_offset', 46 : 'left_offset',
325 # 50 : 'start_angle', 51 : 'end_angle',
326 # 70 : 'order', 71 : 'direction', 72 : 'alignment', 73 : 'side',
327 # 74 : 'bold', 75 : 'italic', 76 : 'underline',
328 # 77 : 'character_set', 78 : 'pitch', 79 'fonttype',
329 # 90 : 'color',
330 # 280 : 'wizard', 330 : 'id'
333 class CArcAlignedText(CEntity):
334 def __init__(self):
335 CEntity.__init__(self, 'ARCALIGNEDTEXT', 'Mesh')
336 self.text = ""
337 self.style = ""
338 self.center = Vector()
339 self.radius = 0.0
340 self.width = 1.0
341 self.height = 1.0
342 self.spacing = 1.0
343 self.offset = 0.0
344 self.right_offset = 0.0
345 self.left_offset = 0.0
346 self.start_angle = 0.0
347 self.end_angle = 0.0
348 self.order = 0
349 self.directions = 0
350 self.alignment = 0
351 self.side = 0
352 self.bold = 0
353 self.italic = 0
354 self.underline = 0
355 self.character_set = 0
356 self.pitch = 0
357 self.fonttype = 0
358 self.color = 0
359 self.wizard = None
360 self.id = None
361 self.normal = Vector((0,0,1))
365 # class CAttdef(CEntity):
366 # 1 : 'text', 2 : 'tag', 3 : 'prompt', 7 : 'style',
367 # 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
368 # 11 : 'alignment_point.x', 21 : 'alignment_point.y', 31 : 'alignment_point.z',
369 # 40 : 'height', 41 : 'x_scale',
370 # 50 : 'rotation_angle', 51 : 'oblique_angle',
371 # 70 : 'flags', 71 : 'text_generation_flags',
372 # 72 : 'horizontal_justification', 74 : 'vertical_justification',
375 class CAttdef(CEntity):
376 def __init__(self):
377 CEntity.__init__(self, 'ATTDEF', None)
378 self.value = ""
379 self.tag = ""
380 self.prompt = ""
381 self.style = ""
382 self.insertion_point = Vector()
383 self.alignment_point = Vector()
384 self.height = 1.0
385 self.x_scale = 1.0
386 self.rotation_angle = 0.0
387 self.oblique_angle = 0.0
388 self.flags = 0
389 self.text_generation_flags = 0
390 self.horizontal_justification = 0.0
391 self.vertical_justification = 0.0
392 self.normal = Vector((0,0,1))
394 def draw(self):
395 drawText(self.text, self.insertion_point, self.height, self.x_scale, self.rotation_angle, self.oblique_angle, self.normal)
396 return
399 # class CAttrib(CEntity):
400 # 1 : 'text', 2 : 'tag', 3 : 'prompt', 7 : 'style',
401 # 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
402 # 11 : 'alignment_point.x', 21 : 'alignment_point.y', 31 : 'alignment_point.z',
403 # 40 : 'height', 41 : 'x_scale',
404 # 50 : 'rotation_angle', 51 : 'oblique_angle',
405 # 70 : 'flags', 73 : 'length',
406 # 71 : 'text_generation_flags', 72 : 'horizontal_justification', 74 : 'vertical_justification',
409 class CAttrib(CEntity):
410 def __init__(self):
411 CEntity.__init__(self, 'ATTRIB', None)
412 self.text = ""
413 self.tag = ""
414 self.prompt = ""
416 self.style = ""
417 self.insertion_point = Vector()
418 self.alignment_point = Vector()
419 self.height = 1.0
420 self.x_scale = 1.0
421 self.rotation_angle = 0.0
422 self.oblique_angle = 0.0
423 self.flags = 0
424 self.length = 1.0
425 self.text_generation_flags = 0
426 self.horizontal_justification = 0.0
427 self.vertical_justification = 0.0
428 self.normal = Vector((0,0,1))
430 def draw(self):
431 drawText(self.text, self.insertion_point, self.height, self.x_scale, self.rotation_angle, self.oblique_angle, self.normal)
432 return
436 # class CBlock(CEntity):
437 # 1 : 'xref', 2 : 'name', 3 : 'also_name',
438 # 10 : 'base_point.x', 20 : 'base_point.y', 30 : 'base_point.z',
439 # 40 : 'size', 41 : 'x_scale',
440 # 50 : 'rotation_angle', 51 : 'oblique_angle',
441 # 70 : 'flags',
444 class CBlock(CEntity):
445 def __init__(self):
446 CEntity.__init__(self, 'BLOCK', None)
447 self.xref = ""
448 self.name = ""
449 self.also_name = ""
450 self.base_point = Vector()
451 self.size = 1.0
452 self.x_scale = 1.0
453 self.rotation_angle = 0.0
454 self.oblique_angle = 0.0
455 self.flags = 0
456 self.normal = Vector((0,0,1))
458 def display(self):
459 CEntity.display(self)
460 print("%s %s %s " % (self.xref, self.name, self.also_name))
461 print(self.base_point)
463 def draw(self):
464 # Todo
465 return
468 # class CCircle(CEntity):
469 # 10 : 'center.x', 20 : 'center.y', 30 : 'center.z',
470 # 40 : 'radius'
473 class CCircle(CEntity):
474 def __init__(self):
475 CEntity.__init__(self, 'CIRCLE', 'Mesh')
476 self.center = Vector()
477 self.radius = 0.0
478 self.thickness = 0.0
479 self.normal = Vector((0,0,1))
481 def display(self):
482 CEntity.display(self)
483 print(self.center)
484 print("%.4f" % self.radius)
486 def build(self, vn=0):
487 w = 2*math.pi/theCircleRes
488 r = self.radius
489 center = self.center
490 points = []
491 edges, faces = [], []
492 v0 = vn
493 for n in range(theCircleRes):
494 s = math.sin(n*w)
495 c = math.cos(n*w)
496 v = center + Vector((r*c, r*s, 0))
497 points.append(v)
499 pn = len(points)
500 thic = self.thickness
501 t_vector = Vector((0, 0, thic))
502 if thic != 0 and (toggle & T_ThicON):
503 thic_points = [v + t_vector for v in points]
504 if thic < 0.0:
505 thic_points.extend(points)
506 points = thic_points
507 else:
508 points.extend(thic_points)
509 faces = [(v0+nr,v0+nr+1,pn+v0+nr+1,pn+v0+nr) for nr in range(pn)]
510 nr = pn -1
511 faces[-1] = (v0+nr,v0,pn+v0,pn+v0+nr)
512 self.drawtype = 'Mesh'
513 vn += 2*pn
514 else:
515 edges = [(v0+nr,v0+nr+1) for nr in range(pn)]
516 nr = pn -1
517 edges[-1] = (v0+nr,v0)
518 vn += pn
519 if self.normal!=Vector((0,0,1)):
520 ma = getOCS(self.normal)
521 if ma:
522 #ma.invert()
523 points = [ma * v for v in points]
524 #print ('cir vn=', vn)
525 #print ('faces=',len(faces))
526 return( (points, edges, faces, vn) )
529 # class CDimension(CEntity):
530 # 1 : 'text', 2 : 'name', 3 : 'style',
531 # 10 : 'def_point.x', 20 : 'def_point.y', 30 : 'def_point.z',
532 # 11 : 'mid_point.x', 21 : 'mid_point.y', 31 : 'mid_point.z',
533 # 12 : 'vector.x', 22 : 'vector.y', 32 : 'vector.z',
534 # 13 : 'def_point2.x', 23 : 'def_point2.y', 33 : 'def_point2.z',
535 # 14 : 'vector2.x', 24 : 'vector2.y', 34 : 'vector2.z',
536 # 15 : 'vector3.x', 25 : 'vector3.y', 35 : 'vector3.z',
537 # 16 : 'vector4.x', 26 : 'vector4.y', 36 : 'vector4.z',
538 # 70 : 'dimtype',
541 class CDimension(CEntity):
542 def __init__(self):
543 CEntity.__init__(self, 'DIMENSION', None)
544 self.text = ""
545 self.name = ""
546 self.style = ""
547 self.def_point = Vector()
548 self.mid_point = Vector()
549 self.vector = Vector()
550 self.def_point2 = Vector()
551 self.vector2 = Vector()
552 self.vector3 = Vector()
553 self.vector4 = Vector()
554 self.dimtype = 0
555 self.normal = Vector((0,0,1))
557 def draw(self):
558 return
561 # class CEllipse(CEntity):
562 # 10 : 'center.x', 20 : 'center.y', 30 : 'center.z',
563 # 11 : 'end_point.x', 21 : 'end_point.y', 31 : 'end_point.z',
564 # 40 : 'ratio', 41 : 'start', 42 : 'end',
567 class CEllipse(CEntity):
568 def __init__(self):
569 CEntity.__init__(self, 'ELLIPSE', 'Mesh')
570 self.center = Vector()
571 self.end_point = Vector()
572 self.ratio = 1.0
573 self.start = 0.0
574 self.end = 2*math.pi
575 self.thickness = 0.0
576 self.normal = Vector((0,0,1))
578 def display(self):
579 CEntity.display(self)
580 print(self.center)
581 print("%.4f" % self.ratio)
583 def build(self, vn=0):
584 dphi = (self.end - self.start)
585 phi0 = self.start
586 w = dphi/theCircleRes
587 r = self.end_point.length
588 f = self.ratio
589 a = self.end_point.x/r
590 b = self.end_point.y/r
591 center = self.center
592 v0 = vn
593 points = []
594 edges, faces = [], []
595 for n in range(theCircleRes):
596 x = r*math.sin(n*w + phi0)
597 y = f*r*math.cos(n*w + phi0)
598 v = (center.x - a*x + b*y, center.y - a*y - b*x, center.z)
599 points.append(v)
601 pn = len(points)
602 thic = self.thickness
603 t_vector = Vector((0, 0, thic))
604 if thic != 0 and (toggle & T_ThicON):
605 thic_points = [v + t_vector for v in points]
606 if thic < 0.0:
607 thic_points.extend(points)
608 points = thic_points
609 else:
610 points.extend(thic_points)
611 faces = [(v0+nr,v0+nr+1,pn+v0+nr+1,pn+v0+nr) for nr in range(pn)]
612 nr = pn -1
613 faces[-1] = (v0+nr,v0,pn+v0,pn+v0+nr)
614 #self.drawtype = 'Mesh'
615 vn += 2*pn
616 else:
617 edges = [(v0+nr,v0+nr+1) for nr in range(pn)]
618 nr = pn -1
619 edges[-1] = (v0+nr,v0)
620 vn += pn
623 if thic != 0 and (toggle & T_ThicON):
624 pass
625 if self.normal!=Vector((0,0,1)):
626 ma = getOCS(self.normal)
627 if ma:
628 #ma.invert()
629 points = [ma * v for v in points]
630 return ((points, edges, faces, vn))
633 # class CHatch(CEntity):
634 # 2 : 'pattern',
635 # 10 : 'point.x', 20 : 'point.y', 30 : 'point.z',
636 # 41 : 'scale', 47 : 'pixelsize', 52 : 'angle',
637 # 70 : 'fill', 71 : 'associativity', 75: 'style', 77 : 'double',
638 # 78 : 'numlines', 91 : 'numpaths', 98 : 'numseeds',
641 class CHatch(CEntity):
642 def __init__(self):
643 CEntity.__init__(self, 'HATCH', None)
644 self.pattern = 0
645 self.point = Vector()
646 self.scale = 1.0
647 self.pixelsize = 1.0
648 self.angle = 0.0
649 self.fill = 0
650 self.associativity = 0
651 self.style = 0
652 self.double = 0
653 self.numlines = 0
654 self.numpaths = 0
655 self.numseeds = 0
656 self.normal = Vector((0,0,1))
659 # class CImage(CEntity):
660 # 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
661 # 11 : 'u_vector.x', 21 : 'u_vector.y', 31 : 'u_vector.z',
662 # 12 : 'v_vector.x', 22 : 'v_vector.y', 32 : 'v_vector.z',
663 # 13 : 'size.x', 23 : 'size.y', 33 : 'size.z',
664 # 14 : 'clip.x', 24 : 'clip.y', 34 : 'clip.z',
665 # 70 : 'display', 71 : 'cliptype',
666 # 90 : 'version',
667 # 280 : 'clipstate', 281 : 'brightness', 282 : 'contrast', 283 : 'fade',
668 # 340 : 'image', 360 : 'reactor'
671 class CImage(CEntity):
672 def __init__(self):
673 CEntity.__init__(self, 'IMAGE', None)
674 self.insertion_point = Vector()
675 self.u_vector = Vector()
676 self.v_vector = Vector()
677 self.size = Vector()
678 self.clip = Vector()
679 self.display = 0
680 self.cliptype = 0
681 self.version = 1
682 self.clipstate = 0
683 self.brightness = 0
684 self.constrast = 0
685 self.fade = 0
686 self.image = None
687 self.reactor = None
688 self.normal = Vector((0,0,1))
691 # class CInsert(CEntity):
692 # 1 : 'attributes_follow', 2 : 'name',
693 # 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
694 # 41 : 'x_scale', 42 : 'y_scale', 43 : 'z_scale',
695 # 44 : 'column_spacing', 45 : 'row_spacing',
696 # 50 : 'rotation_angle', 66 : 'attributes_follow',
697 # 70 : 'column_count', 71 : 'row_count',
700 class CInsert(CEntity):
701 def __init__(self):
702 CEntity.__init__(self, 'INSERT', None)
703 self.attributes_follow = 1
704 self.name = ""
705 self.insertion_point = Vector()
706 self.x_scale = 1.0
707 self.y_scale = 1.0
708 self.z_scale = 1.0
709 self.column_spacing = 1.0
710 self.row_spacing = 1.0
711 self.rotation_angle = 0.0
712 self.column_count = 1
713 self.row_count = 1
714 self.attributes_follow = 0
715 self.normal = Vector((0,0,1))
717 def display(self):
718 CEntity.display(self)
719 print(self.insertion_point)
721 def draw(self):
722 # Todo
723 return
726 # class CLeader(CEntity):
727 # 3 : 'style',
728 # 10 : ['new_vertex(data)'], 20 : 'vertex.y', 30 : 'vertex.z',
729 # 40 : 'height', 41 : 'width',
730 # 71 : 'arrowhead', 72 : 'pathtype', 73 : 'creation',
731 # 74 : 'hookdir', 75 : 'hookline', 76 : 'numverts', 77 : 'color',
732 # 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
733 # 211 : 'horizon.x', 221 : 'horizon.y', 231 : 'horizon.z',
734 # 212 : 'offset_ins.x', 222 : 'offset_ins.y', 232 : 'offset_ins.z',
735 # 213 : 'offset_ann.x', 223 : 'offset_ann.y', 233 : 'offset_ann.z',
738 class CLeader(CEntity):
739 def __init__(self):
740 CEntity.__init__(self, 'LEADER', 'Mesh')
741 self.style = ""
742 self.vertex = None
743 self.verts = []
744 self.height = 1.0
745 self.width = 1.0
746 self.arrowhead = 0
747 self.pathtype = 0
748 self.creation = 0
749 self.hookdir = 0
750 self.hookline = 0
751 self.numverts = 0
752 self.color = 0
753 self.normal = Vector((0,0,1))
754 self.horizon = Vector()
755 self.offset_ins = Vector()
756 self.offset_ann = Vector()
758 def new_vertex(self, data):
759 self.vertex = Vector()
760 self.vertex.x = data
761 self.verts.append(self.vertex)
763 def build(self, vn=0):
764 edges = []
765 for v in self.verts:
766 edges.append((vn, vn+1))
767 vn += 1
768 edges.pop()
769 return (self.verts, edges, [], vn)
771 # class CLwPolyLine(CEntity):
772 # 10 : ['new_vertex(data)'], 20 : 'vertex.y', 30 : 'vertex.z',
773 # 38 : 'elevation', 39 : 'thickness',
774 # 40 : 'start_width', 41 : 'end_width', 42 : 'bulge', 43 : 'constant_width',
775 # 70 : 'flags', 90 : 'numverts'
778 class CLWPolyLine(CEntity):
779 def __init__(self):
780 CEntity.__init__(self, 'LWPOLYLINE', None)
781 self.vertex = None
782 self.verts = []
783 self.elevation = 0
784 self.thickness = 0.0
785 self.start_width = 0.0
786 self.end_width = 0.0
787 self.bulge = 0.0
788 self.constant_width = 0.0
789 self.flags = 0
790 self.numverts = 0
791 self.normal = Vector((0,0,1))
793 def new_vertex(self, data):
794 self.vertex = Vector()
795 self.vertex.x = data
796 self.verts.append(self.vertex)
798 def build(self, vn=0):
799 edges = []
800 v_start = vn
801 for v in self.verts:
802 edges.append((vn, vn+1))
803 vn += 1
804 if self.flags & PL_CLOSED:
805 edges[-1] = (vn-1, v_start)
806 else:
807 edges.pop()
808 verts = self.verts
809 if self.normal!=Vector((0,0,1)):
810 ma = getOCS(self.normal)
811 if ma:
812 #ma.invert()
813 verts = [ma * v for v in verts]
814 return (verts, edges, [], vn-1)
817 # class CLine(CEntity):
818 # 10 : 'start_point.x', 20 : 'start_point.y', 30 : 'start_point.z',
819 # 11 : 'end_point.x', 21 : 'end_point.y', 31 : 'end_point.z',
820 # 39 : 'thickness',
823 class CLine(CEntity):
824 def __init__(self):
825 CEntity.__init__(self, 'LINE', 'Mesh')
826 self.start_point = Vector()
827 self.end_point = Vector()
828 self.thickness = 0.0
829 self.normal = Vector((0,0,1))
831 def display(self):
832 CEntity.display(self)
833 print(self.start_point)
834 print(self.end_point)
836 def build(self, vn=0):
837 points = [self.start_point, self.end_point]
838 faces, edges = [], []
839 n = vn
840 thic = self.thickness
841 if thic != 0 and (toggle & T_ThicON):
842 t_vector = thic * self.normal
843 #print 'deb:thic_vector: ', t_vector #---------------------
844 points.extend([v + t_vector for v in points])
845 faces = [[0+n, 1+n, 3+n, 2+n]]
846 self.drawtype = 'Mesh'
847 else:
848 edges = [[0+n, 1+n]]
849 vn +=2
850 return((points, edges, faces, vn))
852 # class CMLine(CEntity):
853 # 10 : 'start_point.x', 20 : 'start_point.y', 30 : 'start_point.z',
854 # 11 : ['new_vertex(data)'], 21 : 'vertex.y', 31 : 'vertex.z',
855 # 12 : ['new_seg_dir(data)'], 22 : 'seg_dir.y', 32 : 'seg_dir.z',
856 # 13 : ['new_miter_dir(data)'], 23 : 'miter_dir.y', 33 : 'miter_dir.z',
857 # 40 : 'scale', 41 : 'elem_param', 42 : 'fill_param',
858 # 70 : 'justification', 71 : 'flags'
859 # 72 : 'numverts', 73 : 'numelems', 74 : 'numparam', 75 : 'numfills',
860 # 340 : 'id'
863 class CMLine(CEntity):
864 def __init__(self):
865 CEntity.__init__(self, 'MLINE', None)
866 self.start_point = Vector()
867 self.vertex = None
868 self.seg_dir = None
869 self.miter_dir = None
870 self.verts = []
871 self.seg_dirs = []
872 self.miter_dirs = []
873 self.scale = 1.0
874 self.elem_param = 0
875 self.fill_param = 0
876 self.justification = 0
877 self.flags = 0
878 self.numverts = 0
879 self.numelems = 0
880 self.numparam = 0
881 self.numfills = 0
882 self.id = 0
883 self.normal = Vector((0,0,1))
885 def new_vertex(self, data):
886 self.vertex = Vector()
887 self.vertex.x = data
888 self.verts.append(self.vertex)
890 def new_seg_dir(self, data):
891 self.seg_dir = Vector()
892 self.seg_dir.x = data
893 self.seg_dirs.append(self.seg_dir)
895 def new_miter_dir(self, data):
896 self.miter_dir = Vector()
897 self.miter_dir.x = data
898 self.miter_dirs.append(self.miter_dir)
903 # class CMText(CText):
904 # 1 : 'text', 3: 'more_text', 7 : 'style',
905 # 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
906 # 11 : 'alignment_point.x', 21 : 'alignment_point.y', 31 : 'alignment_point.z',
907 # 40 : 'nominal_height', 41 : 'reference_width', 42: 'width', 43 : 'height', 44 : 'line_spacing',
908 # 50 : 'rotation_angle',
909 # 71 : 'attachment_point', 72 : 'drawing_direction', 73 : 'spacing_style',
912 class CMText(CEntity):
913 def __init__(self):
914 CEntity.__init__(self, 'MTEXT', 'Text')
915 self.text = ""
916 self.more_text = ""
917 self.style = ""
918 self.insertion_point = Vector()
919 self.alignment_point = Vector()
920 self.nominal_height = 1.0
921 self.reference_width = 1.0
922 self.width = 1.0
923 self.height = 1.0
924 self.rotation_angle = 0.0
925 self.attachment_point = 0
926 self.drawing_direction = 0
927 self.spacing_style = 0
928 self.normal = Vector((0,0,1))
930 def display(self):
931 CEntity.display(self)
932 print("%s %s" % (self.text, self.style))
933 print('MTEXTinsertion_point=',self.insertion_point)
934 print('MTEXTalignment_point=',self.alignment_point)
936 def draw(self):
937 drawText(self.text, self.insertion_point, self.height, self.width, self.rotation_angle, 0.0, self.normal)
938 return
941 # class CPoint(CEntity):
942 # 10 : 'point.x', 20 : 'point.y', 30 : 'point.z',
943 # 39 : 'thickness', 50 : 'orientation'
946 class CPoint(CEntity):
947 def __init__(self):
948 CEntity.__init__(self, 'POINT', 'Mesh')
949 self.point = Vector()
950 self.thickness = 0.0
951 self.orientation = 0.0
953 def display(self):
954 CEntity.display(self)
955 print(self.point)
956 print("%.4f" % self.orientation)
958 def build(self, vn=0):
959 # draw as mesh-vertex
960 verts = [self.point]
961 return((verts, [], [], vn+1))
963 def draw(self):
964 #todo
965 # draw as empty-object
966 # loc = self.point # UNUSED
967 #bpy.ops.object.new('DXFpoint')
968 pass
971 # class CPolyLine(CEntity):
972 # 1 : 'verts_follow', 2 : 'name',
973 # 10 : 'elevation.x', 20 : 'elevation.y', 30 : 'elevation.z',
974 # 40 : 'start_width', 41 : 'end_width',
975 # 66 : 'verts_follow_flag',
976 # 70 : 'flags', 71 : 'row_count', 72 : 'column_count',
977 # 73 : 'row_density', 74 : 'column_density', 75 : 'linetype',
980 class CPolyLine(CEntity):
981 def __init__(self):
982 CEntity.__init__(self, 'POLYLINE', 'Mesh')
983 self.verts = []
984 self.verts_follow = 1
985 self.name = ""
986 self.elevation = Vector()
987 self.thickness = 0.0
988 self.start_width = 0.0
989 self.end_width = 0.0
990 self.verts_follow_flags = 0
991 self.flags = 0
992 self.row_count = 1
993 self.column_count = 1
994 self.row_density = 1.0
995 self.column_density = 1.0
996 self.linetype = 1
997 self.normal = Vector((0,0,1))
999 def display(self):
1000 CEntity.display(self)
1001 print("VERTS")
1002 for v in self.verts:
1003 print(v.location)
1004 print("END VERTS")
1006 def build(self, vn=0):
1007 verts = []
1008 lines = []
1009 v_start = vn
1010 for vert in self.verts:
1011 verts.append(vert.location)
1012 lines.append((vn, vn+1))
1013 vn += 1
1014 if self.flags & PL_CLOSED:
1015 lines[-1] = (vn-1, v_start)
1016 else:
1017 lines.pop()
1018 if self.normal!=Vector((0,0,1)):
1019 ma = getOCS(self.normal)
1020 if ma:
1021 verts = [ma * v for v in verts]
1022 return((verts, lines, [], vn-1))
1025 # class CShape(CEntity):
1026 # 2 : 'name',
1027 # 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
1028 # 39 : 'thickness',
1029 # 40 : 'size', 41 : 'x_scale',
1030 # 50 : 'rotation_angle', 51 : 'oblique_angle',
1033 class CShape(CEntity):
1034 def __init__(self):
1035 CEntity.__init__(self, 'SHAPE', None)
1036 self.name = ""
1037 self.insertion_point = Vector()
1038 self.thickness = 0.0
1039 self.size = 1.0
1040 self.x_scale = 1.0
1041 self.rotation_angle = 0.0
1042 self.oblique_angle = 0.0
1044 def display(self):
1045 CEntity.display(self)
1046 print("%s" % (self.name))
1047 print(self.insertion_point)
1050 # class CSpline(CEntity):
1051 # 10 : ['new_control_point(data)'], 20 : 'control_point.y', 30 : 'control_point.z',
1052 # 11 : ['new_fit_point(data)'], 21 : 'fit_point.y', 31 : 'fit_point.z',
1053 # 40 : ['new_knot_value(data)'],
1054 # 12 : 'start_tangent.x', 22 : 'start_tangent.y', 32 : 'start_tangent.z',
1055 # 13 : 'end_tangent.x', 23 : 'end_tangent.y', 33 : 'end_tangent.z',
1056 # 41 : 'weight', 42 : 'knot_tol', 43 : 'control_point_tol', 44 : 'fit_tol',
1057 # 70 : 'flag', 71 : 'degree',
1058 # 72 : 'num_knots', 73 : 'num_control_points', 74 : 'num_fit_points',
1059 # 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1062 class CSpline(CEntity):
1063 def __init__(self):
1064 CEntity.__init__(self, 'SPLINE', 'Mesh')
1065 self.control_points = []
1066 self.fit_points = []
1067 self.knot_values = []
1068 self.control_point = None
1069 self.fit_point = None
1070 self.knot_value = None
1071 self.start_tangent = Vector()
1072 self.end_tangent = Vector()
1073 self.weight = 1.0
1074 self.knot_tol = 1e-6
1075 self.control_point_tol = 1e-6
1076 self.fit_tol = 1e-6
1077 self.flag = 0
1078 self.degree = 3
1079 self.num_knots = 0
1080 self.num_control_points = 0
1081 self.num_fit_points = 0
1082 self.thickness = 0.0
1083 self.normal = Vector((0,0,1))
1085 def new_control_point(self, data):
1086 self.control_point = Vector()
1087 self.control_point.x = data
1088 self.control_points.append(self.control_point)
1090 def new_fit_point(self, data):
1091 self.fit_point = Vector()
1092 self.fit_point.x = data
1093 self.fit_points.append(self.fit_point)
1095 def new_knot_value(self, data):
1096 self.knot_value = data
1097 self.knot_values.append(self.knot_value)
1099 def display(self):
1100 #not testet yet (migius)
1101 CEntity.display(self)
1102 print("CONTROL")
1103 for p in self.control_points:
1104 print(p)
1105 print("FIT")
1106 for p in self.fit_points:
1107 print(p)
1108 print("KNOT")
1109 for v in self.knot_values:
1110 print(v)
1112 def build(self, vn=0):
1113 verts = []
1114 lines = []
1115 for vert in self.control_points:
1116 verts.append(vert)
1117 lines.append((vn, vn+1))
1118 vn += 1
1119 lines.pop()
1120 return((verts, lines, [], vn))
1124 # class CSolid(CEntity):
1125 # 10 : 'point0.x', 20 : 'point0.y', 30 : 'point0.z',
1126 # 11 : 'point1.x', 21 : 'point1.y', 31 : 'point1.z',
1127 # 12 : 'point2.x', 22 : 'point2.y', 32 : 'point2.z',
1128 # 13 : 'point3.x', 23 : 'point3.y', 33 : 'point3.z',
1129 # 39 : 'thickness',
1132 class CSolid(CEntity):
1133 def __init__(self):
1134 CEntity.__init__(self, 'SOLID', 'Mesh')
1135 self.point0 = Vector()
1136 self.point1 = Vector()
1137 self.point2 = Vector()
1138 self.point3 = Vector()
1139 self.normal = Vector((0,0,1))
1140 self.thickness = 0.0
1142 def display(self):
1143 CEntity.display(self)
1144 print(self.point0)
1145 print(self.point1)
1146 print(self.point2)
1147 print(self.point3)
1149 def build(self, vn=0):
1150 points, edges, faces = [],[],[]
1151 if self.point2 == self.point3:
1152 points = [self.point0, self.point1, self.point2]
1153 else:
1154 points = [self.point0, self.point1, self.point2, self.point3]
1155 pn = len(points)
1156 v0 = vn
1158 thic = self.thickness
1159 t_vector = Vector((0, 0, thic))
1160 if thic != 0 and (toggle & T_ThicON):
1161 thic_points = [v + t_vector for v in points]
1162 if thic < 0.0:
1163 thic_points.extend(points)
1164 points = thic_points
1165 else:
1166 points.extend(thic_points)
1168 if pn == 4:
1169 faces = [[0,1,3,2], [4,6,7,5], [0,4,5,1],
1170 [1,5,7,3], [3,7,6,2], [2,6,4,0]]
1171 elif pn == 3:
1172 faces = [[0,1,2], [3,5,4], [0,3,4,1], [1,4,5,2], [2,5,3,0]]
1173 elif pn == 2: faces = [[0,1,3,2]]
1174 vn += 2*pn
1175 else:
1176 if pn == 4: faces = [[0,2,3,1]]
1177 elif pn == 3: faces = [[0,2,1]]
1178 elif pn == 2:
1179 edges = [[0,1]]
1180 self.drawtype = 'Mesh'
1181 vn += pn
1182 if self.normal!=Vector((0,0,1)):
1183 ma = getOCS(self.normal)
1184 if ma:
1185 points = [ma * v for v in points]
1186 return((points, edges, faces, vn))
1189 # class CText(CEntity):
1190 # 1 : 'text', 7 : 'style',
1191 # 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
1192 # 11 : 'alignment_point.x', 21 : 'alignment_point.y', 31 : 'alignment_point.z',
1193 # 40 : 'height', 41 : 'x_scale',
1194 # 50 : 'rotation_angle', 51 : 'oblique_angle',
1195 # 71 : 'flags', 72 : 'horizontal_justification', 73 : 'vertical_justification',
1198 class CText(CEntity):
1199 def __init__(self):
1200 CEntity.__init__(self, 'TEXT', 'Text')
1201 self.text = ""
1202 self.style = ""
1203 self.insertion_point = Vector()
1204 self.alignment_point = Vector()
1205 self.height = 1.0
1206 self.x_scale = 1.0
1207 self.rotation_angle = 0.0
1208 self.oblique_angle = 0.0
1209 self.flags = 0
1210 self.horizontal_justification = 0.0
1211 self.vertical_justification = 0.0
1212 self.thickness = 0.0
1213 self.normal = Vector((0,0,1))
1215 def display(self):
1216 CEntity.display(self)
1217 print("%s %s" % (self.text, self.style))
1218 print(self.insertion_point)
1219 print(self.alignment_point)
1221 def draw(self):
1222 drawText(self.text, self.insertion_point, self.height, self.x_scale, self.rotation_angle, self.oblique_angle, self.normal)
1223 return
1226 def drawText(text, loc, size, spacing, angle, shear, normal=Vector((0,0,1))):
1227 #print('angle_deg=',angle)
1228 bpy.ops.object.text_add(
1229 view_align=False,
1230 enter_editmode=False,
1231 location= loc,
1232 #rotation=(0, 0, angle), #need radians here
1234 cu = bpy.context.object.data
1235 cu.body = text
1236 cu.size = size #up 2.56
1237 cu.space_word = spacing #up 2.56
1238 cu.shear = shear
1239 if angle!=0.0 or normal!=Vector((0,0,1)):
1240 obj = bpy.context.object
1241 transform(normal, angle, obj)
1242 return
1245 # class CTolerance(CEntity):
1246 # 3 : 'style',
1247 # 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
1248 # 11 : 'direction.x', 21 : 'direction.y', 31 : 'direction.z',
1251 class CTolerance(CEntity):
1252 def __init__(self):
1253 CEntity.__init__(self, 'TOLERANCE', None)
1254 self.stype = ""
1255 self.insertion_point = Vector()
1256 self.direction = Vector()
1259 # class CTrace(CEntity):
1260 # 10 : 'point0.x', 20 : 'point0.y', 30 : 'point0.z',
1261 # 11 : 'point1.x', 21 : 'point1.y', 31 : 'point1.z',
1262 # 12 : 'point2.x', 22 : 'point2.y', 32 : 'point2.z',
1263 # 13 : 'point3.x', 23 : 'point3.y', 33 : 'point3.z',
1264 # 39 : 'thickness',
1267 class CTrace(CEntity):
1268 def __init__(self):
1269 CEntity.__init__(self, 'TRACE', 'Mesh')
1270 self.point0 = Vector()
1271 self.point1 = Vector()
1272 self.point2 = Vector()
1273 self.point3 = Vector()
1274 self.normal = Vector((0,0,1))
1275 self.thickness = 0.0
1277 def display(self):
1278 CEntity.display(self)
1279 print(self.point0)
1280 print(self.point1)
1281 print(self.point2)
1282 print(self.point3)
1284 def build(self, vn=0):
1285 points, edges, faces = [],[],[]
1286 if self.point2 == self.point3:
1287 points = [self.point0, self.point2, self.point1]
1288 else:
1289 points = [self.point0, self.point2, self.point1, self.point3]
1290 pn = len(points)
1291 v0 = vn
1292 thic = self.thickness
1293 t_vector = Vector((0, 0, thic))
1294 if thic != 0 and (toggle & T_ThicON):
1295 thic_points = [v + t_vector for v in points]
1296 if thic < 0.0:
1297 thic_points.extend(points)
1298 points = thic_points
1299 else:
1300 points.extend(thic_points)
1302 if pn == 4:
1303 faces = [[0,1,3,2], [4,6,7,5], [0,4,5,1],
1304 [1,5,7,3], [3,7,6,2], [2,6,4,0]]
1305 elif pn == 3:
1306 faces = [[0,1,2], [3,5,4], [0,3,4,1], [1,4,5,2], [2,5,3,0]]
1307 elif pn == 2: faces = [[0,1,3,2]]
1308 vn += 2*pn
1309 else:
1310 if pn == 4: faces = [[0,2,3,1]]
1311 elif pn == 3: faces = [[0,2,1]]
1312 elif pn == 2:
1313 edges = [[0,1]]
1314 self.drawtype = 'Mesh'
1315 if self.normal!=Vector((0,0,1)):
1316 ma = getOCS(self.normal)
1317 if ma:
1318 points = [ma * v for v in points]
1319 return ((points, edges, faces, vn))
1322 # class CVertex(CEntity):
1323 # 10 : 'location.x', 20 : 'location.y', 30 : 'location.z',
1324 # 40 : 'start_width', 41 : 'end_width', 42 : 'bulge',
1325 # 50 : 'tangent',
1326 # 70 : 'flags',
1327 # 71 : 'index1', 72 : 'index2', 73 : 'index3', 74 : 'index4',
1330 class CVertex(CEntity):
1331 def __init__(self):
1332 CEntity.__init__(self, 'VERTEX', None)
1333 self.location = Vector()
1334 self.start_width = 0.0
1335 self.end_width = 0.0
1336 self.bulge = 0.0
1337 self.tangent = 0.0
1338 self.flags = 0
1340 def display(self):
1341 return
1343 def draw(self):
1344 return
1347 # class CViewPort(CEntity):
1348 # 10 : 'center.x', 20 : 'center.y', 30 : 'center.z',
1349 # 12 : 'view_center.x', 22 : 'view_center.y', 32 : 'view_center.z',
1350 # 13 : 'snap_base.x', 23 : 'snap_base.y', 33 : 'snap_base.z',
1351 # 14 : 'snap_spacing.x', 24 : 'snap_spacing.y', 34 : 'snap_spacing.z',
1352 # 15 : 'grid_spacing.x', 25 : 'grid_spacing.y', 35 : 'grid_spacing.z',
1353 # 16 : 'view_direction.x', 26 : 'view_direction.y', 36 : 'view_direction.z',
1354 # 40 : 'width', 41 : 'height',
1355 # 68 : 'status', 69 : 'id',
1358 class CViewPort(CEntity):
1359 def __init__(self):
1360 CEntity.__init__(self, 'VIEWPORT', None)
1361 self.center = Vector()
1362 self.view_center = Vector()
1363 self.snap_base = Vector()
1364 self.snap_spacing = Vector()
1365 self.grid_spacing = Vector()
1366 self.view_direction = Vector()
1367 self.width = 1.0
1368 self.height = 1.0
1369 self.status = 0
1370 self.id = 0
1372 def draw(self):
1373 # Todo
1374 return
1377 # class CWipeOut(CEntity):
1378 # 10 : 'point.x', 20 : 'point.y', 30 : 'point.z',
1379 # 11 : 'direction.x', 21 : 'direction.y', 31 : 'direction.z',
1382 class CWipeOut(CEntity):
1383 def __init__(self):
1384 CEntity.__init__(self, 'WIPEOUT', None)
1385 self.point = Vector()
1386 self.direction = Vector()
1391 WORLDX = Vector((1.0,0.0,0.0))
1392 WORLDY = Vector((0.0,1.0,0.0))
1393 WORLDZ = Vector((0.0,0.0,1.0))
1396 def getOCS(az): #-----------------------------------------------------------------
1397 """An implimentation of the Arbitrary Axis Algorithm.
1399 #decide if we need to transform our coords
1400 #if az[0] == 0 and az[1] == 0:
1401 if abs(az.x) < 0.00001 and abs(az.y) < 0.00001:
1402 if az.z > 0.0:
1403 return False
1404 elif az.z < 0.0:
1405 return Matrix((-WORLDX, WORLDY*1, -WORLDZ)).transposed()
1407 cap = 0.015625 # square polar cap value (1/64.0)
1408 if abs(az.x) < cap and abs(az.y) < cap:
1409 ax = WORLDY.cross(az)
1410 else:
1411 ax = WORLDZ.cross(az)
1412 ax.normalize()
1413 ay = az.cross(ax)
1414 ay.normalize()
1415 # Matrices are now constructed from rows, transpose to make the rows into cols
1416 return Matrix((ax, ay, az)).transposed()
1420 def transform(normal, rotation, obj): #--------------------------------------------
1421 """Use the calculated ocs to determine the objects location/orientation in space.
1423 ma = Matrix()
1424 o = Vector(obj.location)
1425 ma_new = getOCS(normal)
1426 if ma_new:
1427 ma_new.resize_4x4()
1428 ma = ma_new
1429 o = ma * o
1431 if rotation != 0:
1432 rmat = Matrix.Rotation(radians(rotation), 4, 'Z')
1433 ma = ma * rmat
1435 obj.matrix_world = ma
1436 obj.location = o
1439 DxfEntityAttributes = {
1440 '3DFACE' : {
1441 10 : 'point0.x', 20 : 'point0.y', 30 : 'point0.z',
1442 11 : 'point1.x', 21 : 'point1.y', 31 : 'point1.z',
1443 12 : 'point2.x', 22 : 'point2.y', 32 : 'point2.z',
1444 13 : 'point3.x', 23 : 'point3.y', 33 : 'point3.z',
1445 70 : 'flags',
1448 '3DSOLID' : {
1449 1 : 'data', 3 : 'more', 70 : 'version',
1452 'ACAD_PROXY_ENTITY' : {
1453 70 : 'format',
1454 90 : 'id', 91 : 'class', 92 : 'graphics_size', 93 : 'entity_size', 95: 'format',
1455 310 : 'data', 330 : 'id1', 340 : 'id2', 350 : 'id3', 360 : 'id4',
1458 'ARC' : {
1459 10 : 'center.x', 20 : 'center.y', 30 : 'center.z',
1460 40 : 'radius',
1461 50 : 'start_angle', 51 : 'end_angle',
1462 39 : 'thickness',
1463 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1466 'ARCALIGNEDTEXT' : {
1467 1 : 'text', 2 : 'font', 3 : 'bigfont', 7 : 'style',
1468 10 : 'center.x', 20 : 'center.y', 30 : 'center.z',
1469 40 : 'radius', 41 : 'width', 42 : 'height', 43 : 'spacing',
1470 44 : 'offset', 45 : 'right_offset', 46 : 'left_offset',
1471 50 : 'start_angle', 51 : 'end_angle',
1472 70 : 'order', 71 : 'direction', 72 : 'alignment', 73 : 'side',
1473 74 : 'bold', 75 : 'italic', 76 : 'underline',
1474 77 : 'character_set', 78 : 'pitch', 79 : 'fonttype',
1475 90 : 'color',
1476 280 : 'wizard', 330 : 'id'
1479 'ATTDEF' : {
1480 1 : 'text', 2 : 'tag', 3 : 'prompt', 7 : 'style',
1481 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
1482 11 : 'alignment_point.x', 21 : 'alignment_point.y', 31 : 'alignment_point.z',
1483 40 : 'height', 41 : 'x_scale',
1484 50 : 'rotation_angle', 51 : 'oblique_angle',
1485 70 : 'flags', 71 : 'text_generation_flags',
1486 72 : 'horizontal_justification', 74 : 'vertical_justification',
1490 'ATTRIB' : {
1491 1 : 'text', 2 : 'tag', 3 : 'prompt', 7 : 'style',
1492 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
1493 11 : 'alignment_point.x', 21 : 'alignment_point.y', 31 : 'alignment_point.z',
1494 40 : 'height', 41 : 'x_scale',
1495 50 : 'rotation_angle', 51 : 'oblique_angle',
1496 70 : 'flags', 73 : 'length',
1497 71 : 'text_generation_flags', 72 : 'horizontal_justification', 74 : 'vertical_justification',
1500 'BLOCK' : {
1501 1 : 'xref', 2 : 'name', 3 : 'also_name',
1502 10 : 'base_point.x', 20 : 'base_point.y', 30 : 'base_point.z',
1503 40 : 'size', 41 : 'x_scale',
1504 50 : 'rotation_angle', 51 : 'oblique_angle',
1505 70 : 'flags',
1508 'CIRCLE' : {
1509 10 : 'center.x', 20 : 'center.y', 30 : 'center.z',
1510 40 : 'radius',
1511 39 : 'thickness',
1512 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1515 'DIMENSION' : {
1516 1 : 'text', 2 : 'name', 3 : 'style',
1517 10 : 'def_point.x', 20 : 'def_point.y', 30 : 'def_point.z',
1518 11 : 'mid_point.x', 21 : 'mid_point.y', 31 : 'mid_point.z',
1519 12 : 'vector.x', 22 : 'vector.y', 32 : 'vector.z',
1520 13 : 'def_point2.x', 23 : 'def_point2.y', 33 : 'def_point2.z',
1521 14 : 'vector2.x', 24 : 'vector2.y', 34 : 'vector2.z',
1522 15 : 'vector3.x', 25 : 'vector3.y', 35 : 'vector3.z',
1523 16 : 'vector4.x', 26 : 'vector4.y', 36 : 'vector4.z',
1524 70 : 'dimtype',
1527 'ELLIPSE' : {
1528 10 : 'center.x', 20 : 'center.y', 30 : 'center.z',
1529 11 : 'end_point.x', 21 : 'end_point.y', 31 : 'end_point.z',
1530 40 : 'ratio', 41 : 'start', 42 : 'end',
1531 39 : 'thickness',
1532 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1535 'HATCH' : {
1536 2 : 'pattern',
1537 10 : 'point.x', 20 : 'point.y', 30 : 'point.z',
1538 41 : 'scale', 47 : 'pixelsize', 52 : 'angle',
1539 70 : 'fill', 71 : 'associativity', 75: 'style', 77 : 'double',
1540 78 : 'numlines', 91 : 'numpaths', 98 : 'numseeds',
1541 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1544 'IMAGE' : {
1545 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
1546 11 : 'u_vector.x', 21 : 'u_vector.y', 31 : 'u_vector.z',
1547 12 : 'v_vector.x', 22 : 'v_vector.y', 32 : 'v_vector.z',
1548 13 : 'size.x', 23 : 'size.y', 33 : 'size.z',
1549 14 : 'clip.x', 24 : 'clip.y', 34 : 'clip.z',
1550 70 : 'display', 71 : 'cliptype',
1551 90 : 'version',
1552 280 : 'clipstate', 281 : 'brightness', 282 : 'contrast', 283 : 'fade',
1553 340 : 'image', 360 : 'reactor',
1556 'INSERT' : {
1557 1 : 'attributes_follow', 2 : 'name',
1558 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
1559 41 : 'x_scale', 42 : 'y_scale', 43 : 'z_scale',
1560 44 : 'column_spacing', 45 : 'row_spacing',
1561 50 : 'rotation_angle', 66 : 'attributes_follow',
1562 70 : 'column_count', 71 : 'row_count',
1563 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1566 'LEADER' : {
1567 3 : 'style',
1568 10 : ['new_vertex(data)'], 20 : 'vertex.y', 30 : 'vertex.z',
1569 40 : 'height', 41 : 'width',
1570 71 : 'arrowhead', 72 : 'pathtype', 73 : 'creation',
1571 74 : 'hookdir', 75 : 'hookline', 76 : 'numverts', 77 : 'color',
1572 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1573 211 : 'horizon.x', 221 : 'horizon.y', 231 : 'horizon.z',
1574 212 : 'offset_ins.x', 222 : 'offset_ins.y', 232 : 'offset_ins.z',
1575 213 : 'offset_ann.x', 223 : 'offset_ann.y', 233 : 'offset_ann.z',
1578 'LINE' : {
1579 10 : 'start_point.x', 20 : 'start_point.y', 30 : 'start_point.z',
1580 11 : 'end_point.x', 21 : 'end_point.y', 31 : 'end_point.z',
1581 39 : 'thickness',
1582 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1585 'LWPOLYLINE' : {
1586 10 : ['new_vertex(data)'], 20 : 'vertex.y', 30 : 'vertex.z',
1587 38 : 'elevation', 39 : 'thickness',
1588 40 : 'start_width', 41 : 'end_width', 42 : 'bulge', 43 : 'constant_width',
1589 70 : 'flags', 90 : 'numverts',
1590 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1593 'MLINE' : {
1594 10 : 'start_point.x', 20 : 'start_point.y', 30 : 'start_point.z',
1595 11 : ['new_vertex(data)'], 21 : 'vertex.y', 31 : 'vertex.z',
1596 12 : ['new_seg_dir(data)'], 22 : 'seg_dir.y', 32 : 'seg_dir.z',
1597 13 : ['new_miter_dir(data)'], 23 : 'miter_dir.y', 33 : 'miter_dir.z',
1598 39 : 'thickness',
1599 40 : 'scale', 41 : 'elem_param', 42 : 'fill_param',
1600 70 : 'justification', 71 : 'flags',
1601 72 : 'numverts', 73 : 'numelems', 74 : 'numparam', 75 : 'numfills',
1602 340 : 'id',
1603 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1606 'MTEXT' : {
1607 1 : 'text', 3: 'more_text', 7 : 'style',
1608 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
1609 11 : 'alignment_point.x', 21 : 'alignment_point.y', 31 : 'alignment_point.z',
1610 40 : 'nominal_height', 41 : 'reference_width', 42: 'width', 43 : 'height', 44 : 'line_spacing',
1611 50 : 'rotation_angle',
1612 71 : 'attachment_point', 72 : 'drawing_direction', 73 : 'spacing_style',
1613 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1616 'POINT' : {
1617 10 : 'point.x', 20 : 'point.y', 30 : 'point.z',
1618 39 : 'thickness', 50 : 'orientation',
1621 'POLYLINE' : {
1622 1 : 'verts_follow', 2 : 'name',
1623 10 : 'elevation.x', 20 : 'elevation.y', 30 : 'elevation.z',
1624 39 : 'thickness',
1625 40 : 'start_width', 41 : 'end_width',
1626 66 : 'verts_follow_flag',
1627 70 : 'flags', 71 : 'row_count', 72 : 'column_count',
1628 73 : 'row_density', 74 : 'column_density', 75 : 'linetype',
1629 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1632 'RAY' : {
1633 10 : 'point.x', 20 : 'point.y', 30 : 'point.z',
1634 11 : 'direction.x', 21 : 'direction.y', 31 : 'direction.z',
1637 'RTEXT' : {
1638 1 : 'text', 7 : 'style',
1639 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
1640 39 : 'thickness',
1641 40 : 'height',
1642 50 : 'rotation_angle',
1643 70 : 'flags',
1644 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1647 'SHAPE' : {
1648 2 : 'name',
1649 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
1650 39 : 'thickness',
1651 40 : 'size', 41 : 'x_scale',
1652 50 : 'rotation_angle', 51 : 'oblique_angle',
1653 39 : 'thickness',
1656 'SOLID' : {
1657 10 : 'point0.x', 20 : 'point0.y', 30 : 'point0.z',
1658 11 : 'point1.x', 21 : 'point1.y', 31 : 'point1.z',
1659 12 : 'point2.x', 22 : 'point2.y', 32 : 'point2.z',
1660 13 : 'point3.x', 23 : 'point3.y', 33 : 'point3.z',
1661 39 : 'thickness',
1662 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1665 'SPLINE' : {
1666 10 : ['new_control_point(data)'], 20 : 'control_point.y', 30 : 'control_point.z',
1667 11 : ['new_fit_point(data)'], 21 : 'fit_point.y', 31 : 'fit_point.z',
1668 40 : ['new_knot_value(data)'],
1669 12 : 'start_tangent.x', 22 : 'start_tangent.y', 32 : 'start_tangent.z',
1670 13 : 'end_tangent.x', 23 : 'end_tangent.y', 33 : 'end_tangent.z',
1671 39 : 'thickness',
1672 41 : 'weight', 42 : 'knot_tol', 43 : 'control_point_tol', 44 : 'fit_tol',
1673 70 : 'flag', 71 : 'degree',
1674 72 : 'num_knots', 73 : 'num_control_points', 74 : 'num_fit_points',
1675 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1678 'TEXT' : {
1679 1 : 'text', 7 : 'style',
1680 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
1681 11 : 'alignment_point.x', 21 : 'alignment_point.y', 31 : 'alignment_point.z',
1682 40 : 'height', 41 : 'x_scale',
1683 50 : 'rotation_angle', 51 : 'oblique_angle',
1684 71 : 'flags', 72 : 'horizontal_justification', 73 : 'vertical_justification',
1685 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1688 'TOLERANCE' : {
1689 3 : 'style',
1690 10 : 'insertion_point.x', 20 : 'insertion_point.y', 30 : 'insertion_point.z',
1691 11 : 'direction.x', 21 : 'direction.y', 31 : 'direction.z',
1694 'TRACE' : {
1695 10 : 'point0.x', 20 : 'point0.y', 30 : 'point0.z',
1696 11 : 'point1.x', 21 : 'point1.y', 31 : 'point1.z',
1697 12 : 'point2.x', 22 : 'point2.y', 32 : 'point2.z',
1698 13 : 'point3.x', 23 : 'point3.y', 33 : 'point3.z',
1699 39 : 'thickness',
1700 210 : 'normal.x', 220 : 'normal.y', 230 : 'normal.z',
1703 'VERTEX' : {
1704 10 : 'location.x', 20 : 'location.y', 30 : 'location.z',
1705 40 : 'start_width', 41 : 'end_width', 42 : 'bulge',
1706 50 : 'tangent',
1707 70 : 'flags',
1708 71 : 'index1', 72 : 'index2', 73 : 'index3', 74 : 'index4',
1711 'VIEWPORT' : {
1712 10 : 'center.x', 20 : 'center.y', 30 : 'center.z',
1713 12 : 'view_center.x', 22 : 'view_center.y', 32 : 'view_center.z',
1714 13 : 'snap_base.x', 23 : 'snap_base.y', 33 : 'snap_base.z',
1715 14 : 'snap_spacing.x', 24 : 'snap_spacing.y', 34 : 'snap_spacing.z',
1716 15 : 'grid_spacing.x', 25 : 'grid_spacing.y', 35 : 'grid_spacing.z',
1717 16 : 'view_direction.x', 26 : 'view_direction.y', 36 : 'view_direction.z',
1718 40 : 'width', 41 : 'height',
1719 68 : 'status', 69 : 'id',
1722 'WIPEOUT' : {
1723 10 : 'point.x', 20 : 'point.y', 30 : 'point.z',
1724 11 : 'direction.x', 21 : 'direction.y', 31 : 'direction.z',
1731 # Flags
1734 # Polyline flags
1735 PL_CLOSED = 0x01
1736 PL_CURVE_FIT_VERTS = 0x02
1737 PL_SPLINE_FIT_VERTS = 0x04
1738 PL_3D_POLYLINE = 0x08
1739 PL_3D_POLYGON_MESH = 0x10
1740 PL_CLOSED_IN_N_DIR = 0x20
1741 PL_POLYFACE_MESH = 0x40
1742 PL_CONTINUOUS = 0x80
1745 # Vertex flags
1746 VX_EXTRA_FLAG_CREATED = 0x01
1747 VX_CURVE_FIT_TANGENT_DEFINED = 0x02
1748 VX_SPLINE_VERTEX_CREATED = 0x08
1749 VX_SPLINE_FRAME_CONTROL_POINT = 0x10
1750 VX_3D_POLYLINE_VERTEX = 0x20
1751 VX_3D_POLYGON_MESH_VERTEX = 0x40
1752 VX_POLYFACE_MESH_VERTEX = 0x80
1754 # 3DFACE flags
1756 F3D_EDGE0_INVISIBLE = 0x01
1757 F3D_EDGE1_INVISIBLE = 0x02
1758 F3D_EDGE2_INVISIBLE = 0x04
1759 F3D_EDGE3_INVISIBLE = 0x08
1762 # readDxfFile(filePath):
1765 def readDxfFile(fileName):
1766 global toggle, theCodec
1768 print( "Opening DXF file "+ fileName )
1770 # fp= open(fileName, "rU")
1771 fp = codecs.open(fileName, "r", encoding=theCodec)
1772 first = True
1773 statements = []
1774 no = 0
1775 for line in fp:
1776 word = line.strip()
1777 no += 1
1778 if first:
1779 if word:
1780 code = int(word)
1781 first = False
1782 else:
1783 if toggle & T_Verbose:
1784 print("%4d: %4d %s" % (no, code, word))
1785 if code < 10:
1786 data = word
1787 elif code < 60:
1788 data = float(word)
1789 elif code < 100:
1790 data = int(word)
1791 elif code < 140:
1792 data = word
1793 elif code < 150:
1794 data = float(word)
1795 elif code < 200:
1796 data = int(word)
1797 elif code < 300:
1798 data = float(word)
1799 elif code < 370:
1800 data = word
1801 elif code < 390:
1802 data = int(word)
1803 elif code < 400:
1804 data = word
1805 elif code < 410:
1806 data = int(word)
1807 elif code < 1010:
1808 data = word
1809 elif code < 1060:
1810 data = float(word)
1811 elif code < 1080:
1812 data = int(word)
1814 statements.append((code,data))
1815 first = True
1816 fp.close()
1818 statements.reverse()
1819 sections = {}
1820 handles = {}
1821 while statements:
1822 (code,data) = statements.pop()
1823 if code == 0:
1824 if data == 'SECTION':
1825 section = CSection()
1826 elif code == 2:
1827 section.type = data
1828 if data == 'HEADER':
1829 parseHeader(section, statements, handles)
1830 known = False
1831 elif data == 'CLASSES':
1832 parseClasses(section, statements, handles)
1833 known = False
1834 elif data == 'TABLES':
1835 parseTables(section, statements, handles)
1836 known = False
1837 elif data == 'BLOCKS':
1838 parseBlocks(section, statements, handles)
1839 known = False
1840 elif data == 'ENTITIES':
1841 parseEntities(section, statements, handles)
1842 known = False
1843 elif data == 'OBJECTS':
1844 parseObjects(section, statements, handles)
1845 elif data == 'THUMBNAILIMAGE':
1846 parseThumbnail(section, statements, handles)
1847 sections[data] = section
1848 elif code == 999:
1849 pass
1850 else:
1851 raise NameError("Unexpected code in SECTION context: %d %s" % (code,data))
1853 if toggle & T_Verbose:
1854 for (typ,section) in sections.items():
1855 section.display()
1856 return sections
1861 # SECTION
1863 # HEADER
1866 # $<variable>
1867 # <group code>
1868 # <value>
1871 # ENDSEC
1874 def parseHeader(section, statements, handles):
1875 while statements:
1876 (code,data) = statements.pop()
1877 if code == 0:
1878 if data == 'ENDSEC':
1879 return
1881 return
1885 # SECTION
1887 # CLASSES
1890 # CLASS
1892 # <class dxf record>
1894 # <class name>
1896 # <app name>
1897 # 90
1898 # <flag>
1899 # 280
1900 # <flag>
1901 # 281
1902 # <flag>
1905 # ENDSEC
1907 def parseClasses(section, statements, handles):
1908 while statements:
1909 (code,data) = statements.pop()
1910 if code == 0:
1911 if data == 'ENDSEC':
1912 return
1914 return
1918 # SECTION
1920 # TABLES
1923 # TABLE
1925 # <table type>
1927 # <handle>
1928 # 100
1929 # AcDbSymbolTable
1930 # 70
1931 # <max. entries>
1934 # <table type>
1936 # <handle>
1937 # 100
1938 # AcDbSymbolTableRecord
1940 # . <data>
1944 # ENDTAB
1947 # ENDSEC
1950 # APPID (application identification table)
1952 # BLOCK_RECORD (block reference table)
1954 # DIMSTYLE (dimension style table)
1956 # LAYER (layer table)
1958 # LTYPE (linetype table)
1960 # STYLE (text style table)
1962 # UCS (User Coordinate System table)
1964 # VIEW (view table)
1966 # VPORT (viewport configuration table)
1969 def parseTables(section, statements, handles):
1970 tables = []
1971 section.data = tables
1972 while statements:
1973 (code,data) = statements.pop()
1974 if code == 0:
1975 if data == 'ENDSEC':
1976 return
1978 known = False
1979 elif data == 'TABLE':
1980 table = CTable()
1981 tables.append(table)
1982 known = False
1983 elif data == 'ENDTAB':
1984 pass
1985 known = False
1986 elif data == table.type:
1987 parseTableType
1988 table = CTable()
1989 tables.append(table)
1990 table.type = word
1991 elif code == 2:
1992 table.type = word
1993 elif code == 5:
1994 table.handle = word
1995 handles[word] = table
1996 elif code == 330:
1997 table.owner = word
1998 elif code == 100:
1999 table.subclass = word
2000 elif code == 70:
2001 table.nEntries = int(word)
2003 return
2006 # SECTION
2008 # BLOCKS
2011 # BLOCK
2013 # <handle>
2014 # 100
2015 # AcDbEntity
2017 # <layer>
2018 # 100
2019 # AcDbBlockBegin
2021 # <block name>
2022 # 70
2023 # <flag>
2024 # 10
2025 # <X value>
2026 # 20
2027 # <Y value>
2028 # 30
2029 # <Z value>
2031 # <block name>
2033 # <xref path>
2036 # <entity type>
2038 # . <data>
2042 # ENDBLK
2044 # <handle>
2045 # 100
2046 # AcDbBlockEnd
2049 # ENDSEC
2051 def parseBlocks(section, statements, handles):
2052 while statements:
2053 (code,data) = statements.pop()
2054 if code == 0:
2055 if data == 'ENDSEC':
2056 return
2058 return
2061 # SECTION
2063 # ENTITIES
2066 # <entity type>
2068 # <handle>
2069 # 330
2070 # <pointer to owner>
2071 # 100
2072 # AcDbEntity
2074 # <layer>
2075 # 100
2076 # AcDb<classname>
2078 # . <data>
2082 # ENDSEC
2084 Ignorables = ['DIMENSION', 'TEXT', 'VIEWPORT']
2086 ClassCreators = {
2087 '3DFACE': 'C3dFace()',
2088 '3DSOLID': 'C3dSolid()',
2089 'ACAD_PROXY_ENTITY': 'CAcadProxyEntity()',
2090 'ACAD_ZOMBIE_ENTITY': 0,
2091 'ARC': 'CArc()',
2092 'ARCALIGNEDTEXT': 'CArcAlignedText()',
2093 'ATTDEF': 'CAttdef()',
2094 'ATTRIB': 'CAttrib()',
2095 'BODY': 0,
2096 'CIRCLE': 'CCircle()',
2097 'DIMENSION': 'CDimension()',
2098 'ELLIPSE': 'CEllipse()',
2099 'HATCH': 'CHatch()',
2100 'IMAGE': 'CImage()',
2101 'INSERT': 'CInsert()',
2102 'LEADER': 'CLeader()',
2103 'LINE': 'CLine()',
2104 'LWPOLYLINE': 'CLWPolyLine()',
2105 'MLINE': 'CMLine()',
2106 'MTEXT': 'CMText()',
2107 'OLEFRAME': 0,
2108 'OLE2FRAME': 0,
2109 'POINT': 'CPoint()',
2110 'POLYLINE': 'CPolyLine()',
2111 'RAY': 'CRay()',
2112 'REGION': 0,
2113 'RTEXT': 'CRText',
2114 'SEQEND': 0,
2115 'SHAPE': 'CShape()',
2116 'SOLID': 'CSolid()',
2117 'SPLINE': 'CSpline()',
2118 'TEXT': 'CText()',
2119 'TOLERANCE': 'CTolerance()',
2120 'TRACE': 'CTrace()',
2121 'VERTEX': 'CVertex()',
2122 'VIEWPORT': 'CViewPort()',
2123 'WIPEOUT': 'CWipeOut()',
2124 'XLINE': 'CXLine()',
2127 def parseEntities(section, statements, handles):
2128 entities = []
2129 section.data = entities
2130 while statements:
2131 (code,data) = statements.pop()
2132 if toggle & T_Verbose:
2133 print("ent", code,data)
2134 if code == 0:
2135 known = True
2136 if data in Ignorables:
2137 ignore = True
2138 else:
2139 ignore = False
2141 try:
2142 creator = ClassCreators[data]
2143 except:
2144 creator = None
2146 if creator:
2147 entity = eval(creator)
2148 elif data == 'ENDSEC':
2149 return
2150 else:
2151 known = False
2153 if data == 'POLYLINE':
2154 verts = entity.verts
2155 elif data == 'VERTEX':
2156 verts.append(entity)
2158 if data == 'SEQEND':
2159 attributes = []
2160 known = False
2161 elif creator == 0:
2162 ignore = True
2163 elif known:
2164 entities.append(entity)
2165 attributes = DxfEntityAttributes[data]
2166 else:
2167 raise NameError("Unknown data %s" % data)
2169 elif not known:
2170 pass
2171 else:
2172 expr = getAttribute(attributes, code)
2173 if expr:
2174 exec(expr)
2175 else:
2176 expr = getAttribute(DxfCommonAttributes, code)
2177 if expr:
2178 exec(expr)
2179 elif code >= 1000 or ignore:
2180 pass
2181 elif toggle & T_Debug:
2182 raise NameError("Unknown code %d for %s" % (code, entity.type))
2184 return
2186 def getAttribute(attributes, code):
2187 try:
2188 ext = attributes[code]
2189 if type(ext) == str:
2190 expr = "entity.%s = data" % ext
2191 else:
2192 name = ext[0]
2193 expr = "entity.%s" % name
2194 except:
2195 expr = None
2196 return expr
2200 # SECTION
2202 # OBJECTS
2205 # DICTIONARY
2207 # <handle>
2208 # 100
2209 # AcDbDictionary
2212 # <dictionary name>
2213 # 350
2214 # <handle of child>
2217 # <object type>
2219 # . <data>
2223 # ENDSEC
2225 def parseObjects(data, statements, handles):
2226 while statements:
2227 (code,data) = statements.pop()
2228 if code == 0:
2229 if data == 'ENDSEC':
2230 return
2232 return
2235 # THUMBNAILIMAGE
2236 # 90
2237 # 45940
2238 # 310
2239 # 28000000B40000005500000001001800000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
2240 # 310
2241 # FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
2242 # 310
2243 # .......
2245 # ENDSEC
2247 def parseThumbnail(section, statements, handles):
2248 """ Just skip these """
2249 while statements:
2250 (code,data) = statements.pop()
2251 if code == 0:
2252 if data == 'ENDSEC':
2253 return
2255 return
2258 # buildGeometry(entities):
2259 # addMesh(name, verts, edges, faces):
2262 def buildGeometry(entities):
2263 try: bpy.ops.object.mode_set(mode='OBJECT')
2264 except: pass
2265 v_verts = []
2266 v_vn = 0
2267 e_verts = []
2268 e_edges = []
2269 e_vn = 0
2270 f_verts = []
2271 f_edges = []
2272 f_faces = []
2273 f_vn = 0
2274 for ent in entities:
2275 if ent.drawtype in {'Mesh', 'Curve'}:
2276 (verts, edges, faces, vn) = ent.build()
2277 if not toggle & T_DrawOne:
2278 drawGeometry(verts, edges, faces)
2279 else:
2280 if verts:
2281 if faces:
2282 for i,f in enumerate(faces):
2283 #print ('face=', f)
2284 faces[i] = tuple(it+f_vn for it in f)
2285 for i,e in enumerate(edges):
2286 edges[i] = tuple(it+f_vn for it in e)
2287 f_verts.extend(verts)
2288 f_edges.extend(edges)
2289 f_faces.extend(faces)
2290 f_vn += len(verts)
2291 elif edges:
2292 for i,e in enumerate(edges):
2293 edges[i] = tuple(it+e_vn for it in e)
2294 e_verts.extend(verts)
2295 e_edges.extend(edges)
2296 e_vn += len(verts)
2297 else:
2298 v_verts.extend(verts)
2299 v_vn += len(verts)
2300 else:
2301 ent.draw()
2303 if toggle & T_DrawOne:
2304 drawGeometry(f_verts, f_edges, f_faces)
2305 drawGeometry(e_verts, e_edges)
2306 drawGeometry(v_verts)
2310 def drawGeometry(verts, edges=[], faces=[]):
2311 if verts:
2312 if edges and (toggle & T_Curves):
2313 print ('draw Curve')
2314 cu = bpy.data.curves.new('DXFlines', 'CURVE')
2315 cu.dimensions = '3D'
2316 buildSplines(cu, verts, edges)
2317 ob = addObject('DXFlines', cu)
2318 else:
2319 #for v in verts: print(v)
2320 #print ('draw Mesh with %s vertices' %(len(verts)))
2321 #for e in edges: print(e)
2322 #print ('draw Mesh with %s edges' %(len(edges)))
2323 #for f in faces: print(f)
2324 #print ('draw Mesh with %s faces' %(len(faces)))
2325 me = bpy.data.meshes.new('DXFmesh')
2326 me.from_pydata(verts, edges, faces)
2327 ob = addObject('DXFmesh', me)
2328 removeDoubles(ob)
2329 return
2333 def buildSplines(cu, verts, edges):
2334 if edges:
2335 point_list = []
2336 (v0,v1) = edges.pop()
2337 v1_old = v1
2338 newPoints = [tuple(verts[v0]),tuple(verts[v1])]
2339 for (v0,v1) in edges:
2340 if v0==v1_old:
2341 newPoints.append(tuple(verts[v1]))
2342 else:
2343 #print ('newPoints=', newPoints)
2344 point_list.append(newPoints)
2345 newPoints = [tuple(verts[v0]),tuple(verts[v1])]
2346 v1_old = v1
2347 point_list.append(newPoints)
2348 for points in point_list:
2349 spline = cu.splines.new('POLY')
2350 #spline = cu.splines.new('BEZIER')
2351 #spline.use_endpoint_u = True
2352 #spline.order_u = 2
2353 #spline.resolution_u = 1
2354 #spline.bezier_points.add(2)
2356 spline.points.add(len(points)-1)
2357 #spline.points.foreach_set('co', points)
2358 for i,p in enumerate(points):
2359 spline.points[i].co = (p[0],p[1],p[2],0)
2361 #print ('spline.type=', spline.type)
2362 #print ('spline number=', len(cu.splines))
2365 def addObject(name, data):
2366 ob = bpy.data.objects.new(name, data)
2367 scn = bpy.context.scene
2368 scn.objects.link(ob)
2369 return ob
2372 def removeDoubles(ob):
2373 global theMergeLimit
2374 if toggle & T_Merge:
2375 scn = bpy.context.scene
2376 scn.objects.active = ob
2377 bpy.ops.object.mode_set(mode='EDIT')
2378 bpy.ops.mesh.remove_doubles(threshold=theMergeLimit)
2379 bpy.ops.object.mode_set(mode='OBJECT')
2384 # clearScene(context):
2387 def clearScene():
2388 global toggle
2389 scn = bpy.context.scene
2390 print("clearScene %s %s" % (toggle & T_NewScene, scn))
2391 if not toggle & T_NewScene:
2392 return scn
2394 for ob in scn.objects:
2395 if ob.type in ["MESH", "CURVE", "TEXT"]:
2396 scn.objects.active = ob
2397 bpy.ops.object.mode_set(mode='OBJECT')
2398 scn.objects.unlink(ob)
2399 del ob
2400 return scn
2403 # readAndBuildDxfFile(filepath):
2406 def readAndBuildDxfFile(filepath):
2407 fileName = os.path.expanduser(filepath)
2408 if fileName:
2409 (shortName, ext) = os.path.splitext(fileName)
2410 #print("filepath: ", filepath)
2411 #print("fileName: ", fileName)
2412 #print("shortName: ", shortName)
2413 if ext.lower() != ".dxf":
2414 print("Error: Not a dxf file: " + fileName)
2415 return
2416 if toggle & T_NewScene:
2417 clearScene()
2418 if 0: # how to switch to the new scene?? (migius)
2419 new_scn = bpy.data.scenes.new(shortName[-20:])
2420 #new_scn.layers = (1<<20) -1
2421 #new_scn_name = new_scn.name # UNUSED
2422 bpy.data.screens.scene = new_scn
2423 #print("newScene: %s" % (new_scn))
2424 sections = readDxfFile(fileName)
2425 print("Building geometry")
2426 buildGeometry(sections['ENTITIES'].data)
2427 print("Done")
2428 return
2429 print("Error: Not a dxf file: " + filepath)
2430 return
2433 # User interface
2436 DEBUG= False
2437 from bpy.props import *
2439 def tripleList(list1):
2440 list3 = []
2441 for elt in list1:
2442 list3.append((elt,elt,elt))
2443 return list3
2445 class IMPORT_OT_autocad_dxf(bpy.types.Operator):
2446 """Import from DXF file format (.dxf)"""
2447 bl_idname = "import_scene.autocad_dxf"
2448 bl_description = 'Import from DXF file format (.dxf)'
2449 bl_label = "Import DXF" +' v.'+ __version__
2450 bl_space_type = "PROPERTIES"
2451 bl_region_type = "WINDOW"
2452 bl_options = {'UNDO'}
2454 filepath = StringProperty(
2455 subtype='FILE_PATH',
2457 new_scene = BoolProperty(
2458 name="Replace scene",
2459 description="Replace scene",
2460 default=toggle & T_NewScene,
2462 #~ new_scene = BoolProperty(
2463 #~ name="New scene",
2464 #~ description="Create new scene",
2465 #~ default=toggle & T_NewScene,
2466 #~ )
2467 curves = BoolProperty(
2468 name="Draw curves",
2469 description="Draw entities as curves",
2470 default=toggle & T_Curves,
2472 thic_on = BoolProperty(
2473 name="Thick ON",
2474 description="Support THICKNESS",
2475 default=toggle & T_ThicON,
2477 merge = BoolProperty(
2478 name="Remove doubles",
2479 description="Merge coincident vertices",
2480 default=toggle & T_Merge,
2482 mergeLimit = FloatProperty(
2483 name="Limit",
2484 description="Merge limit * 0.0001",
2485 default=theMergeLimit * 1e4,
2486 min=1.0,
2487 soft_min=1.0,
2488 max=1000.0,
2489 soft_max=1000.0,
2491 draw_one = BoolProperty(
2492 name="Merge all",
2493 description="Draw all into one mesh object",
2494 default=toggle & T_DrawOne,
2496 circleResolution = IntProperty(
2497 name="Circle resolution",
2498 description="Circle/Arc are approximated with this factor",
2499 default=theCircleRes,
2500 min=4,
2501 soft_min=4,
2502 max=360,
2503 soft_max=360,
2505 codecs = tripleList(['iso-8859-15', 'utf-8', 'ascii'])
2506 codec = EnumProperty(name="Codec",
2507 description="Codec",
2508 items=codecs,
2509 default='ascii',
2511 debug = BoolProperty(
2512 name="Debug",
2513 description="Unknown DXF-codes generate errors",
2514 default=toggle & T_Debug,
2516 verbose = BoolProperty(
2517 name="Verbose",
2518 description="Print debug info",
2519 default=toggle & T_Verbose,
2522 ##### DRAW #####
2523 def draw(self, context):
2524 layout0 = self.layout
2525 #layout0.enabled = False
2527 #col = layout0.column_flow(2,align=True)
2528 layout = layout0.box()
2529 col = layout.column()
2530 #col.prop(self, 'KnotType') waits for more knottypes
2531 #col.label(text="import Parameters")
2532 #col.prop(self, 'replace')
2533 col.prop(self, 'new_scene')
2535 row = layout.row(align=True)
2536 row.prop(self, 'curves')
2537 row.prop(self, 'circleResolution')
2539 row = layout.row(align=True)
2540 row.prop(self, 'merge')
2541 if self.merge:
2542 row.prop(self, 'mergeLimit')
2544 row = layout.row(align=True)
2545 #row.label('na')
2546 row.prop(self, 'draw_one')
2547 row.prop(self, 'thic_on')
2549 col = layout.column()
2550 col.prop(self, 'codec')
2552 row = layout.row(align=True)
2553 row.prop(self, 'debug')
2554 if self.debug:
2555 row.prop(self, 'verbose')
2557 def execute(self, context):
2558 global toggle, theMergeLimit, theCodec, theCircleRes
2559 O_Merge = T_Merge if self.merge else 0
2560 #O_Replace = T_Replace if self.replace else 0
2561 O_NewScene = T_NewScene if self.new_scene else 0
2562 O_Curves = T_Curves if self.curves else 0
2563 O_ThicON = T_ThicON if self.thic_on else 0
2564 O_DrawOne = T_DrawOne if self.draw_one else 0
2565 O_Debug = T_Debug if self.debug else 0
2566 O_Verbose = T_Verbose if self.verbose else 0
2568 toggle = O_Merge | O_DrawOne | O_NewScene | O_Curves | O_ThicON | O_Debug | O_Verbose
2569 theMergeLimit = self.mergeLimit*1e-4
2570 theCircleRes = self.circleResolution
2571 theCodec = self.codec
2573 readAndBuildDxfFile(self.filepath)
2574 return {'FINISHED'}
2576 def invoke(self, context, event):
2577 wm = context.window_manager
2578 wm.fileselect_add(self)
2579 return {'RUNNING_MODAL'}
2582 def menu_func(self, context):
2583 self.layout.operator(IMPORT_OT_autocad_dxf.bl_idname, text="Autocad (.dxf)")
2586 def register():
2587 bpy.utils.register_module(__name__)
2589 bpy.types.INFO_MT_file_import.append(menu_func)
2592 def unregister():
2593 bpy.utils.unregister_module(__name__)
2595 bpy.types.INFO_MT_file_import.remove(menu_func)
2598 if __name__ == "__main__":
2599 register()