示例#1
0
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: