From 1dd571efee1758e622f48a42f46ce8dbc1a507af Mon Sep 17 00:00:00 2001 From: Remigiusz Fiedler Date: Tue, 10 Jul 2012 23:16:32 +0000 Subject: DXF-exporter script moved from addons_contrib to official addons folder --- io_export_dxf/__init__.py | 46 + io_export_dxf/draw_blenders/__init__.py | 87 ++ io_export_dxf/export_dxf.py | 268 ++++++ io_export_dxf/model/__init__.py | 0 io_export_dxf/model/dxfLibrary.py | 927 +++++++++++++++++++++ io_export_dxf/model/migiusModel.py | 122 +++ io_export_dxf/model/model.py | 38 + io_export_dxf/operator.py | 283 +++++++ io_export_dxf/primitive_exporters/__init__.py | 10 + io_export_dxf/primitive_exporters/base_exporter.py | 195 +++++ .../primitive_exporters/camera_exporter.py | 55 ++ .../primitive_exporters/curve_exporter.py | 260 ++++++ .../primitive_exporters/empty_exporter.py | 20 + .../primitive_exporters/insert_exporter.py | 75 ++ io_export_dxf/primitive_exporters/lamp_exporter.py | 21 + io_export_dxf/primitive_exporters/mesh_exporter.py | 154 ++++ io_export_dxf/primitive_exporters/text_exporter.py | 89 ++ .../primitive_exporters/viewborder_exporter.py | 24 + 18 files changed, 2674 insertions(+) create mode 100644 io_export_dxf/__init__.py create mode 100644 io_export_dxf/draw_blenders/__init__.py create mode 100644 io_export_dxf/export_dxf.py create mode 100644 io_export_dxf/model/__init__.py create mode 100644 io_export_dxf/model/dxfLibrary.py create mode 100644 io_export_dxf/model/migiusModel.py create mode 100644 io_export_dxf/model/model.py create mode 100644 io_export_dxf/operator.py create mode 100644 io_export_dxf/primitive_exporters/__init__.py create mode 100644 io_export_dxf/primitive_exporters/base_exporter.py create mode 100644 io_export_dxf/primitive_exporters/camera_exporter.py create mode 100644 io_export_dxf/primitive_exporters/curve_exporter.py create mode 100644 io_export_dxf/primitive_exporters/empty_exporter.py create mode 100644 io_export_dxf/primitive_exporters/insert_exporter.py create mode 100644 io_export_dxf/primitive_exporters/lamp_exporter.py create mode 100644 io_export_dxf/primitive_exporters/mesh_exporter.py create mode 100644 io_export_dxf/primitive_exporters/text_exporter.py create mode 100644 io_export_dxf/primitive_exporters/viewborder_exporter.py (limited to 'io_export_dxf') diff --git a/io_export_dxf/__init__.py b/io_export_dxf/__init__.py new file mode 100644 index 00000000..2ac22ba1 --- /dev/null +++ b/io_export_dxf/__init__.py @@ -0,0 +1,46 @@ +# ***** 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 3 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, see . +# All rights reserved. +# ***** GPL LICENSE BLOCK ***** + +bl_info = { + "name": "Export Autocad DXF Format (.dxf)", + "author": "Remigiusz Fiedler (AKA migius), Vaclav Klecanda", + "version": (2, 1, 3), + "blender": (2, 6, 3), + "location": "File > Export > Autodesk (.dxf)", + "description": "The script exports Blender geometry to DXF format r12 version.", + "warning": "Under construction! Visit Wiki for details.", + "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Import-Export/DXF_Exporter", + "tracker_url": "https://projects.blender.org/tracker/index.php?func=detail&aid=28469", + "category": "Import-Export" +} + +import bpy +from .operator import DXFExporter + +def menu_func(self, context): + self.layout.operator(DXFExporter.bl_idname, text="Autocad (.dxf)") + +def register(): + bpy.utils.register_module(__name__) + bpy.types.INFO_MT_file_export.append(menu_func) + +def unregister(): + bpy.utils.unregister_module(__name__) + bpy.types.INFO_MT_file_export.remove(menu_func) + +if __name__ == "__main__": + register() diff --git a/io_export_dxf/draw_blenders/__init__.py b/io_export_dxf/draw_blenders/__init__.py new file mode 100644 index 00000000..06e5e20f --- /dev/null +++ b/io_export_dxf/draw_blenders/__init__.py @@ -0,0 +1,87 @@ +""" NOTE: +This stuff was in original code but it seems it will be no longer needed. +NOT USED now. +""" + +#----------------------------------------------------- +def mesh_drawBlender(vertList, edgeList, faceList, name="dxfMesh", flatten=False, AT_CUR=True, link=True): + #print 'deb:mesh_drawBlender started XXXXXXXXXXXXXXXXXX' #--------- + ob = Object.New("Mesh",name) + me = Mesh.New(name) + #print 'deb: vertList=\n', vertList #--------- + #print 'deb: edgeList=\n', edgeList #--------- + #print 'deb: faceList=\n', faceList #--------- + me.verts.extend(vertList) + if edgeList: me.edges.extend(edgeList) + if faceList: me.faces.extend(faceList) + if flatten: + for v in me.verts: v.co.z = 0.0 + ob.link(me) + if link: + sce = Scene.getCurrent() + sce.objects.link(ob) + #me.triangleToQuad() + if AT_CUR: + cur_loc = Window.GetCursorPos() + ob.setLocation(cur_loc) + Blender.Redraw() + #return ob + +#----------------------------------------------------- +def curve_drawBlender(vertList, org_point=[0.0,0.0,0.0], closed=0, name="dxfCurve", flatten=False, AT_CUR=True, link=True): + #print 'deb:curve_drawBlender started XXXXXXXXXXXXXXXXXX' #--------- + ob = Object.New("Curve",name) + cu = Curve.New(name) + #print 'deb: vertList=\n', vertList #--------- + curve = cu.appendNurb(BezTriple.New(vertList[0][0])) + for p in vertList[1:]: + curve.append(BezTriple.New(p[0])) + for point in curve: + #point.handleTypes = [VECT, VECT] + point.handleTypes = [FREE, FREE] + point.radius = 1.0 + curve.flagU = closed # 0 sets the curve not cyclic=open + cu.setResolu(6) + cu.update() #important for handles calculation + if flatten: + for v in cu.verts: v.co.z = 0.0 + ob.link(cu) + if link: + sce = Scene.getCurrent() + sce.objects.link(ob) + #me.triangleToQuad() + if AT_CUR: + cur_loc = Window.GetCursorPos() + ob.setLocation(cur_loc) + elif org_point: + cur_loc=org_point + ob.setLocation(cur_loc) + Blender.Redraw() + #return ob + +#----------------------------------------------------- +def drawClipBox(clip_box): + """debug tool: draws Clipping-Box of a Camera View + """ + min_X1, max_X1, min_Y1, max_Y1,\ + min_X2, max_X2, min_Y2, max_Y2,\ + min_Z, max_Z = clip_box + verts = [] + verts.append([min_X1, min_Y1, min_Z]) + verts.append([max_X1, min_Y1, min_Z]) + verts.append([max_X1, max_Y1, min_Z]) + verts.append([min_X1, max_Y1, min_Z]) + verts.append([min_X2, min_Y2, max_Z]) + verts.append([max_X2, min_Y2, max_Z]) + verts.append([max_X2, max_Y2, max_Z]) + verts.append([min_X2, max_Y2, max_Z]) + faces = [[0,1,2,3],[4,5,6,7]] + newmesh = Mesh.New() + newmesh.verts.extend(verts) + newmesh.faces.extend(faces) + + plan = Object.New('Mesh','clip_box') + plan.link(newmesh) + sce = Scene.GetCurrent() + sce.objects.link(plan) + plan.setMatrix(sce.objects.camera.matrix) diff --git a/io_export_dxf/export_dxf.py b/io_export_dxf/export_dxf.py new file mode 100644 index 00000000..fb53e4dd --- /dev/null +++ b/io_export_dxf/export_dxf.py @@ -0,0 +1,268 @@ +import os +import mathutils + +DEBUG = os.environ.get('BLENDER_DEBUG', False) #activates debug mode +if DEBUG: + import sys + sys.path.append(os.environ['PYDEV_DEBUG_PATH']) + import pydevd + +from .model.migiusModel import MigiusDXFLibDrawing + +SUPPORTED_TYPES = ('MESH')#,'CURVE','EMPTY','TEXT','CAMERA','LAMP') + +def exportDXF(context, filePath, settings): + """ + Main entry point into export facility. + """ + print("----------\nExporting to {}".format(filePath)) + import time + time1 = time.clock() + + if settings['verbose']: + print("Generating Object list for export... (Root parents only)") + + scene = context.scene + + if settings['onlySelected'] is True: + objects = (ob for ob in scene.objects if ob.is_visible(scene) and ob.select and ob.type in SUPPORTED_TYPES) + else: + objects = (ob for ob in scene.objects if ob.is_visible(scene) and ob.type in SUPPORTED_TYPES) + + if DEBUG: pydevd.settrace() + mw = get_view_projection_matrix(context, settings) + + try: + # add Entities -------------------- + #todo: fixme: seems to be the reason for missing BLOCK-export + #if APPLY_MODIFIERS: tmp_me = Mesh.New('tmp') + #else: tmp_me = None + + drawing = MigiusDXFLibDrawing() + exported = 0 + for o in objects: + if _exportItem(context, o, mw, drawing, settings): + exported +=1 + + if not drawing.isEmpty(): + # NOTE: Only orthographic projection used now. + # if PERSPECTIVE: # generate view border - passepartout + # from .primitive_exporters.viewborder_exporter import ViewBorderDXFExporter + # e = ViewBorderDXFExporter(settings) + # e.export(drawing, ob, mx, mw) + + drawing.convert(filePath) + + duration = time.clock() - time1 + print('%s objects exported in %.2f seconds. -----DONE-----' %\ + (exported, duration)) + except IOError: + print('DXF Exporter: Write Error: ', filePath) + except Exception as e: + print('Nothing exported. Error: %s' % str(e)) + + print("Finished") + +#------------------------------------------------- +def getCommons(ob, settings): + """set up common attributes for output style: + color=None + extrusion=None + layer='0', + lineType=None + lineTypeScale=None + lineWeight=None + thickness=None + parent=None + """ + + BYBLOCK=0 #DXF-attribute: assign property to BLOCK defaults + BYLAYER=None #256 #DXF-attribute: assign property to LAYER defaults + LAYERNAME_DEF='' #default layer name + LAYERCOLOR_DEF=7 #default layer color index + LAYERLTYPE_DEF=0 #'CONTINUOUS' - default layer lineType + ENTITYLAYER_DEF=LAYERNAME_DEF #default entity color index + ENTITYCOLOR_DEF=BYLAYER #default entity color index + ENTITYLTYPE_DEF=BYLAYER #default entity lineType + + layers = ob.layers #gives a list e.g.[1,5,19] + if layers: ob_layer_nr = layers[0] + if DEBUG: print('ob_layer_nr=', ob_layer_nr) #-------------- + + materials = ob.material_slots + if materials: + ob_material = materials[0] + ob_mat_color = ob_material.material.diffuse_color + else: ob_mat_color, ob_material = None, None + if DEBUG: + print('ob_mat_color, ob_material=', ob_mat_color, ob_material) #-------------- + + data_materials = ob.material_slots + if data_materials: + data_material = data_materials[0] + data_mat_color = data_material.material.diffuse_color + else: data_mat_color, data_material = None, None + if DEBUG: + print('data_mat_color, data_material=', data_mat_color, data_material) #-------------- + + entitylayer = ENTITYLAYER_DEF + c = settings['entitylayer_from'] + #["default_LAYER","obj.name","obj.layer","obj.material","obj.data.name","obj.data.material","..vertexgroup","..group","..map_table"] + if c=="default_LAYER": + entitylayer = LAYERNAME_DEF + elif c=="obj.layer" and ob_layer_nr: + entitylayer = 'LAYER'+ str(ob_layer_nr) + elif c=="obj.material" and ob_material: + entitylayer = ob_material.name + elif c=="obj.name": + entitylayer = ob.name + elif c=="obj.data.material" and ob_material: + entitylayer = data_material.name + elif c=="obj.data.name": + entitylayer = ob.data.name + + entitycolor = ENTITYCOLOR_DEF + cfrom = settings['entitycolor_from'] + if cfrom=="default_COLOR": + entitycolor = LAYERCOLOR_DEF + elif cfrom=="BYLAYER": + entitycolor = BYLAYER + elif cfrom=="BYBLOCK": + entitycolor = BYBLOCK + elif cfrom=="obj.layer" and ob_layer_nr: + entitycolor = ob_layer_nr + elif cfrom=="obj.color" and ob.color: + entitycolor = ob.color + elif cfrom=="obj.material" and ob_mat_color: + entitycolor = ob_mat_color + elif cfrom=="obj.data.material" and data_mat_color: + entitycolor = data_mat_color + + entityltype = ENTITYLTYPE_DEF + etype = settings['entityltype_from'] + if etype=="default_LTYPE": + entityltype = LAYERLTYPE_DEF + elif etype=="BYLAYER": + entityltype = BYLAYER + elif etype=="BYBLOCK": + entityltype = BYBLOCK + elif etype: + entityltype = etype + + return entitylayer, entitycolor, entityltype + +def getCameraMatrix(cam): + raise NotImplementedError() +# camProps = cam.data +# mc0 = act_camera.matrix.copy() +# #print 'deb: camera.Matrix=\n', mc0 #------------------ +# camera = Camera.Get(act_camera.getData(name_only=True)) +# #print 'deb: camera=', dir(camera) #------------------ +# if camera.type=='persp': PERSPECTIVE = 1 +# elif camera.type=='ortho': PERSPECTIVE = 0 +# # mcp is matrix.camera.perspective +# clip_box, mcp = getClipBox(camera) +## if PERSPECTIVE: +## # get border +## # lens = camera.lens +## min_X1, max_X1, min_Y1, max_Y1,\ +## min_X2, max_X2, min_Y2, max_Y2,\ +## min_Z, max_Z = clip_box +## verts = [] +## verts.append([min_X1, min_Y1, min_Z]) +## verts.append([max_X1, min_Y1, min_Z]) +## verts.append([max_X1, max_Y1, min_Z]) +## verts.append([min_X1, max_Y1, min_Z]) +## border=verts +# mw = mc0.copy().invert() +# #ViewVector = mathutils.Vector(Window.GetViewVector()) +# #print 'deb: ViewVector=\n', ViewVector #------------------ +# #TODO: what is Window.GetViewOffset() for? +# #print 'deb: Window.GetViewOffset():', Window.GetViewOffset() #--------- +# #Window.SetViewOffset([0,0,0]) +# mw0 = Window.GetViewMatrix() +# #print 'deb: mwOrtho =\n', mw0 #--------- +# mwp = Window.GetPerspMatrix() #TODO: how to get it working? +# #print 'deb: mwPersp =\n', mwp #--------- +# mw = mw0.copy() + +projectionMapping = { + 'TOP' : mathutils.Vector((0, 0, -1)), + 'BOTTOM' : mathutils.Vector((0, 0, 1)), + 'LEFT' : mathutils.Vector((0, 1, 0)), + 'RIGHT' : mathutils.Vector((0, -1, 0)), + 'FRONT' : mathutils.Vector((-1, 0, 0)), + 'REAR' : mathutils.Vector((1, 0, 0)) +} + +#----------------------------------------------------- +def get_view_projection_matrix(context, settings): + """ + Returns view projection matrix. + Projection matrix is either identity if 3d export is selected or + camera projection if a camera or view is selected. + Currently only orthographic projection is used. (Subject to discussion). + """ + cam = settings['projectionThrough'] + if cam == None: + mw = mathutils.Matrix() + mw.identity() + elif cam in projectionMapping.keys(): + projection = mathutils.Matrix.OrthoProjection(projectionMapping[cam], 4) + mw = projection + else: # get camera with given name + c = context.scene.objects[cam] + mw = getCameraMatrix(c) + return mw + +def _exportItem(ctx, o, mw, drawing, settings): + """ + Export one item from export list. + mw - modelview + """ + if settings['verbose']: print('Exporting %s' % o) + #mx = ob.matrix.copy() + #print 'deb: ob =', ob #--------- + #print 'deb: ob.type =', ob.type #--------- + #print 'deb: mx =\n', mx #--------- + #print 'deb: mw0 =\n', mw0 #--------- + #mx_n is trans-matrix for normal_vectors for front-side faces + mx = o.matrix_world + viewRotation = mw.to_euler().to_matrix() + mx_n = o.rotation_euler.to_matrix() * viewRotation + mx *= mw + + #mx_inv = mx.copy().invert() + elayer, ecolor, eltype = getCommons(o, settings) + if settings['verbose']: + print('elayer=%s, ecolor=%s, eltype=%s' % (elayer, ecolor, eltype)) + #TODO: use o.boundBox for drawing extends ?? + + if elayer != None and not drawing.containsLayer(elayer): + if ecolor!=None: tempcolor = ecolor + else: tempcolor = settings['layercolor_def'] + drawing.addLayer(elayer, tempcolor) + + if DEBUG: pydevd.settrace() + if (o.type == 'MESH') and settings['mesh_as']: + from .primitive_exporters.mesh_exporter import MeshDXFExporter + e = MeshDXFExporter(settings) + elif (o.type == 'CURVE') and settings['curve_as']: + from .primitive_exporters.curve_exporter import CurveDXFExporter + e = CurveDXFExporter(settings) + elif (o.type == 'EMPTY') and settings['empty_as']: + from .primitive_exporters.empty_exporter import EmptyDXFExporter + e = EmptyDXFExporter(settings) + elif (o.type == 'TEXT') and settings['text_as']: + from .primitive_exporters.text_exporter import TextDXFExporter + e = TextDXFExporter(settings) + elif (o.type == 'CAMERA') and settings['camera_as']: + from .primitive_exporters.camera_exporter import CameraDXFExporter + e = CameraDXFExporter(settings) + elif (o.type == 'LAMP') and settings['lamp_as']: + from .primitive_exporters.lamp_exporter import LampDXFExporter + e = LampDXFExporter(settings) + + return e.export(ctx, drawing, o, mx, mx_n, color=ecolor, layer=elayer, lineType=eltype) + + diff --git a/io_export_dxf/model/__init__.py b/io_export_dxf/model/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/io_export_dxf/model/dxfLibrary.py b/io_export_dxf/model/dxfLibrary.py new file mode 100644 index 00000000..c1730d4d --- /dev/null +++ b/io_export_dxf/model/dxfLibrary.py @@ -0,0 +1,927 @@ +#dxfLibrary.py : provides functions for generating DXF files +# -------------------------------------------------------------------------- +__version__ = "v1.35 - 2010.06.23" +__author__ = "Stani Michiels(Stani), Remigiusz Fiedler(migius)" +__license__ = "GPL" +__url__ = "http://wiki.blender.org/index.php/Extensions:2.4/Py/Scripts/Export/DXF" +__bpydoc__ ="""The library to export geometry data to DXF format r12 version. + +Copyright %s +Version %s +License %s +Homepage %s + +See the homepage for documentation. +Dedicated thread on BlenderArtists: http://blenderartists.org/forum/showthread.php?t=136439 + +IDEAs: +- + +TODO: +- add support for DXFr14 version (needs extended file header) +- add support for DXF-SPLINEs (possible first in DXFr14 version) +- add support for DXF-MTEXT +- add user preset for floating point precision (3-16?) + +History +v1.35 - 2010.06.23 by migius + - added (as default) writing to DXF file without RAM-buffering: faster and low-RAM-machines friendly +v1.34 - 2010.06.20 by migius + - bugfix POLYFACE + - added DXF-flags for POLYLINE and VERTEX class (NURBS-export) +v1.33 - 2009.07.03 by migius + - fix MTEXT newline bug (not supported by DXF-Exporter yet) + - modif _point(): converts all coords to floats + - modif LineType class: implement elements + - added VPORT class, incl. defaults + - fix Insert class +v1.32 - 2009.06.06 by migius + - modif Style class: changed defaults to widthFactor=1.0, obliqueAngle=0.0 + - modif Text class: alignment parameter reactivated +v1.31 - 2009.06.02 by migius + - modif _Entity class: added paperspace,elevation +v1.30 - 2009.05.28 by migius + - bugfix 3dPOLYLINE/POLYFACE: VERTEX needs x,y,z coordinates, index starts with 1 not 0 +v1.29 - 2008.12.28 by Yorik + - modif POLYLINE to support bulge segments +v1.28 - 2008.12.13 by Steeve/BlenderArtists + - bugfix for EXTMIN/EXTMAX to suit Cycas-CAD +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/2009 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""" + return '\n'.join([' %s\n%s'%((i+1)*10+index,float(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))]) + 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,paperspace=None,color=None,layer='0', + lineType=None,lineTypeScale=None,lineWeight=None, + extrusion=None,elevation=None,thickness=None, + parent=None): + """None values will be omitted.""" + self.paperspace = paperspace + self.color = color + self.layer = layer + self.lineType = lineType + self.lineTypeScale = lineTypeScale + self.lineWeight = lineWeight + self.extrusion = extrusion + self.elevation = elevation + self.thickness = thickness + #self.visible = visible + 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.paperspace==1: result+=' 67\n1\n' + if parent.layer!=None: result+=' 8\n%s\n'%parent.layer + if parent.color!=None: result+=' 62\n%s\n'%parent.color + if parent.lineType!=None: result+=' 6\n%s\n'%parent.lineType + # TODO: if parent.lineWeight!=None: result+='370\n%s\n'%parent.lineWeight + # TODO: if parent.visible!=None: result+='60\n%s\n'%parent.visible + if parent.lineTypeScale!=None: result+=' 48\n%s\n'%parent.lineTypeScale + if parent.elevation!=None: result+=' 38\n%s\n'%parent.elevation + if parent.thickness!=None: result+=' 39\n%s\n'%parent.thickness + if parent.extrusion!=None: result+='%s\n'%_point(parent.extrusion,200) + 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 flag 70 +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 + +#---polyline flag 75, = curve type +QUADRIC_NURBS = 5 +CUBIC_NURBS = 6 +BEZIER_CURVE = 8 + + +#---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) + while 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)) + 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%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],flag70=0,flag75=0,width=None,**common): + #width = number, or width = list [width_start=None, width_end=None] + #for 2d-polyline: points = [ [[x, y, z], vflag=None, [width_start=None, width_end=None], bulge=0 or None] ...] + #for 3d-polyline: points = [ [[x, y, z], vflag=None], ...] + #for polyface: points = [points_list, faces_list] + _Entity.__init__(self,**common) + self.points=points + self.org_point=org_point + self.pflag70 = flag70 + self.pflag75 = flag75 + self.polyface = False + self.polyline2d = False + self.faces = [] # dummy value + self.width= None # dummy value + if self.pflag70 & POLYFACE_MESH: + self.polyface=True + self.points=points[0] + self.faces=points[1] + self.p_count=len(self.points) + self.f_count=len(self.faces) + elif not (self.pflag70 & POLYLINE_3D): + self.polyline2d = True + if width: + if type(width)!='list': width=[width,width] + self.width=width + + def __str__(self): + result= ' 0\nPOLYLINE\n%s 70\n%s\n' %(self._common(),self.pflag70) + result+=' 66\n1\n' + result+='%s\n' %_point(self.org_point) + if self.polyface: + result+=' 71\n%s\n' %self.p_count + result+=' 72\n%s\n' %self.f_count + elif self.polyline2d: + if self.width!=None: result+=' 40\n%s\n 41\n%s\n' %(self.width[0],self.width[1]) + if self.pflag75: + result+=' 75\n%s\n' %self.pflag75 + for point in self.points: + result+=' 0\nVERTEX\n' + result+=' 8\n%s\n' %self.layer + if self.polyface: + result+='%s\n' %_point(point) + result+=' 70\n192\n' + elif self.polyline2d: + result+='%s\n' %_point(point[0]) + flag = point[1] + if len(point)>2: + [width1, width2] = point[2] + if width1!=None: result+=' 40\n%s\n' %width1 + if width2!=None: result+=' 41\n%s\n' %width2 + if len(point)==4: + bulge = point[3] + if bulge: result+=' 42\n%s\n' %bulge + if flag: + result+=' 70\n%s\n' %flag + else: + result+='%s\n' %_point(point[0]) + flag = point[1] + if flag: + result+=' 70\n%s\n' %flag + + 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): + """Point.""" + def __init__(self,points=None,**common): + _Entity.__init__(self,**common) + self.points=points + def __str__(self): # TODO: + return ' 0\nPOINT\n%s%s\n' %(self._common(), + _points(self.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 + 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' %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): # TODO: + 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=[0.0],flag=0): + self.name=name + self.description=description + self.elements=copy.copy(elements) + self.flag=flag + def __str__(self): + result = ' 0\nLTYPE\n 2\n%s\n 70\n%s\n 3\n%s\n 72\n65\n'%\ + (self.name.upper(),self.flag,self.description) + if self.elements: + elements = ' 73\n%s\n' %(len(self.elements)-1) + elements += ' 40\n%s\n' %(self.elements[0]) + for e in self.elements[1:]: + elements += ' 49\n%s\n' %e + result += elements + return result + + +#----------------------------------------------- +class Style(_Call): + """Text style""" + def __init__(self,name='standard',flag=0,height=0,widthFactor=1.0,obliqueAngle=0.0, + 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 VPort(_Call): + def __init__(self,name,flag=0, + leftBottom=(0.0,0.0), + rightTop=(1.0,1.0), + center=(0.5,0.5), + snap_base=(0.0,0.0), + snap_spacing=(0.1,0.1), + grid_spacing=(0.1,0.1), + direction=(0.0,0.0,1.0), + target=(0.0,0.0,0.0), + height=1.0, + ratio=1.0, + lens=50.0, + frontClipping=0.0, + backClipping=0.0, + snap_rotation=0.0, + twist=0.0, + mode=0, + circle_zoom=100, + fast_zoom=1, + ucsicon=1, + snap_on=0, + grid_on=0, + snap_style=0, + snap_isopair=0 + ): + self.name=name + self.flag=flag + self.leftBottom=leftBottom + self.rightTop=rightTop + self.center=center + self.snap_base=snap_base + self.snap_spacing=snap_spacing + self.grid_spacing=grid_spacing + self.direction=direction + self.target=target + self.height=float(height) + self.ratio=float(ratio) + self.lens=float(lens) + self.frontClipping=float(frontClipping) + self.backClipping=float(backClipping) + self.snap_rotation=float(snap_rotation) + self.twist=float(twist) + self.mode=mode + self.circle_zoom=circle_zoom + self.fast_zoom=fast_zoom + self.ucsicon=ucsicon + self.snap_on=snap_on + self.grid_on=grid_on + self.snap_style=snap_style + self.snap_isopair=snap_isopair + def __str__(self): + output = [' 0', 'VPORT', + ' 2', self.name, + ' 70', self.flag, + _point(self.leftBottom), + _point(self.rightTop,1), + _point(self.center,2), # View center point (in DCS) + _point(self.snap_base,3), + _point(self.snap_spacing,4), + _point(self.grid_spacing,5), + _point(self.direction,6), #view direction from target (in WCS) + _point(self.target,7), + ' 40', self.height, + ' 41', self.ratio, + ' 42', self.lens, + ' 43', self.frontClipping, + ' 44', self.backClipping, + ' 50', self.snap_rotation, + ' 51', self.twist, + ' 71', self.mode, + ' 72', self.circle_zoom, + ' 73', self.fast_zoom, + ' 74', self.ucsicon, + ' 75', self.snap_on, + ' 76', self.grid_on, + ' 77', self.snap_style, + ' 78', self.snap_isopair + ] + + output_str = '' + for s in output: + output_str += '%s\n' %s + return output_str + + + +#----------------------------------------------- +class View(_Call): + def __init__(self,name,flag=0, + width=1.0, + height=1.0, + center=(0.5,0.5), + direction=(0.0,0.0,1.0), + target=(0.0,0.0,0.0), + lens=50.0, + frontClipping=0.0, + backClipping=0.0, + twist=0.0,mode=0 + ): + self.name=name + self.flag=flag + self.width=float(width) + self.height=float(height) + self.center=center + self.direction=direction + self.target=target + self.lens=float(lens) + self.frontClipping=float(frontClipping) + self.backClipping=float(backClipping) + self.twist=float(twist) + self.mode=mode + def __str__(self): + output = [' 0', 'VIEW', + ' 2', self.name, + ' 70', self.flag, + ' 40', self.height, + _point(self.center), + ' 41', self.width, + _point(self.direction,1), + _point(self.target,2), + ' 42', self.lens, + ' 43', self.frontClipping, + ' 44', self.backClipping, + ' 50', self.twist, + ' 71', self.mode + ] + output_str = '' + for s in output: + output_str += '%s\n' %s + return output_str + +#----------------------------------------------- +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,0.0),extmax=(0.0,0.0,0.0), + layers=[Layer()],linetypes=[LineType()],styles=[Style()],blocks=[], + views=[],vports=[],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.vports=copy.copy(vports) + self.blocks=copy.copy(blocks) + self.fileName=fileName + #print 'deb: blocks=',blocks #---------- + #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('vport',[str(x) for x in self.vports]), + 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 _write_section(self,file,name,data): + file.write(' 0\nSECTION\n 2\n%s\n'%name.upper()) + for x in data: + file.write(str(x)) + file.write(' 0\nENDSEC\n') + + def saveas(self,fileName,buffer=0): + """Writes DXF file. Needs target file name. If optional parameter buffer>0, then switch to old behavior: store entire output string in RAM. + """ + self.fileName=fileName + if buffer: self.save() + else: self.export() + + def save(self): + outfile=open(self.fileName,'w') + outfile.write(str(self)) + outfile.close() + + def export(self): + outfile=open(self.fileName,'w') + header=[self.acadver]+[self._point(attr,getattr(self,attr))+'\n' for attr in _HEADER_POINTS] + self._write_section(outfile,'header',header) + tables=[self._table('vport',[str(x) for x in self.vports]), + 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]), + ] + self._write_section(outfile,'tables',tables) + self._write_section(outfile,'blocks',self.blocks) + self._write_section(outfile,'entities',self.entities) + outfile.write(' 0\nEOF\n') + outfile.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][0],points[i+1][0]],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)],flag=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') + else: test() + diff --git a/io_export_dxf/model/migiusModel.py b/io_export_dxf/model/migiusModel.py new file mode 100644 index 00000000..a1e8b830 --- /dev/null +++ b/io_export_dxf/model/migiusModel.py @@ -0,0 +1,122 @@ +""" +Created on Sep 2, 2011 + +@author: vencax +""" + +from .model import DxfDrawing + +try: + from . import dxfLibrary as DXF + #reload(DXF) + #reload(dxfLibrary) + #from dxfLibrary import * +except Exception: + raise Exception("No dxfLibrary.py module in Blender script folder found!") + +#------------------------------------------------------ +#def col2RGB(color): +# return [int(floor(255*color[0])), +# int(floor(255*color[1])), +# int(floor(255*color[2]))] +# +#global dxfColors +#dxfColors=None +# +##------------------------------------------------------ +#def col2DXF(rgbcolor): +# global dxfColors +# if dxfColors is None: +# from dxfColorMap import color_map +# dxfColors = [(tuple(color),idx) for idx, color in color_map.iteritems()] +# dxfColors.sort() +# entry = (tuple(rgbcolor), -1) +# dxfColors.append(entry) +# dxfColors.sort() +# i = dxfColors.index(entry) +# dxfColors.pop(i) +# return dxfColors[i-1][1] + +""" +v = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,\ +28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,46,47,58,59,60,61,62,63,64,91,92,93,94,96,\ +123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,\ +151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,\ +171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,\ +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,\ +211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,\ +231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254] +invalid = ''.join([chr(i) for i in v]) +del v, i +""" +#TODO: validDXFr14 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.' +validDXFr12 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_' +NAMELENGTH_MAX = 80 #max_obnamelength in DXF, (limited to 256? ) +#------------------------------------------------------ +def cleanName(name, valid): + validname = '' + for ch in name: + if ch not in valid: ch = '_' + validname += ch + return validname + +#------------------------------------------------------ +def validDXFr12name(str_name): + dxfname = str(str_name) + dxfname = dxfname[:NAMELENGTH_MAX].upper() + dxfname = cleanName(dxfname, validDXFr12) + return dxfname + +class MigiusDXFLibDrawing(DxfDrawing): + """ Drawing that can convert itself into MIGIUS DXFLib stuff objects """ + + def convert(self, file, **kwargs): + drawing = self._write() + for type, ents in self._entities.items(): + self._processEntityArray(drawing, type, ents) + for v in self._views: + drawing.views.append(DXF.View(**v)) + for v in self._vports: + drawing.vports.append(DXF.VPort(**v)) +# for l in self._layers: + drawing.saveas(file) + + def _write(self): + # init Drawing --------------------- + d=DXF.Drawing() + # add Tables ----------------- + # initialized automatic: d.blocks.append(b) #section BLOCKS + # initialized automatic: d.styles.append(DXF.Style()) #table STYLE + + #table LTYPE --------------- + #d.linetypes.append(DXF.LineType(name='CONTINUOUS',description='--------',elements=[0.0])) + d.linetypes.append(DXF.LineType(name='DOT',description='. . . . . . .',elements=[0.25, 0.0, -0.25])) + d.linetypes.append(DXF.LineType(name='DASHED',description='__ __ __ __ __',elements=[0.8, 0.5, -0.3])) + d.linetypes.append(DXF.LineType(name='DASHDOT',description='__ . __ . __ .',elements=[1.0, 0.5, -0.25, 0.0, -0.25])) + d.linetypes.append(DXF.LineType(name='DIVIDE',description='____ . . ____ . . ',elements=[1.25, 0.5, -0.25, 0.0, -0.25, 0.0, -0.25])) + d.linetypes.append(DXF.LineType(name='BORDER',description='__ __ . __ __ . ',elements=[1.75, 0.5, -0.25, 0.5, -0.25, 0.0, -0.25])) + d.linetypes.append(DXF.LineType(name='HIDDEN',description='__ __ __ __ __',elements=[0.4, 0.25, -0.25])) + d.linetypes.append(DXF.LineType(name='CENTER',description='____ _ ____ _ __',elements=[2.0, 1.25, -0.25, 0.25, -0.25])) + + #d.vports.append(DXF.VPort('*ACTIVE')) + d.vports.append(DXF.VPort('*ACTIVE',center=(-5.0,1.0),height=10.0)) + #d.vports.append(DXF.VPort('*ACTIVE',leftBottom=(-100.0,-60.0),rightTop=(100.0,60.0))) + #d.views.append(DXF.View('Normal')) #table view + d.views.append(DXF.ViewByWindow('BF_TOPVIEW',leftBottom=(-100,-60),rightTop=(100,60))) #idem + + return d + + def _processEntityArray(self, drawing, type, ents): + if type=='Point': + for e in ents: + drawing.append(DXF.Point(**e)) + elif type=='Line': + for e in ents: + drawing.append(DXF.Line(**e)) + elif type=='PolyLine': + for e in ents: + drawing.append(DXF.PolyLine(**e)) + elif type=='Face': + for e in ents: + drawing.append(DXF.Face(**e)) + diff --git a/io_export_dxf/model/model.py b/io_export_dxf/model/model.py new file mode 100644 index 00000000..bff37339 --- /dev/null +++ b/io_export_dxf/model/model.py @@ -0,0 +1,38 @@ + +class DxfDrawing(object): + """ + Represents intermediate model of DXF drawing. It is useful in iterating + through exported object and for easy change the DXF handling library. + """ + def __init__(self): + self._entities = {} + self._layers = {} + self._views = [] + self._vports = [] + self._blocks = [] + + def isEmpty(self): + return len(self._entities) == 0 + + def addEntity(self, type, **kwargs): + if type not in self._entities: + self._entities[type] = [] + self._entities[type].append(kwargs) + + def addLayer(self, name, color): + self._layers[name] = color + + def containsLayer(self, name): + return name in self._layers + + def addBlock(self, block): + self._blocks.append(block) + + def containsBlock(self, blockname): + return blockname in self._blocks + + def convert(self, **kwargs): + """ Converts this drawing into DXF representation object """ + raise NotImplementedError() + + diff --git a/io_export_dxf/operator.py b/io_export_dxf/operator.py new file mode 100644 index 00000000..12d9c9eb --- /dev/null +++ b/io_export_dxf/operator.py @@ -0,0 +1,283 @@ + + +import bpy +from bpy.props import StringProperty, EnumProperty, BoolProperty + +class DXFExporter(bpy.types.Operator): + """ + Export to the Autocad model format (.dxf) + """ + bl_idname = "export.dxf" + bl_label = "Export DXF" + filepath = StringProperty(subtype='FILE_PATH') + + entitylayer_from_items = ( + ('default_LAYER', 'Default Layer', ''), + ('obj.name', 'Object name', ''), + ('obj.layer', 'Object layer', ''), + ('obj.material', 'Object material', ''), + ('obj.data.name', 'Object\' data name', ''), +# ('obj.data.material', 'Material of data', ''), + ('..vertexgroup', 'Vertex Group', ''), + ('..group', 'Group', ''), + ('..map_table', 'Table', '') + ) + layerColorFromItems = ( + ('default_COLOR', 'Vertex Group', ''), + ('BYLAYER', 'BYLAYER', ''), + ('BYBLOCK', 'BYBLOCK', ''), + ('obj.layer', 'Object Layer', ''), + ('obj.color', 'Object Color', ''), + ('obj.material', 'Object material', ''), + # I don'd know ? +# ('obj.data.material', 'Vertex Group', ''), +# ('..map_table', 'Vertex Group', ''), + ) + layerNameFromItems = ( + ('LAYERNAME_DEF', 'Default Name', ''), + ('drawing_name', 'From Drawing name', ''), + ('scene_name', 'From scene name', '') + ) + + exportModeItems = ( + ('ALL', 'All Objects', ''), + ('SELECTION', 'Selected Objects', ''), + ) +# spaceItems = ( +# ('1', 'Paper-Space', ''), +# ('2', 'Model-Space', '') +# ) + + entityltype_fromItems = ( + ('default_LTYPE', 'default_LTYPE', ''), + ('BYLAYER', 'BYLAYER', ''), + ('BYBLOCK', 'BYBLOCK', ''), + ('CONTINUOUS', 'CONTINUOUS', ''), + ('DOT', 'DOT', ''), + ('DASHED', 'DASHED', ''), + ('DASHDOT', 'DASHDOT', ''), + ('BORDER', 'BORDER', ''), + ('HIDDEN', 'HIDDEN', '') + ) + material_toItems = ( + ('NO', 'Do not export', ''), + ('COLOR', 'COLOR', ''), + ('LAYER', 'LAYER', ''), + ('..LINESTYLE', '..LINESTYLE', ''), + ('..BLOCK', '..BLOCK', ''), + ('..XDATA', '..XDATA', ''), + ('..INI-File', '..INI-File', '') + ) + projectionItems=( + ('NO', 'No projection', 'Export 3D scene without any 2D projection'), + ('TOP', 'TOP view', 'Use TOP view for projection'), + ('BOTTOM', 'BOTTOM view', 'Use BOTTOM view for projection'), + ('LEFT', 'LEFT view', 'Use LEFT view for projection'), + ('RIGHT', 'RIGHT view', 'Use RIGHT view for projection'), + ('FRONT', 'FRONT view', 'Use FRONT view for projection'), + ('REAR', 'REAR view', 'Use REAR view for projection') + ) + mesh_asItems = ( + ('NO', 'Do not export', ''), + ('3DFACEs', '3DFACEs', ''), + ('POLYFACE', 'POLYFACE', ''), + ('POLYLINE', 'POLYLINE', ''), + ('LINEs', 'LINEs', 'export Mesh as multiple LINEs'), + ('POINTs', 'POINTs', 'Export Mesh as multiple POINTs') + ) +# curve_asItems = ( +# ('NO', 'Do not export', ''), +# ('LINEs', 'LINEs', ''), +# ('POLYLINE', 'POLYLINE', ''), +# ('..LWPOLYLINE r14', '..LWPOLYLINE r14', ''), +# ('..SPLINE r14', '..SPLINE r14', ''), +# ('POINTs', 'POINTs', '') +# ) +# surface_asItems = ( +# ('NO', 'Do not export', ''), +# ('..3DFACEs', '..3DFACEs', ''), +# ('..POLYFACE', '..POLYFACE', ''), +# ('..POINTs', '..POINTs', ''), +# ('..NURBS', '..NURBS', '') +# ) +# meta_asItems = ( +# ('NO', 'Do not export', ''), +# ('..3DFACEs', '..3DFACEs', ''), +# ('..POLYFACE', '..POLYFACE', ''), +# ('..3DSOLID', '..3DSOLID', '') +# ) +# text_asItems = ( +# ('NO', 'Do not export', ''), +# ('TEXT', 'TEXT', ''), +# ('..MTEXT', '..MTEXT', ''), +# ('..ATTRIBUT', '..ATTRIBUT', '') +# ) +# empty_asItems = ( +# ('NO', 'Do not export', ''), +# ('POINT', 'POINT', ''), +# ('..INSERT', '..INSERT', ''), +# ('..XREF', '..XREF', '') +# ) +# group_asItems = ( +# ('NO', 'Do not export', ''), +# ('..GROUP', '..GROUP', ''), +# ('..BLOCK', '..BLOCK', ''), +# ('..ungroup', '..ungroup', '') +# ) +## parent_asItems = ['..BLOCK','..ungroup'] # ??? +# proxy_asItems = ( +# ('NO', 'Do not export', ''), +# ('..BLOCK','..BLOCK', ''), +# ('..XREF', '..XREF', ''), +# ('..ungroup', '..ungroup', ''), +# ('..POINT', '..POINT', '') +# ) +# camera_asItems = ( +# ('NO', 'Do not export', ''), +# ('..BLOCK', '..BLOCK', ''), +# ('..A_CAMERA', '..A_CAMERA', ''), +# ('VPORT', 'VPORT', ''), +# ('VIEW', 'VIEW', ''), +# ('POINT', 'POINT', '') +# ) +# lamp_asItems = ( +# ('NO', 'Do not export', ''), +# ('..BLOCK', '..BLOCK', ''), +# ('..A_LAMP', '..A_LAMP', ''), +# ('POINT', 'POINT', '') +# ) + # --------- CONTROL PROPERTIES -------------------------------------------- + projectionThrough = EnumProperty(name="Projection", default="NO", + description="Select camera for use to 2D projection", + items=projectionItems) + + onlySelected = BoolProperty(name="Only selected", default=True, + description="What object will be exported? Only selected / all objects.") + + apply_modifiers = BoolProperty(name="Apply modifiers", default=True, + description="Shall be modifiers applied during export?") + # GUI_B ----------------------------------------- + mesh_as = EnumProperty( name="Export Mesh As", default='3DFACEs', + description="Select representation of a mesh", + items=mesh_asItems) +# curve_as = EnumProperty( name="Export Curve As:", default='NO', +# description="Select representation of a curve", +# items=curve_asItems) +# surface_as = EnumProperty( name="Export Surface As:", default='NO', +# description="Select representation of a surface", +# items=surface_asItems) +# meta_as = EnumProperty( name="Export meta As:", default='NO', +# description="Select representation of a meta", +# items=meta_asItems) +# text_as = EnumProperty( name="Export text As:", default='NO', +# description="Select representation of a text", +# items=text_asItems) +# empty_as = EnumProperty( name="Export empty As:", default='NO', +# description="Select representation of a empty", +# items=empty_asItems) +# group_as = EnumProperty( name="Export group As:", default='NO', +# description="Select representation of a group", +# items=group_asItems) +## parent_as = EnumProperty( name="Export parent As:", default='NO', +## description="Select representation of a parent", +## items=parent_asItems) +# proxy_as = EnumProperty( name="Export proxy As:", default='NO', +# description="Select representation of a proxy", +# items=proxy_asItems) +# camera_as = EnumProperty( name="Export camera As:", default='NO', +# description="Select representation of a camera", +# items=camera_asItems) +# lamp_as = EnumProperty( name="Export lamp As:", default='NO', +# description="Select representation of a lamp", +# items=lamp_asItems) + # ---------------------------------------------------------- + entitylayer_from = EnumProperty(name="Entity Layer", default="obj.data.name", + description="Entity LAYER assigned to?", + items=entitylayer_from_items) + entitycolor_from = EnumProperty(name="Entity Color", default="default_COLOR", + description="Entity COLOR assigned to?", + items=layerColorFromItems) + entityltype_from = EnumProperty(name="Entity Linetype", default="CONTINUOUS", + description="Entity LINETYPE assigned to?", + items=entityltype_fromItems) + + layerName_from = EnumProperty(name="Layer Name", default="LAYERNAME_DEF", + description="From where will layer name be taken?", + items=layerNameFromItems) + # GUI_A ----------------------------------------- +# layFrozen_on = BoolProperty(name="LAYER.frozen status", description="(*todo) Support LAYER.frozen status on/off", default=False) +# materialFilter_on = BoolProperty(name="Material filtering", description="(*todo) Material filtering on/off", default=False) +# colorFilter_on = BoolProperty(name="Color filtering", description="(*todo) Color filtering on/off", default=False) +# groupFilter_on = BoolProperty(name="Group filtering", description="(*todo) Group filtering on/off", default=False) +# objectFilter_on = BoolProperty(name="Object filtering", description="(*todo) Object filtering on/off", default=False) +# paper_space_on = EnumProperty(name="Space of export:", default="2", +# description="Select space that will be taken for export.", +# items=spaceItems) +# material_to = EnumProperty(name="Material assigned to?:", default="NO", +# description="Material assigned to?.", +# items=material_toItems) + +# prefix_def = StringProperty(name="Prefix for LAYERs", default="DX_", +# description='Type Prefix for LAYERs') +# layername_def = StringProperty(name="default LAYER name", default="DEF_LAY", +# description='Type default LAYER name') +# layercolor_def = StringProperty(name="Default layer color:", default="1", +# description='Set default COLOR. (0=BYBLOCK,256=BYLAYER)') +# layerltype_def = StringProperty(name="Default LINETYPE", default="DEF_LAY_TYPE", +# description='Set default LINETYPE') + + verbose = BoolProperty(name="Verbose", default=False, + description="Run the exporter in debug mode. Check the console for output.") + + def execute(self, context): + filePath = bpy.path.ensure_ext(self.filepath, ".dxf") + config = { + 'projectionThrough' : self._checkNO(self.projectionThrough), + 'onlySelected' : self.onlySelected, + 'apply_modifiers' : self.apply_modifiers, + # GUI B + 'mesh_as' : self._checkNO(self.mesh_as), +# 'curve_as' : self._checkNO(self.curve_as), +# 'surface_as' : self._checkNO(self.surface_as), +# 'meta_as' : self._checkNO(self.meta_as), +# 'text_as' : self._checkNO(self.text_as), +# 'empty_as' : self._checkNO(self.empty_as), +# 'group_as' : self._checkNO(self.group_as), +# 'proxy_as' : self._checkNO(self.proxy_as), +# 'camera_as' : self._checkNO(self.camera_as), +# 'lamp_as' : self._checkNO(self.lamp_as), + + 'entitylayer_from' : self.entitylayer_from, + 'entitycolor_from' : self.entitycolor_from, + 'entityltype_from' : self.entityltype_from, + 'layerName_from' : self.layerName_from, + + # NOT USED +# 'layFrozen_on' : self.layFrozen_on, +# 'materialFilter_on' : self.materialFilter_on, +# 'colorFilter_on' : self.colorFilter_on, +# 'groupFilter_on' : self.groupFilter_on, +# 'objectFilter_on' : self.objectFilter_on, +# 'paper_space_on' : self.paper_space_on, +# 'layercolor_def' : self.layercolor_def, +# 'material_to' : self.material_to, + + 'verbose' : self.verbose + } + + from .export_dxf import exportDXF + exportDXF(context, filePath, config) + return {'FINISHED'} + + def _checkNO(self, val): + if val == 'NO': return None + else: return val + + def invoke(self, context, event): + if not self.filepath: + self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".dxf") + WindowManager = context.window_manager + WindowManager.fileselect_add(self) + return {'RUNNING_MODAL'} + + diff --git a/io_export_dxf/primitive_exporters/__init__.py b/io_export_dxf/primitive_exporters/__init__.py new file mode 100644 index 00000000..8e49ba00 --- /dev/null +++ b/io_export_dxf/primitive_exporters/__init__.py @@ -0,0 +1,10 @@ +""" +This package contains actual primitive exporter classes. +They are imported and instantiated according object type +that is being exported from export_dxf.py in ../ + +NOTE: Only MESH exporter has been ported since it is imho +mostly used. I am not specialist on Autocad so I cannot +guest how many time the other primitive are used. That's +why they are left unported. +""" diff --git a/io_export_dxf/primitive_exporters/base_exporter.py b/io_export_dxf/primitive_exporters/base_exporter.py new file mode 100644 index 00000000..b85dc127 --- /dev/null +++ b/io_export_dxf/primitive_exporters/base_exporter.py @@ -0,0 +1,195 @@ +import mathutils + +class BasePrimitiveDXFExporter(object): + + INSTANCES = False + PROJECTION = False + HIDDEN_LINES = False + + def __init__(self, settings): + self._settings = settings + + def projected_co(self, verts, matrix): + """ converts coordinates of points from OCS to WCS->ScreenCS + needs matrix: a projection matrix + needs verts: a list of vectors[x,y,z] + returns a list of [x,y,z] + """ + #print 'deb:projected_co() verts=', verts #--------- + temp_verts = [matrix*mathutils.Vector(v) for v in verts] + #print 'deb:projected_co() temp_verts=', temp_verts #--------- + + # if GUI_A['Z_force_on'].val: locZ = GUI_A['Z_elev'].val + # else:locZ = 0.0 + locZ = 0.0 + + if self.PROJECTION: + if self.PERSPECTIVE: + clipStart = 10.0 + for v in temp_verts: + coef = - clipStart / v[2] + v[0] *= coef + v[1] *= coef + v[2] = locZ + for v in temp_verts: + v[2] = locZ + temp_verts = [v[:3] for v in temp_verts] + #print 'deb:projected_co() out_verts=', temp_verts #--------- + return temp_verts + + def isLeftHand(self, matrix): + #Is the matrix a left-hand-system, or not? + ma = matrix.to_euler().to_matrix() + crossXY = self.M_CrossVecs(ma[0], ma[1]) + check = self.M_DotVecs(ma[2], crossXY) + if check < 0.00001: return 1 + return 0 + + #----------------------------------------------------- + def hidden_status(self, faces, mx, mx_n): + # sort out back-faces = with normals pointed away from camera + #print 'HIDDEN_LINES: caution! not full implemented yet' + front_faces = [] + front_edges = [] + for f in faces: + #print 'deb: face=', f #--------- + #print 'deb: dir(face)=', dir(f) #--------- + # get its normal-vector in localCS + vec_normal = f.no.copy() + #print 'deb: vec_normal=', vec_normal #------------------ + # must be transfered to camera/view-CS + vec_normal *= mx_n + #vec_normal *= mb.rotationPart() + #print 'deb:2vec_normal=', vec_normal #------------------ + #vec_normal *= mw0.rotationPart() + #print 'deb:3vec_normal=', vec_normal, '\n' #------------------ + + + frontFace = False + if not self.PERSPECTIVE: #for ortho mode ---------- + # normal must point the Z direction-hemisphere + if vec_normal[2] > 0.00001: + frontFace = True + else: + v = f.verts[0] + vert = mathutils.Vector(v.co) * mx + if mathutils.DotVecs(vert, vec_normal) < 0.00001: + frontFace = True + + if frontFace: + front_faces.append(f.index) + for key in f.edge_keys: + #this test can be done faster with set() + if key not in front_edges: + front_edges.append(key) + + #print 'deb: amount of visible faces=', len(front_faces) #--------- + #print 'deb: visible faces=', front_faces #--------- + #print 'deb: amount of visible edges=', len(front_edges) #--------- + #print 'deb: visible edges=', front_edges #--------- + return front_faces, front_edges + + #----------------------------------------------------- + def toGlobalOrigin(self, points): + """relocates points to the new location + needs a list of points [x,y,z] + """ + # if GUI_A['g_origin_on'].val: + # for p in points: + # p[0] += G_ORIGIN[0] + # p[1] += G_ORIGIN[1] + # p[2] += G_ORIGIN[2] + return points + + #---- migration to 2.49------------------------------------------------- + + #Draw.PupMenu('DXF exporter: Abort%t|This script version works for Blender up 2.49 only!') + def M_CrossVecs(self, v1,v2): + if 'cross' in dir(mathutils.Vector()): + return v1.cross(v2) #for up2.49 + else: + return mathutils.CrossVecs(v1,v2) #for pre2.49 + + def M_DotVecs(self, v1,v2): + if 'cross' in dir(mathutils.Vector()): + return v1.dot(v2) #for up2.49 + else: + return mathutils.DotVecs(v1,v2) #for pre2.49 + +#----------------------------------------------------- + def getExtrusion(self, matrix): + """ calculates DXF-Extrusion = Arbitrary Xaxis and Zaxis vectors """ + AZaxis = matrix[2].copy().resize3D().normalize() # = ArbitraryZvector + Extrusion = [AZaxis[0],AZaxis[1],AZaxis[2]] + if AZaxis[2]==1.0: + Extrusion = None + AXaxis = matrix[0].copy().resize3D() # = ArbitraryXvector + else: + threshold = 1.0 / 64.0 + if abs(AZaxis[0]) < threshold and abs(AZaxis[1]) < threshold: + # AXaxis is the intersection WorldPlane and ExtrusionPlane + AXaxis = self.M_CrossVecs(WORLDY,AZaxis) + else: + AXaxis = self.M_CrossVecs(WORLDZ,AZaxis) + #print 'deb:\n' #------------- + #print 'deb:getExtrusion() Extrusion=', Extrusion #--------- + return Extrusion, AXaxis.normalize() + + #----------------------------------------------------- +# def getZRotation(AXaxis, rot_matrix_invert): +# """calculates ZRotation = angle between ArbitraryXvector and obj.matrix.Xaxis +# +# """ +# # this works: Xaxis is the obj.matrix-Xaxis vector +# # but not correct for all orientations +# #Xaxis = matrix[0].copy().resize3D() # = ArbitraryXvector +# ##Xaxis.normalize() # = ArbitraryXvector +# #ZRotation = - mathutils.AngleBetweenVecs(Xaxis,AXaxis) #output in radians +# +# # this works for all orientations, maybe a bit faster +# # transform AXaxis into OCS:Object-Coord-System +# #rot_matrix = normalizeMat(matrix.rotationPart()) +# #rot_matrix_invert = rot_matrix.invert() +# vec = AXaxis * rot_matrix_invert +# ##vec = AXaxis * matrix.copy().invert() +# ##vec.normalize() # not needed for atan2() +# #print '\ndeb:getExtrusion() vec=', vec #--------- +# ZRotation = - atan2(vec[1],vec[0]) #output in radians +# +# #print 'deb:ZRotation() ZRotation=', ZRotation*r2d #--------- +# return ZRotation +# +# +# #----------------------------------------------------- +# def getTargetOrientation(mx,Extrusion,AXaxis,WCS_loc,sizeX,sizeY,sizeZ,rotX,rotY,rotZ): +# """given +# """ +# if 1: +# rot_matrix = normalizeMat(mx.to_euler().to_matrix()) +# #TODO: workaround for blender negative-matrix.invert() +# # partially done: works only for rotX,rotY==0.0 +# if sizeX<0.0: rot_matrix[0] *= -1 +# if sizeY<0.0: rot_matrix[1] *= -1 +# #if sizeZ<0.0: rot_matrix[2] *= -1 +# rot_matrix_invert = rot_matrix.invert() +# else: #TODO: to check, why below rot_matrix_invert is not equal above one +# rot_euler_matrix = euler2matrix(rotX,rotY,rotZ) +# rot_matrix_invert = euler2matrix(-rotX,-rotY,-rotZ) +# +# # OCS_origin is Global_Origin in ObjectCoordSystem +# OCS_origin = mathutils.Vector(WCS_loc) * rot_matrix_invert +# #print 'deb: OCS_origin=', OCS_origin #--------- +# +# ZRotation = rotZ +# if Extrusion!=None: +# ZRotation = getZRotation(AXaxis,rot_matrix_invert) +# #Zrotmatrix = mathutils.RotationMatrix(-ZRotation, 3, "Z") +# rs, rc = sin(ZRotation), cos(ZRotation) +# Zrotmatrix = mathutils.Matrix([rc, rs,0.0],[-rs,rc,0.0],[0.0,0.0,1.0]) +# #print 'deb: Zrotmatrix=\n', Zrotmatrix #-------------- +# +# # ECS_origin is Global_Origin in EntityCoordSystem +# ECS_origin = OCS_origin * Zrotmatrix +# #print 'deb: ECS_origin=', ECS_origin #--------- +# #TODO: it doesnt work yet for negative scaled curve-objects! +# return ZRotation,Zrotmatrix,OCS_origin,ECS_origin diff --git a/io_export_dxf/primitive_exporters/camera_exporter.py b/io_export_dxf/primitive_exporters/camera_exporter.py new file mode 100644 index 00000000..e31166ed --- /dev/null +++ b/io_export_dxf/primitive_exporters/camera_exporter.py @@ -0,0 +1,55 @@ +from .base_exporter import BasePrimitiveDXFExporter + + +class CameraDXFExporter(BasePrimitiveDXFExporter): + pass + + +#----------------------------------------------------- +def exportCamera(ob, mx, mw, **common): + """converts Camera-Object to desired projection and representation(DXF-Entity type) + """ + location = mathutils.Vector(ob.loc) + [location] = projected_co([location], mx) + [location] = toGlobalOrigin([location]) + view_name=validDXFr12name(('CAM_'+ ob.name)) + + camera = Camera.Get(ob.getData(name_only=True)) + #print 'deb: camera=', dir(camera) #------------------ + if camera.type=='persp': + mode = 1+2+4+16 + # mode flags: 1=persp, 2=frontclip, 4=backclip,16=FrontZ + elif camera.type=='ortho': + mode = 0+2+4+16 + + leftBottom=(0.0,0.0) # default + rightTop=(1.0,1.0) # default + center=(0.0,0.0) # default + + direction = mathutils.Vector(0.0,0.0,1.0) * mx.to_euler().to_matrix() # in W-C-S + direction.normalize() + target=mathutils.Vector(ob.loc) - direction # in W-C-S + #ratio=1.0 + width=height= camera.scale # for ortho-camera + lens = camera.lens # for persp-camera + frontClipping = -(camera.clipStart - 1.0) + backClipping = -(camera.clipEnd - 1.0) + + entities, vport, view = [], None, None + c = camera_as_list[GUI_A['camera_as'].val] + if c=="POINT": # export as POINT + dxfPOINT = DXF.Point(points=[location],**common) + entities.append(dxfPOINT) + elif c=="VIEW": # export as VIEW + view = DXF.View(name=view_name, + center=center, width=width, height=height, + frontClipping=frontClipping,backClipping=backClipping, + direction=direction,target=target,lens=lens,mode=mode + ) + elif c=="VPORT": # export as VPORT + vport = DXF.VPort(name=view_name, + center=center, ratio=1.0, height=height, + frontClipping=frontClipping,backClipping=backClipping, + direction=direction,target=target,lens=lens,mode=mode + ) + return entities, vport, view diff --git a/io_export_dxf/primitive_exporters/curve_exporter.py b/io_export_dxf/primitive_exporters/curve_exporter.py new file mode 100644 index 00000000..d74a459f --- /dev/null +++ b/io_export_dxf/primitive_exporters/curve_exporter.py @@ -0,0 +1,260 @@ +from .base_exporter import BasePrimitiveDXFExporter + + +class CurveDXFExporter(BasePrimitiveDXFExporter): + pass + +#----------------------------------------------------- +def exportCurve(ob, mx, mw, **common): + """converts Curve-Object to desired projection and representation(DXF-Entity type) + """ + entities = [] + block = None + curve = ob.getData() + #print 'deb: curve=', dir(curve) #--------- + # TODO: should be: if curve.users>1 and not (PERSPECTIVE or (PROJECTION and HIDDEN_MODE): + if INSTANCES and curve.users>1 and not PROJECTION: + if curve.name in BLOCKREGISTRY.keys(): + insert_name = BLOCKREGISTRY[curve.name] + # write INSERT to entities + entities = exportInsert(ob, mx,insert_name, **common) + else: + # generate geom_output in ObjectCS + imx = mathutils.Matrix().identity() + WCS_loc = [0,0,0] # WCS_loc is object location in WorldCoordSystem + #print 'deb: WCS_loc=', WCS_loc #--------- + sizeX = sizeY = sizeZ = 1.0 + rotX = rotY = rotZ = 0.0 + Thickness,Extrusion,ZRotation,Elevation = None,None,None,None + ZRotation,Zrotmatrix,OCS_origin,ECS_origin = None,None,None,None + AXaxis = imx[0].copy().resize3D() # = ArbitraryXvector + OCS_origin = [0,0,0] + if not PROJECTION: + #Extrusion, ZRotation, Elevation = getExtrusion(mx) + Extrusion, AXaxis = getExtrusion(imx) + + # no thickness/width for POLYLINEs converted into Screen-C-S + #print 'deb: curve.ext1=', curve.ext1 #--------- + if curve.ext1: Thickness = curve.ext1 * sizeZ + if curve.ext2 and sizeX==sizeY: + Width = curve.ext2 * sizeX + if "POLYLINE"==curve_as_list[GUI_A['curve_as'].val]: # export as POLYLINE + ZRotation,Zrotmatrix,OCS_origin,ECS_origin = getTargetOrientation(imx,Extrusion,\ + AXaxis,WCS_loc,sizeX,sizeY,sizeZ,rotX,rotY,rotZ) + + entities = writeCurveEntities(curve, imx, + Thickness,Extrusion,ZRotation,Elevation,AXaxis,Zrotmatrix, + WCS_loc,OCS_origin,ECS_origin,sizeX,sizeY,sizeZ, + **common) + + if entities: # if not empty block + # write BLOCK definition and INSERT entity + # BLOCKREGISTRY = dictionary 'blender_name':'dxf_name'.append(me.name) + BLOCKREGISTRY[curve.name]=validDXFr12name(('CU_'+ curve.name)) + insert_name = BLOCKREGISTRY[curve.name] + block = DXF.Block(insert_name,flag=0,base=(0,0,0),entities=entities) + # write INSERT as entity + entities = exportInsert(ob, mx, insert_name, **common) + + else: # no other instances, so go the standard way + WCS_loc = ob.loc # WCS_loc is object location in WorldCoordSystem + #print 'deb: WCS_loc=', WCS_loc #--------- + sizeX = ob.SizeX + sizeY = ob.SizeY + sizeZ = ob.SizeZ + rotX = ob.RotX + rotY = ob.RotY + rotZ = ob.RotZ + #print 'deb: sizeX=%s, sizeY=%s' %(sizeX, sizeY) #--------- + + Thickness,Extrusion,ZRotation,Elevation = None,None,None,None + ZRotation,Zrotmatrix,OCS_origin,ECS_origin = None,None,None,None + AXaxis = mx[0].copy().resize3D() # = ArbitraryXvector + OCS_origin = [0,0,0] + if not PROJECTION: + #Extrusion, ZRotation, Elevation = getExtrusion(mx) + Extrusion, AXaxis = getExtrusion(mx) + + # no thickness/width for POLYLINEs converted into Screen-C-S + #print 'deb: curve.ext1=', curve.ext1 #--------- + if curve.ext1: Thickness = curve.ext1 * sizeZ + if curve.ext2 and sizeX==sizeY: + Width = curve.ext2 * sizeX + if "POLYLINE"==curve_as_list[GUI_A['curve_as'].val]: # export as POLYLINE + ZRotation,Zrotmatrix,OCS_origin,ECS_origin = getTargetOrientation(mx,Extrusion,\ + AXaxis,WCS_loc,sizeX,sizeY,sizeZ,rotX,rotY,rotZ) + entities = writeCurveEntities(curve, mx, + Thickness,Extrusion,ZRotation,Elevation,AXaxis,Zrotmatrix, + WCS_loc,OCS_origin,ECS_origin,sizeX,sizeY,sizeZ, + **common) + + return entities, block + + +#------------------------------------------------- +def writeCurveEntities(curve, mx, + Thickness,Extrusion,ZRotation,Elevation,AXaxis,Zrotmatrix, + WCS_loc,OCS_origin,ECS_origin,sizeX,sizeY,sizeZ, + **common): + """help routine for exportCurve() + """ + entities = [] + width1,width2 = None, None + if 1: + for cur in curve: + #print 'deb: START cur=', cur #-------------- + #print 'deb: dir(curve):',dir(cur) #--------- + #print 'deb: curve.type:',cur.type #--------- + points = [] + flags = [] + pflag70, pflag75 = 0,0 + + if cur.type==4: # is NURBS + #if cur.isNurb(): + #print 'deb:isNurb --------------' #--------- + pflag70 = 4 + orderU = cur.orderU + # curve type: + # 0: curvNoFitted + # 5: curvQuadraticBspline + # 6: curvCubicBspline + # 8: curvBezier + if orderU<=4: pflag75 = 5 + elif orderU>=5: pflag75 = 6 + + vflag70 = 16 + i = -2 + for point in cur: + #print 'deb:isNurb point=', point #--------- + i+=1 + if i==orderU-1: i = 0 + if i: + flags.append([16, [width1,width2]]) + else: + flags.append([8, [width1,width2]]) + vec = point[0:3] + #print 'deb: vec=', vec #--------- + pkt = mathutils.Vector(vec) + #print 'deb: pkt=', pkt #--------- + points.append(pkt) + if not cur.isCyclic(): + points = points[1:-1] + flags = flags[1:-1] + elif cur.type==1: # is Bezier + #print 'deb:isBezier --------------' #--------- + pflag75 = 8 + vflag70 = 1 + for point in cur: + #print 'deb:isBezier point=', point #--------- + #print 'deb:isBezier point=', point.getTriple() #--------- + ptan1,pfit,ptan2 = point.getTriple() + #print 'deb: point=', pt #--------- + ptan1 = mathutils.Vector(ptan1) + pfit = mathutils.Vector(pfit) + ptan2 = mathutils.Vector(ptan2) + #print 'deb: pkt=', pkt #--------- + points.append(ptan1) + flags.append([2, [width1,width2]]) + points.append(pfit) + flags.append([1, [width1,width2]]) + points.append(ptan2) + flags.append([2, [width1,width2]]) + if not cur.isCyclic(): + points = points[1:-1] + flags = flags[1:-1] + elif cur.type==0: # is Polygon + #print 'deb:isPolygon --------------' #--------- + #pflag70 = 4 + pflag75 = 0 + for point in cur: + #print 'deb:isPoly point=', point #--------- + vec = point[0:3] + #print 'deb: vec=', vec #--------- + pkt = mathutils.Vector(vec) + #print 'deb: pkt=', pkt #--------- + points.append(pkt) + flags.append([None, [width1,width2]]) + + #print 'deb: points', points #-------------- + if len(points)>1: + c = curve_as_list[GUI_A['curve_as'].val] + + if c=="POLYLINE": # export Curve as POLYLINE + if not PROJECTION: + # recalculate points(2d=X,Y) into Entity-Coords-System + for p in points: # list of vectors + p[0] *= sizeX + p[1] *= sizeY + p2 = p * Zrotmatrix + p2[0] += ECS_origin[0] + p2[1] += ECS_origin[1] + p[0],p[1] = p2[0],p2[1] + else: + points = projected_co(points, mx) + #print 'deb: points', points #-------------- + + if cur.isCyclic(): closed = 1 + else: closed = 0 + points = toGlobalOrigin(points) + points_temp = [] + for p,f in zip(points,flags): + points_temp.append([p,f[0],f[1]]) + points = points_temp + #print 'deb: points', points #-------------- + + if DEBUG: curve_drawBlender(points,OCS_origin,closed) #deb: draw to scene + + common['extrusion']= Extrusion + ##common['rotation']= ZRotation + ##common['elevation']= Elevation + common['thickness']= Thickness + #print 'deb: common=', common #------------------ + + flag70, flag75 = pflag70+closed, pflag75 + if 0: #DEBUG + p=AXaxis[:3] + entities.append(DXF.Line([[0,0,0], p],**common)) + p=ECS_origin[:3] + entities.append(DXF.Line([[0,0,0], p],**common)) + common['color']= 5 + p=OCS_origin[:3] + entities.append(DXF.Line([[0,0,0], p],**common)) + #OCS_origin=[0,0,0] #only debug---------------- + dxfPLINE = DXF.PolyLine(points,OCS_origin, flag70=flag70, flag75=flag70, width=0.0,**common) + entities.append(dxfPLINE) + + dxfPLINE = DXF.PolyLine(points,OCS_origin, flag70=flag70, flag75=flag70, width=0.0,**common) + entities.append(dxfPLINE) + if Thickness: + common['thickness']= -Thickness + dxfPLINE = DXF.PolyLine(points,OCS_origin, flag70=flag70, flag75=flag70, width=0.0,**common) + entities.append(dxfPLINE) + + elif c=="LINEs": # export Curve as multiple LINEs + points = projected_co(points, mx) + if cur.isCyclic(): points.append(points[0]) + #print 'deb: points', points #-------------- + points = toGlobalOrigin(points) + + if DEBUG: curve_drawBlender(points,WCS_loc,closed) #deb: draw to scene + common['extrusion']= Extrusion + common['elevation']= Elevation + common['thickness']= Thickness + #print 'deb: common=', common #------------------ + for i in range(len(points)-1): + linepoints = [points[i], points[i+1]] + dxfLINE = DXF.Line(linepoints,**common) + entities.append(dxfLINE) + if Thickness: + common['thickness']= -Thickness + for i in range(len(points)-1): + linepoints = [points[i], points[i+1]] + dxfLINE = DXF.Line(linepoints,**common) + entities.append(dxfLINE) + + elif c=="POINTs": # export Curve as multiple POINTs + points = projected_co(points, mx) + for p in points: + dxfPOINT = DXF.Point(points=[p],**common) + entities.append(dxfPOINT) + return entities diff --git a/io_export_dxf/primitive_exporters/empty_exporter.py b/io_export_dxf/primitive_exporters/empty_exporter.py new file mode 100644 index 00000000..e849409e --- /dev/null +++ b/io_export_dxf/primitive_exporters/empty_exporter.py @@ -0,0 +1,20 @@ +from .base_exporter import BasePrimitiveDXFExporter + + +class EmptyDXFExporter(BasePrimitiveDXFExporter): + pass + +#----------------------------------------------------- +def exportEmpty(ob, mx, mw, **common): + """converts Empty-Object to desired projection and representation(DXF-Entity type) + """ + p = mathutils.Vector(ob.loc) + [p] = projected_co([p], mx) + [p] = toGlobalOrigin([p]) + + entities = [] + c = empty_as_list[GUI_A['empty_as'].val] + if c=="POINT": # export Empty as POINT + dxfPOINT = DXF.Point(points=[p],**common) + entities.append(dxfPOINT) + return entities diff --git a/io_export_dxf/primitive_exporters/insert_exporter.py b/io_export_dxf/primitive_exporters/insert_exporter.py new file mode 100644 index 00000000..80cf7dbd --- /dev/null +++ b/io_export_dxf/primitive_exporters/insert_exporter.py @@ -0,0 +1,75 @@ + +from .base_exporter import BasePrimitiveDXFExporter + + +class InsertDXFExporter(BasePrimitiveDXFExporter): + pass + +#----------------------------------------------------- +def exportInsert(ob, mx, insert_name, **common): + """converts Object to DXF-INSERT in given orientation + """ + WCS_loc = ob.loc # WCS_loc is object location in WorldCoordSystem + sizeX = ob.SizeX + sizeY = ob.SizeY + sizeZ = ob.SizeZ + rotX = ob.RotX + rotY = ob.RotY + rotZ = ob.RotZ + #print 'deb: sizeX=%s, sizeY=%s' %(sizeX, sizeY) #--------- + + Thickness,Extrusion,ZRotation,Elevation = None,None,None,None + + AXaxis = mx[0].copy().resize3D() # = ArbitraryXvector + if not PROJECTION: + #Extrusion, ZRotation, Elevation = getExtrusion(mx) + Extrusion, AXaxis = getExtrusion(mx) + + entities = [] + + if 1: + if not PROJECTION: + ZRotation,Zrotmatrix,OCS_origin,ECS_origin = getTargetOrientation(mx,Extrusion,\ + AXaxis,WCS_loc,sizeX,sizeY,sizeZ,rotX,rotY,rotZ) + ZRotation *= r2d + point = ECS_origin + else: #TODO: fails correct location + point1 = mathutils.Vector(ob.loc) + [point] = projected_co([point1], mx) + if PERSPECTIVE: + clipStart = 10.0 + coef = -clipStart / (point1*mx)[2] + #print 'deb: coef=', coef #-------------- + #TODO: ? sizeX *= coef + #sizeY *= coef + #sizeZ *= coef + + #print 'deb: point=', point #-------------- + [point] = toGlobalOrigin([point]) + + #if DEBUG: text_drawBlender(textstr,points,OCS_origin) #deb: draw to scene + common['extrusion']= Extrusion + #common['elevation']= Elevation + #print 'deb: common=', common #------------------ + if 0: #DEBUG + #linepoints = [[0,0,0], [AXaxis[0],AXaxis[1],AXaxis[2]]] + linepoints = [[0,0,0], point] + dxfLINE = DXF.Line(linepoints,**common) + entities.append(dxfLINE) + + xscale=sizeX + yscale=sizeY + zscale=sizeZ + cols=None + colspacing=None + rows=None + rowspacing=None + + dxfINSERT = DXF.Insert(insert_name,point=point,rotation=ZRotation,\ + xscale=xscale,yscale=yscale,zscale=zscale,\ + cols=cols,colspacing=colspacing,rows=rows,rowspacing=rowspacing,\ + **common) + entities.append(dxfINSERT) + + return entities + diff --git a/io_export_dxf/primitive_exporters/lamp_exporter.py b/io_export_dxf/primitive_exporters/lamp_exporter.py new file mode 100644 index 00000000..01a65abd --- /dev/null +++ b/io_export_dxf/primitive_exporters/lamp_exporter.py @@ -0,0 +1,21 @@ +from .base_exporter import BasePrimitiveDXFExporter + + +class LampDXFExporter(BasePrimitiveDXFExporter): + pass + +#----------------------------------------------------- +def exportLamp(ob, mx, mw, **common): + """converts Lamp-Object to desired projection and representation(DXF-Entity type) + """ + p = mathutils.Vector(ob.loc) + [p] = projected_co([p], mx) + [p] = toGlobalOrigin([p]) + + entities = [] + c = lamp_as_list[GUI_A['lamp_as'].val] + if c=="POINT": # export as POINT + dxfPOINT = DXF.Point(points=[p],**common) + entities.append(dxfPOINT) + return entities + diff --git a/io_export_dxf/primitive_exporters/mesh_exporter.py b/io_export_dxf/primitive_exporters/mesh_exporter.py new file mode 100644 index 00000000..56509e32 --- /dev/null +++ b/io_export_dxf/primitive_exporters/mesh_exporter.py @@ -0,0 +1,154 @@ + +import mathutils +from .base_exporter import BasePrimitiveDXFExporter +import copy + +class MeshDXFExporter(BasePrimitiveDXFExporter): + + def export(self, ctx, drawing, ob, mx, mx_n, **kwargs): + """ + Converts Mesh-Object to desired projection and representation(DXF-Entity type) + """ + me = self._getMeshData(ctx, ob, self._settings) + # idea: me.transform(mx); get verts data; me.transform(mx_inv)= back to the origin state + # the .transform-method is fast, but bad, cause invasive: + # it manipulates original geometry and by retransformation lefts back rounding-errors + # we dont want to manipulate original data! + #temp_verts = me.verts[:] #doesn't work on ubuntu(Yorik), bug? + if me.vertices: + # check if there are more instances of this mesh (if used by other objects), then write to BLOCK/INSERT + if self.INSTANCES and me.users>1 and not self.PROJECTION and not (ob.modifiers and self._settings['apply_modifiers']): + if drawing.containsBlock(me.name): + entities = self._writeInsert(drawing, ob, mx, me.name) + else: + # generate geom_output in ObjectCS + allpoints = [v.co for v in me.vertices] + identity_matrix = mathutils.Matrix().identity() + allpoints = self.projected_co(allpoints, identity_matrix) + #allpoints = toGlobalOrigin(allpoints) + faces=[] + edges=[] + for e in me.edges: edges.append(e.key) + faces = [[v.index for v in f.verts] for f in me.faces] + entities = self._writeMeshEntities(allpoints, edges, faces, **kwargs) + if entities: # if not empty block + # write BLOCK definition and INSERT entity + # BLOCKREGISTRY = dictionary 'blender_name':'dxf_name'.append(me.name) +# BLOCKREGISTRY[me.name]=self.validDXFr12name(('ME_'+ me.name)) +# insert_name = BLOCKREGISTRY[me.name] + drawing.addBlock(me.name, flag=0,base=(0,0,0),entities=entities) +# block = DXF.Block(insert_name,flag=0,base=(0,0,0),entities=entities) + # write INSERT as entity + entities = self._writeInsert(ob, mx, me.name, **(kwargs)) + + else: # no other instances, so go the standard way + return self._standard_way(drawing, me, mx, mx_n) + + def _writeInsert(self, drawing, ob, mx, insert_name, **kwargs): + from insert_exporter import InsertDXFExporter + ex = InsertDXFExporter(self._settings) + ex.export(drawing, ob, mx, insert_name, **(kwargs)) + + def _getMeshData(self, ctx, obj, settings): + if obj.modifiers and settings['apply_modifiers']: + #this gets mesh with applied modifiers + data = obj.to_mesh(ctx.scene, True, 'PREVIEW') + else: + # me = ob.getData(mesh=1) # is a Mesh if mesh>0 (otherwise it is a NMesh) + data = obj.data + return data + + def _standard_way(self, drawing, me, mx, mx_n, **kwargs): + allpoints = [v.co for v in me.vertices] + allpoints = self.projected_co(allpoints, mx) + allpoints = self.toGlobalOrigin(allpoints) + faces=[] + edges=[] + me.update(calc_tessface=True) + me_faces = me.tessfaces + #print('deb: allpoints=\n', allpoints) #--------- + #print('deb: me_faces=\n', me_faces) #--------- + if me_faces and self.PROJECTION and self.HIDDEN_LINES: + #if DEBUG: print 'deb:exportMesh HIDDEN_LINES mode' #--------- + faces, edges = self.hidden_status(me_faces, mx, mx_n) + faces = [[v.index for v in me_faces[f_nr].vertices] for f_nr in faces] + else: + #if DEBUG: print 'deb:exportMesh STANDARD mode' #--------- + for e in me.edges: edges.append(e.key) + #faces = [f.index for f in me.faces] + ##faces = [[v.index for v in f.vertices] for f in me.faces] + faces = me_faces + #faces = [[allpoints[v.index] for v in f.vertices] for f in me.faces] + #print('deb: allpoints=\n', allpoints) #--------- + #print('deb: edges=\n', edges) #--------- + #print('deb: faces=\n', faces) #--------- + if self.isLeftHand(mx): # then change vertex-order in every face + for f in faces: + f.reverse() + #f = [f[-1]] + f[:-1] #TODO: might be needed + #print('deb: faces=\n', faces) #--------- + entities = self._writeMeshEntities(allpoints, edges, faces, **kwargs) + # TODO: rewrite + for type, args in entities: + drawing.addEntity(type, **(args)) + return True + + def _writeMeshEntities(self, allpoints, edges, faces, **kwargs): + """help routine for exportMesh() + """ + entities = [] + c = self._settings['mesh_as'] + if c=='POINTs': # export Mesh as multiple POINTs + for p in allpoints: + args = copy.copy(kwargs) + args['points'] = [p] + entities.append(('Point', args)) + elif c=='LINEs' or (not faces): + if edges and allpoints: +# if exportsettings['verbose']: +# mesh_drawBlender(allpoints, edges, None) #deb: draw to blender scene + for e in edges: + points = [allpoints[e[0]], allpoints[e[1]]] + args = copy.copy(kwargs) + args['points'] = points + entities.append(('Line', args)) + elif c in ('POLYFACE','POLYLINE'): + if faces and allpoints: + #TODO: purge allpoints: left only vertices used by faces +# if exportsettings['verbose']: +# mesh_drawBlender(allpoints, None, faces) #deb: draw to scene + if not (self.PROJECTION and self.HIDDEN_LINES): + faces = [[v+1 for v in f.vertices] for f in faces] + else: + # for back-Faces-mode remove face-free vertices + map=verts_state= [0]*len(allpoints) + for f in faces: + for v in f: + verts_state[v]=1 + if 0 in verts_state: # if dirty state + i,newverts=0,[] + for used_i,used in enumerate(verts_state): + if used: + newverts.append(allpoints[used_i]) + map[used_i]=i + i+=1 + allpoints = newverts + faces = [[map[v]+1 for v in f] for f in faces] + args = copy.copy(kwargs) + args['flag70'] = 64 + args['flag75'] = 0 + args['width'] = 0.0 + args['points'] = [allpoints, faces] + entities.append(('PolyLine', args)) + elif c=='3DFACEs': + if faces and allpoints: +# if exportsettings['verbose']: +# mesh_drawBlender(allpoints, None, faces) #deb: draw to scene + for f in faces: + points = [allpoints[v_id] for v_id in f.vertices] + args = copy.copy(kwargs) + args['points'] = points +# print(args) + entities.append(('Face', args)) + + return entities diff --git a/io_export_dxf/primitive_exporters/text_exporter.py b/io_export_dxf/primitive_exporters/text_exporter.py new file mode 100644 index 00000000..c7e9d173 --- /dev/null +++ b/io_export_dxf/primitive_exporters/text_exporter.py @@ -0,0 +1,89 @@ +from .base_exporter import BasePrimitiveDXFExporter + + +class TextDXFExporter(BasePrimitiveDXFExporter): + pass + +#----------------------------------------------------- +def exportText(ob, mx, mw, **common): + """converts Text-Object to desired projection and representation(DXF-Entity type) + """ + text3d = ob.getData() + textstr = text3d.getText() + WCS_loc = ob.loc # WCS_loc is object location in WorldCoordSystem + sizeX = ob.SizeX + sizeY = ob.SizeY + sizeZ = ob.SizeZ + rotX = ob.RotX + rotY = ob.RotY + rotZ = ob.RotZ + #print 'deb: sizeX=%s, sizeY=%s' %(sizeX, sizeY) #--------- + + Thickness,Extrusion,ZRotation,Elevation = None,None,None,None + + AXaxis = mx[0].copy().resize3D() # = ArbitraryXvector + if not PROJECTION: + #Extrusion, ZRotation, Elevation = getExtrusion(mx) + Extrusion, AXaxis = getExtrusion(mx) + + # no thickness/width for TEXTs converted into ScreenCS + if text3d.getExtrudeDepth(): + Thickness = text3d.getExtrudeDepth() * sizeZ + + #Horizontal text justification type, code 72, (optional, default = 0) + # integer codes (not bit-coded) + #0=left, 1=center, 2=right + #3=aligned, 4=middle, 5=fit + Alignment = None + alignment = text3d.getAlignment().value + if alignment in (1,2): Alignment = alignment + + textHeight = text3d.getSize() / 1.7 + textFlag = 0 + if sizeX < 0.0: textFlag |= 2 # set flag for horizontal mirrored + if sizeZ < 0.0: textFlag |= 4 # vertical mirrored + + entities = [] + c = text_as_list[GUI_A['text_as'].val] + + if c=="TEXT": # export text as TEXT + if not PROJECTION: + ZRotation,Zrotmatrix,OCS_origin,ECS_origin = getTargetOrientation(mx,Extrusion,\ + AXaxis,WCS_loc,sizeX,sizeY,sizeZ,rotX,rotY,rotZ) + ZRotation *= r2d + point = ECS_origin + else: #TODO: fails correct location + point1 = mathutils.Vector(ob.loc) + [point] = projected_co([point1], mx) + if PERSPECTIVE: + clipStart = 10.0 + coef = -clipStart / (point1*mx)[2] + textHeight *= coef + #print 'deb: coef=', coef #-------------- + + #print 'deb: point=', point #-------------- + [point] = toGlobalOrigin([point]) + point2 = point + + #if DEBUG: text_drawBlender(textstr,points,OCS_origin) #deb: draw to scene + common['extrusion']= Extrusion + #common['elevation']= Elevation + common['thickness']= Thickness + #print 'deb: common=', common #------------------ + if 0: #DEBUG + #linepoints = [[0,0,0], [AXaxis[0],AXaxis[1],AXaxis[2]]] + linepoints = [[0,0,0], point] + dxfLINE = DXF.Line(linepoints,**common) + entities.append(dxfLINE) + + dxfTEXT = DXF.Text(text=textstr,point=point,alignment=point2,rotation=ZRotation,\ + flag=textFlag,height=textHeight,justifyhor=Alignment,**common) + entities.append(dxfTEXT) + if Thickness: + common['thickness']= -Thickness + dxfTEXT = DXF.Text(text=textstr,point=point,alignment=point2,rotation=ZRotation,\ + flag=textFlag,height=textHeight,justifyhor=Alignment,**common) + entities.append(dxfTEXT) + return entities + + diff --git a/io_export_dxf/primitive_exporters/viewborder_exporter.py b/io_export_dxf/primitive_exporters/viewborder_exporter.py new file mode 100644 index 00000000..680e4a54 --- /dev/null +++ b/io_export_dxf/primitive_exporters/viewborder_exporter.py @@ -0,0 +1,24 @@ +from base_exporter import BasePrimitiveDXFExporter + + +class ViewBorderDXFExporter(BasePrimitiveDXFExporter): + + def export(self, ob, mx, mw, **common): + """converts Lamp-Object to desired projection and representation(DXF-Entity type) + """ + identity_matrix = mathutils.Matrix().identity() + points = projected_co(border, identity_matrix) + closed = 1 + points = toGlobalOrigin(points) + c = settings['curve_as'] + if c=="LINEs": # export Curve as multiple LINEs + for i in range(len(points)-1): + linepoints = [points[i], points[i+1]] + dxfLINE = DXF.Line(linepoints,paperspace=espace,color=LAYERCOLOR_DEF) + entities.append(dxfLINE) + else: + fag70, flag75 = closed, 0 + dxfPOLYFACE = DXF.PolyLine([allpoints, faces], flag70=flag70, flag75=flag70, width=0.0, paperspace=espace, color=LAYERCOLOR_DEF) + #dxfPLINE = DXF.PolyLine(points,points[0],[closed,0,0], paperspace=espace, color=LAYERCOLOR_DEF) + d.append(dxfPLINE) + -- cgit v1.2.3