BProjection: i've desactivate some line of code because it make some error and I...
[blender-addons-contrib.git] / space_view3d_paint_bprojection.py
1 bl_info = {
2     "name": "BProjection",
3     "description": "Help Clone tool",
4     "author": "kgeogeo",
5     "version": (1, 0),
6     "blender": (2, 6, 3),
7     "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/3D_interaction/bprojection",
8     "tracker_url":"http://projects.blender.org/tracker/index.php?func=detail&aid=30521&group_id=153&atid=468",
9     "category": "Paint"}
10
11 import bpy
12 from bpy.types import Panel, Operator
13 from bpy.props import IntProperty, FloatProperty, BoolProperty, IntVectorProperty, StringProperty, FloatVectorProperty, CollectionProperty
14 from bpy_extras import view3d_utils
15 import math
16 from math import *
17 import mathutils
18 from mathutils import *
19
20 # Main function for align the plan to view
21 def align_to_view(context):
22     ob = context.object
23     em = bpy.data.objects['Empty for BProjection']       
24     rotation = em.custom_rotation
25     scale = em.custom_scale
26     z = em.custom_location.z
27     pos = [em.custom_location.x, em.custom_location.y]
28     
29     reg = context.area.regions[4]        
30     width = reg.width
31     height = reg.height 
32     
33     sd = context.space_data    
34     r3d = sd.region_3d     
35     r3d.update()
36     vr = r3d.view_rotation
37     quat = mathutils.Quaternion((0.0, 0.0, 1.0), math.radians(float(rotation)))
38     v = Vector((pos[0],pos[1],z))
39     v.rotate(vr)
40
41     em = bpy.data.objects['Empty for BProjection']
42     img = bpy.data.textures['Texture for BProjection'].image
43     if img and img.size[1] != 0:
44         prop = img.size[0]/img.size[1]
45     else: prop = 1    
46     
47     if em.custom_linkscale:    
48         em.scale = Vector((prop*scale[0], scale[0], 1))
49     else:
50         em.scale = Vector((prop*scale[0], scale[1], 1))
51     pos_cur = em.location - sd.cursor_location
52     rot_cur1 = em.rotation_euler.to_quaternion()
53     em.location = v + ob.location            
54     em.rotation_euler = Quaternion.to_euler(vr*quat)   
55     if em.custom_c3d:
56         if em.custom_old_scale != em.custom_scale:
57             pos_cur = em.location - sd.cursor_location       
58         rot_cur2 = em.rotation_euler.to_quaternion()
59         rot_cur1.invert()
60         pos_cur.rotate(rot_cur1)
61         pos_cur.rotate(rot_cur2)
62         v = em.location - pos_cur
63         sd.cursor_location =  v
64
65 # Function to update the properties
66 def update_Location(self, context):          
67     align_to_view(context)
68
69 def find_uv(context):
70     obj = context.object
71     me = obj.data.vertices
72     vg = obj.vertex_groups
73     l=[]
74     index_uv = 0      
75     for face in obj.data.polygons:
76         x=len(face.vertices)
77         for vertex in face.vertices:
78             if len(me[vertex].groups)>0:
79                 for g in me[vertex].groups:
80                     if vg[g.group].name == 'texture plane':
81                         x-=1
82         
83                         
84         if x == 0:
85             l.append([index_uv,len(face.vertices)])
86         index_uv += len(face.vertices)
87     return l
88
89 # Function to update the scaleUV
90 def update_UVScale(self, context):
91     ob = context.object
92     em = bpy.data.objects['Empty for BProjection']
93     v = Vector((em.custom_offsetuv[0]/10 + 0.5, em.custom_offsetuv[1]/10 + 0.5))
94     l = Vector((0.0,0.0))
95     s = em.custom_scaleuv
96     os = em.custom_old_scaleuv 
97     scale = s - os
98     l = find_uv(context)
99     for i,j in l:
100         for t in range(j):
101             d = context.object.data.uv_layers.active.data[i+t]
102             vres =  v - d.uv  
103             d.uv.x = v.x - vres.x/os[0]*s[0]
104             d.uv.y = v.y - vres.y/os[1]*s[1]
105
106     em.custom_old_scaleuv = s  
107     
108     bpy.ops.object.applyimage()
109
110 def update_PropUVScale(self, context):
111     em = bpy.data.objects['Empty for BProjection']
112     if em.custom_linkscaleuv:
113         em.custom_scaleuv = [em.custom_propscaleuv,em.custom_propscaleuv]
114
115 def update_LinkUVScale(self, context):
116     em = bpy.data.objects['Empty for BProjection']
117     if em.custom_linkscaleuv:
118         em.custom_propscaleuv = em.custom_scaleuv.x
119         update_PropUVScale(self, context)
120     else:
121         update_UVScale(self, context) 
122         
123 # Function to update the offsetUV
124 def update_UVOffset(self, context):
125     ob = context.object
126     em = bpy.data.objects['Empty for BProjection']
127     o = em.custom_offsetuv
128     oo = em.custom_old_offsetuv 
129     l = find_uv(context)
130     for i,j in l:
131         for t in range(j):
132             d = context.object.data.uv_layers.active.data[i+t]
133             d.uv = [d.uv[0] - oo[0]/10 + o[0]/10, d.uv[1] - oo[1]/10 + o[1]/10]   
134     em.custom_old_offsetuv = o
135     
136     bpy.ops.object.applyimage()
137
138 # Function to update the flip horizontal
139 def update_FlipUVX(self, context):
140     l = find_uv(context)
141     for i,j in l:
142         for t in range(j):
143             d = context.object.data.uv_layers.active.data[i+t]
144             x = d.uv.x
145             d.uv.x = 1 - x
146     
147     bpy.ops.object.applyimage()
148
149 # Function to update the flip vertical
150 def update_FlipUVY(self, context):
151     l = find_uv(context)
152     for i,j in l:
153         for t in range(j):
154             d = context.object.data.uv_layers.active.data[i+t]
155             y = d.uv[1]
156             d.uv[1] = 1 - y
157     
158     bpy.ops.object.applyimage()
159
160 # Function to update
161 def update_Rotation(self, context):              
162     ob = context.object
163     em = bpy.data.objects['Empty for BProjection']
164     if em.custom_rotc3d:
165         angle = em.custom_rotation - em.custom_old_rotation
166         sd = context.space_data
167         vr = sd.region_3d.view_rotation.copy()        
168         c = sd.cursor_location - ob.location
169         e = bpy.data.objects['Empty for BProjection'].location - ob.location
170         vo = Vector((0.0, 0.0, 1.0))
171         vo.rotate(vr)
172         quat = mathutils.Quaternion(vo, math.radians(angle))
173         v = e-c
174         v.rotate(quat)
175         vr.invert()
176         v.rotate(vr)
177         c.rotate(vr)
178         em.custom_location = c + v
179     else:        
180         align_to_view(context)
181    
182     em.custom_old_rotation = em.custom_rotation
183
184 # Function to update scale
185 def update_Scale(self, context):              
186     ob = context.object
187     em = bpy.data.objects['Empty for BProjection']
188     
189     if em.custom_scac3d:
190         sd = context.space_data
191         r3d =  sd.region_3d
192         vr = r3d.view_rotation.copy()
193         vr.invert()
194         e = em.location - ob.location
195         c = sd.cursor_location - ob.location
196         ce = e - c
197         
198         s = em.custom_scale
199         os = em.custom_old_scale
200         c.rotate(vr)
201         ce.rotate(vr)
202         
203         img = bpy.data.textures['Texture for BProjection'].image
204         if img and img.size[1] != 0:
205             prop = img.size[0]/img.size[1]
206         else: prop = 1
207         
208         v = Vector((s.x*ce.x/os.x, s.y*ce.y/os.y,0.0))
209         em.custom_location = c + v
210         
211
212     else:          
213         align_to_view(context)
214             
215     
216     em.custom_old_scale = em.custom_scale
217
218 def update_PropScale(self, context):
219     em = bpy.data.objects['Empty for BProjection']
220     if em.custom_linkscale:
221         em.custom_scale = [em.custom_propscale,em.custom_propscale]
222     
223 def update_LinkScale(self, context):
224     em = bpy.data.objects['Empty for BProjection']
225     if em.custom_linkscale:
226         em.custom_propscale = em.custom_scale.x
227         update_PropScale(self, context)
228     else:
229         update_Scale(self, context) 
230
231 def update_activeviewname(self, context):
232     em = bpy.data.objects['Empty for BProjection']
233     if self.custom_active:
234         em.custom_active_view = self.custom_active_view
235
236 class custom_props(bpy.types.PropertyGroup):
237     custom_location = FloatVectorProperty(name="Location", description="Location of the plan",
238                                            default=(0,0,-1.0),
239                                            subtype = 'XYZ', size=3)
240                                            
241     custom_rotation = FloatProperty(name="Rotation", description="Rotate the plane",
242                                      min=-180, max=180, default=0)
243                                          
244     custom_scale = FloatVectorProperty(name="Scales", description="Scale the planes",
245                                        subtype = 'XYZ', default=(1.0, 1.0),min = 0.1, size=2)
246     custom_propscale = FloatProperty(name="PropScale", description="Scale the Plan",
247                                            default=1.0,min = 0.1)
248                                                                                     
249     custom_linkscale = BoolProperty(name="linkscale", default=True)
250    
251     # UV properties
252     custom_scaleuv = FloatVectorProperty(name="ScaleUV", description="Scale the texture's UV",
253                                             default=(1.0,1.0),min = 0.01, subtype = 'XYZ', size=2)
254     custom_propscaleuv = FloatProperty(name="PropScaleUV", description="Scale the texture's UV",
255                                            default=1.0,min = 0.01) 
256     custom_offsetuv = FloatVectorProperty(name="OffsetUV", description="Decal the texture's UV",
257                                             default=(0.0,0.0), subtype = 'XYZ', size=2)       
258     custom_linkscaleuv = BoolProperty(name="linkscaleUV", default=True)
259     custom_flipuvx = BoolProperty(name="flipuvx", default=False)
260     custom_flipuvy = BoolProperty(name="flipuvy", default=False)
261     
262     # other properties
263     custom_active= BoolProperty(name="custom_active", default=True)   
264     custom_expand = BoolProperty(name="expand", default=False)
265     
266     custom_active_view = StringProperty(name = "custom_active_view",default = "View",update = update_activeviewname)
267     
268     custom_image = StringProperty(name = "custom_image",default = "")
269     
270     custom_index = IntProperty()
271
272 # Function to create custom properties
273 def createcustomprops(context):
274     Ob = bpy.types.Object    
275     
276     # plane properties 
277     Ob.custom_location = FloatVectorProperty(name="Location", description="Location of the plan",
278                                            default=(5.0,0.0,-1.0),
279                                            subtype = 'XYZ', size=3, update = update_Location)
280                                            
281     Ob.custom_rotation = FloatProperty(name="Rotation", description="Rotate the plane",
282                                      min=-180, max=180, default=0,update = update_Rotation)
283                                      
284     Ob.custom_old_rotation = FloatProperty(name="old_Rotation", description="Old Rotate the plane",
285                                          min=-180, max=180, default=0)
286                                          
287     Ob.custom_scale = FloatVectorProperty(name="Scales", description="Scale the planes",
288                                           subtype = 'XYZ', default=(1.0, 1.0),min = 0.1, size=2,update = update_Scale)
289     Ob.custom_propscale = FloatProperty(name="PropScale", description="Scale the Plan",
290                                            default=1.0,min = 0.1,update = update_PropScale)
291     Ob.custom_old_scale = FloatVectorProperty(name="old_Scales", description="Old Scale the planes",
292                                           subtype = 'XYZ', default=(1.0, 1.0),min = 0.1, size=2)
293                                           
294     Ob.custom_linkscale = BoolProperty(name="linkscale", default=True, update = update_LinkScale)
295     
296                                 
297     Ob.custom_sub = IntProperty(name="Subdivide", description="Number of subdivision of the plan",
298                                      min=1, max=20, default=10)                                
299     
300     # UV properties
301     Ob.custom_scaleuv = FloatVectorProperty(name="ScaleUV", description="Scale the texture's UV",
302                                             default=(1.0,1.0),min = 0.01, subtype = 'XYZ', size=2,update = update_UVScale)
303     Ob.custom_propscaleuv = FloatProperty(name="PropScaleUV", description="Scale the texture's UV",
304                                            default=1.0,min = 0.01,update = update_PropUVScale)    
305     Ob.custom_old_scaleuv = FloatVectorProperty(name="old_ScaleUV", description="Scale the texture's UV",
306                                                 default=(1.0,1.0),min = 0.01, subtype = 'XYZ', size=2)
307     Ob.custom_offsetuv = FloatVectorProperty(name="OffsetUV", description="Decal the texture's UV",
308                                             default=(0.0,0.0), subtype = 'XYZ', size=2,update = update_UVOffset)    
309     Ob.custom_old_offsetuv = FloatVectorProperty(name="old_OffsetUV", description="Decal the texture's UV",
310                                                  default=(0.0,0.0), subtype = 'XYZ', size=2)    
311     Ob.custom_linkscaleuv = BoolProperty(name="linkscaleUV", default=True, update = update_LinkUVScale)
312     Ob.custom_flipuvx = BoolProperty(name="flipuvx", default=False, update = update_FlipUVX)
313     Ob.custom_flipuvy = BoolProperty(name="flipuvy", default=False, update = update_FlipUVY)
314     
315     # other properties    
316     Ob.custom_c3d = BoolProperty(name="c3d", default=True)
317     Ob.custom_rotc3d = BoolProperty(name="rotc3d", default=False)
318     Ob.custom_scac3d = BoolProperty(name="scac3d", default=False)
319     Ob.custom_expand = BoolProperty(name="expand", default=True)
320     Ob.custom_active_view = StringProperty(name = "custom_active_view",default = "View")
321     Ob.custom_active_object = StringProperty(name = "custom_active_object",default = context.object.name)
322     
323     Ob.custom_props = CollectionProperty(type = custom_props)
324
325 # Function to remove custom properties
326 def removecustomprops():    
327     list_prop = ['custom_location', 'custom_rotation', 'custom_old_rotation', 'custom_scale', 'custom_old_scale', 'custom_c3d',
328                  'custom_rotc3d', 'custom_scaleuv', 'custom_flipuvx', 'custom_flipuvy', 'custom_linkscale',
329                  'custom_linkscaleuv', 'custom_old_scaleuv', 'custom_offsetuv', 'custom_old_offsetuv', 'custom_scac3d', 'custom_sub',
330                  'custom_expand', 'custom_active_view', 'custom_propscaleuv', 'custom_props', 'custom_propscale']
331     for prop in list_prop:
332         try:
333             del bpy.data.objects['Empty for BProjection'][prop]
334         except:
335             do = 'nothing'
336 def clear_props(context):
337     em = bpy.data.objects['Empty for BProjection'] 
338     em.custom_scale = [1,1]
339     em.custom_rotation = 0
340     em.custom_scaleuv =[1.0,1.0]
341     em.custom_offsetuv =[0.0,0.0]
342     em.custom_propscaleuv = 1.0
343     em.custom_propscale = 1.0
344     if em.custom_flipuvx == True:
345         em.custom_flipuvx = False
346     if em.custom_flipuvy == True:
347         em.custom_flipuvy = False
348
349 # Oprerator Class to create view            
350 class CreateView(Operator):
351     bl_idname = "object.create_view"
352     bl_label = "Create a new view"
353
354     def execute(self, context):              
355         ob = context.object
356         em = bpy.data.objects['Empty for BProjection']
357         new_props = em.custom_props.add()
358         
359         em.custom_active_view = new_props.custom_active_view               
360         new_props.custom_index = len(em.custom_props)-1
361         bpy.ops.object.active_view(index = new_props.custom_index)
362         ob.data.shape_keys.key_blocks[ob.active_shape_key_index].mute = True
363         bpy.ops.object.shape_key_add(from_mix = False)
364         ob.data.shape_keys.key_blocks[ob.active_shape_key_index].value = 1.0
365         return {'FINISHED'}
366
367 # Oprerator Class to copy view 
368 class SaveView(Operator):
369     bl_idname = "object.save_view"
370     bl_label = "copy the view"
371     
372     index = IntProperty(default = 0)
373     
374     def execute(self, context):              
375         em = bpy.data.objects['Empty for BProjection']
376         prop = em.custom_props[self.index]                            
377         prop.custom_rotation =  em.custom_rotation                    
378         prop.custom_scale =  em.custom_scale                  
379         prop.custom_linkscale =  em.custom_linkscale                                      
380         prop.custom_scaleuv = em.custom_scaleuv
381         prop.custom_propscale = em.custom_propscale
382         prop.custom_offsetuv =  em.custom_offsetuv  
383         prop.custom_linkscaleuv = em.custom_linkscaleuv
384         prop.custom_propscaleuv = em.custom_propscaleuv
385         prop.custom_flipuvx = em.custom_flipuvx
386         prop.custom_flipuvy = em.custom_flipuvy
387         try:
388             prop.custom_image = bpy.data.textures['Texture for BProjection'].image.name
389         except:
390             do = 'nothing'
391         
392         return {'FINISHED'}
393
394 # Oprerator Class to copy view 
395 class PasteView(Operator):
396     bl_idname = "object.paste_view"
397     bl_label = "paste the view"
398     
399     index = IntProperty(default = 0)
400     
401     def execute(self, context):              
402         em = bpy.data.objects['Empty for BProjection']
403         tmp_scac3d = em.custom_scac3d
404         tmp_rotc3d = em.custom_rotc3d
405         em.custom_scac3d = False
406         em.custom_rotc3d = False
407         prop = em.custom_props[self.index]
408         em.custom_linkscale =  prop.custom_linkscale
409         em.custom_offsetuv =  prop.custom_offsetuv 
410         em.custom_linkscaleuv = prop.custom_linkscaleuv
411         em.custom_scaleuv = prop.custom_scaleuv
412         em.custom_propscaleuv = prop.custom_propscaleuv       
413         em.custom_rotation =  prop.custom_rotation                    
414         em.custom_scale =  prop.custom_scale
415         em.custom_propscale = prop.custom_propscale                     
416         if prop.custom_image != '':
417             if bpy.data.textures['Texture for BProjection'].image.name != prop.custom_image:
418                 bpy.data.textures['Texture for BProjection'].image = bpy.data.images[prop.custom_image]
419                 bpy.ops.object.applyimage()
420         if em.custom_flipuvx != prop.custom_flipuvx:
421             em.custom_flipuvx = prop.custom_flipuvx
422         if em.custom_flipuvy != prop.custom_flipuvy:
423             em.custom_flipuvy = prop.custom_flipuvy
424         em.custom_scac3d = tmp_scac3d
425         em.custom_rotc3d = tmp_rotc3d        
426         return {'FINISHED'}
427
428 # Oprerator Class to remove view 
429 class RemoveView(Operator):
430     bl_idname = "object.remove_view"
431     bl_label = "Rmeove the view"
432     
433     index = IntProperty(default = 0)
434     
435     def execute(self, context):              
436         ob = context.object
437         em = bpy.data.objects['Empty for BProjection']
438         
439         ob.active_shape_key_index =  self.index + 1
440         bpy.ops.object.shape_key_remove()
441         
442         if  em.custom_props[self.index].custom_active: 
443             if len(em.custom_props) > 0:
444                 bpy.ops.object.active_view(index = self.index-1)
445             if self.index == 0 and len(em.custom_props) > 1:
446                 bpy.ops.object.active_view(index = 1)            
447                 
448         em.custom_props.remove(self.index)
449                 
450         if len(em.custom_props) == 0:
451             clear_props(context)
452             
453             bpy.ops.object.create_view()            
454                  
455         i=0
456         for item in em.custom_props:
457             item.custom_index = i           
458             i+=1 
459
460         for item in (item for item in em.custom_props if item.custom_active):
461                 ob.active_shape_key_index = item.custom_index+1
462            
463         return {'FINISHED'}
464
465 # Oprerator Class to copy view 
466 class ActiveView(Operator):
467     bl_idname = "object.active_view"
468     bl_label = "Active the view"
469     
470     index = IntProperty(default = 0)
471     
472     def execute(self, context):
473         ob = context.object
474         em = bpy.data.objects['Empty for BProjection']
475         for item in (item for item in em.custom_props if item.custom_active == True):
476             bpy.ops.object.save_view(index = item.custom_index)
477             item.custom_active = False
478         em.custom_props[self.index].custom_active  = True
479         em.custom_active_view = em.custom_props[self.index].custom_active_view 
480         ob.active_shape_key_index =  self.index + 1
481         
482         for i in ob.data.shape_keys.key_blocks:
483             i.mute = True
484         
485         ob.data.shape_keys.key_blocks[ob.active_shape_key_index].mute = False
486         
487         bpy.ops.object.paste_view(index = self.index)         
488         
489         return {'FINISHED'}
490
491 # Draw Class to show the panel
492 class BProjection(Panel):
493     bl_space_type = 'VIEW_3D'
494     bl_region_type = 'UI'
495     bl_label = "BProjection"
496
497     @classmethod
498     def poll(cls, context):
499         return (context.image_paint_object or context.sculpt_object)
500
501     def draw(self, context):        
502         layout = self.layout
503                 
504         try: 
505             bpy.data.objects['Empty for BProjection']
506             
507             tex = bpy.data.textures['Texture for BProjection']
508             ob = context.object
509             em = bpy.data.objects['Empty for BProjection']
510             if ob == bpy.data.objects[em.custom_active_object]:            
511                 col = layout.column(align =True)
512                 col.operator("object.removebprojectionplane", text="Remove BProjection plane")           
513                 
514             box = layout.box()
515
516             row = box.row()
517             if not em.custom_expand:
518                 row.prop(em, "custom_expand", text  = "", icon="TRIA_RIGHT", emboss=False)
519                 row.label(text= 'Paint Object: '+ ob.name)
520             else:
521                 row.prop(em, "custom_expand", text = "" , icon="TRIA_DOWN", emboss=False)                
522                 row.label(text= 'Paint Object: '+ ob.name)
523                 
524                 if ob == bpy.data.objects[em.custom_active_object]:
525                     col = box.column(align =True)
526                     col.template_ID(tex, "image", open="image.open")
527                     row  = box.row(align=True)
528                     row.operator('object.applyimage', text="Apply image", icon = 'FILE_TICK')
529                     row.prop(em, "custom_c3d",text="", icon='CURSOR')
530                     row  = box.row(align =True)
531                     row.label(text="Location:")
532                     row  = box.row(align =True)
533                     row.prop(em,'custom_location', text='')
534                     row  = box.row(align =True)            
535                     row.prop(em,'custom_rotation')
536                     row.prop(em,'custom_rotc3d',text="",icon='MANIPUL')            
537                     row  = box.row(align =True)
538                     row.label(text="Scale:")
539                     row  = box.row(align =True) 
540                     if em.custom_linkscale :
541                         row.prop(em, "custom_propscale",text="")
542                         row.prop(em, "custom_linkscale",text="",icon='LINKED')
543                     else: 
544                         row.prop(em,'custom_scale',text='')
545                         row.prop(em, "custom_linkscale",text="",icon='UNLINKED')
546                     row.prop(em,'custom_scac3d',text="",icon='MANIPUL')                            
547                     row  = box.row(align =True)
548                     row.label(text="UV's Offset:")
549                     row  = box.row(align =True)
550                     row.prop(em,'custom_offsetuv',text='')
551                     row.prop(em, "custom_flipuvx",text="",icon='ARROW_LEFTRIGHT')   
552                     row.prop(em, "custom_flipuvy",text="",icon='FULLSCREEN_ENTER') 
553                     row  = box.row(align =True)
554                     row.label(text="UV's Scale:")
555                     row  = box.row(align =True)                            
556                     if em.custom_linkscaleuv:
557                         row.prop(em,'custom_propscaleuv',text='')
558                         row.prop(em, "custom_linkscaleuv",text="",icon='LINKED')
559                     else: 
560                         row.prop(em,'custom_scaleuv',text='')
561                         row.prop(em, "custom_linkscaleuv",text="",icon='UNLINKED')            
562                     row = box.column(align =True)
563                     row.prop(ob.material_slots['Material for BProjection'].material,'alpha', slider = True)
564                     row = box.column(align =True)
565     
566                 if ob == bpy.data.objects[em.custom_active_object]:    
567                     for item in em.custom_props:
568                         box = layout.box()
569                         row = box.row()
570                         if item.custom_active:
571                             row.operator("object.active_view",text = "", icon='RADIOBUT_ON', emboss = False).index = item.custom_index 
572                         else:
573                             row.operator("object.active_view",text = "", icon='RADIOBUT_OFF', emboss = False).index = item.custom_index 
574                         row.prop(item, "custom_active_view", text="")        
575                         row.operator('object.remove_view', text="", icon = 'PANEL_CLOSE', emboss = False).index = item.custom_index
576                     row = layout.row()
577                     row.operator('object.create_view', text="Create View", icon = 'RENDER_STILL') 
578                 else:
579                     col = box.column(align =True)
580                     col.operator("object.change_object", text="Change Object")       
581
582         except:
583             col = layout.column(align = True)
584             col.operator("object.addbprojectionplane", text="Add BProjection plan")
585                    
586
587 # Oprerator Class to apply the image to the plane             
588 class ApplyImage(Operator):
589     bl_idname = "object.applyimage"
590     bl_label = "Apply image"
591
592     def execute(self, context):        
593         img = bpy.data.textures['Texture for BProjection'].image
594         em = bpy.data.objects['Empty for BProjection']
595         ob = context.object
596         em = bpy.data.objects['Empty for BProjection']
597         cm = context.object.mode
598                
599         bpy.ops.object.editmode_toggle()
600         f = ob.data.polygons
601         nbface = len(ob.data.polygons)
602         uvdata = ob.data.uv_textures.active.data 
603         wasnul = False
604         if len(uvdata) == 0:
605             bpy.ops.object.editmode_toggle()
606             uvdata = ob.data.uv_textures.active.data
607             wasnul = True                        
608         
609         
610         vglen = trunc(pow(em.custom_sub+1, 2))
611         
612         for i,d in zip(f,uvdata):
613             if i.select:
614                 d.image = img
615                         
616         if wasnul == False:
617             bpy.ops.object.editmode_toggle()
618         else:
619             bpy.ops.object.mode_set(mode = cm, toggle=False)
620                 
621         align_to_view(context)
622         
623         return {'FINISHED'}
624
625 # Oprerator Class to make the 4 or 6 point and scale the plan
626 class IntuitiveScale(Operator):
627     bl_idname = "object.intuitivescale"
628     bl_label = "Draw lines"
629
630     def invoke(self, context, event):
631         ob = context.object
632         em = bpy.data.objects['Empty for BProjection']
633         x = event.mouse_region_x
634         y = event.mouse_region_y                
635         if len(ob.grease_pencil.layers.active.frames) == 0: 
636             bpy.ops.gpencil.draw(mode='DRAW', stroke=[{"name":"", "pen_flip":False,
637                                                        "is_start":True, "location":(0, 0, 0),
638                                                        "mouse":(x,y), "pressure":1, "time":0}])
639         else:
640             if em.custom_linkscale:
641                 nb_point = 4
642             else:
643                 nb_point = 6
644                    
645             if len(ob.grease_pencil.layers.active.frames[0].strokes) < nb_point:
646                 bpy.ops.gpencil.draw(mode='DRAW', stroke=[{"name":"", "pen_flip":False,
647                                                            "is_start":True, "location":(0, 0, 0),
648                                                            "mouse":(x,y), "pressure":1, "time":0}])
649                                                            
650             if len(ob.grease_pencil.layers.active.frames[0].strokes) == nb_point:
651                 s = ob.grease_pencil.layers.active.frames[0]
652                 v1 = s.strokes[1].points[0].co - s.strokes[0].points[0].co
653                 if not em.custom_linkscale:
654                     v2 = s.strokes[4].points[0].co - s.strokes[3].points[0].co
655                 else:
656                     v2 = s.strokes[3].points[0].co - s.strokes[2].points[0].co
657                 propx = v1.x/v2.x                
658                 em.custom_scale[0] *= abs(propx)
659                 
660                 if not em.custom_linkscale:
661                     v1 = s.strokes[2].points[0].co - s.strokes[0].points[0].co
662                     v2 = s.strokes[5].points[0].co - s.strokes[3].points[0].co
663                     propy = v1.y/v2.y
664                     em.custom_scale[1] *= abs(propy)
665                 bpy.ops.gpencil.active_frame_delete()
666         
667         return {'FINISHED'}
668
669 # Oprerator Class to configure all wath is needed
670 class AddBProjectionPlane(Operator):
671     bl_idname = "object.addbprojectionplane"
672     bl_label = "Configure"
673     
674     def creatematerial(self, context):        
675         try:
676             matBProjection = bpy.data.materials['Material for BProjection']
677         except:            
678             bpy.data.textures.new(name='Texture for BProjection',type='IMAGE')
679     
680             bpy.data.materials.new(name='Material for BProjection')
681             
682             matBProjection = bpy.data.materials['Material for BProjection']
683             matBProjection.texture_slots.add()
684             matBProjection.use_shadeless = True
685             matBProjection.use_transparency = True
686             matBProjection.active_texture = bpy.data.textures['Texture for BProjection']
687         
688             index = matBProjection.active_texture_index
689             matBProjection.texture_slots[index].texture_coords = 'UV'
690         
691         ob = context.object 
692         old_index = ob.active_material_index
693         bpy.ops.object.material_slot_add()
694         index = ob.active_material_index
695         ob.material_slots[index].material = bpy.data.materials['Material for BProjection']
696         bpy.ops.object.material_slot_assign()
697         ob.active_material_index = old_index
698         ob.data.update()
699             
700     def execute(self, context):    
701         try:
702             bpy.data.objects['Empty for BProjection']
703
704         except:                 
705             createcustomprops(context)
706             cm = bpy.context.object.mode
707             tmp = context.object
708             '''for ob in (ob for ob in bpy.data.objects if ob.type == 'MESH' and ob.hide == False and context.scene in ob.users_scene):
709                 context.scene.objects.active = ob
710                 bpy.ops.object.mode_set(mode = cm, toggle=False)''' 
711             
712             context.scene.objects.active = tmp
713             bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
714             
715             context.space_data.show_relationship_lines = False
716             
717             ob = context.object
718         
719             bpy.ops.object.add()
720             em = context.object
721             em.name = "Empty for BProjection"
722                         
723             context.scene.objects.active = ob
724             ob.select = True
725     
726             bpy.ops.object.editmode_toggle()
727     
728             bpy.ops.mesh.primitive_plane_add()
729             bpy.ops.object.vertex_group_assign(new = True)
730             ob.vertex_groups.active.name = 'texture plane'   
731             bpy.ops.uv.unwrap()
732             
733             bpy.ops.mesh.select_all(action='DESELECT')                                
734             bpy.ops.object.vertex_group_select()
735             
736             bpy.ops.object.editmode_toggle()
737             for i in range(4):
738                 ob.data.edges[len(ob.data.edges)-1-i].crease = 1
739             bpy.ops.object.editmode_toggle()
740
741             bpy.ops.mesh.subdivide(number_cuts = em.custom_sub)
742     
743             em.select = True
744             bpy.ops.object.hook_add_selob()
745             em.select = False
746             em.hide = True   
747                      
748             self.creatematerial(context)
749   
750           
751             bpy.ops.gpencil.data_add()
752             ob.grease_pencil.draw_mode = 'VIEW'
753             bpy.ops.gpencil.layer_add()
754             ob.grease_pencil.layers.active.color = [1.0,0,0]
755             
756             bpy.ops.object.editmode_toggle()
757             
758             bpy.ops.object.shape_key_add(from_mix = False)
759             
760             bpy.ops.object.create_view()
761             # ----------------------------------------------
762             # XXX, this isnt future proof, DON'T USE INDEX's - campbell                    
763             km = bpy.data.window_managers['WinMan'].keyconfigs['Blender'].keymaps['3D View']
764             km.keymap_items[3-1].idname = 'view3d.rotate_view3d'
765             km.keymap_items[19-1].idname = 'view3d.zoom_view3d'
766             km.keymap_items[19-1].properties.delta = 1.0
767             km.keymap_items[20-1].idname = 'view3d.zoom_view3d'
768             km.keymap_items[20-1].properties.delta = -1.0
769             km.keymap_items[4-1].idname = 'view3d.pan_view3d'
770             km.keymap_items[26-1].idname = 'view3d.preset_view3d'
771             km.keymap_items[26-1].properties.view = 'FRONT'
772             km.keymap_items[28-1].idname = 'view3d.preset_view3d'
773             km.keymap_items[28-1].properties.view = 'RIGHT'            
774             km.keymap_items[32-1].idname = 'view3d.preset_view3d'
775             km.keymap_items[32-1].properties.view = 'TOP'
776             km.keymap_items[34-1].idname = 'view3d.preset_view3d'
777             km.keymap_items[34-1].properties.view = 'BACK'
778             km.keymap_items[35-1].idname = 'view3d.preset_view3d'
779             km.keymap_items[35-1].properties.view = 'LEFT'            
780             km.keymap_items[36-1].idname = 'view3d.preset_view3d'
781             km.keymap_items[36-1].properties.view = 'BOTTOM'                                   
782             km = context.window_manager.keyconfigs.default.keymaps['Image Paint']
783             kmi = km.keymap_items.new("object.intuitivescale", 'LEFTMOUSE', 'PRESS', shift=True)
784                         
785             align_to_view(context)
786             
787             context.space_data.cursor_location = em.location
788             
789             bpy.ops.object.mode_set(mode = cm, toggle=False)
790             
791         return {'FINISHED'}
792
793 # Oprerator Class to remove what is no more needed    
794 class RemoveBProjectionPlane(Operator):
795     bl_idname = "object.removebprojectionplane"
796     bl_label = "Configure"
797
798     def removematerial(self, context):
799         ob = context.object 
800         i = 0
801
802         for ms in ob.material_slots:
803             if ms.name == 'Material for BProjection':
804                 index = i
805             i+=1
806                 
807         ob.active_material_index = index
808         bpy.ops.object.material_slot_remove()
809     
810     def execute(self, context):
811         try:               
812             cm = bpy.context.object.mode
813             bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
814             
815             context.space_data.show_relationship_lines = True
816             
817             bpy.ops.object.modifier_remove(modifier="Hook-Empty for BProjection")
818             
819             self.removematerial(context)
820
821             ob = context.object
822     
823             bpy.ops.object.editmode_toggle()
824     
825             bpy.ops.mesh.reveal()
826                                    
827             bpy.ops.mesh.select_all(action='DESELECT')                    
828             
829             ob.vertex_groups.active_index = ob.vertex_groups['texture plane'].index
830             bpy.ops.object.vertex_group_select()
831             bpy.ops.mesh.delete()
832             bpy.ops.object.vertex_group_remove()
833     
834             bpy.ops.object.editmode_toggle()
835    
836             ob.select = False
837                 
838             em = bpy.data.objects['Empty for BProjection']
839             context.scene.objects.active = em
840             em.hide = False
841             em.select = True
842             bpy.ops.object.delete()
843     
844             context.scene.objects.active = ob
845             ob.select = True
846             
847             km = bpy.data.window_managers['WinMan'].keyconfigs['Blender'].keymaps['3D View']
848             # ----------------------------------------------
849             # XXX, this isnt future proof, DON'T USE INDEX's - campbell
850             km.keymap_items[3-1].idname = 'view3d.rotate'
851             km.keymap_items[19-1].idname = 'view3d.zoom'
852             km.keymap_items[19-1].properties.delta = 1.0
853             km.keymap_items[20-1].idname = 'view3d.zoom'
854             km.keymap_items[20-1].properties.delta = -1.0
855             km.keymap_items[4-1].idname = 'view3d.move'
856             km.keymap_items[26-1].idname = 'view3d.viewnumpad'
857             km.keymap_items[26-1].properties.type = 'FRONT'
858             km.keymap_items[28-1].idname = 'view3d.viewnumpad'
859             km.keymap_items[28-1].properties.type = 'RIGHT'            
860             km.keymap_items[32-1].idname = 'view3d.viewnumpad'
861             km.keymap_items[32-1].properties.type = 'TOP'
862             km.keymap_items[34-1].idname = 'view3d.viewnumpad'
863             km.keymap_items[34-1].properties.type = 'BACK'
864             km.keymap_items[35-1].idname = 'view3d.viewnumpad'
865             km.keymap_items[35-1].properties.type = 'LEFT'            
866             km.keymap_items[36-1].idname = 'view3d.viewnumpad'
867             km.keymap_items[36-1].properties.type = 'BOTTOM'            
868             
869             km = context.window_manager.keyconfigs.default.keymaps['Image Paint']
870             #to do
871             for kmi in (kmi for kmi in km.keymap_items if kmi.idname in {"object.intuitivescale", }):
872                     km.keymap_items.remove(kmi)
873             
874             tmp = context.object
875             '''for ob in (ob for ob in bpy.data.objects if ob.type == 'MESH' and ob.hide == False and context.scene in ob.users_scene):
876                 context.scene.objects.active = ob
877                 bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False) '''
878             
879             context.scene.objects.active = tmp
880             ob = context.object           
881             
882             
883             for i in ob.data.shape_keys.key_blocks:
884                 bpy.ops.object.shape_key_remove()
885             bpy.ops.object.shape_key_remove()
886                
887             bpy.ops.object.mode_set(mode = cm, toggle=False)
888             removecustomprops()
889                     
890         except:
891             nothing = 0
892         
893         return {'FINISHED'}
894
895 # Oprerator Class to remove what is no more needed    
896 class ChangeObject(Operator):
897     bl_idname = "object.change_object"
898     bl_label = "Change Object"
899
900     def removematerial(self, context):
901         ob = context.object 
902         i = 0
903
904         for ms in ob.material_slots:
905             if ms.name == 'Material for BProjection':
906                 index = i
907             i+=1
908                 
909         ob.active_material_index = index
910         bpy.ops.object.material_slot_remove()
911     
912     def execute(self, context):
913             new_ob = context.object
914             em = bpy.data.objects['Empty for BProjection']              
915             context.scene.objects.active = bpy.data.objects[em.custom_active_object]
916             ob = context.object
917             if ob != new_ob:
918                 cm = bpy.context.object.mode
919                 bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
920                 
921                 bpy.ops.object.modifier_remove(modifier="Hook-Empty for BProjection") 
922     
923                 ob = context.object
924         
925                 bpy.ops.object.editmode_toggle()
926         
927                 bpy.ops.mesh.reveal()
928                                        
929                 bpy.ops.mesh.select_all(action='DESELECT')                               
930                 ob.vertex_groups.active_index = ob.vertex_groups['texture plane'].index
931                 bpy.ops.object.vertex_group_select()
932                 lo_b = [ob for ob in bpy.data.objects if ob.type == 'MESH']
933                 bpy.ops.mesh.separate(type='SELECTED')
934                 lo_a = [ob for ob in bpy.data.objects if ob.type == 'MESH']
935                 bpy.ops.object.vertex_group_remove()
936                 
937                 for i in lo_b:
938                     lo_a.remove(i)
939                 bplane = lo_a[0]
940                 
941                 bpy.ops.object.editmode_toggle()
942                 
943                 self.removematerial(context)
944                 
945                 bpy.ops.object.mode_set(mode = cm, toggle=False)
946                 
947                 shape_index = ob.active_shape_key_index
948                 
949                 for i in ob.data.shape_keys.key_blocks:
950                     bpy.ops.object.shape_key_remove()
951                 bpy.ops.object.shape_key_remove()
952                 
953                 ob.select = False
954                 
955                 bplane.select = True            
956                 context.scene.objects.active = bplane
957                 for ms in (ms for ms in bplane.material_slots if ms.name != 'Material for BProjection'):
958                     bplane.active_material = ms.material
959                     bpy.ops.object.material_slot_remove()
960                 
961                 for gs in (gs for gs in bplane.vertex_groups if gs.name != 'texture plane'):
962                     bplane.vertex_groups.active_index = gs.index
963                     bpy.ops.object.vertex_group_remove()
964               
965                 context.scene.objects.active = new_ob
966                 cm = new_ob.mode
967                 bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False) 
968                 bpy.ops.object.join()
969     
970                 em.hide = False
971                 em.select = True
972                 new_ob.select = False
973                 bpy.ops.object.location_clear()
974                 bpy.ops.object.rotation_clear()
975                 bpy.ops.object.scale_clear()
976                 context.scene.objects.active = new_ob
977                 bpy.ops.object.editmode_toggle()            
978                 bpy.ops.object.hook_add_selob()
979                 bpy.ops.object.editmode_toggle()
980                 em.hide = True
981                 em.select = False
982                 new_ob.select = True
983                 em.custom_active_object = new_ob.name
984                 tmp = em.custom_c3d
985                 em.custom_c3d = False
986                 bpy.ops.object.active_view(index = shape_index-1)
987                 bpy.ops.object.mode_set(mode = cm, toggle=False)
988                         
989                 sd = context.space_data
990                 r3d = sd.region_3d 
991                 vr = r3d.view_rotation.copy()
992                 vr.invert()
993                 ob_loc = ob.location.copy()            
994                 new_ob_loc = new_ob.location.copy() 
995                 ob_loc.rotate(vr)
996                 new_ob_loc.rotate(vr)
997                 em.custom_location += Vector((ob_loc.x - new_ob_loc.x, ob_loc.y - new_ob_loc.y, 0.0))
998                 em.custom_c3d = tmp
999                     
1000             return {'FINISHED'}
1001
1002 # Oprerator Class to rotate the view3D
1003 class RotateView3D(Operator):
1004     bl_idname = "view3d.rotate_view3d"
1005     bl_label = "Rotate the View3D"
1006     
1007     first_mouse = Vector((0,0))
1008
1009     pan = Vector((0,0))
1010
1011     key = ['']
1012  
1013     first_time = True
1014     
1015     def vect_sphere(self, context, mx, my):
1016         width = context.area.regions[4].width
1017         height = context.area.regions[4].height
1018            
1019         if width >= height:
1020             ratio = height/width
1021         
1022             x = 2*mx/width
1023             y = 2*ratio*my/height
1024             
1025             x = x - 1
1026             y = y - ratio
1027         else:
1028             ratio = width/height
1029         
1030             x = 2*ratio*mx/width
1031             y = 2*my/height
1032  
1033             x = x - ratio
1034             y = y - 1
1035         
1036         z2 = 1 - x * x - y * y
1037         if z2 > 0:
1038             z= sqrt(z2)
1039         else : z=0
1040             
1041         p = Vector((x, y, z))
1042         p.normalize()
1043         return p
1044     
1045     def tracball(self, context, mx, my, origine):
1046         sd = context.space_data
1047         ob = context.object
1048         em = bpy.data.objects['Empty for BProjection']        
1049             
1050         vr_b = sd.region_3d.view_rotation.copy()
1051         vr_b.invert()
1052         pos_init = sd.region_3d.view_location - origine
1053         sd.region_3d.view_location = origine
1054         
1055         v1 = self.vect_sphere(context, self.first_mouse.x, self.first_mouse.y)
1056         v2 = self.vect_sphere(context, mx, my)
1057                         
1058         axis = Vector.cross(v1,v2);
1059         angle = Vector.angle(v1,v2);
1060             
1061         q =  Quaternion(axis,-2*angle)
1062                         
1063         sd.region_3d.view_rotation *=q
1064         sd.region_3d.update()
1065         
1066         vr_a = sd.region_3d.view_rotation.copy()                           
1067         pos_init.rotate(vr_a*vr_b)            
1068         sd.region_3d.view_location =  pos_init + origine
1069         
1070         self.first_mouse = Vector((mx, my))
1071                 
1072     def modal(self, context, event):                                
1073         ob = context.object
1074         em = bpy.data.objects['Empty for BProjection'] 
1075         reg = context.area.regions[4]        
1076         if event.value == 'PRESS':
1077             self.pan = Vector((event.mouse_region_x, event.mouse_region_y))
1078                     
1079             self.key = [event.type]
1080
1081         if event.value == 'RELEASE':
1082             self.key = [''] 
1083
1084         if event.type == 'MOUSEMOVE':                        
1085             
1086             if '' in self.key:
1087                 self.tracball(context, event.mouse_region_x, event.mouse_region_y,ob.location)
1088                 align_to_view(context)
1089                 if self.first_time:
1090                     rot_ang = context.user_preferences.view.rotation_angle            
1091                     context.user_preferences.view.rotation_angle = 0
1092                     bpy.ops.view3d.view_orbit(type='ORBITLEFT')
1093                     context.user_preferences.view.rotation_angle = rot_ang   
1094                     bpy.ops.view3d.view_persportho()         
1095                     bpy.ops.view3d.view_persportho()
1096                     self.first_time = False
1097           
1098             deltax = event.mouse_region_x - round(self.pan.x)
1099             deltay = event.mouse_region_y - round(self.pan.y)          
1100
1101             if 'G' in self.key:       
1102                 sd = context.space_data              
1103                 l =  sd.region_3d
1104                 vr = l.view_rotation.copy()
1105                 vr.invert()
1106                 
1107                 v_init = Vector((0.0,0.0,1.0))
1108                 
1109                 pos = [-deltax,-deltay]
1110                 v = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)
1111                 pos = [0,0]
1112                 vbl = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)        
1113                 loc = vbl - v            
1114                 loc.rotate(vr)
1115                 em.custom_location += loc              
1116                                    
1117             if 'S' in self.key:                
1118                 s = em.custom_scale
1119                 if em.custom_linkscale:
1120                     em.custom_propscale += deltax/20
1121                 else:
1122                     em.custom_scale = [s[0] + deltax/20, s[1] + deltay/20]
1123                                           
1124             if 'Z' in self.key:                
1125                 em.custom_location.z+=deltax/10
1126                       
1127             if 'R' in self.key:
1128                 em.custom_rotation+=deltax
1129                     
1130             if 'U' in self.key:
1131                 suv = em.custom_scaleuv
1132                 if em.custom_linkscaleuv:    
1133                     em.custom_propscaleuv += deltax/50
1134                 else:
1135                     em.custom_scaleuv= [suv[0] + deltax/50 , suv[1] + deltay/50]               
1136
1137             if 'Y' in self.key:       
1138                 ouv = em.custom_offsetuv
1139                 em.custom_offsetuv = [ouv[0] - deltax/50,ouv[1] - deltay/50] 
1140
1141             self.pan = Vector((event.mouse_region_x, event.mouse_region_y))
1142             self.first_mouse = Vector((event.mouse_region_x, self.first_mouse.y))
1143                         
1144         elif event.type == 'MIDDLEMOUSE'and event.value == 'RELEASE':       
1145             
1146             return {'FINISHED'}
1147         
1148         if 'C' in self.key:
1149             clear_props(context)
1150         
1151         if 'O' in self.key:
1152             bpy.ops.object.change_object()            
1153         return {'RUNNING_MODAL'}
1154     
1155     def execute(self, context):        
1156         align_to_view(context)  
1157         
1158         return{'FINISHED'}
1159
1160     def invoke(self, context, event):
1161         context.window_manager.modal_handler_add(self)
1162         self.first_mouse = Vector((event.mouse_region_x,event.mouse_region_y))
1163         self.first_time = True
1164         
1165         return {'RUNNING_MODAL'}
1166
1167 # Oprerator Class to pan the view3D
1168 class PanView3D(bpy.types.Operator):
1169     bl_idname = "view3d.pan_view3d"
1170     bl_label = "Pan View3D"
1171     
1172     first_mouse = Vector((0,0))
1173
1174     def modal(self, context, event):
1175         ob = context.object
1176         em = bpy.data.objects['Empty for BProjection']
1177         width = context.area.regions[4].width
1178         height = context.area.regions[4].height
1179
1180         deltax = event.mouse_region_x - self.first_mouse.x
1181         deltay = event.mouse_region_y - self.first_mouse.y                
1182         
1183         sd = context.space_data              
1184         r3d =  sd.region_3d
1185         vr = r3d.view_rotation.copy()
1186         vr.invert()
1187         
1188         v_init = Vector((0.0,0.0,1.0))
1189         
1190         pos = [deltax,deltay]
1191         v = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1192         pos = [0,0]
1193         vbl = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)        
1194         loc = vbl - v       
1195         sd.region_3d.view_location += loc         
1196         loc.rotate(vr)
1197         em.custom_location += loc
1198
1199         self.first_mouse.x = event.mouse_region_x
1200         self.first_mouse.y = event.mouse_region_y
1201
1202         if event.type == 'MIDDLEMOUSE'and event.value == 'RELEASE':
1203             return {'FINISHED'}
1204         
1205         return {'RUNNING_MODAL'}
1206                 
1207     def invoke(self, context, event):
1208         context.window_manager.modal_handler_add(self)
1209         self.first_mouse.x = event.mouse_region_x
1210         self.first_mouse.y = event.mouse_region_y   
1211         
1212         return {'RUNNING_MODAL'}
1213
1214     def execute(self, context):        
1215         align_to_view(context)  
1216         
1217         return{'FINISHED'}
1218
1219 # Oprerator Class to zoom the view3D
1220 class ZoomView3D(Operator):
1221     bl_idname = "view3d.zoom_view3d"
1222     bl_label = "Zoom View3D"
1223
1224     delta = FloatProperty(
1225         name="delta",
1226         description="Delta",
1227         min=-1.0, max=1,
1228         default=1.0)
1229
1230     def invoke(self, context, event):                   
1231         ob = context.object
1232         em = bpy.data.objects['Empty for BProjection']
1233         sd = context.space_data
1234
1235         width = context.area.regions[4].width
1236         height = context.area.regions[4].height              
1237                     
1238         r3d =  sd.region_3d
1239         v_init = Vector((0.0,0.0,1.0))
1240
1241         pos = [width,height]
1242         vtr_b = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1243         pos = [0,0]
1244         vbl_b = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1245         len_b = vtr_b - vbl_b
1246        
1247         bpy.ops.view3d.zoom(delta = self.delta)
1248         r3d.update()
1249
1250         pos = [width,height]
1251         vtr_a = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1252         pos = [0,0]
1253         vbl_a = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init) 
1254         len_a = vtr_a - vbl_a
1255         
1256         fac = len_a.length/len_b.length
1257         r3d.view_location -= ob.location
1258         r3d.view_location *= fac
1259         r3d.view_location += ob.location
1260         vres = Vector((em.custom_location.x*fac,em.custom_location.y*fac,em.custom_location.z))
1261         em.custom_location = vres
1262         
1263         
1264         align_to_view(context)
1265         
1266         return {'FINISHED'}
1267
1268     def execute(self, context):        
1269         align_to_view(context)
1270         
1271         return{'FINISHED'}
1272
1273 # Oprerator Class to use numpad shortcut
1274 class PresetView3D(Operator):
1275     bl_idname = "view3d.preset_view3d"
1276     bl_label = "Preset View3D"
1277
1278     view = StringProperty(name="View", description="Select the view", default='TOP')
1279
1280     def invoke(self, context, event):                   
1281         ob = context.object
1282         em = bpy.data.objects['Empty for BProjection']
1283         origine = ob.location
1284         sd = context.space_data
1285
1286         vr_b = sd.region_3d.view_rotation.copy()
1287         vr_b.invert()
1288         pos_init = sd.region_3d.view_location - origine
1289         sd.region_3d.view_location = origine
1290
1291         tmp = context.user_preferences.view.smooth_view
1292         context.user_preferences.view.smooth_view = 0
1293         bpy.ops.view3d.viewnumpad(type=self.view)
1294         align_to_view(context)        
1295         context.user_preferences.view.smooth_view = tmp
1296
1297         vr_a = sd.region_3d.view_rotation.copy()                           
1298         pos_init.rotate(vr_a*vr_b)            
1299         sd.region_3d.view_location =  pos_init + origine
1300                
1301                     
1302         return {'FINISHED'}
1303
1304 def register():
1305     bpy.utils.register_module(__name__)
1306
1307 def unregister():
1308     bpy.utils.unregister_module(__name__)
1309
1310 if __name__ == "__main__":
1311     register()