8b2f089c6e
v1.27 - 2008.10.07 by migius - exclude Stani's DXF-Library to extern module - add "hidden mode" substitut: back-faces removal - add support for mesh ->POLYFACE - optimized code for "Flat" procedure - modif FACE class for r12 - add mesh-polygon -> Bezier-curve converter (Yorik's code) - add support for curves ->POLYLINEs - add "3d-View to Flat" - geometry projection to XY-plane
407 lines
13 KiB
Python
407 lines
13 KiB
Python
#!BPY
|
|
|
|
"""
|
|
Name: 'Autodesk DXF (.dxf)'
|
|
Blender: 247
|
|
Group: 'Export'
|
|
Tooltip: 'Export geometry to DXF-r12 (Drawing eXchange Format).'
|
|
"""
|
|
|
|
__version__ = "v1.27beta - 2008.10.07"
|
|
__author__ = "Remigiusz Fiedler (AKA migius)"
|
|
__license__ = "GPL"
|
|
__url__ = "http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_dxf"
|
|
__bpydoc__ ="""The script exports Blender geometry to DXF format r12 version.
|
|
|
|
Version %s
|
|
Copyright %s
|
|
License %s
|
|
|
|
extern dependances: dxfLibrary.py
|
|
|
|
See the homepage for documentation.
|
|
url: %s
|
|
|
|
IDEAs:
|
|
- correct normals for POLYLINE-POLYFACE via proper point-order
|
|
- HPGL output for 2d and flattened 3d content
|
|
|
|
TODO:
|
|
- optimize back-faces removal (probably needs matrix transform)
|
|
- optimize POLYFACE routine: remove double-vertices
|
|
- optimize POLYFACE routine: remove unused vertices
|
|
- support hierarchies: groups, instances, parented structures
|
|
- support 210-code (3d orientation vector)
|
|
- presets for architectural scales
|
|
- write drawing extends for automatic view positioning in CAD
|
|
|
|
History
|
|
v1.27 - 2008.10.07 by migius
|
|
- exclude Stani's DXF-Library to extern module
|
|
v1.26 - 2008.10.05 by migius
|
|
- add "hidden mode" substitut: back-faces removal
|
|
- add support for mesh ->POLYFACE
|
|
- optimized code for "Flat" procedure
|
|
v1.25 - 2008.09.28 by migius
|
|
- modif FACE class for r12
|
|
- add mesh-polygon -> Bezier-curve converter (Yorik's code)
|
|
- add support for curves ->POLYLINEs
|
|
- add "3d-View to Flat" - geometry projection to XY-plane
|
|
v1.24 - 2008.09.27 by migius
|
|
- add start UI with preferences
|
|
- modif POLYLINE class for r12
|
|
- changing output format from r9 to r12(AC1009)
|
|
v1.23 - 2008.09.26 by migius
|
|
- add finish message-box
|
|
v1.22 - 2008.09.26 by migius
|
|
- add support for curves ->LINEs
|
|
- add support for mesh-edges ->LINEs
|
|
v1.21 - 2008.06.04 by migius
|
|
- initial adaptation for Blender
|
|
v1.1 (20/6/2005) by Stani Michiels www.stani.be/python/sdxf
|
|
- Python library to generate dxf drawings
|
|
______________________________________________________________
|
|
""" % (__author__,__version__,__license__,__url__)
|
|
|
|
# --------------------------------------------------------------------------
|
|
# Script copyright (C) 2008 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
|
|
|
|
#import dxfLibrary
|
|
#reload(dxfLibrary)
|
|
from dxfLibrary import *
|
|
|
|
|
|
#-----------------------------------------------------
|
|
def hidden_status(faces, mx_n):
|
|
#print 'HIDDEN_MODE: caution! not full implemented yet'
|
|
ok_faces = []
|
|
ok_edges = []
|
|
#sort out back-faces = with normals pointed away from camera
|
|
for f in faces:
|
|
#print 'deb: face=', 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' #------------------
|
|
|
|
# normal must point the Z direction-hemisphere
|
|
if vec_normal[2] > 0.0 :
|
|
ok_faces.append(f.index)
|
|
for key in f.edge_keys:
|
|
#this test can be done faster with set()
|
|
if key not in ok_edges:
|
|
ok_edges.append(key)
|
|
#print 'deb: amount of visible faces=', len(ok_faces) #---------
|
|
#print 'deb: visible faces=', ok_faces #---------
|
|
#print 'deb: amount of visible edges=', len(ok_edges) #---------
|
|
#print 'deb: visible edges=', ok_edges #---------
|
|
return ok_faces, ok_edges
|
|
|
|
|
|
#-----------------------------------------------------
|
|
def projected_co(vec, mw):
|
|
# convert the world coordinates of vector to screen coordinates
|
|
#co = vec.co.copy().resize4D()
|
|
co = vec.copy().resize4D()
|
|
co[3] = 1.0
|
|
sc = co * mw
|
|
#print 'deb: viewprojection=', sc #---------
|
|
return [sc[0],sc[1],0.0]
|
|
|
|
|
|
#--------not used---------------------------------------------
|
|
def flatten(points, mw):
|
|
for i,v in enumerate(points):
|
|
v = projected_co(v, mw)
|
|
points[i]=v
|
|
#print 'deb: flatten points=', points #---------
|
|
return points
|
|
|
|
#-----------------------------------------------------
|
|
def exportMesh(ob, mx, mx_n):
|
|
entities = []
|
|
me = ob.getData(mesh=1)
|
|
#me.transform(mx)
|
|
# above is eventualy faster, but bad, cause
|
|
# directly transforms origin geometry and write back rounding errors
|
|
me_verts = me.verts[:] #we dont want manipulate origin data
|
|
#print 'deb: me_verts=', me_verts #---------
|
|
#me.transform(mx_inv) #counterpart to - back to the origin state
|
|
for v in me_verts:
|
|
v.co *= mx
|
|
faces=[]
|
|
edges=[]
|
|
if HIDDEN_MODE:
|
|
ok_faces, ok_edges = hidden_status(me.faces, mx_n)
|
|
|
|
#if (not FLATTEN) and len(me.faces)>0 and ONLYFACES:
|
|
if ONLYFACES:
|
|
if POLYFACES: #export 3D as POLYFACEs
|
|
allpoints = []
|
|
allfaces = []
|
|
allpoints = [v.co[:3] for v in me_verts]
|
|
for f in me.faces:
|
|
#print 'deb: face=', f #---------
|
|
if not HIDDEN_MODE or \
|
|
(HIDDEN_MODE and f.index in ok_faces):
|
|
if 1:
|
|
points = f.verts
|
|
face = [p.index+1 for p in points]
|
|
#print 'deb: face=', face #---------
|
|
allfaces.append(face)
|
|
else: #bad, cause create multiple vertex instances
|
|
points = f.verts
|
|
points = [ me_verts[p.index].co[:3] for p in points]
|
|
#points = [p.co[:3] for p in points]
|
|
#print 'deb: points=', points #---------
|
|
index = len(allpoints)+1
|
|
face = [index+i for i in range(len(points))]
|
|
allpoints.extend(points)
|
|
allfaces.append(face)
|
|
if allpoints and allfaces:
|
|
#print 'deb: allpoints=', allpoints #---------
|
|
#print 'deb: allfaces=', allfaces #---------
|
|
dxfPOLYFACE = PolyLine([allpoints, allfaces], flag=64)
|
|
entities.append(dxfPOLYFACE)
|
|
else: #export 3D as 3DFACEs
|
|
for f in me.faces:
|
|
#print 'deb: face=', f #---------
|
|
if not HIDDEN_MODE or \
|
|
(HIDDEN_MODE and f.index in ok_faces):
|
|
points = f.verts
|
|
points = [ me_verts[p.index].co[:3] for p in points]
|
|
#points = [p.co[:3] for p in points]
|
|
#print 'deb: points=', points #---------
|
|
dxfFACE = Face(points)
|
|
entities.append(dxfFACE)
|
|
|
|
else: #export 3D as LINEs
|
|
if HIDDEN_MODE and len(me.faces)!=0:
|
|
for e in ok_edges:
|
|
points = [ me_verts[key].co[:3] for key in e]
|
|
dxfLINE = Line(points)
|
|
entities.append(dxfLINE)
|
|
|
|
else:
|
|
for e in me.edges:
|
|
#print 'deb: edge=', e #---------
|
|
points=[]
|
|
#points = [e.v1.co*mx, e.v2.co*mx]
|
|
points = [ me_verts[key].co[:3] for key in e.key]
|
|
#print 'deb: points=', points #---------
|
|
dxfLINE = Line(points)
|
|
entities.append(dxfLINE)
|
|
return entities
|
|
|
|
|
|
#-----------------------------------------------------
|
|
def exportCurve(ob, mx):
|
|
entities = []
|
|
curve = ob.getData()
|
|
for cur in curve:
|
|
#print 'deb: START cur=', cur #--------------
|
|
if 1: #not cur.isNurb():
|
|
#print 'deb: START points' #--------------
|
|
points = []
|
|
org_point = [0.0,0.0,0.0]
|
|
for point in cur:
|
|
#print 'deb: point=', point #---------
|
|
if cur.isNurb():
|
|
vec = point[0:3]
|
|
else:
|
|
point = point.getTriple()
|
|
#print 'deb: point=', point #---------
|
|
vec = point[1]
|
|
#print 'deb: vec=', vec #---------
|
|
pkt = Mathutils.Vector(vec) * mx
|
|
#print 'deb: pkt=', pkt #---------
|
|
#pkt *= SCALE_FACTOR
|
|
if 0: #FLATTEN:
|
|
pkt = projected_co(pkt, mw)
|
|
points.append(pkt)
|
|
if cur.isCyclic(): closed = 1
|
|
else: closed = 0
|
|
if len(points)>1:
|
|
#print 'deb: points', points #--------------
|
|
if POLYLINES: dxfPLINE = PolyLine(points,org_point,closed)
|
|
else: dxfPLINE = LineList(points,org_point,closed)
|
|
entities.append(dxfPLINE)
|
|
return entities
|
|
|
|
#-----------------------------------------------------
|
|
def do_export(sel_group, filepath):
|
|
Window.WaitCursor(1)
|
|
t = sys.time()
|
|
|
|
#init Drawing ---------------------
|
|
d=Drawing()
|
|
#add 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
|
|
|
|
#add Entities --------------------
|
|
something_ready = False
|
|
#ViewVector = Mathutils.Vector(Window.GetViewVector())
|
|
#print 'deb: ViewVector=', ViewVector #------------------
|
|
mw0 = Window.GetViewMatrix()
|
|
#mw0 = Window.GetPerspMatrix() #TODO: how get it working?
|
|
mw = mw0.copy()
|
|
if FLATTEN:
|
|
m0 = Mathutils.Matrix()
|
|
m0[2][2]=0.0
|
|
mw *= m0 #flatten ViewMatrix
|
|
|
|
for ob in sel_group:
|
|
entities = []
|
|
mx = ob.matrix.copy()
|
|
mb = mx.copy()
|
|
#print 'deb: mb =\n', mb #---------
|
|
#print 'deb: mw0 =\n', mw0 #---------
|
|
mx_n = mx.rotationPart() * mw0.rotationPart() #trans-matrix for normal_vectors
|
|
if SCALE_FACTOR!=1.0: mx *= SCALE_FACTOR
|
|
if FLATTEN: mx *= mw
|
|
|
|
#mx_inv = mx.copy().invert()
|
|
#print 'deb: mx =\n', mx #---------
|
|
#print 'deb: mx_inv=\n', mx_inv #---------
|
|
|
|
if (ob.type == 'Mesh'):
|
|
entities = exportMesh(ob, mx, mx_n)
|
|
elif (ob.type == 'Curve'):
|
|
entities = exportCurve(ob, mx)
|
|
|
|
for e in entities:
|
|
d.append(e)
|
|
something_ready = True
|
|
|
|
if something_ready:
|
|
d.saveas(filepath)
|
|
Window.WaitCursor(0)
|
|
#Draw.PupMenu('DXF Exporter: job finished')
|
|
print 'exported to %s' % filepath
|
|
print 'finished in %.2f seconds' % (sys.time()-t)
|
|
else:
|
|
Window.WaitCursor(0)
|
|
print "Abort: selected objects dont mach choosen export option, nothing exported!"
|
|
Draw.PupMenu('DXF Exporter: nothing exported!|selected objects dont mach choosen export option!')
|
|
|
|
#----globals------------------------------------------
|
|
ONLYSELECTED = True
|
|
POLYLINES = True
|
|
ONLYFACES = False
|
|
POLYFACES = 1
|
|
FLATTEN = 0
|
|
HIDDEN_MODE = False #filter out hidden lines
|
|
SCALE_FACTOR = 1.0 #optional, can be done later in CAD too
|
|
|
|
|
|
|
|
#-----------------------------------------------------
|
|
def dxf_export_ui(filepath):
|
|
global ONLYSELECTED,\
|
|
POLYLINES,\
|
|
ONLYFACES,\
|
|
POLYFACES,\
|
|
FLATTEN,\
|
|
HIDDEN_MODE,\
|
|
SCALE_FACTOR
|
|
|
|
print '\n\nDXF-Export %s -----------------------' %__version__
|
|
#filepath = 'blend_test.dxf'
|
|
# Dont overwrite
|
|
if not BPyMessages.Warning_SaveOver(filepath):
|
|
print 'Aborted by user: nothing exported'
|
|
return
|
|
#test():return
|
|
|
|
|
|
PREF_ONLYSELECTED= Draw.Create(ONLYSELECTED)
|
|
PREF_POLYLINES= Draw.Create(POLYLINES)
|
|
PREF_ONLYFACES= Draw.Create(ONLYFACES)
|
|
PREF_POLYFACES= Draw.Create(POLYFACES)
|
|
PREF_FLATTEN= Draw.Create(FLATTEN)
|
|
PREF_HIDDEN_MODE= Draw.Create(HIDDEN_MODE)
|
|
PREF_SCALE_FACTOR= Draw.Create(SCALE_FACTOR)
|
|
PREF_HELP= Draw.Create(0)
|
|
block = [\
|
|
("only selected", PREF_ONLYSELECTED, "export only selected geometry"),\
|
|
("global Scale:", PREF_SCALE_FACTOR, 0.001, 1000, "set global Scale factor for exporting geometry"),\
|
|
("only faces", PREF_ONLYFACES, "from mesh-objects export only faces, otherwise only edges"),\
|
|
("write POLYFACE", PREF_POLYFACES, "export mesh to POLYFACE, otherwise to 3DFACEs"),\
|
|
("write POLYLINEs", PREF_POLYLINES, "export curve to POLYLINE, otherwise to LINEs"),\
|
|
("3D-View to Flat", PREF_FLATTEN, "flatten geometry according current 3d-View"),\
|
|
("Hidden Mode", PREF_HIDDEN_MODE, "filter out hidden lines"),\
|
|
#(''),\
|
|
("online Help", PREF_HELP, "calls DXF-Exporter Manual Page on Wiki.Blender.org"),\
|
|
]
|
|
|
|
if not Draw.PupBlock("DXF-Exporter %s" %__version__[:10], block): return
|
|
|
|
if PREF_HELP.val!=0:
|
|
try:
|
|
import webbrowser
|
|
webbrowser.open('http://wiki.blender.org/index.php?title=Scripts/Manual/Export/autodesk_dxf')
|
|
except:
|
|
Draw.PupMenu('DXF Exporter: %t|no connection to manual-page on Blender-Wiki! try:|\
|
|
http://wiki.blender.org/index.php?title=Scripts/Manual/Export/autodesk_dxf')
|
|
return
|
|
|
|
ONLYSELECTED = PREF_ONLYSELECTED.val
|
|
POLYLINES = PREF_POLYLINES.val
|
|
ONLYFACES = PREF_ONLYFACES.val
|
|
POLYFACES = PREF_POLYFACES.val
|
|
FLATTEN = PREF_FLATTEN.val
|
|
HIDDEN_MODE = PREF_HIDDEN_MODE.val
|
|
SCALE_FACTOR = PREF_SCALE_FACTOR.val
|
|
|
|
sce = Scene.GetCurrent()
|
|
if ONLYSELECTED: sel_group = sce.objects.selected
|
|
else: sel_group = sce.objects
|
|
|
|
if sel_group: do_export(sel_group, filepath)
|
|
else:
|
|
print "Abort: selection was empty, no object to export!"
|
|
Draw.PupMenu('DXF Exporter: nothing exported!|empty selection!')
|
|
# Timing the script is a good way to be aware on any speed hits when scripting
|
|
|
|
|
|
|
|
#-----------------------------------------------------
|
|
if __name__=='__main__':
|
|
#main()
|
|
if not copy:
|
|
Draw.PupMenu('Error%t|This script requires a full python install')
|
|
Window.FileSelector(dxf_export_ui, 'EXPORT DXF', sys.makename(ext='.dxf'))
|
|
|
|
|
|
|