diff options
Diffstat (limited to 'io_import_dxf/dxfgrabber/entities.py')
-rwxr-xr-x | io_import_dxf/dxfgrabber/entities.py | 930 |
1 files changed, 0 insertions, 930 deletions
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 <mozman@gmx.at>" - -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 - - |