diff options
Diffstat (limited to 'release/scripts/bpymodules')
-rw-r--r-- | release/scripts/bpymodules/BPyAddMesh.py | 27 | ||||
-rw-r--r-- | release/scripts/bpymodules/BPyArmature.py | 75 | ||||
-rw-r--r-- | release/scripts/bpymodules/BPyRegistry.py | 41 | ||||
-rw-r--r-- | release/scripts/bpymodules/BPyRender.py | 141 | ||||
-rw-r--r-- | release/scripts/bpymodules/BPyTextPlugin.py | 814 | ||||
-rw-r--r-- | release/scripts/bpymodules/blend2renderinfo.py | 95 | ||||
-rw-r--r-- | release/scripts/bpymodules/dxfImportObjects.py | 1326 | ||||
-rw-r--r-- | release/scripts/bpymodules/dxfLibrary.py | 708 | ||||
-rw-r--r-- | release/scripts/bpymodules/dxfReader.py | 619 | ||||
-rw-r--r-- | release/scripts/bpymodules/paths_ai2obj.py | 10 | ||||
-rw-r--r-- | release/scripts/bpymodules/paths_gimp2obj.py | 4 | ||||
-rw-r--r-- | release/scripts/bpymodules/paths_svg2obj.py | 5 |
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: |