Scripts:
[blender.git] / release / scripts / knife.py
1 #!BPY
2
3 """
4 Name: 'Blender Knife Tool'
5 Blender: 232
6 Group: 'Mesh'
7 Tooltip: 'Cut a mesh along a plane w/o creating doubles'
8 """
9
10 # $Id$
11 #
12 ###################################################################
13 #                                                                 #
14 # Blender Knife Tool                                              #
15 #                                                                 #
16 # v. 0.0.0 - 0.0.6 (C) December 2002 Stefano <S68> Selleri        #
17 # v. 0.0.7 (C) March 2004 Wim Van Hoydonck                        #
18 # v. 0.0.8 (C) March 2004 Wim Van Hoydonck & Stefano <S68> Selleri#
19 #                                                                 #
20 # Released under the Blender Artistic Licence (BAL)               #
21 # See www.blender.org                                             #
22 #                                                                 #
23 # Works in Blender 2.32 and higher                                #
24 #                                                                 #
25 # this script can be found online at:                             #
26 # http://users.pandora.be/tuinbels/scripts/knife-0.0.8.py         #
27 # http://www.selleri.org/Blender                                  #
28 #                                                                 #
29 # email: tuinbels@hotmail.com                                     #
30 #        selleri@det.unifi.it                                     #
31 ###################################################################
32 # History                                                         #
33 # V: 0.0.0 - 08-12-02 - The script starts to take shape, a        #
34 #                       history is now deserved :)                #
35 #    0.0.1 - 09-12-02 - The faces are correctly selected and      #
36 #                       assigned to the relevant objects now the  #
37 #                       hard (splitting) part...                  #
38 #    0.0.2 - 14-12-02 - Still hacking on the splitting...         #
39 #                       It works, but I have to de-globalize      #
40 #                       the intersection coordinates              #
41 #    0.0.3 - 15-12-02 - First Alpha version                       #
42 #    0.0.4 - 17-12-02 - Upgraded accordingly to eeshlo tips       #
43 #                       Use Matrices for coordinate transf.       #
44 #                       Add a GUI                                 #
45 #                       Make it Run on 2.23                       #
46 #    0.0.5 - 17-12-02 - Eeshlo solved some problems....           #
47 #                       Theeth too adviced me                     #
48 #    0.0.6 - 18-12-02 - Better error messages                     #
49 #    0.0.7 - 26-03-04 - Developer team doubles!                   #
50 #                       This version is by Wim!                   #
51 #                       Doesn't create doubles (AFAIK)            #
52 #                     - Faster (for small meshes), global         #
53 #                       coordinates of verts are calculated only  #
54 #                       once                                      #
55 #                     - Editing the CutPlane in editmode (move)   #
56 #                       shouldn't cause problems anymore          #
57 #                     - Menu button added to choose between the   #
58 #                       different Edit Methods                    #
59 #                     - If a mesh is cut twice at the same place, #
60 #                       this gives errors :( (also happened in    #
61 #                       previous versions)                        #
62 #                     - Willian Padovani Germano solved           #
63 #                       a problem, many thanks :)                 #
64 #                     - Stefano Selleri made some good            #
65 #                       suggestions, thanks :)                    #
66 #    0.0.8 - 26-03-04 - General Interface rewrite (Stefano)       #
67 #    0.0.8a- 31-03-04 - Added some error messages                 #
68 #                     - Cut multiple meshes at once               #
69 #                                                                 #
70 ###################################################################
71
72 import Blender
73 from Blender import *
74 from Blender.sys import time
75 from math import *
76
77 Epsilon = 0.00001
78 msg = ''
79 RBmesh0 = Draw.Create(0)
80 RBmesh1 = Draw.Create(0)
81 RBmesh2 = Draw.Create(1)
82
83 VERSION = '0.0.8'
84
85 # see if time module is available
86 #try:
87 #       import time
88 #       timport = 1
89 #except:
90 #       timport = 0
91
92
93 BL_VERSION = Blender.Get('version')
94 if (BL_VERSION<=223):
95         import Blender210
96
97 #=================================#
98 # Vector and matrix manipulations #
99 #=================================#
100
101 # vector addition
102 def vecadd(a, b):
103         return [a[0] - b[0], a[1] - b[1], a[2] + b[2]]
104
105 # vector substration
106 def vecsub(a, b):
107         return [a[0] - b[0], a[1] - b[1], a[2] - b[2]]
108
109 # vector crossproduct
110 def veccross(x, y):
111         v = [0, 0, 0]
112         v[0] = x[1]*y[2] - x[2]*y[1]
113         v[1] = x[2]*y[0] - x[0]*y[2]
114         v[2] = x[0]*y[1] - x[1]*y[0]
115         return v
116
117 # vector dotproduct
118 def vecdot(x, y):
119         return x[0]*y[0] + x[1]*y[1] + x[2]*y[2]
120
121 # vector length
122 def length(v):
123         return sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2])
124
125 # vector multiplied by constant s
126 def vecmul(a, s):
127         return[a[0]*s, a[1]*s, a[2]*s]
128
129 # vector divided by constant s
130 def vecdiv(a, s):
131         if s!=0.0: s = 1.0/s
132         return vecmul(a, s)
133
134 # matrix(4x3) vector multiplication
135 def mulmatvec4x3(a, b):
136         # a is vector, b is matrix
137         r = [0, 0, 0]
138         r[0] = a[0]*b[0][0] + a[1]*b[1][0] + a[2]*b[2][0] + b[3][0]
139         r[1] = a[0]*b[0][1] + a[1]*b[1][1] + a[2]*b[2][1] + b[3][1]
140         r[2] = a[0]*b[0][2] + a[1]*b[1][2] + a[2]*b[2][2] + b[3][2]
141         return r
142
143 # Normalization of a vector
144 def Normalize(a):
145         lengte = length(a)
146         return vecdiv(a, lengte)
147
148 # calculate normal from 3 verts
149 def Normal(v0, v1, v2):
150         return veccross(vecsub(v0, v1),vecsub(v0, v2))
151
152 #===========================#
153 # Coordinatetransformations #
154 #===========================#
155
156 def GlobalPosition(P, Obj):
157
158         if (BL_VERSION<=223):
159                 m = Obj.matrix
160         else:
161                 m = Obj.getMatrix()
162
163         return mulmatvec4x3(P, m)
164
165 def LocalPosition(P, Obj):
166
167         if (BL_VERSION<=223):
168                 m = Blender210.getObject(Obj.name).inverseMatrix
169         else:
170                 m = Obj.getInverseMatrix()
171
172         return mulmatvec4x3(P, m)
173
174 #================#
175 # Get Plane Data #
176 #================#
177
178 def PlaneData(Plane):
179         global msg
180         #
181         # Calculate: 
182         # - the normal of the plane, 
183         # - the offset of the plane wrt the global coordinate system
184         #   in the direction of the normal of the plane
185         # 
186         PlaneMesh   = NMesh.GetRawFromObject(Plane.name)
187
188         if (len(PlaneMesh.faces)>1):
189                 msg =  "ERROR: Active object must be a single face plane"
190                 return ((0,0,0),(0,0,0),1)
191         else:
192                 if (len(PlaneMesh.verts)<3):
193                         msg = "ERROR: 3 vertices needed to define a plane"
194                         return ((0,0,0),(0,0,0),1)
195                 else:
196                         v0 = GlobalPosition(PlaneMesh.faces[0].v[0].co, Plane)
197                         v1 = GlobalPosition(PlaneMesh.faces[0].v[1].co, Plane)
198                         v2 = GlobalPosition(PlaneMesh.faces[0].v[2].co, Plane)
199                         
200                         # the normal of the plane, calculated from the first 3 verts
201                         PNormal = Normalize(Normal(v0,v1,v2))
202
203                         # offset of the plane, using 1st vertex instead of Plane.getLocaction()
204                         POffset = vecdot(v0,PNormal)
205
206                         return PNormal, POffset, 0
207
208 #====================================#
209 # Position with respect to Cut Plane #
210 #====================================#
211
212 def Distance(P, N, d0):
213         #
214         # distance from a point to a plane
215         #
216         return vecdot(P, N) - d0
217
218 def FacePosition(dist):
219         #
220         # position of a face wrt to the plane
221         #
222         np, nn, nz = 0, 0, 0
223
224         for d in dist:
225
226                 # the distances are calculated in advance
227                 if d > 0:
228                         np += 1
229                 elif d < 0:
230                         nn += 1
231                 else:
232                         nz += 1 
233
234         if np == 0:
235                 return -1
236         if nn == 0:
237                 return 1
238         return 0
239
240 #==========================================#
241 # Append existing faces / create new faces #
242 #==========================================#
243
244 def FaceAppend(me, fidx):
245         #
246         # append a face to a mesh based on a list of vertex-indices
247         #
248         nf = NMesh.Face()
249
250         for i in fidx:
251                 nf.v.append(me.verts[i])
252         me.faces.append(nf)
253
254 def FaceMake(me, vl):
255         #
256         # make one or two new faces based on a list of vertex-indices
257         #
258         idx = len(me.verts)
259
260         if len(vl) <= 4:
261                 nf = NMesh.Face()
262                 for i in range(len(vl)):
263                         nf.v.append(me.verts[vl[i]])
264                 me.faces.append(nf)
265         else:
266                 nf = NMesh.Face()
267                 nf.v.append(me.verts[vl[0]])
268                 nf.v.append(me.verts[vl[1]])
269                 nf.v.append(me.verts[vl[2]])
270                 nf.v.append(me.verts[vl[3]])
271                 me.faces.append(nf)
272
273                 nf = NMesh.Face()
274                 nf.v.append(me.verts[vl[3]])
275                 nf.v.append(me.verts[vl[4]])
276                 nf.v.append(me.verts[vl[0]])
277                 me.faces.append(nf)
278    
279 #=====================================#
280 # Generate vertex lists for new faces #
281 #=====================================#
282
283 def Split(Obj, MeshPos, MeshNeg, Vglob, Vidx, N, d0, newvidx, newvcoo, totverts, d):
284         #
285         # - calculate intersectionpoints of the plane with faces
286         # - see if this intersectionpoint already exists (look for vertices close to the new vertex)
287         # - if it does not yet exist, append a vertex to the mesh,
288         #   remember its index and location and append the index to the appropriate vertex-lists
289         # - if it does, use that vertex (and its index) to create the face
290         #
291  
292         vp = []
293         vn = []
294
295         # distances of the verts wrt the plane are calculated in main part of script
296         
297         for i in range(len(d)):
298                 # the previous vertex
299                 dim1 = d[int(fmod(i-1,len(d)))]
300                 Vim1 = Vglob[int(fmod(i-1,len(d)))]
301
302                 if abs(d[i]) < Epsilon:
303                         # if the vertex lies in the cutplane                    
304                         vp.append(Vidx[i])
305                         vn.append(Vidx[i])
306                 else:
307                         if abs(dim1) < Epsilon:
308                                 # if the previous vertex lies in cutplane
309                                 if d[i] > 0:
310                                         vp.append(Vidx[i])
311                                 else:
312                                         vn.append(Vidx[i])
313                         else:
314                                 if d[i]*dim1 > 0:
315                                         # if they are on the same side of the plane
316                                         if d[i] > 0:
317                                                 vp.append(Vidx[i])
318                                         else:
319                                                 vn.append(Vidx[i])
320                                 else:
321                                         # the vertices are not on the same side of the plane, so we have an intersection
322
323                                         Den = vecdot(vecsub(Vglob[i],Vim1),N)
324
325                                         Vi = []    
326                                         Vi.append ( ((Vim1[0]*Vglob[i][1]-Vim1[1]*Vglob[i][0])*N[1]+(Vim1[0]*Vglob[i][2]-Vim1[2]*Vglob[i][0])*N[2]+(Vglob[i][0]-Vim1[0])*d0)/Den)
327                                         Vi.append ( ((Vim1[1]*Vglob[i][0]-Vim1[0]*Vglob[i][1])*N[0]+(Vim1[1]*Vglob[i][2]-Vim1[2]*Vglob[i][1])*N[2]+(Vglob[i][1]-Vim1[1])*d0)/Den)
328                                         Vi.append ( ((Vim1[2]*Vglob[i][0]-Vim1[0]*Vglob[i][2])*N[0]+(Vim1[2]*Vglob[i][1]-Vim1[1]*Vglob[i][2])*N[1]+(Vglob[i][2]-Vim1[2])*d0)/Den)
329
330                                         ViL = LocalPosition(Vi, Obj)
331
332                                         if newvidx == []: 
333                                                 # if newvidx is empty (the first time Split is called), append a new vertex
334                                                 # to the mesh and remember its vertex-index and location
335                                                 ViLl = NMesh.Vert(ViL[0],ViL[1],ViL[2])
336
337                                                 if MeshPos == MeshNeg:
338                                                         MeshPos.verts.append(ViLl)
339
340                                                 else:
341                                                         MeshPos.verts.append(ViLl)
342                                                         MeshNeg.verts.append(ViLl)
343
344                                                 nvidx = totverts
345                                                 newvidx.append(nvidx)
346                                                 newvcoo.append(ViL)
347
348                                                 vp.append(nvidx)
349                                                 vn.append(nvidx)
350                                         else:
351                                                 # newvidx is not empty
352                                                 dist1 = []
353                                                 tlr = 0
354                                                 for j in range(len(newvidx)): 
355                                                         # calculate the distance from the new vertex to the vertices
356                                                         # in the list with new vertices
357                                                         dist1.append(length(vecsub(ViL, newvcoo[j])))
358                                                 for k in range(len(dist1)):
359                                                         if dist1[k] < Epsilon:
360                                                                 # if distance is smaller than epsilon, use the other vertex
361                                                                 # use newvidx[k] as vert
362                                                                 vp.append(newvidx[k])
363                                                                 vn.append(newvidx[k])
364                                                                 break # get out of closest loop
365                                                         else:
366                                                                 tlr += 1
367
368                                                 if tlr == len(newvidx):
369                                                         nvidx = totverts + len(newvidx)
370                                                         ViLl = NMesh.Vert(ViL[0],ViL[1],ViL[2])
371
372                                                         if MeshPos == MeshNeg:
373                                                                 MeshPos.verts.append(ViLl)
374
375                                                         else:
376                                                                 MeshPos.verts.append(ViLl)
377                                                                 MeshNeg.verts.append(ViLl)
378
379                                                         newvidx.append(nvidx)
380                                                         newvcoo.append(ViL)
381                                                         vp.append(nvidx)
382                                                         vn.append(nvidx)
383
384                                         if d[i] > 0:
385                                                 vp.append(Vidx[i])
386                                         else:
387                                                 vn.append(Vidx[i])
388   
389         return vp, vn, newvidx, newvcoo
390
391 #===========#
392 # Main part #
393 #===========#
394
395 def CutMesh():
396         global msg
397         global RBmesh0,RBmesh1,RBmesh2
398         #if timport == 1:
399         #       start = time.clock()
400         start = time()
401         
402         selected_obs = Object.GetSelected()
403
404         total = len(selected_obs)
405
406         NoErrors=0
407
408         meshes = 0
409
410         # check to see if every selected object is a mesh
411         for ob in selected_obs:
412                 type = ob.getType()
413                 if type == 'Mesh':
414                         meshes += 1
415
416         # at least select two objects
417         if meshes <= 1:
418                 msg = "ERROR: At least two objects should be selected"
419                 NoErrors = 1
420
421         # if not every object is a mesh
422         if meshes != total:
423                 msg = "ERROR: You should only select meshobjects"
424                 NoErrors=1
425
426         # everything is ok
427         if NoErrors == 0:
428                 Pln = selected_obs[0]
429                 PNormal, POffset, NoErrors = PlaneData(Pln)
430
431         # loop to cut multiple meshes at once
432         for o in range(1, total):
433                 
434                 Obj = selected_obs[o]
435
436                 if (NoErrors == 0) :
437                 
438                         m = Obj.getData()
439
440                         if RBmesh1.val == 1:
441
442                                 MeshNew = NMesh.GetRaw()
443
444                         if RBmesh2.val == 1:
445
446                                 MeshPos = NMesh.GetRaw()
447                                 MeshNeg = NMesh.GetRaw()
448
449                         # get the indices of the faces of the mesh
450                         idx = []
451                         for i in range(len(m.faces)):
452                                 idx.append(i)
453
454                         # if idx is not reversed, this results in a list index out of range if
455                         # the original mesh is used (RBmesh1 == 0)
456                         idx.reverse()
457
458                         lenface, vertglob, vertidx, vertdist = [], [], [], []
459
460                         # total number of vertices
461                         totverts = len(m.verts)
462
463                         # for every face: calculate global coordinates of the vertices
464                         #                 append the vertex-index to a list
465                         #                 calculate distance of vertices to cutplane in advance
466
467                         for i in idx:
468                                 fvertidx, Ve, dist = [], [], []
469                                 fa = m.faces[i]
470                                 lenface.append(len(fa))
471                                 for v in fa.v:
472                                         globpos = GlobalPosition(v.co, Obj)
473                                         Ve.append(globpos)
474                                         fvertidx.append(v.index)
475                                         dist.append(Distance(globpos, PNormal, POffset))
476                                 vertidx.append(fvertidx)
477                                 vertglob.append(Ve)
478                                 vertdist.append(dist)
479
480
481                         # append the verts of the original mesh to the new mesh
482                         if RBmesh1.val == 1:
483                                 for v in m.verts:
484                                         MeshNew.verts.append(v)
485         
486                         if RBmesh2.val == 1:
487                                 idx2 = []
488                                 dist2 = []
489                                 for v in m.verts:
490                                         MeshPos.verts.append(v)
491                                         MeshNeg.verts.append(v)
492                                         idx2.append(v.index)
493                                         dist2.append(Distance(GlobalPosition(v.co, Obj), PNormal, POffset))
494
495                         # remove all faces of m if the original object has to be used
496
497                         if RBmesh0.val == 1:
498                                 m.faces = []
499
500                         newvidx, newvcoo = [], []
501                         testidxpos, testidxneg = [], []
502
503                         # what its all about...
504                         for i in idx:
505                                 fp = FacePosition(vertdist[i])
506
507                                 # no intersection
508                                 if fp > 0:
509                                         if RBmesh0.val == 1:
510                                                 FaceAppend(m, vertidx[i])
511                         
512                                         elif RBmesh1.val == 1:
513                                                 FaceAppend(MeshNew, vertidx[i])
514                                 
515                                         elif RBmesh2.val == 1:
516                                                 FaceAppend(MeshPos, vertidx[i])
517
518                                                 if testidxpos == []:
519                                                         testidxpos = vertidx[i]
520                                 elif fp < 0:
521                                         if RBmesh0.val == 1:
522                                                 FaceAppend(m, vertidx[i])
523                                         elif RBmesh1.val == 1:
524                                                 FaceAppend(MeshNew, vertidx[i])
525                                         
526                                         elif RBmesh2.val == 1:
527                                                 FaceAppend(MeshNeg, vertidx[i])
528
529                                                 if testidxneg == []:
530                                                         testidxneg = vertidx[i]
531
532                                 # intersected faces
533                                 else:
534                                         # make new mesh
535                                         if RBmesh1.val == 1:
536                                                 vlp, vln, newvidx, newvcoo = Split(Obj, MeshNew, MeshNew, vertglob[i], vertidx[i], PNormal, POffset, newvidx, newvcoo, totverts, vertdist[i])
537
538                                                 if vlp != 0 and vln != 0:
539                                                         FaceMake(MeshNew, vlp)
540                                                         FaceMake(MeshNew, vln)
541                                                 # two new meshes
542                                         elif RBmesh2.val == 1:
543                                                 vlp, vln, newvidx, newvcoo = Split(Obj, MeshPos, MeshNeg, vertglob[i], vertidx[i], PNormal, POffset, newvidx, newvcoo, totverts, vertdist[i])
544         
545                                                 if vlp != 0 and vln != 0:
546                                                         FaceMake(MeshPos, vlp)
547                                                         FaceMake(MeshNeg, vln)
548
549                                         # use old mesh
550                                         elif RBmesh0.val == 1:
551         
552                                                 vlp, vln, newvidx, newvcoo = Split(Obj, m, m, vertglob[i], vertidx[i], PNormal, POffset, newvidx, newvcoo, totverts, vertdist[i])
553         
554                                                 if vlp != 0 and vln != 0:
555                                                         FaceMake(m, vlp)
556                                                         FaceMake(m, vln)
557
558                         if RBmesh1.val == 1:
559
560                                 ObOne = NMesh.PutRaw(MeshNew)
561
562                                 ObOne.LocX, ObOne.LocY, ObOne.LocZ = Obj.LocX, Obj.LocY, Obj.LocZ
563                                 ObOne.RotX, ObOne.RotY, ObOne.RotZ = Obj.RotX, Obj.RotY, Obj.RotZ
564                                 ObOne.SizeX, ObOne.SizeY, ObOne.SizeZ = Obj.SizeX, Obj.SizeY, Obj.SizeZ
565
566                         elif RBmesh2.val == 1:
567
568                                 # remove verts that do not belong to a face
569                                 idx2.reverse()
570                                 dist2.reverse()
571
572                                 for i in range(len(idx2)):
573                                         if dist2[i] < 0:
574                                                 v = MeshPos.verts[idx2[i]]
575                                                 MeshPos.verts.remove(v)
576                                         if dist2[i] > 0:
577                                                 v = MeshNeg.verts[idx2[i]]
578                                                 MeshNeg.verts.remove(v)
579
580                                 ObPos = NMesh.PutRaw(MeshPos)
581
582                                 ObPos.LocX, ObPos.LocY, ObPos.LocZ = Obj.LocX, Obj.LocY, Obj.LocZ
583                                 ObPos.RotX, ObPos.RotY, ObPos.RotZ = Obj.RotX, Obj.RotY, Obj.RotZ
584                                 ObPos.SizeX, ObPos.SizeY, ObPos.SizeZ = Obj.SizeX, Obj.SizeY, Obj.SizeZ
585
586                                 ObNeg = NMesh.PutRaw(MeshNeg)
587
588                                 ObNeg.LocX, ObNeg.LocY, ObNeg.LocZ = Obj.LocX, Obj.LocY, Obj.LocZ
589                                 ObNeg.RotX, ObNeg.RotY, ObNeg.RotZ = Obj.RotX, Obj.RotY, Obj.RotZ
590                                 ObNeg.SizeX, ObNeg.SizeY, ObNeg.SizeZ = Obj.SizeX, Obj.SizeY, Obj.SizeZ
591
592                         elif RBmesh0.val == 1:
593                                 m.update()
594
595
596         #if timport == 1:
597                 #end = time.clock()
598                 #total = end - start
599                 #print "mesh(es) cut in", total, "seconds" 
600
601         end = time()
602         total = end - start
603         print "mesh(es) cut in", total, "seconds"
604
605 #############################################################
606 # Graphics                                                  #
607 #############################################################
608 def Warn():
609         BGL.glRasterPos2d(115, 23)
610         Blender.Window.Redraw(Blender.Window.Const.TEXT)
611
612 def draw():
613         global msg
614         global RBmesh0,RBmesh1,RBmesh2
615         global VERSION
616         
617         BGL.glClearColor(0.5, 0.5, 0.5, 0.0)
618         BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
619         BGL.glColor3f(0, 0, 0)                  # Black
620         BGL.glRectf(2, 2, 482, 220)
621         BGL.glColor3f(0.48, 0.4, 0.57)          # Light Purple
622         BGL.glRectf(4, 179, 480, 210)
623         BGL.glRectf(4, 34, 480, 150)
624         BGL.glColor3f(0.3, 0.27, 0.35)          # Dark purple
625         BGL.glRectf(4, 151,480, 178)
626         BGL.glRectf(4, 4, 480, 33)
627         
628
629         BGL.glColor3f(1, 1, 1)
630         BGL.glRasterPos2d(8, 200)
631         Draw.Text("Blender Knife Tool -  V. 0.0.8a - 26 March 2004")
632         BGL.glRasterPos2d(8, 185)
633         Draw.Text("by Wim <tuinbels> Van Hoydonck & Stefano <S68> Selleri")
634         Draw.Button("Exit", 1, 430, 185, 40, 20)
635
636         RBmesh0 = Draw.Toggle("Edit Object",    10,10,157,153,18,RBmesh0.val, "The knife creates new vertices in the selected object.");
637         RBmesh1 = Draw.Toggle("New Object",     11,165,157,153,18,RBmesh1.val, "The knife duplicates the object and creates new vertices in the new object.");
638         RBmesh2 = Draw.Toggle("Two New Objects",12,320,157,153,18,RBmesh2.val, "The knife creates two new separate objects.");
639
640         BGL.glRasterPos2d(8, 128)
641         Draw.Text("1 - Draw a Mesh Plane defining the Cut Plane")
642         BGL.glRasterPos2d(8, 108)
643         Draw.Text("2 - Select the Meshes to be Cut and the Cut Plane")
644         BGL.glRasterPos2d(8, 88)
645         Draw.Text("      (Meshes Dark Purple, Plane Light Purple)")
646         BGL.glRasterPos2d(8, 68)
647         Draw.Text("3 - Choose the Edit Method (Radio Buttons above)")
648         BGL.glRasterPos2d(8, 48)
649         Draw.Text("4 - Push the 'CUT' button (below)")
650         #Create Buttons
651         Draw.Button("CUT", 4, 10, 10, 465, 18, "Cut the selected mesh along the plane")
652
653         
654         BGL.glRasterPos2d(10, 223)
655         BGL.glColor3f(1,0,0)
656         Draw.Text(msg)
657         msg = ''
658         
659 def event(evt, val):
660         if (evt == Draw.QKEY or evt == Draw.ESCKEY) and not val:
661                 Draw.Exit()
662         if evt == Draw.CKEY and not val:
663                 CutMesh()
664                 Draw.Redraw()
665
666 def bevent(evt):
667         global RBmesh0,RBmesh1,RBmesh2
668
669         if evt == 1:
670                 Draw.Exit()
671         elif evt == 4:
672                 CutMesh()
673                 Draw.Redraw()
674         elif evt == 10:
675                 RBmesh0.val = 1
676                 RBmesh1.val = 0
677                 RBmesh2.val = 0
678                 Draw.Redraw()
679         elif evt == 11:
680                 RBmesh0.val = 0
681                 RBmesh1.val = 1
682                 RBmesh2.val = 0
683                 Draw.Redraw()
684         elif evt == 12:
685                 RBmesh0.val = 0
686                 RBmesh1.val = 0
687                 RBmesh2.val = 1
688                 Draw.Redraw()
689
690 Draw.Register(draw, event, bevent)