Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'release/scripts/bpymodules')
-rw-r--r--release/scripts/bpymodules/BPyAddMesh.py27
-rw-r--r--release/scripts/bpymodules/BPyArmature.py75
-rw-r--r--release/scripts/bpymodules/BPyRegistry.py41
-rw-r--r--release/scripts/bpymodules/BPyRender.py141
-rw-r--r--release/scripts/bpymodules/BPyTextPlugin.py814
-rw-r--r--release/scripts/bpymodules/blend2renderinfo.py95
-rw-r--r--release/scripts/bpymodules/dxfImportObjects.py1326
-rw-r--r--release/scripts/bpymodules/dxfLibrary.py708
-rw-r--r--release/scripts/bpymodules/dxfReader.py619
-rw-r--r--release/scripts/bpymodules/paths_ai2obj.py10
-rw-r--r--release/scripts/bpymodules/paths_gimp2obj.py4
-rw-r--r--release/scripts/bpymodules/paths_svg2obj.py5
12 files changed, 2165 insertions, 1700 deletions
diff --git a/release/scripts/bpymodules/BPyAddMesh.py b/release/scripts/bpymodules/BPyAddMesh.py
index 6ffb394320a..901e68866cc 100644
--- a/release/scripts/bpymodules/BPyAddMesh.py
+++ b/release/scripts/bpymodules/BPyAddMesh.py
@@ -16,13 +16,17 @@ def add_mesh_simple(name, verts, edges, faces):
scn = bpy.data.scenes.active
if scn.lib: return
ob_act = scn.objects.active
-
+
+ is_editmode = EditMode()
+
cursor = GetCursorPos()
- try: quat = Blender.Mathutils.Quaternion(GetViewQuat())
- except: quat = None
+ quat = None
+ if is_editmode or Blender.Get('add_view_align'): # Aligning seems odd for editmode, but blender does it, oh well
+ try: quat = Blender.Mathutils.Quaternion(GetViewQuat())
+ except: pass
# Exist editmode for non mesh types
- if ob_act and ob_act.type != 'Mesh' and EditMode():
+ if ob_act and ob_act.type != 'Mesh' and is_editmode:
EditMode(0)
# We are in mesh editmode
@@ -64,10 +68,7 @@ def add_mesh_simple(name, verts, edges, faces):
else:
# Mesh with no data, unlikely
me.edges.extend(edges)
- me.faces.extend(faces)
-
- EditMode(1)
-
+ me.faces.extend(faces)
else:
# Object mode add new
@@ -90,8 +91,14 @@ def add_mesh_simple(name, verts, edges, faces):
ob_act.setMatrix(mat)
ob_act.loc = cursor
-
+
+ me.calcNormals()
+
+ if is_editmode or Blender.Get('add_editmode'):
EditMode(1)
+
+
+
def write_mesh_script(filepath, me):
@@ -106,7 +113,7 @@ def write_mesh_script(filepath, me):
file.write('#!BPY\n')
file.write('"""\n')
file.write('Name: \'%s\'\n' % name)
- file.write('Blender: 243\n')
+ file.write('Blender: 245\n')
file.write('Group: \'AddMesh\'\n')
file.write('"""\n\n')
file.write('import BPyAddMesh\n')
diff --git a/release/scripts/bpymodules/BPyArmature.py b/release/scripts/bpymodules/BPyArmature.py
index d0b41dc35c5..63df02d080c 100644
--- a/release/scripts/bpymodules/BPyArmature.py
+++ b/release/scripts/bpymodules/BPyArmature.py
@@ -11,13 +11,19 @@
# 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
+# Version History:
+# 1.0 original release bakes an armature into a matrix
+# 1.1 optional params (ACTION_BAKE, ACTION_BAKE_FIRST_FRAME, direct function to key and return the Action
import Blender
+from Blender import sys
import bpy
-def getBakedPoseData(ob_arm, start_frame, end_frame):
+def getBakedPoseData(ob_arm, start_frame, end_frame, ACTION_BAKE = False, ACTION_BAKE_FIRST_FRAME = True):
'''
If you are currently getting IPO's this function can be used to
- return a list of frame aligned bone dictionary's
+ ACTION_BAKE==False: return a list of frame aligned bone dictionary's
+ ACTION_BAKE==True: return an action with keys aligned to bone constrained movement
+ if ACTION_BAKE_FIRST_FRAME is not supplied or is true: keys begin at frame 1
The data in these can be swaped in for the IPO loc and quat
@@ -77,7 +83,13 @@ def getBakedPoseData(ob_arm, start_frame, end_frame):
# --------------------------------- Main loop to collect IPO data
frame_index = 0
+ NvideoFrames= end_frame-start_frame
for current_frame in xrange(start_frame, end_frame+1):
+ if frame_index==0: start=sys.time()
+ elif frame_index==15: print NvideoFrames*(sys.time()-start),"seconds estimated..." #slows as it grows *3
+ elif frame_index >15:
+ percom= frame_index*100/NvideoFrames
+ print "Frame %i Overall %i percent complete\r" % (current_frame, percom),
ob_arm.action = backup_action
#pose.update() # not needed
Blender.Set('curframe', current_frame)
@@ -88,9 +100,7 @@ def getBakedPoseData(ob_arm, start_frame, end_frame):
for index, parent_index, bone_name, rest_bone, rest_matrix, rest_matrix_inv, pose_bone, ipo in armature_bone_data:
matrix= pose_bone.poseMatrix
-
parent_bone= rest_bone.parent
-
if parent_index != -1:
parent_pose_matrix = armature_bone_data[parent_index][6].poseMatrix
parent_bone_matrix_inv = armature_bone_data[parent_index][5]
@@ -98,40 +108,45 @@ def getBakedPoseData(ob_arm, start_frame, end_frame):
rest_matrix= rest_matrix * parent_bone_matrix_inv
matrix=matrix * rest_matrix.copy().invert()
-
pose_bone.quat= matrix.toQuat()
pose_bone.loc= matrix.translationPart()
- pose_bone.insertKey(ob_arm, 1, POSE_XFORM) # always frame 1
-
- # THIS IS A BAD HACK! IT SUCKS BIGTIME BUT THE RESULT ARE NICE
- # - use a temp action and bake into that, always at the same frame
- # so as not to make big IPO's, then collect the result from the IPOs
+ if ACTION_BAKE==False:
+ pose_bone.insertKey(ob_arm, 1, POSE_XFORM) # always frame 1
+
+ # THIS IS A BAD HACK! IT SUCKS BIGTIME BUT THE RESULT ARE NICE
+ # - use a temp action and bake into that, always at the same frame
+ # so as not to make big IPO's, then collect the result from the IPOs
- # Now get the data from the IPOs
- if not ipo: ipo = armature_bone_data[index][7] = new_action.getChannelIpo(bone_name)
+ # Now get the data from the IPOs
+ if not ipo: ipo = armature_bone_data[index][7] = new_action.getChannelIpo(bone_name)
- loc = Vector()
- quat = Quaternion()
+ loc = Vector()
+ quat = Quaternion()
- for curve in ipo:
- val = curve.evaluate(1)
- curve_name= curve.name
- if curve_name == 'LocX': loc[0] = val
- elif curve_name == 'LocY': loc[1] = val
- elif curve_name == 'LocZ': loc[2] = val
- elif curve_name == 'QuatW': quat[3] = val
- elif curve_name == 'QuatX': quat[0] = val
- elif curve_name == 'QuatY': quat[1] = val
- elif curve_name == 'QuatZ': quat[2] = val
+ for curve in ipo:
+ val = curve.evaluate(1)
+ curve_name= curve.name
+ if curve_name == 'LocX': loc[0] = val
+ elif curve_name == 'LocY': loc[1] = val
+ elif curve_name == 'LocZ': loc[2] = val
+ elif curve_name == 'QuatW': quat[3] = val
+ elif curve_name == 'QuatX': quat[0] = val
+ elif curve_name == 'QuatY': quat[1] = val
+ elif curve_name == 'QuatZ': quat[2] = val
- bake_data[frame_index][bone_name] = loc, quat
-
-
+ bake_data[frame_index][bone_name] = loc, quat
+ else:
+ if ACTION_BAKE_FIRST_FRAME: pose_bone.insertKey(ob_arm, frame_index+1, POSE_XFORM)
+ else: pose_bone.insertKey(ob_arm, current_frame , POSE_XFORM)
frame_index+=1
-
+ print "\nBaking Complete."
ob_arm.action = backup_action
- Blender.Set('curframe', backup_frame)
- return bake_data
+ if ACTION_BAKE==False:
+ Blender.Set('curframe', backup_frame)
+ return bake_data
+ elif ACTION_BAKE==True:
+ return new_action
+ else: print "ERROR: Invalid ACTION_BAKE %i sent to BPyArmature" % ACTION_BAKE
diff --git a/release/scripts/bpymodules/BPyRegistry.py b/release/scripts/bpymodules/BPyRegistry.py
index f0d6da82d52..4d681e15937 100644
--- a/release/scripts/bpymodules/BPyRegistry.py
+++ b/release/scripts/bpymodules/BPyRegistry.py
@@ -193,14 +193,17 @@ def LoadConfigData (key = None):
if bsys.exists(fname): files.append(fname)
for p in files:
- f = file(p, 'r')
- lines = f.readlines()
- f.close()
- if lines: # Lines may be blank
- mainkey = lines[0].split('=')[0].strip()
- pysrc = "\n".join(lines)
- exec(pysrc)
- exec("Registry.SetKey('%s', %s)" % (str(mainkey), mainkey))
+ try:
+ f = file(p, 'r')
+ lines = f.readlines()
+ f.close()
+ if lines: # Lines may be blank
+ mainkey = lines[0].split('=')[0].strip()
+ pysrc = "\n".join(lines)
+ exec(pysrc)
+ exec("Registry.SetKey('%s', %s)" % (str(mainkey), mainkey))
+ except Exception, e:
+ raise Warning(e) # Resend exception as warning
def RemoveConfigData (key = None):
@@ -223,8 +226,11 @@ def RemoveConfigData (key = None):
import os
- for p in files:
- os.remove(p) # remove the file(s)
+ try:
+ for p in files:
+ os.remove(p) # remove the file(s)
+ except Exception, e:
+ raise Warning(e) # Resend exception as warning
def SaveConfigData (key = None):
@@ -250,9 +256,12 @@ def SaveConfigData (key = None):
if not cfgdict: continue
- filename = bsys.join(_CFG_DIR, "%s%s" % (mainkey, _EXT))
- f = file(filename, 'w')
- output = _dict_to_str(mainkey, _sanitize(cfgdict))
- if output!='None':
- f.write(output)
- f.close()
+ try:
+ filename = bsys.join(_CFG_DIR, "%s%s" % (mainkey, _EXT))
+ f = file(filename, 'w')
+ output = _dict_to_str(mainkey, _sanitize(cfgdict))
+ if output!='None':
+ f.write(output)
+ f.close()
+ except Exception, e:
+ raise Warning(e) # Resend exception as warning
diff --git a/release/scripts/bpymodules/BPyRender.py b/release/scripts/bpymodules/BPyRender.py
index e335ee7f6a8..951e1ae6300 100644
--- a/release/scripts/bpymodules/BPyRender.py
+++ b/release/scripts/bpymodules/BPyRender.py
@@ -125,14 +125,14 @@ def imageFromObjectsOrtho(objects, path, width, height, smooth, alpha= True, cam
# camera is wider then image res.
# to make the image wider, reduce the aspy
asp_diff= asp_image_res/asp_cam_mat
- min_asp= int(round(asp_diff * 200))
+ min_asp= asp_diff * 200
#print 'X', min_asp
elif asp_cam_mat < asp_image_res: # asp_cam_mat < asp_image_res
# camera is narrower then image res
# to make the image narrower, reduce the aspx
asp_diff= asp_cam_mat/asp_image_res
- min_asp= int(round(asp_diff * 200))
+ min_asp= asp_diff * 200
#print 'Y', min_asp
else:
min_asp= 200
@@ -181,7 +181,6 @@ def imageFromObjectsOrtho(objects, path, width, height, smooth, alpha= True, cam
Blender.Window.RedrawAll()
- render_context.threads= 2 # good for dual core cpu's
render_context.render()
render_context.saveRenderedImage(path)
Render.CloseRenderWindow()
@@ -496,3 +495,139 @@ def vcol2image(me_s,\
mat.mode &= ~Blender.Material.Modes.SHADELESS
return image
+
+def bakeToPlane(sce, ob_from, width, height, bakemodes, axis='z', margin=0, depth=32):
+ '''
+ Bakes terrain onto a plane from one object
+ sce - scene to bake with
+ ob_from - mesh object
+ width/height - image size
+ bakemodes - list of baking modes to use, Blender.Scene.Render.BakeModes.NORMALS, Blender.Scene.Render.BakeModes.AO ... etc
+ axis - axis to allign the plane to.
+ margin - margin setting for baking.
+ depth - bit depth for the images to bake into, (32 or 128 for floating point images)
+ Example:
+ import Blender
+ from Blender import *
+ import BPyRender
+ sce = Scene.GetCurrent()
+ ob = Object.Get('Plane')
+ BPyRender.bakeToPlane(sce, ob, 512, 512, [Scene.Render.BakeModes.DISPLACEMENT, Scene.Render.BakeModes.NORMALS], 'z', 8 )
+ '''
+
+ # Backup bake settings
+ rend = sce.render
+ BACKUP_bakeDist = rend.bakeDist
+ BACKUP_bakeBias = rend.bakeBias
+ BACKUP_bakeMode = rend.bakeMode
+ BACKUP_bakeClear = rend.bakeClear
+ BACKUP_bakeMargin = rend.bakeMargin
+ BACKUP_bakeToActive = rend.bakeToActive
+ BACKUP_bakeNormalize = rend.bakeNormalize
+
+ # Backup object selection
+ BACKUP_obsel = list(sce.objects.selected)
+ BACKUP_obact = sce.objects.active
+
+ # New bake settings
+ rend.bakeClear = True
+ rend.bakeMargin = margin
+ rend.bakeToActive = True
+ rend.bakeNormalize = True
+
+ # Assume a mesh
+ me_from = ob_from.getData(mesh=1)
+
+ xmin = ymin = zmin = 10000000000
+ xmax = ymax = zmax =-10000000000
+
+ # Dont trust bounding boxes :/
+ #bounds = ob_from.boundingBox
+ #for v in bounds:
+ # x,y,z = tuple(v)
+ mtx = ob_from.matrixWorld
+ for v in me_from.verts:
+ x,y,z = tuple(v.co*mtx)
+
+ xmax = max(xmax, x)
+ ymax = max(ymax, y)
+ zmax = max(zmax, z)
+
+ xmin = min(xmin, x)
+ ymin = min(ymin, y)
+ zmin = min(zmin, z)
+
+ if axis=='x':
+ xmed = (xmin+xmax)/2.0
+ co1 = (xmed, ymin, zmin)
+ co2 = (xmed, ymin, zmax)
+ co3 = (xmed, ymax, zmax)
+ co4 = (xmed, ymax, zmin)
+ rend.bakeDist = ((xmax-xmin)/2.0) + 0.000001 # we need a euler value for this since it
+ elif axis=='y':
+ ymed = (ymin+ymax)/2.0
+ co1 = (xmin, ymed, zmin)
+ co2 = (xmin, ymed, zmax)
+ co3 = (xmax, ymed, zmax)
+ co4 = (xmax, ymed, zmin)
+ rend.bakeDist = ((ymax-ymin)/2.0) + 0.000001
+ elif axis=='z':
+ zmed = (zmin+zmax)/2.0
+ co1 = (xmin, ymin, zmed)
+ co2 = (xmin, ymax, zmed)
+ co3 = (xmax, ymax, zmed)
+ co4 = (xmax, ymin, zmed)
+ rend.bakeDist = ((zmax-zmin)/2.0) + 0.000001
+ else:
+ raise "invalid axis"
+ me_plane = Blender.Mesh.New()
+ ob_plane = Blender.Object.New('Mesh')
+ ob_plane.link(me_plane)
+ sce.objects.link(ob_plane)
+ ob_plane.Layers = ob_from.Layers
+
+ ob_from.sel = 1 # make active
+ sce.objects.active = ob_plane
+ ob_plane.sel = 1
+
+ me_plane.verts.extend([co4, co3, co2, co1])
+ me_plane.faces.extend([(0,1,2,3)])
+ me_plane.faceUV = True
+ me_plane_face = me_plane.faces[0]
+ uvs = me_plane_face.uv
+ uvs[0].x = 0.0; uvs[0].y = 0.0
+ uvs[1].x = 0.0; uvs[1].y = 1.0
+ uvs[2].x = 1.0; uvs[2].y = 1.0
+ uvs[3].x = 1.0; uvs[3].y = 0.0
+
+ images_return = []
+
+ for mode in bakemodes:
+ img = Blender.Image.New('bake', width, height, depth)
+
+ me_plane_face.image = img
+ rend.bakeMode = mode
+ rend.bake()
+ images_return.append( img )
+
+ # Restore bake settings
+ #'''
+ rend.bakeDist = BACKUP_bakeDist
+ rend.bakeBias = BACKUP_bakeBias
+ rend.bakeMode = BACKUP_bakeMode
+ rend.bakeClear = BACKUP_bakeClear
+ rend.bakeMargin = BACKUP_bakeMargin
+ rend.bakeToActive = BACKUP_bakeToActive
+ rend.bakeNormalize = BACKUP_bakeNormalize
+
+
+ # Restore obsel
+ sce.objects.selected = BACKUP_obsel
+ sce.objects.active = BACKUP_obact
+
+ me_plane.verts = None
+ sce.objects.unlink(ob_plane)
+ #'''
+
+ return images_return
+
diff --git a/release/scripts/bpymodules/BPyTextPlugin.py b/release/scripts/bpymodules/BPyTextPlugin.py
new file mode 100644
index 00000000000..cd5a085de37
--- /dev/null
+++ b/release/scripts/bpymodules/BPyTextPlugin.py
@@ -0,0 +1,814 @@
+"""The BPyTextPlugin Module
+
+Use get_cached_descriptor(txt) to retrieve information about the script held in
+the txt Text object.
+
+Use print_cache_for(txt) to print the information to the console.
+
+Use line, cursor = current_line(txt) to get the logical line and cursor position
+
+Use get_targets(line, cursor) to find out what precedes the cursor:
+ aaa.bbb.cc|c.ddd -> ['aaa', 'bbb', 'cc']
+
+Use resolve_targets(txt, targets) to turn a target list into a usable object if
+one is found to match.
+"""
+
+import bpy, sys, os
+import __builtin__, tokenize
+from Blender.sys import time
+from tokenize import generate_tokens, TokenError, \
+ COMMENT, DEDENT, INDENT, NAME, NEWLINE, NL, STRING, NUMBER
+
+class Definition:
+ """Describes a definition or defined object through its name, line number
+ and docstring. This is the base class for definition based descriptors.
+ """
+
+ def __init__(self, name, lineno, doc=''):
+ self.name = name
+ self.lineno = lineno
+ self.doc = doc
+
+class ScriptDesc:
+ """Describes a script through lists of further descriptor objects (classes,
+ defs, vars) and dictionaries to built-in types (imports). If a script has
+ not been fully parsed, its incomplete flag will be set. The time of the last
+ parse is held by the time field and the name of the text object from which
+ it was parsed, the name field.
+ """
+
+ def __init__(self, name, imports, classes, defs, vars, incomplete=False):
+ self.name = name
+ self.imports = imports
+ self.classes = classes
+ self.defs = defs
+ self.vars = vars
+ self.incomplete = incomplete
+ self.parse_due = 0
+
+ def set_delay(self, delay):
+ self.parse_due = time() + delay
+
+class ClassDesc(Definition):
+ """Describes a class through lists of further descriptor objects (defs and
+ vars). The name of the class is held by the name field and the line on
+ which it is defined is held in lineno.
+ """
+
+ def __init__(self, name, parents, defs, vars, lineno, doc=''):
+ Definition.__init__(self, name, lineno, doc)
+ self.parents = parents
+ self.defs = defs
+ self.vars = vars
+
+class FunctionDesc(Definition):
+ """Describes a function through its name and list of parameters (name,
+ params) and the line on which it is defined (lineno).
+ """
+
+ def __init__(self, name, params, lineno, doc=''):
+ Definition.__init__(self, name, lineno, doc)
+ self.params = params
+
+class VarDesc(Definition):
+ """Describes a variable through its name and type (if ascertainable) and the
+ line on which it is defined (lineno). If no type can be determined, type
+ will equal None.
+ """
+
+ def __init__(self, name, type, lineno):
+ Definition.__init__(self, name, lineno)
+ self.type = type # None for unknown (supports: dict/list/str)
+
+# Context types
+CTX_UNSET = -1
+CTX_NORMAL = 0
+CTX_SINGLE_QUOTE = 1
+CTX_DOUBLE_QUOTE = 2
+CTX_COMMENT = 3
+
+# Python keywords
+KEYWORDS = ['and', 'del', 'from', 'not', 'while', 'as', 'elif', 'global',
+ 'or', 'with', 'assert', 'else', 'if', 'pass', 'yield',
+ 'break', 'except', 'import', 'print', 'class', 'exec', 'in',
+ 'raise', 'continue', 'finally', 'is', 'return', 'def', 'for',
+ 'lambda', 'try' ]
+
+# Module file extensions
+MODULE_EXTS = ['.py', '.pyc', '.pyo', '.pyw', '.pyd']
+
+ModuleType = type(__builtin__)
+NoneScriptDesc = ScriptDesc('', dict(), dict(), dict(), dict(), True)
+
+_modules = {}
+_modules_updated = 0
+_parse_cache = dict()
+
+def _load_module_names():
+ """Searches the sys.path for module files and lists them, along with
+ sys.builtin_module_names, in the global dict _modules.
+ """
+
+ global _modules
+
+ for n in sys.builtin_module_names:
+ _modules[n] = None
+ for p in sys.path:
+ if p == '': p = os.curdir
+ if not os.path.isdir(p): continue
+ for f in os.listdir(p):
+ for ext in MODULE_EXTS:
+ if f.endswith(ext):
+ _modules[f[:-len(ext)]] = None
+ break
+
+_load_module_names()
+
+def _trim_doc(doc):
+ """Trims the quotes from a quoted STRING token (eg. "'''text'''" -> "text")
+ """
+
+ l = len(doc)
+ i = 0
+ while i < l/2 and (doc[i] == "'" or doc[i] == '"'):
+ i += 1
+ return doc[i:-i]
+
+def resolve_targets(txt, targets):
+ """Attempts to return a useful object for the locally or externally defined
+ entity described by targets. If the object is local (defined in txt), a
+ Definition instance is returned. If the object is external (imported or
+ built in), the object itself is returned. If no object can be found, None is
+ returned.
+ """
+
+ count = len(targets)
+ if count==0: return None
+
+ obj = None
+ local = None
+ i = 1
+
+ desc = get_cached_descriptor(txt)
+ b = targets[0].find('(')
+ if b==-1: b = None # Trick to let us use [:b] and get the whole string
+
+ if desc.classes.has_key(targets[0][:b]):
+ local = desc.classes[targets[0][:b]]
+ elif desc.defs.has_key(targets[0]):
+ local = desc.defs[targets[0]]
+ elif desc.vars.has_key(targets[0]):
+ obj = desc.vars[targets[0]].type
+
+ if local:
+ while i < count:
+ b = targets[i].find('(')
+ if b==-1: b = None
+ if hasattr(local, 'classes') and local.classes.has_key(targets[i][:b]):
+ local = local.classes[targets[i][:b]]
+ elif hasattr(local, 'defs') and local.defs.has_key(targets[i]):
+ local = local.defs[targets[i]]
+ elif hasattr(local, 'vars') and local.vars.has_key(targets[i]):
+ obj = local.vars[targets[i]].type
+ local = None
+ i += 1
+ break
+ else:
+ local = None
+ break
+ i += 1
+
+ if local: return local
+
+ if not obj:
+ if desc.imports.has_key(targets[0]):
+ obj = desc.imports[targets[0]]
+ else:
+ builtins = get_builtins()
+ if builtins.has_key(targets[0]):
+ obj = builtins[targets[0]]
+
+ while obj and i < count:
+ if hasattr(obj, targets[i]):
+ obj = getattr(obj, targets[i])
+ else:
+ obj = None
+ break
+ i += 1
+
+ return obj
+
+def get_cached_descriptor(txt, force_parse=0):
+ """Returns the cached ScriptDesc for the specified Text object 'txt'. If the
+ script has not been parsed in the last 'period' seconds it will be reparsed
+ to obtain this descriptor.
+
+ Specifying TP_AUTO for the period (default) will choose a period based on the
+ size of the Text object. Larger texts are parsed less often.
+ """
+
+ global _parse_cache
+
+ parse = True
+ key = hash(txt)
+ if not force_parse and _parse_cache.has_key(key):
+ desc = _parse_cache[key]
+ if desc.parse_due > time():
+ parse = desc.incomplete
+
+ if parse:
+ desc = parse_text(txt)
+
+ return desc
+
+def parse_text(txt):
+ """Parses an entire script's text and returns a ScriptDesc instance
+ containing information about the script.
+
+ If the text is not a valid Python script (for example if brackets are left
+ open), parsing may fail to complete. However, if this occurs, no exception
+ is thrown. Instead the returned ScriptDesc instance will have its incomplete
+ flag set and information processed up to this point will still be accessible.
+ """
+
+ start_time = time()
+ txt.reset()
+ tokens = generate_tokens(txt.readline) # Throws TokenError
+
+ curl, cursor = txt.getCursorPos()
+ linen = curl + 1 # Token line numbers are one-based
+
+ imports = dict()
+ imp_step = 0
+
+ classes = dict()
+ cls_step = 0
+
+ defs = dict()
+ def_step = 0
+
+ vars = dict()
+ var1_step = 0
+ var2_step = 0
+ var3_step = 0
+ var_accum = dict()
+ var_forflag = False
+
+ indent = 0
+ prev_type = -1
+ prev_text = ''
+ incomplete = False
+
+ while True:
+ try:
+ type, text, start, end, line = tokens.next()
+ except StopIteration:
+ break
+ except (TokenError, IndentationError):
+ incomplete = True
+ break
+
+ # Skip all comments and line joining characters
+ if type == COMMENT or type == NL:
+ continue
+
+ #################
+ ## Indentation ##
+ #################
+
+ if type == INDENT:
+ indent += 1
+ elif type == DEDENT:
+ indent -= 1
+
+ #########################
+ ## Module importing... ##
+ #########################
+
+ imp_store = False
+
+ # Default, look for 'from' or 'import' to start
+ if imp_step == 0:
+ if text == 'from':
+ imp_tmp = []
+ imp_step = 1
+ elif text == 'import':
+ imp_from = None
+ imp_tmp = []
+ imp_step = 2
+
+ # Found a 'from', create imp_from in form '???.???...'
+ elif imp_step == 1:
+ if text == 'import':
+ imp_from = '.'.join(imp_tmp)
+ imp_tmp = []
+ imp_step = 2
+ elif type == NAME:
+ imp_tmp.append(text)
+ elif text != '.':
+ imp_step = 0 # Invalid syntax
+
+ # Found 'import', imp_from is populated or None, create imp_name
+ elif imp_step == 2:
+ if text == 'as':
+ imp_name = '.'.join(imp_tmp)
+ imp_step = 3
+ elif type == NAME or text == '*':
+ imp_tmp.append(text)
+ elif text != '.':
+ imp_name = '.'.join(imp_tmp)
+ imp_symb = imp_name
+ imp_store = True
+
+ # Found 'as', change imp_symb to this value and go back to step 2
+ elif imp_step == 3:
+ if type == NAME:
+ imp_symb = text
+ else:
+ imp_store = True
+
+ # Both imp_name and imp_symb have now been populated so we can import
+ if imp_store:
+
+ # Handle special case of 'import *'
+ if imp_name == '*':
+ parent = get_module(imp_from)
+ imports.update(parent.__dict__)
+
+ else:
+ # Try importing the name as a module
+ try:
+ if imp_from:
+ module = get_module(imp_from +'.'+ imp_name)
+ else:
+ module = get_module(imp_name)
+ except (ImportError, ValueError, AttributeError, TypeError):
+ # Try importing name as an attribute of the parent
+ try:
+ module = __import__(imp_from, globals(), locals(), [imp_name])
+ imports[imp_symb] = getattr(module, imp_name)
+ except (ImportError, ValueError, AttributeError, TypeError):
+ pass
+ else:
+ imports[imp_symb] = module
+
+ # More to import from the same module?
+ if text == ',':
+ imp_tmp = []
+ imp_step = 2
+ else:
+ imp_step = 0
+
+ ###################
+ ## Class parsing ##
+ ###################
+
+ # If we are inside a class then def and variable parsing should be done
+ # for the class. Otherwise the definitions are considered global
+
+ # Look for 'class'
+ if cls_step == 0:
+ if text == 'class':
+ cls_name = None
+ cls_lineno = start[0]
+ cls_indent = indent
+ cls_step = 1
+
+ # Found 'class', look for cls_name followed by '(' parents ')'
+ elif cls_step == 1:
+ if not cls_name:
+ if type == NAME:
+ cls_name = text
+ cls_sline = False
+ cls_parents = dict()
+ cls_defs = dict()
+ cls_vars = dict()
+ elif type == NAME:
+ if classes.has_key(text):
+ parent = classes[text]
+ cls_parents[text] = parent
+ cls_defs.update(parent.defs)
+ cls_vars.update(parent.vars)
+ elif text == ':':
+ cls_step = 2
+
+ # Found 'class' name ... ':', now check if it's a single line statement
+ elif cls_step == 2:
+ if type == NEWLINE:
+ cls_sline = False
+ else:
+ cls_sline = True
+ cls_doc = ''
+ cls_step = 3
+
+ elif cls_step == 3:
+ if not cls_doc and type == STRING:
+ cls_doc = _trim_doc(text)
+ if cls_sline:
+ if type == NEWLINE:
+ classes[cls_name] = ClassDesc(cls_name, cls_parents, cls_defs, cls_vars, cls_lineno, cls_doc)
+ cls_step = 0
+ else:
+ if type == DEDENT and indent <= cls_indent:
+ classes[cls_name] = ClassDesc(cls_name, cls_parents, cls_defs, cls_vars, cls_lineno, cls_doc)
+ cls_step = 0
+
+ #################
+ ## Def parsing ##
+ #################
+
+ # Look for 'def'
+ if def_step == 0:
+ if text == 'def':
+ def_name = None
+ def_lineno = start[0]
+ def_step = 1
+
+ # Found 'def', look for def_name followed by '('
+ elif def_step == 1:
+ if type == NAME:
+ def_name = text
+ def_params = []
+ elif def_name and text == '(':
+ def_step = 2
+
+ # Found 'def' name '(', now identify the parameters upto ')'
+ # TODO: Handle ellipsis '...'
+ elif def_step == 2:
+ if type == NAME:
+ def_params.append(text)
+ elif text == ':':
+ def_step = 3
+
+ # Found 'def' ... ':', now check if it's a single line statement
+ elif def_step == 3:
+ if type == NEWLINE:
+ def_sline = False
+ else:
+ def_sline = True
+ def_doc = ''
+ def_step = 4
+
+ elif def_step == 4:
+ if type == STRING:
+ def_doc = _trim_doc(text)
+ newdef = None
+ if def_sline:
+ if type == NEWLINE:
+ newdef = FunctionDesc(def_name, def_params, def_lineno, def_doc)
+ else:
+ if type == NAME:
+ newdef = FunctionDesc(def_name, def_params, def_lineno, def_doc)
+ if newdef:
+ if cls_step > 0: # Parsing a class
+ cls_defs[def_name] = newdef
+ else:
+ defs[def_name] = newdef
+ def_step = 0
+
+ ##########################
+ ## Variable assignation ##
+ ##########################
+
+ if cls_step > 0: # Parsing a class
+ # Look for 'self.???'
+ if var1_step == 0:
+ if text == 'self':
+ var1_step = 1
+ elif var1_step == 1:
+ if text == '.':
+ var_name = None
+ var1_step = 2
+ else:
+ var1_step = 0
+ elif var1_step == 2:
+ if type == NAME:
+ var_name = text
+ if cls_vars.has_key(var_name):
+ var_step = 0
+ else:
+ var1_step = 3
+ elif var1_step == 3:
+ if text == '=':
+ var1_step = 4
+ elif text != ',':
+ var1_step = 0
+ elif var1_step == 4:
+ var_type = None
+ if type == NUMBER:
+ close = end[1]
+ if text.find('.') != -1: var_type = float
+ else: var_type = int
+ elif type == STRING:
+ close = end[1]
+ var_type = str
+ elif text == '[':
+ close = line.find(']', end[1])
+ var_type = list
+ elif text == '(':
+ close = line.find(')', end[1])
+ var_type = tuple
+ elif text == '{':
+ close = line.find('}', end[1])
+ var_type = dict
+ elif text == 'dict':
+ close = line.find(')', end[1])
+ var_type = dict
+ if var_type and close+1 < len(line):
+ if line[close+1] != ' ' and line[close+1] != '\t':
+ var_type = None
+ cls_vars[var_name] = VarDesc(var_name, var_type, start[0])
+ var1_step = 0
+
+ elif def_step > 0: # Parsing a def
+ # Look for 'global ???[,???]'
+ if var2_step == 0:
+ if text == 'global':
+ var2_step = 1
+ elif var2_step == 1:
+ if type == NAME:
+ if not vars.has_key(text):
+ vars[text] = VarDesc(text, None, start[0])
+ elif text != ',' and type != NL:
+ var2_step == 0
+
+ else: # In global scope
+ if var3_step == 0:
+ # Look for names
+ if text == 'for':
+ var_accum = dict()
+ var_forflag = True
+ elif text == '=' or (var_forflag and text == 'in'):
+ var_forflag = False
+ var3_step = 1
+ elif type == NAME:
+ if prev_text != '.' and not vars.has_key(text):
+ var_accum[text] = VarDesc(text, None, start[0])
+ elif not text in [',', '(', ')', '[', ']']:
+ var_accum = dict()
+ var_forflag = False
+ elif var3_step == 1:
+ if len(var_accum) != 1:
+ var_type = None
+ vars.update(var_accum)
+ else:
+ var_name = var_accum.keys()[0]
+ var_type = None
+ if type == NUMBER:
+ if text.find('.') != -1: var_type = float
+ else: var_type = int
+ elif type == STRING: var_type = str
+ elif text == '[': var_type = list
+ elif text == '(': var_type = tuple
+ elif text == '{': var_type = dict
+ vars[var_name] = VarDesc(var_name, var_type, start[0])
+ var3_step = 0
+
+ #######################
+ ## General utilities ##
+ #######################
+
+ prev_type = type
+ prev_text = text
+
+ desc = ScriptDesc(txt.name, imports, classes, defs, vars, incomplete)
+ desc.set_delay(10 * (time()-start_time) + 0.05)
+
+ global _parse_cache
+ _parse_cache[hash(txt)] = desc
+ return desc
+
+def get_modules(since=1):
+ """Returns the set of built-in modules and any modules that have been
+ imported into the system upto 'since' seconds ago.
+ """
+
+ global _modules, _modules_updated
+
+ t = time()
+ if _modules_updated < t - since:
+ _modules.update(sys.modules)
+ _modules_updated = t
+ return _modules.keys()
+
+def suggest_cmp(x, y):
+ """Use this method when sorting a list of suggestions.
+ """
+
+ return cmp(x[0].upper(), y[0].upper())
+
+def get_module(name):
+ """Returns the module specified by its name. The module itself is imported
+ by this method and, as such, any initialization code will be executed.
+ """
+
+ mod = __import__(name)
+ components = name.split('.')
+ for comp in components[1:]:
+ mod = getattr(mod, comp)
+ return mod
+
+def type_char(v):
+ """Returns the character used to signify the type of a variable. Use this
+ method to identify the type character for an item in a suggestion list.
+
+ The following values are returned:
+ 'm' if the parameter is a module
+ 'f' if the parameter is callable
+ 'v' if the parameter is variable or otherwise indeterminable
+
+ """
+
+ if isinstance(v, ModuleType):
+ return 'm'
+ elif callable(v):
+ return 'f'
+ else:
+ return 'v'
+
+def get_context(txt):
+ """Establishes the context of the cursor in the given Blender Text object
+
+ Returns one of:
+ CTX_NORMAL - Cursor is in a normal context
+ CTX_SINGLE_QUOTE - Cursor is inside a single quoted string
+ CTX_DOUBLE_QUOTE - Cursor is inside a double quoted string
+ CTX_COMMENT - Cursor is inside a comment
+
+ """
+
+ l, cursor = txt.getCursorPos()
+ lines = txt.asLines(0, l+1)
+
+ # FIXME: This method is too slow in large files for it to be called as often
+ # as it is. So for lines below the 1000th line we do this... (quorn)
+ if l > 1000: return CTX_NORMAL
+
+ # Detect context (in string or comment)
+ in_str = CTX_NORMAL
+ for line in lines:
+ if l == 0:
+ end = cursor
+ else:
+ end = len(line)
+ l -= 1
+
+ # Comments end at new lines
+ if in_str == CTX_COMMENT:
+ in_str = CTX_NORMAL
+
+ for i in range(end):
+ if in_str == 0:
+ if line[i] == "'": in_str = CTX_SINGLE_QUOTE
+ elif line[i] == '"': in_str = CTX_DOUBLE_QUOTE
+ elif line[i] == '#': in_str = CTX_COMMENT
+ else:
+ if in_str == CTX_SINGLE_QUOTE:
+ if line[i] == "'":
+ in_str = CTX_NORMAL
+ # In again if ' escaped, out again if \ escaped, and so on
+ for a in range(i-1, -1, -1):
+ if line[a] == '\\': in_str = 1-in_str
+ else: break
+ elif in_str == CTX_DOUBLE_QUOTE:
+ if line[i] == '"':
+ in_str = CTX_NORMAL
+ # In again if " escaped, out again if \ escaped, and so on
+ for a in range(i-1, -1, -1):
+ if line[i-a] == '\\': in_str = 2-in_str
+ else: break
+
+ return in_str
+
+def current_line(txt):
+ """Extracts the Python script line at the cursor in the Blender Text object
+ provided and cursor position within this line as the tuple pair (line,
+ cursor).
+ """
+
+ lineindex, cursor = txt.getCursorPos()
+ lines = txt.asLines()
+ line = lines[lineindex]
+
+ # Join previous lines to this line if spanning
+ i = lineindex - 1
+ while i > 0:
+ earlier = lines[i].rstrip()
+ if earlier.endswith('\\'):
+ line = earlier[:-1] + ' ' + line
+ cursor += len(earlier)
+ i -= 1
+
+ # Join later lines while there is an explicit joining character
+ i = lineindex
+ while i < len(lines)-1 and lines[i].rstrip().endswith('\\'):
+ later = lines[i+1].strip()
+ line = line + ' ' + later[:-1]
+ i += 1
+
+ return line, cursor
+
+def get_targets(line, cursor):
+ """Parses a period separated string of valid names preceding the cursor and
+ returns them as a list in the same order.
+ """
+
+ brk = 0
+ targets = []
+ j = cursor
+ i = j-1
+ while i >= 0:
+ if line[i] == ')': brk += 1
+ elif brk:
+ if line[i] == '(': brk -= 1
+ else:
+ if line[i] == '.':
+ targets.insert(0, line[i+1:j]); j=i
+ elif not (line[i].isalnum() or line[i] == '_' or line[i] == '.'):
+ break
+ i -= 1
+ targets.insert(0, line[i+1:j])
+ return targets
+
+def get_defs(txt):
+ """Returns a dictionary which maps definition names in the source code to
+ a list of their parameter names.
+
+ The line 'def doit(one, two, three): print one' for example, results in the
+ mapping 'doit' : [ 'one', 'two', 'three' ]
+ """
+
+ return get_cached_descriptor(txt).defs
+
+def get_vars(txt):
+ """Returns a dictionary of variable names found in the specified Text
+ object. This method locates all names followed directly by an equal sign:
+ 'a = ???' or indirectly as part of a tuple/list assignment or inside a
+ 'for ??? in ???:' block.
+ """
+
+ return get_cached_descriptor(txt).vars
+
+def get_imports(txt):
+ """Returns a dictionary which maps symbol names in the source code to their
+ respective modules.
+
+ The line 'from Blender import Text as BText' for example, results in the
+ mapping 'BText' : <module 'Blender.Text' (built-in)>
+
+ Note that this method imports the modules to provide this mapping as as such
+ will execute any initilization code found within.
+ """
+
+ return get_cached_descriptor(txt).imports
+
+def get_builtins():
+ """Returns a dictionary of built-in modules, functions and variables."""
+
+ return __builtin__.__dict__
+
+
+#################################
+## Debugging utility functions ##
+#################################
+
+def print_cache_for(txt, period=sys.maxint):
+ """Prints out the data cached for a given Text object. If no period is
+ given the text will not be reparsed and the cached version will be returned.
+ Otherwise if the period has expired the text will be reparsed.
+ """
+
+ desc = get_cached_descriptor(txt, period)
+ print '================================================'
+ print 'Name:', desc.name, '('+str(hash(txt))+')'
+ print '------------------------------------------------'
+ print 'Defs:'
+ for name, ddesc in desc.defs.items():
+ print ' ', name, ddesc.params, ddesc.lineno
+ print ' ', ddesc.doc
+ print '------------------------------------------------'
+ print 'Vars:'
+ for name, vdesc in desc.vars.items():
+ print ' ', name, vdesc.type, vdesc.lineno
+ print '------------------------------------------------'
+ print 'Imports:'
+ for name, item in desc.imports.items():
+ print ' ', name.ljust(15), item
+ print '------------------------------------------------'
+ print 'Classes:'
+ for clsnme, clsdsc in desc.classes.items():
+ print ' *********************************'
+ print ' Name:', clsnme
+ print ' ', clsdsc.doc
+ print ' ---------------------------------'
+ print ' Defs:'
+ for name, ddesc in clsdsc.defs.items():
+ print ' ', name, ddesc.params, ddesc.lineno
+ print ' ', ddesc.doc
+ print ' ---------------------------------'
+ print ' Vars:'
+ for name, vdesc in clsdsc.vars.items():
+ print ' ', name, vdesc.type, vdesc.lineno
+ print ' *********************************'
+ print '================================================'
diff --git a/release/scripts/bpymodules/blend2renderinfo.py b/release/scripts/bpymodules/blend2renderinfo.py
new file mode 100644
index 00000000000..1b9dec58d55
--- /dev/null
+++ b/release/scripts/bpymodules/blend2renderinfo.py
@@ -0,0 +1,95 @@
+#!/usr/bin/python
+
+# --------------------------------------------------------------------------
+# ***** 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 struct
+
+# In Blender, selecting scenes in the databrowser (shift+f4) will tag for rendering.
+
+# This struct wont change according to ton.
+# Note that the size differs on 32/64bit
+'''
+typedef struct BHead {
+ int code, len;
+ void *old;
+ int SDNAnr, nr;
+} BHead;
+'''
+
+
+def read_blend_rend_chunk(path):
+ file = open(path, 'rb')
+
+ if file.read(len('BLENDER')) != 'BLENDER':
+ return []
+
+ #
+ if file.read(1) == '-':
+ is64bit = True
+ else: # '_'
+ is64bit = False
+
+ if file.read(1) == 'V':
+ isBigEndian = True # ppc
+ else: # 'V'
+ isBigEndian = False # x86
+
+
+ # Now read the bhead chunk!!!
+ file.read(3) # skip the version
+
+ scenes = []
+
+ while file.read(4) == 'REND':
+
+ if is64bit: sizeof_bhead = sizeof_bhead_left = 24 # 64bit
+ else: sizeof_bhead = sizeof_bhead_left = 20 # 32bit
+
+ sizeof_bhead_left -= 4
+
+ if isBigEndian: rend_length = struct.unpack('>i', file.read(4))[0]
+ else: rend_length = struct.unpack('<i', file.read(4))[0]
+
+ sizeof_bhead_left -= 4
+
+ # We dont care about the rest of the bhead struct
+ file.read(sizeof_bhead_left)
+
+ # Now we want the scene name, start and end frame. this is 32bites long
+
+ if isBigEndian: start_frame, end_frame = struct.unpack('>2i', file.read(8))
+ else: start_frame, end_frame = struct.unpack('<2i', file.read(8))
+
+ scene_name = file.read(24)
+ scene_name = scene_name[ : scene_name.index('\0') ]
+
+ scenes.append( (start_frame, end_frame, scene_name) )
+ return scenes
+
+def main():
+ import sys
+ for arg in sys.argv[1:]:
+ if arg.lower().endswith('.blend'):
+ print read_blend_rend_chunk(arg)
+
+if __name__ == '__main__':
+ main()
+
diff --git a/release/scripts/bpymodules/dxfImportObjects.py b/release/scripts/bpymodules/dxfImportObjects.py
deleted file mode 100644
index 960c4c1ac15..00000000000
--- a/release/scripts/bpymodules/dxfImportObjects.py
+++ /dev/null
@@ -1,1326 +0,0 @@
-"""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.
-"""
-
-# --------------------------------------------------------------------------
-# DXF Import Objects v0.8 by Ed Blake (AKA Kitsu)
-# --------------------------------------------------------------------------
-# ***** 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 *****
-# --------------------------------------------------------------------------
-from math 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)
-
-#---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
-
-#---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
-class Object:
- """Empty container class for dxf objects"""
-
- def __init__(self, _type=''):
- """_type expects a string value."""
- self.type = _type
- self.name = ''
- self.data = []
-
- def __str__(self):
- if self.name:
- return self.name
- else:
- return self.type
-
- def __repr__(self):
- return str(self.data)
-
- def get_type(self, kind=''):
- """Despite the name, this method actually returns all objects of type 'kind' from self.data."""
- if type:
- objects = []
- for item in self.data:
- if type(item) != list and item.type == kind:
- # we want this type of object
- objects.append(item)
- elif type(item) == list and item[0] == kind:
- # we want this type of data
- objects.append(item[1])
- return objects
-
-
-class Layer:
- """Class for objects representing dxf layers."""
-
- def __init__(self, obj):
- """Expects an entity object of type line as input."""
- self.type = obj.type
- self.data = obj.data[:]
-
- self.name = obj.get_type(2)[0]
- self.color = obj.get_type(62)[0]
- 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)
-
-
-
-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 = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- discard, self.layer, discard_index = get_layer(obj.data)
- del obj.data[discard_index]
-
- 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
- sx, sy, sz, ex, ey, ez = 0, 0, 0, 0, 0, 0
- for item in data:
- if item[0] == 10: # 10 = x
- sx = item[1]
- elif item[0] == 20: # 20 = y
- sy = item[1]
- elif item[0] == 30: # 30 = z
- sz = item[1]
- elif item[0] == 11: # 11 = x
- ex = item[1]
- elif item[0] == 21: # 21 = y
- ey = item[1]
- elif item[0] == 31: # 31 = z
- ez = item[1]
- return [[sx, sy, sz], [ex, ey, ez]]
-
-
-
- def __repr__(self):
- return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)
-
-
-
-class LWpolyline:
- """Class for objects representing dxf LWpolylines."""
-
- def __init__(self, obj):
- """Expects an entity object of type lwpolyline as input."""
- 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 = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- self.elevation = obj.get_type(38)
- if self.elevation:
- self.elevation = self.elevation[0]
- else:
- self.elevation = 0
-
- self.flags = obj.get_type(70)
- if self.flags:
- self.flags = self.flags[0]
- else:
- self.flags = 0
-
- self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen
- discard, self.layer, discard_index = get_layer(obj.data)
- del obj.data[discard_index]
- self.points = self.get_points(obj.data)
- self.extrusion = self.get_extrusion(obj.data)
-
-
-
-
-
-
- def get_points(self, data):
- """Gets points for a polyline type object.
-
- 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 get_extrusion(self, data):
- """Find the axis of extrusion.
-
- Used to get the objects Object Coordinate System (ocs).
- """
- vec = [0,0,1]
- for item in data:
- if item[0] == 210: # 210 = x
- vec[0] = item[1]
- elif item[0] == 220: # 220 = y
- vec[1] = item[1]
- elif item[0] == 230: # 230 = z
- vec[2] = item[1]
- return vec
-
-
- def __repr__(self):
- return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)
-
-
-
-class Polyline:
- """Class for objects representing dxf LWpolylines."""
-
- def __init__(self, obj):
- """Expects an entity object of type polyline as input."""
- if not obj.type == 'polyline':
- raise TypeError, "Wrong type %s for polyline object!" %obj.type
- self.type = obj.type
- self.data = obj.data[:]
- self.points = []
-
- # optional data (with defaults)
- self.space = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- self.elevation = obj.get_type(30)
- if self.elevation:
- self.elevation = self.elevation[0]
- else:
- self.elevation = 0
-
- self.flags = obj.get_type(70)
- if self.flags:
- self.flags = self.flags[0]
- else:
- self.flags = 0
-
- self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen
-
- discard, self.layer, discard_index = get_layer(obj.data)
- del obj.data[discard_index]
- self.extrusion = self.get_extrusion(obj.data)
-
-
-
-
-
- def get_extrusion(self, data):
- """Find the axis of extrusion.
-
- Used to get the objects Object Coordinate System (ocs).
- """
- vec = [0,0,1]
- for item in data:
- if item[0] == 210: # 210 = x
- vec[0] = item[1]
- elif item[0] == 220: # 220 = y
- vec[1] = item[1]
- elif item[0] == 230: # 230 = z
- vec[2] = item[1]
- return vec
-
-
- def __repr__(self):
- return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)
-
-
-
-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.
- """
- self.loc = [0,0,0]
- self.bulge = 0
- self.swidth = 0
- self.ewidth = 0
- self.flags = 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)
-
-
- 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
- """
- for item in data:
- if item[0] == 10: # 10 = x
- self.x = item[1]
- elif item[0] == 20: # 20 = y
- self.y = item[1]
- elif item[0] == 30: # 30 = z
- self.z = item[1]
- elif item[0] == 40: # 40 = start width
- self.swidth = item[1]
- elif item[0] == 41: # 41 = end width
- self.ewidth = item[1]
- elif item[0] == 42: # 42 = bulge
- self.bulge = item[1]
- elif item[0] == 70: # 70 = vert flags
- self.flags = item[1]
-
-
- 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" %(self.loc, self.swidth, self.ewidth, self.bulge)
-
-
- 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 = obj.get_type(40)[0]
- self.value = obj.get_type(1)[0] # The text string value
-
- # optional data (with defaults)
- self.space = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- self.rotation = obj.get_type(50) # radians?
- if not self.rotation:
- self.rotation = 0
- else:
- self.rotation = self.rotation[0]
-
- self.width_factor = obj.get_type(41) # Scaling factor along local x axis
- if not self.width_factor:
- self.width_factor = 1
- else:
- self.width_factor = self.width_factor[0]
-
- self.oblique = obj.get_type(51) # skew in degrees -90 <= oblique <= 90
- if not self.oblique:
- self.oblique = 0
- else:
- self.oblique = self.oblique[0]
-
- self.halignment = obj.get_type(72) # horiz. alignment
- if not self.halignment: # 0=left, 1=center, 2=right, 3=aligned, 4=middle, 5=fit
- self.halignment = 0
- else:
- self.halignment = self.halignment[0]
-
- self.valignment = obj.get_type(73) # vert. alignment
- if not self.valignment: # 0=baseline, 1=bottom, 2=middle, 3=top
- self.valignment = 0
- else:
- self.valignment = self.valignment[0]
-
- discard, self.layer, discard_index = get_layer(obj.data)
- del obj.data[discard_index]
- self.loc = self.get_loc(obj.data, self.halignment, self.valignment)
- self.extrusion = self.get_extrusion(obj.data)
-
-
-
-
- def get_loc(self, data, halign, valign):
- """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
- for item in data:
- if item[0] == 10: # 10 = x
- x = item[1]
- elif item[0] == 20: # 20 = y
- y = item[1]
- elif item[0] == 30: # 30 = z
- z = item[1]
- elif item[0] == 11: # 11 = x
- jx = item[1]
- elif item[0] == 21: # 21 = y
- jy = item[1]
- elif item[0] == 31: # 31 = z
- jz = item[1]
-
- if halign or valign:
- x, y, z = jx, jy, jz
- return [x, y, z]
-
- def get_extrusion(self, data):
- """Find the axis of extrusion.
-
- Used to get the objects Object Coordinate System (ocs).
- """
- vec = [0,0,1]
- for item in data:
- if item[0] == 210: # 210 = x
- vec[0] = item[1]
- elif item[0] == 220: # 220 = y
- vec[1] = item[1]
- elif item[0] == 230: # 230 = z
- vec[2] = item[1]
- return vec
-
-
- def __repr__(self):
- return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value)
-
-
-
-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 = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- self.rotation = obj.get_type(50) # radians
- if not self.rotation:
- self.rotation = 0
- else:
- self.rotation = self.rotation[0]
-
- self.width_factor = obj.get_type(42) # Scaling factor along local x axis
- if not self.width_factor:
- self.width_factor = 1
- else:
- self.width_factor = self.width_factor[0]
-
- self.line_space = obj.get_type(44) # percentage of default
- if not self.line_space:
- self.line_space = 1
- else:
- self.line_space = self.line_space[0]
-
- discard, self.layer, discard_index = get_layer(obj.data)
- del obj.data[discard_index]
- self.loc = self.get_loc(obj.data)
- self.extrusion = self.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 location.
- """
- loc = [0,0,0]
- for item in data:
- if item[0] == 10: # 10 = x
- loc[0] = item[1]
- elif item[0] == 20: # 20 = y
- loc[1] = item[1]
- elif item[0] == 30: # 30 = z
- loc[2] = item[1]
- return loc
-
-
-
-
- def get_extrusion(self, data):
- """Find the axis of extrusion.
-
- Used to get the objects Object Coordinate System (ocs).
- """
- vec = [0,0,1]
- for item in data:
- if item[0] == 210: # 210 = x
- vec[0] = item[1]
- elif item[0] == 220: # 220 = y
- vec[1] = item[1]
- elif item[0] == 230: # 230 = z
- vec[2] = item[1]
- return vec
-
-
- def __repr__(self):
- return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value)
-
-
-
-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 = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- discard, self.layer, discard_index = get_layer(obj.data)
- del obj.data[discard_index]
- self.loc = self.get_loc(obj.data)
- self.extrusion = self.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]
- for item in data:
- if item[0] == 10: # 10 = x
- loc[0] = item[1]
- elif item[0] == 20: # 20 = y
- loc[1] = item[1]
- elif item[0] == 30: # 30 = z
- loc[2] = item[1]
- return loc
-
-
-
- def get_extrusion(self, data):
- """Find the axis of extrusion.
-
- Used to get the objects Object Coordinate System (ocs).
- """
- vec = [0,0,1]
- for item in data:
- if item[0] == 210: # 210 = x
- vec[0] = item[1]
- elif item[0] == 220: # 220 = y
- vec[1] = item[1]
- elif item[0] == 230: # 230 = z
- vec[2] = item[1]
- return vec
-
-
- def __repr__(self):
- return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius)
-
-
-
-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 = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- discard, self.layer, discard_index = get_layer(obj.data)
- del obj.data[discard_index]
- self.loc = self.get_loc(obj.data)
- self.extrusion = self.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]
- for item in data:
- if item[0] == 10: # 10 = x
- loc[0] = item[1]
- elif item[0] == 20: # 20 = y
- loc[1] = item[1]
- elif item[0] == 30: # 30 = z
- loc[2] = item[1]
- return loc
-
-
-
- def get_extrusion(self, data):
- """Find the axis of extrusion.
-
- Used to get the objects Object Coordinate System (ocs).
- """
- vec = [0,0,1]
- for item in data:
- if item[0] == 210: # 210 = x
- vec[0] = item[1]
- elif item[0] == 220: # 220 = y
- vec[1] = item[1]
- elif item[0] == 230: # 230 = z
- vec[2] = item[1]
- return vec
-
-
- def __repr__(self):
- return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius)
-
-
-
-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 = obj.get_type(2)[0]
-
- # optional data (with defaults)
- self.insertion_units = obj.get_type(70)
- if not self.insertion_units:
- self.insertion_units = None
- else:
- self.insertion_units = self.insertion_units[0]
-
- self.insert_units = obj.get_type(1070)
- if not self.insert_units:
- self.insert_units = None
- else:
- self.insert_units = self.insert_units[0]
-
-
-
-
-
-
- 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[:]
-
- # required data
- self.flags = obj.get_type(70)[0]
- self.entities = Object('block_contents')
- self.entities.data = objectify([ent for ent in obj.data if type(ent) != list])
-
- # optional data (with defaults)
- self.name = obj.get_type(3)
- if self.name:
- self.name = self.name[0]
- else:
- self.name = ''
-
- self.path = obj.get_type(1)
- if self.path:
- self.path = self.path[0]
- else:
- self.path = ''
-
- self.discription = obj.get_type(4)
- if self.discription:
- self.discription = self.discription[0]
- else:
- self.discription = ''
-
- discard, self.layer, discard_index = get_layer(obj.data)
- del obj.data[discard_index]
- self.loc = self.get_loc(obj.data)
-
-
-
-
-
- def get_loc(self, data):
- """Gets the insert point of the block."""
- loc = [0, 0, 0]
- for item in data:
- if type(item) != list:
- continue
- if item[0] == 10: # 10 = x
- loc[0] = item[1]
- elif item[0] == 20: # 20 = y
- loc[1] = item[1]
- elif item[0] == 30: # 30 = z
- loc[2] = item[1]
- 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.block = obj.get_type(2)[0]
-
- # optional data (with defaults)
- self.rotation = obj.get_type(50)
- if self.rotation:
- self.rotation = self.rotation[0]
- else:
- self.rotation = 0
-
- self.space = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- discard, self.layer, discard_index = get_layer(obj.data)
- del obj.data[discard_index]
- 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 = self.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]
- for item in data:
- if item[0] == 10: # 10 = x
- loc[0] = item[1]
- elif item[0] == 20: # 20 = y
- loc[1] = item[1]
- elif item[0] == 30: # 30 = z
- loc[2] = item[1]
- return loc
-
-
-
- def get_scale(self, data):
- """Gets the x/y/z scale factor for the block.
- """
- scale = [1, 1, 1]
- for item in data:
- if item[0] == 41: # 41 = x scale
- scale[0] = item[1]
- elif item[0] == 42: # 42 = y scale
- scale[1] = item[1]
- elif item[0] == 43: # 43 = z scale
- scale[2] = item[1]
- return scale
-
-
-
- def get_array(self, data):
- """Returns the pair (row number, row spacing), (column number, column spacing)."""
- columns = 1
- rows = 1
- cspace = 0
- rspace = 0
- for item in data:
- if item[0] == 70: # 70 = columns
- columns = item[1]
- elif item[0] == 71: # 71 = rows
- rows = item[1]
- if item[0] == 44: # 44 = columns
- cspace = item[1]
- elif item[0] == 45: # 45 = rows
- rspace = item[1]
- return (rows, rspace), (columns, cspace)
-
-
-
- def get_extrusion(self, data):
- """Find the axis of extrusion.
-
- Used to get the objects Object Coordinate System (ocs).
- """
- vec = [0,0,1]
- for item in data:
- if item[0] == 210: # 210 = x
- vec[0] = item[1]
- elif item[0] == 220: # 220 = y
- vec[1] = item[1]
- elif item[0] == 230: # 230 = z
- vec[2] = item[1]
- return vec
-
-
- def __repr__(self):
- return "%s: layer - %s, block - %s" %(self.__class__.__name__, self.layer, self.block)
-
-
-
-
-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 = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- discard, self.layer, discard_index = get_layer(obj.data)
- del obj.data[discard_index]
- self.loc = self.get_loc(obj.data)
- self.major = self.get_major(obj.data)
- self.extrusion = self.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]
- for item in data:
- if item[0] == 10: # 10 = x
- loc[0] = item[1]
- elif item[0] == 20: # 20 = y
- loc[1] = item[1]
- elif item[0] == 30: # 30 = z
- loc[2] = item[1]
- 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]
- for item in data:
- if item[0] == 11: # 11 = x
- loc[0] = item[1]
- elif item[0] == 21: # 21 = y
- loc[1] = item[1]
- elif item[0] == 31: # 31 = z
- loc[2] = item[1]
- return loc
-
-
-
- def get_extrusion(self, data):
- """Find the axis of extrusion.
-
- Used to get the objects Object Coordinate System (ocs).
- """
- vec = [0,0,1]
- for item in data:
- if item[0] == 210: # 210 = x
- vec[0] = item[1]
- elif item[0] == 220: # 220 = y
- vec[1] = item[1]
- elif item[0] == 230: # 230 = z
- vec[2] = item[1]
- return vec
-
-
- def __repr__(self):
- return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius)
-
-
-
-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 = obj.get_type(67)
- if self.space:
- self.space = self.space[0]
- else:
- self.space = 0
-
- self.color_index = obj.get_type(62)
- if self.color_index:
- self.color_index = self.color_index[0]
- else:
- self.color_index = BYLAYER
-
- discard, self.layer, discard_index = get_layer(obj.data)
- del obj.data[discard_index]
- 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 = False
- for item in data:
- # ----------- a -------------
- if item[0] == 10: # 10 = x
- a[0] = item[1]
- elif item[0] == 20: # 20 = y
- a[1] = item[1]
- elif item[0] == 30: # 30 = z
- a[2] = item[1]
- # ----------- b -------------
- elif item[0] == 11: # 11 = x
- b[0] = item[1]
- elif item[0] == 21: # 21 = y
- b[1] = item[1]
- elif item[0] == 31: # 31 = z
- b[2] = item[1]
- # ----------- c -------------
- elif item[0] == 12: # 12 = x
- c[0] = item[1]
- elif item[0] == 22: # 22 = y
- c[1] = item[1]
- elif item[0] == 32: # 32 = z
- c[2] = item[1]
- # ----------- d -------------
- elif item[0] == 13: # 13 = x
- d = [0, 0, 0]
- d[0] = item[1]
- elif item[0] == 23: # 23 = y
- d[1] = item[1]
- elif item[0] == 33: # 33 = z
- d[2] = item[1]
- out = [a,b,c]
- if d:
- out.append(d)
- return out
-
-
- def __repr__(self):
- return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points)
-
-
-def get_name(data):
- """Get the name of an object from its object data.
-
- Returns a pair of (data_item, name) where data_item is the list entry where the name was found
- (the data_item can be used to remove the entry from the object data). Be sure to check
- name not None before using the returned values!
- """
- value = None
- for i, item in enumerate(data):
- if item[0] == 2:
- value = item[1]
- break
- return item, value, i
-
-def get_layer(data):
- """Expects object data as input.
-
- Returns (entry, layer_name, entry_index) where entry is the data item that provided the layer name.
- """
- value = None
- for i, item in enumerate(data):
- if item[0] == 8:
- value = item[1]
- break
- return item, value, i
-
-
-# type to object map
-type_map = {
- 'line':Line,
- 'lwpolyline':LWpolyline,
- 'text':Text,
- 'mtext':Mtext,
- 'circle':Circle,
- 'arc':Arc,
- 'layer':Layer,
- 'block_record':BlockRecord,
- 'block':Block,
- 'insert':Insert,
- 'ellipse':Ellipse,
- '3dface':Face
-}
-
-def objectify(data):
- """Expects a section type object's data as input.
-
- Maps object data to the correct object type.
- """
- objects = [] # colector for finished objects
- known_types = type_map.keys() # so we don't have to call foo.keys() every iteration
- index = 0
- while index < len(data):
- item = data[index]
- if type(item) != list and item.type in known_types:
- # proccess the object and append the resulting object
- objects.append(type_map[item.type](item))
- elif 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':
- pline = Polyline(item)
- while 1:
- index += 1
- item = data[index]
- if item.type == 'vertex':
- v = Vertex(item)
- pline.points.append(v)
- elif item.type == 'seqend':
- break
- else:
- print "Error: non-vertex found before seqend!"
- index -= 1
- break
- objects.append(pline)
- else:
- # we will just let the data pass un-harrased
- objects.append(item)
- index += 1
- return objects
-if __name__ == "__main__":
- print "No example yet!" \ No newline at end of file
diff --git a/release/scripts/bpymodules/dxfLibrary.py b/release/scripts/bpymodules/dxfLibrary.py
new file mode 100644
index 00000000000..5c63e7f5bf5
--- /dev/null
+++ b/release/scripts/bpymodules/dxfLibrary.py
@@ -0,0 +1,708 @@
+#dxfLibrary.py : provides functions for generating DXF files
+# --------------------------------------------------------------------------
+__version__ = "v1.27beta - 2008.10.05"
+__author__ = "Stani Michiels(Stani), Remigiusz Fiedler(migius)"
+__license__ = "GPL"
+__url__ = "http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_dxf"
+__bpydoc__ ="""The script exports geometry data to DXF format r12 version.
+
+Copyright %s
+Version %s
+License %s
+Homepage %s
+
+See the homepage for documentation.
+url:
+
+IDEAs:
+-
+
+TODO:
+-
+
+History
+v1.27 - 2008.10.07 by migius
+- beautifying output code: keys whitespace prefix
+- refactoring DXF-strings format: NewLine moved to the end of
+v1.26 - 2008.10.05 by migius
+- modif POLYLINE to support POLYFACE
+v1.25 - 2008.09.28 by migius
+- modif FACE class for r12
+v1.24 - 2008.09.27 by migius
+- modif POLYLINE class for r12
+- changing output format from r9 to r12(AC1009)
+v1.1 (20/6/2005) by www.stani.be/python/sdxf
+- Python library to generate dxf drawings
+______________________________________________________________
+""" % (__author__,__version__,__license__,__url__)
+
+# --------------------------------------------------------------------------
+# DXF Library: copyright (C) 2005 by Stani Michiels (AKA Stani)
+# 2008 modif by 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
+#from Blender import Mathutils, Window, Scene, sys, Draw
+#import BPyMessages
+
+try:
+ import copy
+ #from struct import pack
+except:
+ copy = None
+
+####1) Private (only for developpers)
+_HEADER_POINTS=['insbase','extmin','extmax']
+
+#---helper functions-----------------------------------
+def _point(x,index=0):
+ """Convert tuple to a dxf point"""
+ #print 'deb: _point=', x #-------------
+ return '\n'.join([' %s\n%s'%((i+1)*10+index,x[i]) for i in range(len(x))])
+
+def _points(plist):
+ """Convert a list of tuples to dxf points"""
+ out = '\n'.join([_point(plist[i],i)for i in range(len(plist))])
+ #print 'deb: points=\n', out #-------------------
+ return out
+
+#---base classes----------------------------------------
+class _Call:
+ """Makes a callable class."""
+ def copy(self):
+ """Returns a copy."""
+ return copy.deepcopy(self)
+
+ def __call__(self,**attrs):
+ """Returns a copy with modified attributes."""
+ copied=self.copy()
+ for attr in attrs:setattr(copied,attr,attrs[attr])
+ return copied
+
+#-------------------------------------------------------
+class _Entity(_Call):
+ """Base class for _common group codes for entities."""
+ def __init__(self,color=None,extrusion=None,layer='0',
+ lineType=None,lineTypeScale=None,lineWeight=None,
+ thickness=None,parent=None):
+ """None values will be omitted."""
+ self.color = color
+ self.extrusion = extrusion
+ self.layer = layer
+ self.lineType = lineType
+ self.lineTypeScale = lineTypeScale
+ self.lineWeight = lineWeight
+ self.thickness = thickness
+ self.parent = parent
+
+ def _common(self):
+ """Return common group codes as a string."""
+ if self.parent:parent=self.parent
+ else:parent=self
+ result =''
+ if parent.layer!=None: result+=' 8\n%s\n'%parent.layer
+ if parent.color!=None: result+=' 62\n%s\n'%parent.color
+ if parent.extrusion!=None: result+='%s\n'%_point(parent.extrusion,200)
+ if parent.lineType!=None: result+=' 6\n%s\n'%parent.lineType
+ #TODO: if parent.lineWeight!=None: result+='370\n%s\n'%parent.lineWeight
+ if parent.lineTypeScale!=None: result+=' 48\n%s\n'%parent.lineTypeScale
+ if parent.thickness!=None: result+=' 39\n%s\n'%parent.thickness
+ return result
+
+#--------------------------
+class _Entities:
+ """Base class to deal with composed objects."""
+ def __dxf__(self):
+ return []
+
+ def __str__(self):
+ return ''.join([str(x) for x in self.__dxf__()])
+
+#--------------------------
+class _Collection(_Call):
+ """Base class to expose entities methods to main object."""
+ def __init__(self,entities=[]):
+ self.entities=copy.copy(entities)
+ #link entities methods to drawing
+ for attr in dir(self.entities):
+ if attr[0]!='_':
+ attrObject=getattr(self.entities,attr)
+ if callable(attrObject):
+ setattr(self,attr,attrObject)
+
+####2) Constants
+#---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)
+
+#---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
+
+#---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
+
+####3) Classes
+#---entitities -----------------------------------------------
+#--------------------------
+class Arc(_Entity):
+ """Arc, angles in degrees."""
+ def __init__(self,center=(0,0,0),radius=1,
+ startAngle=0.0,endAngle=90,**common):
+ """Angles in degrees."""
+ _Entity.__init__(self,**common)
+ self.center=center
+ self.radius=radius
+ self.startAngle=startAngle
+ self.endAngle=endAngle
+ def __str__(self):
+ return ' 0\nARC\n%s%s\n 40\n%s\n 50\n%s\n 51\n%s\n'%\
+ (self._common(),_point(self.center),
+ self.radius,self.startAngle,self.endAngle)
+
+#-----------------------------------------------
+class Circle(_Entity):
+ """Circle"""
+ def __init__(self,center=(0,0,0),radius=1,**common):
+ _Entity.__init__(self,**common)
+ self.center=center
+ self.radius=radius
+ def __str__(self):
+ return ' 0\nCIRCLE\n%s%s\n 40\n%s\n'%\
+ (self._common(),_point(self.center),self.radius)
+
+#-----------------------------------------------
+class Face(_Entity):
+ """3dface"""
+ def __init__(self,points,**common):
+ _Entity.__init__(self,**common)
+ if len(points)<4: #fix for r12 format
+ points.append(points[-1])
+ self.points=points
+
+ def __str__(self):
+ out = ' 0\n3DFACE\n%s%s\n' %(self._common(),_points(self.points))
+ #print 'deb:out=', out #-------------------
+ return out
+
+#-----------------------------------------------
+class Insert(_Entity):
+ """Block instance."""
+ def __init__(self,name,point=(0,0,0),
+ xscale=None,yscale=None,zscale=None,
+ cols=None,colspacing=None,rows=None,rowspacing=None,
+ rotation=None,
+ **common):
+ _Entity.__init__(self,**common)
+ self.name=name
+ self.point=point
+ self.xscale=xscale
+ self.yscale=yscale
+ self.zscale=zscale
+ self.cols=cols
+ self.colspacing=colspacing
+ self.rows=rows
+ self.rowspacing=rowspacing
+ self.rotation=rotation
+
+ def __str__(self):
+ result=' 0\nINSERT\n 2\n%s\n%s\n%s\n'%\
+ (self.name,self._common(),_point(self.point))
+ if self.xscale!=None:result+=' 41\n%s\n'%self.xscale
+ if self.yscale!=None:result+=' 42\n%s\n'%self.yscale
+ if self.zscale!=None:result+=' 43\n%s\n'%self.zscale
+ if self.rotation:result+=' 50\n%s\n'%self.rotation
+ if self.cols!=None:result+=' 70\n%s\n'%self.cols
+ if self.colspacing!=None:result+=' 44\n%s\n'%self.colspacing
+ if self.rows!=None:result+=' 71\n%s\n'%self.rows
+ if self.rowspacing!=None:result+=' 45\n%s\n'%self.rowspacing
+ return result
+
+#-----------------------------------------------
+class Line(_Entity):
+ """Line"""
+ def __init__(self,points,**common):
+ _Entity.__init__(self,**common)
+ self.points=points
+ def __str__(self):
+ return ' 0\nLINE\n%s%s\n' %(
+ self._common(), _points(self.points))
+
+
+#-----------------------------------------------
+class PolyLine(_Entity):
+ def __init__(self,points,org_point=[0,0,0],flag=0,width=None,**common):
+ _Entity.__init__(self,**common)
+ self.points=points
+ self.org_point=org_point
+ self.flag=flag
+ if self.flag==64:
+ self.points=points[0]
+ self.faces=points[1]
+ self.p_count=len(self.points)
+ self.f_count=len(self.faces)
+ self.width=width
+
+ def __str__(self):
+ result= ' 0\nPOLYLINE\n%s 70\n%s\n' %(self._common(),self.flag)
+ #print 'deb: self._common()', self._common() #----------
+ result+=' 66\n1\n'
+ result+='%s\n' %_point(self.org_point)
+ if self.flag==64:
+ result+=' 71\n%s\n' %self.p_count
+ result+=' 72\n%s\n' %self.f_count
+ for point in self.points:
+ result+=' 0\nVERTEX\n'
+ result+=' 8\n%s\n' %self.layer
+ result+='%s\n' %_point(point)
+ if self.flag==64: result+=' 70\n192\n'
+ if self.width: result+=' 40\n%s\n 41\n%s\n' %(self.width,self.width)
+ if self.flag==64:
+ for face in self.faces:
+ result+=' 0\nVERTEX\n'
+ result+=' 8\n%s\n' %self.layer
+ result+='%s\n' %_point(self.org_point)
+ result+=' 70\n128\n'
+ result+=' 71\n%s\n' %face[0]
+ result+=' 72\n%s\n' %face[1]
+ result+=' 73\n%s\n' %face[2]
+ if len(face)==4: result+=' 74\n%s\n' %face[3]
+ result+=' 0\nSEQEND\n'
+ result+=' 8\n%s\n' %self.layer
+ return result
+
+#-----------------------------------------------
+class Point(_Entity):
+ """Colored solid fill."""
+ def __init__(self,points=None,**common):
+ _Entity.__init__(self,**common)
+ self.points=points
+
+#-----------------------------------------------
+class Solid(_Entity):
+ """Colored solid fill."""
+ def __init__(self,points=None,**common):
+ _Entity.__init__(self,**common)
+ self.points=points
+ def __str__(self):
+ return ' 0\nSOLID\n%s%s\n' %(self._common(),
+ _points(self.points[:2]+[self.points[3],self.points[2]])
+ )
+
+
+#-----------------------------------------------
+class Text(_Entity):
+ """Single text line."""
+ def __init__(self,text='',point=(0,0,0),alignment=None,
+ flag=None,height=1,justifyhor=None,justifyver=None,
+ rotation=None,obliqueAngle=None,style=None,xscale=None,**common):
+ _Entity.__init__(self,**common)
+ self.text=text
+ self.point=point
+ self.alignment=alignment
+ self.flag=flag
+ self.height=height
+ self.justifyhor=justifyhor
+ self.justifyver=justifyver
+ self.rotation=rotation
+ self.obliqueAngle=obliqueAngle
+ self.style=style
+ self.xscale=xscale
+ def __str__(self):
+ result= ' 0\nTEXT\n%s%s\n 40\n%s\n 1\n%s\n'%\
+ (self._common(),_point(self.point),self.height,self.text)
+ if self.rotation: result+=' 50\n%s\n'%self.rotation
+ if self.xscale: result+=' 41\n%s\n'%self.xscale
+ if self.obliqueAngle: result+=' 51\n%s\n'%self.obliqueAngle
+ if self.style: result+=' 7\n%s\n'%self.style
+ if self.flag: result+=' 71\n%s\n'%self.flag
+ if self.justifyhor: result+=' 72\n%s\n'%self.justifyhor
+ #TODO: if self.alignment: result+='%s\n'%_point(self.alignment,1)
+ if self.justifyver: result+=' 73\n%s\n'%self.justifyver
+ return result
+
+#-----------------------------------------------
+class Mtext(Text):
+ """Surrogate for mtext, generates some Text instances."""
+ def __init__(self,text='',point=(0,0,0),width=250,spacingFactor=1.5,down=0,spacingWidth=None,**options):
+ Text.__init__(self,text=text,point=point,**options)
+ if down:spacingFactor*=-1
+ self.spacingFactor=spacingFactor
+ self.spacingWidth=spacingWidth
+ self.width=width
+ self.down=down
+ def __str__(self):
+ texts=self.text.replace('\r\n','\n').split('\n')
+ if not self.down:texts.reverse()
+ result=''
+ x=y=0
+ if self.spacingWidth:spacingWidth=self.spacingWidth
+ else:spacingWidth=self.height*self.spacingFactor
+ for text in texts:
+ while text:
+ result+='%s\n'%Text(text[:self.width],
+ point=(self.point[0]+x*spacingWidth,
+ self.point[1]+y*spacingWidth,
+ self.point[2]),
+ alignment=self.alignment,flag=self.flag,height=self.height,
+ justifyhor=self.justifyhor,justifyver=self.justifyver,
+ rotation=self.rotation,obliqueAngle=self.obliqueAngle,
+ style=self.style,xscale=self.xscale,parent=self
+ )
+ text=text[self.width:]
+ if self.rotation:x+=1
+ else:y+=1
+ return result[1:]
+
+#-----------------------------------------------
+##class _Mtext(_Entity):
+## """Mtext not functioning for minimal dxf."""
+## def __init__(self,text='',point=(0,0,0),attachment=1,
+## charWidth=None,charHeight=1,direction=1,height=100,rotation=0,
+## spacingStyle=None,spacingFactor=None,style=None,width=100,
+## xdirection=None,**common):
+## _Entity.__init__(self,**common)
+## self.text=text
+## self.point=point
+## self.attachment=attachment
+## self.charWidth=charWidth
+## self.charHeight=charHeight
+## self.direction=direction
+## self.height=height
+## self.rotation=rotation
+## self.spacingStyle=spacingStyle
+## self.spacingFactor=spacingFactor
+## self.style=style
+## self.width=width
+## self.xdirection=xdirection
+## def __str__(self):
+## input=self.text
+## text=''
+## while len(input)>250:
+## text+='3\n%s\n'%input[:250]
+## input=input[250:]
+## text+='1\n%s\n'%input
+## result= '0\nMTEXT\n%s\n%s\n40\n%s\n41\n%s\n71\n%s\n72\n%s%s\n43\n%s\n50\n%s\n'%\
+## (self._common(),_point(self.point),self.charHeight,self.width,
+## self.attachment,self.direction,text,
+## self.height,
+## self.rotation)
+## if self.style:result+='7\n%s\n'%self.style
+## if self.xdirection:result+='%s\n'%_point(self.xdirection,1)
+## if self.charWidth:result+='42\n%s\n'%self.charWidth
+## if self.spacingStyle:result+='73\n%s\n'%self.spacingStyle
+## if self.spacingFactor:result+='44\n%s\n'%self.spacingFactor
+## return result
+
+#---tables ---------------------------------------------------
+#-----------------------------------------------
+class Block(_Collection):
+ """Use list methods to add entities, eg append."""
+ def __init__(self,name,layer='0',flag=0,base=(0,0,0),entities=[]):
+ self.entities=copy.copy(entities)
+ _Collection.__init__(self,entities)
+ self.layer=layer
+ self.name=name
+ self.flag=0
+ self.base=base
+ def __str__(self):
+ e=''.join([str(x)for x in self.entities])
+ return ' 0\nBLOCK\n 8\n%s\n 2\n%s\n 70\n%s\n%s\n 3\n%s\n%s 0\nENDBLK\n'%\
+ (self.layer,self.name.upper(),self.flag,_point(self.base),self.name.upper(),e)
+
+#-----------------------------------------------
+class Layer(_Call):
+ """Layer"""
+ def __init__(self,name='pydxf',color=7,lineType='continuous',flag=64):
+ self.name=name
+ self.color=color
+ self.lineType=lineType
+ self.flag=flag
+ def __str__(self):
+ return ' 0\nLAYER\n 2\n%s\n 70\n%s\n 62\n%s\n 6\n%s\n'%\
+ (self.name.upper(),self.flag,self.color,self.lineType)
+
+#-----------------------------------------------
+class LineType(_Call):
+ """Custom linetype"""
+ def __init__(self,name='continuous',description='Solid line',elements=[],flag=64):
+ # TODO: Implement lineType elements
+ self.name=name
+ self.description=description
+ self.elements=copy.copy(elements)
+ self.flag=flag
+ def __str__(self):
+ return ' 0\nLTYPE\n 2\n%s\n 70\n%s\n 3\n%s\n 72\n65\n 73\n%s\n 40\n0.0\n'%\
+ (self.name.upper(),self.flag,self.description,len(self.elements))
+
+#-----------------------------------------------
+class Style(_Call):
+ """Text style"""
+ def __init__(self,name='standard',flag=0,height=0,widthFactor=40,obliqueAngle=50,
+ mirror=0,lastHeight=1,font='arial.ttf',bigFont=''):
+ self.name=name
+ self.flag=flag
+ self.height=height
+ self.widthFactor=widthFactor
+ self.obliqueAngle=obliqueAngle
+ self.mirror=mirror
+ self.lastHeight=lastHeight
+ self.font=font
+ self.bigFont=bigFont
+ def __str__(self):
+ return ' 0\nSTYLE\n 2\n%s\n 70\n%s\n 40\n%s\n 41\n%s\n 50\n%s\n 71\n%s\n 42\n%s\n 3\n%s\n 4\n%s\n'%\
+ (self.name.upper(),self.flag,self.flag,self.widthFactor,
+ self.obliqueAngle,self.mirror,self.lastHeight,
+ self.font.upper(),self.bigFont.upper())
+
+#-----------------------------------------------
+class View(_Call):
+ def __init__(self,name,flag=0,width=1,height=1,center=(0.5,0.5),
+ direction=(0,0,1),target=(0,0,0),lens=50,
+ frontClipping=0,backClipping=0,twist=0,mode=0):
+ self.name=name
+ self.flag=flag
+ self.width=width
+ self.height=height
+ self.center=center
+ self.direction=direction
+ self.target=target
+ self.lens=lens
+ self.frontClipping=frontClipping
+ self.backClipping=backClipping
+ self.twist=twist
+ self.mode=mode
+ def __str__(self):
+ return ' 0\nVIEW\n 2\n%s\n 70\n%s\n 40\n%s\n%s\n 41\n%s\n%s\n%s\n 42\n%s\n 43\n%s\n 44\n%s\n 50\n%s\n 71\n%s\n'%\
+ (self.name,self.flag,self.height,_point(self.center),self.width,
+ _point(self.direction,1),_point(self.target,2),self.lens,
+ self.frontClipping,self.backClipping,self.twist,self.mode)
+
+#-----------------------------------------------
+def ViewByWindow(name,leftBottom=(0,0),rightTop=(1,1),**options):
+ width=abs(rightTop[0]-leftBottom[0])
+ height=abs(rightTop[1]-leftBottom[1])
+ center=((rightTop[0]+leftBottom[0])*0.5,(rightTop[1]+leftBottom[1])*0.5)
+ return View(name=name,width=width,height=height,center=center,**options)
+
+#---drawing
+#-----------------------------------------------
+class Drawing(_Collection):
+ """Dxf drawing. Use append or any other list methods to add objects."""
+ def __init__(self,insbase=(0.0,0.0,0.0),extmin=(0.0,0.0),extmax=(0.0,0.0),
+ layers=[Layer()],linetypes=[LineType()],styles=[Style()],blocks=[],
+ views=[],entities=None,fileName='test.dxf'):
+ # TODO: replace list with None,arial
+ if not entities:entities=[]
+ _Collection.__init__(self,entities)
+ self.insbase=insbase
+ self.extmin=extmin
+ self.extmax=extmax
+ self.layers=copy.copy(layers)
+ self.linetypes=copy.copy(linetypes)
+ self.styles=copy.copy(styles)
+ self.views=copy.copy(views)
+ self.blocks=copy.copy(blocks)
+ self.fileName=fileName
+ #private
+ #self.acadver='9\n$ACADVER\n1\nAC1006\n'
+ self.acadver=' 9\n$ACADVER\n 1\nAC1009\n'
+ """DXF AutoCAD-Release format codes
+ AC1021 2008, 2007
+ AC1018 2006, 2005, 2004
+ AC1015 2002, 2000i, 2000
+ AC1014 R14,14.01
+ AC1012 R13
+ AC1009 R12,11
+ AC1006 R10
+ AC1004 R9
+ AC1002 R2.6
+ AC1.50 R2.05
+ """
+
+ def _name(self,x):
+ """Helper function for self._point"""
+ return ' 9\n$%s\n' %x.upper()
+
+ def _point(self,name,x):
+ """Point setting from drawing like extmin,extmax,..."""
+ return '%s%s' %(self._name(name),_point(x))
+
+ def _section(self,name,x):
+ """Sections like tables,blocks,entities,..."""
+ if x: xstr=''.join(x)
+ else: xstr=''
+ return ' 0\nSECTION\n 2\n%s\n%s 0\nENDSEC\n'%(name.upper(),xstr)
+
+ def _table(self,name,x):
+ """Tables like ltype,layer,style,..."""
+ if x: xstr=''.join(x)
+ else: xstr=''
+ return ' 0\nTABLE\n 2\n%s\n 70\n%s\n%s 0\nENDTAB\n'%(name.upper(),len(x),xstr)
+
+ def __str__(self):
+ """Returns drawing as dxf string."""
+ header=[self.acadver]+[self._point(attr,getattr(self,attr))+'\n' for attr in _HEADER_POINTS]
+ header=self._section('header',header)
+
+ tables=[self._table('ltype',[str(x) for x in self.linetypes]),
+ self._table('layer',[str(x) for x in self.layers]),
+ self._table('style',[str(x) for x in self.styles]),
+ self._table('view',[str(x) for x in self.views]),
+ ]
+ tables=self._section('tables',tables)
+
+ blocks=self._section('blocks',[str(x) for x in self.blocks])
+
+ entities=self._section('entities',[str(x) for x in self.entities])
+
+ all=''.join([header,tables,blocks,entities,' 0\nEOF\n'])
+ return all
+
+ def saveas(self,fileName):
+ self.fileName=fileName
+ self.save()
+
+ def save(self):
+ test=open(self.fileName,'w')
+ test.write(str(self))
+ test.close()
+
+
+#---extras
+#-----------------------------------------------
+class Rectangle(_Entity):
+ """Rectangle, creates lines."""
+ def __init__(self,point=(0,0,0),width=1,height=1,solid=None,line=1,**common):
+ _Entity.__init__(self,**common)
+ self.point=point
+ self.width=width
+ self.height=height
+ self.solid=solid
+ self.line=line
+ def __str__(self):
+ result=''
+ points=[self.point,(self.point[0]+self.width,self.point[1],self.point[2]),
+ (self.point[0]+self.width,self.point[1]+self.height,self.point[2]),
+ (self.point[0],self.point[1]+self.height,self.point[2]),self.point]
+ if self.solid:
+ result+= Solid(points=points[:-1],parent=self.solid)
+ if self.line:
+ for i in range(4):
+ result+= Line(points=[points[i],points[i+1]],parent=self)
+ return result[1:]
+
+#-----------------------------------------------
+class LineList(_Entity):
+ """Like polyline, but built of individual lines."""
+ def __init__(self,points=[],org_point=[0,0,0],closed=0,**common):
+ _Entity.__init__(self,**common)
+ self.closed=closed
+ self.points=copy.copy(points)
+ def __str__(self):
+ if self.closed:points=self.points+[self.points[0]]
+ else: points=self.points
+ result=''
+ for i in range(len(points)-1):
+ result+= Line(points=[points[i],points[i+1]],parent=self)
+ return result[1:]
+
+#-----------------------------------------------------
+def test():
+ #Blocks
+ b=Block('test')
+ b.append(Solid(points=[(0,0,0),(1,0,0),(1,1,0),(0,1,0)],color=1))
+ b.append(Arc(center=(1,0,0),color=2))
+
+ #Drawing
+ d=Drawing()
+ #tables
+ d.blocks.append(b) #table blocks
+ d.styles.append(Style()) #table styles
+ d.views.append(View('Normal')) #table view
+ d.views.append(ViewByWindow('Window',leftBottom=(1,0),rightTop=(2,1))) #idem
+
+ #entities
+ d.append(Circle(center=(1,1,0),color=3))
+ d.append(Face(points=[(0,0,0),(1,0,0),(1,1,0),(0,1,0)],color=4))
+ d.append(Insert('test',point=(3,3,3),cols=5,colspacing=2))
+ d.append(Line(points=[(0,0,0),(1,1,1)]))
+ d.append(Mtext('Click on Ads\nmultiple lines with mtext',point=(1,1,1),color=5,rotation=90))
+ d.append(Text('Please donate!',point=(3,0,1)))
+ d.append(Rectangle(point=(2,2,2),width=4,height=3,color=6,solid=Solid(color=2)))
+ d.append(Solid(points=[(4,4,0),(5,4,0),(7,8,0),(9,9,0)],color=3))
+ d.append(PolyLine(points=[(1,1,1),(2,1,1),(2,2,1),(1,2,1)],closed=1,color=1))
+
+ #d.saveas('c:\\test.dxf')
+ d.saveas('test.dxf')
+
+
+#-----------------------------------------------------
+if __name__=='__main__':
+ if not copy:
+ Draw.PupMenu('Error%t|This script requires a full python install')
+ main()
+ \ No newline at end of file
diff --git a/release/scripts/bpymodules/dxfReader.py b/release/scripts/bpymodules/dxfReader.py
index d4a39cf63d6..df4ebc309e4 100644
--- a/release/scripts/bpymodules/dxfReader.py
+++ b/release/scripts/bpymodules/dxfReader.py
@@ -1,11 +1,12 @@
"""This module provides a function for reading dxf files and parsing them into a useful tree of objects and data.
- The convert function is called by the readDXF fuction to convert dxf strings into the correct data based
- on their type code. readDXF expects a (full path) file name as input.
+ The convert function is called by the readDXF fuction to convert dxf strings into the correct data based
+ on their type code. readDXF expects a (full path) file name as input.
"""
# --------------------------------------------------------------------------
# DXF Reader v0.9 by Ed Blake (AKA Kitsu)
+# 2008.05.08 modif.def convert() by Remigiusz Fiedler (AKA migius)
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
@@ -30,215 +31,215 @@
#from dxfImportObjects import *
class Object:
- """Empty container class for dxf objects"""
-
- def __init__(self, _type='', block=False):
- """_type expects a string value."""
- self.type = _type
- self.name = ''
- self.data = []
-
- def __str__(self):
- if self.name:
- return self.name
- else:
- return self.type
-
- def __repr__(self):
- return str(self.data)
-
- def get_type(self, kind=''):
- """Despite the name, this method actually returns all objects of type 'kind' from self.data."""
- if type:
- objects = []
- for item in self.data:
- if type(item) != list and item.type == kind:
- # we want this type of object
- objects.append(item)
- elif type(item) == list and item[0] == kind:
- # we want this type of data
- objects.append(item[1])
- return objects
-
+ """Empty container class for dxf objects"""
+
+ def __init__(self, _type='', block=False):
+ """_type expects a string value."""
+ self.type = _type
+ self.name = ''
+ self.data = []
+
+ def __str__(self):
+ if self.name:
+ return self.name
+ else:
+ return self.type
+
+ def __repr__(self):
+ return str(self.data)
+
+ def get_type(self, kind=''):
+ """Despite the name, this method actually returns all objects of type 'kind' from self.data."""
+ if type:
+ objects = []
+ for item in self.data:
+ if type(item) != list and item.type == kind:
+ # we want this type of object
+ objects.append(item)
+ elif type(item) == list and item[0] == kind:
+ # we want this type of data
+ objects.append(item[1])
+ return objects
+
class InitializationError(Exception): pass
class StateMachine:
- """(finite) State Machine from the great David Mertz's great Charming Python article."""
-
- def __init__(self):
- self.handlers = []
- self.startState = None
- self.endStates = []
-
- def add_state(self, handler, end_state=0):
- """All states and handlers are functions which return
- a state and a cargo."""
- self.handlers.append(handler)
- if end_state:
- self.endStates.append(handler)
- def set_start(self, handler):
- """Sets the starting handler function."""
- self.startState = handler
-
-
- def run(self, cargo=None):
- if not self.startState:
- raise InitializationError,\
- "must call .set_start() before .run()"
- if not self.endStates:
- raise InitializationError, \
- "at least one state must be an end_state"
- handler = self.startState
- while 1:
- (newState, cargo) = handler(cargo)
- #print cargo
- if newState in self.endStates:
- return newState(cargo)
- #break
- elif newState not in self.handlers:
- raise RuntimeError, "Invalid target %s" % newState
- else:
- handler = newState
+ """(finite) State Machine from the great David Mertz's great Charming Python article."""
+
+ def __init__(self):
+ self.handlers = []
+ self.startState = None
+ self.endStates = []
+
+ def add_state(self, handler, end_state=0):
+ """All states and handlers are functions which return
+ a state and a cargo."""
+ self.handlers.append(handler)
+ if end_state:
+ self.endStates.append(handler)
+ def set_start(self, handler):
+ """Sets the starting handler function."""
+ self.startState = handler
+
+
+ def run(self, cargo=None):
+ if not self.startState:
+ raise InitializationError,\
+ "must call .set_start() before .run()"
+ if not self.endStates:
+ raise InitializationError, \
+ "at least one state must be an end_state"
+ handler = self.startState
+ while 1:
+ (newState, cargo) = handler(cargo)
+ #print cargo
+ if newState in self.endStates:
+ return newState(cargo)
+ #break
+ elif newState not in self.handlers:
+ raise RuntimeError, "Invalid target %s" % newState
+ else:
+ handler = newState
def get_name(data):
- """Get the name of an object from its object data.
-
- Returns a pair of (data_item, name) where data_item is the list entry where the name was found
- (the data_item can be used to remove the entry from the object data). Be sure to check
- name not None before using the returned values!
- """
- value = None
- for item in data:
- if item[0] == 2:
- value = item[1]
- break
- return item, value
+ """Get the name of an object from its object data.
+
+ Returns a pair of (data_item, name) where data_item is the list entry where the name was found
+ (the data_item can be used to remove the entry from the object data). Be sure to check
+ name not None before using the returned values!
+ """
+ value = None
+ for item in data:
+ if item[0] == 2:
+ value = item[1]
+ break
+ return item, value
def get_layer(data):
- """Expects object data as input.
-
- Returns (entry, layer_name) where entry is the data item that provided the layer name.
- """
- value = None
- for item in data:
- if item[0] == 8:
- value = item[1]
- break
- return item, value
+ """Expects object data as input.
+
+ Returns (entry, layer_name) where entry is the data item that provided the layer name.
+ """
+ value = None
+ for item in data:
+ if item[0] == 8:
+ value = item[1]
+ break
+ return item, value
def convert(code, value):
- """Convert a string to the correct Python type based on its dxf code.
- code types:
- ints = 60-79, 170-179, 270-289, 370-389, 400-409, 1060-1070
- longs = 90-99, 420-429, 440-459, 1071
- floats = 10-39, 40-59, 110-139, 140-149, 210-239, 460-469, 1010-1059
- hex = 105, 310-379, 390-399
- strings = 0-9, 100, 102, 300-309, 410-419, 430-439, 470-479, 999, 1000-1009
- """
- if 59 < code < 80 or 169 < code < 180 or 269 < code < 290 or 369 < code < 390 or 399 < code < 410 or 1059 < code < 1071:
- value = int(value)
- elif 89 < code < 100 or 419 < code < 430 or 439 < code < 460 or code == 1071:
- value = long(value)
- elif 9 < code < 60 or 109 < code < 150 or 209 < code < 240 or 459 < code < 470 or 1009 < code < 1060:
- value = float(value)
- elif code == 105 or 309 < code < 380 or 389 < code < 400:
- value = int(value, 16) # should be left as string?
- else: # it's already a string so do nothing
- pass
- return value
+ """Convert a string to the correct Python type based on its dxf code.
+ code types:
+ ints = 60-79, 170-179, 270-289, 370-389, 400-409, 1060-1070
+ longs = 90-99, 420-429, 440-459, 1071
+ floats = 10-39, 40-59, 110-139, 140-149, 210-239, 460-469, 1010-1059
+ hex = 105, 310-379, 390-399
+ strings = 0-9, 100, 102, 300-309, 410-419, 430-439, 470-479, 999, 1000-1009
+ """
+ if 59 < code < 80 or 169 < code < 180 or 269 < code < 290 or 369 < code < 390 or 399 < code < 410 or 1059 < code < 1071:
+ value = int(float(value))
+ elif 89 < code < 100 or 419 < code < 430 or 439 < code < 460 or code == 1071:
+ value = long(float(value))
+ elif 9 < code < 60 or 109 < code < 150 or 209 < code < 240 or 459 < code < 470 or 1009 < code < 1060:
+ value = float(value)
+ elif code == 105 or 309 < code < 380 or 389 < code < 400:
+ value = int(value, 16) # should be left as string?
+ else: # it's already a string so do nothing
+ pass
+ return value
def findObject(infile, kind=''):
- """Finds the next occurance of an object."""
- obj = False
- while 1:
- line = infile.readline()
- if not line: # readline returns '' at eof
- return False
- if not obj: # We're still looking for our object code
- if line.lower().strip() == '0':
- obj = True # found it
- else: # we are in an object definition
- if kind: # if we're looking for a particular kind
- if line.lower().strip() == kind:
- obj = Object(line.lower().strip())
- break
- else: # otherwise take anything non-numeric
- if line.lower().strip() not in string.digits:
- obj = Object(line.lower().strip())
- break
- obj = False # whether we found one or not it's time to start over
- return obj
+ """Finds the next occurance of an object."""
+ obj = False
+ while 1:
+ line = infile.readline()
+ if not line: # readline returns '' at eof
+ return False
+ if not obj: # We're still looking for our object code
+ if line.lower().strip() == '0':
+ obj = True # found it
+ else: # we are in an object definition
+ if kind: # if we're looking for a particular kind
+ if line.lower().strip() == kind:
+ obj = Object(line.lower().strip())
+ break
+ else: # otherwise take anything non-numeric
+ if line.lower().strip() not in string.digits:
+ obj = Object(line.lower().strip())
+ break
+ obj = False # whether we found one or not it's time to start over
+ return obj
def handleObject(infile):
- """Add data to an object until end of object is found."""
- line = infile.readline()
- if line.lower().strip() == 'section':
- return 'section' # this would be a problem
- elif line.lower().strip() == 'endsec':
- return 'endsec' # this means we are done with a section
- else: # add data to the object until we find a new object
- obj = Object(line.lower().strip())
- obj.name = obj.type
- done = False
- data = []
- while not done:
- line = infile.readline()
- if not data:
- if line.lower().strip() == '0':
- #we've found an object, time to return
- return obj
- else:
- # first part is always an int
- data.append(int(line.lower().strip()))
- else:
- data.append(convert(data[0], line.strip()))
- obj.data.append(data)
- data = []
+ """Add data to an object until end of object is found."""
+ line = infile.readline()
+ if line.lower().strip() == 'section':
+ return 'section' # this would be a problem
+ elif line.lower().strip() == 'endsec':
+ return 'endsec' # this means we are done with a section
+ else: # add data to the object until we find a new object
+ obj = Object(line.lower().strip())
+ obj.name = obj.type
+ done = False
+ data = []
+ while not done:
+ line = infile.readline()
+ if not data:
+ if line.lower().strip() == '0':
+ #we've found an object, time to return
+ return obj
+ else:
+ # first part is always an int
+ data.append(int(line.lower().strip()))
+ else:
+ data.append(convert(data[0], line.strip()))
+ obj.data.append(data)
+ data = []
def handleTable(table, infile):
- """Special handler for dealing with nested table objects."""
- item, name = get_name(table.data)
- if name: # We should always find a name
- table.data.remove(item)
- table.name = name.lower()
- # This next bit is from handleObject
- # handleObject should be generalized to work with any section like object
- while 1:
- obj = handleObject(infile)
- if obj.type == 'table':
- print "Warning: previous table not closed!"
- return table
- elif obj.type == 'endtab':
- return table # this means we are done with the table
- else: # add objects to the table until one of the above is found
- table.data.append(obj)
-
-
-
+ """Special handler for dealing with nested table objects."""
+ item, name = get_name(table.data)
+ if name: # We should always find a name
+ table.data.remove(item)
+ table.name = name.lower()
+ # This next bit is from handleObject
+ # handleObject should be generalized to work with any section like object
+ while 1:
+ obj = handleObject(infile)
+ if obj.type == 'table':
+ print "Warning: previous table not closed!"
+ return table
+ elif obj.type == 'endtab':
+ return table # this means we are done with the table
+ else: # add objects to the table until one of the above is found
+ table.data.append(obj)
+
+
+
def handleBlock(block, infile):
- """Special handler for dealing with nested table objects."""
- item, name = get_name(block.data)
- if name: # We should always find a name
- block.data.remove(item)
- block.name = name
- # This next bit is from handleObject
- # handleObject should be generalized to work with any section like object
- while 1:
- obj = handleObject(infile)
- if obj.type == 'block':
- print "Warning: previous block not closed!"
- return block
- elif obj.type == 'endblk':
- return block # this means we are done with the table
- else: # add objects to the table until one of the above is found
- block.data.append(obj)
-
-
-
+ """Special handler for dealing with nested table objects."""
+ item, name = get_name(block.data)
+ if name: # We should always find a name
+ block.data.remove(item)
+ block.name = name
+ # This next bit is from handleObject
+ # handleObject should be generalized to work with any section like object
+ while 1:
+ obj = handleObject(infile)
+ if obj.type == 'block':
+ print "Warning: previous block not closed!"
+ return block
+ elif obj.type == 'endblk':
+ return block # this means we are done with the table
+ else: # add objects to the table until one of the above is found
+ block.data.append(obj)
+
+
+
"""These are the states/functions used in the State Machine.
states:
@@ -250,133 +251,131 @@ states:
"""
def start(cargo):
- """Expects the infile as cargo, initializes the cargo."""
- #print "Entering start state!"
- infile = cargo
- drawing = Object('drawing')
- section = findObject(infile, 'section')
- if section:
- return start_section, (infile, drawing, section)
- else:
- return error, (infile, "Failed to find any sections!")
+ """Expects the infile as cargo, initializes the cargo."""
+ #print "Entering start state!"
+ infile = cargo
+ drawing = Object('drawing')
+ section = findObject(infile, 'section')
+ if section:
+ return start_section, (infile, drawing, section)
+ else:
+ return error, (infile, "Failed to find any sections!")
def start_section(cargo):
- """Expects [infile, drawing, section] as cargo, builds a nested section object."""
- #print "Entering start_section state!"
- infile = cargo[0]
- drawing = cargo[1]
- section = cargo[2]
- # read each line, if it is an object declaration go to object mode
- # otherwise create a [index, data] pair and add it to the sections data.
- done = False
- data = []
- while not done:
- line = infile.readline()
-
- if not data: # if we haven't found a dxf code yet
- if line.lower().strip() == '0':
- # we've found an object
- while 1: # no way out unless we find an end section or a new section
- obj = handleObject(infile)
- if obj == 'section': # shouldn't happen
- print "Warning: failed to close previous section!"
- return end_section, (infile, drawing)
- elif obj == 'endsec': # This section is over, look for the next
- drawing.data.append(section)
- return end_section, (infile, drawing)
- elif obj.type == 'table': # tables are collections of data
- obj = handleTable(obj, infile) # we need to find all there contents
- section.data.append(obj) # before moving on
- elif obj.type == 'block': # the same is true of blocks
- obj = handleBlock(obj, infile) # we need to find all there contents
- section.data.append(obj) # before moving on
- else: # found another sub-object
- section.data.append(obj)
- else:
- data.append(int(line.lower().strip()))
- else: # we have our code, now we just need to convert the data and add it to our list.
- data.append(convert(data[0], line.strip()))
- section.data.append(data)
- data = []
+ """Expects [infile, drawing, section] as cargo, builds a nested section object."""
+ #print "Entering start_section state!"
+ infile = cargo[0]
+ drawing = cargo[1]
+ section = cargo[2]
+ # read each line, if it is an object declaration go to object mode
+ # otherwise create a [index, data] pair and add it to the sections data.
+ done = False
+ data = []
+ while not done:
+ line = infile.readline()
+
+ if not data: # if we haven't found a dxf code yet
+ if line.lower().strip() == '0':
+ # we've found an object
+ while 1: # no way out unless we find an end section or a new section
+ obj = handleObject(infile)
+ if obj == 'section': # shouldn't happen
+ print "Warning: failed to close previous section!"
+ return end_section, (infile, drawing)
+ elif obj == 'endsec': # This section is over, look for the next
+ drawing.data.append(section)
+ return end_section, (infile, drawing)
+ elif obj.type == 'table': # tables are collections of data
+ obj = handleTable(obj, infile) # we need to find all there contents
+ section.data.append(obj) # before moving on
+ elif obj.type == 'block': # the same is true of blocks
+ obj = handleBlock(obj, infile) # we need to find all there contents
+ section.data.append(obj) # before moving on
+ else: # found another sub-object
+ section.data.append(obj)
+ else:
+ data.append(int(line.lower().strip()))
+ else: # we have our code, now we just need to convert the data and add it to our list.
+ data.append(convert(data[0], line.strip()))
+ section.data.append(data)
+ data = []
def end_section(cargo):
- """Expects (infile, drawing) as cargo, searches for next section."""
- #print "Entering end_section state!"
- infile = cargo[0]
- drawing = cargo[1]
- section = findObject(infile, 'section')
- if section:
- return start_section, (infile, drawing, section)
- else:
- return end, (infile, drawing)
+ """Expects (infile, drawing) as cargo, searches for next section."""
+ #print "Entering end_section state!"
+ infile = cargo[0]
+ drawing = cargo[1]
+ section = findObject(infile, 'section')
+ if section:
+ return start_section, (infile, drawing, section)
+ else:
+ return end, (infile, drawing)
def end(cargo):
- """Expects (infile, drawing) as cargo, called when eof has been reached."""
- #print "Entering end state!"
- infile = cargo[0]
- drawing = cargo[1]
- #infile.close()
- return drawing
+ """Expects (infile, drawing) as cargo, called when eof has been reached."""
+ #print "Entering end state!"
+ infile = cargo[0]
+ drawing = cargo[1]
+ #infile.close()
+ return drawing
def error(cargo):
- """Expects a (infile, string) as cargo, called when there is an error during processing."""
- #print "Entering error state!"
- infile = cargo[0]
- err = cargo[1]
- infile.close()
- print "There has been an error:"
- print err
- return False
+ """Expects a (infile, string) as cargo, called when there is an error during processing."""
+ #print "Entering error state!"
+ infile = cargo[0]
+ err = cargo[1]
+ infile.close()
+ print "There has been an error:"
+ print err
+ return False
def readDXF(filename, objectify):
- """Given a file name try to read it as a dxf file.
-
- Output is an object with the following structure
- drawing
- header
- header data
- classes
- class data
- tables
- table data
- blocks
- block data
- entities
- entity data
- objects
- object data
- where foo data is a list of sub-objects. True object data
- is of the form [code, data].
-"""
- infile = open(filename)
-
- sm = StateMachine()
- sm.add_state(error, True)
- sm.add_state(end, True)
- sm.add_state(start_section)
- sm.add_state(end_section)
- sm.add_state(start)
- sm.set_start(start)
- try:
- drawing = sm.run(infile)
- if drawing:
- drawing.name = filename
- for obj in drawing.data:
- item, name = get_name(obj.data)
- if name:
- obj.data.remove(item)
- obj.name = name.lower()
- setattr(drawing, name.lower(), obj)
- # Call the objectify function to cast
- # raw objects into the right types of object
- obj.data = objectify(obj.data)
- #print obj.name
- finally:
- infile.close()
- return drawing
-if __name__ == "__main__":
- filename = r".\examples\block-test.dxf"
- drawing = readDXF(filename)
- for item in drawing.entities.data:
- print item
+ """Given a file name try to read it as a dxf file.
+ Output is an object with the following structure
+ drawing
+ header
+ header data
+ classes
+ class data
+ tables
+ table data
+ blocks
+ block data
+ entities
+ entity data
+ objects
+ object data
+ where foo data is a list of sub-objects. True object data
+ is of the form [code, data].
+"""
+ infile = open(filename)
+ sm = StateMachine()
+ sm.add_state(error, True)
+ sm.add_state(end, True)
+ sm.add_state(start_section)
+ sm.add_state(end_section)
+ sm.add_state(start)
+ sm.set_start(start)
+ try:
+ drawing = sm.run(infile)
+ if drawing:
+ drawing.name = filename
+ for obj in drawing.data:
+ item, name = get_name(obj.data)
+ if name:
+ obj.data.remove(item)
+ obj.name = name.lower()
+ setattr(drawing, name.lower(), obj)
+ # Call the objectify function to cast
+ # raw objects into the right types of object
+ obj.data = objectify(obj.data)
+ #print obj.name
+ finally:
+ infile.close()
+ return drawing
+if __name__ == "__main__":
+ filename = r".\examples\block-test.dxf"
+ drawing = readDXF(filename)
+ for item in drawing.entities.data:
+ print item
diff --git a/release/scripts/bpymodules/paths_ai2obj.py b/release/scripts/bpymodules/paths_ai2obj.py
index dcf56853184..6eb5023a8d4 100644
--- a/release/scripts/bpymodules/paths_ai2obj.py
+++ b/release/scripts/bpymodules/paths_ai2obj.py
@@ -1,3 +1,4 @@
+# -*- coding: latin-1 -*-
"""
paths_ai2obj.py
# ---------------------------------------------------------------
@@ -42,10 +43,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# Communiquer les problemes et erreurs sur:
# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender
#----------------------------------------------
+
+#Changelog
#----------------------------------------------
-#Chagelog
-#----------------------------------------------
-# 0.1.1 : 2004/08/03, bug in boudingbox reading when Value are negative
+# 0.1.1 : 2004/08/03, bug in boundingbox reading when Value are negative
# 0.1.2 : 2005/06/12, gmove tranformation properties
# 0.1.3 : 2005/06/25, added a __name__ test to use the script alone
# 0.1.4 : 2005/06/25, closepath improvements
@@ -57,6 +58,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# 0.1.8 : 2006/07/03, two more closepath improvements
# 0.1.9 : 2007/05/06, modif on the method that gets the last object on
the list data
+# 2008/03/12, Added character encoding line so french text
+# does not break python interpreters.
+
"""
SHARP_IMPORT=0
SCALE=1
diff --git a/release/scripts/bpymodules/paths_gimp2obj.py b/release/scripts/bpymodules/paths_gimp2obj.py
index 8b31c5d7294..c2ce9718c71 100644
--- a/release/scripts/bpymodules/paths_gimp2obj.py
+++ b/release/scripts/bpymodules/paths_gimp2obj.py
@@ -1,3 +1,4 @@
+# -*- coding: latin-1 -*-
"""
#----------------------------------------------
# (c) jm soler juillet 2004,
@@ -43,6 +44,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_gimp.htm
# Communiquer les problemes et erreurs sur:
# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender
+# Modification History:
+# 2008-03-12 Added character encoding line so french text does not break
+# python interpreters.
#---------------------------------------------
SHARP_IMPORT=0
diff --git a/release/scripts/bpymodules/paths_svg2obj.py b/release/scripts/bpymodules/paths_svg2obj.py
index e535af705df..de40bea3191 100644
--- a/release/scripts/bpymodules/paths_svg2obj.py
+++ b/release/scripts/bpymodules/paths_svg2obj.py
@@ -1309,8 +1309,9 @@ def curve_FILL(Courbe,proprietes):
if not 'fill:none' in pr:
Courbe[n].fill=1
if USE_COLORS:
- if '#' in pr:
- i= pr.find('fill:#')+6
+ i= pr.find('fill:#')
+ if i != -1:
+ i= i+6
Courbe[n].color=[int(pr[i:i+2],16),int(pr[i+2:i+4],16),int(pr[i+4:i+6],16)]
Courbe[n].mat=1
elif ';fill-opacity' in pr: