Example #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 WMFLoader(GenericLoader):

	def __init__(self, file, filename, match):
		GenericLoader.__init__(self, file, filename, match)
		self.file = file
		self.curstyle = Style()
		self.verbosity = 0
		self.gdiobjects = []
		self.dcstack = []
		self.curpoint = Point(0, 0)

	def _print(self, format, *args, **kw):
		if self.verbosity:
			try:
				if kw:
					text = format % kw
				elif args:
					text = format % args
				else:
					text = format
			except:
				text = string.join([format] + map(str, args))
			if text[-1] != '\n':
				text = text + '\n'
			sys.stdout.write(text)

	def get_struct(self, format):
		size = calcsize(format)
		return unpack(format, self.file.read(size))

	def get_int16(self):
		return self.get_struct('<h')[0]

	def get_int32(self):
		return self.get_struct('<i')[0]

	def read_headers(self):
		self.file.seek(0)
		placeable = self.file.read(calcsize(struct_placeable_header))
		key, handle, left, top, right, bottom, inch, reserved, checksum\
				= unpack(struct_placeable_header, placeable)
		if key != rx_magic:
			raise SketchLoadError(_("The file is not a placeable "
									"windows metafile"))
			self._print("The file is not a placeable windows metafile")
		sum = 0
		for word in unpack('<10h', placeable[:20]):
			sum = sum ^ word
		if sum != checksum:
			#raise SketchLoadError(_("The file has an incorrect checksum"))
			self._print("The file has an incorrect checksum")

		self.inch = inch
		self.bbox = (left, top, right, bottom)
		factor = 72.0 / self.inch
		self.wx = self.wy = 0
		self.wwidth = right - left
		self.wheight = bottom - top
		self.vx = self.vy = 0
		self.vwidth = self.wwidth
		self.vheight = self.wheight
		self.base_trafo = Trafo(factor, 0, 0, -factor,
								0, factor * self.vheight)
		self.update_trafo()

		header = self.file.read(calcsize(struct_wmf_header))
		filetype, headersize, version, filesize, numobj, maxrecord, numparams\
					= unpack(struct_wmf_header, header)

		self._print('\nHeader\n------\n')
		fmt = '% 10s: %s\n'
		self._print(fmt, 'inch', self.inch)
		self._print(fmt, 'bbox', self.bbox)
		self._print(fmt, 'headersize', headersize)
		self._print(fmt, 'version', version)
		self._print(fmt, 'numobj', numobj)
		self._print(fmt, 'numparams', numparams)
		self._print(fmt, 'maxrecord', maxrecord)
		self._print('\n')

	def update_trafo(self):
		wt = Translation(-self.wx, -self.wy)
		vt = Translation(self.vx, self.vy)
		scale = Scale(float(self.vwidth) / self.wwidth,
						float(self.vheight) / self.wheight)
		self.trafo = self.base_trafo(vt(scale(wt)))

	def add_gdiobject(self, object):
		try:
			idx = self.gdiobjects.index(None)
		except ValueError:
			self.gdiobjects.append(object)
		else:
			self.gdiobjects[idx] = object

	def delete_gdiobject(self, idx):
		self.gdiobjects[idx] = None

	def SelectObject(self):
		idx = self.get_int16()
		try:
			object = self.gdiobjects[idx]
		except IndexError:
			print 'Index Error:', idx, self.gdiobjects
			raise
		for property, value in object:
			setattr(self.curstyle, property, value)
		self._print('->', idx, object)

	def DeleteObject(self):
		idx = self.get_int16()
		self.delete_gdiobject(idx)
		self._print('->', idx)

	def get_dc(self):
		return self.curstyle.Duplicate(), self.trafo, self.curpoint

	def set_dc(self, dc):
		self.curstyle, self.trafo, self.curpoint = dc

	def SaveDC(self):
		self.dcstack.append(self.get_dc())

	def RestoreDC(self):
		self.set_dc(self.dcstack[-1])
		del self.dcstack[-1]

	def SetMapMode(self):
		mode = self.get_int16()
		self._print('->', mode)

	def SetWindowOrg(self):
		self.wy, self.wx = self.get_struct('<hh')
		self.update_trafo()
		self._print('->', self.wx, self.wy)

	def SetWindowExt(self):
		self.wheight, self.wwidth = self.get_struct('<hh')
		self.update_trafo()
		self._print('->', self.wwidth, self.wheight)

	def SetPolyFillMode(self):
		mode = self.get_int16()
		self._print('->', mode)

	SetBkMode = noop
	SetBkColor = noop
	SetROP2 = noop

	def CreateBrushIndirect(self):
		style, r, g, b, hatch = self.get_struct('<hBBBxh')
		if style == 1:
			pattern = EmptyPattern
		else:
			pattern = SolidPattern(CreateRGBColor(r/255.0, g/255.0, b/255.0))
		self.add_gdiobject((('fill_pattern', pattern),))

		self._print('->', style, r, g, b, hatch)

	def DibCreatePatternBrush(self):
		self.add_message(_("Bitmap brushes not yet implemented. Using black"))
		pattern = SolidPattern(StandardColors.black)
		self.add_gdiobject((('fill_pattern', pattern),))

	def CreatePenIndirect(self):
		style, widthx, widthy, r, g, b = self.get_struct('<hhhBBBx')
		cap = (style & 0x0F00) >> 8
		join = (style & 0x00F0) >> 4
		style = style & 0x000F
		if style == 5:
			pattern = EmptyPattern
		else:
			pattern = SolidPattern(CreateRGBColor(r/255.0, g/255.0, b/255.0))
		width = abs(widthx * self.trafo.m11)
		self.add_gdiobject((('line_pattern', pattern,),
							('line_width',  width)))
		self._print('->', style, widthx, widthy, r, g, b, cap, join)

	def CreatePalette(self):
		self.add_gdiobject((('ignore', None),))

	def CreateRegion(self):
		self.add_gdiobject((('ignore', None),))

	CreateFontIndirect = CreatePalette
	SelectPalette = noop
	RealizePalette = noop
	
	SetTextColor = noop
	SetTextAlign = noop
	SetTextJustification = noop

	SetStretchBltMode = noop
	
	def read_points(self, num):
		coords = self.get_struct('<' + num * 'hh')
		points = [];
		append = points.append
		trafo = self.trafo
		for i in range(0, 2 * num, 2):
			append(trafo(coords[i], coords[i + 1]))
		return points

	def Polyline(self):
		points = self.read_points(self.get_int16())
		if points:
			path = CreatePath()
			map(path.AppendLine, points)
			self.prop_stack.AddStyle(self.curstyle.Duplicate())
			self.prop_stack.SetProperty(fill_pattern = EmptyPattern)
			self.bezier((path,))

		#for i in range(len(points)):
		#    self._print('->', points[i])

	def Polygon(self):
		points = self.read_points(self.get_int16())
		if points:
			path = CreatePath()
			map(path.AppendLine, points)
			if path.Node(-1) != path.Node(0):
				#print 'correct polygon'
				path.AppendLine(path.Node(0))
			path.load_close()
			self.prop_stack.AddStyle(self.curstyle.Duplicate())
			self.bezier((path,))

		#for i in range(len(points)):
		#    self._print('->', points[i])

	def PolyPolygon(self):
		nr_of_polygons = self.get_int16()
		nr_of_points = []
		for i in range(nr_of_polygons):
			nr_of_points.append(self.get_int16())
		path = ()
		for i in nr_of_points:
			points = self.read_points(i)
			if points:
				subpath = CreatePath()
				map(subpath.AppendLine, points)
				if subpath.Node(-1) != subpath.Node(0):
					subpath.AppendLine(subpath.Node(0))
				subpath.load_close()
				path = path + (subpath,)
		if path:
			self.prop_stack.AddStyle(self.curstyle.Duplicate())
			self.bezier(path)

	def MoveTo(self):
		y, x = self.get_struct('<hh')
		self.curpoint = self.trafo(x, y)
		self._print('->', self.curpoint)
	
	def LineTo(self):
		y, x = self.get_struct('<hh')
		p = self.trafo(x, y)
		self.prop_stack.AddStyle(self.curstyle.Duplicate())
		self.prop_stack.SetProperty(fill_pattern = EmptyPattern)
		path = CreatePath()
		path.AppendLine(self.curpoint)
		path.AppendLine(p)
		self.bezier((path,))
		self.curpoint = p
		self._print('->', self.curpoint)

	def Ellipse(self):
		bottom, right, top, left = self.get_struct('<hhhh')
		left, top = self.trafo(left, top)
		right, bottom = self.trafo(right, bottom)
		self.prop_stack.AddStyle(self.curstyle.Duplicate())
		self.ellipse((right - left) / 2, 0, 0, (bottom - top) / 2,
						(right + left) / 2, (top + bottom) / 2)

	def Arc(self, arc_type = const.ArcArc):
		ye, xe, ys, xs, bottom, right, top, left = self.get_struct('<hhhhhhhh')
		left, top = self.trafo(left, top)
		right, bottom = self.trafo(right, bottom)
		xs, ys = self.trafo(xs, ys)
		xe, ye = self.trafo(xe, ye)
		self.prop_stack.AddStyle(self.curstyle.Duplicate())
		if arc_type == const.ArcArc:
			self.prop_stack.SetProperty(fill_pattern = EmptyPattern)
		if left != right and top != bottom:
			t = Trafo((right - left) / 2, 0, 0, (bottom - top) / 2,
						(right + left) / 2, (top + bottom) / 2).inverse()
			# swap start and end-angle
			end_angle = t(xs, ys).polar()[1]
			start_angle = t(xe, ye).polar()[1]
		else:
			start_angle = end_angle = 0.0
		self.ellipse((right - left) / 2, 0, 0, (bottom - top) / 2,
						(right + left) / 2, (top + bottom) / 2,
						start_angle = start_angle, end_angle = end_angle,
						arc_type = arc_type)
	def Pie(self):
		self.Arc(const.ArcPieSlice)

	def Rectangle(self):
		bottom, right, top, left = self.get_struct('<hhhh')
		left, top = self.trafo(left, top)
		right, bottom = self.trafo(right, bottom)
		self.prop_stack.AddStyle(self.curstyle.Duplicate())
		self.rectangle(right - left, 0, 0, bottom - top, left, top)

	def RoundRect(self):
		ellh, ellw, bottom, right, top, left = self.get_struct('<hhhhhh')
		left, top = self.trafo(left, top)
		right, bottom = self.trafo(right, bottom)
		ellw, ellh = self.trafo.DTransform(ellw, ellh)
		self._print('->', left, top, right, bottom, ellw, ellh)
		self.prop_stack.AddStyle(self.curstyle.Duplicate())
		self.rectangle(right - left, 0, 0, bottom - top, left, top,
						radius1 = abs(ellw / (right - left)),
						radius2 = abs(ellh / (bottom - top)))
		

	def Escape(self):
		pass

	def interpret(self):
		tell = self.file.tell
		function = -1
		while function:
			pos = tell()
			size, function = self.get_struct('<ih')
			self._print('%5d: %4x: %s' % (size, function,
											wmf_functions.get(function, '')))
			if hasattr(self, wmf_functions.get(function, '')):
				getattr(self, wmf_functions[function])()
			else:
				if function:
					self.file.read(2 * (size - 3))
					self._print('*** unimplemented:',
								wmf_functions.get(function, ''))
			pos = pos + 2 * size
			if tell() < pos:
				self.file.read(pos - tell())
			elif tell() > pos:
				self._print('read too many bytes')
				self.file.seek(pos - tell(), 1)

	def Load(self):
		self.document()
		self.layer(name = _("WMF objects"))
		self.read_headers()
		self.interpret()
		self.end_all()
		self.object.load_Completed()
		return self.object
Example #3
0
class DSTLoader(GenericLoader):
    def __init__(self, file, filename, match):
        GenericLoader.__init__(self, file, filename, match)
        self.file = file
        self.basename, self.ext = os.path.splitext(filename)

    def initialize(self):
        self.draw = 0
        self.scale = .283464566929
        self.cur_x = 0.0
        self.cur_y = 0.0
        self.palette = Palette(self.basename)
        self.path = CreatePath()
        self.cur_style = Style()
        self.cur_style.line_width = 0.6
        self.cur_style.line_join = const.JoinRound
        self.cur_style.line_cap = const.CapRound
        self.cur_style.line_pattern = self.palette.next_color(1)

    def readInt32(self, file):
        try:
            data = unpack('<I', file.read(4))[0]
        except:
            data = None
        return data

    def readInt8(self, file):
        try:
            data = int(unpack('B', file.read(1))[0])
        except:
            data = None
        return data

    def get_position(self, x=None, y=None):
        if x is None:
            x = self.cur_x
        else:
            x = float(x) * self.scale + self.cur_x
        if y is None:
            y = self.cur_y
        else:
            y = float(y) * self.scale + self.cur_y
        return x, y

    def bezier(self):
        if self.path.len > 1:
            self.prop_stack.AddStyle(self.cur_style.Duplicate())
            GenericLoader.bezier(self, paths=(self.path, ))
        self.path = CreatePath()

    def jump(self, x, y):
        x, y = self.get_position(x, y)
        self.cur_x = x
        self.cur_y = y

    def needle_move(self, x, y):
        if self.draw == 1:
            self.path.AppendLine(x, y)
        else:
            self.bezier()
            self.path.AppendLine(x, y)
        self.cur_x = x
        self.cur_y = y

    def needle_down(self, x=None, y=None):
        self.draw = 1
        x, y = self.get_position(x, y)
        self.needle_move(x, y)

    def needle_up(self, x=None, y=None):
        if self.draw == 1:
            self.bezier()
        self.draw = 0
        x, y = self.get_position(x, y)
        self.needle_move(x, y)

    def decode_x(self, d1, d2, d3):
        x = 1 * byte(d1, 7) - 1 * byte(d1, 6) + 9 * byte(d1, 5) - 9 * byte(
            d1, 4)
        x += 3 * byte(d2, 7) - 3 * byte(d2, 6) + 27 * byte(d2, 5) - 27 * byte(
            d2, 4)
        x += 81 * byte(d3, 5) - 81 * byte(d3, 4)
        return x

    def decode_y(self, d1, d2, d3):
        y = 1 * byte(d1, 0) - 1 * byte(d1, 1) + 9 * byte(d1, 2) - 9 * byte(
            d1, 3)
        y += 3 * byte(d2, 0) - 3 * byte(d2, 1) + 27 * byte(d2, 2) - 27 * byte(
            d2, 3)
        y += 81 * byte(d3, 2) - 81 * byte(d3, 3)
        return y

    def decode_flag(self, d3):
        if d3 == 243:
            return END
        if d3 & 195 == 3:
            return NORMAL
        elif d3 & 195 == 131:
            return JUMP
        elif d3 & 195 == 195:
            return CHANGECOLOR
        else:
            return UNKNOWN

    def readheader(self, file):
        file.seek(0)
        header = file.read(512).split('\r')
        dict = {}
        for i in header:
            if i[2] == ':':
                dict[i[0:2]] = i[3:].replace(' ', '')
        x = int(dict['-X'])
        y = int(dict['-Y'])
        self.jump(x, y)

    def Load(self):
        file = self.file
        fileinfo = os.stat(self.filename)
        totalsize = fileinfo[6]
        self.initialize()
        self.readheader(file)
        self.document()
        self.layer(name=_("DST_objects"))
        parsed = 0
        parsed_interval = totalsize / 99 + 1
        flag = UNKNOWN
        while 1:

            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)

            data = file.read(3)
            if len(data) < 3 or flag == 'END':
                self.needle_up()
                ## END INTERPRETATION
                app.updateInfo(inf2=_('Parsing is finished'), inf3=100)
                break

            d1, d2, d3 = unpack('BBB', data)
            x = self.decode_x(d1, d2, d3)
            y = self.decode_y(d1, d2, d3)
            #XXX swap coordinate
            x, y = y, x

            flag = self.decode_flag(d3)
            if flag == NORMAL:
                self.needle_down(x, y)
            elif flag == CHANGECOLOR:
                self.needle_up(x, y)
                self.cur_style.line_pattern = self.palette.next_color()
            elif flag == JUMP:
                #self.bezier() # cut the rope
                self.jump(x, y)

        self.end_all()
        self.object.load_Completed()
        return self.object