From 37939a32083be2ca80b296bd8b030bffaf65928d Mon Sep 17 00:00:00 2001 From: Lukas Treyer Date: Tue, 16 Aug 2016 18:24:32 +0200 Subject: updating to newest version of dxfgrabber; needed for further updates regarding inf.0 problem. --- io_import_dxf/__init__.py | 27 +- io_import_dxf/dxfgrabber/__init__.py | 2 +- io_import_dxf/dxfgrabber/acdsdata.py | 4 +- io_import_dxf/dxfgrabber/blockssection.py | 6 +- io_import_dxf/dxfgrabber/codepage.py | 0 io_import_dxf/dxfgrabber/color.py | 0 io_import_dxf/dxfgrabber/const.py | 0 io_import_dxf/dxfgrabber/cydxfentity.py | 7 - io_import_dxf/dxfgrabber/cytags.py | 7 - io_import_dxf/dxfgrabber/decode.py | 0 io_import_dxf/dxfgrabber/defaultchunk.py | 5 +- io_import_dxf/dxfgrabber/drawing.py | 4 +- io_import_dxf/dxfgrabber/dxf12.py | 202 ------- io_import_dxf/dxfgrabber/dxf13.py | 546 ------------------ io_import_dxf/dxfgrabber/dxfattr.py | 47 -- io_import_dxf/dxfgrabber/dxfentity.py | 84 --- io_import_dxf/dxfgrabber/entities.py | 930 ------------------------------ io_import_dxf/dxfgrabber/entitysection.py | 16 +- io_import_dxf/dxfgrabber/headersection.py | 7 +- io_import_dxf/dxfgrabber/juliandate.py | 0 io_import_dxf/dxfgrabber/layers.py | 90 +-- io_import_dxf/dxfgrabber/linetypes.py | 72 +-- io_import_dxf/dxfgrabber/pytags.py | 385 ------------- io_import_dxf/dxfgrabber/sections.py | 7 - io_import_dxf/dxfgrabber/styles.py | 91 ++- io_import_dxf/dxfgrabber/tablessection.py | 18 +- io_import_dxf/dxfgrabber/tags.py | 422 +++++++++++++- io_import_dxf/dxfimport/convert.py | 2 +- io_import_dxf/dxfimport/do.py | 18 +- io_import_dxf/dxfimport/fake_entities.py | 6 +- io_import_dxf/dxfimport/is_.py | 5 +- 31 files changed, 537 insertions(+), 2473 deletions(-) mode change 100755 => 100644 io_import_dxf/dxfgrabber/__init__.py mode change 100755 => 100644 io_import_dxf/dxfgrabber/acdsdata.py mode change 100755 => 100644 io_import_dxf/dxfgrabber/blockssection.py mode change 100755 => 100644 io_import_dxf/dxfgrabber/codepage.py mode change 100755 => 100644 io_import_dxf/dxfgrabber/color.py mode change 100755 => 100644 io_import_dxf/dxfgrabber/const.py delete mode 100755 io_import_dxf/dxfgrabber/cydxfentity.py delete mode 100755 io_import_dxf/dxfgrabber/cytags.py mode change 100755 => 100644 io_import_dxf/dxfgrabber/decode.py mode change 100755 => 100644 io_import_dxf/dxfgrabber/defaultchunk.py mode change 100755 => 100644 io_import_dxf/dxfgrabber/drawing.py delete mode 100755 io_import_dxf/dxfgrabber/dxf12.py delete mode 100755 io_import_dxf/dxfgrabber/dxf13.py delete mode 100755 io_import_dxf/dxfgrabber/dxfattr.py delete mode 100755 io_import_dxf/dxfgrabber/dxfentity.py delete mode 100755 io_import_dxf/dxfgrabber/entities.py mode change 100755 => 100644 io_import_dxf/dxfgrabber/entitysection.py mode change 100755 => 100644 io_import_dxf/dxfgrabber/juliandate.py mode change 100755 => 100644 io_import_dxf/dxfgrabber/layers.py mode change 100755 => 100644 io_import_dxf/dxfgrabber/linetypes.py delete mode 100755 io_import_dxf/dxfgrabber/pytags.py mode change 100755 => 100644 io_import_dxf/dxfgrabber/styles.py mode change 100755 => 100644 io_import_dxf/dxfgrabber/tablessection.py mode change 100755 => 100644 io_import_dxf/dxfgrabber/tags.py (limited to 'io_import_dxf') diff --git a/io_import_dxf/__init__.py b/io_import_dxf/__init__.py index 5d588f76..d768d624 100644 --- a/io_import_dxf/__init__.py +++ b/io_import_dxf/__init__.py @@ -22,7 +22,6 @@ import bpy import os from bpy.props import StringProperty, BoolProperty, EnumProperty, IntProperty, FloatProperty from .dxfimport.do import Do, Indicator -from .dxfgrabber.headersection import MinVersionError from .transverse_mercator import TransverseMercator @@ -114,20 +113,18 @@ def read(report, filename, obj_merge=BY_LAYER, import_text=True, import_light=Tr thicknessWidth=True, but_group_by_att=True, dxf_unit_scale=1.0): # import dxf and export nurbs types to sat/sab files # because that's how autocad stores nurbs types in a dxf... - try: - do = Do(filename, obj_merge, import_text, import_light, export_acis, merge_lines, do_bbox, block_rep, recenter, - projDXF, projSCN, thicknessWidth, but_group_by_att, dxf_unit_scale) - errors = do.entities(os.path.basename(filename).replace(".dxf", ""), new_scene) - - # display errors - for error in errors: - report({'ERROR', 'INFO'}, error) - - # inform the user about the sat/sab files - if len(do.acis_files) > 0: - report({'INFO'}, "Exported %d NURBS objects to sat/sab files next to your DXF file" % len(do.acis_files)) - except MinVersionError as minv: - report({'ERROR', 'INFO'}, str(minv)) + do = Do(filename, obj_merge, import_text, import_light, export_acis, merge_lines, do_bbox, block_rep, recenter, + projDXF, projSCN, thicknessWidth, but_group_by_att, dxf_unit_scale) + + errors = do.entities(os.path.basename(filename).replace(".dxf", ""), new_scene) + + # display errors + for error in errors: + report({'ERROR', 'INFO'}, error) + + # inform the user about the sat/sab files + if len(do.acis_files) > 0: + report({'INFO'}, "Exported %d NURBS objects to sat/sab files next to your DXF file" % len(do.acis_files)) def display_groups_in_outliner(): diff --git a/io_import_dxf/dxfgrabber/__init__.py b/io_import_dxf/dxfgrabber/__init__.py old mode 100755 new mode 100644 index 9d3da9d0..2581a404 --- a/io_import_dxf/dxfgrabber/__init__.py +++ b/io_import_dxf/dxfgrabber/__init__.py @@ -3,7 +3,7 @@ # Created: 21.07.2012 # License: MIT License -version = (0, 7, 4) +version = (0, 8, 1) VERSION = "%d.%d.%d" % version __author__ = "mozman " diff --git a/io_import_dxf/dxfgrabber/acdsdata.py b/io_import_dxf/dxfgrabber/acdsdata.py old mode 100755 new mode 100644 index 60538d5f..b864fff0 --- a/io_import_dxf/dxfgrabber/acdsdata.py +++ b/io_import_dxf/dxfgrabber/acdsdata.py @@ -21,10 +21,10 @@ class AcDsDataSection(object): @classmethod def from_tags(cls, tags, drawing): data_section = cls() - data_section._build(tags, drawing.dxfversion) + data_section._build(tags) return data_section - def _build(self, tags, dxfversion): + def _build(self, tags): if len(tags) == 3: # empty entities section return diff --git a/io_import_dxf/dxfgrabber/blockssection.py b/io_import_dxf/dxfgrabber/blockssection.py old mode 100755 new mode 100644 index d8f6b057..a64a364e --- a/io_import_dxf/dxfgrabber/blockssection.py +++ b/io_import_dxf/dxfgrabber/blockssection.py @@ -21,17 +21,17 @@ class BlocksSection(object): def from_tags(tags, drawing): blocks_section = BlocksSection() if drawing.grab_blocks: - blocks_section._build(tags, drawing.dxfversion) + blocks_section._build(tags) return blocks_section - def _build(self, tags, dxfversion): + def _build(self, tags): if len(tags) == 3: # empty block section return groups = list() for group in TagGroups(islice(tags, 2, len(tags)-1)): groups.append(group) if group[0].value == 'ENDBLK': - entities = build_entities(groups, dxfversion) + entities = build_entities(groups) block = entities[0] block.set_entities(entities[1:-1]) self._add(block) diff --git a/io_import_dxf/dxfgrabber/codepage.py b/io_import_dxf/dxfgrabber/codepage.py old mode 100755 new mode 100644 diff --git a/io_import_dxf/dxfgrabber/color.py b/io_import_dxf/dxfgrabber/color.py old mode 100755 new mode 100644 diff --git a/io_import_dxf/dxfgrabber/const.py b/io_import_dxf/dxfgrabber/const.py old mode 100755 new mode 100644 diff --git a/io_import_dxf/dxfgrabber/cydxfentity.py b/io_import_dxf/dxfgrabber/cydxfentity.py deleted file mode 100755 index be39b48d..00000000 --- a/io_import_dxf/dxfgrabber/cydxfentity.py +++ /dev/null @@ -1,7 +0,0 @@ -def __bootstrap__(): - global __bootstrap__, __loader__, __file__ - import sys, pkg_resources, imp - __file__ = pkg_resources.resource_filename(__name__,'cydxfentity.so') - __loader__ = None; del __bootstrap__, __loader__ - imp.load_dynamic(__name__,__file__) -__bootstrap__() diff --git a/io_import_dxf/dxfgrabber/cytags.py b/io_import_dxf/dxfgrabber/cytags.py deleted file mode 100755 index 071cea03..00000000 --- a/io_import_dxf/dxfgrabber/cytags.py +++ /dev/null @@ -1,7 +0,0 @@ -def __bootstrap__(): - global __bootstrap__, __loader__, __file__ - import sys, pkg_resources, imp - __file__ = pkg_resources.resource_filename(__name__,'cytags.so') - __loader__ = None; del __bootstrap__, __loader__ - imp.load_dynamic(__name__,__file__) -__bootstrap__() diff --git a/io_import_dxf/dxfgrabber/decode.py b/io_import_dxf/dxfgrabber/decode.py old mode 100755 new mode 100644 diff --git a/io_import_dxf/dxfgrabber/defaultchunk.py b/io_import_dxf/dxfgrabber/defaultchunk.py old mode 100755 new mode 100644 index 5a280bd1..1df9969a --- a/io_import_dxf/dxfgrabber/defaultchunk.py +++ b/io_import_dxf/dxfgrabber/defaultchunk.py @@ -9,14 +9,13 @@ from .tags import Tags, DXFTag class DefaultChunk(object): - def __init__(self, tags, drawing): + def __init__(self, tags): assert isinstance(tags, Tags) self.tags = tags - self._drawing = drawing @staticmethod def from_tags(tags, drawing): - return DefaultChunk(tags, drawing) + return DefaultChunk(tags) @property def name(self): diff --git a/io_import_dxf/dxfgrabber/drawing.py b/io_import_dxf/dxfgrabber/drawing.py old mode 100755 new mode 100644 index 1b275e86..f9a01faf --- a/io_import_dxf/dxfgrabber/drawing.py +++ b/io_import_dxf/dxfgrabber/drawing.py @@ -5,7 +5,7 @@ __author__ = "mozman " -from .tags import TagIterator +from .tags import stream_tagger from .sections import Sections DEFAULT_OPTIONS = { @@ -23,7 +23,7 @@ class Drawing(object): self.assure_3d_coords = options.get('assure_3d_coords', False) self.resolve_text_styles = options.get('resolve_text_styles', True) - tagreader = TagIterator(stream, self.assure_3d_coords) + tagreader = stream_tagger(stream, self.assure_3d_coords) self.dxfversion = 'AC1009' self.encoding = 'cp1252' self.filename = None diff --git a/io_import_dxf/dxfgrabber/dxf12.py b/io_import_dxf/dxfgrabber/dxf12.py deleted file mode 100755 index 7663ae44..00000000 --- a/io_import_dxf/dxfgrabber/dxf12.py +++ /dev/null @@ -1,202 +0,0 @@ -# Purpose: DXF12 tag wrapper -# Created: 21.07.2012, taken from my ezdxf project -# Copyright (C) 2012, Manfred Moitzi -# License: MIT License -from __future__ import unicode_literals -__author__ = "mozman " - - -from .dxfattr import DXFAttr, DXFAttributes, DefSubclass -from .dxfentity import DXFEntity -from . import const -from .const import XTYPE_3D, XTYPE_2D_3D - -def make_attribs(additional=None): - dxfattribs = { - 'handle': DXFAttr(5), - 'layer': DXFAttr(8), # layername as string, default is '0' - 'linetype': DXFAttr(6), # linetype as string, special names BYLAYER/BYBLOCK, default is BYLAYER - 'thickness': DXFAttr(39), - 'color': DXFAttr(62), # dxf color index, 0 .. BYBLOCK, 256 .. BYLAYER, default is 256 - 'paperspace': DXFAttr(67), # 0 .. modelspace, 1 .. paperspace, default is 0 - 'extrusion': DXFAttr(210, XTYPE_3D), - } - if additional: - dxfattribs.update(additional) - return DXFAttributes(DefSubclass(None, dxfattribs)) - - -class Line(DXFEntity): - DXFATTRIBS = make_attribs({ - 'start': DXFAttr(10, XTYPE_2D_3D), - 'end': DXFAttr(11, XTYPE_2D_3D), - }) - - -class Point(DXFEntity): - DXFATTRIBS = make_attribs({ - 'point': DXFAttr(10, XTYPE_2D_3D), - }) - - -class Circle(DXFEntity): - DXFATTRIBS = make_attribs({ - 'center': DXFAttr(10, XTYPE_2D_3D), - 'radius': DXFAttr(40), - }) - - -class Arc(DXFEntity): - DXFATTRIBS = make_attribs({ - 'center': DXFAttr(10, XTYPE_2D_3D), - 'radius': DXFAttr(40), - 'startangle': DXFAttr(50), - 'endangle': DXFAttr(51), - }) - - -class Trace(DXFEntity): - DXFATTRIBS = make_attribs({ - 'vtx0': DXFAttr(10, XTYPE_2D_3D), - 'vtx1': DXFAttr(11, XTYPE_2D_3D), - 'vtx2': DXFAttr(12, XTYPE_2D_3D), - 'vtx3': DXFAttr(13, XTYPE_2D_3D), - }) - - -Solid = Trace - - -class Face(DXFEntity): - DXFATTRIBS = make_attribs({ - 'vtx0': DXFAttr(10, XTYPE_2D_3D), - 'vtx1': DXFAttr(11, XTYPE_2D_3D), - 'vtx2': DXFAttr(12, XTYPE_2D_3D), - 'vtx3': DXFAttr(13, XTYPE_2D_3D), - 'invisible_edge': DXFAttr(70), - }) - - -class Text(DXFEntity): - DXFATTRIBS = make_attribs({ - 'insert': DXFAttr(10, XTYPE_2D_3D), - 'height': DXFAttr(40), - 'text': DXFAttr(1), - 'rotation': DXFAttr(50), # in degrees (circle = 360deg) - 'oblique': DXFAttr(51), # in degrees, vertical = 0deg - 'style': DXFAttr(7), # text style - 'width': DXFAttr(41), # width FACTOR! - 'textgenerationflag': DXFAttr(71), # 2 = backward (mirr-x), 4 = upside down (mirr-y) - 'halign': DXFAttr(72), # horizontal justification - 'valign': DXFAttr(73), # vertical justification - 'alignpoint': DXFAttr(11, XTYPE_2D_3D), - }) - - -class Insert(DXFEntity): - DXFATTRIBS = make_attribs({ - 'attribsfollow': DXFAttr(66), - 'name': DXFAttr(2), - 'insert': DXFAttr(10, XTYPE_2D_3D), - 'xscale': DXFAttr(41), - 'yscale': DXFAttr(42), - 'zscale': DXFAttr(43), - 'rotation': DXFAttr(50), - 'colcount': DXFAttr(70), - 'rowcount': DXFAttr(71), - 'colspacing': DXFAttr(44), - 'rowspacing': DXFAttr(45), - }) - - -class SeqEnd(DXFEntity): - DXFATTRIBS = DXFAttributes(DefSubclass(None, {'handle': DXFAttr(5), 'paperspace': DXFAttr(67), })) - - -class Attrib(DXFEntity): # also ATTDEF - DXFATTRIBS = make_attribs({ - 'insert': DXFAttr(10, XTYPE_2D_3D), - 'height': DXFAttr(40), - 'text': DXFAttr(1), - 'prompt': DXFAttr(3), # just in ATTDEF not ATTRIB - 'tag': DXFAttr(2), - 'flags': DXFAttr(70), - 'fieldlength': DXFAttr(73), - 'rotation': DXFAttr(50), - 'oblique': DXFAttr(51), - 'width': DXFAttr(41), # width factor - 'style': DXFAttr(7), - 'textgenerationflag': DXFAttr(71), # 2 = backward (mirr-x), 4 = upside down (mirr-y) - 'halign': DXFAttr(72), # horizontal justification - 'valign': DXFAttr(74), # vertical justification - 'alignpoint': DXFAttr(11, XTYPE_2D_3D), - }) - - -class Polyline(DXFEntity): - DXFATTRIBS = make_attribs({ - 'elevation': DXFAttr(10, XTYPE_2D_3D), - 'flags': DXFAttr(70), - 'defaultstartwidth': DXFAttr(40), - 'defaultendwidth': DXFAttr(41), - 'mcount': DXFAttr(71), - 'ncount': DXFAttr(72), - 'msmoothdensity': DXFAttr(73), - 'nsmoothdensity': DXFAttr(74), - 'smoothtype': DXFAttr(75), - }) - - def get_vertex_flags(self): - return const.VERTEX_FLAGS[self.get_mode()] - - @property - def flags(self): - return self.get_dxf_attrib('flags', 0) - - def get_mode(self): - flags = self.flags - if flags & const.POLYLINE_SPLINE_FIT_VERTICES_ADDED: - return 'spline2d' - elif flags & const.POLYLINE_3D_POLYLINE: - return 'polyline3d' - elif flags & const.POLYLINE_3D_POLYMESH: - return 'polymesh' - elif flags & const.POLYLINE_POLYFACE: - return 'polyface' - else: - return 'polyline2d' - - def is_mclosed(self): - return bool(self.flags & const.POLYLINE_MESH_CLOSED_M_DIRECTION) - - def is_nclosed(self): - return bool(self.flags & const.POLYLINE_MESH_CLOSED_N_DIRECTION) - - -class Vertex(DXFEntity): - DXFATTRIBS = make_attribs({ - 'location': DXFAttr(10, XTYPE_2D_3D), - 'startwidth': DXFAttr(40), - 'endwidth': DXFAttr(41), - 'bulge': DXFAttr(42), - 'flags': DXFAttr(70), - 'tangent': DXFAttr(50), - 'vtx0': DXFAttr(71), - 'vtx1': DXFAttr(72), - 'vtx2': DXFAttr(73), - 'vtx3': DXFAttr(74), - }) - - -class Block(DXFEntity): - DXFATTRIBS = make_attribs({ - 'name': DXFAttr(2), - 'name2': DXFAttr(3), - 'flags': DXFAttr(70), - 'basepoint': DXFAttr(10, XTYPE_2D_3D), - 'xrefpath': DXFAttr(1), - }) - - -class EndBlk(SeqEnd): - DXFATTRIBS = DXFAttributes(DefSubclass(None, {'handle': DXFAttr(5)})) diff --git a/io_import_dxf/dxfgrabber/dxf13.py b/io_import_dxf/dxfgrabber/dxf13.py deleted file mode 100755 index d88ada42..00000000 --- a/io_import_dxf/dxfgrabber/dxf13.py +++ /dev/null @@ -1,546 +0,0 @@ -# Purpose: DXF13 tag wrapper -# Created: 21.07.2012, taken from my ezdxf project -# Copyright (C) 2012, Manfred Moitzi -# License: MIT License -from __future__ import unicode_literals -__author__ = "mozman " - - -from . import dxf12 -from .dxfentity import DXFEntity -from .dxfattr import DXFAttr, DXFAttributes, DefSubclass -from . import const -from .const import XTYPE_2D, XTYPE_3D, XTYPE_2D_3D -from .tags import Tags -from .decode import decode - -none_subclass = DefSubclass(None, { - 'handle': DXFAttr(5), - 'block_record': DXFAttr(330), # Soft-pointer ID/handle to owner BLOCK_RECORD object -}) - -entity_subclass = DefSubclass('AcDbEntity', { - 'paperspace': DXFAttr(67), # 0 .. modelspace, 1 .. paperspace, default is 0 - 'layer': DXFAttr(8), # layername as string, default is '0' - 'linetype': DXFAttr(6), # linetype as string, special names BYLAYER/BYBLOCK, default is BYLAYER - 'ltscale': DXFAttr(48), # linetype scale, default is 1.0 - 'invisible': DXFAttr(60), # invisible .. 1, visible .. 0, default is 0 - 'color': DXFAttr(62), # dxf color index, 0 .. BYBLOCK, 256 .. BYLAYER, default is 256 - 'true_color': DXFAttr(420), # true color as 0x00RRGGBB 24-bit value (since AC1018) - 'transparency': DXFAttr(440), # transparency value 0x020000TT (since AC1018) 0 = fully transparent / 255 = opaque - 'shadow_mode': DXFAttr(284), # shadow_mode (since AC1021) - # 0 = Casts and receives shadows - # 1 = Casts shadows - # 2 = Receives shadows - # 3 = Ignores shadows -}) - -line_subclass = DefSubclass('AcDbLine', { - 'start': DXFAttr(10, XTYPE_2D_3D), - 'end': DXFAttr(11, XTYPE_2D_3D), - 'thickness': DXFAttr(39), - 'extrusion': DXFAttr(210, XTYPE_3D), -}) - - -class Line(dxf12.Line): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, line_subclass) - -point_subclass = DefSubclass('AcDbPoint', { - 'point': DXFAttr(10, XTYPE_2D_3D), - 'thickness': DXFAttr(39), - 'extrusion': DXFAttr(210, XTYPE_3D), -}) - - -class Point(dxf12.Point): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, point_subclass) - - -circle_subclass = DefSubclass('AcDbCircle', { - 'center': DXFAttr(10, XTYPE_2D_3D), - 'radius': DXFAttr(40), - 'thickness': DXFAttr(39), - 'extrusion': DXFAttr(210, XTYPE_3D), -}) - - -class Circle(dxf12.Circle): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, circle_subclass) - -arc_subclass = DefSubclass('AcDbArc', { - 'startangle': DXFAttr(50), - 'endangle': DXFAttr(51), -}) - - -class Arc(dxf12.Arc): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, circle_subclass, arc_subclass) - - -trace_subclass = DefSubclass('AcDbTrace', { - 'vtx0': DXFAttr(10, XTYPE_2D_3D), - 'vtx1': DXFAttr(11, XTYPE_2D_3D), - 'vtx2': DXFAttr(12, XTYPE_2D_3D), - 'vtx3': DXFAttr(13, XTYPE_2D_3D), - 'thickness': DXFAttr(39), - 'extrusion': DXFAttr(210, XTYPE_3D), -}) - - -class Trace(dxf12.Trace): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, trace_subclass) - - -Solid = Trace - - -face_subclass = DefSubclass('AcDbFace', { - 'vtx0': DXFAttr(10, XTYPE_2D_3D), - 'vtx1': DXFAttr(11, XTYPE_2D_3D), - 'vtx2': DXFAttr(12, XTYPE_2D_3D), - 'vtx3': DXFAttr(13, XTYPE_2D_3D), - 'invisible_edge': DXFAttr(70), -}) - - -class Face(dxf12.Face): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, face_subclass) - - -text_subclass = ( - DefSubclass('AcDbText', { - 'insert': DXFAttr(10, XTYPE_2D_3D), - 'height': DXFAttr(40), - 'text': DXFAttr(1), - 'rotation': DXFAttr(50), # in degrees (circle = 360deg) - 'oblique': DXFAttr(51), # in degrees, vertical = 0deg - 'style': DXFAttr(7), # text style - 'width': DXFAttr(41), # width FACTOR! - 'textgenerationflag': DXFAttr(71), # 2 = backward (mirr-x), 4 = upside down (mirr-y) - 'halign': DXFAttr(72), # horizontal justification - 'alignpoint': DXFAttr(11, XTYPE_2D_3D), - 'thickness': DXFAttr(39), - 'extrusion': DXFAttr(210, XTYPE_3D), - }), - DefSubclass('AcDbText', {'valign': DXFAttr(73)})) - - -class Text(dxf12.Text): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, *text_subclass) - -polyline_subclass = DefSubclass('AcDb2dPolyline', { - 'elevation': DXFAttr(10, XTYPE_3D), - 'flags': DXFAttr(70), - 'defaultstartwidth': DXFAttr(40), - 'defaultendwidth': DXFAttr(41), - 'mcount': DXFAttr(71), - 'ncount': DXFAttr(72), - 'msmoothdensity': DXFAttr(73), - 'nsmoothdensity': DXFAttr(74), - 'smoothtype': DXFAttr(75), - 'thickness': DXFAttr(39), - 'extrusion': DXFAttr(210, XTYPE_3D), -}) - - -class Polyline(dxf12.Polyline): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, polyline_subclass) - - -vertex_subclass = ( - DefSubclass('AcDbVertex', {}), # subclasses[2] - DefSubclass('AcDb2dVertex', { # subclasses[3] - 'location': DXFAttr(10, XTYPE_2D_3D), - 'startwidth': DXFAttr(40), - 'endwidth': DXFAttr(41), - 'bulge': DXFAttr(42), - 'flags': DXFAttr(70), - 'tangent': DXFAttr(50), - 'vtx0': DXFAttr(71), - 'vtx1': DXFAttr(72), - 'vtx2': DXFAttr(73), - 'vtx3': DXFAttr(74), - }) -) - -EMPTY_SUBCLASS = Tags() - - -class Vertex(dxf12.Vertex): - VTX3D = const.VTX_3D_POLYFACE_MESH_VERTEX | const.VTX_3D_POLYGON_MESH_VERTEX | const.VTX_3D_POLYLINE_VERTEX - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, *vertex_subclass) - - def post_read_correction(self): - if self.tags.subclasses[2][0].value != 'AcDbVertex': - self.tags.subclasses.insert(2, EMPTY_SUBCLASS) # create empty AcDbVertex subclass - - -class SeqEnd(dxf12.SeqEnd): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass) - -lwpolyline_subclass = DefSubclass('AcDbPolyline', { - 'elevation': DXFAttr(38), - 'thickness': DXFAttr(39), - 'flags': DXFAttr(70), - 'const_width': DXFAttr(43), - 'count': DXFAttr(90), - 'extrusion': DXFAttr(210, XTYPE_3D), -}) - - -LWPOINTCODES = (10, 20, 40, 41, 42) - - -class LWPolyline(DXFEntity): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, lwpolyline_subclass) - - def __iter__(self): - subclass = self.tags.subclasses[2] # subclass AcDbPolyline - - def get_vertex(): - point.append(attribs.get(40, 0)) - point.append(attribs.get(41, 0)) - point.append(attribs.get(42, 0)) - return tuple(point) - - point = None - attribs = {} - for tag in subclass: - if tag.code in LWPOINTCODES: - if tag.code == 10: - if point is not None: - yield get_vertex() - point = list(tag.value) - attribs = {} - else: - attribs[tag.code] = tag.value - if point is not None: - yield get_vertex() # last point - - def data(self): - full_points = list(self) - points = [] - width = [] - bulge = [] - for point in full_points: - x = 2 if len(point) == 5 else 3 - points.append(point[:x]) - width.append((point[-3], point[-2])) - bulge.append(point[-1]) - return points, width, bulge - - @property - def flags(self): - return self.get_dxf_attrib('flags', 0) - - def is_closed(self): - return bool(self.flags & const.LWPOLYLINE_CLOSED) - - -insert_subclass = DefSubclass('AcDbBlockReference', { - 'attribsfollow': DXFAttr(66), - 'name': DXFAttr(2), - 'insert': DXFAttr(10, XTYPE_2D_3D), - 'xscale': DXFAttr(41), - 'yscale': DXFAttr(42), - 'zscale': DXFAttr(43), - 'rotation': DXFAttr(50), - 'colcount': DXFAttr(70), - 'rowcount': DXFAttr(71), - 'colspacing': DXFAttr(44), - 'rowspacing': DXFAttr(45), - 'extrusion': DXFAttr(210, XTYPE_3D), -}) - - -class Insert(dxf12.Insert): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, insert_subclass) - - -attrib_subclass = ( - DefSubclass('AcDbText', { - 'insert': DXFAttr(10, XTYPE_2D_3D), - 'thickness': DXFAttr(39), - 'height': DXFAttr(40), - 'text': DXFAttr(1), - 'style': DXFAttr(7), # DXF-specs: 'AcDbAttribute'; AutoCAD: 'AcDbText' - }), - DefSubclass('AcDbAttribute', { - 'tag': DXFAttr(2), - 'flags': DXFAttr(70), - 'fieldlength': DXFAttr(73), - 'rotation': DXFAttr(50), - 'width': DXFAttr(41), - 'oblique': DXFAttr(51), - 'textgenerationflag': DXFAttr(71), - 'halign': DXFAttr(72), - 'valign': DXFAttr(74), - 'alignpoint': DXFAttr(11, XTYPE_2D_3D), - 'extrusion': DXFAttr(210, XTYPE_3D), - }) -) - - -class Attrib(dxf12.Attrib): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, *attrib_subclass) - - -attdef_subclass = ( - DefSubclass('AcDbText', { - 'insert': DXFAttr(10, XTYPE_2D_3D), - 'thickness': DXFAttr(39), - 'height': DXFAttr(40), - 'text': DXFAttr(1), - 'rotation': DXFAttr(50), - 'width': DXFAttr(41), - 'oblique': DXFAttr(51), - 'style': DXFAttr(7), - 'textgenerationflag': DXFAttr(71), - 'halign': DXFAttr(72), - 'alignpoint': DXFAttr(11), - 'extrusion': DXFAttr(210), - }), - DefSubclass('AcDbAttributeDefinition', { - 'prompt': DXFAttr(3), - 'tag': DXFAttr(2), - 'flags': DXFAttr(70), - 'fieldlength': DXFAttr(73), - 'valign': DXFAttr(74), - })) - - -class Attdef(dxf12.Attrib): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, *attdef_subclass) - - -ellipse_subclass = DefSubclass('AcDbEllipse', { - 'center': DXFAttr(10, XTYPE_2D_3D), - 'majoraxis': DXFAttr(11, XTYPE_2D_3D), # relative to the center - 'extrusion': DXFAttr(210, XTYPE_3D), - 'ratio': DXFAttr(40), - 'startparam': DXFAttr(41), # this value is 0.0 for a full ellipse - 'endparam': DXFAttr(42), # this value is 2*pi for a full ellipse -}) - - -class Ellipse(DXFEntity): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, ellipse_subclass) - - -ray_subclass = DefSubclass('AcDbRay', { - 'start': DXFAttr(10, XTYPE_3D), - 'unitvector': DXFAttr(11, XTYPE_3D), -}) - - -class Ray(DXFEntity): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, ray_subclass) - - -xline_subclass = DefSubclass('AcDbXline', { - 'start': DXFAttr(10, XTYPE_3D), - 'unitvector': DXFAttr(11, XTYPE_3D), -}) - - -class XLine(DXFEntity): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, xline_subclass) - - -spline_subclass = DefSubclass('AcDbSpline', { - 'normalvector': DXFAttr(210, XTYPE_3D), # omitted if spline is not planar - 'flags': DXFAttr(70), - 'degree': DXFAttr(71), - 'nknots': DXFAttr(72), - 'ncontrolpoints': DXFAttr(73), - 'nfitcounts': DXFAttr(74), - 'knot_tolerance': DXFAttr(42), # default 0.0000001 - 'controlpoint_tolerance': DXFAttr(43), # default 0.0000001 - 'fit_tolerance': DXFAttr(44), # default 0.0000000001 - 'starttangent': DXFAttr(12, XTYPE_3D), # optional - 'endtangent': DXFAttr(13, XTYPE_3D), # optional -}) - - -class Spline(DXFEntity): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, spline_subclass) - - def knots(self): - # groupcode 40, multiple values: nknots - subclass = self.tags.subclasses[2] # subclass AcDbSpline - return (tag.value for tag in subclass if tag.code == 40) - - def weights(self): - # groupcode 41, multiple values - subclass = self.tags.subclasses[2] # subclass AcDbSpline - return (tag.value for tag in subclass if tag.code == 41) - - def controlpoints(self): - # groupcode 10,20,30, multiple values: ncontrolpoints - return self._get_points(10) - - def fitpoints(self): - # groupcode 11,21,31, multiple values: nfitpoints - return self._get_points(11) - - def _get_points(self, code): - return (tag.value for tag in self.tags.subclasses[2] if tag.code == code) - - -helix_subclass = DefSubclass('AcDbHelix', { - 'helix_major_version': DXFAttr(90), - 'helix_maintainance_version': DXFAttr(91), - 'axis_base_point': DXFAttr(10, XTYPE_3D), - 'start_point': DXFAttr(11, XTYPE_3D), - 'axis_vector': DXFAttr(12, XTYPE_3D), - 'radius': DXFAttr(40), - 'turns': DXFAttr(41), - 'turn_height': DXFAttr(42), - 'handedness': DXFAttr(290), # 0 = left, 1 = right - 'constrain': DXFAttr(280), # 0 = Constrain turn height; 1 = Constrain turns; 2 = Constrain height -}) - - -class Helix(Spline): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, spline_subclass, helix_subclass) - -mtext_subclass = DefSubclass('AcDbMText', { - 'insert': DXFAttr(10, XTYPE_3D), - 'height': DXFAttr(40), - 'reference_rectangle_width': DXFAttr(41), - 'horizontal_width': DXFAttr(42), - 'vertical_height': DXFAttr(43), - 'attachmentpoint': DXFAttr(71), - 'text': DXFAttr(1), # also group code 3, if more than 255 chars - 'style': DXFAttr(7), # text style - 'extrusion': DXFAttr(210, XTYPE_3D), - 'xdirection': DXFAttr(11, XTYPE_3D), - 'rotation': DXFAttr(50), # xdirection beats rotation - 'linespacing': DXFAttr(44), # valid from 0.25 to 4.00 -}) - - -class MText(DXFEntity): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, mtext_subclass) - - def rawtext(self): - subclass = self.tags.subclasses[2] - lines = [tag.value for tag in subclass.find_all(3)] - lines.append(self.get_dxf_attrib('text')) - return ''.join(lines) - -block_subclass = ( - DefSubclass('AcDbEntity', {'layer': DXFAttr(8)}), - DefSubclass('AcDbBlockBegin', { - 'name': DXFAttr(2), - 'name2': DXFAttr(3), - 'description': DXFAttr(4), - 'flags': DXFAttr(70), - 'basepoint': DXFAttr(10, XTYPE_2D_3D), - 'xrefpath': DXFAttr(1), - }) -) - - -class Block(dxf12.Block): - DXFATTRIBS = DXFAttributes(none_subclass, *block_subclass) - -endblock_subclass = ( - DefSubclass('AcDbEntity', {'layer': DXFAttr(8)}), - DefSubclass('AcDbBlockEnd', {}), -) - - -class EndBlk(dxf12.EndBlk): - DXFATTRIBS = DXFAttributes(none_subclass, *endblock_subclass) - -sun_subclass = DefSubclass('AcDbSun', { - 'version': DXFAttr(90), - 'status': DXFAttr(290), - 'sun_color': DXFAttr(63), # ??? DXF Color Index = (1 .. 255), 256 by layer - 'intensity': DXFAttr(40), - 'shadows': DXFAttr(291), - 'date': DXFAttr(91), # Julian day - 'time': DXFAttr(92), # Time (in seconds past midnight) - 'daylight_savings_time': DXFAttr(292), - 'shadow_type': DXFAttr(70), # 0 = Ray traced shadows; 1 = Shadow maps - 'shadow_map_size': DXFAttr(71), # 0 = Ray traced shadows; 1 = Shadow maps - 'shadow_softness': DXFAttr(280), -}) - - -# SUN resides in the objects section and has no AcDbEntity subclass -class Sun(DXFEntity): - DXFATTRIBS = DXFAttributes(none_subclass, sun_subclass) - -mesh_subclass = DefSubclass('AcDbSubDMesh', { - 'version': DXFAttr(71), - 'blend_crease': DXFAttr(72), # 0 = off, 1 = on - 'subdivision_levels': DXFAttr(91), # int >= 1 -}) - - -class Mesh(DXFEntity): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, mesh_subclass) - -light_subclass = DefSubclass('AcDbLight', { - 'version': DXFAttr(90), - 'name': DXFAttr(1), - 'light_type': DXFAttr(70), # distant = 1; point = 2; spot = 3 - 'status': DXFAttr(290), - 'light_color': DXFAttr(63), # DXF Color Index = (1 .. 255), 256 by layer - 'true_color': DXFAttr(421), # 24-bit color 0x00RRGGBB - 'plot_glyph': DXFAttr(291), - 'intensity': DXFAttr(40), - 'position': DXFAttr(10, XTYPE_3D), - 'target': DXFAttr(11, XTYPE_3D), - 'attenuation_type': DXFAttr(72), # 0 = None; 1 = Inverse Linear; 2 = Inverse Square - 'use_attenuation_limits': DXFAttr(292), # bool - 'attenuation_start_limit': DXFAttr(41), - 'attenuation_end_limit': DXFAttr(42), - 'hotspot_angle': DXFAttr(50), - 'fall_off_angle': DXFAttr(51), - 'cast_shadows': DXFAttr(293), - 'shadow_type': DXFAttr(73), # 0 = Ray traced shadows; 1 = Shadow maps - 'shadow_map_size': DXFAttr(91), - 'shadow_softness': DXFAttr(280), -}) - - -class Light(DXFEntity): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, light_subclass) - - -modeler_geometry_subclass = DefSubclass('AcDbModelerGeometry', { - 'version': DXFAttr(70), -}) - - -class Body(DXFEntity): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, modeler_geometry_subclass) - - def get_acis_data(self): - # for AC1027 and later - ACIS data is stored in the ACDSDATA section in Standard ACIS Binary format - geometry = self.tags.subclasses[2] # AcDbModelerGeometry - return decode([tag.value for tag in geometry if tag.code in (1, 3)]) - -solid3d_subclass = DefSubclass('AcDb3dSolid', { - 'handle_to_history_object': DXFAttr(350), -}) - -# Region == Body - - -class Solid3d(Body): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, modeler_geometry_subclass, solid3d_subclass) - - -surface_subclass = DefSubclass('AcDbSurface', { - 'u_isolines': DXFAttr(71), - 'v_isolines': DXFAttr(72), -}) - - -class Surface(Body): - DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, modeler_geometry_subclass, surface_subclass) diff --git a/io_import_dxf/dxfgrabber/dxfattr.py b/io_import_dxf/dxfgrabber/dxfattr.py deleted file mode 100755 index a98f038d..00000000 --- a/io_import_dxf/dxfgrabber/dxfattr.py +++ /dev/null @@ -1,47 +0,0 @@ -# Purpose: define dxf attributes -# Created: 21.07.2012, taken from my ezdxf project -# Copyright (C) 2012, Manfred Moitzi -# License: MIT License -from __future__ import unicode_literals -__author__ = "mozman " - -from collections import namedtuple -from .const import XTYPE_NONE - - -def DXFAttr(code, xtype=XTYPE_NONE): - # assert type(xtype) is int - return _DXFAttr(code, xtype) - -_DXFAttr = namedtuple('DXFAttr', 'code xtype') -DXFAttr3 = namedtuple('DXFAttr3', 'code xtype subclass') -DefSubclass = namedtuple('DefSubclass', 'name attribs') - - -class DXFAttributes(object): - def __init__(self, *subclassdefs): - self._subclasses = [] - self._attribs = {} - for subclass in subclassdefs: - self.add_subclass(subclass) - - def add_subclass(self, subclass): - subclass_index = len(self._subclasses) - self._subclasses.append(subclass) - self._add_subclass_attribs(subclass, subclass_index) - - def _add_subclass_attribs(self, subclass, subclass_index): - for name, dxfattrib in subclass.attribs.items(): - self._attribs[name] = DXFAttr3(dxfattrib.code, dxfattrib.xtype, subclass_index) - - def __getitem__(self, name): - return self._attribs[name] - - def __contains__(self, name): - return name in self._attribs - - def keys(self): - return iter(self._attribs.keys()) - - def subclasses(self): - return iter(self._subclasses) diff --git a/io_import_dxf/dxfgrabber/dxfentity.py b/io_import_dxf/dxfgrabber/dxfentity.py deleted file mode 100755 index 26cfc436..00000000 --- a/io_import_dxf/dxfgrabber/dxfentity.py +++ /dev/null @@ -1,84 +0,0 @@ -# Purpose: generic tag wrapper -# Created: 21.07.2012, taken from my ezdxf project -# Copyright (C) 2012, Manfred Moitzi -# License: MIT License -from __future__ import unicode_literals -__author__ = "mozman " - -import os - -from .const import ENV_CYTHON, XTYPE_NONE, XTYPE_2D, XTYPE_3D, XTYPE_2D_3D - -cyDXFEntity = None -OPTIMIZE = True -if ENV_CYTHON in os.environ: - if os.environ[ENV_CYTHON].upper() in ('1', 'ON', 'TRUE'): - OPTIMIZE = True - else: - OPTIMIZE = False -try: - if OPTIMIZE: - from.cydxfentity import cyDXFEntity -except ImportError: - pass - - -class pyDXFEntity(object): - DXFATTRIBS = {} - - def __init__(self, tags): - self.tags = tags - - def dxftype(self): - return self.tags.noclass[0].value - - def get_dxf_attrib(self, key, default=ValueError): - # core function - every optimization is useful - try: - dxfattr = self.DXFATTRIBS[key] - except KeyError: - # attribute is not defined - returning the default value is useful - # to query newer DXF attributes on older DXF files. - # !! Problem: misspelled attributes with default values do not - # raise an Exception !! - if default is ValueError: - raise ValueError("DXFAttrib '%s' is not defined." % key) - else: - return default - try: - return self._get_dxf_attrib(dxfattr) - except ValueError: # attribute is defined but no value is present - if default is ValueError: - raise ValueError("DXFAttrib '%s': value is not present." % key) - else: - return default - - def _get_dxf_attrib(self, dxfattr): - # no subclass is subclass index 0 - subclass_tags = self.tags.subclasses[dxfattr.subclass] - xtype = dxfattr.xtype - if xtype != XTYPE_NONE and xtype != XTYPE_2D_3D: - return self._get_extented_type(subclass_tags, dxfattr.code, xtype) - else: - return subclass_tags.get_value(dxfattr.code) - - def paperspace(self): - return self.get_dxf_attrib('paperspace', default=0) == 1 - - def post_read_correction(self): - pass - - @staticmethod - def _get_extented_type(tags, code, xtype): - value = tags.get_value(code) - if len(value) == 2: - if xtype == XTYPE_3D: - return value[0], value[1], 0. - elif xtype == XTYPE_2D: - return value[0], value[1] - return value - -if cyDXFEntity is not None: - DXFEntity = cyDXFEntity -else: - DXFEntity = pyDXFEntity \ No newline at end of file diff --git a/io_import_dxf/dxfgrabber/entities.py b/io_import_dxf/dxfgrabber/entities.py deleted file mode 100755 index 937b05bd..00000000 --- a/io_import_dxf/dxfgrabber/entities.py +++ /dev/null @@ -1,930 +0,0 @@ -# encoding: utf-8 -# Purpose: entity classes -# Created: 21.07.2012, parts taken from my ezdxf project -# Copyright (C) 2012, Manfred Moitzi -# License: MIT License -from __future__ import unicode_literals -__author__ = "mozman " - -from . import dxf12, dxf13 -from . import const -from .juliandate import calendar_date -from datetime import datetime -from .color import TrueColor -import math - -from .styles import default_text_style - -SPECIAL_CHARS = { - 'd': '°' -} - - -class SeqEnd(object): - def __init__(self, wrapper): - self.dxftype = wrapper.dxftype() - - -class Entity(SeqEnd): - def __init__(self, wrapper): - super(Entity, self).__init__(wrapper) - self.paperspace = bool(wrapper.paperspace()) - - -class Shape(Entity): - def __init__(self, wrapper): - super(Shape, self).__init__(wrapper) - get_dxf = wrapper.get_dxf_attrib - self.layer = get_dxf('layer', '0') - self.linetype = get_dxf('linetype', None) # None=BYLAYER - self.thickness = get_dxf('thickness', 0.0) - self.extrusion = get_dxf('extrusion', (0., 0., 1.)) - self.ltscale = get_dxf('ltscale', 1.0) - self.invisible = get_dxf('invisible', 0) # 0=visible - self.color = get_dxf('color', const.BYLAYER) # 256=BYLAYER, 0=BYBLOCK - self.true_color = get_dxf('true_color', None) # 0x00RRGGBB - if self.true_color is not None: - self.true_color = TrueColor(self.true_color) - self.transparency = get_dxf('transparency', None) # 0x020000TT - if self.transparency is not None: - # 0.0 = opaque & 1.0 if fully transparent - self.transparency = 1. - float(self.transparency & 0xFF) / 255. - self.shadow_mode = get_dxf('shadow_mode', None) - # 0 = Casts and receives shadows - # 1 = Casts shadows - # 2 = Receives shadows - # 3 = Ignores shadows - - # if adding additional DXF attributes, do it also for PolyShape - - -class PolyShape(object): - """ Base class for Polyface and Polymesh, both are special cases of POLYLINE. - """ - def __init__(self, polyline, dxftype): - self.dxftype = dxftype - self.paperspace = polyline.paperspace - self.layer = polyline.layer - self.linetype = polyline.linetype - self.ltscale = polyline.ltscale - self.invisible = polyline.invisible - self.color = polyline.color - self.true_color = polyline.true_color - self.transparency = polyline.transparency - self.shadow_mode = polyline.shadow_mode - - -class Line(Shape): - def __init__(self, wrapper): - super(Line, self).__init__(wrapper) - self.start = wrapper.get_dxf_attrib('start') - self.end = wrapper.get_dxf_attrib('end') - - -class Point(Shape): - def __init__(self, wrapper): - super(Point, self).__init__(wrapper) - self.point = wrapper.get_dxf_attrib('point') - - -class Circle(Shape): - def __init__(self, wrapper): - super(Circle, self).__init__(wrapper) - self.center = wrapper.get_dxf_attrib('center') - self.radius = wrapper.get_dxf_attrib('radius') - - -class Arc(Shape): - def __init__(self, wrapper): - super(Arc, self).__init__(wrapper) - get_dxf = wrapper.get_dxf_attrib - self.center = get_dxf('center') - self.radius = get_dxf('radius') - self.startangle = get_dxf('startangle') - self.endangle = get_dxf('endangle') - - -class Trace(Shape): - def __init__(self, wrapper): - super(Trace, self).__init__(wrapper) - get_dxf = wrapper.get_dxf_attrib - self.points = [ - get_dxf(vname) for vname in const.VERTEXNAMES - ] - -Solid = Trace - - -class Face(Trace): - def __init__(self, wrapper): - super(Face, self).__init__(wrapper) - self.invisible_edge = wrapper.get_dxf_attrib('invisible_edge', 0) - - def is_edge_invisible(self, edge): - # edges 0 .. 3 - return bool(self.invisible_edge & (1 << edge)) - - -class Text(Shape): - def __init__(self, wrapper): - super(Text, self).__init__(wrapper) - get_dxf = wrapper.get_dxf_attrib - self.insert = get_dxf('insert') - self.text = get_dxf('text') - self.height = get_dxf('height', 0) - self.width = get_dxf('width', 0) - self.oblique = get_dxf('oblique', None) - self.rotation = get_dxf('rotation', 0.) - self.style = get_dxf('style', "") - self.halign = get_dxf('halign', 0) - self.valign = get_dxf('valign', 0) - self.alignpoint = get_dxf('alignpoint', None) - if get_dxf('textgenerationflag', None) is not None: - self.is_backwards = bool(get_dxf('textgenerationflag', 0) & 2) - self.is_upside_down = bool(get_dxf('textgenerationflag', 0) & 4) - else: - self.is_backwards = None - self.is_upside_down = None - self.font = "" - self.bigfont = "" - - def resolve_text_style(self, text_styles): - style = text_styles.get(self.style, None) - if style is None: - style = default_text_style - if self.height == 0: - self.height = style.height - if self.width == 0: - self.width = style.width - if self.oblique is None: - self.oblique = style.oblique - if self.is_backwards is None: - self.is_backwards = style.is_backwards - if self.is_upside_down is None: - self.is_upside_down = style.is_upside_down - if self.font is None: - self.font = style.font - if self.bigfont is None: - self.bigfont = style.bigfont - - def plain_text(self): - chars = [] - raw_chars = list(reversed(self.text)) # text splitted into chars, in reversed order for efficient pop() - while len(raw_chars): - char = raw_chars.pop() - if char == '%': # formatting codes and special characters - if len(raw_chars) and raw_chars[-1] == '%': - raw_chars.pop() # '%' - if len(raw_chars): - special_char = raw_chars.pop() # command char - chars.append(SPECIAL_CHARS.get(special_char, "")) - else: # char is just a single '%' - chars.append(char) - else: # char is what it is, a character - chars.append(char) - return "".join(chars) - - -class Insert(Shape): - def __init__(self, wrapper): - super(Insert, self).__init__(wrapper) - get_dxf = wrapper.get_dxf_attrib - self.name = get_dxf('name') - self.insert = get_dxf('insert') - self.rotation = get_dxf('rotation', 0.) - self.scale = get_dxf('xscale', 1.), get_dxf('yscale', 1.), get_dxf('zscale', 1.) - self.row_count = get_dxf('rowcount', 1) - self.row_spacing = get_dxf('rowspacing', 0.) - self.col_count = get_dxf('colcount', 1) - self.col_spacing = get_dxf('colspacing', 0.) - self.attribsfollow = bool(get_dxf('attribsfollow', 0)) - self.attribs = [] - - def find_attrib(self, attrib_tag): - for attrib in self.attribs: - if attrib.tag == attrib_tag: - return attrib - return None - - def append_data(self, attribs): - self.attribs = attribs - - -class Attrib(Text): # also ATTDEF - def __init__(self, wrapper): - super(Attrib, self).__init__(wrapper) - self.tag = wrapper.get_dxf_attrib('tag') - -_LINE_TYPES = frozenset(('spline2d', 'polyline2d', 'polyline3d')) - - -class Polyline(Shape): - def __init__(self, wrapper): - super(Polyline, self).__init__(wrapper) - self.vertices = [] # set in append data - self.points = [] # set in append data - self.controlpoints = [] # set in append data - self.width = [] # set in append data - self.bulge = [] # set in append data - self.tangents = [] # set in append data - self.flags = wrapper.flags - self.mode = wrapper.get_mode() - get_dxf = wrapper.get_dxf_attrib - self.mcount = get_dxf('mcount', 0) - self.ncount = get_dxf('ncount', 0) - self.default_start_width = get_dxf('defaultstartwidth', 0.) - self.default_end_width = get_dxf('defaultendwidth', 0.) - self.is_mclosed = wrapper.is_mclosed() - self.is_nclosed = wrapper.is_nclosed() - self.elevation = get_dxf('elevation', (0., 0., 0.)) - self.m_smooth_density = get_dxf('msmoothdensity', 0.) - self.n_smooth_density = get_dxf('nsmoothdensity', 0.) - self.smooth_type = get_dxf('smoothtype', 0) - self.spline_type = None - if self.mode == 'spline2d': - if self.smooth_type == const.POLYMESH_CUBIC_BSPLINE: - self.spline_type = 'cubic_bspline' - elif self.smooth_type == const.POLYMESH_QUADRIC_BSPLINE: - self.spline_type = 'quadratic_bspline' - elif self.smooth_type == const.POLYMESH_BEZIER_SURFACE: - self.spline_type = 'bezier_curve' # is this a valid spline type for DXF12? - - def __len__(self): - return len(self.vertices) - - def __getitem__(self, item): - return self.vertices[item] - - def __iter__(self): - return iter(self.vertices) - - @property - def is_closed(self): - return self.is_mclosed - - @is_closed.setter - def is_closed(self, status): - self.is_mclosed = status - - def append_data(self, vertices): - def default_width(start_width, end_width): - if start_width == 0.: - start_width = self.default_start_width - if end_width == 0.: - end_width = self.default_end_width - return start_width, end_width - - self.vertices = vertices - if self.mode in _LINE_TYPES: - for vertex in self.vertices: - if vertex.flags & const.VTX_SPLINE_FRAME_CONTROL_POINT: - self.controlpoints.append(vertex.location) - else: - self.points.append(vertex.location) - self.width.append(default_width(vertex.start_width, vertex.end_width)) - self.bulge.append(vertex.bulge) - self.tangents.append(vertex.tangent if vertex.flags & const.VTX_CURVE_FIT_TANGENT else None) - - def cast(self): - if self.mode == 'polyface': - return Polyface(self) - elif self.mode == 'polymesh': - return Polymesh(self) - else: - return self - - -class SubFace(object): - def __init__(self, face_record, vertices): - self._vertices = vertices - self.face_record = face_record - - def __len__(self): - return len(self.face_record.vtx) - - def __getitem__(self, item): - return self._vertices[self._vertex_index(item)] - - def __iter__(self): - return (self._vertices[index].location for index in self.indices()) - - def _vertex_index(self, pos): - return abs(self.face_record.vtx[pos]) - 1 - - def indices(self): - return tuple(abs(i)-1 for i in self.face_record.vtx if i != 0) - - def is_edge_visible(self, pos): - return self.face_record.vtx[pos] > 0 - - -class Polyface(PolyShape): - def __init__(self, polyline): - VERTEX_FLAGS = const.VTX_3D_POLYFACE_MESH_VERTEX + const.VTX_3D_POLYGON_MESH_VERTEX - - def is_vertex(flags): - return flags & VERTEX_FLAGS == VERTEX_FLAGS - - super(Polyface, self).__init__(polyline, 'POLYFACE') - vertices = [] - face_records = [] - for vertex in polyline.vertices: - (vertices if is_vertex(vertex.flags) else face_records).append(vertex) - - self.vertices = vertices - self._face_records = face_records - - def __getitem__(self, item): - return SubFace(self._face_records[item], self.vertices) - - def __len__(self): - return len(self._face_records) - - def __iter__(self): - return (SubFace(f, self.vertices) for f in self._face_records) - - -class Polymesh(PolyShape): - def __init__(self, polyline): - super(Polymesh, self).__init__(polyline, 'POLYMESH') - self.mcount = polyline.mcount - self.ncount = polyline.ncount - self.is_mclosed = polyline.is_mclosed - self.is_nclosed = polyline.is_nclosed - self._vertices = polyline.vertices - self.m_smooth_density = polyline.m_smooth_density - self.n_smooth_density = polyline.n_smooth_density - self.smooth_type = polyline.smooth_type - - def __iter__(self): - return iter(self._vertices) - - def get_location(self, pos): - return self.get_vertex(pos).location - - def get_vertex(self, pos): - mcount = self.mcount - ncount = self.ncount - m, n = pos - if 0 <= m < mcount and 0 <= n < ncount: - pos = m * ncount + n - return self._vertices[pos] - else: - raise IndexError(repr(pos)) - - -class Vertex(Shape): - def __init__(self, wrapper): - super(Vertex, self).__init__(wrapper) - get_dxf = wrapper.get_dxf_attrib - self.location = get_dxf('location') - self.flags = get_dxf('flags', 0) - self.start_width = get_dxf('startwidth', 0) - self.end_width = get_dxf('endwidth', 0) - self.bulge = get_dxf('bulge', 0) - self.tangent = get_dxf('tangent', None) - self.vtx = self._get_vtx(wrapper) - - def _get_vtx(self, wrapper): - vtx = [] - get_dxf = wrapper.get_dxf_attrib - for vname in const.VERTEXNAMES: - try: - vtx.append(get_dxf(vname)) - except ValueError: - pass - return tuple(vtx) - - -class LWPolyline(Shape): - def __init__(self, wrapper): - super(LWPolyline, self).__init__(wrapper) - self.points, self.width, self.bulge = wrapper.data() - self.const_width = wrapper.get_dxf_attrib('const_width', 0) - self.is_closed = wrapper.is_closed() - self.elevation = wrapper.get_dxf_attrib('elevation', (0., 0., 0.)) - - def __len__(self): - return len(self.points) - - def __getitem__(self, item): - return self.points[item] - - def __iter__(self): - return iter(self.points) - - -class Ellipse(Shape): - def __init__(self, wrapper): - super(Ellipse, self).__init__(wrapper) - get_dxf = wrapper.get_dxf_attrib - self.center = get_dxf('center') - self.majoraxis = get_dxf('majoraxis') - self.ratio = get_dxf('ratio', 1.0) # circle - self.startparam = get_dxf('startparam', 0.) - self.endparam = get_dxf('endparam', 6.283185307179586) # 2*pi - - -class Ray(Shape): - def __init__(self, wrapper): - super(Ray, self).__init__(wrapper) - self.start = wrapper.get_dxf_attrib('start') - self.unitvector = wrapper.get_dxf_attrib('unitvector') - -XLine = Ray - - -class Spline(Shape): - def __init__(self, wrapper): - super(Spline, self).__init__(wrapper) - get_dxf = wrapper.get_dxf_attrib - self.normalvector = get_dxf('normalvector', None) - self.flags = get_dxf('flags', 0) - self.degree = get_dxf('degree', 3) - self.starttangent = get_dxf('starttangent', None) - self.endtangent = get_dxf('endtangent', None) - self.knots = tuple(wrapper.knots()) - self.weights = tuple(wrapper.weights()) - self.tol_knot = get_dxf('knot_tolernace', .0000001) - self.tol_controlpoint = get_dxf('controlpoint_tolerance', .0000001) - self.tol_fitpoint = get_dxf('fitpoint_tolerance', .0000000001) - self.controlpoints = tuple(wrapper.controlpoints()) - self.fitpoints = tuple(wrapper.fitpoints()) - if len(self.weights) == 0: - self.weights = tuple([1.0] * len(self.controlpoints)) - - @property - def is_closed(self): - return bool(self.flags & const.SPLINE_CLOSED) - - @property - def is_periodic(self): - return bool(self.flags & const.SPLINE_PERIODIC) - - @property - def is_rational(self): - return bool(self.flags & const.SPLINE_RATIONAL) - - @property - def is_planar(self): - return bool(self.flags & const.SPLINE_PLANAR) - - @property - def is_linear(self): - return bool(self.flags & const.SPLINE_LINEAR) - - -class Helix(Spline): - def __init__(self, wrapper): - super(Helix, self).__init__(wrapper) - get_dxf = wrapper.get_dxf_attrib - self.helix_version = (get_dxf('helix_major_version', 1), - get_dxf('helix_maintainance_version', 1)) - self.axis_base_point = get_dxf('axis_base_point', None) - self.start_point = get_dxf('start_point', None) - self.axis_vector = get_dxf('axis_vector', None) - self.radius = get_dxf('radius', 0) - self.turns = get_dxf('turns', 0) - self.turn_height = get_dxf('turn_height', 0) - self.handedness = get_dxf('handedness', 0) # 0 = left, 1 = right - self.constrain = get_dxf('constrain', 0) - # 0 = Constrain turn height; - # 1 = Constrain turns; - # 2 = Constrain height - - -def deg2vec(deg): - rad = float(deg) * math.pi / 180.0 - return math.cos(rad), math.sin(rad), 0. - - -def normalized(vector): - x, y, z = vector - m = (x**2 + y**2 + z**2)**0.5 - return x/m, y/m, z/m - -################################################## -# MTEXT inline codes -# \L Start underline -# \l Stop underline -# \O Start overstrike -# \o Stop overstrike -# \K Start strike-through -# \k Stop strike-through -# \P New paragraph (new line) -# \pxi Control codes for bullets, numbered paragraphs and columns -# \X Paragraph wrap on the dimension line (only in dimensions) -# \Q Slanting (obliquing) text by angle - e.g. \Q30; -# \H Text height - e.g. \H3x; -# \W Text width - e.g. \W0.8x; -# \F Font selection -# -# e.g. \Fgdt;o - GDT-tolerance -# e.g. \Fkroeger|b0|i0|c238|p10 - font Kroeger, non-bold, non-italic, codepage 238, pitch 10 -# -# \S Stacking, fractions -# -# e.g. \SA^B: -# A -# B -# e.g. \SX/Y: -# X -# - -# Y -# e.g. \S1#4: -# 1/4 -# -# \A Alignment -# -# \A0; = bottom -# \A1; = center -# \A2; = top -# -# \C Color change -# -# \C1; = red -# \C2; = yellow -# \C3; = green -# \C4; = cyan -# \C5; = blue -# \C6; = magenta -# \C7; = white -# -# \T Tracking, char.spacing - e.g. \T2; -# \~ Non-wrapping space, hard space -# {} Braces - define the text area influenced by the code -# \ Escape character - e.g. \\ = "\", \{ = "{" -# -# Codes and braces can be nested up to 8 levels deep - -ESCAPED_CHARS = "\\{}" -GROUP_CHARS = "{}" -ONE_CHAR_COMMANDS = "PLlOoKkX" - - -class MText(Shape): - def __init__(self, wrapper): - - super(MText, self).__init__(wrapper) - self.insert = wrapper.get_dxf_attrib('insert') - self.rawtext = wrapper.rawtext() - get_dxf = wrapper.get_dxf_attrib - self.height = get_dxf('height', 0) - self.rect_width = get_dxf('reference_rectangle_width', None) - self.horizontal_width = get_dxf('horizontal_width', None) - self.vertical_height = get_dxf('vertical_height', None) - self.linespacing = get_dxf('linespacing', 1.0) - self.attachmentpoint = get_dxf('attachmentpoint', 1) - self.style = get_dxf('style', 'STANDARD') - self.extrusion = get_dxf('extrusion', (0., 0., 1.)) - try: - xdir = wrapper.get_dxf_attrib('xdirection') - except ValueError: - xdir = deg2vec(get_dxf('rotation', 0.0)) - self.xdirection = normalized(xdir) - self.font = None - self.bigfont = None - - def lines(self): - return self.rawtext.split('\P') - - def plain_text(self, split=False): - chars = [] - raw_chars = list(reversed(self.rawtext)) # text splitted into chars, in reversed order for efficient pop() - while len(raw_chars): - char = raw_chars.pop() - if char == '\\': # is a formatting command - try: - char = raw_chars.pop() - except IndexError: - break # premature end of text - just ignore - - if char in ESCAPED_CHARS: # \ { } - chars.append(char) - elif char in ONE_CHAR_COMMANDS: - if char == 'P': # new line - chars.append('\n') - # discard other commands - else: # more character commands are terminated by ';' - stacking = char == 'S' # stacking command surrounds user data - try: - while char != ';': # end of format marker - char = raw_chars.pop() - if stacking and char != ';': - chars.append(char) # append user data of stacking command - except IndexError: - break # premature end of text - just ignore - elif char in GROUP_CHARS: # { } - pass # discard group markers - elif char == '%': # special characters - if len(raw_chars) and raw_chars[-1] == '%': - raw_chars.pop() # discard next '%' - if len(raw_chars): - special_char = raw_chars.pop() - # replace or discard formatting code - chars.append(SPECIAL_CHARS.get(special_char, "")) - else: # char is just a single '%' - chars.append(char) - else: # char is what it is, a character - chars.append(char) - - plain_text = "".join(chars) - return plain_text.split('\n') if split else plain_text - - def resolve_text_style(self, text_styles): - style = text_styles.get(self.style, None) - if style is None: - style = default_text_style - if self.height == 0: - self.height = style.height - if self.font is None: - self.font = style.font - if self.bigfont is None: - self.bigfont = style.font - - -class Block(Shape): - def __init__(self, wrapper): - super(Block, self).__init__(wrapper) - self.basepoint = wrapper.get_dxf_attrib('basepoint') - self.name = wrapper.get_dxf_attrib('name') - self.flags = wrapper.get_dxf_attrib('flags', 0) - self.xrefpath = wrapper.get_dxf_attrib('xrefpath', "") - self._entities = list() - - @property - def is_xref(self): - return bool(self.flags & const.BLK_XREF) - - @property - def is_xref_overlay(self): - return bool(self.flags & const.BLK_XREF_OVERLAY) - - @property - def is_anonymous(self): - return bool(self.flags & const.BLK_ANONYMOUS) - - def set_entities(self, entities): - self._entities = entities - - def __iter__(self): - return iter(self._entities) - - def __getitem__(self, item): - return self._entities[item] - - def __len__(self): - return len(self._entities) - - -class BlockEnd(SeqEnd): - pass - - -def unpack_seconds(seconds): - seconds = int(seconds / 1000) # remove 1/1000 part - hours = int(seconds / 3600) - seconds = int(seconds % 3600) - minutes = int(seconds / 60) - seconds = int(seconds % 60) - return hours, minutes, seconds - - -class Sun(Entity): - def __init__(self, wrapper): - super(Sun, self).__init__(wrapper) - get_dxf = wrapper.get_dxf_attrib - self.version = get_dxf('version', 1) - self.status = bool(get_dxf('status', 0)) # on/off ? - self.sun_color = get_dxf('sun_color', None) # None is unset - self.intensity = get_dxf('intensity', 0) - self.shadows = bool(get_dxf('shadows', 0)) - julian_date = get_dxf('date', 0.) - if julian_date > 0.: - date = calendar_date(julian_date) - else: - date = datetime.now() - hours, minutes, seconds = unpack_seconds(get_dxf('time', 0)) - self.date = datetime(date.year, date.month, date.day, hours, minutes, seconds) - self.daylight_savings_time = bool(get_dxf('daylight_savings_time', 0)) - self.shadow_type = get_dxf('shadows_type', 0) - self.shadow_map_size = get_dxf('shadow_map_size', 0) - self.shadow_softness = get_dxf('shadow_softness', 0) - - -class Mesh(Shape): - def __init__(self, wrapper): - super(Mesh, self).__init__(wrapper) - get_dxf = wrapper.get_dxf_attrib - self.version = get_dxf('version', 2) - self.blend_crease = bool(get_dxf('blend_crease', 0)) - self.subdivision_levels = get_dxf('subdivision_levels', 1) - # rest are mostly positional tags - self.vertices = [] - self.faces = [] - self.edges = [] - self.edge_crease_list = [] - - subdmesh_tags = wrapper.tags.get_subclass('AcDbSubDMesh') - # for all blocks I ignore the count values, perhaps they are wrong, - # but I use the count tags as indicator for the begin of the list - try: - pos = subdmesh_tags.tag_index(92) - except ValueError: # no vertices??? - return - else: - self.vertices = Mesh.get_vertices(subdmesh_tags, pos+1) - try: - pos = subdmesh_tags.tag_index(93) - except ValueError: # no faces??? - pass - else: - self.faces = Mesh.get_faces(subdmesh_tags, pos+1) - try: - pos = subdmesh_tags.tag_index(94) - except ValueError: # no edges - pass - else: - self.edges = Mesh.get_edges(subdmesh_tags, pos+1) - try: - pos = subdmesh_tags.tag_index(95) - except ValueError: # no edges crease values - pass - else: - self.edge_crease_list = Mesh.get_edge_crease_list(subdmesh_tags, pos+1) - - def get_face(self, index): - return tuple(self.vertices[vertex_index] for vertex_index in self.faces[index]) - - def get_edge(self, index): - return tuple(self.vertices[vertex_index] for vertex_index in self.edges[index]) - - @staticmethod - def get_vertices(tags, pos): - vertices = [] - itags = iter(tags[pos:]) - while True: - try: - tag = next(itags) - except StopIteration: # premature end of tags, return what you got - break - if tag.code == 10: - vertices.append(tag.value) - else: - break - return vertices - - @staticmethod - def get_faces(tags, pos): - faces = [] - face = [] - itags = iter(tags[pos:]) - try: - while True: - tag = next(itags) - # loop until first tag.code != 90 - if tag.code != 90: - break - count = tag.value # count of vertex indices - while count > 0: - tag = next(itags) - face.append(tag.value) - count -= 1 - faces.append(tuple(face)) - del face[:] - except StopIteration: # premature end of tags, return what you got - pass - return faces - - @staticmethod - def get_edges(tags, pos): - edges = [] - start_index = None - for index in Mesh.get_raw_list(tags, pos, code=90): - if start_index is None: - start_index = index - else: - edges.append((start_index, index)) - start_index = None - return edges - - @staticmethod - def get_edge_crease_list(tags, pos): - return Mesh.get_raw_list(tags, pos, code=140) - - @staticmethod - def get_raw_list(tags, pos, code): - raw_list = [] - itags = iter(tags[pos:]) - while True: - try: - tag = next(itags) - except StopIteration: - break - if tag.code == code: - raw_list.append(tag.value) - else: - break - return raw_list - - -class Light(Shape): - def __init__(self, wrapper): - super(Light, self).__init__(wrapper) - get_dxf = wrapper.get_dxf_attrib - self.version = get_dxf('version', 1) - self.name = get_dxf('name', "") - self.light_type = get_dxf('light_type', 1) # distant = 1; point = 2; spot = 3 - self.status = bool(get_dxf('status', 0)) # on/off ? - self.light_color = get_dxf('light_color', None) # 0 is unset - self.true_color = get_dxf('true_color', None) # None is unset - self.plot_glyph = bool(get_dxf('plot_glyph', 0)) - self.intensity = get_dxf('intensity', 0) - self.position = get_dxf('position', (0, 0, 1)) - self.target = get_dxf('target', (0, 0, 0)) - self.attenuation_type = get_dxf('attenuation_type', 0) # 0 = None; 1 = Inverse Linear; 2 = Inverse Square - self.use_attenuation_limits = bool(get_dxf('use_attenuation_limits', 0)) - self.attenuation_start_limit = get_dxf('attenuation_start_limit', 0) - self.attenuation_end_limit = get_dxf('attenuation_end_limit', 0) - self.hotspot_angle = get_dxf('hotspot_angle', 0) - self.fall_off_angle = get_dxf('fall_off_angle', 0) - self.cast_shadows = bool(get_dxf('cast_shadows', 0)) - self.shadow_type = get_dxf('shadow_type', 0) # 0 = Ray traced shadows; 1 = Shadow maps - self.shadow_map_size = get_dxf('shadow_map_size', 0) - self.shadow_softness = get_dxf('shadow_softness', 0) - - -class Body(Shape): - def __init__(self, wrapper): - super(Body, self).__init__(wrapper) - # need handle to get SAB data in DXF version AC1027 and later - self.handle = wrapper.get_dxf_attrib('handle', None) - self.version = wrapper.get_dxf_attrib('version', 1) - self.acis = wrapper.get_acis_data() - - def set_sab_data(self, sab_data): - self.acis = sab_data - - @property - def is_sat(self): - return isinstance(self.acis, list) # but could be an empty list - - @property - def is_sab(self): - return not self.is_sat # has binary encoded ACIS data - -Solid3d = Body -# perhaps reading creation history is needed - - -class Surface(Body): - def __init__(self, wrapper): - super(Surface, self).__init__(wrapper) - self.u_isolines = wrapper.get_dxf_attrib('u_isolines', 0) - self.v_isolines = wrapper.get_dxf_attrib('v_isolines', 0) - - -EntityTable = { - 'LINE': (Line, dxf12.Line, dxf13.Line), - 'POINT': (Point, dxf12.Point, dxf13.Point), - 'CIRCLE': (Circle, dxf12.Circle, dxf13.Circle), - 'ARC': (Arc, dxf12.Arc, dxf13.Arc), - 'TRACE': (Trace, dxf12.Trace, dxf13.Trace), - 'SOLID': (Solid, dxf12.Solid, dxf13.Solid), - '3DFACE': (Face, dxf12.Face, dxf13.Face), - 'TEXT': (Text, dxf12.Text, dxf13.Text), - 'INSERT': (Insert, dxf12.Insert, dxf13.Insert), - 'SEQEND': (SeqEnd, dxf12.SeqEnd, dxf13.SeqEnd), - 'ATTRIB': (Attrib, dxf12.Attrib, dxf13.Attrib), - 'ATTDEF': (Attrib, dxf12.Attrib, dxf13.Attdef), - 'POLYLINE': (Polyline, dxf12.Polyline, dxf13.Polyline), - 'VERTEX': (Vertex, dxf12.Vertex, dxf13.Vertex), - 'BLOCK': (Block, dxf12.Block, dxf13.Block), - 'ENDBLK': (BlockEnd, dxf12.EndBlk, dxf13.EndBlk), - 'LWPOLYLINE': (LWPolyline, None, dxf13.LWPolyline), - 'ELLIPSE': (Ellipse, None, dxf13.Ellipse), - 'RAY': (Ray, None, dxf13.Ray), - 'XLINE': (XLine, None, dxf13.XLine), - 'SPLINE': (Spline, None, dxf13.Spline), - 'HELIX': (Helix, None, dxf13.Helix), - 'MTEXT': (MText, None, dxf13.MText), - 'SUN': (Sun, None, dxf13.Sun), - 'MESH': (Mesh, None, dxf13.Mesh), - 'LIGHT': (Light, None, dxf13.Light), - 'BODY': (Body, None, dxf13.Body), - 'REGION': (Body, None, dxf13.Body), - '3DSOLID': (Solid3d, None, dxf13.Solid3d), - 'SURFACE': (Surface, None, dxf13.Surface), - 'PLANESURFACE': (Surface, None, dxf13.Surface), -} - - -def entity_factory(tags, dxfversion): - dxftype = tags.get_type() - cls, dxf12wrapper, dxf13wrapper = EntityTable[dxftype] - wrapper = dxf12wrapper(tags) if dxfversion == "AC1009" else dxf13wrapper(tags) - wrapper.post_read_correction() - shape = cls(wrapper) - return shape - - diff --git a/io_import_dxf/dxfgrabber/entitysection.py b/io_import_dxf/dxfgrabber/entitysection.py old mode 100755 new mode 100644 index e87bbb46..cd717c56 --- a/io_import_dxf/dxfgrabber/entitysection.py +++ b/io_import_dxf/dxfgrabber/entitysection.py @@ -8,8 +8,8 @@ __author__ = "mozman " from itertools import islice from .tags import TagGroups, DXFStructureError -from .tags import ClassifiedTags -from .entities import entity_factory +from .tags import Tags +from .dxfentities import entity_factory class EntitySection(object): @@ -21,7 +21,7 @@ class EntitySection(object): @classmethod def from_tags(cls, tags, drawing): entity_section = cls() - entity_section._build(tags, drawing.dxfversion) + entity_section._build(tags) return entity_section def get_entities(self): @@ -40,21 +40,21 @@ class EntitySection(object): # end of public interface - def _build(self, tags, dxfversion): + def _build(self, tags): if len(tags) == 3: # empty entities section return groups = TagGroups(islice(tags, 2, len(tags)-1)) - self._entities = build_entities(groups, dxfversion) + self._entities = build_entities(groups) class ObjectsSection(EntitySection): name = 'objects' -def build_entities(tag_groups, dxfversion): +def build_entities(tag_groups): def build_entity(group): try: - entity = entity_factory(ClassifiedTags(group), dxfversion) + entity = entity_factory(Tags(group)) except KeyError: entity = None # ignore unsupported entities return entity @@ -71,7 +71,7 @@ def build_entities(tag_groups, dxfversion): collector = None else: collector.append(entity) - elif entity.dxftype == 'POLYLINE': + elif entity.dxftype in ('POLYLINE', 'POLYFACE', 'POLYMESH'): collector = _Collector(entity) elif entity.dxftype == 'INSERT' and entity.attribsfollow: collector = _Collector(entity) diff --git a/io_import_dxf/dxfgrabber/headersection.py b/io_import_dxf/dxfgrabber/headersection.py index 8c709a5e..5c6d1622 100755 --- a/io_import_dxf/dxfgrabber/headersection.py +++ b/io_import_dxf/dxfgrabber/headersection.py @@ -7,6 +7,7 @@ __author__ = "mozman " from .tags import TagGroups, DXFTag + class HeaderSection(dict): name = "header" @@ -31,9 +32,3 @@ class HeaderSection(dict): groups = TagGroups(tags[2:-1], split_code=9) for group in groups: self[group[0].value] = group[1].value - - -class MinVersionError(Exception): - - def __init__(self, version): - Exception.__init__(self, "Minimum Version DXF12 (AC1009) not met. Version found: %s." % version) diff --git a/io_import_dxf/dxfgrabber/juliandate.py b/io_import_dxf/dxfgrabber/juliandate.py old mode 100755 new mode 100644 diff --git a/io_import_dxf/dxfgrabber/layers.py b/io_import_dxf/dxfgrabber/layers.py old mode 100755 new mode 100644 index de6ae39f..02ef66e8 --- a/io_import_dxf/dxfgrabber/layers.py +++ b/io_import_dxf/dxfgrabber/layers.py @@ -6,20 +6,34 @@ __author__ = "mozman " from .tags import TagGroups -from .tags import ClassifiedTags -from .dxfentity import DXFEntity +from .tags import Tags -from .dxfattr import DXFAttr, DXFAttributes, DefSubclass +LOCK = 0b00000100 +FROZEN = 0b00000001 class Layer(object): - def __init__(self, wrapper): - self.name = wrapper.get_dxf_attrib('name') - self.color = wrapper.get_color() - self.linetype = wrapper.get_dxf_attrib('linetype') - self.locked = wrapper.is_locked() - self.frozen = wrapper.is_frozen() - self.on = wrapper.is_on() + def __init__(self, tags): + self.name = "" + self.color = 7 + self.linetype = "" + self.locked = False + self.frozen = False + self.on = True + for code, value in tags.plain_tags(): + if code == 2: + self.name = value + elif code == 70: + self.frozen = bool(value & FROZEN) + self.locked = bool(value & LOCK) + elif code == 62: + if value < 0: + self.on = False + self.color = abs(value) + else: + self.color = value + elif code == 6: + self.linetype = value class Table(object): @@ -55,66 +69,22 @@ class Table(object): # end public interface - def _classified_tags(self, tags): + def entry_tags(self, tags): groups = TagGroups(tags) assert groups.get_name(0) == 'TABLE' assert groups.get_name(-1) == 'ENDTAB' for entrytags in groups[1:-1]: - yield ClassifiedTags(entrytags) + yield Tags(entrytags) class LayerTable(Table): name = 'layers' @staticmethod - def from_tags(tags, drawing): - dxfversion = drawing.dxfversion + def from_tags(tags): layers = LayerTable() - for entrytags in layers._classified_tags(tags): - dxflayer = layers.wrap(entrytags, dxfversion) - layers._table_entries[dxflayer.get_dxf_attrib('name')] = Layer(dxflayer) + for entrytags in layers.entry_tags(tags): + layer = Layer(entrytags) + layers._table_entries[layer.name] = layer return layers - @staticmethod - def wrap(tags, dxfversion): - return DXF12Layer(tags) if dxfversion == "AC1009" else DXF13Layer(tags) - - -class DXF12Layer(DXFEntity): - DXFATTRIBS = DXFAttributes(DefSubclass(None, { - 'handle': DXFAttr(5), - 'name': DXFAttr(2), - 'flags': DXFAttr(70), - 'color': DXFAttr(62), # dxf color index, if < 0 layer is off - 'linetype': DXFAttr(6), - })) - LOCK = 0b00000100 - FROZEN = 0b00000001 - - def is_frozen(self): - return self.get_dxf_attrib('flags') & DXF12Layer.FROZEN > 0 - - def is_locked(self): - return self.get_dxf_attrib('flags') & DXF12Layer.LOCK > 0 - - def is_off(self): - return self.get_dxf_attrib('color') < 0 - - def is_on(self): - return not self.is_off() - - def get_color(self): - return abs(self.get_dxf_attrib('color')) - -none_subclass = DefSubclass(None, {'handle': DXFAttr(5)}) -symbol_subclass = DefSubclass('AcDbSymbolTableRecord', {}) -layer_subclass = DefSubclass('AcDbLayerTableRecord', { - 'name': DXFAttr(2), # layer name - 'flags': DXFAttr(70), - 'color': DXFAttr(62), # dxf color index - 'linetype': DXFAttr(6), # linetype name -}) - - -class DXF13Layer(DXF12Layer): - DXFATTRIBS = DXFAttributes(none_subclass, symbol_subclass, layer_subclass) diff --git a/io_import_dxf/dxfgrabber/linetypes.py b/io_import_dxf/dxfgrabber/linetypes.py old mode 100755 new mode 100644 index 3e2c877e..8e4441bb --- a/io_import_dxf/dxfgrabber/linetypes.py +++ b/io_import_dxf/dxfgrabber/linetypes.py @@ -5,70 +5,34 @@ __author__ = "mozman " -from .dxfentity import DXFEntity from .layers import Table -from .dxfattr import DXFAttr, DXFAttributes, DefSubclass class Linetype(object): - def __init__(self, wrapper): - self.name = wrapper.get_dxf_attrib('name') - self.description = wrapper.get_dxf_attrib('description') - self.length = wrapper.get_dxf_attrib('length') # overall length of the pattern - self.pattern = wrapper.get_pattern() # list of floats: value>0: line, value<0: gap, value=0: dot + def __init__(self, tags): + self.name = "" + self.description = "" + self.length = 0 # overall length of the pattern + self.pattern = [] # list of floats: value>0: line, value<0: gap, value=0: dot + for code, value in tags.plain_tags(): + if code == 2: + self.name = value + elif code == 3: + self.description = value + elif code == 40: + self.length = value + elif code == 49: + self.pattern.append(value) class LinetypeTable(Table): name = 'linetypes' @staticmethod - def from_tags(tags, drawing): - dxfversion = drawing.dxfversion + def from_tags(tags): styles = LinetypeTable() - for entrytags in styles._classified_tags(tags): - dxfstyle = styles.wrap(entrytags, dxfversion) - styles._table_entries[dxfstyle.get_dxf_attrib('name')] = Linetype(dxfstyle) + for entry_tags in styles.entry_tags(tags): + style = Linetype(entry_tags) + styles._table_entries[style.name] = style return styles - - @staticmethod - def wrap(tags, dxfversion): - return DXF12Linetype(tags) if dxfversion == "AC1009" else DXF13Linetype(tags) - - -class DXF12Linetype(DXFEntity): - DXFATTRIBS = DXFAttributes(DefSubclass(None, { - 'handle': DXFAttr(5), - 'name': DXFAttr(2), - 'description': DXFAttr(3), - 'length': DXFAttr(40), - 'items': DXFAttr(73), - })) - - def get_pattern(self): - items = self.get_dxf_attrib('items') - if items == 0: - return [] - else: - tags = self.tags.noclass - return [pattern_tag.value for pattern_tag in tags.find_all(49)] - -none_subclass = DefSubclass(None, {'handle': DXFAttr(5)}) -symbol_subclass = DefSubclass('AcDbSymbolTableRecord', {}) -linetype_subclass = DefSubclass('AcDbLinetypeTableRecord', { - 'name': DXFAttr(2), - 'description': DXFAttr(3), - 'length': DXFAttr(40), - 'items': DXFAttr(73), -}) - - -class DXF13Linetype(DXF12Linetype): - DXFATTRIBS = DXFAttributes(none_subclass, symbol_subclass, linetype_subclass) - def get_pattern(self): - items = self.get_dxf_attrib('items') - if items == 0: - return [] - else: - tags = self.tags.get_subclass('AcDbLinetypeTableRecord') - return [pattern_tag.value for pattern_tag in tags.find_all(49)] diff --git a/io_import_dxf/dxfgrabber/pytags.py b/io_import_dxf/dxfgrabber/pytags.py deleted file mode 100755 index d8d0479b..00000000 --- a/io_import_dxf/dxfgrabber/pytags.py +++ /dev/null @@ -1,385 +0,0 @@ -# Purpose: tag reader -# Created: 21.07.2012, taken from my ezdxf project -# Copyright (C) 2012, Manfred Moitzi -# License: MIT License -from __future__ import unicode_literals -__author__ = "mozman " - -from io import StringIO -from collections import namedtuple -from itertools import chain, islice -from . import tostr - - -DXFTag = namedtuple('DXFTag', 'code value') -NONE_TAG = DXFTag(999999, 'NONE') -APP_DATA_MARKER = 102 -SUBCLASS_MARKER = 100 -XDATA_MARKER = 1001 - - -class DXFStructureError(Exception): - pass - - -def point_tuple(value): - return tuple(float(f) for f in value) - - -POINT_CODES = frozenset(chain(range(10, 20), (210, ), range(110, 113), range(1010, 1020))) - - -def is_point_tag(tag): - return tag[0] in POINT_CODES - - -class TagIterator(object): - def __init__(self, textfile, assure_3d_coords=False): - self.textfile = textfile - self.readline = textfile.readline - self.undo = False - self.last_tag = NONE_TAG - self.undo_coord = None - self.eof = False - self.assure_3d_coords = assure_3d_coords - - def __iter__(self): - return self - - def __next__(self): - def undo_tag(): - self.undo = False - tag = self.last_tag - return tag - - def read_next_tag(): - try: - code = int(self.readline()) - value = self.readline().rstrip('\n') - except UnicodeDecodeError: - raise # because UnicodeDecodeError() is a subclass of ValueError() - except (EOFError, ValueError): - raise StopIteration() - return code, value - - def read_point(code_x, value_x): - try: - code_y, value_y = read_next_tag() # 2. coordinate is always necessary - except StopIteration: - code_y = 0 # -> DXF structure error in following if-statement - - if code_y != code_x + 10: - raise DXFStructureError("invalid 2D/3D point found") - - value_y = float(value_y) - try: - code_z, value_z = read_next_tag() - except StopIteration: # 2D point at end of file - self.eof = True # store reaching end of file - if self.assure_3d_coords: - value = (value_x, value_y, 0.) - else: - value = (value_x, value_y) - else: - if code_z != code_x + 20: # not a Z coordinate -> 2D point - self.undo_coord = (code_z, value_z) - if self.assure_3d_coords: - value = (value_x, value_y, 0.) - else: - value = (value_x, value_y) - else: # is a 3D point - value = (value_x, value_y, float(value_z)) - return value - - def next_tag(): - code = 999 - while code == 999: # skip comments - if self.undo_coord is not None: - code, value = self.undo_coord - self.undo_coord = None - else: - code, value = read_next_tag() - - if code in POINT_CODES: # 2D or 3D point - value = read_point(code, float(value)) # returns a tuple of floats, no casting needed - else: - value = cast_tag_value(code, value) - self.last_tag = DXFTag(code, value) - return self.last_tag - - if self.eof: # stored end of file - raise StopIteration() - - if self.undo: - return undo_tag() - else: - return next_tag() - # for Python 2.7 - next = __next__ - - def undo_tag(self): - if not self.undo: - self.undo = True - else: - raise ValueError('No tag to undo') - - -class StringIterator(TagIterator): - def __init__(self, dxfcontent): - super(StringIterator, self).__init__(StringIO(dxfcontent)) - - -class TagCaster: - def __init__(self): - self._cast = self._build() - - def _build(self): - table = {} - for caster, codes in TYPES: - for code in codes: - table[code] = caster - return table - - def cast(self, tag): - code, value = tag - typecaster = self._cast.get(code, tostr) - try: - value = typecaster(value) - except ValueError: - if typecaster is int: # convert float to int - value = int(float(value)) - else: - raise - return DXFTag(code, value) - - def cast_value(self, code, value): - typecaster = self._cast.get(code, tostr) - try: - return typecaster(value) - except ValueError: - if typecaster is int: # convert float to int - return int(float(value)) - else: - raise - -TYPES = [ - (tostr, range(0, 10)), - (point_tuple, range(10, 20)), - (float, range(20, 60)), - (int, range(60, 100)), - (tostr, range(100, 106)), - (point_tuple, range(110, 113)), - (float, range(113, 150)), - (int, range(170, 180)), - (point_tuple, [210]), - (float, range(211, 240)), - (int, range(270, 290)), - (int, range(290, 300)), # bool 1=True 0=False - (tostr, range(300, 370)), - (int, range(370, 390)), - (tostr, range(390, 400)), - (int, range(400, 410)), - (tostr, range(410, 420)), - (int, range(420, 430)), - (tostr, range(430, 440)), - (int, range(440, 460)), - (float, range(460, 470)), - (tostr, range(470, 480)), - (tostr, range(480, 482)), - (tostr, range(999, 1010)), - (point_tuple, range(1010, 1020)), - (float, range(1020, 1060)), - (int, range(1060, 1072)), -] - -_TagCaster = TagCaster() -cast_tag = _TagCaster.cast -cast_tag_value = _TagCaster.cast_value - - -class Tags(list): - """ DXFTag() chunk as flat list. """ - def find_all(self, code): - """ Returns a list of DXFTag(code, ...). """ - return [tag for tag in self if tag.code == code] - - def tag_index(self, code, start=0, end=None): - """ Return first index of DXFTag(code, ...). """ - if end is None: - end = len(self) - for index, tag in enumerate(islice(self, start, end)): - if tag.code == code: - return start+index - raise ValueError(code) - - def get_value(self, code): - for tag in self: - if tag.code == code: - return tag.value - raise ValueError(code) - - @staticmethod - def from_text(text): - return Tags(StringIterator(text)) - - def get_type(self): - return self.__getitem__(0).value - - -class TagGroups(list): - """ - Group of tags starting with a SplitTag and ending before the next SplitTag. - - A SplitTag is a tag with code == splitcode, like (0, 'SECTION') for splitcode=0. - - """ - def __init__(self, tags, split_code=0): - super(TagGroups, self).__init__() - self._buildgroups(tags, split_code) - - def _buildgroups(self, tags, split_code): - def push_group(): - if len(group) > 0: - self.append(group) - - def start_tag(itags): - tag = next(itags) - while tag.code != split_code: - tag = next(itags) - return tag - - itags = iter(tags) - group = Tags([start_tag(itags)]) - - for tag in itags: - if tag.code == split_code: - push_group() - group = Tags([tag]) - else: - group.append(tag) - push_group() - - def get_name(self, index): - return self[index][0].value - - @staticmethod - def from_text(text, split_code=0): - return TagGroups(Tags.from_text(text), split_code) - - -class ClassifiedTags: - """ Manage Subclasses, AppData and Extended Data """ - - def __init__(self, iterable=None): - self.appdata = list() # code == 102, keys are "{", values are Tags() - self.subclasses = list() # code == 100, keys are "subclassname", values are Tags() - self.xdata = list() # code >= 1000, keys are "APPNAME", values are Tags() - if iterable is not None: - self._setup(iterable) - - @property - def noclass(self): - return self.subclasses[0] - - def _setup(self, iterable): - tagstream = iter(iterable) - - def collect_subclass(start_tag): - """ a subclass can contain appdata, but not xdata, ends with - SUBCLASSMARKER or XDATACODE. - """ - data = Tags() if start_tag is None else Tags([start_tag]) - try: - while True: - tag = next(tagstream) - if tag.code == APP_DATA_MARKER and tag.value[0] == '{': - app_data_pos = len(self.appdata) - data.append(DXFTag(tag.code, app_data_pos)) - collect_appdata(tag) - elif tag.code in (SUBCLASS_MARKER, XDATA_MARKER): - self.subclasses.append(data) - return tag - else: - data.append(tag) - except StopIteration: - pass - self.subclasses.append(data) - return NONE_TAG - - def collect_appdata(starttag): - """ appdata, can not contain xdata or subclasses """ - data = Tags([starttag]) - while True: - try: - tag = next(tagstream) - except StopIteration: - raise DXFStructureError("Missing closing DXFTag(102, '}') for appdata structure.") - data.append(tag) - if tag.code == APP_DATA_MARKER: - break - self.appdata.append(data) - - def collect_xdata(starttag): - """ xdata are always at the end of the entity and can not contain - appdata or subclasses - """ - data = Tags([starttag]) - try: - while True: - tag = next(tagstream) - if tag.code == XDATA_MARKER: - self.xdata.append(data) - return tag - else: - data.append(tag) - except StopIteration: - pass - self.xdata.append(data) - return NONE_TAG - - tag = collect_subclass(None) # preceding tags without a subclass - while tag.code == SUBCLASS_MARKER: - tag = collect_subclass(tag) - while tag.code == XDATA_MARKER: - tag = collect_xdata(tag) - - if tag is not NONE_TAG: - raise DXFStructureError("Unexpected tag '%r' at end of entity." % tag) - - def __iter__(self): - for subclass in self.subclasses: - for tag in subclass: - if tag.code == APP_DATA_MARKER and isinstance(tag.value, int): - for subtag in self.appdata[tag.value]: - yield subtag - else: - yield tag - - for xdata in self.xdata: - for tag in xdata: - yield tag - - def get_subclass(self, name): - for subclass in self.subclasses: - if len(subclass) and subclass[0].value == name: - return subclass - raise KeyError("Subclass '%s' does not exist." % name) - - def get_xdata(self, appid): - for xdata in self.xdata: - if xdata[0].value == appid: - return xdata - raise ValueError("No extended data for APPID '%s'" % appid) - - def get_appdata(self, name): - for appdata in self.appdata: - if appdata[0].value == name: - return appdata - raise ValueError("Application defined group '%s' does not exist." % name) - - def get_type(self): - return self.noclass[0].value - - @staticmethod - def from_text(text): - return ClassifiedTags(StringIterator(text)) diff --git a/io_import_dxf/dxfgrabber/sections.py b/io_import_dxf/dxfgrabber/sections.py index c1b03714..286ebf09 100755 --- a/io_import_dxf/dxfgrabber/sections.py +++ b/io_import_dxf/dxfgrabber/sections.py @@ -8,7 +8,6 @@ __author__ = "mozman " from .codepage import toencoding from .defaultchunk import DefaultChunk, iterchunks from .headersection import HeaderSection -from .headersection import MinVersionError from .tablessection import TablesSection from .entitysection import EntitySection, ObjectsSection from .blockssection import BlocksSection @@ -30,11 +29,6 @@ class Sections(object): section = cls() self._sections[section.name] = section - def check_min_version(self, version_string): - v = int(version_string.replace("AC", "")) - if v < 1009: - raise MinVersionError(version_string) - def _setup_sections(self, tagreader, drawing): def name(section): return section[1].value @@ -44,7 +38,6 @@ class Sections(object): if bootstrap: new_section = HeaderSection.from_tags(section) drawing.dxfversion = new_section.get('$ACADVER', 'AC1009') - self.check_min_version(drawing.dxfversion) codepage = new_section.get('$DWGCODEPAGE', 'ANSI_1252') drawing.encoding = toencoding(codepage) bootstrap = False diff --git a/io_import_dxf/dxfgrabber/styles.py b/io_import_dxf/dxfgrabber/styles.py old mode 100755 new mode 100644 index 8553bc4f..3d5dc5e0 --- a/io_import_dxf/dxfgrabber/styles.py +++ b/io_import_dxf/dxfgrabber/styles.py @@ -5,75 +5,52 @@ from __future__ import unicode_literals __author__ = "mozman " -from .dxfentity import DXFEntity from .layers import Table -from .dxfattr import DXFAttr, DXFAttributes, DefSubclass -from .tags import ClassifiedTags +from .tags import Tags class Style(object): - def __init__(self, wrapper): - self.name = wrapper.get_dxf_attrib('name') - self.height = wrapper.get_dxf_attrib('height') - self.width = wrapper.get_dxf_attrib('width') - self.oblique = wrapper.get_dxf_attrib('oblique') - # backward & mirror_y was first and stays for compatibility - self.backward = bool(wrapper.get_dxf_attrib('generation_flags') & 2) - self.mirror_y = bool(wrapper.get_dxf_attrib('generation_flags') & 4) - self.is_backwards = self.backward - self.is_upside_down = self.mirror_y - self.font = wrapper.get_dxf_attrib('font') - self.bigfont = wrapper.get_dxf_attrib('bigfont', "") + def __init__(self, tags): + self.name = "" + self.height = 1.0 + self.width = 1.0 + self.oblique = 0. + self.is_backwards = False + self.is_upside_down = False + self.font = "" + self.big_font = "" + for code, value in tags.plain_tags(): + if code == 2: + self.name = value + elif code == 70: + self.flags = value + elif code == 40: + self.height = value + elif code == 41: + self.width = value + elif code == 50: + self.oblique = value + elif code == 71: + self.is_backwards = bool(value & 2) + self.is_upside_down = bool(value & 4) + self.oblique = value + elif code == 3: + self.font = value + elif code == 4: + self.big_font = value class StyleTable(Table): name = 'styles' @staticmethod - def from_tags(tags, drawing): - dxfversion = drawing.dxfversion + def from_tags(tags): styles = StyleTable() - for entrytags in styles._classified_tags(tags): - dxfstyle = styles.wrap(entrytags, dxfversion) - styles._table_entries[dxfstyle.get_dxf_attrib('name')] = Style(dxfstyle) + for entry_tags in styles.entry_tags(tags): + style = Style(entry_tags) + styles._table_entries[style.name] = style return styles - @staticmethod - def wrap(tags, dxfversion): - return DXF12Style(tags) if dxfversion == "AC1009" else DXF13Style(tags) - - -class DXF12Style(DXFEntity): - DXFATTRIBS = DXFAttributes(DefSubclass(None, { - 'handle': DXFAttr(5), - 'name': DXFAttr(2), - 'flags': DXFAttr(70), - 'height': DXFAttr(40), # fixed height, 0 if not fixed - 'width': DXFAttr(41), # width factor - 'oblique': DXFAttr(50), # oblique angle in degree, 0 = vertical - 'generation_flags': DXFAttr(71), # 2 = backward, 4 = mirrored in Y - 'last_height': DXFAttr(42), # last height used - 'font': DXFAttr(3), # primary font file name - 'bigfont': DXFAttr(4), # big font name, blank if none - })) - -none_subclass = DefSubclass(None, {'handle': DXFAttr(5)}) -symbol_subclass = DefSubclass('AcDbSymbolTableRecord', {}) -style_subclass = DefSubclass('AcDbTextStyleTableRecord', { - 'name': DXFAttr(2), - 'flags': DXFAttr(70), - 'height': DXFAttr(40), # fixed height, 0 if not fixed - 'width': DXFAttr(41), # width factor - 'oblique': DXFAttr(50), # oblique angle in degree, 0 = vertical - 'generation_flags': DXFAttr(71), # 2 = backward, 4 = mirrored in Y - 'last_height': DXFAttr(42), # last height used - 'font': DXFAttr(3), # primary font file name - 'bigfont': DXFAttr(4), # big font name, blank if none -}) - - -class DXF13Style(DXF12Style): - DXFATTRIBS = DXFAttributes(none_subclass, symbol_subclass, style_subclass) DEFAULT_STYLE = """ 0 STYLE @@ -97,4 +74,4 @@ Arial """ -default_text_style = Style(DXF12Style(ClassifiedTags.from_text(DEFAULT_STYLE))) \ No newline at end of file +default_text_style = Style(Tags.from_text(DEFAULT_STYLE)) diff --git a/io_import_dxf/dxfgrabber/tablessection.py b/io_import_dxf/dxfgrabber/tablessection.py old mode 100755 new mode 100644 index 3737138a..345487fa --- a/io_import_dxf/dxfgrabber/tablessection.py +++ b/io_import_dxf/dxfgrabber/tablessection.py @@ -29,12 +29,6 @@ def tablename(dxfname): return TABLENAMES.get(name, name+'s') -class GenericTable(DefaultChunk): - @property - def name(self): - return tablename(self.tags[1].value) - - class DefaultDrawing(object): dxfversion = 'AC1009' encoding = 'cp1252' @@ -43,9 +37,8 @@ class DefaultDrawing(object): class TablesSection(object): name = 'tables' - def __init__(self, drawing=DefaultDrawing()): + def __init__(self): self._tables = dict() - self._drawing = drawing self._create_default_tables() def _create_default_tables(self): @@ -55,7 +48,7 @@ class TablesSection(object): @staticmethod def from_tags(tags, drawing): - tables_section = TablesSection(drawing) + tables_section = TablesSection() tables_section._setup_tables(tags) return tables_section @@ -71,8 +64,9 @@ class TablesSection(object): itertags = skiptags(iter(tags), 2) # (0, 'SECTION'), (2, 'TABLES') for table in iterchunks(itertags, stoptag='ENDSEC', endofchunk='ENDTAB'): table_class = table_factory(name(table)) - new_table = table_class.from_tags(table, self._drawing) - self._tables[new_table.name] = new_table + if table_class is not None: + new_table = table_class.from_tags(table) + self._tables[new_table.name] = new_table def __getattr__(self, key): try: @@ -89,4 +83,4 @@ TABLESMAP = { def table_factory(name): - return TABLESMAP.get(name, GenericTable) + return TABLESMAP.get(name, None) diff --git a/io_import_dxf/dxfgrabber/tags.py b/io_import_dxf/dxfgrabber/tags.py old mode 100755 new mode 100644 index fed6aa88..b406bd02 --- a/io_import_dxf/dxfgrabber/tags.py +++ b/io_import_dxf/dxfgrabber/tags.py @@ -5,32 +5,410 @@ from __future__ import unicode_literals __author__ = "mozman " -import os -from .const import ENV_CYTHON - -OPTIMIZE = True -if ENV_CYTHON in os.environ: - if os.environ[ENV_CYTHON].upper() in ('1', 'ON', 'TRUE'): - OPTIMIZE = True - else: - OPTIMIZE = False -try: - if not OPTIMIZE: - raise ImportError - CYTHON_EXT = True - from.cytags import TagIterator, Tags, TagGroups, DXFTag, NONE_TAG - from.cytags import DXFStructureError, StringIterator, ClassifiedTags -except ImportError: - CYTHON_EXT = False - from.pytags import TagIterator, Tags, TagGroups, DXFTag, NONE_TAG - from.pytags import DXFStructureError, StringIterator, ClassifiedTags - - import sys from .codepage import toencoding from .const import acadrelease from array import array +from io import StringIO +from collections import namedtuple +from itertools import chain, islice +from . import tostr + + +DXFTag = namedtuple('DXFTag', 'code value') +NONE_TAG = DXFTag(999999, 'NONE') +APP_DATA_MARKER = 102 +SUBCLASS_MARKER = 100 +XDATA_MARKER = 1001 + + +class DXFStructureError(Exception): + pass + + +def point_tuple(value): + return tuple(float(f) for f in value) + + +POINT_CODES = frozenset(chain(range(10, 20), (210, ), range(110, 113), range(1010, 1020))) + + +def is_point_tag(tag): + return tag[0] in POINT_CODES + + +class TagCaster: + def __init__(self): + self._cast = self._build() + + def _build(self): + table = {} + for caster, codes in TYPES: + for code in codes: + table[code] = caster + return table + + def cast(self, tag): + code, value = tag + typecaster = self._cast.get(code, tostr) + try: + value = typecaster(value) + except ValueError: + if typecaster is int: # convert float to int + value = int(float(value)) + else: + raise + return DXFTag(code, value) + + def cast_value(self, code, value): + typecaster = self._cast.get(code, tostr) + try: + return typecaster(value) + except ValueError: + if typecaster is int: # convert float to int + return int(float(value)) + else: + raise + +TYPES = [ + (tostr, range(0, 10)), + (point_tuple, range(10, 20)), + (float, range(20, 60)), + (int, range(60, 100)), + (tostr, range(100, 106)), + (point_tuple, range(110, 113)), + (float, range(113, 150)), + (int, range(170, 180)), + (point_tuple, [210]), + (float, range(211, 240)), + (int, range(270, 290)), + (int, range(290, 300)), # bool 1=True 0=False + (tostr, range(300, 370)), + (int, range(370, 390)), + (tostr, range(390, 400)), + (int, range(400, 410)), + (tostr, range(410, 420)), + (int, range(420, 430)), + (tostr, range(430, 440)), + (int, range(440, 460)), + (float, range(460, 470)), + (tostr, range(470, 480)), + (tostr, range(480, 482)), + (tostr, range(999, 1010)), + (point_tuple, range(1010, 1020)), + (float, range(1020, 1060)), + (int, range(1060, 1072)), +] + +_TagCaster = TagCaster() +cast_tag = _TagCaster.cast +cast_tag_value = _TagCaster.cast_value + + +def stream_tagger(stream, assure_3d_coords=False): + """ Generates DXFTag() from a stream (untrusted external source). Does not skip comment tags 999. + """ + class Counter: + def __init__(self): + self.counter = 0 + + undo_tag = None + line = Counter() # writeable line counter for next_tag(), Python 2.7 does not support the nonlocal statement + + def next_tag(): + code = stream.readline() + value = stream.readline() + line.counter += 2 + if code and value: # StringIO(): empty strings indicates EOF + return DXFTag(int(code[:-1]), value[:-1]) # without '\n' + else: # StringIO(): missing '\n' indicates EOF + raise EOFError() + + while True: + try: + if undo_tag is not None: + x = undo_tag + undo_tag = None + else: + x = next_tag() + code = x.code + if code == 999: # skip comments + continue + if code in POINT_CODES: + y = next_tag() # y coordinate is mandatory + if y.code != code + 10: + raise DXFStructureError("Missing required y coordinate near line: {}.".format(line.counter)) + z = next_tag() # z coordinate just for 3d points + try: + if z.code == code + 20: + point = (float(x.value), float(y.value), float(z.value)) + else: + if assure_3d_coords: + point = (float(x.value), float(y.value), 0.) + else: + point = (float(x.value), float(y.value)) + undo_tag = z + except ValueError: + raise DXFStructureError('Invalid floating point values near line: {}.'.format(line.counter)) + yield DXFTag(code, point) + else: # just a single tag + try: + yield cast_tag(x) + except ValueError: + raise DXFStructureError('Invalid tag (code={code}, value="{value}") near line: {line}.'.format( + line=line.counter, + code=x.code, + value=x.value, + )) + except EOFError: + return + + +def string_tagger(s): + return stream_tagger(StringIO(s)) + + +class Tags(list): + """ DXFTag() chunk as flat list. """ + def find_all(self, code): + """ Returns a list of DXFTag(code, ...). """ + return [tag for tag in self if tag.code == code] + + def tag_index(self, code, start=0, end=None): + """Return first index of DXFTag(code, value). + """ + if end is None: + end = len(self) + index = start + while index < end: + if self[index].code == code: + return index + index += 1 + raise ValueError(code) + + def get_value(self, code): + for tag in self: + if tag.code == code: + return tag.value + raise ValueError(code) + + @staticmethod + def from_text(text): + return Tags(string_tagger(text)) + + def get_type(self): + return self.__getitem__(0).value + + def plain_tags(self): # yield no app data and no xdata + is_app_data = False + for tag in self: + if tag.code >= 1000: # skip xdata + continue + if tag.code == APP_DATA_MARKER: + if is_app_data: # tag.value == '}' + is_app_data = False # end of app data + else: # value == '{APPID' + is_app_data = True # start of app data + continue + if not is_app_data: + yield tag + + def xdata(self): + index = 0 + end = len(self) + while index < end: + if self[index].code > 999: # all xdata tag codes are >= 1000 + return self[index:] # xdata is always at the end of the DXF entity + index += 1 + return [] + + def app_data(self): + app_data = {} + app_tags = None + for tag in self: + if tag.code == APP_DATA_MARKER: + if tag.value == '}': # end of app data + app_tags.append(tag) + app_data[app_tags[0].value] = app_tags + app_tags = None + else: + app_tags = [tag] + else: + if app_tags is not None: # collection app data + app_tags.append(tag) + return app_data + + def subclasses(self): + classes = {} + name = 'noname' + tags = [] + for tag in self.plain_tags(): + if tag.code == SUBCLASS_MARKER: + classes[name] = tags + tags = [] + name = tag.value + else: + tags.append(tag) + classes[name] = tags + return classes + + def get_subclass(self, name): + classes = self.subclasses() + return classes.get(name, 'noname') + + +class TagGroups(list): + """ + Group of tags starting with a SplitTag and ending before the next SplitTag. + + A SplitTag is a tag with code == splitcode, like (0, 'SECTION') for splitcode=0. + + """ + def __init__(self, tags, split_code=0): + super(TagGroups, self).__init__() + self._build_groups(tags, split_code) + + def _build_groups(self, tags, splitcode): + def append(tag): # first do nothing, skip tags in front of the first split tag + pass + group = None + for tag in tags: # has to work with iterators/generators + if tag.code == splitcode: + if group is not None: + self.append(group) + group = Tags([tag]) + append = group.append # redefine append: add tags to this group + else: + append(tag) + if group is not None: + self.append(group) + + def get_name(self, index): + return self[index][0].value + + @staticmethod + def from_text(text, split_code=0): + return TagGroups(Tags.from_text(text), split_code) + + +class ClassifiedTags: + """ Manage Subclasses, AppData and Extended Data """ + + def __init__(self, iterable=None): + self.appdata = list() # code == 102, keys are "{", values are Tags() + self.subclasses = list() # code == 100, keys are "subclassname", values are Tags() + self.xdata = list() # code >= 1000, keys are "APPNAME", values are Tags() + if iterable is not None: + self._setup(iterable) + + @property + def noclass(self): + return self.subclasses[0] + + def _setup(self, iterable): + tagstream = iter(iterable) + + def collect_subclass(start_tag): + """ a subclass can contain appdata, but not xdata, ends with + SUBCLASSMARKER or XDATACODE. + """ + data = Tags() if start_tag is None else Tags([start_tag]) + try: + while True: + tag = next(tagstream) + if tag.code == APP_DATA_MARKER and tag.value[0] == '{': + app_data_pos = len(self.appdata) + data.append(DXFTag(tag.code, app_data_pos)) + collect_appdata(tag) + elif tag.code in (SUBCLASS_MARKER, XDATA_MARKER): + self.subclasses.append(data) + return tag + else: + data.append(tag) + except StopIteration: + pass + self.subclasses.append(data) + return NONE_TAG + + def collect_appdata(starttag): + """ appdata, can not contain xdata or subclasses """ + data = Tags([starttag]) + while True: + try: + tag = next(tagstream) + except StopIteration: + raise DXFStructureError("Missing closing DXFTag(102, '}') for appdata structure.") + data.append(tag) + if tag.code == APP_DATA_MARKER: + break + self.appdata.append(data) + + def collect_xdata(starttag): + """ xdata are always at the end of the entity and can not contain + appdata or subclasses + """ + data = Tags([starttag]) + try: + while True: + tag = next(tagstream) + if tag.code == XDATA_MARKER: + self.xdata.append(data) + return tag + else: + data.append(tag) + except StopIteration: + pass + self.xdata.append(data) + return NONE_TAG + + tag = collect_subclass(None) # preceding tags without a subclass + while tag.code == SUBCLASS_MARKER: + tag = collect_subclass(tag) + while tag.code == XDATA_MARKER: + tag = collect_xdata(tag) + + if tag is not NONE_TAG: + raise DXFStructureError("Unexpected tag '%r' at end of entity." % tag) + + def __iter__(self): + for subclass in self.subclasses: + for tag in subclass: + if tag.code == APP_DATA_MARKER and isinstance(tag.value, int): + for subtag in self.appdata[tag.value]: + yield subtag + else: + yield tag + + for xdata in self.xdata: + for tag in xdata: + yield tag + + def get_subclass(self, name): + for subclass in self.subclasses: + if len(subclass) and subclass[0].value == name: + return subclass + raise KeyError("Subclass '%s' does not exist." % name) + + def get_xdata(self, appid): + for xdata in self.xdata: + if xdata[0].value == appid: + return xdata + raise ValueError("No extended data for APPID '%s'" % appid) + + def get_appdata(self, name): + for appdata in self.appdata: + if appdata[0].value == name: + return appdata + raise ValueError("Application defined group '%s' does not exist." % name) + + def get_type(self): + return self.noclass[0].value + + @staticmethod + def from_text(text): + return ClassifiedTags(string_tagger(text)) + class DXFInfo(object): def __init__(self): @@ -53,7 +431,7 @@ class DXFInfo(object): def dxfinfo(stream): info = DXFInfo() tag = DXFTag(999999, '') - tagreader = TagIterator(stream) + tagreader = stream_tagger(stream) while tag != DXFTag(0, 'ENDSEC'): tag = next(tagreader) if tag.code != 9: diff --git a/io_import_dxf/dxfimport/convert.py b/io_import_dxf/dxfimport/convert.py index 8260b519..c21d274c 100644 --- a/io_import_dxf/dxfimport/convert.py +++ b/io_import_dxf/dxfimport/convert.py @@ -78,7 +78,7 @@ def bspline_to_cubic(do, en, curve, errors=None): return new_spline knots = list(en.knots) - spline = [ShortVec(cp) for cp in en.controlpoints] + spline = [ShortVec(cp) for cp in en.control_points] degree = len(knots) - len(spline) - 1 if degree <= 3: clean_knots() diff --git a/io_import_dxf/dxfimport/do.py b/io_import_dxf/dxfimport/do.py index e6eb45ea..4b73eaac 100644 --- a/io_import_dxf/dxfimport/do.py +++ b/io_import_dxf/dxfimport/do.py @@ -281,10 +281,10 @@ class Do: def arc(self, en, curve=None, aunits=None, angdir=None, angbase=None): """ - en: dxf entity (en.startangle, en.endangle, en.center, en.radius) + en: dxf entity (en.start_angle, en.end_angle, en.center, en.radius) curve: optional; Blender curve data of type "CURVE" (object.data) to which the arc should be added to return control points of a cubic spline (do be used in a spline with bulges / series of arcs) - note: en.startangle + en.endangle: angles measured from the angle base (angbase) in the direction of + note: en.start_angle + en.end_angle: angles measured from the angle base (angbase) in the direction of angdir (1 = clockwise, 0 = counterclockwise) """ treshold = 0.005 @@ -298,11 +298,11 @@ class Do: kappa = 0.5522848 if aunits == 0: - s = radians(en.startangle+angbase) - e = radians(en.endangle+angbase) + s = radians(en.start_angle+angbase) + e = radians(en.end_angle+angbase) else: - s = en.startangle+angbase - e = en.endangle+angbase + s = en.start_angle+angbase + e = en.end_angle+angbase if s > e: e += 2 * pi @@ -420,7 +420,7 @@ class Do: ratio: ratio between major and minor axis lengths (always < 1) curve: Blender curve data of type "CURVE" (object.data) to which the ellipse should be added to """ - major = Vector(en.majoraxis) + major = Vector(en.major_axis) en.__dict__["radius"] = major.length c = self.circle(en, curve, major.normalized()) b = c.bezier_points @@ -755,7 +755,7 @@ class Do: ratio = 50 / en.rect_width d.size = en.height * ratio * 1.4 # XXX HACK scale = (1 / ratio, 1 / ratio, 1 / ratio) - d.space_line = en.linespacing + d.space_line = en.line_spacing else: width = en.rect_width scale = (1, 1, 1) @@ -1494,6 +1494,8 @@ class Do: if self.but_group_by_att and self.combination != BY_CLOSED_NO_BULGE_POLY and self.combination != BY_BLOCK: for atts, by_att in groupsort.by_attributes(grouped_entities): thickness, subd, width, extrusion = atts + if extrusion is None: # unset extrusion defaults to (0, 0, 1) + extrusion = (0, 0, 1) att = "" if thickness != 0: att += "thickness" + str(thickness) + ", " diff --git a/io_import_dxf/dxfimport/fake_entities.py b/io_import_dxf/dxfimport/fake_entities.py index a3df42f0..35338a7d 100644 --- a/io_import_dxf/dxfimport/fake_entities.py +++ b/io_import_dxf/dxfimport/fake_entities.py @@ -25,15 +25,15 @@ class ArcEntity: an arc. ArcEntity is just used to call do.arc() without having a real Arc-Entity from dxfgrabber. """ def __init__(self, start, end, center, radius, angdir): - self.startangle = start - self.endangle = end + self.start_angle = start + self.end_angle = end self.center = center self.radius = radius self.angdir = angdir def __str__(self): return "startangle: %s, endangle: %s, center: %s, radius: %s, angdir: %s" % \ - (str(self.startangle), str(self.endangle), str(self.center), str(self.radius), str(self.angdir)) + (str(self.start_angle), str(self.end_angle), str(self.center), str(self.radius), str(self.angdir)) class LineEntity: diff --git a/io_import_dxf/dxfimport/is_.py b/io_import_dxf/dxfimport/is_.py index 20d6fe43..6a8977a5 100644 --- a/io_import_dxf/dxfimport/is_.py +++ b/io_import_dxf/dxfimport/is_.py @@ -106,7 +106,10 @@ def varying_width(entity): if hasattr(entity, "width"): ew = entity.width if hasattr(ew, "__iter__"): - return ew.count(ew[0]) != len(ew) or ew[0][0] != ew[0][1] + if len(ew) == 0: + return False + else: + return ew.count(ew[0]) != len(ew) or ew[0][0] != ew[0][1] return False -- cgit v1.2.3