~valavanisalex/ubuntu/precise/inkscape/fix-943984

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/share/extensions/polyhedron_3d.py

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2009-07-02 17:09:45 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702170945-nn6d6zswovbwju1t
Tags: 0.47~pre1-0ubuntu1
* New upstream release.
  - Don't constrain maximization on small resolution devices (pre0)
    (LP: #348842)
  - Fixes segfault on startup (pre0)
    (LP: #391149)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python 
 
2
'''
 
3
Copyright (C) 2007 John Beard john.j.beard@gmail.com
 
4
 
 
5
##This extension draws 3d objects from a Wavefront .obj 3D file stored in a local folder
 
6
##Many settings for appearance, lighting, rotation, etc are available.
 
7
 
 
8
#                              ^y
 
9
#                              |
 
10
#        __--``|               |_--``|     __--
 
11
#  __--``      |         __--``|     |_--``
 
12
# |       z    |        |      |_--``|
 
13
# |       <----|--------|-----_0-----|----------------
 
14
# |            |        |_--`` |     |
 
15
# |      __--``     <-``|      |_--``
 
16
# |__--``           x   |__--``|
 
17
#   IMAGE PLANE           SCENE|
 
18
#                              |
 
19
 
 
20
#Vertices are given as "v" followed by three numbers (x,y,z).
 
21
#All files need a vertex list
 
22
#v  x.xxx   y.yyy   z.zzz
 
23
 
 
24
#Faces are given by a list of vertices
 
25
#(vertex 1 is the first in the list above, 2 the second, etc):
 
26
#f  1   2   3
 
27
 
 
28
#Edges are given by a list of vertices. These will be broken down
 
29
#into adjacent pairs automatically.
 
30
#l  1   2   3
 
31
 
 
32
#Faces are rendered according to the painter's algorithm and perhaps
 
33
#back-face culling, if selected. The parameter to sort the faces by
 
34
#is user-selectable between max, min and average z-value of the vertices
 
35
 
 
36
######LICENCE#######
 
37
This program is free software; you can redistribute it and/or modify
 
38
it under the terms of the GNU General Public License as published by
 
39
the Free Software Foundation; either version 2 of the License, or
 
40
(at your option) any later version.
 
41
 
 
42
This program is distributed in the hope that it will be useful,
 
43
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
44
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
45
GNU General Public License for more details.
 
46
 
 
47
You should have received a copy of the GNU General Public License
 
48
along with this program; if not, write to the Free Software
 
49
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
50
'''
 
51
 
 
52
import inkex
 
53
import simplestyle, sys, re
 
54
from math import *
 
55
try:
 
56
    from numpy import *
 
57
except:
 
58
    inkex.errormsg(_("Failed to import the numpy module. This module is required by this extension. Please install them and try again.  On a Debian-like system this can be done with the command, sudo apt-get install python-numpy."))
 
59
    sys.exit()
 
60
 
 
61
#FILE IO ROUTINES
 
62
def get_filename(self_options):
 
63
        if self_options.obj == 'from_file':
 
64
            file = self_options.spec_file
 
65
        else:
 
66
            file = self_options.obj + '.obj'
 
67
            
 
68
        return file
 
69
 
 
70
def objfile(name):
 
71
    import os.path
 
72
    if __name__ == '__main__':
 
73
        filename = sys.argv[0]
 
74
    else:
 
75
        filename = __file__
 
76
    path = os.path.abspath(os.path.dirname(filename))
 
77
    path = os.path.join(path, 'Poly3DObjects', name)
 
78
    return path
 
79
    
 
80
def get_obj_data(obj, name):
 
81
    infile = open(objfile(name))
 
82
    
 
83
    #regular expressions
 
84
    getname = '(.[nN]ame:\\s*)(.*)'
 
85
    floating = '([\-\+\\d*\.e]*)'   #a possibly non-integer number, with +/- and exponent.
 
86
    getvertex = '(v\\s+)'+floating+'\\s+'+floating+'\\s+'+floating
 
87
    getedgeline = '(l\\s+)(.*)'
 
88
    getfaceline = '(f\\s+)(.*)'
 
89
    getnextint = '(\\d+)([/\\d]*)(.*)'#we need to deal with 123\343\123 or 123\\456 as equivalent to 123 (we are ignoring the other options in the obj file)
 
90
    
 
91
    for line in infile:
 
92
        if line[0]=='#':                    #we have a comment line
 
93
            m = re.search(getname, line)        #check to see if this line contains a name
 
94
            if m:
 
95
                obj.name = m.group(2)           #if it does, set the property
 
96
        elif line[0] == 'v':                #we have a vertex (maybe)
 
97
            m = re.search(getvertex, line)      #check to see if this line contains a valid vertex
 
98
            if m:                               #we have a valid vertex
 
99
                obj.vtx.append( [float(m.group(2)), float(m.group(3)), float(m.group(4)) ] )
 
100
        elif line[0] == 'l':                #we have a line (maybe)
 
101
            m = re.search(getedgeline, line)    #check to see if this line begins 'l '
 
102
            if m:                               #we have a line beginning 'l '
 
103
                vtxlist = []    #buffer
 
104
                while line:
 
105
                    m2 = re.search(getnextint, line)
 
106
                    if m2:
 
107
                        vtxlist.append( int(m2.group(1)) )
 
108
                        line = m2.group(3)#remainder
 
109
                    else:
 
110
                        line = None
 
111
                if len(vtxlist) > 1:#we need at least 2 vertices to make an edge
 
112
                    for i in range (len(vtxlist)-1):#we can have more than one vertex per line - get adjacent pairs
 
113
                        obj.edg.append( ( vtxlist[i], vtxlist[i+1] ) )#get the vertex pair between that vertex and the next
 
114
        elif line[0] == 'f':                #we have a face (maybe)
 
115
            m = re.search(getfaceline, line)
 
116
            if m:                               #we have a line beginning 'f '
 
117
                vtxlist = []#buffer
 
118
                while line:
 
119
                    m2 = re.search(getnextint, line)
 
120
                    if m2:
 
121
                        vtxlist.append( int(m2.group(1)) )
 
122
                        line = m2.group(3)#remainder
 
123
                    else:
 
124
                        line = None
 
125
                if len(vtxlist) > 2:            #we need at least 3 vertices to make an edge
 
126
                    obj.fce.append(vtxlist)
 
127
    
 
128
    if obj.name == '':#no name was found, use filename, without extension (.obj)
 
129
        obj.name = name[0:-4]
 
130
 
 
131
#RENDERING AND SVG OUTPUT FUNCTIONS
 
132
 
 
133
def draw_SVG_dot((cx, cy), st, name, parent):
 
134
    style = { 'stroke': '#000000', 'stroke-width':str(st.th), 'fill': st.fill, 'stroke-opacity':st.s_opac, 'fill-opacity':st.f_opac}
 
135
    circ_attribs = {'style':simplestyle.formatStyle(style),
 
136
                    inkex.addNS('label','inkscape'):name,
 
137
                    'r':str(st.r),
 
138
                    'cx':str(cx), 'cy':str(-cy)}
 
139
    inkex.etree.SubElement(parent, inkex.addNS('circle','svg'), circ_attribs )
 
140
    
 
141
def draw_SVG_line((x1, y1),(x2, y2), st, name, parent):
 
142
    style = { 'stroke': '#000000', 'stroke-width':str(st.th), 'stroke-linecap':st.linecap}
 
143
    line_attribs = {'style':simplestyle.formatStyle(style),
 
144
                    inkex.addNS('label','inkscape'):name,
 
145
                    'd':'M '+str(x1)+','+str(-y1)+' L '+str(x2)+','+str(-y2)}
 
146
    inkex.etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs )
 
147
    
 
148
def draw_SVG_poly(pts, face, st, name, parent):
 
149
    style = { 'stroke': '#000000', 'stroke-width':str(st.th), 'stroke-linejoin':st.linejoin, \
 
150
              'stroke-opacity':st.s_opac, 'fill': st.fill, 'fill-opacity':st.f_opac}   
 
151
    for i in range(len(face)):
 
152
        if i == 0:#for first point
 
153
            d = 'M'#move to
 
154
        else:
 
155
            d = d + 'L'#line to
 
156
        d = d+ str(pts[face[i]-1][0]) + ',' + str(-pts[face[i]-1][1])#add point
 
157
    d = d + 'z' #close the polygon
 
158
    
 
159
    line_attribs = {'style':simplestyle.formatStyle(style),
 
160
                    inkex.addNS('label','inkscape'):name,'d': d}
 
161
    inkex.etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs )
 
162
    
 
163
def draw_edges( edge_list, pts, st, parent ):
 
164
    for edge in edge_list:#for every edge
 
165
        pt_1 = pts[ edge[0]-1 ][0:2] #the point at the start
 
166
        pt_2 = pts[ edge[1]-1 ][0:2] #the point at the end
 
167
        name = 'Edge'+str(edge[0])+'-'+str(edge[1])
 
168
        draw_SVG_line(pt_1,pt_2,st, name, parent)#plot edges
 
169
                              
 
170
def draw_faces( faces_data, pts, obj, shading, fill_col,st, parent):          
 
171
    for face in faces_data:#for every polygon that has been sorted
 
172
        if shading:
 
173
            st.fill = get_darkened_colour(fill_col, face[1]/pi)#darken proportionally to angle to lighting vector
 
174
        else:
 
175
            st.fill = get_darkened_colour(fill_col, 1)#do not darken colour
 
176
                          
 
177
        face_no = face[3]#the number of the face to draw
 
178
        draw_SVG_poly(pts, obj.fce[ face_no ], st, 'Face:'+str(face_no), parent)
 
179
 
 
180
def get_darkened_colour( (r,g,b), factor):
 
181
#return a hex triplet of colour, reduced in lightness proportionally to a value between 0 and 1
 
182
    return  '#' + "%02X" % floor( factor*r ) \
 
183
                + "%02X" % floor( factor*g ) \
 
184
                + "%02X" % floor( factor*b ) #make the colour string
 
185
 
 
186
def make_rotation_log(options):
 
187
#makes a string recording the axes and angles of each roation, so an object can be repeated
 
188
    return   options.r1_ax+str('%.2f'%options.r1_ang)+':'+\
 
189
             options.r2_ax+str('%.2f'%options.r2_ang)+':'+\
 
190
             options.r3_ax+str('%.2f'%options.r3_ang)+':'+\
 
191
             options.r1_ax+str('%.2f'%options.r4_ang)+':'+\
 
192
             options.r2_ax+str('%.2f'%options.r5_ang)+':'+\
 
193
             options.r3_ax+str('%.2f'%options.r6_ang)
 
194
 
 
195
#MATHEMATICAL FUNCTIONS
 
196
def get_angle( vector1, vector2 ): #returns the angle between two vectors
 
197
    return acos( dot(vector1, vector2) )
 
198
 
 
199
def length(vector):#return the pythagorean length of a vector
 
200
    return sqrt(dot(vector,vector))
 
201
 
 
202
def normalise(vector):#return the unit vector pointing in the same direction as the argument
 
203
    return vector / length(vector)
 
204
 
 
205
def get_normal( pts, face): #returns the normal vector for the plane passing though the first three elements of face of pts
 
206
    #n = pt[0]->pt[1] x pt[0]->pt[3]
 
207
    a = (array(pts[ face[0]-1 ]) - array(pts[ face[1]-1 ]))
 
208
    b = (array(pts[ face[0]-1 ]) - array(pts[ face[2]-1 ]))
 
209
    return cross(a,b).flatten()
 
210
 
 
211
def get_unit_normal(pts, face, cw_wound): #returns the unit normal for the plane passing through the first three points of face, taking account of winding
 
212
    if cw_wound:
 
213
        winding = -1 #if it is clockwise wound, reverse the vecotr direction
 
214
    else:
 
215
        winding = 1 #else leave alone
 
216
    
 
217
    return winding*normalise(get_normal(pts, face))
 
218
 
 
219
def rotate( matrix, angle, axis ):#choose the correct rotation matrix to use
 
220
    if   axis == 'x':
 
221
        matrix = rot_x(matrix, angle)
 
222
    elif axis == 'y':
 
223
        matrix = rot_y(matrix, angle)
 
224
    elif axis == 'z':
 
225
        matrix = rot_z(matrix, angle)
 
226
    return matrix
 
227
    
 
228
def rot_z( matrix , a):#rotate around the z-axis by a radians
 
229
    trans_mat = mat(array( [[ cos(a) , -sin(a) ,    0   ],
 
230
                            [ sin(a) ,  cos(a) ,    0   ],
 
231
                            [   0    ,    0    ,    1   ]]))
 
232
    return trans_mat*matrix
 
233
 
 
234
def rot_y( matrix , a):#rotate around the y-axis by a radians
 
235
    trans_mat = mat(array( [[ cos(a) ,    0    , sin(a) ],
 
236
                            [   0    ,    1    ,    0   ],
 
237
                            [-sin(a) ,    0    , cos(a) ]]))
 
238
    return trans_mat*matrix
 
239
    
 
240
def rot_x( matrix , a):#rotate around the x-axis by a radians
 
241
    trans_mat = mat(array( [[   1    ,    0    ,    0   ],
 
242
                            [   0    ,  cos(a) ,-sin(a) ],
 
243
                            [   0    ,  sin(a) , cos(a) ]]))
 
244
    return trans_mat*matrix
 
245
 
 
246
def get_transformed_pts( vtx_list, trans_mat):#translate the points according to the matrix
 
247
    transformed_pts = []
 
248
    for vtx in vtx_list:
 
249
        transformed_pts.append((trans_mat * mat(vtx).T).T.tolist()[0] )#transform the points at add to the list
 
250
    return transformed_pts
 
251
 
 
252
def get_max_z(pts, face): #returns the largest z_value of any point in the face
 
253
    max_z = pts[ face[0]-1 ][2]
 
254
    for i in range(1, len(face)):
 
255
        if pts[ face[0]-1 ][2] >= max_z:
 
256
            max_z = pts[ face[0]-1 ][2]
 
257
    return max_z
 
258
    
 
259
def get_min_z(pts, face): #returns the smallest z_value of any point in the face
 
260
    min_z = pts[ face[0]-1 ][2]
 
261
    for i in range(1, len(face)):
 
262
        if pts[ face[i]-1 ][2] <= min_z:
 
263
            min_z = pts[ face[i]-1 ][2]
 
264
    return min_z
 
265
    
 
266
def get_cent_z(pts, face): #returns the centroid z_value of any point in the face
 
267
    sum = 0
 
268
    for i in range(len(face)):
 
269
            sum += pts[ face[i]-1 ][2]
 
270
    return sum/len(face)
 
271
    
 
272
def get_z_sort_param(pts, face, method): #returns the z-sorting parameter specified by 'method' ('max', 'min', 'cent')  
 
273
    z_sort_param = ''
 
274
    if  method == 'max':
 
275
        z_sort_param  = get_max_z(pts, face)
 
276
    elif method == 'min':
 
277
        z_sort_param  = get_min_z(pts, face)
 
278
    else:
 
279
        z_sort_param  = get_cent_z(pts, face)
 
280
    return z_sort_param
 
281
 
 
282
#OBJ DATA MANIPULATION
 
283
def remove_duplicates(list):#removes the duplicates from a list
 
284
    list.sort()#sort the list
 
285
 
 
286
    last = list[-1]
 
287
    for i in range(len(list)-2, -1, -1):
 
288
        if last==list[i]:
 
289
            del list[i]
 
290
        else:
 
291
            last = list[i]
 
292
    return list
 
293
 
 
294
def make_edge_list(face_list):#make an edge vertex list from an existing face vertex list
 
295
    edge_list = []
 
296
    for i in range(len(face_list)):#for every face
 
297
        edges = len(face_list[i]) #number of edges around that face
 
298
        for j in range(edges):#for every vertex in that face
 
299
            new_edge = [face_list[i][j], face_list[i][(j+1)%edges] ]
 
300
            new_edge.sort() #put in ascending order of vertices (to ensure we spot duplicates)
 
301
            edge_list.append( new_edge )#get the vertex pair between that vertex and the next
 
302
    
 
303
    return remove_duplicates(edge_list)
 
304
    
 
305
class Style(object): #container for style information
 
306
    def __init__(self,options):
 
307
        self.th = options.th
 
308
        self.fill= '#ff0000'
 
309
        self.col = '#000000'
 
310
        self.r = 2
 
311
        self.f_opac = str(options.f_opac/100.0)
 
312
        self.s_opac = str(options.s_opac/100.0)
 
313
        self.linecap = 'round'
 
314
        self.linejoin = 'round'
 
315
 
 
316
class Obj(object): #a 3d object defined by the vertices and the faces (eg a polyhedron)
 
317
#edges can be generated from this information
 
318
    def __init__(self):
 
319
        self.vtx = []
 
320
        self.edg = []
 
321
        self.fce = []
 
322
        self.name=''
 
323
        
 
324
    def set_type(self, options):
 
325
        if options.type == 'face':
 
326
            if self.fce != []:
 
327
                self.type = 'face'
 
328
            else:
 
329
                inkex.errormsg(_('No face data found in specified file\n'))
 
330
                self.type = 'error'
 
331
        else:
 
332
            if self.edg != []:
 
333
                self.type = 'edge'
 
334
            else:
 
335
                inkex.errormsg(_('No edge data found in specified file\n'))
 
336
                obj.type = 'error'
 
337
 
 
338
class Poly_3D(inkex.Effect):
 
339
    def __init__(self):
 
340
        inkex.Effect.__init__(self)
 
341
        self.OptionParser.add_option("--tab",
 
342
            action="store", type="string", 
 
343
            dest="tab", default="object") 
 
344
 
 
345
#MODEL FILE SETTINGS
 
346
        self.OptionParser.add_option("--obj",
 
347
            action="store", type="string", 
 
348
            dest="obj", default='cube')
 
349
        self.OptionParser.add_option("--spec_file",
 
350
            action="store", type="string", 
 
351
            dest="spec_file", default='great_rhombicuboct.obj')
 
352
        self.OptionParser.add_option("--cw_wound",
 
353
            action="store", type="inkbool", 
 
354
            dest="cw_wound", default='true')
 
355
        self.OptionParser.add_option("--type",
 
356
            action="store", type="string", 
 
357
            dest="type", default='face')
 
358
#VEIW SETTINGS
 
359
        self.OptionParser.add_option("--r1_ax",
 
360
            action="store", type="string", 
 
361
            dest="r1_ax", default=0)
 
362
        self.OptionParser.add_option("--r2_ax",
 
363
            action="store", type="string", 
 
364
            dest="r2_ax", default=0)
 
365
        self.OptionParser.add_option("--r3_ax",
 
366
            action="store", type="string", 
 
367
            dest="r3_ax", default=0)
 
368
        self.OptionParser.add_option("--r4_ax",
 
369
            action="store", type="string", 
 
370
            dest="r4_ax", default=0)
 
371
        self.OptionParser.add_option("--r5_ax",
 
372
            action="store", type="string", 
 
373
            dest="r5_ax", default=0)
 
374
        self.OptionParser.add_option("--r6_ax",
 
375
            action="store", type="string", 
 
376
            dest="r6_ax", default=0)
 
377
        self.OptionParser.add_option("--r1_ang",
 
378
            action="store", type="float", 
 
379
            dest="r1_ang", default=0)
 
380
        self.OptionParser.add_option("--r2_ang",
 
381
            action="store", type="float", 
 
382
            dest="r2_ang", default=0)
 
383
        self.OptionParser.add_option("--r3_ang",
 
384
            action="store", type="float", 
 
385
            dest="r3_ang", default=0)
 
386
        self.OptionParser.add_option("--r4_ang",
 
387
            action="store", type="float", 
 
388
            dest="r4_ang", default=0)
 
389
        self.OptionParser.add_option("--r5_ang",
 
390
            action="store", type="float", 
 
391
            dest="r5_ang", default=0)
 
392
        self.OptionParser.add_option("--r6_ang",
 
393
            action="store", type="float", 
 
394
            dest="r6_ang", default=0)
 
395
        self.OptionParser.add_option("--scl",
 
396
            action="store", type="float", 
 
397
            dest="scl", default=100.0)
 
398
#STYLE SETTINGS
 
399
        self.OptionParser.add_option("--show",
 
400
            action="store", type="string", 
 
401
            dest="show", default='faces')
 
402
        self.OptionParser.add_option("--shade",
 
403
            action="store", type="inkbool", 
 
404
            dest="shade", default='true')
 
405
        self.OptionParser.add_option("--f_r",
 
406
            action="store", type="int", 
 
407
            dest="f_r", default=255)
 
408
        self.OptionParser.add_option("--f_g",
 
409
            action="store", type="int", 
 
410
            dest="f_g", default=0)
 
411
        self.OptionParser.add_option("--f_b",
 
412
            action="store", type="int", 
 
413
            dest="f_b", default=0)
 
414
        self.OptionParser.add_option("--f_opac",
 
415
            action="store", type="int", 
 
416
            dest="f_opac", default=100)
 
417
        self.OptionParser.add_option("--s_opac",
 
418
            action="store", type="int", 
 
419
            dest="s_opac", default=100)
 
420
        self.OptionParser.add_option("--th",
 
421
            action="store", type="float", 
 
422
            dest="th", default=2)
 
423
        self.OptionParser.add_option("--lv_x",
 
424
            action="store", type="float", 
 
425
            dest="lv_x", default=1)
 
426
        self.OptionParser.add_option("--lv_y",
 
427
            action="store", type="float", 
 
428
            dest="lv_y", default=1)
 
429
        self.OptionParser.add_option("--lv_z",
 
430
            action="store", type="float", 
 
431
            dest="lv_z", default=-2)
 
432
        self.OptionParser.add_option("--back",
 
433
            action="store", type="inkbool", 
 
434
            dest="back", default='false')
 
435
        self.OptionParser.add_option("--norm",
 
436
            action="store", type="inkbool", 
 
437
            dest="norm", default='true')
 
438
        self.OptionParser.add_option("--z_sort",
 
439
            action="store", type="string", 
 
440
            dest="z_sort", default='min')
 
441
            
 
442
            
 
443
    def effect(self):
 
444
        so = self.options#shorthand
 
445
        
 
446
        #INITIALISE AND LOAD DATA
 
447
        
 
448
        obj = Obj() #create the object
 
449
        file = get_filename(so)#get the file to load data from
 
450
        get_obj_data(obj, file)#load data from the obj file
 
451
        obj.set_type(so)#set the type (face or edge) as per the settings
 
452
        
 
453
        st = Style(so) #initialise style
 
454
        fill_col = (so.f_r, so.f_g, so.f_b) #colour tuple for the face fill
 
455
        lighting = normalise( (so.lv_x,-so.lv_y,so.lv_z) ) #unit light vector
 
456
        
 
457
        #INKSCAPE GROUP TO CONTAIN THE POLYHEDRON
 
458
        
 
459
        #Put in in the centre of the current view
 
460
        poly_transform = 'translate(' + str( self.view_center[0]) + ',' + str( self.view_center[1]) + ')'
 
461
        #we will put all the rotations in the object name, so it can be repeated in 
 
462
        poly_name = obj.name+':'+make_rotation_log(so)
 
463
        poly_attribs = {inkex.addNS('label','inkscape'):poly_name,
 
464
                        'transform':poly_transform }
 
465
        poly = inkex.etree.SubElement(self.current_layer, 'g', poly_attribs)#the group to put everything in
 
466
        
 
467
        #TRANFORMATION OF THE OBJECT (ROTATION, SCALE, ETC)
 
468
        
 
469
        trans_mat = mat(identity(3, float)) #init. trans matrix as identity matrix
 
470
        for i in range(1, 7):#for each rotation
 
471
            axis  = eval('so.r'+str(i)+'_ax')
 
472
            angle = eval('so.r'+str(i)+'_ang') *pi/180
 
473
            trans_mat = rotate(trans_mat, angle, axis)
 
474
        trans_mat = trans_mat*so.scl #scale by linear factor (do this only after the transforms to reduce round-off)
 
475
        
 
476
        transformed_pts = get_transformed_pts(obj.vtx, trans_mat) #the points as projected in the z-axis onto the viewplane
 
477
        
 
478
        #RENDERING OF THE OBJECT
 
479
        
 
480
        if so.show == 'vtx':
 
481
            for i in range(len(transformed_pts)):
 
482
                draw_SVG_dot([transformed_pts[i][0],transformed_pts[i][1]], st, 'Point'+str(i), poly)#plot points using transformed_pts x and y coords
 
483
        
 
484
        elif so.show == 'edg':
 
485
            if obj.type == 'face':#we must generate the edge list from the faces
 
486
                edge_list = make_edge_list(obj.fce)
 
487
            else:#we already have an edge list
 
488
                edge_list = obj.edg
 
489
                        
 
490
            draw_edges( edge_list, transformed_pts, st, poly)
 
491
                              
 
492
        elif so.show == 'fce':
 
493
            if obj.type == 'face':#we have a face list
 
494
               
 
495
                z_list = []
 
496
                
 
497
                for i in range(len(obj.fce)):
 
498
                    face = obj.fce[i] #the face we are dealing with
 
499
                    norm = get_unit_normal(transformed_pts, face, so.cw_wound) #get the normal vector to the face
 
500
                    angle = get_angle( norm, lighting )#get the angle between the normal and the lighting vector
 
501
                    z_sort_param = get_z_sort_param(transformed_pts, face, so.z_sort)
 
502
                    
 
503
                    if so.back or norm[2] > 0: # include all polygons or just the front-facing ones as needed
 
504
                        z_list.append((z_sort_param, angle, norm, i))#record the maximum z-value of the face and angle to light, along with the face ID and normal
 
505
                
 
506
                z_list.sort(lambda x, y: cmp(x[0],y[0])) #sort by ascending sort parameter of the face
 
507
                draw_faces( z_list, transformed_pts, obj, so.shade, fill_col, st, poly)
 
508
 
 
509
            else:#we cannot generate a list of faces from the edges without a lot of computation
 
510
                inkex.errormsg(_('Face Data Not Found. Ensure file contains face data, and check the file is imported as "Face-Specified" under the "Model File" tab.\n'))
 
511
        else:
 
512
            inkex.errormsg(_('Internal Error. No view type selected\n'))
 
513
        
 
514
if __name__ == '__main__':
 
515
    e = Poly_3D()
 
516
    e.affect()
 
517
 
 
518
 
 
519
# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99