~siretart/ubuntu/utopic/blender/libav10

« back to all changes in this revision

Viewing changes to release/scripts/addons/add_mesh_solid.py

  • Committer: Package Import Robot
  • Author(s): Matteo F. Vescovi
  • Date: 2012-07-23 08:54:18 UTC
  • mfrom: (14.2.16 sid)
  • mto: (14.2.19 sid)
  • mto: This revision was merged to the branch mainline in revision 42.
  • Revision ID: package-import@ubuntu.com-20120723085418-9foz30v6afaf5ffs
Tags: 2.63a-2
* debian/: Cycles support added (Closes: #658075)
  For now, this top feature has been enabled only
  on [any-amd64 any-i386] architectures because
  of OpenImageIO failing on all others
* debian/: scripts installation path changed
  from /usr/lib to /usr/share:
  + debian/patches/: patchset re-worked for path changing
  + debian/control: "Breaks" field added on yafaray-exporter

Show diffs side-by-side

added added

removed removed

Lines of Context:
8
8
#
9
9
# This program is distributed in the hope that it will be useful,
10
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
12
# GNU General Public License for more details.
13
13
#
14
14
# You should have received a copy of the GNU General Public License
17
17
#
18
18
# ***** END GPL LICENCE BLOCK *****
19
19
 
20
 
bl_addon_info = {
 
20
bl_info = {
21
21
    "name": "Regular Solids",
22
22
    "author": "DreamPainter",
23
 
    "version": (1,),
24
 
    "blender": (2, 5, 3),
25
 
    "api": 31965,
26
 
    "location": "View3D > Add > Mesh > Regular Solids",
27
 
    "description": "Add a Regular Solid mesh.",
 
23
    "version": (2, 0),
 
24
    "blender": (2, 5, 9),
 
25
    "location": "View3D > Add > Mesh > Solids",
 
26
    "description": "Add a regular solid",
28
27
    "warning": "",
29
28
    "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
30
29
        "Scripts/Add_Mesh/Add_Solid",
31
30
    "tracker_url": "https://projects.blender.org/tracker/index.php?"\
32
 
        "func=detail&aid=22405&group_id=153&atid=469",
 
31
        "func=detail&aid=22405",
33
32
    "category": "Add Mesh"}
34
33
 
35
 
 
36
34
import bpy
37
35
from bpy.props import FloatProperty,EnumProperty,BoolProperty
38
36
from math import sqrt
39
 
from mathutils import Vector,Matrix
40
 
#from rawMeshUtils import *
 
37
from mathutils import Vector
41
38
from functools import reduce
42
 
 
43
 
# Apply view rotation to objects if "Align To" for
44
 
# new objects was set to "VIEW" in the User Preference.
45
 
def apply_object_align(context, ob):
46
 
    obj_align = bpy.context.user_preferences.edit.object_align
47
 
 
48
 
    if (context.space_data.type == 'VIEW_3D'
49
 
        and obj_align == 'VIEW'):
50
 
            view3d = context.space_data
51
 
            region = view3d.region_3d
52
 
            viewMatrix = region.view_matrix
53
 
            rot = viewMatrix.rotation_part()
54
 
            ob.rotation_euler = rot.invert().to_euler()
55
 
 
56
 
 
57
 
# Create a new mesh (object) from verts/edges/faces.
58
 
# verts/edges/faces ... List of vertices/edges/faces for the
59
 
#                       new mesh (as used in from_pydata).
60
 
# name ... Name of the new mesh (& object).
61
 
# edit ... Replace existing mesh data.
62
 
# Note: Using "edit" will destroy/delete existing mesh data.
63
 
def create_mesh_object(context, verts, edges, faces, name, edit):
64
 
    scene = context.scene
65
 
    obj_act = scene.objects.active
66
 
 
67
 
    # Can't edit anything, unless we have an active obj.
68
 
    if edit and not obj_act:
69
 
        return None
70
 
 
71
 
    # Create new mesh
72
 
    mesh = bpy.data.meshes.new(name)
73
 
 
74
 
    # Make a mesh from a list of verts/edges/faces.
75
 
    mesh.from_pydata(verts, edges, faces)
76
 
 
77
 
    # Update mesh geometry after adding stuff.
78
 
    mesh.update()
79
 
 
80
 
    # Deselect all objects.
81
 
    bpy.ops.object.select_all(action='DESELECT')
82
 
 
83
 
    if edit:
84
 
        # Replace geometry of existing object
85
 
 
86
 
        # Use the active obj and select it.
87
 
        ob_new = obj_act
88
 
        ob_new.select = True
89
 
 
90
 
        if obj_act.mode == 'OBJECT':
91
 
            # Get existing mesh datablock.
92
 
            old_mesh = ob_new.data
93
 
 
94
 
            # Set object data to nothing
95
 
            ob_new.data = None
96
 
 
97
 
            # Clear users of existing mesh datablock.
98
 
            old_mesh.user_clear()
99
 
 
100
 
            # Remove old mesh datablock if no users are left.
101
 
            if (old_mesh.users == 0):
102
 
                bpy.data.meshes.remove(old_mesh)
103
 
 
104
 
            # Assign new mesh datablock.
105
 
            ob_new.data = mesh
106
 
 
107
 
    else:
108
 
        # Create new object
109
 
        ob_new = bpy.data.objects.new(name, mesh)
110
 
 
111
 
        # Link new object to the given scene and select it.
112
 
        scene.objects.link(ob_new)
113
 
        ob_new.select = True
114
 
 
115
 
        # Place the object at the 3D cursor location.
116
 
        ob_new.location = scene.cursor_location
117
 
 
118
 
        apply_object_align(context, ob_new)
119
 
 
120
 
    if obj_act and obj_act.mode == 'EDIT':
121
 
        if not edit:
122
 
            # We are in EditMode, switch to ObjectMode.
123
 
            bpy.ops.object.mode_set(mode='OBJECT')
124
 
 
125
 
            # Select the active object as well.
126
 
            obj_act.select = True
127
 
 
128
 
            # Apply location of new object.
129
 
            scene.update()
130
 
 
131
 
            # Join new object into the active.
132
 
            bpy.ops.object.join()
133
 
 
134
 
            # Switching back to EditMode.
135
 
            bpy.ops.object.mode_set(mode='EDIT')
136
 
 
137
 
            ob_new = obj_act
138
 
 
139
 
    else:
140
 
        # We are in ObjectMode.
141
 
        # Make the new object the active one.
142
 
        scene.objects.active = ob_new
143
 
 
144
 
    return ob_new
145
 
 
146
 
 
147
 
# A very simple "bridge" tool.
148
 
# Connects two equally long vertex rows with faces.
149
 
# Returns a list of the new faces (list of  lists)
150
 
#
151
 
# vertIdx1 ... First vertex list (list of vertex indices).
152
 
# vertIdx2 ... Second vertex list (list of vertex indices).
153
 
# closed ... Creates a loop (first & last are closed).
154
 
# flipped ... Invert the normal of the face(s).
155
 
#
156
 
# Note: You can set vertIdx1 to a single vertex index to create
157
 
#       a fan/star of faces.
158
 
# Note: If both vertex idx list are the same length they have
159
 
#       to have at least 2 vertices.
160
 
def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
161
 
    faces = []
162
 
 
163
 
    if not vertIdx1 or not vertIdx2:
164
 
        return None
165
 
 
166
 
    if len(vertIdx1) < 2 and len(vertIdx2) < 2:
167
 
        return None
168
 
 
169
 
    fan = False
170
 
    if (len(vertIdx1) != len(vertIdx2)):
171
 
        if (len(vertIdx1) == 1 and len(vertIdx2) > 1):
172
 
            fan = True
173
 
        else:
174
 
            return None
175
 
 
176
 
    total = len(vertIdx2)
177
 
 
178
 
    if closed:
179
 
        # Bridge the start with the end.
180
 
        if flipped:
181
 
            face = [
182
 
                vertIdx1[0],
183
 
                vertIdx2[0],
184
 
                vertIdx2[total - 1]]
185
 
            if not fan:
186
 
                face.append(vertIdx1[total - 1])
187
 
            faces.append(face)
188
 
 
189
 
        else:
190
 
            face = [vertIdx2[0], vertIdx1[0]]
191
 
            if not fan:
192
 
                face.append(vertIdx1[total - 1])
193
 
            face.append(vertIdx2[total - 1])
194
 
            faces.append(face)
195
 
 
196
 
    # Bridge the rest of the faces.
197
 
    for num in range(total - 1):
198
 
        if flipped:
199
 
            if fan:
200
 
                face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]]
201
 
            else:
202
 
                face = [vertIdx2[num], vertIdx1[num],
203
 
                    vertIdx1[num + 1], vertIdx2[num + 1]]
204
 
            faces.append(face)
205
 
        else:
206
 
            if fan:
207
 
                face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]]
208
 
            else:
209
 
                face = [vertIdx1[num], vertIdx2[num],
210
 
                    vertIdx2[num + 1], vertIdx1[num + 1]]
211
 
            faces.append(face)
212
 
 
213
 
    return faces
 
39
from bpy_extras.object_utils import object_data_add
 
40
 
214
41
# this function creates a chain of quads and, when necessary, a remaining tri
215
42
# for each polygon created in this script. be aware though, that this function
216
43
# assumes each polygon is convex.
217
44
#  poly: list of faces, or a single face, like those
218
45
#        needed for mesh.from_pydata.
219
 
#  returns the tesselated faces.
 
46
#  returns the tessellated faces.
220
47
def createPolys(poly):
221
48
    # check for faces
222
49
    if len(poly) == 0:
226
53
        poly = [poly] # if only one, make it a list of one face
227
54
    faces = []
228
55
    for i in poly:
229
 
        l = len(i)
 
56
        L = len(i)
230
57
        # let all faces of 3 or 4 verts be
231
 
        if l < 5:
 
58
        if L < 5:
232
59
            faces.append(i)
233
60
        # split all polygons in half and bridge the two halves
234
61
        else:
235
 
            half = int(l/2)
236
 
            f = createFaces(i[:half],[i[-1-j] for j in range(half)])        
 
62
            f = [[i[x],i[x+1],i[L-2-x],i[L-1-x]] for x in range(L//2-1)]
237
63
            faces.extend(f)
238
 
            # if the polygon has an odd number of verts, add the last tri
239
 
            if l%2 == 1:
240
 
                faces.append([i[half-1],i[half],i[half+1]])
 
64
            if L&1 == 1: 
 
65
                faces.append([i[L//2-1+x] for x in [0,1,2]])
241
66
    return faces
242
 
 
 
67
    
243
68
# function to make the reduce function work as a workaround to sum a list of vectors 
244
 
def Asum(list):
 
69
def vSum(list):
245
70
    return reduce(lambda a,b: a+b, list)
246
 
 
 
71
    
247
72
# creates the 5 platonic solids as a base for the rest
248
73
#  plato: should be one of {"4","6","8","12","20"}. decides what solid the
249
74
#         outcome will be.
250
 
#  returns a list of vertices and faces and the appropriate name
 
75
#  returns a list of vertices and faces
251
76
def source(plato):
252
77
    verts = []
253
78
    faces = []
308
133
                 [0,10,8],[1,8,10],[2,9,11],[3,11,9],[4,2,0],[5,0,2],[6,1,3],[7,3,1],
309
134
                 [8,6,4],[9,4,6],[10,5,7],[11,7,5]]
310
135
 
311
 
    # handles faulty values of plato
312
 
    else:
313
 
        print("Choose keyword 'plato' from {'4','6','8','12','20'}")
314
 
        return None
315
 
 
316
136
    # convert the tuples to Vectors
317
137
    verts = [Vector(i) for i in v]
318
138
 
319
139
    return verts,faces
320
 
 
 
140
    
321
141
# processes the raw data from source
322
142
def createSolid(plato,vtrunc,etrunc,dual,snub):
323
 
    verts = []
324
 
    faces = []
325
 
    edges = []
326
143
    # the duals from each platonic solid
327
144
    dualSource = {"4":"4",
328
145
                  "6":"8",
333
150
    # constants saving space and readability
334
151
    vtrunc *= 0.5
335
152
    etrunc *= 0.5
336
 
    supposed_size = 0
337
 
    noSnub = (snub == "0") or (etrunc == 0.5) or (etrunc == 0)
338
 
    lSnub = (snub == "L") and (0 < etrunc < 0.5)
339
 
    rSnub = (snub == "R") and (0 < etrunc < 0.5)
 
153
    supposedSize = 0
 
154
    noSnub = (snub == "None") or (etrunc == 0.5) or (etrunc == 0)
 
155
    lSnub = (snub == "Left") and (0 < etrunc < 0.5)
 
156
    rSnub = (snub == "Right") and (0 < etrunc < 0.5)
340
157
 
341
158
    # no truncation
342
159
    if vtrunc == 0:
343
160
        if dual: # dual is as simple as another, but mirrored platonic solid
344
 
            vInput,fInput = source(dualSource[plato])
345
 
            supposed_size = Asum(vInput[i] for i in fInput[0]).length / len(fInput[0])
346
 
            vInput = [-i*supposed_size for i in vInput]            # mirror it
347
 
            return vInput,fInput
 
161
            vInput, fInput = source(dualSource[plato])
 
162
            supposedSize = vSum(vInput[i] for i in fInput[0]).length/len(fInput[0])
 
163
            vInput = [-i*supposedSize for i in vInput]            # mirror it
 
164
            return vInput, fInput
348
165
        return source(plato)
349
 
    # simple truncation of the source
350
 
    elif 0.5 >= vtrunc > 0:
351
 
        vInput,fInput = source(plato)
352
 
    # truncation is now equal to simple truncation of the dual of the source
353
 
    elif vtrunc > 0.5: 
354
 
        vInput,fInput = source(dualSource[plato])
355
 
        supposed_size = Asum(vInput[i] for i in fInput[0]).length / len(fInput[0])
356
 
        # account for the source being a dual
357
 
        vtrunc = 1-vtrunc
358
 
        if vtrunc == 0: # no truncation
 
166
    elif 0 < vtrunc <= 0.5: # simple truncation of the source
 
167
        vInput, fInput = source(plato)
 
168
    else:
 
169
        # truncation is now equal to simple truncation of the dual of the source
 
170
        vInput, fInput = source(dualSource[plato])
 
171
        supposedSize = vSum(vInput[i] for i in fInput[0]).length / len(fInput[0])
 
172
        vtrunc = 1-vtrunc # account for the source being a dual
 
173
        if vtrunc == 0: # no truncation needed
359
174
            if dual:
360
 
                vInput,fInput = source(plato)
361
 
                vInput = [i*supposed_size for i in vInput]
362
 
                return vInput,fInput,sourceName
363
 
            vInput = [-i*supposed_size for i in vInput]
364
 
            return vInput,fInput
365
 
 
366
 
    # generate a database for creating the faces. this exists out of a list for
367
 
    # every vertex in the source
368
 
    # 0 : vertex id
369
 
    # 1 : vertices connected to this vertex, listed ccw(Counter Clock Wise)
370
 
    # 2 : vertices generated to form the faces of this vertex
371
 
    # 3 : faces connected to this vertex, listed ccw
372
 
    # 4 : dictionairy containing the verts used by the connected faces
373
 
    # 5 : list of edges that use this vertex, listed ccw
374
 
    # 6 : dictionairy containing the verts used by the connected edges
375
 
    v = [[i,[],[],[],{},[],{}] for i in range(len(vInput))]
376
 
 
377
 
    # this piece of code, generates the database and the lists in ccw order
 
175
                vInput, fInput = source(plato)
 
176
                vInput = [i*supposedSize for i in vInput]
 
177
                return vInput, fInput
 
178
            vInput = [-i*supposedSize for i in vInput]
 
179
            return vInput, fInput
 
180
    
 
181
    # generate connection database
 
182
    vDict = [{} for i in vInput]
 
183
    # for every face, store what vertex comes after and before the current vertex    
378
184
    for x in range(len(fInput)):
379
185
        i = fInput[x]
380
 
        # in every faces, check which vertices connect the each vert and sort
381
 
        #  in ccw order
382
 
        for j in range(-1,len(i)-1):
383
 
            # only generate an edge dict, if edge truncation is needed
384
 
            if etrunc:
385
 
                # list edges as [min,max], to evade confusion
386
 
                first = min([i[j-1],i[j]])
387
 
                last = max([i[j-1],i[j]])
388
 
                # if an edge is not allready in, add it and give the index
389
 
                try:
390
 
                    y = edges.index([first,last])
391
 
                except:
392
 
                    edges.append([first,last])
393
 
                    y = len(edges)-1
394
 
                # add a dict item
395
 
                v[i[j]][6][str(y)] = [0,0]
396
 
            # the vertex before and after the current vertex, check whether they
397
 
            #  are allready in the database
398
 
            after = i[j+1] not in v[i[j]][1]
399
 
            before = i[j-1] not in v[i[j]][1]
400
 
            # sort them and add faces and, when necessary, edges in the database
401
 
            if after:
402
 
                if before:
403
 
                    v[i[j]][1].append(i[j+1])
404
 
                    v[i[j]][1].append(i[j-1])
405
 
                    v[i[j]][3].append(x)
406
 
                    if etrunc: v[i[j]][5].append(y)
407
 
                else:
408
 
                    z = v[i[j]][1].index(i[j-1])
409
 
                    v[i[j]][1].insert(z,i[j+1])
410
 
                    v[i[j]][3].insert(z,x)
411
 
                    if etrunc: v[i[j]][5].insert(z,y)
412
 
            else:
413
 
                z = v[i[j]][1].index(i[j+1])
414
 
                v[i[j]][3].insert(z,x)
415
 
                if etrunc: v[i[j]][5].insert(z,y)
416
 
                if before:
417
 
                    v[i[j]][1].insert(z+1,i[j-1])
418
 
            # add the current face to the current vertex in the dict
419
 
            v[i[j]][4][str(x)] = [0,0] 
420
 
 
421
 
    # generate vert-only truncated vertices by linear interpolation         
422
 
    for i in v:
423
 
        for j in range(len(i[1])):
424
 
            verts.append(vInput[i[0]]*(1-vtrunc)+vInput[i[1][j]]*vtrunc)
425
 
            l = len(verts)-1
426
 
            # face resulting from truncating this vertex
427
 
            i[2].append(l)
428
 
            # this vertex is used by both faces using this edge
429
 
            i[4][str(i[3][j])][1] = l
430
 
            i[4][str(i[3][j-1])][0] = l
431
 
 
432
 
    # only truncate edges when needed
433
 
    vert_faces = []
434
 
    if etrunc:
435
 
        # generate a new list of vertices, by linear interpolating each vert-face
436
 
        nVerts = []
437
 
        for i in v:
438
 
            f = []
439
 
            # weird range so we dont run out of array bounds
440
 
            for j in range(-1,len(i[2])-1):
441
 
                # making use of the fact that the snub operation takes only
442
 
                #  one of the two vertices per edge. so rSnub only takes the
443
 
                #  first, lSnub only takes the second, and noSnub takes both
444
 
                if rSnub or noSnub: 
445
 
                    # interpolate
446
 
                    nVerts.append((1-etrunc)*verts[i[2][j]] + etrunc*verts[i[2][j-1]])
447
 
                    # add last vertex to the vert-face, face-face and edge-face
448
 
                    l = len(nVerts)-1
449
 
                    f.append(l)
450
 
                    i[4][str(i[3][j-1])][0] = l
451
 
                    i[6][str(i[5][j-1])][1] = l
452
 
                if lSnub or noSnub:
453
 
                    # interpolate
454
 
                    nVerts.append((1-etrunc)*verts[i[2][j]] + etrunc*verts[i[2][j+1]])
455
 
                    # add last vertex to the vert-face, face-face and edge-face
456
 
                    l = len(nVerts)-1
457
 
                    f.append(l)
458
 
                    i[4][str(i[3][j])][1] = l
459
 
                    i[6][str(i[5][j-1])][0] = l
460
 
            # add vert-face
461
 
            vert_faces.append(f)
462
 
 
463
 
        # snub operator creates 2 tri's instead of a planar quad, needing the
464
 
        #  next piece of code. making use of the dictionairy to create them.
465
 
        if lSnub or rSnub:
466
 
            edge_faces = []
467
 
            for x in range(len(edges)):
468
 
                one = v[edges[x][0]]    # the first vertex of this edge
469
 
                two = v[edges[x][1]]    # the second
470
 
                # using max() since the dict consists of one filled spot and one
471
 
                #  empty('cause only one vert is created)
472
 
                f = [max(two[6][str(x)]),max(one[6][str(x)])]
473
 
                index = one[5].index(x)
474
 
                # create this tri from the middle line and the the previous edge
475
 
                #  on this vertex
476
 
                if lSnub:
477
 
                    f.append(max(one[6][str(one[5][index-1])]))
478
 
                else: # or in this case, the next
479
 
                    if index+1 >= len(one[5]): index = -1
480
 
                    f.append(max(one[6][str(one[5][index+1])]))
481
 
                edge_faces.append(f)
482
 
 
483
 
                # do the same for the other end of the edge
484
 
                f = [max(one[6][str(x)]),max(two[6][str(x)])]
485
 
                index = two[5].index(x)
486
 
                if lSnub:
487
 
                    f.append(max(two[6][str(two[5][index-1])]))
488
 
                else:
489
 
                    if index+1 >= len(one[5]): index = -1
490
 
                    f.append(max(two[6][str(two[5][index+1])]))
491
 
                edge_faces.append(f)
492
 
        else:
493
 
            # generate edge-faces from the dictionairy, simple quads for noSnub
494
 
            edge_faces = []
495
 
            for i in range(len(edges)):
496
 
                f = []
497
 
                for j in edges[i]:
498
 
                    f.extend(v[j][6][str(i)])
499
 
                edge_faces.append(f)
500
 
        verts = nVerts
501
 
    else:
502
 
        # generate vert-faces for non-edge-truncation
503
 
        vert_faces = [i[2] for i in v]
 
186
        for j in range(len(i)):
 
187
            vDict[i[j-1]][i[j]] = [i[j-2],x]
 
188
            if len(vDict[i[j-1]]) == 1: vDict[i[j-1]][-1] = i[j] 
 
189
    
 
190
    # the actual connection database: exists out of:
 
191
    # [vtrunc pos, etrunc pos, connected vert IDs, connected face IDs]
 
192
    vData = [[[],[],[],[]] for i in vInput]
 
193
    fvOutput = [] # faces created from truncated vertices
 
194
    feOutput = [] # faces created from truncated edges
 
195
    vOutput = [] # newly created vertices
 
196
    for x in range(len(vInput)):
 
197
        i = vDict[x] # lookup the current vertex
 
198
        current = i[-1]
 
199
        while True: # follow the chain to get a ccw order of connected verts and faces
 
200
            vData[x][2].append(i[current][0])
 
201
            vData[x][3].append(i[current][1])
 
202
            # create truncated vertices
 
203
            vData[x][0].append((1-vtrunc)*vInput[x] + vtrunc*vInput[vData[x][2][-1]])
 
204
            current = i[current][0]
 
205
            if current == i[-1]: break # if we're back at the first: stop the loop
 
206
        fvOutput.append([]) # new face from truncated vert
 
207
        fOffset = x*(len(i)-1) # where to start off counting faceVerts
 
208
        # only create one vert where one is needed (v1 todo: done) 
 
209
        if etrunc == 0.5: 
 
210
            for j in range(len(i)-1):
 
211
                vOutput.append((vData[x][0][j]+vData[x][0][j-1])*etrunc) # create vert
 
212
                fvOutput[x].append(fOffset+j) # add to face
 
213
            fvOutput[x] = fvOutput[x][1:]+[fvOutput[x][0]] # rotate face for ease later on
 
214
            # create faces from truncated edges.
 
215
            for j in range(len(i)-1):
 
216
                if x > vData[x][2][j]: #only create when other vertex has been added
 
217
                    index = vData[vData[x][2][j]][2].index(x)
 
218
                    feOutput.append([fvOutput[x][j],fvOutput[x][j-1],
 
219
                                     fvOutput[vData[x][2][j]][index],
 
220
                                     fvOutput[vData[x][2][j]][index-1]])
 
221
        # edge truncation between none and full
 
222
        elif etrunc > 0:
 
223
            for j in range(len(i)-1):
 
224
                # create snubs from selecting verts from rectified meshes
 
225
                if rSnub:
 
226
                    vOutput.append(etrunc*vData[x][0][j]+(1-etrunc)*vData[x][0][j-1])
 
227
                    fvOutput[x].append(fOffset+j)
 
228
                elif lSnub:
 
229
                    vOutput.append((1-etrunc)*vData[x][0][j]+etrunc*vData[x][0][j-1])
 
230
                    fvOutput[x].append(fOffset+j)
 
231
                else: #noSnub, select both verts from rectified mesh
 
232
                    vOutput.append(etrunc*vData[x][0][j]+(1-etrunc)*vData[x][0][j-1])
 
233
                    vOutput.append((1-etrunc)*vData[x][0][j]+etrunc*vData[x][0][j-1])
 
234
                    fvOutput[x].append(2*fOffset+2*j)
 
235
                    fvOutput[x].append(2*fOffset+2*j+1)
 
236
            # rotate face for ease later on
 
237
            if noSnub: fvOutput[x] = fvOutput[x][2:]+fvOutput[x][:2]
 
238
            else: fvOutput[x] = fvOutput[x][1:]+[fvOutput[x][0]]
 
239
            # create single face for each edge
 
240
            if noSnub:
 
241
                for j in range(len(i)-1):
 
242
                    if x > vData[x][2][j]:
 
243
                        index = vData[vData[x][2][j]][2].index(x)
 
244
                        feOutput.append([fvOutput[x][j*2],fvOutput[x][2*j-1],
 
245
                                         fvOutput[vData[x][2][j]][2*index],
 
246
                                         fvOutput[vData[x][2][j]][2*index-1]])
 
247
            # create 2 tri's for each edge for the snubs
 
248
            elif rSnub:
 
249
                for j in range(len(i)-1):
 
250
                    if x > vData[x][2][j]:
 
251
                        index = vData[vData[x][2][j]][2].index(x)
 
252
                        feOutput.append([fvOutput[x][j],fvOutput[x][j-1],
 
253
                                         fvOutput[vData[x][2][j]][index]])
 
254
                        feOutput.append([fvOutput[x][j],fvOutput[vData[x][2][j]][index],
 
255
                                         fvOutput[vData[x][2][j]][index-1]])
 
256
            elif lSnub:
 
257
                for j in range(len(i)-1):
 
258
                    if x > vData[x][2][j]:
 
259
                        index = vData[vData[x][2][j]][2].index(x)
 
260
                        feOutput.append([fvOutput[x][j],fvOutput[x][j-1],
 
261
                                         fvOutput[vData[x][2][j]][index-1]])
 
262
                        feOutput.append([fvOutput[x][j-1],fvOutput[vData[x][2][j]][index],
 
263
                                         fvOutput[vData[x][2][j]][index-1]])
 
264
        # special rules fro birectified mesh (v1 todo: done)
 
265
        elif vtrunc == 0.5:
 
266
            for j in range(len(i)-1):
 
267
                if x < vData[x][2][j]: # use current vert, since other one has not passed yet
 
268
                    vOutput.append(vData[x][0][j])
 
269
                    fvOutput[x].append(len(vOutput)-1)
 
270
                else:
 
271
                    # search for other edge to avoid duplicity
 
272
                    connectee = vData[x][2][j]
 
273
                    fvOutput[x].append(fvOutput[connectee][vData[connectee][2].index(x)])
 
274
        else: # vert truncation only
 
275
            vOutput.extend(vData[x][0]) # use generated verts from way above
 
276
            for j in range(len(i)-1):   # create face from them
 
277
                fvOutput[x].append(fOffset+j)
504
278
 
505
279
    # calculate supposed vertex length to ensure continuity
506
 
    if supposed_size:
507
 
        supposed_size *= len(vert_faces[0])/Asum(verts[i] for i in vert_faces[0]).length
508
 
        verts = [-i*supposed_size for i in verts]
509
 
        
510
 
    # generate face-faces by looking up the old verts and replacing them with
511
 
    #  the vertices in the dictionairy
512
 
    face_faces = []
 
280
    if supposedSize and not dual:                    # this to make the vtrunc > 1 work
 
281
        supposedSize *= len(fvOutput[0])/vSum(vOutput[i] for i in fvOutput[0]).length
 
282
        vOutput = [-i*supposedSize for i in vOutput]
 
283
    
 
284
    # create new faces by replacing old vert IDs by newly generated verts
 
285
    ffOutput = [[] for i in fInput]
513
286
    for x in range(len(fInput)):
514
 
        f = []
515
 
        for j in fInput[x]:
516
 
            # again using the fact, that only one of the two verts is used
517
 
            #  for snub operation
518
 
            if rSnub and etrunc:
519
 
                f.append(v[j][4][str(x)][0])
520
 
            elif lSnub and etrunc:
521
 
                f.append(v[j][4][str(x)][1])
522
 
            else:
523
 
                # for cool graphics, comment the first line and uncomment the second line
524
 
                # then work the vTrunc property, leave the other properties at 0 
525
 
                # (can also change 0 to 1 in second line to change from ccw to cw)
526
 
                f.extend(v[j][4][str(x)])                  # first
527
 
                #f.append(v[j][4][str(x)][0])               # second
528
 
        face_faces.append(f)
 
287
        # only one generated vert per vertex, so choose accordingly
 
288
        if etrunc == 0.5 or (etrunc == 0 and vtrunc == 0.5) or lSnub or rSnub:
 
289
            ffOutput[x] = [fvOutput[i][vData[i][3].index(x)-1] for i in fInput[x]]
 
290
        # two generated verts per vertex
 
291
        elif etrunc > 0:
 
292
            for i in fInput[x]:
 
293
                ffOutput[x].append(fvOutput[i][2*vData[i][3].index(x)-1])
 
294
                ffOutput[x].append(fvOutput[i][2*vData[i][3].index(x)-2])
 
295
        else: # cutting off corners also makes 2 verts
 
296
            for i in fInput[x]:
 
297
                ffOutput[x].append(fvOutput[i][vData[i][3].index(x)])
 
298
                ffOutput[x].append(fvOutput[i][vData[i][3].index(x)-1])
529
299
    
530
 
    if dual:
531
 
        # create verts by taking the average of all vertices that make up each
532
 
        #  face. do it in this order to ease the following face creation
533
 
        nVerts = []
534
 
        for i in vert_faces:
535
 
            nVerts.append(Asum(verts[j] for j in i)/len(i))
536
 
        if etrunc:
537
 
            eStart = len(nVerts)
538
 
            for i in edge_faces:
539
 
                nVerts.append(Asum(verts[j] for j in i)/len(i))
540
 
        fStart = len(nVerts)
541
 
        for i in face_faces:
542
 
            nVerts.append(Asum(verts[j] for j in i)/len(i))
543
 
        # the special face generation for snub duals, it sucks, even i dont get it
544
 
        if lSnub or rSnub:
545
 
            for x in range(len(fInput)):
546
 
                i = fInput[x]
547
 
                for j in range(-1,len(i)-1):
548
 
                
549
 
                    if i[j] > i[j+1]: 
550
 
                        eNext = edges.index([i[j+1],i[j]])
551
 
                        [a,b] = [1,0]
552
 
                    else: 
553
 
                        eNext = edges.index([i[j],i[j+1]])
554
 
                        [a,b] = [0,1]
555
 
                    if i[j] > i[j-1]: 
556
 
                        ePrev = edges.index([i[j-1],i[j]])
557
 
                        [c,d] = [0,1]
558
 
                    else: 
559
 
                        ePrev = edges.index([i[j],i[j-1]])
560
 
                        [c,d] = [1,0]
561
 
                    if lSnub:
562
 
                        f = [eStart+2*eNext+b,eStart+2*eNext+a,i[j]]
563
 
                        f.append(eStart+2*ePrev+d)
564
 
                        f.append(fStart + x)
565
 
                    else:
566
 
                        f = [eStart+2*ePrev+c,eStart+2*ePrev+d,i[j]]
567
 
                        f.append(eStart+2*eNext+a)
568
 
                        f.append(fStart + x)
569
 
                    if supposed_size: faces.append(f)
570
 
                    else: faces.append(f[2:]+f[:2])
571
 
        else:
572
 
            # for noSnub situations, the face generation is somewhat easier.
573
 
            # first calculate what order faces must be added to ensure convex solids
574
 
            # this by calculating the angle between the middle of the four vertices
575
 
            #  and the first face. if the face is above the middle, use that diagonal
576
 
            #  otherwise use the other diagonal
577
 
            if etrunc:
578
 
                f = [v[0][0],eStart+v[0][5][-1],fStart+v[0][3][0],eStart+v[0][5][0]]
579
 
            else:
580
 
                f = [v[0][0],fStart+v[0][3][0],v[0][1][0],fStart+v[0][3][-1]]
581
 
            p = [nVerts[i] for i in f]
582
 
            mid = 0.25*Asum(p)
583
 
            norm = (p[1]-p[0]).cross(p[2]-p[0])
584
 
            dot = norm.dot(mid-p[0])/(norm.length*(mid-p[0]).length)
585
 
            tollerance = 0.001 # ~ cos(0.06 degrees)
586
 
            if ((dot > tollerance) and (not supposed_size)) or ((dot < -tollerance) and (supposed_size)):
587
 
                direction = 1 # first diagonal
588
 
            elif ((dot < -tollerance) and (not supposed_size)) or ((dot > tollerance) and (supposed_size)):
589
 
                direction = -1 # second diagonal
590
 
            else: 
591
 
                direction = 0 # no diagonal, face is planar (somewhat)
592
 
        
593
 
            if etrunc: # for every vertex
594
 
                for i in v: # add the face, consisting of the vert,edge,next
595
 
                            # edge and face between those edges
596
 
                    for j in range(len(i[1])):
597
 
                        f = [i[0],eStart+i[5][j-1],fStart+i[3][j],eStart+i[5][j]]
598
 
                        if direction == 1: # first diagonal
599
 
                            faces.extend([[f[0],f[1],f[3]],[f[1],f[2],f[3]]])
600
 
                        elif direction == -1: # first diagonal
601
 
                            faces.extend([[f[0],f[1],f[2]],[f[0],f[2],f[3]]])
602
 
                        else:
603
 
                            faces.append(f) # no diagonal
604
 
            else:
605
 
                for i in v: # for every vertex
606
 
                    for j in range(len(i[1])):
607
 
                        if i[0] < i[1][j]: # face consists of vert, vert on other
608
 
                                           # end of edge and both faces using that
609
 
                                           # edge, so exclude verts allready used
610
 
                            f = [i[0],fStart+i[3][j], i[1][j],fStart+i[3][j-1]]
611
 
                            if direction == -1: # secong diagonal
612
 
                                faces.extend([[f[0],f[1],f[3]],[f[1],f[2],f[3]]])
613
 
                            elif direction == 1: # first diagonal
614
 
                                faces.extend([[f[0],f[1],f[2]],[f[0],f[2],f[3]]])
615
 
                            else:
616
 
                                faces.append(f) # no diagonal
617
 
        verts = nVerts  # use new vertices
618
 
    else:
619
 
        # concatenate all faces, since they dont have to be used sepperately anymore
620
 
        faces = face_faces
621
 
        if etrunc: faces += edge_faces
622
 
        faces += vert_faces
 
300
    if not dual:
 
301
        return vOutput,fvOutput + feOutput + ffOutput
 
302
    else: 
 
303
        # do the same procedure as above, only now on the generated mesh
 
304
        # generate connection database
 
305
        vDict = [{} for i in vOutput]
 
306
        dvOutput = [0 for i in fvOutput + feOutput + ffOutput]
 
307
        dfOutput = []
 
308
        
 
309
        for x in range(len(dvOutput)): # for every face
 
310
            i = (fvOutput + feOutput + ffOutput)[x] # choose face to work with
 
311
            # find vertex from face
 
312
            normal = (vOutput[i[0]]-vOutput[i[1]]).cross(vOutput[i[2]]-vOutput[i[1]]).normalized()
 
313
            dvOutput[x] = normal/(normal.dot(vOutput[i[0]]))
 
314
            for j in range(len(i)): # create vert chain
 
315
                vDict[i[j-1]][i[j]] = [i[j-2],x]
 
316
                if len(vDict[i[j-1]]) == 1: vDict[i[j-1]][-1] = i[j]
 
317
        
 
318
        # calculate supposed size for continuity
 
319
        supposedSize = vSum([vInput[i] for i in fInput[0]]).length/len(fInput[0])
 
320
        supposedSize /= dvOutput[-1].length
 
321
        dvOutput = [i*supposedSize for i in dvOutput]
 
322
        
 
323
        # use chains to create faces
 
324
        for x in range(len(vOutput)):
 
325
            i = vDict[x]
 
326
            current = i[-1]
 
327
            face = []
 
328
            while True:
 
329
                face.append(i[current][1])
 
330
                current = i[current][0]
 
331
                if current == i[-1]: break
 
332
            dfOutput.append(face)
 
333
        
 
334
        return dvOutput,dfOutput
623
335
 
624
 
    return verts,faces
625
 
            
626
 
        
627
336
class Solids(bpy.types.Operator):
628
337
    """Add one of the (regular) solids (mesh)"""
629
338
    bl_idname = "mesh.primitive_solid_add"
630
339
    bl_label = "(Regular) solids"
631
 
    bl_description = "Add one of the platoic or archimedean solids"
632
 
    bl_options = {'REGISTER', 'UNDO'}
 
340
    bl_description = "Add one of the Platonic, Archimedean or Catalan solids"
 
341
    bl_options = {'REGISTER', 'UNDO', 'PRESET'}
633
342
 
634
343
    source = EnumProperty(items = (("4","Tetrahedron",""),
635
344
                                   ("6","Hexahedron",""),
663
372
                           default = 0.0,
664
373
                           precision = 3,
665
374
                           step = 0.2)
666
 
    snub = EnumProperty(items = (("0","No Snub",""),
667
 
                                 ("L","Left Snub",""),
668
 
                                 ("R","Right Snub","")),
 
375
    snub = EnumProperty(items = (("None","No Snub",""),
 
376
                                 ("Left","Left Snub",""),
 
377
                                 ("Right","Right Snub","")),
669
378
                        name = "Snub",
670
379
                        description = "Create the snub version")
671
380
    dual = BoolProperty(name="Dual",
691
400
                                   ("dt4","Triakis Tetrahedron",""),
692
401
                                   ("dr4","Rhombic Dodecahedron",""),
693
402
                                   ("dt6","Triakis Octahedron",""),
694
 
                                   ("dt8","Triakis Hexahedron",""),
 
403
                                   ("dt8","Tetrakis Hexahedron",""),
695
404
                                   ("db6","Deltoidal Icositetrahedron",""),
696
405
                                   ("dc6","Disdyakis Dodecahedron",""),
697
406
                                   ("ds6","Pentagonal Icositetrahedron",""),
700
409
                                   ("dt20","Pentakis Dodecahedron",""),
701
410
                                   ("db12","Deltoidal Hexecontahedron",""),
702
411
                                   ("dc12","Disdyakis Triacontahedron",""),
703
 
                                   ("ds12","Pentagonal Hexecontahedron",""),
704
 
                                   ("c","Cube",""),
705
 
                                   ("sb","Soccer ball","")),
 
412
                                   ("ds12","Pentagonal Hexecontahedron","")),
706
413
                            name = "Presets",
707
414
                            description = "Parameters for some hard names")
708
415
    
709
416
    # actual preset values
710
 
    p = {"t4":["4",2/3,0,0,"0"],
711
 
         "r4":["4",1,1,0,"0"],
712
 
         "t6":["6",2/3,0,0,"0"],
713
 
         "t8":["8",2/3,0,0,"0"],
714
 
         "b6":["6",1.0938,1,0,"0"],
715
 
         "c6":["6",1.0572,0.585786,0,"0"],
716
 
         "s6":["6",1.0875,0.704,0,"L"],
717
 
         "r12":["12",1,0,0,"0"],
718
 
         "t12":["12",2/3,0,0,"0"],
719
 
         "t20":["20",2/3,0,0,"0"],
720
 
         "b12":["12",1.1338,1,0,"0"],
721
 
         "c12":["20",0.921,0.553,0,"0"],
722
 
         "s12":["12",1.1235,0.68,0,"L"],
723
 
         "dt4":["4",2/3,0,1,"0"],
724
 
         "dr4":["4",1,2/3,1,"0"],
725
 
         "dt6":["6",4/3,0,1,"0"],
726
 
         "dt8":["8",1,0,1,"0"],
727
 
         "db6":["6",1.0938,0.756,1,"0"],
728
 
         "dc6":["6",1,1,1,"0"],
729
 
         "ds6":["6",1.0875,0.704,1,"L"],
730
 
         "dr12":["12",1.54,0,1,"0"],
731
 
         "dt12":["12",5/3,0,1,"0"],
732
 
         "dt20":["20",2/3,0,1,"0"],
733
 
         "db12":["12",1,0.912,1,"0"],
734
 
         "dc12":["20",0.921,1,1,"0"],
735
 
         "ds12":["12",1.1235,0.68,1,"L"],
736
 
         "c":["6",0,0,0,"0"],
737
 
         "sb":["20",2/3,0,0,"0"]}
 
417
    p = {"t4":["4",2/3,0,0,"None"],
 
418
         "r4":["4",1,1,0,"None"],
 
419
         "t6":["6",2/3,0,0,"None"],
 
420
         "t8":["8",2/3,0,0,"None"],
 
421
         "b6":["6",1.0938,1,0,"None"],
 
422
         "c6":["6",1.0572,0.585786,0,"None"],
 
423
         "s6":["6",1.0875,0.704,0,"Left"],
 
424
         "r12":["12",1,0,0,"None"],
 
425
         "t12":["12",2/3,0,0,"None"],
 
426
         "t20":["20",2/3,0,0,"None"],
 
427
         "b12":["12",1.1338,1,0,"None"],
 
428
         "c12":["20",0.921,0.553,0,"None"],
 
429
         "s12":["12",1.1235,0.68,0,"Left"],
 
430
         "dt4":["4",2/3,0,1,"None"],
 
431
         "dr4":["4",1,1,1,"None"],
 
432
         "dt6":["6",2/3,0,1,"None"],
 
433
         "dt8":["8",2/3,0,1,"None"],
 
434
         "db6":["6",1.0938,1,1,"None"],
 
435
         "dc6":["6",1.0572,0.585786,1,"None"],
 
436
         "ds6":["6",1.0875,0.704,1,"Left"],
 
437
         "dr12":["12",1,0,1,"None"],
 
438
         "dt12":["12",2/3,0,1,"None"],
 
439
         "dt20":["20",2/3,0,1,"None"],
 
440
         "db12":["12",1.1338,1,1,"None"],
 
441
         "dc12":["20",0.921,0.553,1,"None"],
 
442
         "ds12":["12",1.1235,0.68,1,"Left"]}
738
443
    
739
 
    edit = BoolProperty(name="",
740
 
                        description="",
741
 
                        default=False,
742
 
                        options={'HIDDEN'})
 
444
    #previous preset, for User-friendly reasons
 
445
    previousSetting = ""
743
446
 
744
447
    def execute(self,context):
745
 
        # turn off undo for better performance (3 - 5x faster), also makes sure
 
448
        # turn off undo for better performance (3-5x faster), also makes sure
746
449
        #  that mesh ops are undoable and entire script acts as one operator
747
450
        bpy.context.user_preferences.edit.use_global_undo = False
748
451
 
749
 
 
750
 
        #if preset, set preset
 
452
        # piece of code to make presets remain until parameters are changed
751
453
        if self.preset != "0":
752
 
            using = self.p[self.preset]
753
 
            self.source = using[0]
754
 
            self.vTrunc = using[1]
755
 
            self.eTrunc = using[2]
756
 
            self.dual = using[3]
757
 
            self.snub = using[4]
758
 
            self.preset = "0"
 
454
            #if preset, set preset
 
455
            if self.previousSetting != self.preset:
 
456
                using = self.p[self.preset]
 
457
                self.source = using[0]
 
458
                self.vTrunc = using[1]
 
459
                self.eTrunc = using[2]
 
460
                self.dual = using[3]
 
461
                self.snub = using[4]
 
462
            else: 
 
463
                using = self.p[self.preset]
 
464
                result0 = self.source == using[0]
 
465
                result1 = abs(self.vTrunc - using[1]) < 0.004
 
466
                result2 = abs(self.eTrunc - using[2]) < 0.0015
 
467
                result4 = using[4] == self.snub or ((using[4] == "Left") and 
 
468
                                                self.snub in ["Left","Right"])
 
469
                if (result0 and result1 and result2 and result4): 
 
470
                    if self.p[self.previousSetting][3] != self.dual:
 
471
                        if self.preset[0] == "d": 
 
472
                            self.preset = self.preset[1:]
 
473
                        else:
 
474
                            self.preset = "d" + self.preset
 
475
                else:   
 
476
                    self.preset = "0"
759
477
 
 
478
        self.previousSetting = self.preset
 
479
        
760
480
        # generate mesh    
761
 
        verts,faces = createSolid(self.source,
762
 
                                  self.vTrunc,
763
 
                                  self.eTrunc,
764
 
                                  self.dual,
765
 
                                  self.snub)
 
481
        verts,faces  = createSolid(self.source,
 
482
                                   self.vTrunc,
 
483
                                   self.eTrunc,
 
484
                                   self.dual,
 
485
                                   self.snub)
766
486
 
767
487
        # turn n-gons in quads and tri's
768
488
        faces = createPolys(faces)
769
489
        
770
490
        # resize to normal size, or if keepSize, make sure all verts are of length 'size'
771
491
        if self.keepSize:
772
 
            rad = self.size/verts[0].length
 
492
            rad = self.size/verts[-1 if self.dual else 0].length
773
493
        else: rad = self.size
774
494
        verts = [i*rad for i in verts]
775
495
 
776
496
        # generate object
777
 
        obj = create_mesh_object(context,verts,[],faces,"Solid",self.edit)
778
 
 
779
 
        # vertices will be on top of each other in some cases,
780
 
        #    so remove doubles then
781
 
        if ((self.vTrunc == 1) and (self.eTrunc == 0)) or (self.eTrunc == 1):
782
 
            current_mode = obj.mode
783
 
            if current_mode == 'OBJECT':
784
 
                bpy.ops.object.mode_set(mode='EDIT')
785
 
            bpy.ops.mesh.select_all(action='SELECT')
786
 
            bpy.ops.mesh.remove_doubles()
787
 
            bpy.ops.object.mode_set(mode=current_mode)
788
 
 
789
 
        # snub duals suck, so make all normals point outwards
790
 
        if self.dual and (self.snub != "0"):
791
 
            current_mode = obj.mode
792
 
            if current_mode == 'OBJECT':
793
 
                bpy.ops.object.mode_set(mode='EDIT')
794
 
            bpy.ops.mesh.select_all(action='SELECT')
795
 
            bpy.ops.mesh.normals_make_consistent()
796
 
            bpy.ops.object.mode_set(mode=current_mode)
 
497
        # Create new mesh
 
498
        mesh = bpy.data.meshes.new("Solid")
 
499
 
 
500
        # Make a mesh from a list of verts/edges/faces.
 
501
        mesh.from_pydata(verts, [], faces)
 
502
 
 
503
        # Update mesh geometry after adding stuff.
 
504
        mesh.update()
 
505
        
 
506
        object_data_add(context, mesh, operator=None)
 
507
        # object generation done
797
508
 
798
509
        # turn undo back on
799
510
        bpy.context.user_preferences.edit.use_global_undo = True 
812
523
        layout.menu(PlatonicMenu.bl_idname, text = "Platonic")
813
524
        layout.menu(ArchiMenu.bl_idname, text = "Archimeadean")
814
525
        layout.menu(CatalanMenu.bl_idname, text = "Catalan")
815
 
        layout.menu(OtherMenu.bl_idname, text = "Others")
816
526
 
817
527
class PlatonicMenu(bpy.types.Menu):
818
528
    """Define Platonic menu"""
868
578
        layout.operator(Solids.bl_idname, text = "Rhombic Triacontahedron").preset = "dr12"
869
579
        layout.operator(Solids.bl_idname, text = "Triakis Icosahedron").preset = "dt12"
870
580
        layout.operator(Solids.bl_idname, text = "Pentakis Dodecahedron").preset = "dt20"
871
 
        layout.operator(Solids.bl_idname, text = "Deltoidal Hexecontahedron").preset = "dt20"
872
 
        layout.operator(Solids.bl_idname, text = "Disdyakis Triacontahedron").preset = "db12"
 
581
        layout.operator(Solids.bl_idname, text = "Deltoidal Hexecontahedron").preset = "db12"
 
582
        layout.operator(Solids.bl_idname, text = "Disdyakis Triacontahedron").preset = "dc12"
873
583
        layout.operator(Solids.bl_idname, text = "Pentagonal Hexecontahedron").preset = "ds12"
874
 
 
875
 
class OtherMenu(bpy.types.Menu):
876
 
    """Defines Others preset menu"""
877
 
    bl_idname = "Others_calls"
878
 
    bl_label = "Others"
879
 
    
880
 
    def draw(self, context):
881
 
        layout = self.layout
882
 
        layout.operator_context = 'INVOKE_REGION_WIN'
883
 
        layout.operator(Solids.bl_idname, text = "Cube").preset = "c"
884
 
        layout.operator(Solids.bl_idname, text = "Soccer ball").preset = "sb"
885
584
        
886
 
 
887
 
import space_info
888
 
 
889
 
 
890
585
def menu_func(self, context):
891
586
    self.layout.menu(Solids_add_menu.bl_idname, icon="PLUGIN")
892
587
 
893
588
 
894
589
def register():
895
 
    space_info.INFO_MT_mesh_add.append(menu_func)
 
590
    bpy.utils.register_module(__name__)
 
591
 
 
592
    bpy.types.INFO_MT_mesh_add.append(menu_func)
 
593
 
896
594
 
897
595
def unregister():
898
 
    space_info.INFO_MT_mesh_add.remove(menu_func)
899
 
      
 
596
    bpy.utils.unregister_module(__name__)
 
597
 
 
598
    bpy.types.INFO_MT_mesh_add.remove(menu_func)
 
599
 
 
600
 
900
601
if __name__ == "__main__":
901
602
    register()