#!BPY

"""
Name: 'Autodesk DXF (.dxf)'
Blender: 244
Group: 'Import'
Tooltip: 'Import for DXF geometry data (Drawing eXchange Format).'
"""
__author__ = 'Kitsu(Ed Blake) & migius(Remigiusz Fiedler)'
__version__ = '1.0.beta10 - 2007.09.09 by migius'
__url__ = ["http://blenderartists.org/forum/showthread.php?t=84319",
	 "http://wiki.blender.org/index.php/Scripts/Manual/Import/DXF-3D"]
__email__ = ["Kitsune_e(at)yahoo.com", "migius(at)4d-vectors.de"]
__bpydoc__ = """\
This script imports DXF objects (2d/3d) into Blender.

This script imports 2d and 3d Geometery from DXFr12 format files.
This version is focused on import of 3d-objects.

Supported DXF Objects:
LINE
POINT
SOLID
TRACE
TEXT
INSERT (=block)
MINSERT (=array)
CIRCLE
ARC
3DFACE
2d-POLYLINE (=plane, incl. arc, variable-width, curve, spline)
3d-POLYLINE (=no-plane)
3d-POLYMESH
3d-POLYFACE
under construction, partly supported DXF>r12:
LWPOLYLINE (LightWeight), MLINE, MTEXT, ELLIPSE

Unsupported DXF Objects:
DXF r12: DIMENSION, XREF (External Reference)
DXF>r12: SPLINE, GROUP, RAY/XLINE, LEADER, 3DSOLID, BODY, REGION, dynamic BLOCK

Supported Properties:
Hierarchy: Entire DXF BLOCKs hierarchy is preserved after import into Blender
visibility, frozen
COLOR
LAYER
thickness
width
(todo: grouped, XDATA)
It is recommended to use DXF-object properties for coding Blender materials.

Notes:
- Recommend that you run 'RemoveDoubles' on each imported mesh after using this script
- Blocks are created on layer 19 then referenced at each insert point.
* Big DXF-files (over 1500 objects) decrease import performance. The problem is not the inefficiency of python-scripting but Blenders performance in creating new objects in his database - probably a database management problem.
* The Blender curves of imported ARCs and POLYLINE-arc-segments have light malformed ends.(to fix in beta10)
	
TODO:  
- the new style object visibility
- support for Spline-curves, Besier-curves
- support for real 3d-solids (ACIS)
- (to see more, search for "-todo-" in script)


History:
 v1.0 - 2007.09 by migius: "full 3d"-release
 planned tasks:
 -- filtering of unused/not-inserted BLOCKs
 -- human-formating of data in INI-File
 -- suport for MLine
 -- suport for Ellipse
 -- suport for Mtext
 -- blender_object.ID.properties[dxf_layer_name]
 -- Configuration files(.ini) should/can handle various material setups
 -- added f_layerFilter
 -- to-check: obj/mat/group/_mapping-idea from ideasman42:
 -- better support for long dxf-layer-names 
 -- support width_force for LINEs/ARCs/CIRCLEs/ELLIPSEs = "solidify"
 -- curves: added fill/non-fill option for closed curves: CIRCLEs,ELLIPSEs,POLYLINEs
 -- bug:? object = Object.Get(obname) -> = SCENE.getChildren(obname)
 -- command-line-mode/batch-mode
 -- fixed malformed endpoints of Blender curves of imported ARCs and POLYLINE-arc segments. 
 beta10: 2007.09.09 by migius
 a1 added "fill_on" option to draw top and bottom sides of CIRCLEs and ELLIPSEs
 a1 rewrite f_CIRCLE.Draw: from Mesh.Primitive to Mesh
 a1 bugfix "newScene"-mode: Cylinders/Arcs were drawn at <0,0,0>location
 beta09: 2007.09.02 by migius
 g5 redesign UI: grouping of buttons
 g3 update multi-import-mode: <*.*> button
 g- added multi-import-mode: (path/*) for importing many dxf-files at once
 g- added import into newScene
 g- redesign UI: user presets, into newScene-import  
 f- cleanup code
 f- bugfix: thickness for Bezier/Bsplines into Blender-curves
 f- BlenderWiki documentation, on-line Manual
 f- added import POLYLINE-Bsplines into Blender-NURBSCurves
 f- added import POLYLINE-arc-segments into Blender-BezierCurves
 f- added import POLYLINE-Bezier-curves into Blender-Curves
 d5 rewrite: Optimization Levels, added 'directDrawing'
 d4 added: f_set_thick(cntrolled by ini-parameters)
 d4 bugfix: face-normals in objects with minus thickness
 d4 added: placeholder'Empty'-size in f_Insert.draw
 d3 rewrite f_Text.Draw: added suport for all Text's parameters
 d2 redesign: progressbar 
 e- tuning by ideasman42: better use of the Py API.
 c- tuning by ideasman42
 b- rewrite f_Text.Draw rotation/transform
 b- bugfix: POLYLINE-segment-intersection more reliable now
 b- bugfix: circle:_thic, 'Empties':no material_assignement
 b- added material assignment (from layer and/or color)
 a- added empty, cylinder and UVsphere for POINTs
 a- added support for 2d-POLYLINE: splines, fitted curves, fitted surfaces
 a- redesign f_Drawer for block_definitions
 a- rewrite import into Blender-Curve-Object
 beta08: 2007.07.27 by migius
 l- bugfix: solid_vgroups, clean:scene.objects.new()
 l- redesign UI to standard Draw.Register+FileSelector, advanced_config_option
 k- bugfix UI:fileSelect() for MacOSX os.listdir()
 k- added reset/save/load for config-data
 k- redesign keywords/drawTypes/Draw.Create_Buttons
 j- new interface using UIBlock() with own FileSelector, cause Window.FileSelector() too buggy
 i- rewritten Class:Settings for better config-parameter management
 h- bugfix: face-normals in objects with minus thickness
 h- added Vertex-Groups in polylines and solids generated Meshes, for easier material assignment
 h- beautify code, whitespace->tabs
 h- added settings.thic_force switch for forcing thickness
 h- added one Object/Mesh for all simple-entities from the same Layer,
	sorted in Vertex-Groups(color_name)  (fewer objects = better import performance)
 g- rewrote: insert-point-handle-object is a small tetrahedron
 e- bugfix: closed-polymesh3d
 - rewrote: startUI, type_map.keys, f_drawer, for all class_f_draw(added "settings" as attribut)
 - added 2d/3d-support for Polyline_Width incl. angleintersection
 beta07: 2007.06.19 by migius
 - added 3d-support for LWPolylines
 - added 2d/3d-support for Points
 beta06: 2007.06.15 by migius
 - cleanup code
 - added 2d/3d-support for MINSERT=BlockArray in f_drawer, added f_rotXY_Vec
 beta05: 2007.06.14 by migius
 - added 2d/3d-support for 3d-PolyLine, PolyMesh and PolyFace
 - added Global-Scale for size control of imported scenes
 beta04: 2007.06.12 by migius
 - rewrote the f_drawBulge for correct import the arc-segments of Polylines
 beta03: 2007.06.10 by migius
 - rewrote interface
 beta02: 2007.06.09 by migius
 - added 3d-support for Arcs and Circles
 - added support for Object_Thickness(=height)
 beta01: 2007.06.08 by migius
 - added 3d-support for Blocks/Inserts within nested-structures
 - rewrote f_transform for correct 3d-location/3d-rotation
 - added 3d-support Lines, 3dFaces
 - added 2d+3d-support for Solids and Traces

 v0.9 - 2007.01 by kitsu: (for 2.43)
 -

 v0.8 - 2006.12 by kitsu:
 -

 v0.5b - 2006.10 by kitsu: (for 2.42a)
 -

"""

# --------------------------------------------------------------------------
# DXF Import v1.0 by Ed Blake (AKA kitsu) and Remigiusz Fiedler (AKA migius)
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------

import Blender
import bpy
from Blender import *
#from Blender.Mathutils import Vector, Matrix
#import BPyMessages


from dxfReader import readDXF	  # get_name, get_layer
from dxfReader import Object as dxfObject
from dxfColorMap import color_map
from math import *

try:
	import os
	if os.name:# != 'mac':
		import psyco
		psyco.log()
		psyco.full(memory=100)
		psyco.profile(0.05, memory=100)
		psyco.profile(0.2)
except ImportError:
	pass

print '\n\n\n\n'
print 'Import DXF to Blender *** START ***'   #---------------------

SCENE = None
WORLDX = Mathutils.Vector((1,0,0))
WORLDY = Mathutils.Vector((1,1,0))
WORLDZ = Mathutils.Vector((0,0,1))

G_SCALE = 1.0	   #(0.0001-1000) global scaling factor for all dxf data
MIN_DIST = 0.001	#cut-off value for sort out short-distance polyline-"duoble_vertex"
ARC_RESOLUTION = 64   #(4-500) arc/circle resolution - number of segments
ARC_RADIUS = 1.0   #(0.01-100) arc/circle radius for number of segments algorithm
THIN_RESOLUTION = 8   #(4-500) thin_cylinder arc_resolution - number of segments
MIN_THICK = MIN_DIST * 10.0  #minimal thickness by forced thickness
MIN_WIDTH = MIN_DIST * 10.0  #minimal width by forced width
ANGLECUT_LIMIT = 3.0	 #limit for anglecut of polylines-wide-segments (values:1.0 - 5.0)
TARGET_LAYER = 3	#target blender_layer
GROUP_BYLAYER = 0   #(0/1) all entities from same layer import into one blender-group

FILENAME_MAX = 180	#max length of path+file_name string  (FILE_MAXDIR + FILE_MAXFILE)
MAX_NAMELENGTH = 17   #max_effective_obnamelength in blender =21=17+(.001)
INIFILE_DEFAULT_NAME = 'importDXF'
INIFILE_EXTENSION = '.ini'
INIFILE_HEADER = 'ImportDXF.py ver.1.0 config data'

AUTO = BezTriple.HandleTypes.AUTO
FREE = BezTriple.HandleTypes.FREE
VECT = BezTriple.HandleTypes.VECT
ALIGN = BezTriple.HandleTypes.ALIGN
cur_COUNTER = 0  #counter for progress_bar


"""This module provides wrapper objects for dxf entities.

	The wrappers expect a "dxf object" as input.  The dxf object is
	an object with a type and a data attribute.  Type is a lowercase
	string matching the 0 code of a dxf entity.  Data is a list containing
	dxf objects or lists of [code, data] pairs.

	This module is not general, and is only for dxf import.
"""

# from Stani's dxf writer v1.1 (c)www.stani.be (GPL)
#---color values
BYBLOCK=0
BYLAYER=256

#---block-type flags (bit coded values, may be combined):
ANONYMOUS		   =1  # This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application
NON_CONSTANT_ATTRIBUTES =2  # This block has non-constant attribute definitions (this bit is not set if the block has any attribute definitions that are constant, or has no attribute definitions at all)
XREF					=4  # This block is an external reference (xref)
XREF_OVERLAY			=8  # This block is an xref overlay
EXTERNAL				=16 # This block is externally dependent
RESOLVED				=32 # This is a resolved external reference, or dependent of an external reference (ignored on input)
REFERENCED	  =64 # This definition is a referenced external reference (ignored on input)

#---polyline flags
CLOSED			  =1  # This is a closed polyline (or a polygon mesh closed in the M direction)
CURVE_FIT			   =2  # Curve-fit vertices have been added
SPLINE_FIT		  =4  # Spline-fit vertices have been added
POLYLINE_3D	 =8   # This is a 3D polyline
POLYGON_MESH				=16  # This is a 3D polygon mesh
CLOSED_N					=32  # The polygon mesh is closed in the N direction
POLYFACE_MESH		   =64   # The polyline is a polyface mesh
CONTINOUS_LINETYPE_PATTERN  =128	# The linetype pattern is generated continuously around the vertices of this polyline

#---text flags
#horizontal
LEFT		= 0
CENTER  = 1
RIGHT   = 2
ALIGNED  = 3 #if vertical alignment = 0
MIDDLE  = 4 #if vertical alignment = 0
FIT   = 5 #if vertical alignment = 0
#vertical
BASELINE	= 0
BOTTOM  = 1
MIDDLE  = 2
TOP   = 3

#---mtext flags
#attachment point
TOP_LEFT		= 1
TOP_CENTER  = 2
TOP_RIGHT   = 3
MIDDLE_LEFT  = 4
MIDDLE_CENTER   = 5
MIDDLE_RIGHT	= 6
BOTTOM_LEFT  = 7
BOTTOM_CENTER   = 8
BOTTOM_RIGHT	= 9
#drawing direction
LEFT_RIGHT  = 1
TOP_BOTTOM  = 3
BY_STYLE		= 5 #the flow direction is inherited from the associated text style
#line spacing style (optional):
AT_LEAST		= 1 #taller characters will override
EXACT	   = 2 #taller characters will not override



class Layer:  #-----------------------------------------------------------------
	"""Class for objects representing dxf layers.
	"""
	def __init__(self, obj, name=None, color=None, frozen=None):
		"""Expects an object of type layer as input.
		"""
		self.type = obj.type
		self.data = obj.data[:]

		if name:
			self.name = name
			#self.bfname = name  #remi--todo-----------
		else:
			self.name = obj.get_type(2)[0] #layer name of object

		if color:
			self.color = color
		else:
			self.color = obj.get_type(62)[0]  #color of object

		if frozen:
			self.frozen = frozen
		else:
			self.flags = obj.get_type(70)[0]
			self.frozen = self.flags&1


	def __repr__(self):
		return "%s: name - %s, color - %s" %(self.__class__.__name__, self.name, self.color)



def getit(obj, typ, default=None):  #------------------------------------------
	"""Universal procedure for geting data from list/objects.
	"""
	it = default
	if type(obj) == list:  #if obj is a list, then searching in a list
		for item in obj:
			#print 'deb:getit item, type(item)', item, type(item)
			try:
				if item[0] == typ:
					it = item[1]
					break  #as soon as the first found
			except:
				# TODO - I found one case where item was a text instance
				# that failed with no __getitem__
				pass
	else:	#else searching in Object with get_type-Methode
		item = obj.get_type(typ)
		if item:
			it = item[0]
	#print 'deb:getit:typ, it', typ, it #----------
	return it



def get_extrusion(data):	 #-------------------------------------------------
	"""Find the axis of extrusion.

	Used to get from object_data the objects Object Coordinate System (ocs).
	"""
	#print 'deb:get_extrusion: data: \n', data  #---------------
	vec = [0,0,1]
	vec[0] = getit(data, 210, 0) # 210 = x
	vec[1] = getit(data, 220, 0) # 220 = y
	vec[2] = getit(data, 230, 1) # 230 = z
	#print 'deb:get_extrusion: vec: ', vec  #---------------
	return vec





class Solid:  #-----------------------------------------------------------------
	"""Class for objects representing dxf solid or trace.
	"""
	def __init__(self, obj):
		"""Expects an entity object of type solid or trace as input.
		"""
		if obj.type == 'trace':
			obj.type = 'solid'
		if not obj.type == 'solid':
			raise TypeError, "Wrong type \'%s\' for solid/trace object!" %obj.type
		self.type = obj.type
		self.data = obj.data[:]

		self.space = getit(obj, 67, 0)
		self.thic =  getit(obj, 39, 0)
		self.color_index = getit(obj, 62, BYLAYER)

		self.layer = getit(obj.data, 8, None)
		self.extrusion = get_extrusion(obj.data)
		self.points = self.get_points(obj.data)



	def get_points(self, data):
		"""Gets start and end points for a solid type object.

		Solids have 3 or 4 points and fixed codes for each value.
		"""

		# start x, y, z and end x, y, z = 0
		a = [0, 0, 0]
		b = [0, 0, 0]
		c = [0, 0, 0]
		d = [0, 0, 0]
		a[0] = getit(data, 10, None) # 10 = x
		a[1] = getit(data, 20, None) # 20 = y
		a[2] = getit(data, 30,  0) # 30 = z
		b[0] = getit(data, 11, None)
		b[1] = getit(data, 21, None)
		b[2] = getit(data, 31,  0)
		c[0] = getit(data, 12, None)
		c[1] = getit(data, 22, None)
		c[2] = getit(data, 32,  0)
		out = [a,b,c]

		d[0] =  getit(data, 13, None)
		if d[0] != None:
			d[1] = getit(data, 23, None)
			d[2] = getit(data, 33,  0)
			out.append(d)
		#print 'deb:solid.vertices:---------\n', out  #-----------------------
		return out


	def __repr__(self):
		return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)


	def draw(self, settings):
		"""for SOLID: generate Blender_geometry.
		"""
		points = self.points
		if not points: return
		edges, faces = [], []
		l = len(self.points)

		obname = 'so_%s' %self.layer  # create object name from layer name
		obname = obname[:MAX_NAMELENGTH]

		vg_left, vg_right, vg_top, vg_bottom, vg_start, vg_end = [], [], [], [], [], []
		thic = set_thick(self.thic, settings)
		if thic != 0:
			thic_points = [[v[0], v[1], v[2] + thic] for v in points[:]]
			if thic < 0.0:
				thic_points.extend(points)
				points = thic_points
			else:
				points.extend(thic_points)

			if   l == 4:
				faces = [[0,1,3,2], [4,6,7,5], [0,4,5,1],
						 [1,5,7,3], [3,7,6,2], [2,6,4,0]]
				vg_left = [2,6,4,0]
				vg_right = [1,5,7,3]
				vg_top = [4,6,7,5]
				vg_bottom = [0,1,3,2]
				vg_start = [0,4,5,1]
				vg_end = [3,7,6,2]
			elif l == 3:
				faces = [[0,1,2], [3,5,4], [0,3,4,1], [1,4,5,2], [2,5,3,0]]
				vg_top = [3,4,5]
				vg_bottom = [0,1,2]
				vg_left = [2,5,3,0]
				vg_right = [1,4,5,2]
				vg_start = [0,3,4,1]
			elif l == 2: faces = [[0,1,3,2]]
		else:
			if   l == 4: faces = [[0,1,3,2]]
			elif l == 3: faces = [[0,1,2]]
			elif l == 2: edges = [[0,1]]



		me = Mesh.New(obname)		  # create a new mesh
		me.verts.extend(points)		# add vertices to mesh
		if faces: me.faces.extend(faces)		   # add faces to the mesh
		if edges: me.edges.extend(edges)		   # add faces to the mesh

		ob = SCENE.objects.new(me) # create a new mesh_object
		if settings.var['vGroup_on']:
			# each MeshSite becomes vertexGroup for easier material assignment ---------------------
			replace = Blender.Mesh.AssignModes.ADD  #or .AssignModes.ADD/REPLACE
			if vg_left: me.addVertGroup('side.left')  ; me.assignVertsToGroup('side.left',  vg_left, 1.0, replace)
			if vg_right:me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', vg_right, 1.0, replace)
			if vg_top:  me.addVertGroup('side.top')   ; me.assignVertsToGroup('side.top',   vg_top, 1.0, replace)
			if vg_bottom:me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',vg_bottom, 1.0, replace)
			if vg_start:me.addVertGroup('side.start') ; me.assignVertsToGroup('side.start', vg_start, 1.0, replace)
			if vg_end:  me.addVertGroup('side.end')   ; me.assignVertsToGroup('side.end',   vg_end,   1.0, replace)

		transform(self.extrusion, 0, ob)

		return ob




class Line:  #-----------------------------------------------------------------
	"""Class for objects representing dxf lines.
	"""
	def __init__(self, obj):
		"""Expects an entity object of type line as input.
		"""
		if not obj.type == 'line':
			raise TypeError, "Wrong type \'%s\' for line object!" %obj.type
		self.type = obj.type
		self.data = obj.data[:]

		self.space = getit(obj, 67, 0)
		self.thic =  getit(obj, 39, 0)
		#print 'deb:self.thic: ', self.thic #---------------------
		self.color_index = getit(obj, 62, BYLAYER)

		self.layer = getit(obj.data, 8, None)
		self.extrusion = get_extrusion(obj.data)
		self.points = self.get_points(obj.data)


	def get_points(self, data):
		"""Gets start and end points for a line type object.

		Lines have a fixed number of points (two) and fixed codes for each value.
		"""
		# start x,y,z and end x,y,z = 0
		a = [0, 0, 0]
		b = [0, 0, 0]
		a[0] = getit(data, 10, None) # 10 = x
		a[1] = getit(data, 20, None) # 20 = y
		a[2] = getit(data, 30,  0) # 30 = z
		b[0] = getit(data, 11, None)
		b[1] = getit(data, 21, None)
		b[2] = getit(data, 31,  0)
		out = [a,b]
		return out


	def __repr__(self):
		return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)


	def draw(self, settings):
		"""for LINE: generate Blender_geometry.
		"""
		# Generate the geometery
		#settings.var['curves_on']=False

		points = self.points

		global activObjectLayer
		global activObjectName
		#print 'deb:draw:line.ob IN activObjectName: ', activObjectName #---------------------

		if activObjectLayer == self.layer and settings.var['one_mesh_on']:
			obname = activObjectName
			#print 'deb:line.draw obname from activObjectName: ', obname #---------------------
			ob = Object.Get(obname)  # open an existing mesh_object
			#ob = SCENE.getChildren(obname)  # open an existing mesh_object
			me = Mesh.Get(ob.name)   # open objects mesh data
		else:
			obname = 'li_%s' %self.layer  # create object name from layer name
			obname = obname[:MAX_NAMELENGTH]
			me = Mesh.New(obname)		  # create a new mesh
			ob = SCENE.objects.new(me) # create a new mesh_object
			activObjectName = ob.name
			activObjectLayer = self.layer
			#print ('deb:line.draw new line.ob+mesh:"%s" created!' %ob.name) #---------------------

		#if settings.var['width_force']: # -todo-----------

		faces, edges = [], []
		n = len(me.verts)
		thic = set_thick(self.thic, settings)
		if thic != 0:
			t, e = thic, self.extrusion
			#print 'deb:thic, extr: ', t, e #---------------------
			points.extend([[v[0]+t*e[0], v[1]+t*e[1], v[2]+t*e[2]] for v in points[:]])
			faces = [[0+n, 1+n, 3+n, 2+n]]
		else:
			me.verts.extend(points) # add vertices to mesh
			edges = [[0+n, 1+n]]

		me.verts.extend(points) # add vertices to mesh
		if faces: me.faces.extend(faces)	   # add faces to the mesh
		if edges: me.edges.extend(edges)	   # add faces to the mesh

		if settings.var['vGroup_on']:
			# entities with the same color build one vertexGroup for easier material assignment ---------------------
			ob.link(me) # link mesh to that object
			vG_name = 'color_%s' %self.color_index
			if edges: faces = edges
			replace = Blender.Mesh.AssignModes.ADD  #or .AssignModes.REPLACE or ADD
			try:
				me.assignVertsToGroup(vG_name,  faces[0], 1.0, replace)
				#print 'deb: existed vGroup:', vG_name #---------------------
			except:
				me.addVertGroup(vG_name)
				me.assignVertsToGroup(vG_name,  faces[0], 1.0, replace)
				#print 'deb: create new vGroup:', vG_name #---------------------


		#print 'deb:draw:line.ob OUT activObjectName: ', activObjectName #---------------------
		return ob



class Point:  #-----------------------------------------------------------------
	"""Class for objects representing dxf points.
	"""
	def __init__(self, obj):
		"""Expects an entity object of type point as input.
		"""
		if not obj.type == 'point':
			raise TypeError, "Wrong type %s for point object!" %obj.type
		self.type = obj.type
		self.data = obj.data[:]

		self.space = getit(obj, 67, 0)
		self.thic =  getit(obj, 39, 0)
		#print 'deb:self.thic: ', self.thic #---------------------
		self.color_index = getit(obj, 62, BYLAYER)

		self.layer = getit(obj.data, 8, None)
		self.extrusion = get_extrusion(obj.data)
		self.points = self.get_points(obj.data)


	def get_points(self, data):
		"""Gets coordinates for a point type object.

		Points have fixed codes for each value.
		"""
		a = [0, 0, 0]
		a[0] = getit(data, 10, None) # 10 = x
		a[1] = getit(data, 20, None) # 20 = y
		a[2] = getit(data, 30,  0) # 30 = z
		out = [a]
		return out


	def __repr__(self):
		return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)


	def draw(self, settings):
		"""for POINT: generate Blender_geometry.
		"""
		points = self.points
		obname = 'po_%s' %self.layer  # create object name from layer name
		obname = obname[:MAX_NAMELENGTH]
		points_as = settings.var['points_as']
		thic = settings.var['thick_min']
		if thic < settings.var['dist_min']: thic = settings.var['dist_min']

		if points_as in [1,3,4]:
			if points_as == 1: # as 'empty'
				c = 'Empty'
			if points_as == 3: # as 'thin sphere'
				res = settings.var['thin_res']
				c = Mesh.Primitives.UVsphere(res,res,thic)
			if points_as == 4: # as 'thin box'
				c = Mesh.Primitives.Cube(thic)
			ob = SCENE.objects.new(c, obname) # create a new object
			transform(self.extrusion, 0, ob)
			ob.loc = tuple(points[0])

		elif points_as == 2: # as 'vertex'
			global activObjectLayer
			global activObjectName
			#print 'deb:draw:point.ob IN activObjectName: ', activObjectName #---------------------
			if activObjectLayer == self.layer and settings.var['one_mesh_on']:
				obname = activObjectName
				#print 'deb:draw:point.ob obname from activObjectName: ', obname #---------------------
				ob = Object.Get(obname)  # open an existing mesh_object
				#ob = SCENE.getChildren(obname)  # open an existing mesh_object
				me = Mesh.Get(ob.name)   # open objects mesh data
			else:
				me = Mesh.New(obname)		  # create a new mesh
				ob = SCENE.objects.new(me) # create a new mesh_object
				activObjectName = ob.name
				activObjectLayer = self.layer
				#print ('deb:draw:point new point.ob+mesh:"%s" created!' %ob.name) #---------------------
			me.verts.extend(points) # add vertices to mesh

		return ob




class LWpolyline:  #-----------------------------------------------------------------
	"""Class for objects representing dxf LWpolylines.
	"""
	def __init__(self, obj):
		"""Expects an entity object of type lwpolyline as input.
		"""
		#print 'deb:LWpolyline.START:----------------' #------------------------
		if not obj.type == 'lwpolyline':
			raise TypeError, "Wrong type %s for polyline object!" %obj.type
		self.type = obj.type
		self.data = obj.data[:]

		# required data
		self.num_points = obj.get_type(90)[0]

		# optional data (with defaults)
		self.space = getit(obj, 67, 0)

		self.color_index = getit(obj, 62, BYLAYER)

		self.elevation =  getit(obj, 30, 0)
		self.thic =  getit(obj, 39, 0)
		self.flags = getit(obj, 70, 0)

		self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen

		self.layer = getit(obj.data, 8, None)
		self.points = self.get_points(obj.data)
		self.extrusion = get_extrusion(obj.data)

		#print 'deb:LWpolyline.obj.data:\n', obj.data #------------------------
		#print 'deb:LWpolyline.ENDinit:----------------' #------------------------


	def get_points(self, data):
		"""Gets points for a polyline type object.

		LW-Polylines have no fixed number of verts, and
		each vert can have a number of properties.
		Verts should be coded as
		10:xvalue
		20:yvalue
		40:startwidth or 0
		41:endwidth or 0
		42:bulge or 0
		for each vert
		"""
		num = self.num_points
		point = None
		points = []
		for item in data:
			if item[0] == 10:   # 10 = x
				if point:
					points.append(point)
				point = Vertex()
				point.x = item[1]
			elif item[0] == 20: # 20 = y
				point.y = item[1]
			elif item[0] == 40: # 40 = start width
				point.swidth = item[1]
			elif item[0] == 41: # 41 = end width
				point.ewidth = item[1]
			elif item[0] == 42: # 42 = bulge
				point.bulge = item[1]
		points.append(point)
		return points



	def __repr__(self):
		return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)


	def draw(self, settings):
		"""for LWPOLYLINE: generate Blender_geometry.
		"""
		#print 'deb:LWpolyline.draw.START:----------------' #------------------------
		points = []
		obname = 'lw_%s' %self.layer  # create object name from layer name
		obname = obname[:MAX_NAMELENGTH]
		#settings.var['curves_on'] == True
		#print 'deb:index_len: ', len(self.points) #------------------
		for i, point in enumerate(self.points):
			#print 'deb:index: ', i #------------------
			if not point.bulge:
				points.append(point.loc)
			elif point.bulge and not self.closed and i == len(self.points)-1:
				points.append(point.loc)
			elif point.bulge:	 #
				if i == len(self.points)-1:
					point2 = self.points[0]
				else:
					point2 = self.points[i+1]
				arc_res = settings.var['arc_res']/sqrt(settings.var['arc_rad'])
				verts = drawBulge(point, point2, arc_res)
#			   if i == len(self.points)-1:
#				   if self.closed:
#					   verts.pop() #remove last(=first) vertex
#			   else:
#				   verts.pop() #remove last vertex, because this point will be writen as the next vertex
				points.extend(verts)

		thic = self.thic
		if settings.var['thick_force'] and thic == 0: thic = settings.var['thick_min']
		if settings.var['thick_on'] and thic != 0:
			len1 = len(points)
			points.extend([[point[0], point[1], point[2]+thic] for point in points])
			faces = []
			#print 'deb:len1:', len1  #-----------------------
			faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)]
			if self.closed:
				faces.append([len1-1, 0, len1, 2*len1-1])
			#print 'deb:faces_list:\n', faces  #-----------------------
			me = Mesh.New(obname)		  # create a new mesh
			ob = SCENE.objects.new(me) # create a new mesh_object
			me.verts.extend(points) # add vertices to mesh
			me.faces.extend(faces)   # add faces to the mesh
		else:
			edges = [[num, num+1] for num in xrange(len(points)-1)]
			if self.closed:
				edges.append([len(points)-1, 0])
			#print 'deb:edges_list:\n', edges  #-----------------------
			me = Mesh.New(obname)		  # create a new mesh
			ob = SCENE.objects.new(me) # create a new mesh_object
			me.verts.extend(points) # add vertices to mesh
			me.edges.extend(edges)   # add edges to the mesh

		ob.LocZ = self.elevation
		transform(self.extrusion, 0, ob)

		#print 'deb:LWpolyline.draw.END:----------------' #------------------------
		return ob



class Polyline:  #-----------------------------------------------------------------
	"""Class for objects representing dxf Polylines.
	"""
	def __init__(self, obj):
		"""Expects an entity object of type polyline as input.
		"""
		#print 'deb:polyline.init.START:----------------' #------------------------
		if not obj.type == 'polyline':
			raise TypeError, "Wrong type %s for polyline object!" %obj.type
		self.type = obj.type
		self.data = obj.data[:]
		#print 'deb:polyline.obj.data[:]:\n', obj.data[:] #------------------------
		self.points = []

		# optional data (with defaults)
		self.space = getit(obj, 67, 0)
		self.elevation =  getit(obj, 30, 0)
		#print 'deb:elevation: ', self.elevation #---------------
		self.thic =  getit(obj, 39, 0)
		self.color_index = getit(obj, 62, BYLAYER)

		self.flags = getit(obj, 70, 0)
		self.closed = self.flags & 1   # closed in the M direction
		self.curved = self.flags & 2   # Bezier-curve-fit vertices have been added
		self.spline = self.flags & 4   # Bspline-fit vertices have been added
		self.poly3d = self.flags & 8   # 3D-polyline
		self.plmesh = self.flags & 16  # 3D-polygon mesh
		self.closeN = self.flags & 32  # closed in the N direction
		self.plface = self.flags & 64  # 3D-polyface mesh
		self.contin = self.flags & 128 # the linetype pattern is generated continuously

		if self.poly3d or self.plface or self.plmesh:
			self.poly2d = False  # its not a 2D-polyline
		else:
			self.poly2d = True   # it is a 2D-polyline

		self.swidth =  getit(obj, 40, 0) # default start width
		self.ewidth =  getit(obj, 41, 0) # default end width
		#self.bulge  =  getit(obj, 42, None) # bulge of the segment
		self.vectorsM =  getit(obj, 71, None) # PolyMesh: expansion in M-direction / PolyFace: number of the vertices
		self.vectorsN =  getit(obj, 72, None) # PolyMesh: expansion in M-direction / PolyFace: number of faces
		#self.resolM =  getit(obj, 73, None) # resolution of surface in M direction
		#self.resolN =  getit(obj, 74, None) # resolution of surface in N direction
		self.curvetyp =  getit(obj, 75, 0) # type of curve/surface: 0=None/5=Quadric/6=Cubic/8=Bezier
		self.curvNormal = False
		self.curvQBspline = False
		self.curvCBspline = False
		self.curvBezier = False
		if   self.curvetyp == 0: self.curvNormal = True
		elif self.curvetyp == 5: self.curvQBspline = True
		elif self.curvetyp == 6: self.curvCBspline = True
		elif self.curvetyp == 8: self.curvBezier = True

		self.layer = getit(obj.data, 8, None)
		self.extrusion = get_extrusion(obj.data)

		self.points = []  #list with vertices coordinats
		self.faces  = []  #list with vertices assigment to faces
		#print 'deb:polyline.init.ENDinit:----------------' #------------



	def __repr__(self):
		return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)



	def draw(self, settings):   #-------------%%%% DRAW POLYLINE %%%---------------
		"""for POLYLINE: generate Blender_geometry.
		"""
		ob = []
		if self.plface:  #---- 3dPolyFace - mesh with free topology
			ob = self.drawPlFace(settings)
		elif self.plmesh:  #---- 3dPolyMesh - mesh with ortogonal topology
			ob = self.drawPlMesh(settings)
		#---- 2dPolyline - plane polyline with arc/wide/thic segments
		#---- 3dPolyline - noplane polyline (thin segments = without arc/wide/thic)
		elif  self.poly2d or self.poly3d:
			if settings.var['curves_on']: # and self.spline:
				ob = self.drawPolyCurve(settings)
			else:
				ob = self.drawPoly2d(settings)
		return ob



	def drawPlFace(self, settings):  #---- 3dPolyFace - mesh with free topology
		"""Generate the geometery of polyface.
		"""
		#print 'deb:polyface.draw.START:----------------' #------------------------
		points = []
		faces = []
		#print 'deb:len of pointsList ====== ', len(self.points) #------------------------
		for point in self.points:
			if point.face:
				faces.append(point.face)
			else:
				points.append(point.loc)


		#print 'deb:len of points_list:\n', len(points)  #-----------------------
		#print 'deb:points_list:\n', points  #-----------------------
		#print 'deb:faces_list:\n', faces  #-----------------------
		obname = 'pf_%s' %self.layer  # create object name from layer name
		obname = obname[:MAX_NAMELENGTH]
		me = Mesh.New(obname)		  # create a new mesh
		ob = SCENE.objects.new(me) # create a new mesh_object
		me.verts.extend(points) # add vertices to mesh
		me.faces.extend(faces)   # add faces to the mesh

		transform(self.extrusion, 0, ob)
		#print 'deb:polyface.draw.END:----------------' #------------------------

		return ob



	def drawPlMesh(self, settings):  #---- 3dPolyMesh - mesh with orthogonal topology
		"""Generate the geometery of polymesh.
		"""
		#print 'deb:polymesh.draw.START:----------------' #------------------------
		#points = []
		#print 'deb:len of pointsList ====== ', len(self.points) #------------------------
		faces = []
		m = self.vectorsM
		n = self.vectorsN
		for j in xrange(m - 1):
			for i in xrange(n - 1):
				nn = j * n
				faces.append([nn+i, nn+i+1, nn+n+i+1, nn+n+i])

		if self.closed:   #mesh closed in N-direction
			nn = (m-1)*n
			for i in xrange(n - 1):
				faces.append([nn+i, nn+i+1, i+1, i])

		if self.closeN:   #mesh closed in M-direction
			for j in xrange(m-1):
				nn = j * n
				faces.append([nn+n-1, nn, nn+n, nn+n-1+n])

		if self.closed and self.closeN:   #mesh closed in M/N-direction
				faces.append([ (n*m)-1, (m-1)*n, 0, n-1])

		#print 'deb:len of points_list:\n', len(points)  #-----------------------
		#print 'deb:faces_list:\n', faces  #-----------------------
		obname = 'pm_%s' %self.layer  # create object name from layer name
		obname = obname[:MAX_NAMELENGTH]
		me = Mesh.New(obname)		  # create a new mesh
		ob = SCENE.objects.new(me) # create a new mesh_object
		me.verts.extend([point.loc for point in self.points]) # add vertices to mesh
		me.faces.extend(faces)   # add faces to the mesh

		transform(self.extrusion, 0, ob)
		#print 'deb:polymesh.draw.END:----------------' #------------------------
		return ob


	def drawPolyCurve(self, settings):  #---- Polyline - draw as Blender-curve
		"""Generate the geometery of polyline as Blender-curve.
		"""
		#print 'deb:polyline2dCurve.draw.START:----------------' #---
		if len(self.points) < 2:
			#print 'deb:drawPoly2d exit, cause POLYLINE has less than 2 vertices' #---------
			return

		if self.spline: pline_typ = 'ps'	# Polyline-nurbSpline
		elif self.curved: pline_typ = 'pc'  # Polyline-bezierCurve
		else: pline_typ = 'pl'			  # Polyline
		obname = '%s_%s' %(pline_typ, self.layer)  # create object_name from layer name
		obname = obname[:MAX_NAMELENGTH]
		d_points = []
		#for DXFr10-format: update all points[].loc[2] == None -> 0.0 
		for point in self.points:
			if point.loc[2] == None:
				point.loc[2] = self.elevation
			d_points.append(point)

		thic = set_thick(self.thic, settings)

		if thic != 0.0:   #hack: Blender<2.45 curve-extrusion
			LocZ = d_points[0].loc[2]
			temp_points = []
			for point in d_points:
				point.loc[2] = 0.0
				temp_points.append(point)
			d_points = temp_points
		
		#print 'deb:polyline2dCurve.draw d_points=', d_points  #---------------
		pline = Curve.New(obname)   # create new curve data

		if False: #self.spline:  # NURBSplines-----FAKE(with Bezier)-----
			#print 'deb:polyline2dCurve.draw self.spline!' #---------------
			curve = pline.appendNurb(BezTriple.New(d_points[0]))
			for p in d_points[1:]:
				curve.append(BezTriple.New(p))
			for point in curve:
				point.handleTypes = [AUTO, AUTO]
			if self.closed:
				curve.flagU = 1 # Set curve cyclic=close
			else:
				curve.flagU = 0 # Set curve not cyclic=open
				curve[0].handleTypes = [FREE, ALIGN]   #remi--todo-----
				curve[-1].handleTypes = [ALIGN, FREE]   #remi--todo-----

		elif self.spline:  # NURBSplines-----TODO--:if curvQBspline: generate middlepoints---
			#print 'deb:polyline2dCurve.draw self.spline!' #---------------
			weight1 = 0.5
			weight2 = 1.0
			# generate middlepoints except start/end-segments ---
			if self.curvQBspline:
				temp_points = []
				point = d_points[0].loc
				point.append(weight1)
				temp_points.append(point)
				for i in xrange(1,len(d_points)-2):
					point1 = d_points[i].loc
					point2 = d_points[i+1].loc
					mpoint = list((Mathutils.Vector(point1) + Mathutils.Vector(point2)) * 0.5)
					mpoint.append(weight2)
					point1.append(weight1)
					temp_points.append(point1)
					temp_points.append(mpoint)
				point2.append(weight1)
				temp_points.append(point2)
				point = d_points[-1].loc
				point.append(weight1)
				temp_points.append(point)
				d_points = temp_points
			else:
				temp_points = []
				for d in d_points:
					d = d.loc
					d.append(weight1)
					temp_points.append(d)
				d_points = temp_points

			if not self.closed:
				# generate extended startpoint and endpoint------
				point1 = Mathutils.Vector(d_points[0][:3])
				point2 = Mathutils.Vector(d_points[1][:3])
				startpoint = list(point1 - point2 + point1)
				startpoint.append(weight1)
				point1 = Mathutils.Vector(d_points[-1][:3])
				point2 = Mathutils.Vector(d_points[-2][:3])
				endpoint = list(point1 - point2 + point1)
				endpoint.append(weight1)
				temp_points = []
				temp_points.append(startpoint)
				temp_points.extend(d_points)
				d_points = temp_points
				d_points.append(endpoint)

			point = d_points[0]
			curve = pline.appendNurb(point)
			curve.setType(4) #NURBS curve
			for point in d_points[1:]:
				curve.append(point)
			if self.closed:
				curve.flagU = 1 # Set curve cyclic=close
			else:
				curve.flagU = 0 # Set curve not cyclic=open

		elif  self.curved:  #--Bezier-curves---OK-------
			#print 'deb:polyline2dCurve.draw self.curved!' #---------------
			curve = pline.appendNurb(BezTriple.New(d_points[0]))
			for p in d_points[1:]:
				curve.append(BezTriple.New(p))
			for point in curve:
				point.handleTypes = [AUTO, AUTO]
			if self.closed:
				curve.flagU = 1 # Set curve cyclic=close
			else:
				curve.flagU = 0 # Set curve not cyclic=open
				curve[0].handleTypes = [FREE, ALIGN]   #remi--todo-----
				curve[-1].handleTypes = [ALIGN, FREE]   #remi--todo-----

		else:	#--straight line/arc-segments----OK------
			points = []
			d_points.append(d_points[0])  #------ first vertex added -------------
			#curve.setType(0) #polygon_type of Blender_curve
			for i in xrange(len(d_points)-1):
				point1 = d_points[i]
				point2 = d_points[i+1]
				if point1.bulge and (i < len(d_points)-2 or self.closed):
					verts = drawBulge(point1, point2, arc_res=8, curve_on=True) #calculate additional points for bulge
					if i == 0: curve = pline.appendNurb(BezTriple.New(verts[0]))
					else: curve.append(BezTriple.New(verts[0]))
					curve[-1].handleTypes = [VECT, VECT]  #--todo--calculate bezier-tangents
					for p in verts[1:]:
						curve.append(BezTriple.New(p))
						curve[-1].handleTypes = [AUTO, AUTO]  #--todo--calculate bezier-tangents
#				   curve[-1].handleTypes = [VECT, VECT]   #--todo--calculate bezier-tangents
				else:
					if i == 0: curve = pline.appendNurb(BezTriple.New(point1.loc))
					else: curve.append(BezTriple.New(point1.loc))
					curve[-1].handleTypes = [VECT, VECT]   #--todo--calculate bezier-tangents
			if self.closed:
				curve.flagU = 1 # Set curve cyclic=close
#			   curve[0].handleTypes = [VECT, VECT]   #--todo--calculate bezier-tangents
			else:
				curve.flagU = 0 # Set curve not cyclic=open
				curve[0].handleTypes = [FREE, VECT]   #--todo--calculate bezier-tangents
				curve[-1].handleTypes = [VECT, FREE]  #--todo--calculate bezier-tangents

		pline.update()
		ob = SCENE.objects.new(pline) # create a new curve_object

		if thic != 0.0: #hack: Blender<2.45 curve-extrusion
			thic = thic * 0.5
			pline.setExt1(1.0)  # curve-extrusion accepts only (0.0 - 2.0)
			ob.LocZ = thic + LocZ

		transform(self.extrusion, 0, ob)
		if thic != 0.0:
			ob.SizeZ *= abs(thic)

		#print 'deb:polyline2dCurve.draw.END:----------------' #-----
		return ob


	def drawPoly2d(self, settings):  #---- 2dPolyline - plane wide/thic lines
		"""Generate the geometery of regular polyline.
		"""
		#print 'deb:polyline2d.draw.START:----------------' #------------------------
		points = []
		d_points = []
		swidths = []
		ewidths = []
		swidth_default = self.swidth #default start width of POLYLINEs segments
		ewidth_default = self.ewidth #default end width of POLYLINEs segments
		thic = set_thick(self.thic, settings)
		if self.spline: pline_typ = 'ps'
		elif self.curved: pline_typ = 'pc'
		else: pline_typ = 'pl'
		obname = '%s_%s' %(pline_typ, self.layer)  # create object_name from layer name
#	   obname = 'pl_%s' %self.layer  # create object name from layer name
		obname = obname[:MAX_NAMELENGTH]

		if len(self.points) < 2:
			#print 'deb:drawPoly2d exit, cause POLYLINE has less than 2 vertices' #---------
			return
		#d_points = self.points[:]
		#for DXFr10-format: update all points[].loc[2] == None -> 0.0 
		for point in self.points:
			if point.loc[2] == None:
				point.loc[2] = self.elevation
			d_points.append(point)
		#print 'deb:len of d_pointsList ====== ', len(d_points) #------------------------

		#add duplic of the first vertex at the end of pointslist
		d_points.append(d_points[0])

		#print 'deb:len of d_pointsList ====== ', len(d_points) #------------------------
		#print 'deb:d_pointsList ======:\n ', d_points #------------------------


		#routine to sort out of "double.vertices" --------
		minimal_dist =  settings.var['dist_min'] * 0.1
		temp_points = []
		for i in xrange(len(d_points)-1):
			point = d_points[i]
			point2 = d_points[i+1]
			#print 'deb:double.vertex p1,p2', point, point2 #------------------------
			delta = Mathutils.Vector(point2.loc) - Mathutils.Vector(point.loc)
			if delta.length > minimal_dist:
				 temp_points.append(point)
			#else: print 'deb:double.vertex sort out!' #------------------------
		temp_points.append(d_points[-1])  #------ last vertex added -------------
		d_points = temp_points   #-----vertex.list without "double.vertices"
		#print 'deb:d_pointsList =after DV-outsorting=====:\n ', d_points #------------------------

		#print 'deb:len of d_pointsList ====== ', len(d_points) #------------------------
		if len(d_points) < 2:
			#print 'deb:drawPoly2d corrupted Vertices' #---------
			return

		#analyse of straight- and bulge-segments (generation of additional points for bulge)
		exist_wide_segment = False
		for i in xrange(len(d_points)-1):
			point1 = d_points[i]
			point2 = d_points[i+1]
			#print 'deb:pline.tocalc.point1:', point1 #------------------------
			#print 'deb:pline.tocalc.point2:', point2 #------------------------

			swidth = point1.swidth
			ewidth = point1.ewidth
			if swidth == None: swidth = swidth_default
			if ewidth == None: ewidth = ewidth_default

			if swidth != 0.0 or ewidth != 0.0: exist_wide_segment = True

			if settings.var['width_force']:  # force minimal width for thin segments
				if swidth < settings.var['width_min']: swidth = settings.var['width_min']
				if ewidth < settings.var['width_min']: ewidth = settings.var['width_min']
				if not settings.var['width_on']:  # then force minimal width for all segments
					swidth = settings.var['width_min']
					ewidth = settings.var['width_min']

			if point1.bulge and (i < (len(d_points)-2) or self.closed):
				arc_res = settings.var['arc_res']/sqrt(settings.var['arc_rad'])
				verts = drawBulge(point1, point2, arc_res) #calculate additional points for bulge
				points.extend(verts)
				delta_width = (ewidth - swidth) / len(verts)
				width_list = [swidth + (delta_width * ii) for ii in xrange(len(verts)+1)]
				swidths.extend(width_list[0:-1])
				ewidths.extend(width_list[1:])
			else:
				points.append(point1.loc)
				swidths.append(swidth)
				ewidths.append(ewidth)


		#--calculate width_vectors: left-side- and right-side-points ----------------
		# 1.level:IF width  ---------------------------------------
		if (settings.var['width_on'] and exist_wide_segment) or settings.var['width_force']:
			points.append(d_points[0].loc)  #temporarly add first vertex at the end (for better loop)

			pointsLs = []   # list of left-start-points
			pointsLe = []   # list of left-end-points
			pointsRs = []   # list of right-start-points
			pointsRe = []   # list of right-end-points
			pointsW  = []   # list of entire-border-points
			#rotMatr90 = Mathutils.Matrix(rotate 90 degree around Z-axis) = normalvectorXY
			rotMatr90 = Mathutils.Matrix([0, -1, 0], [1, 0, 0], [0, 0, 1])
			for i in xrange(len(points)-1):
				point1 = points[i]
				point2 = points[i+1]
				point1vec = Mathutils.Vector(point1)
				point2vec = Mathutils.Vector(point2)
				swidth05 = swidths[i] * 0.5
				ewidth05 = ewidths[i] * 0.5
				if swidth05 == 0: swidth05 = 0.5 * settings.var['dist_min'] #minimal width
				if ewidth05 == 0: ewidth05 = 0.5 * settings.var['dist_min'] #minimal width

				normal_vector = rotMatr90 * (point2vec-point1vec).normalize()
				swidth05vec = swidth05 * normal_vector
				ewidth05vec = ewidth05 * normal_vector
				pointsLs.append(point1vec + swidth05vec) #vertex left start
				pointsRs.append(point1vec - swidth05vec) #vertex right start
				pointsLe.append(point2vec + ewidth05vec) #vertex left end
				pointsRe.append(point2vec - ewidth05vec) #vertex right end

			pointsLc, pointsRc = [], []

			# 2.level:IF width and corner-intersection activated
			if settings.var['pl_section_on']:  #optional clean corner-intersections
				if not self.closed:
					pointsLc.append(pointsLs[0])
					pointsRc.append(pointsRs[0])
					lenL = len(pointsLs)-2 #without the last point at the end of the list
				else:
					pointsLs.append(pointsLs[0])
					pointsRs.append(pointsRs[0])
					pointsLe.append(pointsLe[0])
					pointsRe.append(pointsRe[0])
					points.append(points[0])
					lenL = len(pointsLs)-1  #without the duplic of the first point at the end of the list
					#print 'deb:pointsLs():\n',  pointsLs  #----------------
					#print 'deb:lenL, len.pointsLs():', lenL,',', len(pointsLs)  #----------------
				for i in xrange(lenL):
					pointVec = Mathutils.Vector(points[i+1])
					#print 'deb:pointVec: ', pointVec  #-------------
					#compute left-corner-points
					vecL1 = pointsLs[i]
					vecL2 = pointsLe[i]
					vecL3 = pointsLs[i+1]
					vecL4 = pointsLe[i+1]
					#print 'deb:vectorsL:---------\n', vecL1,'\n',vecL2,'\n',vecL3,'\n',vecL4  #-------------
					#cornerpointL = Geometry.LineIntersect2D(vec1, vec2, vec3, vec4)
					cornerpointL = Mathutils.LineIntersect(vecL1, vecL2, vecL3, vecL4)
					#print 'deb:cornerpointL: ', cornerpointL  #-------------

					#compute right-corner-points
					vecR1 = pointsRs[i]
					vecR2 = pointsRe[i]
					vecR3 = pointsRs[i+1]
					vecR4 = pointsRe[i+1]
					#print 'deb:vectorsR:---------\n', vecR1,'\n',vecR2,'\n',vecR3,'\n',vecR4  #-------------
					#cornerpointR = Geometry.LineIntersect2D(vec1, vec2, vec3, vec4)
					cornerpointR = Mathutils.LineIntersect(vecR1, vecR2, vecR3, vecR4)
					#print 'deb:cornerpointR: ', cornerpointR  #-------------

					#if diststance(cornerL-center-cornerR) < limiter * (seg1_endWidth + seg2_startWidth)
					if cornerpointL != None and cornerpointR != None:
						cornerpointL = cornerpointL[0]
						cornerpointR = cornerpointR[0]
						max_cornerDist = (vecL2 - vecR2).length + (vecL3 - vecR3).length
						is_cornerDist = (cornerpointL - pointVec).length + (cornerpointR - pointVec).length
						# anglecut --------- limited by ANGLECUT_LIMIT (1.0 - 5.0)
						if is_cornerDist < max_cornerDist * settings.var['angle_cut']:
							pointsLc.append(cornerpointL)
							pointsRc.append(cornerpointR)
						else:
							pointsLc.extend((pointsLe[i],pointsLs[i+1]))
							pointsRc.extend((pointsRe[i],pointsRs[i+1]))
					else:
						pointsLc.extend((pointsLe[i],pointsLs[i+1]))
						pointsRc.extend((pointsRe[i],pointsRs[i+1]))
				if not self.closed:
					pointsLc.append(pointsLe[-2])
					pointsRc.append(pointsRe[-2])
				else:
					"""   """

			# 2.level:IF width but not corner-intersection activated
			else:
				# points_multiplexer of start-points and end-points
				lenL = len(pointsLs) - 1 #without the duplic of the first point at the end of list
				if self.closed: lenL += 1  #inclusive the duplic of the first point at the end of list
				for i in xrange(lenL):
					pointsLc.extend((pointsLs[i], pointsLe[i]))
					pointsRc.extend((pointsRs[i], pointsRe[i]))

			pointsW = pointsLc + pointsRc  # all_points_List = left_side + right_side
			#print 'deb:pointsW():\n',  pointsW  #----------------
			len1 = int(len(pointsW) * 0.5)
			#print 'deb:len1:', len1  #-----------------------

			# 2.level:IF width and thickness  ---------------------
			if thic != 0:
				thic_pointsW = []
				thic_pointsW.extend([[point[0], point[1], point[2]+thic] for point in pointsW])
				if thic < 0.0:
					thic_pointsW.extend(pointsW)
					pointsW = thic_pointsW
				else:
					pointsW.extend(thic_pointsW)
				faces = []
				f_start, f_end = [], []
				f_bottom = [[num, num+1, len1+num+1, len1+num] for num in xrange(len1-1)]
				f_top   = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1+len1, len1+len1+len1-1)]
				f_left   = [[num, len1+len1+num, len1+len1+num+1, num+1] for num in xrange(len1-1)]
				f_right  = [[num, num+1, len1+len1+num+1, len1+len1+num] for num in xrange(len1, len1+len1-1)]

				if self.closed:
					f_bottom.append([len1-1, 0, len1, len1+len1-1])  #bottom face
					f_top.append(   [len1+len1+len1-1, len1+len1+len1+len1-1, len1+len1+len1, len1+len1+0])  #top face
					f_left.append(  [0, len1-1, len1+len1+len1-1, len1+len1])  #left face
					f_right.append( [len1, len1+len1+len1, len1+len1+len1+len1-1, len1+len1-1])  #right face
				else:
					f_start = [[0, len1, len1+len1+len1, len1+len1]]
					f_end   = [[len1+len1-1, 0+len1-1, len1+len1+len1-1, len1+len1+len1+len1-1]]

				faces = f_bottom + f_top + f_left + f_right + f_start + f_end
				#faces = f_bottom + f_top
				#faces = f_left + f_right + f_start + f_end
				#print 'deb:faces_list:\n', faces  #-----------------------
				me = Mesh.New(obname)		  # create a new mesh
				ob = SCENE.objects.new(me) # create a new mesh_object
				me.verts.extend(pointsW)		# add vertices to mesh
				me.faces.extend(faces)  # add faces to the mesh

				# each MeshSite becomes vertexGroup for easier material assignment ---------------------
				# The mesh must first be linked to an object so the method knows which object to update.
				# This is because vertex groups in Blender are stored in the object -- not in the mesh,
				# which may be linked to more than one object.
				if settings.var['vGroup_on']:
					# each MeshSite becomes vertexGroup for easier material assignment ---------------------
					replace = Blender.Mesh.AssignModes.REPLACE  #or .AssignModes.ADD
					vg_left, vg_right, vg_top, vg_bottom = [], [], [], []
					for v in f_left: vg_left.extend(v)
					for v in f_right: vg_right.extend(v)
					for v in f_top: vg_top.extend(v)
					for v in f_bottom: vg_bottom.extend(v)
					me.addVertGroup('side.left')  ; me.assignVertsToGroup('side.left',  list(set(vg_left)), 1.0, replace)
					me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', list(set(vg_right)), 1.0, replace)
					me.addVertGroup('side.top')   ; me.assignVertsToGroup('side.top',   list(set(vg_top)), 1.0, replace)
					me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',list(set(vg_bottom)), 1.0, replace)
					if not self.closed:
						me.addVertGroup('side.start'); me.assignVertsToGroup('side.start', f_start[0], 1.0, replace)
						me.addVertGroup('side.end')  ; me.assignVertsToGroup('side.end',   f_end[0],   1.0, replace)


			# 2.level:IF width, but no-thickness  ---------------------
			else:
				faces = []
				faces = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1 - 1)]
				if self.closed:
					faces.append([len1, 0, len1-1, len1+len1-1])
				me = Mesh.New(obname)		  # create a new mesh
				ob = SCENE.objects.new(me) # create a new mesh_object
				me.verts.extend(pointsW)		# add vertices to mesh
				me.faces.extend(faces)  # add faces to the mesh


		# 1.level:IF no-width, but thickness ---------------------
		elif thic != 0:
			len1 = len(points)
			thic_points = []
			thic_points.extend([[point[0], point[1], point[2]+thic] for point in points])
			if thic < 0.0:
				thic_points.extend(points)
				points = thic_points
			else:
				points.extend(thic_points)
			faces = []
			faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)]
			if self.closed:
				faces.append([len1-1, 0, len1, 2*len1-1])
			me = Mesh.New(obname)		  # create a new mesh
			ob = SCENE.objects.new(me) # create a new mesh_object
			me.verts.extend(points)   # add vertices to mesh
			me.faces.extend(faces)  # add faces to the mesh

		# 1.level:IF no-width and no-thickness  ---------------------
		else:
			edges = [[num, num+1] for num in xrange(len(points)-1)]
			if self.closed:
				edges.append([len(points)-1, 0])
			me = Mesh.New(obname)		  # create a new mesh
			ob = SCENE.objects.new(me) # create a new mesh_object
			me.verts.extend(points)   # add vertices to mesh
			me.edges.extend(edges)  # add edges to the mesh

		transform(self.extrusion, 0, ob)
		#print 'deb:polyline.draw.END:----------------' #-----------------------
		return ob




class Vertex(object):  #-----------------------------------------------------------------
	"""Generic vertex object used by polylines (and maybe others).
	"""

	def __init__(self, obj=None):
		"""Initializes vertex data.

		The optional obj arg is an entity object of type vertex.
		"""
		#print 'deb:Vertex.init.START:----------------' #-----------------------
		self.loc = [0,0,0]
		self.face = []
		self.swidth = 0
		self.ewidth = 0
		self.bulge = 0
		if obj is not None:
			if not obj.type == 'vertex':
				raise TypeError, "Wrong type %s for vertex object!" %obj.type
			self.type = obj.type
			self.data = obj.data[:]
			self.get_props(obj.data)
		#print 'deb:Vertex.init.END:----------------' #------------------------


	def get_props(self, data):
		"""Gets coords for a VERTEX type object.

		Each vert can have a number of properties.
		Verts should be coded as
		10:xvalue
		20:yvalue
		40:startwidth or 0
		41:endwidth or 0
		42:bulge or 0
		"""
		self.x = getit(data, 10, None)
		self.y = getit(data, 20, None)
		self.z = getit(data, 30, None)

		self.flags  = getit(data, 70, 0) # flags
		self.curved = self.flags&1   # Bezier-curve-fit:additional-vertex
		self.curv_t = self.flags&2   # Bezier-curve-fit:tangent exists
		self.spline = self.flags&8   # Bspline-fit:additional-vertex
		self.splin2 = self.flags&16  # Bspline-fit:control-vertex
		self.poly3d = self.flags&32  # polyline3d:control-vertex
		self.plmesh = self.flags&64  # polymesh3d:control-vertex
		self.plface = self.flags&128 # polyface

		# if PolyFace.Vertex with Face_definition
		if self.curv_t:
			self.curv_tangent =  getit(data, 50, None) # curve_tangent

		if self.plface and not self.plmesh:
				v1 = getit(data, 71, 0) # polyface:Face.vertex 1.
				v2 = getit(data, 72, 0) # polyface:Face.vertex 2.
				v3 = getit(data, 73, 0) # polyface:Face.vertex 3.
				v4 = getit(data, 74, None) # polyface:Face.vertex 4.
				self.face = [abs(v1)-1,abs(v2)-1,abs(v3)-1]
				if v4 != None:
					self.face.append(abs(v4)-1)
		else:   #--parameter for polyline2d
			self.swidth = getit(data, 40, None) # start width
			self.ewidth = getit(data, 41, None) # end width
			self.bulge  = getit(data, 42, 0) # bulge of segment


	def __len__(self):
		return 3


	def __getitem__(self, key):
		return self.loc[key]


	def __setitem__(self, key, value):
		if key in [0,1,2]:
			self.loc[key]


	def __iter__(self):
		return self.loc.__iter__()


	def __str__(self):
		return str(self.loc)


	def __repr__(self):
		return "Vertex %s, swidth=%s, ewidth=%s, bulge=%s, face=%s" %(self.loc, self.swidth, self.ewidth, self.bulge, self.face)


	def getx(self):
		return self.loc[0]
	def setx(self, value):
		self.loc[0] = value
	x = property(getx, setx)


	def gety(self):
		return self.loc[1]
	def sety(self, value):
		self.loc[1] = value
	y = property(gety, sety)


	def getz(self):
		return self.loc[2]
	def setz(self, value):
		self.loc[2] = value
	z = property(getz, setz)



class Text:  #-----------------------------------------------------------------
	"""Class for objects representing dxf Text.
	"""
	def __init__(self, obj):
		"""Expects an entity object of type text as input.
		"""
		if not obj.type == 'text':
			raise TypeError, "Wrong type %s for text object!" %obj.type
		self.type = obj.type
		self.data = obj.data[:]

		# required data
		self.height = 1.7 * obj.get_type(40)[0]  #text.height
		self.value = obj.get_type(1)[0]   #The text string value

		# optional data (with defaults)
		self.space = getit(obj, 67, 0)
		self.color_index = getit(obj, 62, BYLAYER)
		self.thic =  getit(obj, 39, 0)

		self.rotation = getit(obj, 50, 0)  # radians
		self.width_factor = getit(obj, 41, 1) # Scaling factor along local x axis
		self.oblique = getit(obj, 51, 0) # oblique angle: skew in degrees -90 <= oblique <= 90

		#self.style = getit(obj, 7, 'STANDARD') # --todo---- Text style name (optional, default = STANDARD)

		#Text generation flags (optional, default = 0):
		#2 = backward (mirrored in X),
		#4 = upside down (mirrored in Y)
		self.flags = getit(obj, 71, 0)
		self.mirrorX, self.mirrorY = 1.0, 1.0
		if self.flags&2: self.mirrorX = - 1.0
		if self.flags&4: self.mirrorY = - 1.0

		# vertical.alignment: 0=baseline, 1=bottom, 2=middle, 3=top
		self.valignment = getit(obj, 73, 0)
		#Horizontal text justification type (optional, default = 0) integer codes (not bit-coded)
		#0=left, 1=center, 2=right
		#3=aligned, 4=middle, 5=fit
		self.halignment = getit(obj, 72, 0)

		self.layer = getit(obj.data, 8, None)
		self.loc1, self.loc2 = self.get_loc(obj.data)
		if self.loc2[0] != None and self.halignment != 5: 
			self.loc = self.loc2
		else:
			self.loc = self.loc1
		self.extrusion = get_extrusion(obj.data)



	def get_loc(self, data):
		"""Gets adjusted location for text type objects.

		If group 72 and/or 73 values are nonzero then the first alignment point values
		are ignored and AutoCAD calculates new values based on the second alignment
		point and the length and height of the text string itself (after applying the
		text style). If the 72 and 73 values are zero or missing, then the second
		alignment point is meaningless.
		I don't know how to calc text size...
		"""
		# bottom left x, y, z and justification x, y, z = 0
		#x, y, z, jx, jy, jz = 0, 0, 0, 0, 0, 0
		x  = getit(data, 10, None) #First alignment point (in OCS). 
		y  = getit(data, 20, None)
		z  = getit(data, 30, 0.0)
		jx = getit(data, 11, None) #Second alignment point (in OCS). 
		jy = getit(data, 21, None)
		jz = getit(data, 31, 0.0)
		return [x, y, z],[jx, jy, jz]


	def __repr__(self):
		return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value)


	def draw(self, settings):
		"""for TEXTs: generate Blender_geometry.
		"""
		obname = 'tx_%s' %self.layer  # create object name from layer name
		obname = obname[:MAX_NAMELENGTH]
		txt = Text3d.New(obname)
		ob = SCENE.objects.new(txt) # create a new text_object

		txt.setText(self.value)
		txt.setSize(1.0) #Blender<2.45 accepts only (0.0 - 5.0)
		#txt.setSize(self.height)
		#txt.setWidth(self.bold)
		#setLineSeparation(sep)
		txt.setShear(self.oblique/90)

		thic = set_thick(self.thic, settings)
		if thic != 0.0:
			thic = self.thic * 0.5
			self.loc[2] += thic
			txt.setExtrudeDepth(1.0)  #Blender<2.45 accepts only (0.1 - 10.0)
		if self.halignment == 0:
			align = Text3d.LEFT
		elif self.halignment == 1:
			align = Text3d.MIDDLE
		elif self.halignment == 2:
			align = Text3d.RIGHT
		else:
			align = Text3d.LEFT
		txt.setAlignment(align)

		if self.valignment == 1:
			txt.setYoffset(0.0)
		elif self.valignment == 2:
			txt.setYoffset(- self.height * 0.5)
		elif self.valignment == 3:
			txt.setYoffset(- self.height)

		# move the object center to the text location
		ob.loc = tuple(self.loc)
		transform(self.extrusion, self.rotation, ob)

		# flip it and scale it to the text width
		ob.SizeX *= self.height * self.width_factor * self.mirrorX
		ob.SizeY *= self.height * self.mirrorY
		if thic != 0.0: ob.SizeZ *= abs(thic)
		return ob


	
def set_thick(thickness, settings):
	"""Set thickness relative to settings variables.
	
	Set thickness relative to settings variables:
	'thick_on','thick_force','thick_min'.
	Accepted also minus values of thickness
	python trick: sign(x)=cmp(x,0)
	"""
	if settings.var['thick_force']:
		if settings.var['thick_on']:
			if abs(thickness) <  settings.var['thick_min']:
				thic = settings.var['thick_min'] * cmp(self.thic,0)
			else: thic = thickness
		else: thic = settings.var['thick_min']
	else: 
		if settings.var['thick_on']: thic = thickness
		else: thic = 0.0
	return thic




class Mtext:  #-----------------------------------------------------------------
	"""Class for objects representing dxf Mtext.
	"""

	def __init__(self, obj):
		"""Expects an entity object of type mtext as input.
		"""
		if not obj.type == 'mtext':
			raise TypeError, "Wrong type %s for mtext object!" %obj.type
		self.type = obj.type
		self.data = obj.data[:]

		# required data
		self.height = obj.get_type(40)[0]
		self.width = obj.get_type(41)[0]
		self.alignment = obj.get_type(71)[0] # alignment 1=TL, 2=TC, 3=TR, 4=ML, 5=MC, 6=MR, 7=BL, 8=BC, 9=BR
		self.value = self.get_text(obj.data) # The text string value

		# optional data (with defaults)
		self.space = getit(obj, 67, 0)
		self.color_index = getit(obj, 62, BYLAYER)
		self.rotation = getit(obj, 50, 0)  # radians

		self.width_factor = getit(obj, 42, 1) # Scaling factor along local x axis
		self.line_space = getit(obj, 44, 1) # percentage of default

		self.layer = getit(obj.data, 8, None)
		self.loc = self.get_loc(obj.data)
		self.extrusion = get_extrusion(obj.data)


	def get_text(self, data):
		"""Reconstructs mtext data from dxf codes.
		"""
		primary = ''
		secondary = []
		for item in data:
			if item[0] == 1: # There should be only one primary...
				primary = item[1]
			elif item[0] == 3: # There may be any number of extra strings (in order)
				secondary.append(item[1])
		if not primary:
			#raise ValueError, "Empty Mtext Object!"
			string = "Empty Mtext Object!"
		if not secondary:
			string = primary.replace(r'\P', '\n')
		else:
			string = ''.join(secondary)+primary
			string = string.replace(r'\P', '\n')
		return string


	def get_loc(self, data):
		"""Gets location for a mtext type objects.

		Mtext objects have only one point indicating 
		"""	 
		loc = [0, 0, 0]
		loc[0] = getit(data, 10, None)
		loc[1] = getit(data, 20, None)
		loc[2] = getit(data, 30, 0.0)
		return loc


	def __repr__(self):
		return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value)


	def draw(self, settings):
		"""for MTEXTs: generate Blender_geometry.
		"""
		# Now Create an object
		obname = 'tm_%s' %self.layer  # create object name from layer name
		obname = obname[:MAX_NAMELENGTH]
		txt = Text3d.New(obname)
		ob = SCENE.objects.new(txt) # create a new text_object

		txt.setSize(1)
		# Blender doesn't give access to its text object width currently
		# only to the text3d's curve width...
		#txt.setWidth(text.width/10)
		txt.setLineSeparation(self.line_space)
		txt.setExtrudeDepth(0.5)
		txt.setText(self.value)

		# scale it to the text size
		ob.SizeX = self.height * self.width_factor
		ob.SizeY = self.height
		ob.SizeZ = self.height

		# move the object center to the text location
		ob.loc = tuple(self.loc)
		transform(self.extrusion, self.rotation, ob)

		return ob




class Circle:  #-----------------------------------------------------------------
	"""Class for objects representing dxf Circles.
	"""

	def __init__(self, obj):
		"""Expects an entity object of type circle as input.
		"""
		if not obj.type == 'circle':
			raise TypeError, "Wrong type %s for circle object!" %obj.type
		self.type = obj.type
		self.data = obj.data[:]

		# required data
		self.radius = obj.get_type(40)[0]

		# optional data (with defaults)
		self.space = getit(obj, 67, 0)
		self.thic =  getit(obj, 39, 0)
		self.color_index = getit(obj, 62, BYLAYER)

		self.layer = getit(obj.data, 8, None)
		self.loc = self.get_loc(obj.data)
		self.extrusion = get_extrusion(obj.data)



	def get_loc(self, data):
		"""Gets the center location for circle type objects.

		Circles have a single coord location.
		"""
		loc = [0, 0, 0]
		loc[0] = getit(data, 10, None)
		loc[1] = getit(data, 20, None)
		loc[2] = getit(data, 30, 0.0)
		return loc



	def __repr__(self):
		return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius)


	def draw(self, settings):
		"""for CIRCLE: generate Blender_geometry.
		"""
		obname = 'ci_%s' %self.layer  # create object name from layer name
		obname = obname[:MAX_NAMELENGTH]
		radius = self.radius

		thic = set_thick(self.thic, settings)
		if settings.var['curves_on']:
			c = Curve.New(obname)   # create new curve data
			p1 = (0, -radius, 0)
			p2 = (radius, 0, 0)
			p3 = (0, radius, 0)
			p4 = (-radius, 0, 0)

			p1 = BezTriple.New(p1)
			p2 = BezTriple.New(p2)
			p3 = BezTriple.New(p3)
			p4 = BezTriple.New(p4)

			curve = c.appendNurb(p1)
			curve.append(p2)
			curve.append(p3)
			curve.append(p4)
			for point in curve:
				point.handleTypes = [AUTO, AUTO]
			curve.flagU = 1 # Set curve cyclic=closed
			c.update()

			#remi --todo-----to check---------------------------
			ob = SCENE.objects.new(c) # create a new circle_mesh_object
			ob.loc = tuple(self.loc)
			if thic != 0.0: #hack: Blender<2.45 curve-extrusion
				thic = thic * 0.5
				c.setExt1(1.0)  # curve-extrusion accepts only (0.0 - 2.0)
				ob.LocZ = thic + self.loc[2]
			transform(self.extrusion, 0, ob)
			if thic != 0.0:
				ob.SizeZ *= abs(thic)
			return ob

		elif False:
			verts_num = settings.var['arc_res'] * sqrt(radius / settings.var['arc_rad'])
			if verts_num > 100: verts_num = 100 # Blender accepts only values [3:500]
			if verts_num < 4: verts_num = 4 # Blender accepts only values [3:500]
			if thic != 0:
				loc2 = thic * 0.5   #-----blenderAPI draw Cylinder with 2*thickness
				self.loc[2] += loc2  #---new location for the basis of cylinder
				#print 'deb:circleDraw:self.loc2:', self.loc  #-----------------------
				c = Mesh.Primitives.Cylinder(int(verts_num), radius*2, abs(thic))
			else:
				c = Mesh.Primitives.Circle(int(verts_num), radius*2)

			#c.update()
			ob = SCENE.objects.new(c, obname) # create a new circle_mesh_object
			ob.loc = tuple(self.loc)
			transform(self.extrusion, 0, ob)
			return ob

		else:
			cir = Mesh.New(obname)		 # create a new mesh
			ob = SCENE.objects.new(cir) # create a new arc_object
			# set a number of segments in entire circle
			arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad'])
			start, end = 0.0 , 360.0
			verts, edges = drawArc(None, radius, start, end, arc_res)
			verts = verts[:-2] #list without last point (cause first piont equal)
			edges = edges[:-1]
			edges[-1][1] = 0
			print 'deb:edges:', edges  #remi-todo----- why is this List inhomogene ? ----------
			if thic != 0:
				len1 = len(verts)
				thic_verts = []
				thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts])
				if thic < 0.0:
					thic_verts.extend(verts)
					verts = thic_verts
				else:
					verts.extend(thic_verts)
				faces = []
				faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)]
				faces.append([len1 - 1, 0, len1, len1 + len1 -1])
				if settings.var['fill_on']:
					if thic < 0.0:
						verts.append([0,0,thic])  #center of top side
						verts.append([0,0,0])  #center of bottom side
					else:
						verts.append([0,0,0])  #center of bottom side
						verts.append([0,0,thic])  #center of top side
					center1 = len(verts)-2
					center2 = len(verts)-1
					faces.extend([num+1, num, center1] for num in xrange(len1 - 1))
					faces.append([0, len1 - 1, center1])
					faces.extend([num+len1, num+1+len1, center2] for num in xrange(len1 - 1))
					faces.append([len1-1+len1, 0+len1, center2])
					#print 'deb:verts:', verts  #---------------
					#print 'deb:faces:', faces  #---------------
				cir.verts.extend(verts) # add vertices to mesh
				cir.faces.extend(faces)  # add faces to the mesh
			else:
				cir.verts.extend(verts) # add vertices to mesh
				cir.edges.extend(edges)  # add edges to the mesh

			ob.loc = tuple(self.loc)
			transform(self.extrusion, 0, ob)
			return ob
			
			


class Arc:  #-----------------------------------------------------------------
	"""Class for objects representing dxf arcs.
	"""

	def __init__(self, obj):
		"""Expects an entity object of type arc as input.
		"""
		if not obj.type == 'arc':
			raise TypeError, "Wrong type %s for arc object!" %obj.type
		self.type = obj.type
		self.data = obj.data[:]

		# required data
		self.radius = obj.get_type(40)[0]
		self.start_angle = obj.get_type(50)[0]
		self.end_angle = obj.get_type(51)[0]

		# optional data (with defaults)
		self.space = getit(obj, 67, 0)
		self.thic =  getit(obj, 39, 0)
		self.color_index = getit(obj, 62, BYLAYER)

		self.layer = getit(obj.data, 8, None)
		self.loc = self.get_loc(obj.data)
		self.extrusion = get_extrusion(obj.data)



	def get_loc(self, data):
		"""Gets the center location for arc type objects.

		Arcs have a single coord location.
		"""
		loc = [0, 0, 0]
		loc[0] = getit(data, 10, None)
		loc[1] = getit(data, 20, None)
		loc[2] = getit(data, 30, 0.0)
		return loc



	def __repr__(self):
		return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius)


	def draw(self, settings):
		"""for ARC: generate Blender_geometry.
		"""
		obname = 'ar_%s' %self.layer  # create object name from layer name
		obname = obname[:MAX_NAMELENGTH]

		center = self.loc
		radius = self.radius
		start = self.start_angle
		end = self.end_angle
		#print 'deb:drawArc: center, radius, start, end:\n', center, radius, start, end  #---------
		thic = set_thick(self.thic, settings)

		if settings.var['curves_on']:
			arc_res = 8
			verts, edges = drawArc(None, radius, start, end, arc_res)
			arc = Curve.New(obname) # create new curve data
			curve = arc.appendNurb(BezTriple.New(verts[0]))
			for p in verts[1:]:
				curve.append(BezTriple.New(p))
			for point in curve:
				point.handleTypes = [AUTO, AUTO]
				#print 'deb:arc.draw point=', point  #---------------
			curve[0].handleTypes = [FREE, VECT]   #remi--todo-----
			curve[-1].handleTypes = [VECT, FREE]   #remi--todo-----
			curve.flagU = 0 # Set curve not cyclic=open
			arc.update()

			#remi --todo-----to check---------------------------
			ob = SCENE.objects.new(arc) # create a new circle_mesh_object
			ob.loc = tuple(self.loc)
			if thic != 0.0: #hack: Blender<2.45 curve-extrusion
				thic = thic * 0.5
				arc.setExt1(1.0)  # curve-extrusion accepts only (0.0 - 2.0)
				ob.LocZ = thic + self.loc[2]
			transform(self.extrusion, 0, ob)
			if thic != 0.0:
				ob.SizeZ *= abs(thic)
			return ob

		else:
			arc = Mesh.New(obname)		 # create a new mesh
			ob = SCENE.objects.new(arc) # create a new arc_object
			# set a number of segments in entire circle
			arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad'])
			verts, edges = drawArc(None, radius, start, end, arc_res)
			if thic != 0:
				len1 = len(verts)
				thic_verts = []
				thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts])
				if thic < 0.0:
					thic_verts.extend(verts)
					verts = thic_verts
				else:
					verts.extend(thic_verts)
				faces = []
				#print 'deb:len1:', len1  #-----------------------
				#print 'deb:verts:', verts  #remi-todo----- why is this List inhomogene ----------
				faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)]

				arc.verts.extend(verts) # add vertices to mesh
				arc.faces.extend(faces)  # add faces to the mesh
			else:
				arc.verts.extend(verts) # add vertices to mesh
				arc.edges.extend(edges)  # add edges to the mesh

			#arc.update()
			#ob = SCENE.objects.new(arc) # create a new arc_object
			#ob.link(arc)
			ob.loc = tuple(center)
			#ob.loc = Mathutils.Vector(ob.loc)
			transform(self.extrusion, 0, ob)
			#ob.size = (1,1,1)
			return ob


class BlockRecord:  #-----------------------------------------------------------------
	"""Class for objects representing dxf block_records.
	"""

	def __init__(self, obj):
		"""Expects an entity object of type block_record as input.
		"""
		if not obj.type == 'block_record':
			raise TypeError, "Wrong type %s for block_record object!" %obj.type
		self.type = obj.type
		self.data = obj.data[:]

		# required data
		self.name =  getit(obj, 2, None)

		# optional data (with defaults)
		self.insertion_units =  getit(obj, 70, None)
		self.insert_units = getit(obj, 1070, None)
		"""code 1070 Einfügeeinheiten:
		0 = Keine Einheiten; 1 = Zoll; 2 = Fuß; 3 = Meilen; 4 = Millimeter;
		5 = Zentimeter; 6 = Meter; 7 = Kilometer; 8 = Mikrozoll;
		9 = Mils; 10 = Yard; 11 = Angstrom; 12 = Nanometer;
		13 = Mikrons; 14 = Dezimeter; 15 = Dekameter;
		16 = Hektometer; 17 = Gigameter; 18 = Astronomische Einheiten;
		19 = Lichtjahre; 20 = Parsecs
		"""


	def __repr__(self):
		return "%s: name - %s, insert units - %s" %(self.__class__.__name__, self.name, self.insertion_units)




class Block:  #-----------------------------------------------------------------
	"""Class for objects representing dxf blocks.
	"""

	def __init__(self, obj):
		"""Expects an entity object of type block as input.
		"""
		if not obj.type == 'block':
			raise TypeError, "Wrong type %s for block object!" %obj.type
		self.type = obj.type
		self.data = obj.data[:]
		self.name = obj.name

		# required data
		self.flags = obj.get_type(70)[0]
		self.entities = dxfObject('block_contents') #creates empty entities_container for this block
		self.entities.data = objectify([ent for ent in obj.data if type(ent) != list])

		# optional data (with defaults)
		self.path = getit(obj, 1, '')
		self.discription = getit(obj, 4, '')

		self.layer = getit(obj.data, 8, None)
		self.loc = self.get_loc(obj.data)


	def get_loc(self, data):
		"""Gets the insert point of the block.
		"""
		loc = [0, 0, 0]
		loc[0] = getit(data, 10, None) # 10 = x
		loc[1] = getit(data, 20, None) # 20 = y
		loc[2] = getit(data, 30,  0.0) # 30 = z
		return loc


	def __repr__(self):
		return "%s: name - %s, description - %s, xref-path - %s" %(self.__class__.__name__, self.name, self.discription, self.path)




class Insert:  #-----------------------------------------------------------------
	"""Class for objects representing dxf inserts.
	"""

	def __init__(self, obj):
		"""Expects an entity object of type insert as input.
		"""
		if not obj.type == 'insert':
			raise TypeError, "Wrong type %s for insert object!" %obj.type
		self.type = obj.type
		self.data = obj.data[:]

		# required data
		self.blockname = obj.get_type(2)[0]

		# optional data (with defaults)
		self.rotation =  getit(obj, 50, 0)
		self.space = getit(obj, 67, 0)
		self.color_index = getit(obj, 62, BYLAYER)

		self.layer = getit(obj.data, 8, None)
		self.loc = self.get_loc(obj.data)
		self.scale = self.get_scale(obj.data)
		self.rows, self.columns = self.get_array(obj.data)
		self.extrusion = get_extrusion(obj.data)



	def get_loc(self, data):
		"""Gets the center location for block type objects.
		"""
		loc = [0, 0, 0]
		loc[0] = getit(data, 10, 0.0)
		loc[1] = getit(data, 20, 0.0)
		loc[2] = getit(data, 30, 0.0)
		return loc



	def get_scale(self, data):
		"""Gets the x/y/z scale factor for the block.
		"""
		scale = [1, 1, 1]
		scale[0] = getit(data, 41, 1.0)
		scale[1] = getit(data, 42, 1.0)
		scale[2] = getit(data, 43, 1.0)
		return scale



	def get_array(self, data):
		"""Returns the pair (row number, row spacing), (column number, column spacing).
		"""
		columns = getit(data, 70, 1)
		rows	= getit(data, 71, 1)
		cspace  = getit(data, 44, 0.0)
		rspace  = getit(data, 45, 0.0)
		return (rows, rspace), (columns, cspace)



	def __repr__(self):
		return "%s: layer - %s, blockname - %s" %(self.__class__.__name__, self.layer, self.blockname)


	def draw(self, settings, deltaloc):
		"""for INSERT(block): draw empty-marker for duplicated Blender_Group.

		Blocks are made of three objects:
			the block_record in the tables section
			the block in the blocks section
			the insert object in the entities section

		block_records give the insert units, blocks provide the objects drawn in the
		block, and the insert object gives the location/scale/rotation of the block
		instances.  To draw a block you must first get a group with all the
		blocks entities drawn in it, then scale the entities to match the world
		units, then dupligroup that data to an object matching each insert object.
		"""

		obname = 'in_%s' %self.blockname  # create object name from block name
		obname = obname[:MAX_NAMELENGTH]

		if settings.drawTypes['insert']:  #if insert_drawType activated
			ob = SCENE.objects.new('Empty', obname) # create a new empty_object
			empty_size = 1.0 * settings.var['g_scale']
			if   empty_size < 0.01:  empty_size = 0.01
			elif empty_size > 10.0:  empty_size = 10.0
			ob.drawSize = empty_size

			# get our block_def-group
			block = settings.blocks(self.blockname)
			ob.DupGroup = block
			ob.enableDupGroup = True

		#print 'deb:draw.block.deltaloc:', deltaloc #--------------------
		ob.loc = tuple(self.loc)
		if deltaloc:
			deltaloc = rotXY_Vec(self.rotation, deltaloc)
			#print 'deb:draw.block.loc:', deltaloc  #--------------------
			ob.loc = [ob.loc[0]+deltaloc[0], ob.loc[1]+deltaloc[1], ob.loc[2]+deltaloc[2]]
		transform(self.extrusion, self.rotation, ob)
		ob.size = tuple(self.scale)
		return ob




class Ellipse:  #-----------------------------------------------------------------
	"""Class for objects representing dxf ellipses.
	"""

	def __init__(self, obj):
		"""Expects an entity object of type ellipse as input.
		"""
		if not obj.type == 'ellipse':
			raise TypeError, "Wrong type %s for ellipse object!" %obj.type
		self.type = obj.type
		self.data = obj.data[:]

		# required data
		self.ratio = obj.get_type(40)[0]
		self.start_angle = obj.get_type(41)[0]
		self.end_angle = obj.get_type(42)[0]

		# optional data (with defaults)
		self.space = getit(obj, 67, 0)
		self.thic =  getit(obj, 39, 0.0)
		self.color_index = getit(obj, 62, BYLAYER)

		self.layer = getit(obj.data, 8, None)
		self.loc = self.get_loc(obj.data)
		self.major = self.get_major(obj.data)
		self.extrusion = get_extrusion(obj.data)
		self.radius = sqrt(self.major[0]**2 + self.major[0]**2 + self.major[0]**2)


	def get_loc(self, data):
		"""Gets the center location for arc type objects.

		Arcs have a single coord location.
		"""
		loc = [0.0, 0.0, 0.0]
		loc[0] = getit(data, 10, 0.0)
		loc[1] = getit(data, 20, 0.0)
		loc[2] = getit(data, 30, 0.0)
		return loc


	def get_major(self, data):
		"""Gets the major axis for ellipse type objects.

		The ellipse major axis defines the rotation of the ellipse and its radius.
		"""
		loc = [0.0, 0.0, 0.0]
		loc[0] = getit(data, 11, 0.0)
		loc[1] = getit(data, 21, 0.0)
		loc[2] = getit(data, 31, 0.0)
		return loc


	def __repr__(self):
		return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius)


	def draw(self, settings):
		"""for ELLIPSE: generate Blender_geometry.
		"""
		# Generate the geometery
		center = self.loc
		thic = set_thick(self.thic, settings)

		if settings.var['curves_on']:
			ob = drawCurveArc(self)
		else:
			obname = 'el_%s' %self.layer  # create object name from layer name
			obname = obname[:MAX_NAMELENGTH]
			me = Mesh.New(obname)		  # create a new mesh
			ob = SCENE.objects.new(me) # create a new mesh_object

			major = Mathutils.Vector(self.major)
			#remi--todo----AngleBetweenVecs makes abs(value)!-----
			delta = Mathutils.AngleBetweenVecs(major, WORLDX)
			radius = major.length
			start = degrees(self.start_angle)
			end = degrees(self.end_angle)

			# set a number of segments in entire circle
			arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad'])
			verts, edges = drawArc(None, radius, start, end, arc_res)

			if thic != 0:
				len1 = len(verts)
				thic_verts = []
				thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts])
				if thic < 0.0:
					thic_verts.extend(verts)
					verts = thic_verts
				else:
					verts.extend(thic_verts)
				faces = []
				#print 'deb:len1:', len1  #-----------------------
				#print 'deb:verts:', verts  #remi--todo----- why is this List inhomogene? ----------
				faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)]

				me.verts.extend(verts)  # add vertices to mesh
				me.faces.extend(faces)   # add faces to the mesh
			else:
				me.verts.extend(verts)  # add vertices to mesh
				me.edges.extend(edges)   # add edges to the mesh

		ob.loc = tuple(center)
		ob.SizeY = self.ratio
		transform(self.extrusion, 0, ob)

		return ob



class Face:  #-----------------------------------------------------------------
	"""Class for objects representing dxf 3d faces.
	"""

	def __init__(self, obj):
		"""Expects an entity object of type 3dfaceplot as input.
		"""
		if not obj.type == '3dface':
			raise TypeError, "Wrong type %s for 3dface object!" %obj.type
		self.type = obj.type
		self.data = obj.data[:]

		# optional data (with defaults)
		self.space = getit(obj, 67, 0)
		self.color_index = getit(obj, 62, BYLAYER)

		self.layer = getit(obj.data, 8, None)
		self.points = self.get_points(obj.data)


	def get_points(self, data):
		"""Gets 3-4 points for a 3d face type object.

		Faces have three or optionally four verts.
		"""
		a = [0, 0, 0]
		b = [0, 0, 0]
		c = [0, 0, 0]
		d = [0, 0, 0]
		a[0] = getit(data, 10, None) # 10 = x
		a[1] = getit(data, 20, None) # 20 = y
		a[2] = getit(data, 30,  0.0) # 30 = z
		b[0] = getit(data, 11, None)
		b[1] = getit(data, 21, None)
		b[2] = getit(data, 31,  0.0)
		c[0] = getit(data, 12, None)
		c[1] = getit(data, 22, None)
		c[2] = getit(data, 32,  0.0)
		out = [a,b,c]

		d[0] =  getit(data, 13, None)
		if d[0] != None:
			d[1] = getit(data, 23, None)
			d[2] = getit(data, 33,  0.0)
			out.append(d)

		#if len(out) < 4: print '3dface with only 3 vertices:\n',a,b,c,d #-----------------
		return out


	def __repr__(self):
		return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)


	def draw(self, settings):
		"""for 3DFACE: generate Blender_geometry.
		"""
		# Generate the geometery
		points = self.points

		global activObjectLayer
		global activObjectName
		#print 'deb:draw:face.ob IN activObjectName: ', activObjectName #---------------------

		if activObjectLayer == self.layer and settings.var['one_mesh_on']:
			obname = activObjectName
			#print 'deb:face.draw obname from activObjectName: ', obname #---------------------
			ob = Object.Get(obname)  # open an existing mesh_object
			#ob = SCENE.getChildren(obname)  # open an existing mesh_object
		else:
			obname = 'fa_%s' %self.layer  # create object name from layer name
			obname = obname[:MAX_NAMELENGTH]
			me = Mesh.New(obname)		  # create a new mesh
			ob = SCENE.objects.new(me) # create a new mesh_object
			activObjectName = ob.name
			activObjectLayer = self.layer
			#print ('deb:except. new face.ob+mesh:"%s" created!' %ob.name) #---------------------

		me = Mesh.Get(ob.name)   # open objects mesh data
		faces, edges = [], []
		n = len(me.verts)
		if len(self.points) == 4:
			faces = [[0+n,1+n,2+n,3+n]]
		elif len(self.points) == 3:
			faces = [[0+n,1+n,2+n]]
		elif len(self.points) == 2:
			edges = [[0+n,1+n]]

		me.verts.extend(points) # add vertices to mesh
		if faces: me.faces.extend(faces)	   # add faces to the mesh
		if edges: me.edges.extend(edges)	   # add faces to the mesh
		if settings.var['vGroup_on']:
			# entities with the same color build one vertexGroup for easier material assignment ---------------------
			ob.link(me) # link mesh to that object
			vG_name = 'color_%s' %self.color_index
			if edges: faces = edges
			replace = Blender.Mesh.AssignModes.ADD  #or .AssignModes.REPLACE or ADD
			try:
				me.assignVertsToGroup(vG_name,  faces[0], 1.0, replace)
				#print 'deb: existed vGroup:', vG_name #---------------------
			except:
				me.addVertGroup(vG_name)
				me.assignVertsToGroup(vG_name,  faces[0], 1.0, replace)
				#print 'deb: create new vGroup:', vG_name #--------------------

		#print 'deb:draw:face.ob OUT activObjectName: ', activObjectName #---------------------
		return ob


#---------------------------------------------------------------------------------------
# type to object maping (sorted-dictionary for f_obiectify ONLY!, format={'key':Class} )
type_map = {
	'layer':Layer,
	'block_record':BlockRecord,
	'block':Block,
	'insert':Insert,
	'point':Point,
	'3dface':Face,
	'line':Line,
#   'mline':MLine,
	'polyline':Polyline,
	'lwpolyline':LWpolyline,
#   'region':Region,
	'trace':Solid,
	'solid':Solid,
	'text':Text,
	'mtext':Mtext,
	'circle':Circle,
	'ellipse':Ellipse,
	'arc':Arc
}



def objectify(data):  #-----------------------------------------------------------------
	"""Expects a section type object's data as input.

	Maps object data to the correct object type.
	"""
	#print 'deb:objectify start %%%%%%%%%%%' #---------------
	objects = [] # colector for finished objects
	known_types = type_map.keys() # so we don't have to call foo.keys() every iteration
	curves_on = GUI_A['curves_on'].val
	index = 0
	while index < len(data):
		item = data[index]
		#print 'deb:objectify item: \n', item #------------
		if type(item) != list and item.type == 'table':
			item.data = objectify(item.data) # tables have sub-objects
			objects.append(item)
		elif type(item) != list and item.type == 'polyline': #remi --todo-----------
			#print 'deb:gosub Polyline\n' #-------------
			pline = Polyline(item)
			while 1:
				index += 1
				item = data[index]
				if item.type == 'vertex':
					#print 'deb:objectify gosub Vertex--------' #-------------
					v = Vertex(item)
					if pline.spline: # Bspline-curve
						# then for Blender-mesh  filter only additional_vertices
						# OR
						# then for Blender-curve filter only spline_control_vertices
						if (v.spline and not curves_on) or (curves_on and v.splin2): #correct for real NURBS-import
						#if (v.spline and not curves_on) or (curves_on and not v.splin2): #fake for Bezier-emulation of NURBS-import
							pline.points.append(v)
					elif pline.curved:  # Bezier-curve
						# then for Blender-mesh filter only curve_additional_vertices
						# OR
						# then for Blender-curve filter curve_control_vertices
						if not curves_on or (curves_on and not v.curved):
							pline.points.append(v)
					else:
						pline.points.append(v)
				elif item.type == 'seqend':
					#print 'deb:objectify it is seqEND ---------\n' #-------------
					break
				else:
					print "Error: non-vertex found before seqend!"
					index -= 1  #so go back one step
					break
			objects.append(pline)
		elif type(item) != list and item.type in known_types:
			# proccess the object and append the resulting object
			objects.append(type_map[item.type](item))
		else:
			# we will just let the data pass un-harrased
			objects.append(item)
		index += 1
	#print 'deb:objectify objects:\n', objects #------------
	#print 'deb:objectify END %%%%%%%%' #------------
	return objects



class MatColors:  #-----------------------------------------------------------------
	"""A smart container for dxf-color based materials.

	This class is a wrapper around a dictionary mapping dxf-color indicies to materials.
	When called with a color index it returns a material corrisponding to that index.
	Behind the scenes it checks if that index is in its keys, and if not it creates
	a new material.  It then adds the new index:material pair to its dict and returns
	the material.
	"""

	def __init__(self, map):
		"""Expects a map - a dictionary mapping layer names to layers.
		"""
		self.map = map  # a dictionary of layername:layer
		self.colMaterials = {}  # a dictionary of color_index:blender_material
		#print 'deb:init_MatColors argument.map: ', map #------------------


	def __call__(self, color=None):
		"""Return the material associated with color.

		If a layer name is provided, the color of that layer is used.
		"""
		if not color:
			color = 0
		if type(color) == str:
			#print 'deb:color is string:--------------: ', color #--todo---bug with ARC from ARC-T0.DXF layer="T-3DARC-1"-----
			try:
				color = self.map[color].color
				#print 'deb:color=self.map[color].color:', color #------------------
			except KeyError:
				layer = Layer(name=color, color=0, frozen=False)
				self.map[color] = layer
				color = 0
		color = abs(color)
		if color not in self.colMaterials.keys():
			self.add(color)
		return self.colMaterials[color]


	def add(self, color):
		"""Create a new material 'ColorNr-N' using the provided color index-N.
		"""
		global color_map
		mat = Material.New('ColorNr-%s' %color)
		mat.setRGBCol(color_map[color])
		mat.mode |= Material.Modes.SHADELESS
		mat.mode |= Material.Modes.WIRE
#	   try: mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc-bug
#	   except: pass
		self.colMaterials[color] = mat



class MatLayers:  #-----------------------------------------------------------------
	"""A smart container for dxf-layer based materials.

	This class is a wrapper around a dictionary mapping dxf-layer names to materials.
	When called with a layer name it returns a material corrisponding to that.
	Behind the scenes it checks if that layername is in its keys, and if not it creates
	a new material.  It then adds the new layername:material pair to its dict and returns
	the material.
	"""

	def __init__(self, map):
		"""Expects a map - a dictionary mapping layer names to layers.
		"""
		self.map = map  # a dictionary of layername:layer
		self.layMaterials = {}  # a dictionary of layer_name:blender_material
		#print 'deb:init_MatLayers argument.map: ', map #------------------


	def __call__(self, layername=None):
		"""Return the material associated with dxf-layer.

		If a dxf-layername is not provided, create a new material
		"""
		if layername not in self.layMaterials.keys():
			self.add(layername)
		return self.layMaterials[layername]


	def add(self, layername):
		"""Create a new material 'layername'.
		"""
		try: mat = Material.Get('Lay-%s' %layername)
		except: mat = Material.New('Lay-%s' %layername)
		#print 'deb:MatLayers material: ', mat  #----------
		#print 'deb:MatLayers getMode: ', mat.getMode()  #----------
		global layersmap
		color = layersmap[layername].color
		#print 'deb:MatLayers layer_color: ', color  #-----------
		global color_map
		mat.setRGBCol(color_map[color])
		mat.mode |= Material.Modes.SHADELESS
		mat.mode |= Material.Modes.WIRE
#	   try: mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc-bug
#	   except: pass
		self.layMaterials[layername] = mat




class Blocks:  #-----------------------------------------------------------------
	"""A smart container for blocks.

	This class is a wrapper around a dictionary mapping block names to Blender data blocks.
	When called with a name string it returns a block corresponding to that name.
	Behind the scenes it checks if that name is in its keys, and if not it creates
	a new data block.  It then adds the new name:block_data pair to its dict and returns
	the block.
	"""

	def __init__(self, blocksmap, settings):
		"""Expects a dictionary mapping block_name:block_data.
		"""
		self.blocksmap = blocksmap	 #a dictionary mapping block_name:block_data
		self.settings = settings
		self.blocks = {}   #container for blocks


	def __call__(self, name=None):
		"""Return the data block associated with that block_name.

		If that name is not in its keys, it creates a new data block.
		If no name is provided return entire self.blocks container.
		"""
		if not name:
			return self.blocks
		if name not in self.blocks.keys():
			self.addBlock(name)
		return self.blocks[name]


	def addBlock(self, name):
		"""Create a new 'block group' for the block name.
		"""
		block_def = Group.New('bl_%s' %name)  # groupObject contains definition of BLOCK
		block = self.blocksmap[name]
		self.settings.write("\nDrawing block:\'%s\' ..." % name)
		drawEntities(block.entities, self.settings, block_def)
		self.settings.write("Drawing block:\'%s\' done!" %name)
		self.blocks[name] = block_def





class Settings:  #-----------------------------------------------------------------
	"""A container for all the import settings and objects used by the draw functions.

	This is like a collection of globally accessable persistant properties and functions.
	"""
	# Optimization constants
	MIN = 0
	MID = 1
	PRO = 2
	MAX = 3

	def __init__(self, keywords, drawTypes):
		"""initialize all the important settings used by the draw functions.
		"""
		self.obj_number = 1 #global object_number for progress_bar

		self.var = dict(keywords)	  #a dictionary of (key_variable:Value) control parameter
		self.drawTypes = dict(drawTypes) #a dictionary of (entity_type:True/False) = import on/off for this entity_type

		self.var['colorFilter_on'] = False   #deb:remi------------
		self.acceptedColors = [0,2,3,4,5,6,7,8,9,
							   10 ]

		self.var['layerFilter_on'] = False   #deb:remi------------
		self.acceptedLayers = ['3',
						   '0'
						  ]

		self.var['blockFilter_on'] = False   #deb:remi------------
		self.acceptedBlocks = ['BOX01',
						   'BOX02'
						  ]


	def update(self, keywords, drawTypes):
		"""update all the important settings used by the draw functions.
		"""

		for k, v in keywords.iteritems():
			self.var[k] = v
			#print 'deb:settings_update var %s= %s' %(k, self.var[k]) #--------------
		for t, v in drawTypes.iteritems():
			self.drawTypes[t] = v
			#print 'deb:settings_update drawType %s= %s' %(t, self.drawTypes[t]) #--------------

		#print 'deb:self.drawTypes', self.drawTypes #---------------


	def validate(self, drawing):
		"""Given the drawing, build dictionaries of Layers, Colors and Blocks.
		"""

		#de:	paßt die distance parameter an globalScale
		if self.var['g_scale'] != 1:
			self.var['dist_min']  = self.var['dist_min'] / self.var['g_scale']
			self.var['thick_min'] = self.var['thick_min'] / self.var['g_scale']
			self.var['width_min'] = self.var['width_min'] / self.var['g_scale']

		# First sort out all the section_items
		sections = dict([(item.name, item) for item in drawing.data])

		# The section:header may be omited
		if 'header' in sections.keys():
			self.write("Found section:header!")
		else:
			self.write("File contains no section:header!")

		# The section:tables may be partialy or completely missing.
		self.layersTable = False
		self.colMaterials = MatColors({})
		self.layMaterials = MatLayers({})
		if 'tables' in sections.keys():
			self.write("Found section:tables!")
			# First sort out all the tables
			tables = dict([(item.name, item) for item in sections["tables"].data])
			if 'layer' in tables.keys():
				self.write("Found table:layers!")
				self.layersTable = True
				# Read the layers table and get the layer colors
				global layersmap
				layersmap = getLayersmap(drawing)
				self.colMaterials = MatColors(layersmap)
				self.layMaterials = MatLayers(layersmap)
			else:
				self.write("File contains no table:layers!")
		else:
			self.write("File contains no section:tables!")
			self.write("File contains no table:layers!")

		# The section:blocks may be omited
		if 'blocks' in sections.keys():
			self.write("Found section:blocks!")
			# Read the block definitions and build our block object
			if self.drawTypes['insert']:  #if drawing of type 'Insert' activated
				blocksmap, self.obj_number = getBlocksmap(drawing)  #Build a dictionary of blockname:block_data pairs
				self.blocks = Blocks(blocksmap, self) # initiates container for blocks_data

			#print 'deb: self.obj_number', self.obj_number #----------
		else:
			self.write("File contains no section:blocks!")
			self.drawTypes['insert'] = False

		# The section:entities
		if 'entities' in sections.keys():
			self.write("Found section:entities!")

			self.obj_number += len(drawing.entities.data)
			#print 'deb: self.obj_number', self.obj_number #----------
			self.obj_number = 1.0 / self.obj_number


	def write(self, text, newline=True):
		"""Wraps the built-in print command in a optimization check.
		"""
		if self.var['optimization'] <= self.MID:
			if newline:
				print text
			else:
				print text,


	def redraw(self):
		"""Update Blender if optimization level is low enough.
		"""
		if self.var['optimization'] <= self.MIN:
			Blender.Redraw()


	def progress(self, done, text):
		"""Wrapper for Blender.Window.DrawProgressBar.
		"""
		if self.var['optimization'] <= self.PRO:
			progressbar = done * self.obj_number
			Window.DrawProgressBar(progressbar, text)
			#print 'deb:drawer done, progressbar: ', done, progressbar  #-----------------------


	def layer_isOff(self, name):
		"""Given a layer name, and return its visible status.
		"""
		# colors are negative if layer is off
		try:
			#print 'deb:layer_isOff self.colMaterials.map:\n', self.colMaterials.map #--------------
			layer = self.colMaterials.map[name]
		except KeyError: return False
		if layer.color < 0: return True
		#print 'deb:layer_isOff: layer is ON' #---------------
		return False


	def layer_isFrozen(self, name):
		"""Given a layer name, and return its frozen status.
		"""
		# colors are negative if layer is off
		try:
			#print 'deb:layer_isFrozen self.colMaterials.map:\n', self.colMaterials.map #---------------
			layer = self.colMaterials.map[name]
		except KeyError: return False
		if layer.frozen: return True
		#print 'deb:layer_isFrozen: layer is not FROZEN' #---------------
		return False




def main(dxfFile):  #---------------#############################-----------
	#print 'deb:filename:', filename #--------------
	global SCENE
	editmode = Window.EditMode()	# are we in edit mode?  If so ...
	if editmode:
		Window.EditMode(0) # leave edit mode before

	#SCENE = bpy.data.scenes.active
	#SCENE.objects.selected = [] # deselect all
	
	global cur_COUNTER  #counter for progress_bar
	cur_COUNTER = 0

	try:
		print "Getting settings..."
		global GUI_A, GUI_B
		if GUI_A['g_scale_on'].val:
			GUI_A['g_scale'].val = 10.0 ** int(GUI_A['g_scale_as'].val)
		else:
			GUI_A['g_scale'].val = 1.0

		keywords = {}
		drawTypes = {}
		for k, v in GUI_A.iteritems():
			keywords[k] = v.val
		for k, v in GUI_B.iteritems():
			drawTypes[k] = v.val
		#print 'deb:startUInew keywords: ', keywords #--------------
		#print 'deb:startUInew drawTypes: ', drawTypes #--------------

		# The settings object controls how dxf entities are drawn
		settings.update(keywords, drawTypes)
		#print 'deb:settings.var:\n', settings.var  #-----------------------

		if not settings:
			#Draw.PupMenu('DXF importer:  EXIT!%t')
			print '\nDXF Import: terminated by user!'
			Window.WaitCursor(False)
			if editmode: Window.EditMode(1) # and put things back how we fond them
			return None

		#no more used dxfFile = dxfFileName.val
		#print 'deb: dxfFile file: ', dxfFile #----------------------
		if dxfFile.lower().endswith('.dxf') and sys.exists(dxfFile):
			Window.WaitCursor(True)   # Let the user know we are thinking
			print 'start	reading DXF file: %s.' % dxfFile
			time1 = Blender.sys.time()  #time marker1
			drawing = readDXF(dxfFile, objectify)
			print 'finished reading DXF file in %.4f sec.' % (Blender.sys.time()-time1)
			Window.WaitCursor(False)
		else:
			if UI_MODE: Draw.PupMenu('DXF importer:  EXIT----------!%t| no valid DXF-file selected!')
			print "DXF importer: error, no DXF-file selected. Abort!"
			Window.WaitCursor(False)
			if editmode: Window.EditMode(1) # and put things back how we fond them
			return None

		settings.validate(drawing)

		Window.WaitCursor(True)   # Let the user know we are thinking
		settings.write("\n\nDrawing entities...")

		# Draw all the know entity types in the current scene
		global oblist
		oblist = []  # a list of all created AND linked objects for final f_globalScale
		time2 = Blender.sys.time()  #time marker2

		drawEntities(drawing.entities, settings)

		#print 'deb:drawEntities after: oblist:', oblist #-----------------------
		if oblist: # and settings.var['g_scale'] != 1:
			globalScale(oblist, settings.var['g_scale'])

		# Set the visable layers
		SCENE.setLayers([i+1 for i in range(18)])
		SCENE.update(1)
		#Blender.Redraw(-1)
		SCENE.objects.selected = [i[0] for i in oblist] #select only the imported objects		   
		#SCENE.objects.selected = SCENE.objects   #select all objects in current scene		  
		Blender.Redraw()

		time_text = Blender.sys.time() - time2
		Window.WaitCursor(False)
		message = 'DXF Import to Blender: done in %.4f sec.  --------------------' % time_text
		settings.progress(1.0/settings.obj_number, 'DXF import done!')
		print message
		#settings.write(message)
		if UI_MODE: Draw.PupMenu('DXF importer:	Done!|finished in %.4f sec.' % time_text)

	finally:
		# restore state even if things didn't work
		#print 'deb:drawEntities finally!' #-----------------------
		Window.WaitCursor(False)
		if editmode: Window.EditMode(1) # and put things back how we fond them



def getOCS(az):  #-----------------------------------------------------------------
	"""An implimentation of the Arbitrary Axis Algorithm.
	"""
	#decide if we need to transform our coords
	if az[0] == 0 and az[1] == 0:
		return False
	#elif abs(az[0]) < 0.0001 and abs(az[1]) < 0.0001:
	#   return False

	az = Mathutils.Vector(az)

	cap = 0.015625 # square polar cap value (1/64.0)
	if abs(az.x) < cap and abs(az.y) < cap:
		ax = Mathutils.CrossVecs(WORLDY, az)
	else:
		ax = Mathutils.CrossVecs(WORLDZ, az)
	ax = ax.normalize()
	ay = Mathutils.CrossVecs(az, ax)
	ay = ay.normalize()
	return ax, ay, az



def transform(normal, rotation, obj):  #--------------------------------------------
	"""Use the calculated ocs to determine the objects location/orientation in space.

	Quote from dxf docs:
		The elevation value stored with an entity and output in DXF files is a sum
	of the Z-coordinate difference between the UCS XY plane and the OCS XY
	plane, and the elevation value that the user specified at the time the entity
	was drawn.
	"""
	ma = Mathutils.Matrix([1,0,0],[0,1,0],[0,0,1])
	o = Mathutils.Vector(obj.loc)
	ocs = getOCS(normal)
	if ocs:
		ma = Mathutils.Matrix(ocs[0], ocs[1], ocs[2])
		o = ma.invert() * o
		ma = Mathutils.Matrix(ocs[0], ocs[1], ocs[2])

	if rotation != 0:
		g = radians(-rotation)
		rmat = Mathutils.Matrix([cos(g), -sin(g), 0], [sin(g), cos(g), 0], [0, 0, 1])
		ma = rmat * ma

	obj.setMatrix(ma)
	obj.loc = o
	#print 'deb:new obj.matrix:\n', obj.getMatrix()   #--------------------



def rotXY_Vec(rotation, vec):  #----------------------------------------------------
	"""Rotate vector vec in XY-plane. vec must be in radians
	"""
	if rotation != 0:
		o = Mathutils.Vector(vec)
		g = radians(-rotation)
		vec = o * Mathutils.Matrix([cos(g), -sin(g), 0], [sin(g), cos(g), 0], [0, 0, 1])
	return vec



def getLayersmap(drawing):  #------------------------------------------------------
	"""Build a dictionary of layername:layer pairs for the given drawing.
	"""
	tables = drawing.tables
	for table in tables.data:
		if table.name == 'layer':
			layers = table
			break
	layersmap = {}
	for item in layers.data:
		if type(item) != list and item.type == 'layer':
			layersmap[item.name] = item
	return layersmap



def getBlocksmap(drawing):  #--------------------------------------------------------
	"""Build a dictionary of blockname:block_data pairs for the given drawing.
	"""
	blocksmap = {}
	obj_number = 0
	for item in drawing.blocks.data:
		#print 'deb:getBlocksmap item=' ,item #--------
		#print 'deb:getBlocksmap item.entities=' ,item.entities #--------
		#print 'deb:getBlocksmap item.entities.data=' ,item.entities.data #--------
		if type(item) != list and item.type == 'block':
			obj_number += len(item.entities.data)
			try:
				blocksmap[item.name] = item
			except KeyError:
				# annon block
				print 'Cannot map "%s" - "%s" as Block!' %(item.name, item)
	return blocksmap, obj_number





def drawEntities(entities, settings, block_def=None):  #----------------------------------------
	"""Draw every kind of thing in the entity list.

	If provided 'block_def': the entities are to be added to the Blender 'group'.
	"""
	for _type in type_map.keys():
		#print 'deb:drawEntities_type:', _type #------------------
		# for each known type get a list of that type and call the associated draw function
		drawer(_type, entities.get_type(_type), settings, block_def)


def drawer(_type, entities, settings, block_def):  #------------------------------------------
	"""Call with a list of entities and a settings object to generate Blender geometry.

	If 'block_def': the entities are to be added to the Blender 'group'.
	"""
	if entities:
		# Break out early if settings says we aren't drawing the current dxf-type
		global cur_COUNTER  #counter for progress_bar
		group = None
		#print 'deb:drawer.check:_type: ', _type  #--------------------
		if _type == '3dface':_type = 'face' # hack, while python_variable_name can not beginn with a nummber
		if not settings.drawTypes[_type] or _type == 'block_record':
			message = 'Skipping dxf\'%ss\' entities' %_type
			settings.write(message, True)
			cur_COUNTER += len(entities)
			settings.progress(cur_COUNTER, message)
			return
		#print 'deb:drawer.todo:_type:', _type  #-----------------------

		len_temp = len(entities)
		# filtering only model-space enitities (no paper-space enitities)
		entities = [entity for entity in entities if entity.space == 0]

		# filtering only objects with color from acceptedColorsList
		if settings.var['colorFilter_on']:
			entities = [entity for entity in entities if entity.color in settings.acceptedColors]

		# filtering only objects on layers from acceptedLayersList
		if settings.var['layerFilter_on']:
#		   entities = [entity for entity in entities if entity.layer[0] in ['M','3','0'] and not entity.layer.endswith('H')]
			entities = [entity for entity in entities if entity.layer in settings.acceptedLayers]

		# filtering only objects on not-frozen layers
		entities = [entity for entity in entities if not settings.layer_isFrozen(entity.layer)]

		global activObjectLayer, activObjectName
		activObjectLayer = ''
		activObjectName = ''

		message = "Drawing dxf\'%ss\'..." %_type
		cur_COUNTER += len_temp - len(entities)
		settings.write(message, False)
		settings.progress(cur_COUNTER, message)
		if len(entities) > 0.1 / settings.obj_number:
			show_progress = int(0.03 / settings.obj_number)
		else: show_progress = 0
		cur_temp = 0

		#print 'deb:drawer cur_COUNTER: ', cur_COUNTER  #-----------------------

		for entity in entities:   #----loop-------------------------------------
			settings.write('\b.', False)
			cur_COUNTER += 1
			if show_progress:
				cur_temp += 1
				if cur_temp == show_progress:
					settings.progress(cur_COUNTER, message)
					cur_temp = 0
					#print 'deb:drawer show_progress=',show_progress  #-----------------------
				
			# get the layer group (just to make things a little cleaner)
			if settings.var['group_bylayer_on'] and not block_def:
				group = getGroup('l:%s' % entity.layer[:MAX_NAMELENGTH-2])

			if _type == 'insert':   #---- INSERT and MINSERT=array ------------------------
				#print 'deb:insert entity.loc:', entity.loc #----------------
				columns = entity.columns[0]
				coldist = entity.columns[1]
				rows	= entity.rows[0]
				rowdist = entity.rows[1]
				deltaloc = [0,0,0]
				#print 'deb:insert columns, rows:', columns, rows   #-----------
				for col in xrange(columns):
					deltaloc[0] =  col * coldist
					for row in xrange(rows):
						deltaloc[1] =  row * rowdist
						#print 'deb:insert col=%s, row=%s,deltaloc=%s' %(col, row, deltaloc) #------
						ob = entity.draw(settings, deltaloc)   #-----draw BLOCK----------
						setObjectProperties(ob, group, entity, settings, block_def)
						if ob:
							if settings.var['optimization'] <= settings.MIN:
								if settings.var['g_scale'] != 1: globalScaleOne(ob, True, settings.var['g_scale'])
								settings.redraw()
							else: oblist.append((ob, True))
					
			else:   #---draw entities except BLOCKs/INSERTs---------------------
				alt_obname = activObjectName
				ob = entity.draw(settings)
				if ob and ob.name != alt_obname:
					setObjectProperties(ob, group, entity, settings, block_def)
					if settings.var['optimization'] <= settings.MIN:
						if settings.var['g_scale'] != 1: globalScaleOne(ob, False, settings.var['g_scale'])
						settings.redraw()
					else: oblist.append((ob, False))

		#print 'deb:Finished drawing:', entities[0].type   #------------------------
		message = "\nDrawing dxf\'%ss\' done!" % _type
		settings.write(message, True)



def globalScale(oblist, SCALE):  #---------------------------------------------------------
	"""Global_scale for list of all imported objects.

	oblist is a list of pairs (ob, insertFlag), where insertFlag=True/False
	"""
	#print 'deb:globalScale.oblist: ---------%\n', oblist #---------------------
	for l in oblist:
		ob, insertFlag  = l[0], l[1]
		globalScaleOne(ob, insertFlag, SCALE)


def globalScaleOne(ob, insertFlag, SCALE):  #---------------------------------------------------------
	"""Global_scale imported object.
	"""
	#print 'deb:globalScaleOne  ob: ', ob #---------------------
	SCALE_MAT= Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1])
	if insertFlag:  # by BLOCKs/INSERTs only insert-point must be scaled------------
		ob.loc = Mathutils.Vector(ob.loc) * SCALE_MAT
	else:   # entire scaling for all other imported objects ------------
		ob.setMatrix(ob.matrixWorld*SCALE_MAT)



def setObjectProperties(ob, group, entity, settings, block_def):  #-----------------------
	"""Link object to scene.
	"""

	if not ob:  #remi--todo-----------------------
		message = "\nObject \'%s\' not found!" %entity
		settings.write(message)
		return

	if group:
		setGroup(group, ob)  # if object belongs to group

	if block_def:   # if object belongs to BLOCK_def - Move it to layer nr19
		setGroup(block_def, ob)
		#print 'deb:setObjectProperties  \'%s\' set to block_def_group!' %ob.name #---------
		ob.layers = [19]
	else:
		#ob.layers = [i+1 for i in xrange(20)] #remi--todo------------
		ob.layers = [settings.var['target_layer']]

	# Set material for any objects except empties
	if ob.type != 'Empty':
		setMaterial_from(entity, ob, settings, block_def)

	# Set the visibility
	if settings.layer_isOff(entity.layer):
		#ob.layers = [20]  #remi--todo-------------
		ob.restrictDisplay = True
		ob.restrictRender = True

	#print 'deb:\n---------linking Object %s!' %ob.name #----------



def getGroup(name):  #-----------------------------------------------------------------
	"""Returns a Blender group-object.
	"""
	try:
		group = Group.Get(name)
	except: # What is the exception?
		group = Group.New(name)
	return group


def setGroup(group, ob):  #------------------------------------------------------------
	"""Assigns object to Blender group.
	"""
	try:
		group.objects.link(ob)
	except:
		group.objects.append(ob)  #remi?---------------



def setMaterial_from(entity, ob, settings, block_def):  #------------------------------------------------
	""" Set Blender-material for the object controled by item.

	Set Blender-material for the object
	 - controlled by settings.var['material_from']
	"""
	if settings.var['material_from'] == 1: # 1= material from color
		if entity.color_index == BYLAYER:
			mat = settings.colMaterials(entity.layer)
		else:
			mat = settings.colMaterials(entity.color_index)
	elif settings.var['material_from'] == 2: # 2= material from layer
		mat = settings.layMaterials(entity.layer)
#   elif settings.var['material_from'] == 3: # 3= material from layer+color
#	   mat = settings.layMaterials(entity.layer)
#	   color = entity.color_index
#	   if type(color) == int:
#		   mat.setRGBCol(color_map[abs(color)])
#   elif settings.var['material_from'] == 4: # 4= material from block
#   elif settings.var['material_from'] == 5: # 5= material from INI-file
	else:					   # set neutral material
		try:
			mat = Material.Get('dxf-neutral')
		except:
			mat = Material.New('dxf-neutral')
			mat.mode |= Material.Modes.SHADELESS
			mat.mode |= Material.Modes.WIRE
#		   try:mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc1-bug
#		   except: pass
	try:
		#print 'deb:material mat:', mat #-----------
		ob.setMaterials([mat])  #assigns Blender-material to object
	except ValueError:
		settings.write("material error - \'%s\'!" %mat)
	ob.colbits = 0x01 # Set OB materials.



def drawBulge(p1, p2, arc_res, curve_on=False):   #-------------------------------------------------
	"""return the center, radius, start angle, and end angle given two points.

	Needs to take into account bulge sign.
	negative = clockwise
	positive = counter-clockwise

	to find center given two points, and arc angle
	calculate radius
		Cord = sqrt(start^2 + end^2)
		S = (bulge*Cord)/2
		radius = ((Cord/2)^2+S^2)/2*S
	angle of arc = 4*atan( bulge )
	angle from p1 to center is (180-angle)/2
	get vector pointing from p1 to p2 (p2 - p1)
	normalize it and multiply by radius
	rotate around p1 by angle to center, point to center.
	start angle = angle between (center - p1) and worldX
	end angle = angle between (center - p2) and worldX
	"""

	bulge = p1.bulge
	p2 = Mathutils.Vector(p2.loc)
	p1 = Mathutils.Vector(p1.loc)
	cord = p2 - p1 # vector from p1 to p2
	clength = cord.length
	s = (bulge * clength)/2.0 # sagitta (height)
	radius = abs(((clength/2.0)**2.0 + s**2.0)/(2.0*s)) # magic formula
	angle = (degrees(4.0*atan(bulge))) # theta (included angle)
	if curve_on:
		verts_num = 8
	else:
		verts_num = arc_res * sqrt(radius)  # set a number of segments in entire circle
		if verts_num > 1024: verts_num = 1024 # Blender accepts only values [3:500]
		if verts_num < 4: verts_num = 4 # Blender accepts only values [3:500]
	pieces = int(abs(angle)/(360.0/verts_num))
	if pieces < 3: pieces = 3  #bulge under arc_resolution
	#if pieces < 3: points = [p1, p2] ;return points
	step = angle/pieces  # set step so pieces * step = degrees in arc
	delta = (180.0 - abs(angle))/2.0 # the angle from cord to center
	if bulge < 0: delta = -delta
	radial = cord.normalize() * radius # a radius length vector aligned with cord
	rmat = Mathutils.RotationMatrix(-delta, 3, 'Z')
	center = p1 + (rmat * radial) # rotate radial by delta degrees, then add to p1 to find center
	#length = radians(abs(angle)) * radius
	#print 'deb:drawBulge:\n angle, delta: ', angle, delta  #----------------
	#print 'deb:center, radius: ', center, radius  #----------------------

	startpoint = p1 - center
	#endpoint = p2 - center
	stepmatrix = Mathutils.RotationMatrix(-step, 3, "Z")
	points = [startpoint]
	point = Mathutils.Vector(startpoint)
	for i in xrange(int(pieces)-1):  #fast (but not so acurate as: vector * RotMatrix(step * i)
		point = stepmatrix * point
		points.append(point)
	points = [[point[0]+center[0], point[1]+center[1], point[2]+center[2]] for point in points]
	return points



def drawArc(center, radius, start, end, arc_res):  #-----------------------------------------
	"""Draw a mesh arc with the given parameters.
	"""
	# center is currently set by object
	# if start > end: start = start - 360
	if end > 360: end = end%360.0

	startmatrix = Mathutils.RotationMatrix(-start, 3, "Z")
	startpoint = startmatrix * Mathutils.Vector(radius, 0, 0)
	endmatrix = Mathutils.RotationMatrix(-end, 3, "Z")
	endpoint = endmatrix * Mathutils.Vector(radius, 0, 0)

	if end < start: end +=360.0
	angle = end - start
	#length = radians(angle) * radius

	#if radius < MIN_DIST * 10: # if circumfence is too small
	if arc_res > 1024: arc_res = 1024 
	if arc_res < 4: arc_res = 4 
	pieces = int(abs(angle)/(360.0/arc_res)) # set a fixed step of ARC_RESOLUTION
	if pieces < 3: pieces = 3  #cambo-----
	step = angle/pieces # set step so pieces * step = degrees in arc

	stepmatrix = Mathutils.RotationMatrix(-step, 3, "Z")
	points = [startpoint]
	point = Mathutils.Vector(startpoint)
	for i in xrange(int(pieces)):
		point = stepmatrix * point
		points.append(point)
	points.append(endpoint)

	if center:
		points = [[point[0]+center[0], point[1]+center[1], point[2]+center[2]] for point in points]
	edges = [[num, num+1] for num in xrange(len(points)-1)]

	return points, edges



def drawCurveCircle(circle):  #--- no more used --------------------------------------------
	"""Given a dxf circle object return a blender circle object using curves.
	"""
	c = Curve.New('circle') # create new  curve data
	center = circle.loc
	radius = circle.radius

	p1 = (0, -radius, 0)
	p2 = (radius, 0, 0)
	p3 = (0, radius, 0)
	p4 = (-radius, 0, 0)

	p1 = BezTriple.New(p1)
	p2 = BezTriple.New(p2)
	p3 = BezTriple.New(p3)
	p4 = BezTriple.New(p4)

	curve = c.appendNurb(p1)
	curve.append(p2)
	curve.append(p3)
	curve.append(p4)
	for point in curve:
		point.handleTypes = [AUTO, AUTO]
	curve.flagU = 1 # Set curve cyclic
	c.update()

	ob = Object.New('Curve', 'circle')  # make curve object
	return ob


def drawCurveArc(self):  #---- only for ELLIPSE -------------------------------------------------------------
	"""Given a dxf ELLIPSE object return a blender_curve.
	"""
	center = self.loc
	radius = self.radius
	start = self.start_angle
	end = self.end_angle

	if start > end:
		start = start - 360.0
	startmatrix = Mathutils.RotationMatrix(start, 3, "Z")
	startpoint = startmatrix * Mathutils.Vector((radius, 0, 0))
	endmatrix = Mathutils.RotationMatrix(end, 3, "Z")
	endpoint = endmatrix * Mathutils.Vector((radius, 0, 0))
	# Note: handles must be tangent to arc and of correct length...

	a = Curve.New('arc')			 # create new  curve data

	p1 = (0, -radius, 0)
	p2 = (radius, 0, 0)
	p3 = (0, radius, 0)
	p4 = (-radius, 0, 0)

	p1 = BezTriple.New(p1)
	p2 = BezTriple.New(p2)
	p3 = BezTriple.New(p3)
	p4 = BezTriple.New(p4)

	curve = a.appendNurb(p1)
	curve.append(p2)
	curve.append(p3)
	curve.append(p4)
	for point in curve:
		point.handleTypes = [AUTO, AUTO]
	curve.flagU = 1 # Set curve cyclic
	a.update()

	ob = Object.New('Curve', 'arc') # make curve object
	return ob




# GUI STUFF -----#################################################-----------------
from Blender.BGL import *

EVENT_NONE = 1
EVENT_START = 2
EVENT_REDRAW = 3
EVENT_LOAD_INI = 4
EVENT_SAVE_INI = 5
EVENT_PRESET = 6
EVENT_CHOOSE_INI = 7
EVENT_CHOOSE_DXF = 8
EVENT_HELP = 9
EVENT_CONFIG = 10
EVENT_PRESETS = 11
EVENT_DXF_DIR = 12
EVENT_PRESET2D = 20
EVENT_EXIT = 100
GUI_EVENT = EVENT_NONE

GUI_A = {}  # GUI-buttons dictionary for parameter
GUI_B = {}  # GUI-buttons dictionary for drawingTypes

# settings default, initialize ------------------------

points_as_menu  = "convert to: %t|empty %x1|mesh.vertex %x2|thin sphere %x3|thin box %x4"
lines_as_menu   = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|*thin box %x4"
mlines_as_menu  = "convert to: %t|*edge %x1|*mesh %x2|*thin cylinder %x3|*thin box %x4"
plines_as_menu  = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|*thin box %x4"
plines3_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|*thin box %x4"
plmesh_as_menu  = "convert to: %t|mesh %x1"
solids_as_menu  = "convert to: %t|mesh %x1"
blocks_as_menu  = "convert to: %t|dupl.group %x1|*real.group %x2|*exploded %x3"
texts_as_menu   = "convert to: %t|text %x1|*mesh %x2"
material_from_menu= "material from: %t|COLOR %x1|LAYER %x2|*LAYER+COLOR %x3|*BLOCK %x4|*XDATA %x5|*INI-File %x6"
g_scale_list	= "scale factor: %t|x 1000 %x3|x 100 %x2|x 10 %x1|x 1 %x0|x 0.1 %x-1|x 0.01 %x-2|x 0.001 %x-3|x 0.0001 %x-4|x 0.00001 %x-5"

dxfFileName = Draw.Create("")
iniFileName = Draw.Create(INIFILE_DEFAULT_NAME + INIFILE_EXTENSION)
user_preset = 0
config_UI = Draw.Create(0)   #switch_on/off extended config_UI

keywords_org = {
	'curves_on' : 0,
	'optimization': 2,
	'one_mesh_on': 1,
	'vGroup_on' : 1,
	'dummy_on' : 0,
	'newScene_on' : 1,
	'target_layer' : TARGET_LAYER,
	'group_bylayer_on' : GROUP_BYLAYER,
	'g_scale'   : float(G_SCALE),
	'g_scale_as': int(log10(G_SCALE)), #   0,
	'g_scale_on': 1,
	'thick_on'  : 1,
	'thick_min' : float(MIN_THICK),
	'thick_force': 0,
	'width_on'  : 1,
	'width_min' : float(MIN_WIDTH),
	'width_force': 0,
	'dist_on'   : 1,
	'dist_min'  : float(MIN_DIST),
	'dist_force': 0,
	'material_on': 1,
	'material_from': 2,
	'pl_3d'  : 1,
	'fill_on'	: 1,
	'arc_res'   : ARC_RESOLUTION,
	'arc_rad'   : ARC_RADIUS,
	'thin_res'  : THIN_RESOLUTION,
	'angle_cut' : ANGLECUT_LIMIT,
	'pl_section_on': 1,
	'points_as' : 2,
	'lines_as'  : 2,
	'mlines_as' : 2,
	'plines_as' : 2,
	'plines3_as': 2,
	'plmesh_as' : 1,
	'solids_as' : 1,
	'blocks_as' : 1,
	'texts_as'  : 1
	}

drawTypes_org = {
	'point' : 1,
	'line'  : 1,
	'arc'   : 1,
	'circle': 1,
	'ellipse': 0,
	'mline' : 0,
	'polyline': 1,
	'plmesh': 1,
	'pline3': 1,
	'lwpolyline': 1,
	'text'  : 1,
	'mtext' : 0,
	'block' : 1,
	'insert': 1,
	'face'  : 1,
	'solid' : 1,
	'trace' : 1
	}

# creating of GUI-buttons
# GUI_A - GUI-buttons dictionary for parameter
# GUI_B - GUI-buttons dictionary for drawingTypes
for k, v in keywords_org.iteritems():
	GUI_A[k] = Draw.Create(v)
for k, v in drawTypes_org.iteritems():
	GUI_B[k] = Draw.Create(v)
#print 'deb:init GUI_A: ', GUI_A #---------------
#print 'deb:init GUI_B: ', GUI_B #---------------
# initialize settings-object controls how dxf entities are drawn
settings = Settings(keywords_org, drawTypes_org)



def saveConfig():  #remi--todo-----------------------------------------------
	"""Save settings/config/materials from GUI to INI-file.

	Write all config data to INI-file.
	"""
	global iniFileName

	iniFile = iniFileName.val
	#print 'deb:saveConfig inifFile: ', inifFile #----------------------
	if iniFile.lower().endswith(INIFILE_EXTENSION):
		output = '[%s,%s]' %(GUI_A, GUI_B)
		if output =='None':
			Draw.PupMenu('DXF importer: INI-file:  Alert!%t|no config-data present to save!')
		else:
			#if BPyMessages.Warning_SaveOver(iniFile): #<- remi find it too abstarct
			if sys.exists(iniFile):
				f = file(iniFile, 'r'); header_str = f.readline(); f.close()
				if header_str.startswith(INIFILE_HEADER[0:12]):
					if Draw.PupMenu('  OK ? %t|SAVE OVER: ' + '\'%s\'' %iniFile) == 1:
						save_ok = True
				elif Draw.PupMenu('  OK ? %t|SAVE OVER: ' + '\'%s\'' %iniFile +
					 '|Alert: this file has no valid ImportDXF-format| ! it may belong to another aplication !') == 1:
					save_ok = True
				else: save_ok = False
			else: save_ok = True

			if save_ok:
				try:
					f = file(iniFile, 'w')
					f.write(INIFILE_HEADER + '\n')
					f.write(output)
					f.close()
					Draw.PupMenu('DXF importer: INI-file: Done!%t|config-data saved in ' + '\'%s\'' %iniFile)
				except:
					Draw.PupMenu('DXF importer: INI-file: Error!%t|failure by writing to ' + '\'%s\'|no config-data saved!' %iniFile)

	else:
		Draw.PupMenu('DXF importer: INI-file:  Alert!%t|no valid name/extension for INI-file selected!')
		print "DXF importer: Alert!: no valid INI-file selected."
		if not iniFile:
			if dxfFileName.val.lower().endswith('.dxf'):
				iniFileName.val = dxfFileName.val[0:-4] + INIFILE_EXTENSION


def loadConfig():  #remi--todo-----------------------------------------------
	"""Load settings/config/materials from INI-file.

	Read material-assignements from config-file.
	"""
	#070724 buggy Window.FileSelector(loadConfigFile, 'Load config data from INI-file', inifilename)
	global iniFileName, GUI_A, GUI_B

	iniFile = iniFileName.val
	#print 'deb:loadConfig iniFile: ', iniFile #----------------------
	if iniFile.lower().endswith(INIFILE_EXTENSION) and sys.exists(iniFile):
		f = file(iniFile, 'r')
		header_str = f.readline()
		if not header_str.startswith(INIFILE_HEADER):
			f.close()
			Draw.PupMenu('DXF importer: INI-file:  Alert!%t|no valid header in INI-file: ' + '\'%s\'' %iniFile)
		else:
			data_str = f.read()
			f.close()
			#print 'deb:loadConfig data_str from %s: \n' %iniFile , data_str #--------------------------
			data = eval(data_str)
			for k, v in data[0].iteritems():
				try:
					GUI_A[k].val = v
				except:
					GUI_A[k] = Draw.Create(v)
			for k, v in data[1].iteritems():
				try:
					GUI_B[k].val = v
				except:
					GUI_B[k] = Draw.Create(v)
	else:
		Draw.PupMenu('DXF importer: INI-file:  Alert!%t|no valid INI-file selected!')
		print "DXF importer: Alert!: no valid INI-file selected."
		if not iniFileName:
			if dxfFileName.val.lower().endswith('.dxf'):
				iniFileName.val = dxfFileName.val[0:-4] + INIFILE_EXTENSION



def resetDefaultConfig():  #-----------------------------------------------
	"""Resets settings/config/materials to defaults.

	"""
	global GUI_A, GUI_B
	#print 'deb:lresetDefaultConfig keywords_org: \n', keywords_org #---------
	for k, v in keywords_org.iteritems():
		GUI_A[k].val = v
	for k, v in drawTypes_org.iteritems():
		GUI_B[k].val = v


def resetDefaultConfig_2D():  #-----------------------------------------------
	"""Sets settings/config/materials to defaults 2D.

	"""
	resetDefaultConfig()
	global GUI_A, GUI_B
	keywords2d = {
		'curves_on' : 0,
		'one_mesh_on': 1,
		'vGroup_on' : 1,
		'thick_on'  : 0,
		'thick_force': 0,
		'width_on'  : 1,
		'width_force': 0,
		'dist_on'   : 1,
		'dist_force': 0,
		'pl_3d'  : 0,
		'fill_on'	: 0,
		'pl_section_on': 1,
		'points_as' : 2,
		'lines_as'  : 2,
		'mlines_as' : 2,
		'plines_as' : 2,
		'solids_as' : 1,
		'blocks_as' : 1,
		'texts_as'  : 1
		}

	drawTypes2d = {
		'point' : 1,
		'line'  : 1,
		'arc'   : 1,
		'circle': 1,
		'ellipse': 0,
		'mline' : 0,
		'polyline': 1,
		'plmesh': 0,
		'pline3': 0,
		'lwpolyline': 1,
		'text'  : 1,
		'mtext' : 0,
		'block' : 1,
		'insert': 1,
		'face'  : 0,
		'solid' : 1,
		'trace' : 1
		}

	for k, v in keywords2d.iteritems():
		GUI_A[k].val = v
	for k, v in drawTypes2d.iteritems():
		GUI_B[k].val = v



def draw_UI():  #-----------------------------------------------------------------
	""" Draw startUI and setup Settings.
	"""
	global GUI_A, GUI_B #__version__
	global user_preset, iniFileName, dxfFileName, config_UI

	# This is for easy layout changes
	but_0c = 70  #button 1.column width
	but_1c = 70  #button 1.column width
	but_2c = 70  #button 2.column
	but_3c = 70  #button 3.column
	menu_margin = 10
	butt_margin = 10
	menu_w = (3 * butt_margin) + but_0c + but_1c + but_2c + but_3c  #menu width

	simple_menu_h = 110
	extend_menu_h = 380
	y = simple_menu_h		 # y is menu upper.y
	if config_UI.val: y += extend_menu_h
	x = 20 #menu left.x
	but0c = x + menu_margin  #buttons 0.column position.x
	but1c = but0c + but_0c + butt_margin
	but2c = but1c + but_1c + butt_margin
	but3c = but2c + but_2c + butt_margin

	# Here starts menu -----------------------------------------------------
	#glClear(GL_COLOR_BUFFER_BIT)
	#glRasterPos2d(8, 125)

	colorbox(x, y+20, x+menu_w+menu_margin*2, menu_margin)
	Draw.Label("DXF Importer  ver." + __version__, but0c, y, menu_w, 20)

	if config_UI.val:
		y -= 30
		Draw.BeginAlign()
		GUI_B['point'] = Draw.Toggle('POINT', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['point'].val, "support dxf-POINT on/off")
		Draw.Label('-->', but2c, y, but_2c, 20)
		GUI_A['points_as'] = Draw.Menu(points_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['points_as'].val, "select target Blender-object")
		Draw.EndAlign()

		y -= 20
		Draw.BeginAlign()
		GUI_B['line'] = Draw.Toggle('LINE.ARC.CIRCLE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['line'].val, "support dxf-LINE,ARC,CIRCLE,ELLIPSE on/off")
		Draw.Label('-->', but2c, y, but_2c, 20)
		GUI_A['lines_as'] = Draw.Menu(lines_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['lines_as'].val, "select target Blender-object")
		Draw.EndAlign()

		y -= 20
		Draw.BeginAlign()
		GUI_B['mline'] = Draw.Toggle('*MLINE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['mline'].val, "(*wip)support dxf-MLINE on/off")
		Draw.Label('-->', but2c, y, but_2c, 20)
		GUI_A['mlines_as'] = Draw.Menu(mlines_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['mlines_as'].val, "select target Blender-object")
		Draw.EndAlign()

		y -= 20
		Draw.BeginAlign()
		GUI_B['polyline'] = Draw.Toggle('2D-POLYLINE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['polyline'].val, "support dxf-2D-POLYLINE on/off")
		Draw.Label('-->', but2c, y, but_2c, 20)
		GUI_A['plines_as'] = Draw.Menu(plines_as_menu,   EVENT_NONE, but3c, y, but_3c, 20, GUI_A['plines_as'].val, "select target Blender-object")
		Draw.EndAlign()

		y -= 20
		Draw.BeginAlign()
		GUI_B['pline3'] = Draw.Toggle('3D-POLYLINE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['pline3'].val, "support dxf-3D-POLYLINE on/off")
		Draw.Label('-->', but2c, y, but_2c, 20)
		GUI_A['plines3_as'] = Draw.Menu(plines3_as_menu,   EVENT_NONE, but3c, y, but_3c, 20, GUI_A['plines3_as'].val, "select target Blender-object")
		Draw.EndAlign()

		y -= 20
		Draw.BeginAlign()
		GUI_B['plmesh'] = Draw.Toggle('POLYMESH/-FACE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['plmesh'].val, "support dxf-POLYMESH/POLYFACE on/off")
		Draw.Label('-->', but2c, y, but_2c, 20)
		GUI_A['plmesh_as'] = Draw.Menu(plmesh_as_menu,   EVENT_NONE, but3c, y, but_3c, 20, GUI_A['plmesh_as'].val, "select target Blender-object")
		Draw.EndAlign()

		y -= 20
		Draw.BeginAlign()
		GUI_B['solid'] = Draw.Toggle('3DFACE.SOLID.TRACE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['solid'].val, "support dxf-3DFACE, SOLID and TRACE on/off")
		Draw.Label('-->', but2c, y, but_2c, 20)
		GUI_A['solids_as'] = Draw.Menu(solids_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['solids_as'].val, "select target Blender-object")
		Draw.EndAlign()

		y -= 20
		Draw.BeginAlign()
		GUI_B['text'] = Draw.Toggle('TEXT', EVENT_NONE, but0c, y, but_0c, 20, GUI_B['text'].val, "support dxf-TEXT on/off")
		GUI_B['mtext'] = Draw.Toggle('*MTEXT', EVENT_NONE, but1c, y, but_1c-butt_margin, 20, GUI_B['mtext'].val, "(*wip)support dxf-MTEXT on/off")
		Draw.Label('-->', but2c, y, but_2c, 20)
		GUI_A['texts_as'] = Draw.Menu(texts_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['texts_as'].val, "select target Blender-object")
		Draw.EndAlign()

		y -= 20
		Draw.BeginAlign()
		GUI_B['block'] = Draw.Toggle('BLOCK / ARRAY', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['block'].val, "support dxf-BLOCK and ARRAY on/off")
		Draw.Label('-->', but2c, y, but_2c, 20)
		GUI_A['blocks_as'] = Draw.Menu(blocks_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['blocks_as'].val, "select target Blender-object")
		Draw.EndAlign()


		y -= 20
		Draw.BeginAlign()
		GUI_A['material_from'] = Draw.Menu(material_from_menu,   EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_A['material_from'].val, "material assignment from?")
		Draw.Label('-->', but2c, y, but_2c, 20)
		GUI_A['material_on'] = Draw.Toggle('material', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['material_on'].val, "support for material assignment on/off")
		Draw.EndAlign()


		y -= 30
		GUI_A['group_bylayer_on'] = Draw.Toggle('oneGroup', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['group_bylayer_on'].val, "grouping entities from the same layer on/off")
		GUI_A['curves_on'] = Draw.Toggle('to Curves', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['curves_on'].val, "drawing LINE/ARC/POLYLINE into Blender-Curves instead of Meshes on/off")
		Draw.BeginAlign()
		GUI_A['g_scale_on'] = Draw.Toggle('glob.Scale', EVENT_NONE, but2c, y, but_2c, 20, GUI_A['g_scale_on'].val, "scaling all DXF objects on/off")
		GUI_A['g_scale_as'] = Draw.Menu(g_scale_list, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['g_scale_as'].val, "10^ factor for scaling the DXFdata")
		Draw.EndAlign()


		y -= 20
		#Draw.Label('', but1c+but_1c/2, y, but_1c/2, 20)
		GUI_A['one_mesh_on'] = Draw.Toggle('oneMesh', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['one_mesh_on'].val, "drawing DXF-entities into one mesh-object. Recommended for big DXF-files. on/off")
		GUI_A['vGroup_on'] = Draw.Toggle('vGroups', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['vGroup_on'].val, "support Blender-VertexGroups on/off")
		Draw.BeginAlign()
		GUI_A['dist_on'] = Draw.Toggle('dist.:', EVENT_NONE, but2c, y, but_2c-20, 20, GUI_A['dist_on'].val, "support distance on/off")
		GUI_A['dist_force'] = Draw.Toggle('F', EVENT_NONE, but2c+but_2c-20, y,  20, 20, GUI_A['dist_force'].val, "force minimal distance on/off")
		GUI_A['dist_min'] = Draw.Number('', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['dist_min'].val, 0, 10, "minimal lenght/distance (double.vertex removing)")
		Draw.EndAlign()

		y -= 20
		Draw.BeginAlign()
		GUI_A['pl_section_on'] = Draw.Toggle('int.section', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['pl_section_on'].val, "support POLYLINE-wide-segment-intersection on/off")
		GUI_A['angle_cut'] = Draw.Number('', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['angle_cut'].val, 1, 5, "it limits POLYLINE-wide-segment-intersection: 1.0-5.0")
		Draw.EndAlign()
		Draw.BeginAlign()
		GUI_A['thick_on'] = Draw.Toggle('thick:', EVENT_NONE, but2c, y, but_2c-20, 20, GUI_A['thick_on'].val, "support thickness on/off")
		GUI_A['thick_force'] = Draw.Toggle('F', EVENT_NONE, but2c+but_2c-20, y,  20, 20, GUI_A['thick_force'].val, "force minimal thickness on/off")
		GUI_A['thick_min'] = Draw.Number('', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['thick_min'].val, 0, 10, "minimal thickness")
		Draw.EndAlign()


		y -= 20
		Draw.BeginAlign()
#	   GUI_A['thin_res'] = Draw.Number('thin:', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['thin_res'].val, 4, 500, "thin cylinder resolution - number of segments")
		GUI_A['arc_rad'] = Draw.Number('radi:', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['arc_rad'].val, 0.01, 100, "basis radius for arc/circle resolution")
		GUI_A['arc_res'] = Draw.Number('res:', EVENT_NONE, but1c, y, but_1c-25, 20, GUI_A['arc_res'].val, 4, 500, "arc/circle resolution - number of segments")
		GUI_A['fill_on'] = Draw.Toggle('cap', EVENT_NONE, but1c+but_1c-25, y,  25, 20, GUI_A['fill_on'].val, "draws top and bottom caps of CYLINDERs on/off")
		Draw.EndAlign()
		Draw.BeginAlign()
		GUI_A['width_on'] = Draw.Toggle('width:', EVENT_NONE, but2c, y, but_2c-20, 20, GUI_A['width_on'].val, "support width on/off")
		GUI_A['width_force'] = Draw.Toggle('F', EVENT_NONE, but2c+but_2c-20, y, 20, 20, GUI_A['width_force'].val, "force minimal width on/off")
		GUI_A['width_min'] = Draw.Number('', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['width_min'].val, 0, 10, "minimal width")
		Draw.EndAlign()

		y -= 30
		#GUI_A['dummy_on'] = Draw.Toggle(' - ', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['dummy_on'].val, "reserved")
		GUI_A['newScene_on'] = Draw.Toggle('newScene', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['newScene_on'].val, "creates new Blender-Scene for each import on/off")
		GUI_A['target_layer'] = Draw.Number('layer', EVENT_NONE, but2c, y, but_2c, 20, GUI_A['target_layer'].val, 1, 18, "imports into this Blender-layer (<19> reserved for block_definitions)")
		GUI_A['optimization'] = Draw.Number('optim:', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['optimization'].val, 0, 3, "Optimization Level: 0=Debug/directDrawing, 1=Verbose, 2=ProgressBar, 3=silentMode/fastest")

		y -= 30
		Draw.BeginAlign()
		Draw.PushButton('INI file >', EVENT_CHOOSE_INI, but0c, y, but_0c, 20, 'Select INI-file from project directory')
		iniFileName = Draw.String(' :', EVENT_NONE, but1c, y, menu_w-but_0c-butt_margin, 20, iniFileName.val, FILENAME_MAX, "write here the name of the INI-file")
		Draw.EndAlign()

		y -= 20
		Draw.BeginAlign()
		Draw.PushButton('Presets', EVENT_PRESETS, but0c, y, but_0c, 20, "tipist for Preset-INI-files")
		Draw.PushButton('Load', EVENT_LOAD_INI, but1c, y, but_1c, 20, '	 Loads configuration from ini-file: %s' % iniFileName.val)
		Draw.PushButton('Save', EVENT_SAVE_INI, but2c, y, but_2c, 20, 'Saves configuration to ini-file: %s' % iniFileName.val)
#	   user_preset = Draw.Number('preset:', EVENT_PRESETS, but2c, y, but_2c, 20, user_preset.val, 0, 5, "call user Preset-INI-files")
		Draw.PushButton('2D', EVENT_PRESET2D, but3c, y, but_3c/2, 20, 'resets configuration to 2D-defaults')
		Draw.PushButton('3D', EVENT_PRESET, but3c+but_3c/2, y, but_3c/2, 20, 'resets configuration to 3D-defaults')
		Draw.EndAlign()


	y -= 30
	Draw.BeginAlign()
	Draw.PushButton('DXFfile >', EVENT_CHOOSE_DXF, but0c, y, but_0c, 20, 'Select DXF-file from project directory')
	dxfFileName = Draw.String(' :', EVENT_NONE, but1c, y, but_1c+but_2c+but_3c-20, 20, dxfFileName.val, FILENAME_MAX, "type the name of DXF-file or * for multi-import")
	Draw.PushButton('*.*', EVENT_DXF_DIR, but3c+but_3c-20, y, 20, 20, 'Set asterisk * as filter')
	Draw.EndAlign()


	y -= 50
	Draw.BeginAlign()
	Draw.PushButton('EXIT', EVENT_EXIT, but0c, y, but_0c, 40, '' )
	Draw.PushButton('HELP', EVENT_HELP, but1c, y, but_1c, 20, 'calls BlenderWiki for Manual, Updates and Support.')
	Draw.PushButton('START IMPORT', EVENT_START, but2c, y, but_2c+but_3c+butt_margin, 40, 'Start the import procedure')
	Draw.EndAlign()

	config_UI = Draw.Toggle('CONFIG', EVENT_CONFIG, but1c-butt_margin/2, y+20, but_1c+butt_margin, 20, config_UI.val, 'Advanced configuration on/off' )

	y -= 20
	Draw.BeginAlign()
	Draw.Label(' ', but0c-menu_margin, y, menu_margin, 20)
	Draw.Label("*) parts under construction", but0c, y, menu_w, 20)
	Draw.Label(' ', but0c+menu_w, y, menu_margin, 20)
	Draw.EndAlign()

#-- END GUI Stuf-----------------------------------------------------

def colorbox(x,y,xright,bottom):
   glColor3f(0.75, 0.75, 0.75)
   glRecti(x + 1, y + 1, xright - 1, bottom - 1)

def dxf_callback(input_filename):
	global dxfFileName
	dxfFileName.val=input_filename
	
def ini_callback(input_texture):
	global iniFileName
	iniFileName.val=input_texture

def event(evt, val):
	if evt in (Draw.QKEY, Draw.ESCKEY) and not val:
		Blender.Draw.Exit()

def bevent(evt):
#   global EVENT_NONE,EVENT_LOAD_DXF,EVENT_LOAD_INI,EVENT_SAVE_INI,EVENT_EXIT
	global config_UI, user_preset

	######### Manages GUI events
	if (evt==EVENT_EXIT):
		Blender.Draw.Exit()
	elif (evt==EVENT_CHOOSE_INI):
		Window.FileSelector(ini_callback, "INI-file Selection", '*.ini')
	elif (evt==EVENT_CONFIG):
		Draw.Redraw()
	elif (evt==EVENT_PRESET):
		resetDefaultConfig()
		Draw.Redraw()
	elif (evt==EVENT_PRESET2D):
		resetDefaultConfig_2D()
		Draw.Redraw()
	elif (evt==EVENT_PRESETS):
		user_preset += 1
		if user_preset > 5: user_preset = 1
		iniFileName.val = INIFILE_DEFAULT_NAME + str(user_preset) + INIFILE_EXTENSION
		Draw.Redraw()
	elif (evt==EVENT_HELP):
		try:
			import webbrowser
			webbrowser.open('http://wiki.blender.org/index.php?title=Scripts/Manual/Import/DXF-3D')
		except:
			Draw.PupMenu('DXF importer: HELP Alert!%t|no connection to manual-page on Blender-Wiki!	try:|\
http://wiki.blender.org/index.php?title=Scripts/Manual/Import/DXF-3D')
		Draw.Redraw()
	elif (evt==EVENT_LOAD_INI):
		loadConfig()
		Draw.Redraw()
	elif (evt==EVENT_SAVE_INI):
		saveConfig()
		Draw.Redraw()
	elif (evt==EVENT_DXF_DIR):
		dxfFile = dxfFileName.val
		dxfPathName = ''
		if '/' in dxfFile:
			dxfPathName = '/'.join(dxfFile.split('/')[:-1]) + '/'
		elif '\\' in dxfFile:
			dxfPathName = '\\'.join(dxfFile.split('\\')[:-1]) + '\\'
		dxfFileName.val = dxfPathName + '*.dxf'
		global GUI_A
		GUI_A['newScene_on'].val = 1
		Draw.Redraw()
	elif (evt==EVENT_CHOOSE_DXF):
		Window.FileSelector(dxf_callback, "DXF-file Selection", '*.dxf')
	elif (evt==EVENT_START):
		dxfFile = dxfFileName.val
		#print 'deb: dxfFile file: ', dxfFile #----------------------
		if dxfFile.lower().endswith('*.dxf'):
			if Draw.PupMenu('DXF importer:  OK?|will import all DXF-files from:|%s' % dxfFile) == 1:
				global UI_MODE
				UI_MODE = False
				multi_import(dxfFile[:-5])  # cut last char:'*.dxf'
				Draw.Exit()
			else:
				Draw.Redraw()
		elif dxfFile.lower().endswith('.dxf') and sys.exists(dxfFile):
			if GUI_A['newScene_on'].val:
				_dxf_file = dxfFile.split('/')[-1].split('\\')[-1]
				_dxf_file = _dxf_file[:-4]  # cut last char:'.dxf'
				_dxf_file = _dxf_file[:MAX_NAMELENGTH]  #? [-MAX_NAMELENGTH:])
				global SCENE
				SCENE = Blender.Scene.New(_dxf_file)
				SCENE.makeCurrent()
				#or so? Blender.Scene.makeCurrent(_dxf_file)
				#sce = bpy.data.scenes.new(_dxf_file)
				#bpy.data.scenes.active = sce
			else:
				SCENE = Blender.Scene.GetCurrent()
				SCENE.objects.selected = [] # deselect all
			main(dxfFile)
			#SCENE.objects.selected = SCENE.objects		 
			#Window.RedrawAll()
			#Blender.Redraw()
			#Draw.Redraw()
		else:
			Draw.PupMenu('DXF importer:  Alert!%t|no valid DXF-file selected!')
			print "DXF importer: error, no valid DXF-file selected! try again"
			Draw.Redraw()




def multi_import(DIR):
	"""Imports all DXF-files from directory DIR.
	
	"""
	global SCENE
	batchTIME = Blender.sys.time()
	#if #DIR == "": DIR = os.path.curdir
	if DIR == "": DIR = Blender.sys.dirname(Blender.Get('filename'))
	print 'Searching for DXF-files in %s' %DIR
	files = \
		[sys.join(DIR, f) for f in os.listdir(DIR) if f.lower().endswith('.dxf')] 
	if not files:
		print '...None DXF-files found. Abort!'
		return
	
	i = 0
	for dxfFile in files:
		i += 1
		print 'Importing', dxfFile, '  NUMBER', i, 'of', len(files)
		if GUI_A['newScene_on'].val:
			_dxf_file = dxfFile.split('/')[-1].split('\\')[-1]
			_dxf_file = _dxf_file[:-4]  # cut last char:'.dxf'
			_dxf_file = _dxf_file[:MAX_NAMELENGTH]  #? [-MAX_NAMELENGTH:])
			SCENE = Blender.Scene.New(_dxf_file)
			SCENE.makeCurrent()
			#or so? Blender.Scene.makeCurrent(_dxf_file)
			#sce = bpy.data.scenes.new(_dxf_file)
			#bpy.data.scenes.active = sce
		else:
			SCENE = Blender.Scene.GetCurrent()
			SCENE.objects.selected = [] # deselect all
		main(dxfFile)
		#Blender.Redraw()

	print 'TOTAL TIME: %.6f' % (Blender.sys.time() - batchTIME)




if __name__ == "__main__":
	UI_MODE = True
	Draw.Register(draw_UI, event, bevent)


"""
if 1:
	# DEBUG ONLY
	UI_MODE = False
	TIME= Blender.sys.time()
	#DIR = '/dxf_r12_testfiles/'
	DIR = '/metavr/'
	import os
	print 'Searching for files'
	os.system('find %s -iname "*.dxf" > /tmp/tempdxf_list' % DIR)
	# os.system('find /storage/ -iname "*.dxf" > /tmp/tempdxf_list')
	print '...Done'
	file= open('/tmp/tempdxf_list', 'r')
	lines= file.readlines()
	file.close()
	# sort by filesize for faster testing
	lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines]
	lines_size.sort()
	lines = [f[1] for f in lines_size]

	for i, _dxf in enumerate(lines):
		if i >= 70:
			#if 1:
			print 'Importing', _dxf, '\nNUMBER', i, 'of', len(lines)
			if True:
				_dxf_file= _dxf.split('/')[-1].split('\\')[-1]
				_dxf_file = _dxf_file[:-4]  # cut last char:'.dxf'
				_dxf_file = _dxf_file[:MAX_NAMELENGTH]  #? [-MAX_NAMELENGTH:])
				sce = bpy.data.scenes.new(_dxf_file)
				bpy.data.scenes.active = sce
			dxfFileName.val = _dxf
			main(_dxf)

	print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME)
"""