class DXFLoader(GenericLoader): functions={ "POP_TRAFO": 'pop_trafo', "TABLE": 'load_TABLE', "BLOCK": 'load_BLOCK', "LINE": 'load_line', "LWPOLYLINE": 'load_lwpolyline', "POLYLINE": 'load_polyline', "SEQEND": 'load_seqend', "VERTEX": 'load_vertex', "CIRCLE": 'load_circle', "ARC": 'load_arc', "ELLIPSE": 'load_ellips', "POINT": 'load_point', "SOLID": 'load_solid', "INSERT": 'load_insert', "TEXT": 'load_text', #"MTEXT": 'load_text', "3DFACE": 'load_3dface', "SPLINE": 'load_spline', "VIEWPORT": 'load_bypass', } def __init__(self, file, filename, match): GenericLoader.__init__(self, file, filename, match) self.file = file self.DWGCODEPAGE = 'latin1' self.unit_to_pt = 2.83464566929 self.dynamic_style_dict = {} self.style_dict = {} self.ltype_dict = {'CONTINUOUS': { '2': 'CONTINUOUS', # Linetype name '3': 'Solid line', # Descriptive text for linetype '49': [], # Dash, dot or space length #(one entry per element) } } self.layer_dict = {'0': { '2': '0', # Layer name '6': 'CONTINUOUS', #Linetype name '62': 0, # Color number '370': None, #Line weight } } self.block_dict = {} self.stack = [] self.stack_trafo = [] self.default_layer = '0' self.default_style = 'STANDARD' self.default_block = None self.default_line_width = 30 self.EXTMIN = (1e+20, 1e+20) self.EXTMAX = (-1e+20, -1e+20) self.PEXTMIN = (1e+20, 1e+20) self.PEXTMAX = (-1e+20, -1e+20) self.general_param = { '8': self.default_layer, # Layer name '6': 'BYLAYER', # Linetype name '62': 256, # Color number '48': 1.0, # Linetype scale #'60': 0, # Object visibility. If 1 Invisible } self.curstyle = Style() self.update_trafo() def update_trafo(self, scale = 1): EXT_hight = self.EXTMAX[0] - self.EXTMIN[0] EXT_width = self.EXTMAX[1] - self.EXTMIN[1] PEXT_hight = self.PEXTMAX[0] - self.PEXTMIN[0] PEXT_width = self.PEXTMAX[1] - self.PEXTMIN[1] if EXT_hight > 0: scale = 840 / max(EXT_hight, EXT_width) self.unit_to_pt = scale x = self.EXTMIN[0] * scale y = self.EXTMIN[1] * scale elif PEXT_hight > 0: scale = 840 / max(PEXT_hight, PEXT_width) self.unit_to_pt = scale x = self.PEXTMIN[0] * scale y = self.PEXTMIN[1] * scale else: x = 0 y = 0 self.trafo = Trafo(scale, 0, 0, scale, -x, -y) def push_trafo(self, trafo = None): # save trafo in stack_trafo if trafo is None: trafo = self.trafo self.stack_trafo.append(trafo) def pop_trafo(self): self.trafo = self.stack_trafo.pop() def get_pattern(self, color_index): # 0 = Color BYBLOCK if color_index == 0: block_name = self.default_block if block_name is None: layer_name = '0' else: layer_name = self.block_dict[block_name]['8'] color_index = self.layer_dict[layer_name]['62'] # 256 = Color BYLAYER if color_index == 256 or color_index is None: layer_name = self.default_layer color_index = self.layer_dict[layer_name]['62'] ## FIXMY 257 = Color BYENTITY if color_index < 0: pattern = EmptyPattern else: pattern = SolidPattern(colors[color_index]) return pattern def get_line_width(self, layer_name = None): if layer_name is None: layer_name = self.default_layer layer = self.layer_dict[layer_name] if '370' in layer: width = layer['370'] if width == -3 or width is None: width = self.default_line_width width = width * 72.0 / 2.54 /1000 # th 100 mm to pt if width <= 0.0: # XXX width = 0.1 return width def get_line_type(self, linetype_name = None, scale = 1.0, width = 1.0, layer_name = None): #if linetype_name == 'BYBLOCK': #block_name = self.default_block #layer_name = self.block_dict[block_name]['8'] if layer_name is None: layer_name = self.default_layer if linetype_name is None or linetype_name == 'BYLAYER' or linetype_name == 'BYBLOCK': linetype_name = self.layer_dict[layer_name]['6'] linetype = self.ltype_dict[upper(linetype_name)]['49'] lscale = scale * self.unit_to_pt / width dashes = map(lambda i : abs(linetype[i]) * lscale, xrange(len(linetype))) return tuple(dashes) def get_line_style(self, **kw): if kw['8'] in self.layer_dict: self.default_layer = layer_name = kw['8'] else: layer_name = self.default_layer linetype_name = upper(kw['6']) scale = kw['48'] color_index = kw['62'] style = Style() style.line_width = self.get_line_width() style.line_join = const.JoinRound style.line_cap = const.CapRound style.line_dashes = self.get_line_type(linetype_name = linetype_name, scale = scale, width = style.line_width) style.line_pattern = self.get_pattern(color_index) return style ################ # HEADER Section # def load_HEADER(self): return_code = False header_dict = {} variable = None params = {} line1, line2 = self.read_record() while line1 or line2: if variable and (line1 == '9' or line1 == '0'): header_dict[variable] = params else: params[line1] = line2 if line1 == '0' and line2 == 'ENDSEC': return_code = True break elif line1 == '9': params = {} variable = line2 line1, line2 = self.read_record() return return_code, header_dict def process_header(self, header): if '$DWGCODEPAGE' in header: self.DWGCODEPAGE = 'cp'+ upper(header['$DWGCODEPAGE']['3']).replace('ANSI_', '').replace('DOS','') if '$INSUNITS' in header: INSUNITS = convert('70', header['$INSUNITS']['70']) if INSUNITS in unit: self.unit_to_pt = unit[INSUNITS] if '$EXTMIN' in header: param10 = convert('10', header['$EXTMIN']['10']) param20 = convert('20', header['$EXTMIN']['20']) self.EXTMIN = (param10, param20) if '$EXTMAX' in header: param10 = convert('10', header['$EXTMAX']['10']) param20 = convert('20', header['$EXTMAX']['20']) self.EXTMAX = (param10, param20) if '$PEXTMIN' in header: param10 = convert('10', header['$PEXTMIN']['10']) param20 = convert('20', header['$PEXTMIN']['20']) self.PEXTMIN = (param10, param20) if '$PEXTMAX' in header: param10 = convert('10', header['$PEXTMAX']['10']) param20 = convert('20', header['$PEXTMAX']['20']) self.PEXTMAX = (param10, param20) self.update_trafo() if '$CLAYER' in header: self.default_layer = convert('8', header['$CLAYER']['8'], self.DWGCODEPAGE) ################ # TABLES Section # def load_TABLE(self): param={ '2': '', # Table name '70': 0 # Maximum number of entries in table } param = self.read_param(param) table_name = param['2'] table_number = param['70'] print '****', table_name, table_number line1, line2 = self.read_record() while line1 or line2: if line1 == '0' and line2 == 'ENDTAB': break if table_name == 'LTYPE': self.load_LTYPE() elif table_name == 'LAYER': self.load_LAYER() elif table_name == 'STYLE': self.load_STYLE() line1, line2 = self.read_record() def load_LTYPE(self): param={ '2': '', # Linetype name '3': '', # Descriptive text for linetype #'73': 0, # The number of linetype elements #'40': 0, # Total pattern length '49': [], # Dash, dot or space length (one entry per element) } param = self.read_param(param, [0]) name = upper(param['2']) if name: self.ltype_dict[name] = param dashes = [] for i in xrange(len(param['49'])): dashes.append(abs(param['49'][i]) * self.unit_to_pt) name3 = param['3'] #print name3, dashes if name3 and dashes: style = Style() style.line_dashes = tuple(dashes) style = style.AsDynamicStyle() style.SetName(name + name3) self.dynamic_style_dict[name] = style def load_LAYER(self): param={ '2': None, # Layer name '6': None, #Linetype name '62': 0, # Color number '370': None, #Line weight } param = self.read_param(param, [0]) layer_name = param['2'] if layer_name: self.layer_dict[layer_name]=param self.layer(name = layer_name) def load_STYLE(self): param={ '2': None, # Style name '70': 0, # Flag '40': 0.0, # Fixed text height; 0 if not fixed '41': 0.0, # Width factor '42': 0.0, # Last height used '50': 0.0, # Oblique angle '71': 0, # Text generation flags '3': None, # Primary font file name '4': None, # Bigfont file name '1000': None, } param = self.read_param(param, [0]) style_name = upper(param['2']) self.style_dict[style_name] = param ################ # BLOCKS Section # def load_BLOCK(self): param={ '2': '', # Block name '10': 0.0, # X Base point '20': 0.0, # Y Base point #'30': 0.0, # Z Base point '8': self.default_layer, # Layer name 'data': [], # block data } param = self.read_param(param) block_name = param['2'] print '****', block_name line1, line2 = self.read_record() while line1 or line2: if line1 == '0' and line2 == 'ENDBLK': param = self.read_param(param) break param['data'].append(line1) param['data'].append(line2) line1, line2 = self.read_record() param['data'].reverse() self.block_dict[block_name] = param # print self.block_dict[block_name] ################ # ENTITIES Section # def load_line(self): param={ '10': None, # X coordinat '20': None, # y coordinat #'30': None, # Z coordinat '11': None, # X coordinat endpoint '21': None, # y coordinat endpoint #'31': None, # z coordinat endpoint } param.update(self.general_param) param = self.read_param(param) self.path = CreatePath() self.path.AppendLine(self.trafo(param['10'], param['20'])) self.path.AppendLine(self.trafo(param['11'], param['21'])) style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) self.bezier(self.path,) def load_lwpolyline(self): param={ '90': 0, # Number of vertices '70': 0, # bit codes for Polyline entity '40': None, # Starting width '43': 0, '370': None, #Line weight } param.update(self.general_param) param = self.read_param(param,[10,20,42]) if param['40'] is not None: line_width = param['40'] * self.unit_to_pt else: line_width = param['43'] * self.unit_to_pt if param['370'] is not None: line_width = param['370'] * self.unit_to_pt * 72.0 / 2.54 /1000 self.curstyle = self.get_line_style(**param) # if Group 70 Flag bit value set 1 This is a closed Polyline path_flag = param['70'] vertex_path = [] for i in xrange(param['90']): vertex={ '10': None, # X coordinat '20': None, # Y coordinat '42': 0.0 # Bulge } # 10 line1, line2 = self.read_record() vertex[line1] = convert(line1, line2, self.DWGCODEPAGE) # 20 line1, line2 = self.read_record() vertex[line1] = convert(line1, line2, self.DWGCODEPAGE) # 42 line1, line2 = self.read_record() if line1 == '42': vertex[line1] = convert(line1, line2, self.DWGCODEPAGE) else: self.push_record(line1, line2) vertex_path.append((vertex['10'], vertex['20'], vertex['42'])) self.load_seqend(vertex_path, path_flag) def load_polyline(self): param={ '70': 0, # bit codes for Polyline entity '40': 0.01, #XXX FIXMY } param.update(self.general_param) param = self.read_param(param) self.vertex_path = [] self.curstyle.line_width=param['40'] * 72 # XXX self.unit_to_pt self.curstyle.line_pattern = self.get_pattern(param['62']) # if Group 70 Flag bit value set 1 This is a closed Polyline self.path_flag = param['70'] def load_vertex(self): param={#'62': 7, # color #'6': 'CONTINUOUS', # style '10': None, # X coordinat '20': None, # Y coordinat '42': 0.0 # Bulge } param = self.read_param(param) self.vertex_path.append((param['10'], param['20'], param['42'])) def load_seqend(self, line = None, path_flag = None): if line is None: line = self.vertex_path if path_flag is None: path_flag = self.path_flag if path_flag > 1: print 'FIXMY. Curves and smooth surface type', path_flag close_path = path_flag & 1 == 1 path = CreatePath() if len(line): for i in line: x, y, bulge = i #print x, y, bulge path.AppendLine(self.trafo(x, y)) if close_path: if path.Node(0) != path.Node(-1): path.AppendLine(path.Node(0)) path.ClosePath() self.prop_stack.AddStyle(self.curstyle.Duplicate()) self.bezier(path,) def load_circle(self): param={ '10': None, # X coordinat center '20': None, # Y coordinat center #'30': None, # Z coordinat center '40': 0.0 # radius } param.update(self.general_param) param = self.read_param(param) x = param['10'] y = param['20'] r = param['40'] t = self.trafo(Trafo(r,0,0,r,x,y)) style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) apply(self.ellipse, t.coeff()) def load_arc(self): param={ '10': None, # X coordinat center '20': None, # Y coordinat center #'30': None, # Z coordinat center '40': 0.0, # radius '50': 0.0, # Start angle '51': 0.0 # End angle } param.update(self.general_param) param = self.read_param(param) cx = param['10'] cy = param['20'] rx = ry = param['40'] start_angle = param['50'] * degrees end_angle = param['51'] * degrees trafo = self.trafo(Trafo(rx, 0, 0, ry, cx, cy)) rx, w1, w2, ry, cx, cy = trafo.coeff() style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) apply(self.ellipse, (rx, w1, w2, ry, cx, cy, start_angle, end_angle, ArcArc)) def load_ellips(self): param={ '10': 0.0, # X coordinat center '20': 0.0, # Y coordinat center #'30': 0.0, # Z coordinat center '11': 0.0, # Endpoint of major axis, relative to the center '21': 0.0, #'31': 0.0, '40': 0.0, # Ratio of minor axis to major axis '41': 0.0, # Start parameter (this value is 0.0 for a full ellipse) '42': 0.0, # End parameter (this value is 2pi for a full ellipse) } param.update(self.general_param) param = self.read_param(param) cx = param['10'] cy = param['20'] rx = sqrt(param['21']**2 + param['11']**2) ry = rx * param['40'] start_angle = param['41'] end_angle = param['42'] angle=atan2(param['21'], param['11']) center = self.trafo(cx, cy) radius = self.trafo.DTransform(rx, ry) trafo = Trafo(radius.x, 0, 0, radius.y) trafo = Rotation(angle)(trafo) trafo = Translation(center)(trafo) rx, w1, w2, ry, cx, cy = trafo.coeff() style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) apply(self.ellipse, (rx, w1, w2, ry, cx, cy, start_angle, end_angle, ArcArc)) def load_point(self): param={ '10': None, # X coordinat center '20': None, # Y coordinat center #'30': None, # Z coordinat center } param.update(self.general_param) param = self.read_param(param) x = param['10'] y = param['20'] r = 0.3 t = self.trafo(Trafo(r,0,0,r,x,y)) style = self.curstyle.Duplicate() style.line_pattern = EmptyPattern style.fill_pattern = self.get_pattern(param['62']) self.prop_stack.AddStyle(style.Duplicate()) apply(self.ellipse, t.coeff()) def load_solid(self): param={ '10': None, '20': None, #'30': None, '11': None, '21': None, #'31': None, '12': None, '22': None, #'32': None, '13': None, '23': None, #'33': None, } param.update(self.general_param) param = self.read_param(param) style = self.curstyle.Duplicate() style.line_pattern = EmptyPattern style.fill_pattern = self.get_pattern(param['62']) self.path = CreatePath() self.path.AppendLine(self.trafo(param['10'], param['20'])) self.path.AppendLine(self.trafo(param['11'], param['21'])) self.path.AppendLine(self.trafo(param['12'], param['22'])) self.path.AppendLine(self.trafo(param['13'], param['23'])) self.path.ClosePath() self.prop_stack.AddStyle(style.Duplicate()) self.bezier(self.path,) def load_insert(self): param={ '2': None, # Block name '10': 0.0, # X coordinat '20': 0.0, # Y coordinat #'30': 0.0, # Z coordinat '41': 1.0, # X scale factor '42': 1.0, # Y scale factor #'43': 1.0, # Z scale factor '50': 0.0, # Rotation angle '66': 0, # Attributes-follow flag } param = self.read_param(param) block_name = self.default_block = param['2'] if block_name: self.stack += ['POP_TRAFO', '0'] + self.block_dict[block_name]['data'] self.push_trafo() x = param['10'] y = param['20'] block_x = self.block_dict[block_name]['10'] block_y = self.block_dict[block_name]['20'] scale_x = param['41'] * self.trafo.m11 scale_y = param['42'] * self.trafo.m22 angle = param['50'] * degrees translate = self.trafo(x, y) trafo = Trafo(1, 0, 0, 1, -block_x, -block_y) trafo = Scale(scale_x,scale_y)(trafo) trafo = Rotation(angle)(trafo) trafo = Translation(translate)(trafo) self.trafo = trafo if param['66'] != 0: line1, line2 = self.read_record() while line1 or line2: if line1 == '0' and line2 == 'SEQEND': break else: if line1 == '0': self.run(line2) line1, line2 = self.read_record() def load_text(self): param={ '10': 0.0, '20': 0.0, '40': None, # Text height '1': '', # Default value '50': 0, # Text rotation '41': 1, # Relative X scale factor—width # '8': self.default_layer, # Layer name '7': self.default_style, # Style name '72': 0, #Horizontal text justification type } param.update(self.general_param) param = self.read_param(param) x = param['10'] y = param['20'] scale_x = param['41'] scale_y = 1 angle = param['50'] * pi / 180 font_size = param['40'] * self.trafo.m11 halign = [ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT, \ ALIGN_LEFT, ALIGN_LEFT, ALIGN_LEFT][param['72']] text = unicode_decoder(param['1'], self.DWGCODEPAGE) #style = self.style_dict[param['7']] # print style style_text = self.curstyle.Duplicate() style_text.line_pattern = EmptyPattern style_text.fill_pattern = self.get_pattern(param['62']) style_name = upper(param['7']) style = self.style_dict[style_name] font_name = style['1000'] if font_name == 'Arial': # XXX font_name = 'ArialMT' style_text.font = GetFont(font_name) # print style_text.font style_text.font_size = font_size trafo_text = Translation(self.trafo(x, y))(Rotation(angle))(Scale(scale_x, scale_y)) self.prop_stack.AddStyle(style_text.Duplicate()) self.simple_text(strip(text), trafo_text, halign = halign) def load_3dface(self): param={ '10': None, '20': None, #'30': None, '11': None, '21': None, #'31': None, '12': None, '22': None, #'32': None, '13': None, '23': None, #'33': None, '70': 0, # Invisible edge flags } param.update(self.general_param) param = self.read_param(param) self.path = CreatePath() if param['70'] != 0: print 'FIXMY. 3dface Invisible edge flags', param['70'] self.path.AppendLine(self.trafo(param['10'], param['20'])) self.path.AppendLine(self.trafo(param['11'], param['21'])) self.path.AppendLine(self.trafo(param['12'], param['22'])) self.path.AppendLine(self.trafo(param['13'], param['23'])) self.path.ClosePath() style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) self.bezier(self.path,) def load_spline(self): param={ '70': 0, # Spline flag '71': 0, # Degree of the spline curve '72': 0, # Number of knots '73': 0, # Number of control points '74': 0, # Number of fit points '40': [], # Knot value '10': [], # Control points X '20': [], # Control points Y #'30': [], # Control points Z } param.update(self.general_param) param = self.read_param(param) closed = param['70'] & 1 path = CreatePath() f13 = 1.0 / 3.0 f23 = 2.0 / 3.0 curve = path.AppendBezier straight = path.AppendLine pts = map(lambda x, y: self.trafo(x, y), param['10'],param['20']) print 'SPLINE', param['70'], len(pts) #for i in range(0, len(pts)-1): #self.ellipse(.2, 0, 0, .2, pts[i][0],pts[i][1]) if param['70'] <= 1: straight(pts[0]) for i in range(1, len(pts) / 4): node = pts[i * 4] c1 = pts[i * 4 - 3] c2 = pts[i * 4 - 2] print c1, c2, node curve(c1, c2, node) #straight(node) if closed: curve(pts[-3], pts[-2], pts[0]) else: curve(pts[-4], pts[-4], pts[-1]) if param['70'] & 4 == 4: last = pts[0] cur = pts[1] start = node = (last + cur) / 2 if closed: straight(node) else: straight(last) straight(node) last = cur for cur in pts[2:]: c1 = f13 * node + f23 * last node = (last + cur) / 2 c2 = f13 * node + f23 * last curve(c1, c2, node) last = cur if closed: curve(f13 * node + f23 * last, f13 * start + f23 * last, start) else: straight(last) if param['70'] & 8 == 8: node = pts[0] c1 = pts[1] c2 = pts[2] # first node straight(node) if len(pts) > 4: c2 = (pts[2] + pts[1]) / 2 c3 = pts[3] * f13 + pts[2] * f23 node = (c3 + c2) / 2 curve(c1, c2, node) c1 = c3 for i in range(3, len(pts) - 3): c2 = pts[i - 1] * f13 + pts[i] * f23 c3 = pts[i] * f23 + pts[i + 1] * f13 node = (c3 + c2) / 2 curve(c1, c2, node) c1 = c3 c2 = pts[-4] * f13 + pts[-3] * f23 c3 = (pts[-3] + pts[-2]) / 2 node = (c3 + c2) / 2 curve(c1, c2, node) c1 = c3 # last node curve(c1, pts[-2], pts[-1]) style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) self.bezier(path,) def load_bypass(self): pass ########################################################################### def get_compiled(self): funclist={} for char, name in self.functions.items(): method = getattr(self, name) argc = method.im_func.func_code.co_argcount - 1 funclist[char] = (method, argc) return funclist def push_record(self, line1, line2): # save data in stack self.stack.append(line2) self.stack.append(line1) def read_record(self): # if the stack is empty read two lines from a file if self.stack: line1 = self.stack.pop() line2 = self.stack.pop() else: line1 = self.file.readline().strip() line2 = self.file.readline().strip() return line1, line2 def read_param(self, param, stop=None): # read data and fill in the dictionary if stop is None: stop = [0, 9] line1, line2 = self.read_record() while line1 or line2: if int(line1) in stop: self.push_record(line1, line2) return param else: if line1 in param: value = convert(line1, line2, self.DWGCODEPAGE) if type(param[line1]) == list: param[line1].append(value) else: param[line1] = value line1,line2 = self.read_record() return False def find_record(self, code1, code2): # read data until to not overlap line1 == code1 and line2 == code2 # return True # else return False line1, line2 = self.read_record() while line1 or line2: if line1 == code1 and line2 == code2: return True line1, line2 = self.read_record() return False def load_section(self): return_code = False file = self.file parsed = self.parsed parsed_interval = self.parsed_interval line1, line2 = self.read_record() while line1 or line2: interval_count = file.tell() / parsed_interval if interval_count > parsed: parsed += 10 # 10% progress app.updateInfo(inf2 = '%u' % parsed + _('% of file is parsed...'), inf3 = parsed) if line1 == '0' and line2 == 'ENDSEC': return_code = True break elif line1 == '0': self.run(line2) line1, line2 = self.read_record() self.parsed = parsed return return_code def load_sections(self): return_code = False param={ '2': '', # name section } param = self.read_param(param) name=param['2'] print '**',name if name == 'HEADER': return_code, header_dict = self.load_HEADER() self.process_header(header_dict) elif name == 'CLASSES': return_code = self.find_record('0','ENDSEC') elif name == 'OBJECTS': return_code = self.find_record('0','ENDSEC') elif name == 'THUMBNAILIMAGE': return_code = self.find_record('0','ENDSEC') else: return_code = self.load_section() return return_code def interpret(self): file = self.file if type(file) == StringType: file = open(file, 'r') file.seek(0) readline = file.readline fileinfo = os.stat(self.filename) totalsize = fileinfo[6] self.parsed = 0 self.parsed_interval = totalsize / 99 + 1 line1, line2 = self.read_record() while line1 or line2: if line1 == '0': if line2 == 'EOF': break elif not self.load_sections(): warn_tb(INTERNAL, _('DXFLoader: error. Non find end of sections')) line1, line2 = self.read_record() def run(self,keyword, *args): if keyword is None: return return_code = False unknown_operator = (None, None) funclist = self.funclist if keyword is not None: method, argc = funclist.get(keyword, unknown_operator) if method is not None: try: ##print '******', keyword if len(args): i = 0 while i<len(args): return_code = apply(method, args[i:argc+i]) i+=argc else: return_code = method() except: warn_tb(INTERNAL, 'DXFLoader: error') else: self.add_message(_('Not interpreted %s') % keyword) return return_code def Load(self): import time start_time = time.clock() #print ' ************ "DXF_objects" **************' self.funclist = self.get_compiled() self.document() self.layer(name = _("DXF_objects")) self.interpret() self.end_all() for style in self.dynamic_style_dict.values(): self.object.load_AddStyle(style) self.object.load_Completed() print 'times',time.clock() - start_time return self.object
class XFigLoader(SimplifiedLoader): format_name = format_name functions = [('define_color', 0), ('read_ellipse', 1), ('read_polyline', 2), ('read_spline', 3), ('read_text', 4), ('read_arc', 5), ('begin_compound', 6), ('end_compound', -6)] def __init__(self, file, filename, match): SimplifiedLoader.__init__(self, file, filename, match) self.layout = None self.format_version = atof(match.group('version')) self.trafo = Trafo(1.0, 0.0, 0.0, -1.0, 0.0, 800) self.colors = std_colors + [StandardColors.black] * 512 self.depths = {} # map object ids to depth self.guess_cont() def readline(self): line = SimplifiedLoader.readline(self) while line[:1] == '#': line = SimplifiedLoader.readline(self) return line def get_compiled(self): funclist = {} for name, rx in self.functions: funclist[rx] = getattr(self, name) return funclist def set_depth(self, depth): self.depths[id(self.object)] = -depth def define_color(self, line): idx, color = split(line, None, 1) self.colors[atoi(idx)] = XRGBColor(color) def get_pattern(self, color, style = None): if style == -1: return EmptyPattern rgb = self.colors[color] if style is not None: if color in (BLACK, DEFAULT_COLOR): if style > 0 and style <= 20: rgb = Blend(self.colors[WHITE], rgb, (20 - style) / 20.0) elif style == 0: rgb = self.colors[WHITE] else: if style >= 0 and style < 20: rgb = Blend(self.colors[BLACK], rgb, (20 - style) / 20.0) elif style > 20 and style <= 40: rgb = Blend(self.colors[WHITE], rgb, (style - 20) / 20.0) return SolidPattern(rgb) def line(self, color, width, join, cap, style = 0, style_val = 0): if width: val = style_val / width width = width * 72.0/80.0 pattern = self.get_pattern(color) dashes = () if style == 1: # dashed dashes = (val, val) elif style == 2: # dotted dashes = (1 / width, val) elif style == 3: # dash-dot dashes = (val, 0.5 * val, 1 / width, 0.5 * val) elif style == 4: # dash-dot-dot dashes = (val, 0.45 * val, 1 / width, 0.333 * val, 1 / width, 0.45 * val) elif style == 5: # dash-dot-dot-dot dashes = (val, 0.4 * val, 1 / width, 0.333 * val, 1 / width, 0.333 * val, 1 / width, 0.4 * val) try: self.set_properties(line_pattern = pattern, line_width = width, line_join = xfig_join[join], line_cap = xfig_cap[cap], line_dashes = dashes) except: raise SketchLoadError("can't assign line style: %s:%s" % sys.exc_info()[:2]) else: self.empty_line() def fill(self, color, style): pattern = self.get_pattern(color, style) try: self.set_properties(fill_pattern = pattern) except: raise SketchLoadError("can't assign fill style: %s:%s" % sys.exc_info()[:2]) def font(self, font, size, flags): if flags & 4: # A PostScript font name = psfonts[font] else: # A TeX font. map to psfont name = texfonts[font] self.add_message(_("PostScript font `%(ps)s' substituted for " "TeX-font `%(tex)s'") % {'ps':name, 'tex':tex_font_names[font]}) self.set_properties(font = GetFont(name), font_size = size) def read_tokens(self, num): # read NUM tokens from the input file. return an empty list if # eof met before num items are read readline = self.readline; tokenize = skread.tokenize_line tokens = [] while len(tokens) < num: line = readline() if not line: return [] tokens = tokens + tokenize(line) return tokens def read_arc(self, line): readline = self.readline; tokenize = skread.tokenize_line args = tokenize(line) if len(args) != 21: raise SketchLoadError('Invalid Arc specification') sub_type, line_style, thickness, pen_color, fill_color, depth, \ pen_style, area_fill, style, cap, direction, \ forward_arrow, backward_arrow, \ cx, cy, x1, y1, x2, y2, x3, y3 = args self.fill(fill_color, area_fill) self.line(pen_color, thickness, const.JoinMiter, cap, line_style, style) if forward_arrow: readline() # XXX: implement this if backward_arrow:readline() # XXX: implement this trafo = self.trafo center = trafo(cx, cy); start = trafo(x1, y1); end = trafo(x3, y3) radius = abs(start - center) start_angle = atan2(start.y - center.y, start.x - center.x) end_angle = atan2(end.y - center.y, end.x - center.x) if direction == 0: start_angle, end_angle = end_angle, start_angle if sub_type == 1: sub_type = const.ArcArc else: sub_type = const.ArcPieSlice self.ellipse(radius, 0, 0, radius, center.x, center.y, start_angle, end_angle, sub_type) self.set_depth(depth) def read_ellipse(self, line): readline = self.readline; tokenize = skread.tokenize_line args = tokenize(line) if len(args) != 19: raise SketchLoadError('Invalid Ellipse specification') sub_type, line_style, thickness, pen_color, fill_color, depth, \ pen_style, area_fill, style, direction, angle, \ cx, cy, rx, ry, sx, sy, ex, ey = args self.fill(fill_color, area_fill) self.line(pen_color, thickness, const.JoinMiter, const.CapButt, line_style, style) center = self.trafo(cx, cy); radius = self.trafo.DTransform(rx, ry) trafo = Trafo(radius.x, 0, 0, radius.y) trafo = Rotation(angle)(trafo) trafo = Translation(center)(trafo) apply(self.ellipse, trafo.coeff()) self.set_depth(depth) def read_polyline(self, line): readline = self.readline; tokenize = skread.tokenize_line args = tokenize(line) if len(args) != 15: raise SketchLoadError('Invalid PolyLine specification') sub_type, line_style, thickness, pen_color, fill_color, depth, \ pen_style, area_fill, style, join, cap, \ radius, forward_arrow, backward_arrow, npoints = args self.fill(fill_color, area_fill) self.line(pen_color, thickness, join, cap, line_style, style) if forward_arrow: readline() # XXX: implement this if backward_arrow:readline() # XXX: implement this if sub_type == 5: readline() # imported picture ncoords = npoints * 2 pts = self.read_tokens(ncoords) if not pts: raise SketchLoadError('Missing points for polyline') if len(pts) > ncoords: del pts[ncoords:] trafo = self.trafo if sub_type in (1, 3, 5): path = CreatePath() map(path.AppendLine, coords_to_points(pts, trafo)) if sub_type == 3: path.load_close(1) self.bezier(paths = path) self.set_depth(depth) elif sub_type in (2, 4): wx, wy = trafo(pts[2], pts[3]) - trafo(pts[0], pts[1]) hx, hy = trafo(pts[4], pts[5]) - trafo(pts[2], pts[3]) x, y = trafo(pts[0], pts[1]) if sub_type == 4 and radius > 0: radius1 = (radius * 72.0/80.0) / max(abs(wx),abs(wy)) radius2 = (radius * 72.0/80.0) / max(abs(hx),abs(hy)) else: radius1 = radius2 = 0 self.rectangle(wx, wy, hx, hy, x, y, radius1 = radius1, radius2 = radius2) self.set_depth(depth) def read_spline(self, line): readline = self.readline; tokenize = skread.tokenize_line args = tokenize(line) if len(args) != 13: raise SketchLoadError('Invalid Spline specification') sub_type, line_style, thickness, pen_color, fill_color, depth, \ pen_style, area_fill, style, cap, \ forward_arrow, backward_arrow, npoints = args closed = sub_type & 1 if forward_arrow: readline() if backward_arrow:readline() # in 3.2 all splines are stored as x-splines... if self.format_version == 3.2: if sub_type in (0, 2): sub_type = 4 else: sub_type = 5 self.fill(fill_color, area_fill) self.line(pen_color, thickness, 0, cap, line_style, style) ncoords = npoints * 2 pts = self.read_tokens(ncoords) if not pts: raise SketchLoadError('Missing points for spline') if len(pts) > ncoords: del pts[ncoords:] pts = coords_to_points(pts, self.trafo) path = CreatePath() if sub_type in (2, 3): # interpolated spline, read 2 control points for each node ncontrols = 4 * npoints controls = self.read_tokens(ncontrols) if not controls: raise SketchLoadError('Missing control points for spline') if len(controls) > ncontrols: del controls[ncontrols:] controls = coords_to_points(controls[2:-2], self.trafo) path.AppendLine(pts[0]) ncontrols = 2 * (npoints - 1) controls = [controls] * (npoints - 1) map(path.AppendBezier, map(getitem, controls, range(0, ncontrols, 2)), map(getitem, controls, range(1, ncontrols, 2)), pts[1:]) elif sub_type in (0, 1): # approximated spline f13 = 1.0 / 3.0; f23 = 2.0 / 3.0 curve = path.AppendBezier straight = path.AppendLine last = pts[0] cur = pts[1] start = node = (last + cur) / 2 if closed: straight(node) else: straight(last) straight(node) last = cur for cur in pts[2:]: c1 = f13 * node + f23 * last node = (last + cur) / 2 c2 = f13 * node + f23 * last curve(c1, c2, node) last = cur if closed: curve(f13 * node + f23 * last, f13 * start + f23 * last, start) else: straight(last) elif sub_type in (4, 5): # An X-spline. Treat it like a polyline for now. # read and discard the control info self.read_tokens(npoints) self.add_message(_("X-Spline treated as PolyLine")) map(path.AppendLine, pts) if closed: path.AppendLine(path.Node(0)) if closed: path.load_close(1) self.bezier(paths = path) self.set_depth(depth) def read_text(self, line): args = tokenize(line, 12) # don't tokenize the text itself if len(args) != 13: # including the unparsed rest of the line raise SketchLoadError('Invalid text specification') sub_type, color, depth, pen_style, font, size, angle, flags, \ height, length, x, y, rest = args self.fill(color, None) self.font(font, size * 0.9, flags) if len(rest) > 2: #at least a space and a newline # read the actual text. This implementation may fail in # certain cases! string = rest[1:] while string[-5:] != '\\001\n': line = self.readline() if not line: raise SketchLoadError('Premature end of string') string = string + line globals = {'__builtins__': {}} try: # using eval here might be a security hole! string = eval('"""' + string[:-5] + '"""', globals) except: string = eval("'''" + string[:-5] + "'''", globals) else: raise SketchLoadError('Invalid text string') trafo = Translation(self.trafo(x, y))(Rotation(angle)) self.simple_text(string, trafo = trafo, halign = align[sub_type]) self.set_depth(depth) def begin_compound(self, line): self.begin_group() def end_compound(self, line): try: self.end_group() except EmptyCompositeError: pass def end_composite(self): # sort composite_items by their depth items = self.composite_items depths = map(self.depths.get, map(id, items), [-10000]*len(items)) depths = map(None, depths, range(len(items)), items) depths.sort() self.composite_items = map(getitem, depths, [2] * len(items)) SimplifiedLoader.end_composite(self) def read_header(self): format = orientation = None if self.format_version >= 3.0: line = strip(self.readline()) if line: # portrait/landscape if lower(line) == 'landscape': orientation = pagelayout.Landscape else: orientation = pagelayout.Portrait else: raise SketchLoadError('No format specification') line = strip(self.readline()) if line: # centering line = lower(line) if line == 'center' or line == 'flush left': line = lower(strip(self.readline())) if not line: raise SketchLoadError( 'No Center/Flushleft or Units specification') if line == 'metric': # ignore for now pass if self.format_version >= 3.2: self.readline() # papersize self.readline() # magnification self.readline() # pages self.readline() # transparent color line = strip(self.readline()) if line: try: ppi, coord = map(atoi, split(line)) except: raise SketchLoadError('Invalid Resolution specification') self.trafo = self.trafo(Scale(72.0 / ppi)) def Load(self): file = self.file funclist = self.get_compiled() # binding frequently used functions to local variables speeds up # the process considerably... readline = file.readline; tokenize = skread.tokenize_line self.document() self.layer(_("Layer 1")) try: self.read_header() line = self.readline() while line: tokens = tokenize(line, 1) if len(tokens) > 1: function, rest = tokens else: function = tokens[0] rest = '' if type(function) == type(0): function = funclist.get(function) if function: function(rest) line = self.readline() except SketchLoadError, value: warn_tb(INTERNAL) raise SketchLoadError('%d:%s' % (self.lineno, str(value))), None,\ sys.exc_traceback except: