1d2bd7cdf826bf5aaaab365e518d5536569eb9c8
[blender-addons-contrib.git] / cursor_control / operators.py
1 # -*- coding: utf-8 -*-
2 # ##### BEGIN GPL LICENSE BLOCK #####
3 #
4 #  This program is free software; you can redistribute it and/or
5 #  modify it under the terms of the GNU General Public License
6 #  as published by the Free Software Foundation; either version 2
7 #  of the License, or (at your option) any later version.
8 #
9 #  This program is distributed in the hope that it will be useful,
10 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 #  GNU General Public License for more details.
13 #
14 #  You should have received a copy of the GNU General Public License
15 #  along with this program; if not, write to the Free Software Foundation,
16 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 #
18 # ##### END GPL LICENSE BLOCK #####
19
20
21
22 """
23   TODO:
24
25       IDEAS:
26
27       LATER:
28
29       ISSUES:
30           Bugs:
31           Mites:
32
33       QUESTIONS:
34
35
36 """
37
38
39
40 import bpy
41 import bgl
42 import math
43 from mathutils import Vector, Matrix
44 from mathutils import geometry
45 from misc_utils import *
46 from constants_utils import *
47 from cursor_utils import *
48 from ui_utils import *
49 from geometry_utils import *
50
51
52 class VIEW3D_OT_cursor_to_origin(bpy.types.Operator):
53     '''Move to world origin'''
54     bl_idname = "view3d.cursor_to_origin"
55     bl_label = "Move to world origin"
56     bl_options = {'REGISTER'}
57
58     def modal(self, context, event):
59         return {'FINISHED'}
60
61     def execute(self, context):
62         cc = context.scene.cursor_control
63         cc.hideLinexChoice()
64         cc.setCursor([0,0,0])
65         return {'FINISHED'}
66
67
68
69 class VIEW3D_OT_cursor_to_active_object_center(bpy.types.Operator):
70     '''Move to active object origin'''
71     bl_idname = "view3d.cursor_to_active_object_center"
72     bl_label = "Move to active object origin"
73     bl_options = {'REGISTER'}
74
75     def modal(self, context, event):
76         return {'FINISHED'}
77
78     def execute(self, context):
79         cc = context.scene.cursor_control
80         cc.hideLinexChoice()
81         cc.setCursor(context.active_object.location)
82         return {'FINISHED'}
83
84
85
86 #class VIEW3D_OT_cursor_to_nearest_object(bpy.types.Operator):
87     #'''Move to center of nearest object'''
88     #bl_idname = "view3d.cursor_to_nearest_object"
89     #bl_label = "Move to center of nearest object"
90     #bl_options = {'REGISTER'}
91
92     #def modal(self, context, event):
93         #return {'FINISHED'}
94
95     #def execute(self, context):
96         #cc.setCursor(context.active_object.location)
97         #return {'FINISHED'}
98
99
100
101 #class VIEW3D_OT_cursor_to_selection_midpoint(bpy.types.Operator):
102     #'''Move to active objects median'''
103     #bl_idname = "view3d.cursor_to_selection_midpoint"
104     #bl_label = "Move to active objects median"
105     #bl_options = {'REGISTER'}
106
107     #def modal(self, context, event):
108         #return {'FINISHED'}
109
110     #def execute(self, context):
111         #location = Vector((0,0,0))
112         #n = 0
113         #for obj in context.selected_objects:
114             #location = location + obj.location
115             #n += 1
116         #if (n==0):
117             #return {'CANCELLED'}
118         #location = location / n
119         #cc.setCursor(location)
120         #return {'FINISHED'}
121
122
123
124 class VIEW3D_OT_cursor_to_sl(bpy.types.Operator):
125     '''Move to saved location'''
126     bl_idname = "view3d.cursor_to_sl"
127     bl_label = "Move to saved location"
128     bl_options = {'REGISTER'}
129
130     def modal(self, context, event):
131         return {'FINISHED'}
132
133     def execute(self, context):
134         cc = context.scene.cursor_control
135         if hasattr(context.scene, "cursor_memory"):
136             cm = context.scene.cursor_memory
137             cc.hideLinexChoice()
138             cc.setCursor(cm.savedLocation)
139         return {'FINISHED'}
140
141
142
143 class VIEW3D_OT_cursor_to_sl_mirror(bpy.types.Operator):
144     '''Mirror cursor around SL or selection'''
145     bl_idname = "view3d.cursor_to_sl_mirror"
146     bl_label = "Mirror cursor around SL or selection"
147     bl_options = {'REGISTER'}
148
149     def modal(self, context, event):
150         return {'FINISHED'}
151
152     def mirror(self, cc, p):
153         v = p - Vector(CursorAccess.getCursor())
154         cc.setCursor(p + v)
155
156     def execute(self, context):
157         BlenderFake.forceUpdate()
158         obj = context.active_object
159         cc = context.scene.cursor_control
160         cc.hideLinexChoice()
161         
162         if obj==None or obj.data.total_vert_sel==0:
163             if hasattr(context.scene, "cursor_memory"):
164                 cm = context.scene.cursor_memory
165                 self.mirror(cc, Vector(cm.savedLocation))
166             return {'FINISHED'}
167
168         mat = obj.matrix_world
169
170         if obj.data.total_vert_sel==1:
171             sf = [f for f in obj.data.vertices if f.select == 1]
172             self.mirror(cc, mat*Vector(sf[0].co))
173             return {'FINISHED'}
174
175         mati = mat.copy()
176         mati.invert()
177         c = mati*Vector(CursorAccess.getCursor())
178
179         if obj.data.total_vert_sel==2:
180             sf = [f for f in obj.data.vertices if f.select == 1]
181             p = G3.closestP2L(c, Vector(sf[0].co), Vector(sf[1].co))
182             self.mirror(cc, mat*p)
183             return {'FINISHED'}
184             
185         if obj.data.total_vert_sel==3:
186             sf = [f for f in obj.data.vertices if f.select == 1]
187             v0 = Vector(sf[0].co)
188             v1 = Vector(sf[1].co)
189             v2 = Vector(sf[2].co)
190             normal = (v1-v0).cross(v2-v0)
191             normal.normalize();            
192             p = G3.closestP2S(c, v0, normal)
193             self.mirror(cc, mat*p)
194             return {'FINISHED'}
195               
196         if obj.data.total_face_sel==1:
197             sf = [f for f in obj.data.faces if f.select == 1]
198             v0 = Vector(obj.data.vertices[sf[0].vertices[0]].co)
199             v1 = Vector(obj.data.vertices[sf[0].vertices[1]].co)
200             v2 = Vector(obj.data.vertices[sf[0].vertices[2]].co)
201             normal = (v1-v0).cross(v2-v0)
202             normal.normalize();            
203             p = G3.closestP2S(c, v0, normal)
204             self.mirror(cc, mat*p)
205             return {'FINISHED'}
206
207         return {'CANCELLED'}
208
209
210 class VIEW3D_OT_cursor_to_vertex(bpy.types.Operator):
211     '''Move to closest vertex'''
212     bl_idname = "view3d.cursor_to_vertex"
213     bl_label = "Move to closest vertex"
214     bl_options = {'REGISTER'}
215
216     def modal(self, context, event):
217         return {'FINISHED'}
218
219     def execute(self, context):
220         BlenderFake.forceUpdate()
221         cc = context.scene.cursor_control
222         cc.hideLinexChoice()
223         obj = context.active_object
224         mat = obj.matrix_world
225         mati = mat.copy()
226         mati.invert()
227         vs = obj.data.vertices
228         c = mati*Vector(CursorAccess.getCursor())
229         v = None
230         d = -1
231         for vv in vs:
232             if not vv.select:
233                 continue
234             w = Vector(vv.co)
235             dd = G3.distanceP2P(c, w)
236             if d<0 or dd<d:
237                 v = w
238                 d = dd
239         if v==None:
240             return
241         cc.setCursor(mat*v)
242         return {'FINISHED'}
243
244
245 class VIEW3D_OT_cursor_to_line(bpy.types.Operator):
246     '''Move to closest point on line'''
247     bl_idname = "view3d.cursor_to_line"
248     bl_label = "Move to closest point on line"
249     bl_options = {'REGISTER'}
250
251     def modal(self, context, event):
252         return {'FINISHED'}
253
254     def execute(self, context):
255         BlenderFake.forceUpdate()
256         cc = context.scene.cursor_control
257         cc.hideLinexChoice()
258         obj = bpy.context.active_object
259         mat = obj.matrix_world
260         if obj.data.total_vert_sel==2:
261             sf = [f for f in obj.data.vertices if f.select == 1]
262             p = CursorAccess.getCursor()
263             v0 = mat*sf[0].co
264             v1 = mat*sf[1].co
265             q = G3.closestP2L(p, v0, v1)
266             cc.setCursor(q)
267             return {'FINISHED'}
268         if obj.data.total_edge_sel<2:
269             return {'CANCELLED'}
270         mati = mat.copy()
271         mati.invert()
272         c = mati*Vector(CursorAccess.getCursor())
273         q = None
274         d = -1
275         for ee in obj.data.edges:
276             if not ee.select:
277                 continue
278             e1 = Vector(obj.data.vertices[ee.vertices[0]].co)
279             e2 = Vector(obj.data.vertices[ee.vertices[1]].co)
280             qq = G3.closestP2L(c, e1, e2)
281             dd = G3.distanceP2P(c, qq)
282             if d<0 or dd<d:
283                 q = qq
284                 d = dd
285         if q==None:
286             return {'CANCELLED'}
287         cc.setCursor(mat*q)
288         return {'FINISHED'}
289
290
291 class VIEW3D_OT_cursor_to_edge(bpy.types.Operator):
292     '''Move to closest point on edge'''
293     bl_idname = "view3d.cursor_to_edge"
294     bl_label = "Move to closest point on edge"
295     bl_options = {'REGISTER'}
296
297     def modal(self, context, event):
298         return {'FINISHED'}
299
300     def execute(self, context):
301         BlenderFake.forceUpdate()
302         cc = context.scene.cursor_control
303         cc.hideLinexChoice()
304         obj = bpy.context.active_object
305         mat = obj.matrix_world
306         if obj.data.total_vert_sel==2:
307             sf = [f for f in obj.data.vertices if f.select == 1]
308             p = CursorAccess.getCursor()
309             v0 = mat*sf[0].co
310             v1 = mat*sf[1].co
311             q = G3.closestP2E(p, v0, v1)
312             cc.setCursor(q)
313             return {'FINISHED'}
314         if obj.data.total_edge_sel<2:
315             return {'CANCELLED'}
316         mati = mat.copy()
317         mati.invert()
318         c = mati*Vector(CursorAccess.getCursor())
319         q = None
320         d = -1
321         for ee in obj.data.edges:
322             if not ee.select:
323                 continue
324             e1 = Vector(obj.data.vertices[ee.vertices[0]].co)
325             e2 = Vector(obj.data.vertices[ee.vertices[1]].co)
326             qq = G3.closestP2E(c, e1, e2)
327             dd = G3.distanceP2P(c, qq)
328             if d<0 or dd<d:
329                 q = qq
330                 d = dd
331         if q==None:
332             return {'CANCELLED'}
333         cc.setCursor(mat*q)
334         return {'FINISHED'}
335
336
337 class VIEW3D_OT_cursor_to_plane(bpy.types.Operator):
338     '''Move to closest point on a plane'''
339     bl_idname = "view3d.cursor_to_plane"
340     bl_label = "Move to closest point on a plane"
341     bl_options = {'REGISTER'}
342
343     def modal(self, context, event):
344         return {'FINISHED'}
345
346     def execute(self, context):
347         BlenderFake.forceUpdate()
348         cc = context.scene.cursor_control
349         cc.hideLinexChoice()
350         obj = bpy.context.active_object
351         mesh = obj.data.vertices
352         mat = obj.matrix_world
353         if obj.data.total_vert_sel==3:
354             sf = [f for f in obj.data.vertices if f.select == 1]
355             v0 = Vector(sf[0].co)
356             v1 = Vector(sf[1].co)
357             v2 = Vector(sf[2].co)
358             normal = (v1-v0).cross(v2-v0)
359             normal.normalize();
360             p = CursorAccess.getCursor()
361             n = mat*normal-obj.location
362             v = mat*v0
363             k = - (p-v).dot(n) / n.dot(n)
364             q = p+n*k
365             cc.setCursor(q)
366             return {'FINISHED'}
367
368         mati = mat.copy()
369         mati.invert()
370         c = mati*Vector(CursorAccess.getCursor())
371         q = None
372         d = -1
373         for ff in obj.data.faces:
374             if not ff.select:
375                 continue
376             qq = G3.closestP2S(c, Vector(obj.data.vertices[ff.vertices[0]].co), ff.normal)
377             dd = G3.distanceP2P(c, qq)
378             if d<0 or dd<d:
379                 q = qq
380                 d = dd
381         if q==None:
382             return {'CANCELLED'}
383         cc.setCursor(mat*q)
384         return {'FINISHED'}
385
386
387 class VIEW3D_OT_cursor_to_face(bpy.types.Operator):
388     '''Move to closest point on a face'''
389     bl_idname = "view3d.cursor_to_face"
390     bl_label = "Move to closest point on a face"
391     bl_options = {'REGISTER'}
392
393     def modal(self, context, event):
394         return {'FINISHED'}
395
396     def execute(self, context):
397         BlenderFake.forceUpdate()
398         cc = context.scene.cursor_control
399         cc.hideLinexChoice()
400         obj = bpy.context.active_object
401         mesh = obj.data.vertices
402         mat = obj.matrix_world
403         mati = mat.copy()
404         mati.invert()
405         c = mati*Vector(CursorAccess.getCursor())
406         if obj.data.total_vert_sel==3:
407             sf = [f for f in obj.data.vertices if f.select == 1]
408             v0 = Vector(sf[0].co)
409             v1 = Vector(sf[1].co)
410             v2 = Vector(sf[2].co)
411             fv = [v0, v1, v2]
412             normal = (v1-v0).cross(v2-v0)
413             normal.normalize();
414             q = G3.closestP2F(c, fv, normal)
415             cc.setCursor(mat*q)
416             return {'FINISHED'}
417
418         #visual = True
419
420         qqq = []
421         q = None
422         d = -1
423         for ff in obj.data.faces:
424             if not ff.select:
425                 continue
426             fv=[]
427             for vi in ff.vertices:
428                 fv.append(Vector(obj.data.vertices[vi].co))
429             qq = G3.closestP2F(c, fv, ff.normal)
430             #if visual:
431                 #qqq.append(qq)
432             dd = G3.distanceP2P(c, qq)
433             if d<0 or dd<d:
434                 q = qq
435                 d = dd
436         if q==None:
437             return {'CANCELLED'}
438
439         #if visual:
440             #ci = MeshEditor.addVertex(c)
441             #for qq in qqq:
442                 #qqi = MeshEditor.addVertex(qq)
443                 #MeshEditor.addEdge(ci, qqi)
444
445         cc.setCursor(mat*q)
446         return {'FINISHED'}
447
448
449 class VIEW3D_OT_cursor_to_vertex_median(bpy.types.Operator):
450     '''Move to median of vertices'''
451     bl_idname = "view3d.cursor_to_vertex_median"
452     bl_label = "Move to median of vertices"
453     bl_options = {'REGISTER'}
454
455     def modal(self, context, event):
456         return {'FINISHED'}
457
458     def execute(self, context):
459         BlenderFake.forceUpdate()
460         cc = context.scene.cursor_control
461         cc.hideLinexChoice()
462         obj = context.active_object
463         mat = obj.matrix_world
464         vs = obj.data.vertices
465         selv = [v for v in vs if v.select == 1]
466         location = Vector((0,0,0))
467         for v in selv:
468             location = location + v.co
469         n = len(selv)
470         if (n==0):
471             return {'CANCELLED'}
472         location = location / n
473         cc.setCursor(mat*location)
474         return {'FINISHED'}
475
476
477 class VIEW3D_OT_cursor_to_linex(bpy.types.Operator):
478     '''Alternate between closest encounter points of two lines'''
479     bl_idname = "view3d.cursor_to_linex"
480     bl_label = "Alternate between to closest encounter points of two lines"
481     bl_options = {'REGISTER'}
482
483     def modal(self, context, event):
484         return {'FINISHED'}
485
486     def execute(self, context):
487         BlenderFake.forceUpdate()
488         obj = bpy.context.active_object
489         mat = obj.matrix_world
490
491         se = [e for e in obj.data.edges if (e.select == 1)]
492         e1v1 = obj.data.vertices[se[0].vertices[0]].co
493         e1v2 = obj.data.vertices[se[0].vertices[1]].co
494         e2v1 = obj.data.vertices[se[1].vertices[0]].co
495         e2v2 = obj.data.vertices[se[1].vertices[1]].co
496
497         qq = geometry.intersect_line_line (e1v1, e1v2, e2v1, e2v2)
498
499         q = None
500         if len(qq)==0:
501             #print ("lx 0")
502             return {'CANCELLED'}
503
504         if len(qq)==1:
505             #print ("lx 1")
506             q = qq[0]
507         
508         if len(qq)==2:
509             cc = context.scene.cursor_control
510             cc.cycleLinexCoice(2)
511             q = qq[cc.linexChoice]
512
513         #q = geometry.intersect_line_line (e1v1, e1v2, e2v1, e2v2)[qc] * mat
514         #i2 = geometry.intersect_line_line (e2v1, e2v2, e1v1, e1v2)[0] * mat
515         cc.setCursor(mat*q)
516         return {'FINISHED'}
517
518
519 class VIEW3D_OT_cursor_to_cylinderaxis(bpy.types.Operator):
520     '''Move to closest point on cylinder axis'''
521     bl_idname = "view3d.cursor_to_cylinderaxis"
522     bl_label = "Move to closest point on cylinder axis"
523     bl_options = {'REGISTER'}
524
525     def modal(self, context, event):
526         return {'FINISHED'}
527
528     def execute(self, context):
529         BlenderFake.forceUpdate()
530         cc = context.scene.cursor_control
531         cc.hideLinexChoice()
532         obj = bpy.context.active_object
533         mesh = obj.data.vertices
534         mat = obj.matrix_world
535         mati = mat.copy()
536         mati.invert()
537         c = mati*Vector(CursorAccess.getCursor())
538
539         sf = [f for f in obj.data.vertices if f.select == 1]
540         v0 = Vector(sf[0].co)
541         v1 = Vector(sf[1].co)
542         v2 = Vector(sf[2].co)
543         fv = [v0, v1, v2]
544         q = G3.closestP2CylinderAxis(c, fv)
545         if(q==None):
546             return {'CANCELLED'}
547         cc.setCursor(mat*q)
548         return {'FINISHED'}     
549
550
551 class VIEW3D_OT_cursor_to_spherecenter(bpy.types.Operator):
552     '''Move to center of cylinder or sphere'''
553     bl_idname = "view3d.cursor_to_spherecenter"
554     bl_label = "Move to center of cylinder or sphere"
555     bl_options = {'REGISTER'}
556
557     def modal(self, context, event):
558         return {'FINISHED'}
559
560     def execute(self, context):
561         BlenderFake.forceUpdate()
562         cc = context.scene.cursor_control
563         cc.hideLinexChoice()
564         obj = bpy.context.active_object
565         mesh = obj.data.vertices
566         mat = obj.matrix_world
567         mati = mat.copy()
568         mati.invert()
569         c = mati*Vector(CursorAccess.getCursor())
570
571         if obj.data.total_vert_sel==3:
572             sf = [f for f in obj.data.vertices if f.select == 1]
573             v0 = Vector(sf[0].co)
574             v1 = Vector(sf[1].co)
575             v2 = Vector(sf[2].co)
576             fv = [v0, v1, v2]
577             q = G3.closestP2CylinderAxis(c, fv)
578             #q = G3.centerOfSphere(fv)
579             if(q==None):
580                 return {'CANCELLED'}
581             cc.setCursor(mat*q)
582             return {'FINISHED'}
583         if obj.data.total_vert_sel==4:
584             sf = [f for f in obj.data.vertices if f.select == 1]
585             v0 = Vector(sf[0].co)
586             v1 = Vector(sf[1].co)
587             v2 = Vector(sf[2].co)
588             v3 = Vector(sf[3].co)
589             fv = [v0, v1, v2, v3]
590             q = G3.centerOfSphere(fv)
591             if(q==None):
592                 return {'CANCELLED'}
593             cc.setCursor(mat*q)
594             return {'FINISHED'}
595         return {'CANCELLED'}
596
597
598
599 class VIEW3D_OT_cursor_to_perimeter(bpy.types.Operator):
600     '''Move to perimeter of cylinder or sphere'''
601     bl_idname = "view3d.cursor_to_perimeter"
602     bl_label = "Move to perimeter of cylinder or sphere"
603     bl_options = {'REGISTER'}
604
605     def modal(self, context, event):
606         return {'FINISHED'}
607
608     def execute(self, context):
609         BlenderFake.forceUpdate()
610         cc = context.scene.cursor_control
611         cc.hideLinexChoice()
612         obj = bpy.context.active_object
613         mesh = obj.data.vertices
614         mat = obj.matrix_world
615         mati = mat.copy()
616         mati.invert()
617         c = mati*Vector(CursorAccess.getCursor())
618
619         if obj.data.total_vert_sel==3:
620             sf = [f for f in obj.data.vertices if f.select == 1]
621             v0 = Vector(sf[0].co)
622             v1 = Vector(sf[1].co)
623             v2 = Vector(sf[2].co)
624             fv = [v0, v1, v2]
625             q = G3.closestP2Cylinder(c, fv)
626             if(q==None):
627                 return {'CANCELLED'}
628             #q = G3.centerOfSphere(fv)
629             cc.setCursor(mat*q)
630             return {'FINISHED'}
631         if obj.data.total_vert_sel==4:
632             sf = [f for f in obj.data.vertices if f.select == 1]
633             v0 = Vector(sf[0].co)
634             v1 = Vector(sf[1].co)
635             v2 = Vector(sf[2].co)
636             v3 = Vector(sf[3].co)
637             fv = [v0, v1, v2, v3]
638             q = G3.closestP2Sphere(c, fv)
639             if(q==None):
640                 return {'CANCELLED'}
641             cc.setCursor(mat*q)
642             return {'FINISHED'}
643         return {'CANCELLED'}
644
645
646
647 #class VIEW3D_OT_cursor_offset_from_radius(bpy.types.Operator):
648     #'''Calculate offset from radius'''
649     #bl_idname = "view3d.cursor_offset_from_radius"
650     #bl_label = "Calculate offset from radius"
651     #bl_options = {'REGISTER'}
652
653     #def modal(self, context, event):
654         #return {'FINISHED'}
655
656     #def execute(self, context):
657         #BlenderFake.forceUpdate()
658         #cc = context.scene.cursor_control
659         #cc.hideLinexChoice()
660         #obj = bpy.context.active_object
661         #mesh = obj.data.vertices
662         #mat = obj.matrix_world
663         #mati = mat.copy()
664         #mati.invert()
665         #c = mati*Vector(CursorAccess.getCursor())
666
667         #if obj.data.total_vert_sel==3:
668             #sf = [f for f in obj.data.vertices if f.select == 1]
669             #v0 = Vector(sf[0].co)
670             #v1 = Vector(sf[1].co)
671             #v2 = Vector(sf[2].co)
672             #fv = [v0, v1, v2]
673             #q = G3.centerOfSphere(fv)
674             #d = (v0-q).length
675             #cc.stepLengthValue = d
676             #return {'FINISHED'}
677         #if obj.data.total_vert_sel==4:
678             #sf = [f for f in obj.data.vertices if f.select == 1]
679             #v0 = Vector(sf[0].co)
680             #v1 = Vector(sf[1].co)
681             #v2 = Vector(sf[2].co)
682             #v3 = Vector(sf[3].co)
683             #fv = [v0, v1, v2, v3]
684             #q = G3.centerOfSphere(fv)
685             #d = (v0-q).length
686             #cc.stepLengthValue = d
687             #return {'FINISHED'}
688         #return {'CANCELLED'}
689
690
691
692 class VIEW3D_OT_cursor_stepval_phinv(bpy.types.Operator):
693     '''Set step value to 1/Phi'''
694     bl_idname = "view3d.cursor_stepval_phinv"
695     bl_label = "Set step value to 1/Phi"
696     bl_options = {'REGISTER'}
697
698     def modal(self, context, event):
699         return {'FINISHED'}
700
701     def execute(self, context):
702         cc = context.scene.cursor_control
703         cc.stepLengthValue = PHI_INV
704         BlenderFake.forceRedraw()
705         return {'FINISHED'}
706
707
708
709 class VIEW3D_OT_cursor_stepval_phi(bpy.types.Operator):
710     '''Set step value to Phi'''
711     bl_idname = "view3d.cursor_stepval_phi"
712     bl_label = "Set step value to Phi"
713     bl_options = {'REGISTER'}
714
715     def modal(self, context, event):
716         return {'FINISHED'}
717
718     def execute(self, context):
719         cc = context.scene.cursor_control
720         cc.stepLengthValue = PHI
721         BlenderFake.forceRedraw()
722         return {'FINISHED'}
723
724
725
726 class VIEW3D_OT_cursor_stepval_phi2(bpy.types.Operator):
727     '''Set step value to Phi²'''
728     bl_idname = "view3d.cursor_stepval_phi2"
729     bl_label = "Set step value to Phi²"
730     bl_options = {'REGISTER'}
731
732     def modal(self, context, event):
733         return {'FINISHED'}
734
735     def execute(self, context):
736         cc = context.scene.cursor_control
737         cc.stepLengthValue = PHI_SQR
738         BlenderFake.forceRedraw()
739         return {'FINISHED'}
740
741
742
743 class VIEW3D_OT_cursor_stepval_vvdist(bpy.types.Operator):
744     '''Set step value to distance vertex-vertex'''
745     bl_idname = "view3d.cursor_stepval_vvdist"
746     bl_label = "Set step value to distance vertex-vertex"
747     bl_options = {'REGISTER'}
748
749     def modal(self, context, event):
750         return {'FINISHED'}
751
752     def execute(self, context):
753         BlenderFake.forceUpdate()
754         cc = context.scene.cursor_control
755         cc.hideLinexChoice()
756         obj = bpy.context.active_object
757         mesh = obj.data.vertices
758         mat = obj.matrix_world
759         mati = mat.copy()
760         mati.invert()
761         c = mati*Vector(CursorAccess.getCursor())
762
763         sf = [f for f in obj.data.vertices if f.select == 1]
764         v0 = Vector(sf[0].co)
765         v1 = Vector(sf[1].co)
766         q = (v0-v1).length
767         cc.stepLengthValue = q
768
769         BlenderFake.forceRedraw()
770         return {'FINISHED'}
771
772
773
774
775 class VIEW3D_OT_ccdelta_invert(bpy.types.Operator):
776     '''Invert delta vector'''
777     bl_idname = "view3d.ccdelta_invert"
778     bl_label = "Invert delta vector"
779     bl_options = {'REGISTER'}
780
781     def modal(self, context, event):
782         return {'FINISHED'}
783
784     def execute(self, context):
785         cc = context.scene.cursor_control
786         cc.invertDeltaVector()
787         return {'FINISHED'}
788
789
790
791 class VIEW3D_OT_ccdelta_normalize(bpy.types.Operator):
792     '''Normalize delta vector'''
793     bl_idname = "view3d.ccdelta_normalize"
794     bl_label = "Normalize delta vector"
795     bl_options = {'REGISTER'}
796
797     def modal(self, context, event):
798         return {'FINISHED'}
799
800     def execute(self, context):
801         cc = context.scene.cursor_control
802         cc.normalizeDeltaVector()
803         return {'FINISHED'}
804
805
806
807 class VIEW3D_OT_ccdelta_add(bpy.types.Operator):
808     '''Add delta vector to 3D cursor'''
809     bl_idname = "view3d.ccdelta_add"
810     bl_label = "Add delta vector to 3D cursor"
811     bl_options = {'REGISTER'}
812
813     def modal(self, context, event):
814         return {'FINISHED'}
815
816     def execute(self, context):
817         cc = context.scene.cursor_control
818         cc.addDeltaVectorToCursor()
819         return {'FINISHED'}
820
821
822
823 class VIEW3D_OT_ccdelta_sub(bpy.types.Operator):
824     '''Subtract delta vector to 3D cursor'''
825     bl_idname = "view3d.ccdelta_sub"
826     bl_label = "Subtract delta vector to 3D cursor"
827     bl_options = {'REGISTER'}
828
829     def modal(self, context, event):
830         return {'FINISHED'}
831
832     def execute(self, context):
833         cc = context.scene.cursor_control
834         cc.subDeltaVectorToCursor()
835         return {'FINISHED'}
836
837
838
839 class VIEW3D_OT_ccdelta_vvdist(bpy.types.Operator):
840     '''Set delta vector from selection'''
841     bl_idname = "view3d.ccdelta_vvdist"
842     bl_label = "Set delta vector from selection"
843     bl_options = {'REGISTER'}
844
845     def modal(self, context, event):
846         return {'FINISHED'}
847
848     def execute(self, context):
849         BlenderFake.forceUpdate()
850         cc = context.scene.cursor_control
851         obj = bpy.context.active_object
852         if obj.data.total_vert_sel==0:
853             if hasattr(context.scene, "cursor_memory"):
854                 cm = context.scene.cursor_memory
855                 
856                 mesh = obj.data.vertices
857                 mat = obj.matrix_world
858                 mati = mat.copy()
859                 mati.invert()
860                 c = mati*Vector(CursorAccess.getCursor())
861                 
862                 v0 = Vector(cm.savedLocation)
863                 v1 = Vector(c)
864                 cc.deltaVector = v0-v1
865                 
866                 
867         if obj.data.total_vert_sel==1:
868             mesh = obj.data.vertices
869             mat = obj.matrix_world
870             mati = mat.copy()
871             mati.invert()
872             c = mati*Vector(CursorAccess.getCursor())
873
874             sf = [f for f in obj.data.vertices if f.select == 1]
875             v0 = Vector(sf[0].co)
876             v1 = Vector(c)
877             cc.deltaVector = v0-v1
878
879         if obj.data.total_vert_sel==2:
880             #mesh = obj.data.vertices
881             #mat = obj.matrix_world
882             #mati = mat.copy()
883             #mati.invert()
884             #c = mati*Vector(CursorAccess.getCursor())
885
886             sf = [f for f in obj.data.vertices if f.select == 1]
887             v0 = Vector(sf[0].co)
888             v1 = Vector(sf[1].co)
889             cc.deltaVector = v1-v0
890
891         return {'FINISHED'}
892
893
894
895