Update for API change: scene.cursor_location -> scene.cursor.location
[blender-addons-contrib.git] / np_station / np_roto_move.py
1
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 bl_info = {
22     'name': 'NP 020 Roto Move',
23     'author': 'Okavango & the Blenderartists community',
24     'version': (0, 2, 0),
25     'blender': (2, 75, 0),
26     'location': 'View3D',
27     'warning': '',
28     'description': 'Rotates selected objects using snap points',
29     'wiki_url': '',
30     'category': '3D View'}
31
32 import bpy
33 import copy
34 import bgl
35 import blf
36 import mathutils
37 from mathutils import *
38 from math import *
39 #from math import sin, cos, tan, atan, degrees, radians, asin, acos
40 from bpy_extras import view3d_utils
41 from bpy.app.handlers import persistent
42
43 from .utils_geometry import *
44 from .utils_graphics import *
45 from .utils_function import *
46
47 # Defining the main class - the macro:
48
49 class NP020RotoMove(bpy.types.Macro):
50     bl_idname = 'object.np_020_roto_move'
51     bl_label = 'NP 020 Roto Move'
52     bl_options = {'UNDO'}
53
54
55 # Defining the storage class that will serve as a variable bank for exchange among the classes. Later, this bank will receive more variables with their values for safe keeping, as the program goes on:
56
57 class NP020RM:
58
59     flag = 'RUNTRANSCENTER'
60     angstep = 10
61     radius = 1
62     rdelta = 100
63
64 # Defining the scene update algorithm that will track the state of the objects during modal transforms, which is otherwise impossible:
65 '''
66 @persistent
67 def NPRM_scene_update(context):
68
69     if bpy.data.objects.is_updated:
70         region = bpy.context.region
71         rv3d = bpy.context.region_data
72         helper = NP020RM.helper
73         co = helper.location
74 '''
75 # Defining the first of the classes from the macro, that will gather the current system settings set by the user. Some of the system settings will be changed during the process, and will be restored when macro has completed.
76
77 class NPRMGetContext(bpy.types.Operator):
78     bl_idname = 'object.np_rm_get_context'
79     bl_label = 'NP RM Get Context'
80     bl_options = {'INTERNAL'}
81
82     def execute(self, context):
83         if bpy.context.selected_objects == []:
84             self.report({'WARNING'}, "Please select objects first")
85             return {'CANCELLED'}
86         NP020RM.use_snap = copy.deepcopy(bpy.context.tool_settings.use_snap)
87         NP020RM.snap_element = copy.deepcopy(bpy.context.tool_settings.snap_element)
88         NP020RM.snap_target = copy.deepcopy(bpy.context.tool_settings.snap_target)
89         NP020RM.pivot_point = copy.deepcopy(bpy.context.space_data.pivot_point)
90         NP020RM.trans_orient = copy.deepcopy(bpy.context.space_data.transform_orientation)
91         NP020RM.curloc = copy.deepcopy(bpy.context.scene.cursor.location)
92         NP020RM.acob = bpy.context.active_object
93         if bpy.context.mode == 'OBJECT':
94             NP020RM.edit_mode = 'OBJECT'
95         elif bpy.context.mode in ('EDIT_MESH', 'EDIT_CURVE', 'EDIT_SURFACE', 'EDIT_TEXT', 'EDIT_ARMATURE', 'EDIT_METABALL', 'EDIT_LATTICE'):
96             NP020RM.edit_mode = 'EDIT'
97         elif bpy.context.mode == 'POSE':
98             NP020RM.edit_mode = 'POSE'
99         elif bpy.context.mode == 'SCULPT':
100             NP020RM.edit_mode = 'SCULPT'
101         elif bpy.context.mode == 'PAINT_WEIGHT':
102             NP020RM.edit_mode = 'WEIGHT_PAINT'
103         elif bpy.context.mode == 'PAINT_TEXTURE':
104             NP020RM.edit_mode = 'TEXTURE_PAINT'
105         elif bpy.context.mode == 'PAINT_VERTEX':
106             NP020RM.edit_mode = 'VERTEX_PAINT'
107         elif bpy.context.mode == 'PARTICLE':
108             NP020RM.edit_mode = 'PARTICLE_EDIT'
109         return {'FINISHED'}
110
111
112 # Defining the operator for aquiring the list of selected objects and storing them for later re-calls:
113
114 class NPRMGetSelection(bpy.types.Operator):
115     bl_idname = 'object.np_rm_get_selection'
116     bl_label = 'NP RM Get Selection'
117     bl_options = {'INTERNAL'}
118
119     def execute(self, context):
120         # Reading and storing the selection:
121         NP020RM.selob = bpy.context.selected_objects
122         return {'FINISHED'}
123
124
125 # Defining the operator that will read the mouse position in 3D when the command is activated and store it as a location for placing the helper object under the mouse:
126
127 class NPRMGetMouseloc(bpy.types.Operator):
128     bl_idname = 'object.np_rm_get_mouseloc'
129     bl_label = 'NP RM Get Mouseloc'
130     bl_options = {'INTERNAL'}
131
132     def modal(self, context, event):
133         region = context.region
134         rv3d = context.region_data
135         co2d = ((event.mouse_region_x, event.mouse_region_y))
136         view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, co2d)
137         enterloc = view3d_utils.region_2d_to_origin_3d(region, rv3d, co2d) + view_vector*100
138         NP020RM.enterloc = copy.deepcopy(enterloc)
139         np_print('02_GetMouseloc_FINISHED', ';', 'NP020RM.flag = ', NP020RM.flag)
140         return{'FINISHED'}
141
142     def invoke(self,context,event):
143         args = (self, context)
144         context.window_manager.modal_handler_add(self)
145         np_print('02_GetMouseloc_INVOKED_FINISHED', ';', 'NP020RM.flag = ', NP020RM.flag)
146         return {'RUNNING_MODAL'}
147
148
149 # Defining the operator that will generate the helper object at the spot marked by mouse, preparing for translation:
150
151 class NPRMAddHelper(bpy.types.Operator):
152     bl_idname = 'object.np_rm_add_helper'
153     bl_label = 'NP RM Add Helper'
154     bl_options = {'INTERNAL'}
155
156     def execute(self, context):
157         np_print('03_AddHelper_START', ';', 'NP020RM.flag = ', NP020RM.flag)
158         enterloc = NP020RM.enterloc
159         bpy.ops.object.add(type = 'MESH',location = enterloc)
160         helper = bpy.context.active_object
161         helper.name = 'NP_RM_helper'
162         NP020RM.helper = helper
163         np_print('03_AddHelper_FINISHED', ';', 'NP020RM.flag = ', NP020RM.flag)
164         return{'FINISHED'}
165
166
167 # Defining the operator that will change some of the system settings and prepare objects for the operation:
168
169 class NPRMPrepareContext(bpy.types.Operator):
170     bl_idname = 'object.np_rm_prepare_context'
171     bl_label = 'NP RM Prepare Context'
172     bl_options = {'INTERNAL'}
173
174     def execute(self, context):
175         selob = NP020RM.selob
176         helper = NP020RM.helper
177         flag = NP020RM.flag
178         if flag == 'RUNROTEND':
179             proj_start = NP020RM.proj_start
180             ndef = NP020RM.ndef
181             helper.location = copy.deepcopy(NP020RM.startloc)
182             centerloc = NP020RM.centerloc
183             v1 = helper.location
184             v2 = helper.location + Vector ((0.0, 0.0, 1.0))
185             v3 = helper.location + ndef
186             rot_axis = geometry.normal(v1, v2, v3)
187             rot_ang = Vector ((0.0, 0.0, 1.0)).angle(ndef)
188             np_print('rot_axis, rot_ang =', rot_axis, degrees(rot_ang))
189             bpy.ops.object.select_all(action = 'DESELECT')
190             helper.select_set(True)
191             bpy.ops.transform.rotate(value = rot_ang ,axis = rot_axis)
192             bpy.ops.transform.create_orientation(use = True)
193             #bpy.ops.transform.rotate(value = -rot_ang ,axis = rot_axis)
194             for ob in selob:
195                 ob.select_set(True)
196             bpy.context.view_layer.objects.active = helper
197             bpy.context.tool_settings.use_snap = False
198             bpy.context.tool_settings.snap_element = 'VERTEX'
199             bpy.context.tool_settings.snap_target = 'ACTIVE'
200             bpy.context.space_data.pivot_point = 'CURSOR'
201             #bpy.context.space_data.transform_orientation = 'GLOBAL'
202             bpy.context.scene.cursor.location = centerloc
203         else:
204             for ob in selob:
205                 ob.select_set(False)
206             helper.select_set(True)
207             bpy.context.view_layer.objects.active = helper
208             bpy.context.tool_settings.use_snap = False
209             bpy.context.tool_settings.snap_element = 'VERTEX'
210             bpy.context.tool_settings.snap_target = 'ACTIVE'
211             bpy.context.space_data.pivot_point = 'ACTIVE_ELEMENT'
212             bpy.context.space_data.transform_orientation = 'GLOBAL'
213             NP020RM.centerloc = None
214             NP020RM.qdef = None
215             NP020RM.ndef = Vector((0.0, 0.0, 1.0))
216             NP020RM.alpha_0 = 90
217             NP020RM.alpha_1 = 90
218         return{'FINISHED'}
219
220
221 # Defining the operator that will let the user translate the helper to the desired point. It also uses some listening operators that clean up the leftovers should the user interrupt the command. Many thanks to CoDEmanX and lukas_t:
222
223 class NPRMRunTranslate(bpy.types.Operator):
224     bl_idname = 'object.np_rm_run_translate'
225     bl_label = 'NP RM Run Translate'
226     bl_options = {'INTERNAL'}
227
228     if NP020RM.flag == 'RUNTRANSCENTER': np_print('04_RunTrans_START',';','NP020RM.flag = ', NP020RM.flag)
229     elif NP020RM.flag == 'RUNTRANSSTART': np_print('06_RunTrans_START',';','NP020RM.flag = ', NP020RM.flag)
230     count = 0
231
232     def modal(self, context, event):
233         context.area.tag_redraw()
234         selob = NP020RM.selob
235         helper = NP020RM.helper
236         flag = NP020RM.flag
237         self.count += 1
238
239         if self.count == 1:
240             if flag == 'RUNTRANSCENTER': np_print('04_RunTrans_START',';','NP020RM.flag = ', NP020RM.flag)
241             elif flag == 'RUNTRANSSTART': np_print('06_RunTrans_START',';','NP020RM.flag = ', NP020RM.flag)
242
243         if event.type == 'MOUSEMOVE':
244             self.co2d = ((event.mouse_region_x, event.mouse_region_y))
245             if flag == 'RUNTRANSCENTER': np_print('04_RunTrans_mousemove',';','NP020RM.flag = ', NP020RM.flag)
246             elif flag == 'RUNTRANSSTART': np_print('06_RunTrans_mousemove',';','NP020RM.flag = ', NP020RM.flag)
247
248         elif event.type in ('LEFTMOUSE', 'RET', 'NUMPAD_ENTER', 'SPACE') and event.value == 'RELEASE':
249             bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
250             self.co2d = ((event.mouse_region_x, event.mouse_region_y))
251             if flag == 'RUNTRANSCENTER':
252                 NP020RM.centerloc = copy.deepcopy(helper.location)
253                 helper.hide = True
254                 NP020RM.flag = 'BGLPLANE'
255             elif flag == 'RUNTRANSSTART':
256                 NP020RM.startloc = copy.deepcopy(helper.location)
257                 NP020RM.alpha_0_def = copy.deepcopy(NP020RM.alpha_0)
258                 NP020RM.flag = 'RUNROTEND'
259             np_print('04_RunTrans_left_enter_FINISHED',';','NP020RM.flag = ', NP020RM.flag)
260             return{'FINISHED'}
261
262         elif event.type in ('ESC', 'RIGHTMOUSE'):
263             bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
264             NP020RM.flag = 'EXIT'
265             np_print('04_RunTrans_esc_right_FINISHED',';','NP020RM.flag = ', NP020RM.flag)
266             return{'FINISHED'}
267
268         np_print('04_RunTrans_count_PASS_THROUGH',';','NP020RM.flag = ', NP020RM.flag)
269         return{'PASS_THROUGH'}
270
271     def invoke(self, context, event):
272         np_print('04_RunTrans_INVOKE_START')
273         helper = NP020RM.helper
274         flag = NP020RM.flag
275         selob = NP020RM.selob
276
277         if context.area.type == 'VIEW_3D':
278             if flag in ('RUNTRANSCENTER', 'RUNTRANSSTART'):
279                 self.co2d = ((event.mouse_region_x, event.mouse_region_y))
280                 args = (self, context)
281                 self._handle = bpy.types.SpaceView3D.draw_handler_add(DRAW_Overlay, args, 'WINDOW', 'POST_PIXEL')
282                 context.window_manager.modal_handler_add(self)
283                 bpy.ops.transform.translate('INVOKE_DEFAULT')
284                 np_print('04_RunTrans_INVOKED_RUNNING_MODAL',';','NP020RM.flag = ', NP020RM.flag)
285                 return {'RUNNING_MODAL'}
286             else:
287                 np_print('04_RunTrans_INVOKE_DECLINED_wrong_flag_FINISHED',';','NP020RM.flag = ', NP020RM.flag)
288                 return {'FINISHED'}
289         else:
290             self.report({'WARNING'}, "View3D not found, cannot run operator")
291             NP020RM.flag = 'EXIT'
292             np_print('04_RunTrans_INVOKE_DECLINED_no_VIEW_3D_FINISHED',';','NP020RM.flag = ', NP020RM.flag)
293             return {'FINISHED'}
294
295
296 # Defining the operator that will ineract with user and let him choose the plane of rotation:
297
298 class NPRMBglPlane(bpy.types.Operator):
299     bl_idname = "object.np_rm_bgl_plane"
300     bl_label = "NP RM Bgl Plane"
301     bl_options = {'INTERNAL'}
302
303     np_print('05_BglPlane_START',';','NP020RM.flag = ', NP020RM.flag)
304
305     def modal(self,context,event):
306         np_print('05_BglPlane_START',';','NP020RM.flag = ', NP020RM.flag)
307         context.area.tag_redraw()
308         flag = NP020RM.flag
309         mode = NP020RM.mode
310         plane = NP020RM.plane
311         helper = NP020RM.helper
312         centerloc = NP020RM.centerloc
313
314         if event.type == 'MOUSEMOVE':
315             self.co2d = ((event.mouse_region_x, event.mouse_region_y))
316             np_print('05_BglPlane_mousemove',';','NP020RM.flag = ', NP020RM.flag, 'NP020RM.mode = ', NP020RM.mode, 'NP020RM.plane = ', NP020RM.plane)
317
318         elif event.type in ('LEFTMOUSE', 'RIGHTMOUSE', 'RET', 'NUMPAD_ENTER'):
319             bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
320             region = context.region
321             rv3d = context.region_data
322             co2d = self.co2d
323             view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, co2d)
324             viewloc = view3d_utils.region_2d_to_origin_3d(region, rv3d, co2d)
325             away = (centerloc - viewloc).length
326             pointloc = viewloc + view_vector * away # to place the helper on centerloc to be in the vicinity of projection plane
327             helper.location = pointloc
328             helper.hide = False
329             NP020RM.qdef = copy.deepcopy(NP020RM.q)
330             NP020RM.ndef = copy.deepcopy(NP020RM.n)
331             NP020RM.plane = 'SET'
332             NP020RM.flag = 'RUNTRANSSTART'
333             np_print('05_BglPlane_lmb_FINISHED',';','NP020RM.flag = ', NP020RM.flag, 'NP020RM.mode = ', NP020RM.mode, 'NP020RM.plane = ', NP020RM.plane)
334             return{'FINISHED'}
335
336         elif event.ctrl and event.value == 'PRESS':
337             bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
338             if mode == 'FREE':
339                 NP020RM.mode = 'X'
340             elif mode == 'X':
341                 NP020RM.mode = 'Y'
342             elif mode == 'Y':
343                 NP020RM.mode = 'Z'
344             else:
345                 NP020RM.mode = 'FREE'
346             np_print('05_BglPlane_rmb_FINISHED',';','NP020RM.flag = ', NP020RM.flag, 'NP020RM.mode = ', NP020RM.mode, 'NP020RM.plane = ', NP020RM.plane)
347
348         elif event.type == 'ESC':
349             bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
350             NP020RM.flag = 'EXIT'
351             np_print('05_BglPlane_esc_FINISHED',';','NP020RM.flag = ', NP020RM.flag)
352             return{'FINISHED'}
353
354         elif event.type in {'MIDDLEMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE'}:
355             np_print('05_BglPlane_middle_wheel_any_PASS_THROUGH')
356             return {'PASS_THROUGH'}
357
358         np_print('05_BglPlane_standard_RUNNING_MODAL',';','NP020RM.flag = ', NP020RM.flag)
359         return {'RUNNING_MODAL'}
360
361     def invoke(self, context, event):
362         np_print('05_BglPlane_INVOKE_START')
363         flag = NP020RM.flag
364         NP020RM.plane = 'CHOOSE'
365         NP020RM.mode = 'FREE'
366         self.co2d = ((event.mouse_region_x, event.mouse_region_y))
367         if flag == 'BGLPLANE':
368             args = (self, context)
369             self._handle = bpy.types.SpaceView3D.draw_handler_add(DRAW_Overlay, args, 'WINDOW', 'POST_PIXEL')
370             context.window_manager.modal_handler_add(self)
371             np_print('05_BglPlane_INVOKED_RUNNING_MODAL',';','NP020RM.flag = ', NP020RM.flag)
372             return {'RUNNING_MODAL'}
373         else:
374             np_print('05_BglPlane_INVOKE_DECLINED_wrong_flag_FINISHED',';','NP020RM.flag = ', NP020RM.flag)
375             return {'FINISHED'}
376
377
378 # Defining the operator that will let the user rotate the selection with the helper to the desired point. It also uses some listening operators that clean up the leftovers should the user interrupt the command. Many thanks to CoDEmanX and lukas_t:
379
380 class NPRMRunRotate(bpy.types.Operator):
381     bl_idname = 'object.np_rm_run_rotate'
382     bl_label = 'NP RM Run Rotate'
383     bl_options = {'INTERNAL'}
384
385
386     np_print('07_RunRotate_START',';','NP020RM.flag = ', NP020RM.flag)
387
388
389     def modal(self, context, event):
390         context.area.tag_redraw()
391         selob = NP020RM.selob
392         helper = NP020RM.helper
393         flag = NP020RM.flag
394
395
396         if event.type == 'MOUSEMOVE':
397             self.co2d = ((event.mouse_region_x, event.mouse_region_y))
398             if flag == 'RUNTRANSCENTER': np_print('04_RunTrans_mousemove',';','NP020RM.flag = ', NP020RM.flag)
399             elif flag == 'RUNTRANSSTART': np_print('06_RunTrans_mousemove',';','NP020RM.flag = ', NP020RM.flag)
400
401         elif event.type in ('LEFTMOUSE', 'RET', 'NUMPAD_ENTER', 'SPACE') and event.value == 'RELEASE':
402             bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
403             self.co2d = ((event.mouse_region_x, event.mouse_region_y))
404             NP020RM.flag = 'EXIT'
405             bpy.ops.transform.delete_orientation()
406             np_print('04_RunTrans_left_enter_FINISHED',';','NP020RM.flag = ', NP020RM.flag)
407             return{'FINISHED'}
408
409         elif event.type in ('ESC', 'RIGHTMOUSE'):
410             bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
411             bpy.ops.transform.delete_orientation()
412             NP020RM.flag = 'EXIT'
413             np_print('04_RunTrans_esc_right_FINISHED',';','NP020RM.flag = ', NP020RM.flag)
414             return{'FINISHED'}
415
416         np_print('04_RunTrans_count_PASS_THROUGH',';','NP020RM.flag = ', NP020RM.flag)
417         return{'PASS_THROUGH'}
418
419     def invoke(self, context, event):
420         np_print('07_RunRotate_INVOKE_START')
421         helper = NP020RM.helper
422         flag = NP020RM.flag
423         selob = NP020RM.selob
424         ndef = NP020RM.ndef
425
426
427         if context.area.type == 'VIEW_3D':
428             if flag == 'RUNROTEND':
429                 self.co2d = ((event.mouse_region_x, event.mouse_region_y))
430                 args = (self, context)
431                 self._handle = bpy.types.SpaceView3D.draw_handler_add(DRAW_Overlay, args, 'WINDOW', 'POST_PIXEL')
432                 context.window_manager.modal_handler_add(self)
433                 NP020RM.rot_helper_0 = copy.deepcopy(helper.rotation_euler)
434                 bpy.ops.transform.rotate('INVOKE_DEFAULT', constraint_axis=(False, False, True))
435
436                 np_print('04_RunTrans_INVOKED_RUNNING_MODAL',';','NP020RM.flag = ', NP020RM.flag)
437                 return {'RUNNING_MODAL'}
438             else:
439                 np_print('04_RunTrans_INVOKE_DECLINED_wrong_flag_FINISHED',';','NP020RM.flag = ', NP020RM.flag)
440                 return {'FINISHED'}
441         else:
442             self.report({'WARNING'}, "View3D not found, cannot run operator")
443             NP020RM.flag = 'EXIT'
444             np_print('04_RunTrans_INVOKE_DECLINED_no_VIEW_3D_FINISHED',';','NP020RM.flag = ', NP020RM.flag)
445             return {'FINISHED'}
446
447 # Defining the set of instructions that will draw the OpenGL elements on the screen during the execution of RunTranslate operator:
448
449 def DRAW_Overlay(self, context):
450
451     np_print('DRAW_Overlay_START',';','NP020RM.flag = ', NP020RM.flag)
452
453     flag = NP020RM.flag
454     helper = NP020RM.helper
455     angstep = NP020RM.angstep
456     region = bpy.context.region
457     rv3d = bpy.context.region_data
458     rw = region.width
459     rh = region.height
460     if NP020RM.centerloc == None: centerloc = helper.location
461     else: centerloc = NP020RM.centerloc
462     qdef = NP020RM.qdef
463     ndef = NP020RM.ndef
464     alpha_0 = NP020RM.alpha_0
465     alpha_1 = NP020RM.alpha_1
466     np_print('rw, rh', rw, rh)
467     rmin = int(min(rw, rh) / 10)
468     if rmin == 0: rmin = 1
469     co2d = self.co2d
470     if flag in ('RUNTRANSCENTER', 'RUNTRANSSTART'): co2d = view3d_utils.location_3d_to_region_2d(region, rv3d, helper.location)
471     if qdef == None:
472         q = get_ro_normal_from_vertical(region, rv3d, co2d)[1]
473         n = get_ro_normal_from_vertical(region, rv3d, co2d)[0]
474     else:
475         q = qdef
476         n = ndef
477     NP020RM.q = q
478     NP020RM.n = n
479     #co2d_exp = (event.mouse_region_x, event.mouse_region_y)
480     #n_exp = get_ro_normal_from_vertical(region, rv3d, co2d_exp)[0]
481     #np_print('co2d, n, q, n_exp', co2d, n, q)
482
483     # writing the dots for circle at center of scene:
484     radius = 1
485     ang = 0.0
486     circle = [(0.0 ,0.0 ,0.0)]
487     while ang < 360.0:
488         circle.append(((cos(radians(ang)) * radius), (sin(radians(ang)) * radius), (0.0)))
489         ang += 10
490     circle.append(((cos(radians(0.0)) * radius), (sin(radians(0.0)) * radius), (0.0)))
491
492     # rotating and translating the circle to user picked angle and place:
493     circle = rotate_graphic(circle, q)
494     circle = translate_graphic(circle, centerloc)
495
496     rmax = 1
497     for i, co in enumerate(circle):
498         co = view3d_utils.location_3d_to_region_2d(region, rv3d, co)
499         circle[i] = co
500     for i in range(1, 18):
501         r = (circle[0] - circle[i]).length
502         r1 = (circle[0] - circle[i + 18]).length
503         #if (r + r1) > rmax and abs(r - r1) < min(r, r1)/5: rmax = (r+r1)/2
504         #if (r + r1) > rmax and abs(r - r1) < min(r, r1)/10: rmax = r + r1
505         if (r + r1) > rmax and (r + r1) / 2 < rmin: rmax = (r + r1)
506         elif (r + r1) > rmax and (r + r1) / 2 >= rmin: rmax = (r + r1) * rmin / (((r + r1) / 2)- ((r + r1) / 2) - rmin)
507         rmax = abs(rmax)
508         circle[i] = co
509     np_print('rmin', rmin)
510     np_print('rmax', rmax)
511     if flag not in ('RUNTRANSSTART', 'RUNROTEND'):
512         fac = (rmin * 2) / rmax
513         NP020RM.fac = fac
514     else: fac = NP020RM.fac
515
516     radius = 1 * fac
517     ang = 0.0
518     circle = [(0.0 ,0.0 ,0.0)]
519     while ang < 360.0:
520         circle.append(((cos(radians(ang)) * radius), (sin(radians(ang)) * radius), (0.0)))
521         ang += 10
522     circle.append(((cos(radians(0.0)) * radius), (sin(radians(0.0)) * radius), (0.0)))
523
524
525     if flag == 'RUNTRANSCENTER':
526         instruct = 'place center point'
527         keys_aff = 'LMB / ENT / NUMPAD ENT - confirm, CTRL - snap'
528         keys_nav = ''
529         keys_neg = 'ESC - quit'
530
531         r1 = 1
532         r2 = 1.5
533         walpha = construct_roto_widget(alpha_0, alpha_1, fac, r1, r2, angstep)
534
535         r1 = 1.5
536         r2 = 2
537         wbeta_L = construct_roto_widget(90, 0, fac, r1, r2, angstep)
538
539         r1 = 1.5
540         r2 = 2
541         wbeta_D = construct_roto_widget(0, 90, fac, r1, r2, angstep)
542
543     elif flag == 'BGLPLANE':
544         instruct = 'choose rotation plane'
545         keys_aff = 'LMB / ENT / NUMPAD ENT - confirm'
546         keys_nav = 'MMB / SCROLL - navigate'
547         keys_neg = 'ESC - quit'
548
549         ro_hor, isohipse = get_ro_x_from_iso(region, rv3d, co2d, centerloc)
550         NP020RM.ro_hor = copy.deepcopy(ro_hor)
551         bgl.glEnable(bgl.GL_BLEND)
552         bgl.glColor4f(1.0, 0.0, 0.0, 1.0)
553         bgl.glLineWidth(2)
554         bgl.glBegin(bgl.GL_LINE_STRIP)
555         for co in isohipse:
556             co = view3d_utils.location_3d_to_region_2d(region, rv3d, co)
557             bgl.glVertex2f(*co)
558         bgl.glEnd()
559
560         bgl.glEnable(bgl.GL_POINT_SMOOTH)
561         bgl.glPointSize(4)
562         bgl.glBegin(bgl.GL_POINTS)
563         for co in isohipse:
564             co = view3d_utils.location_3d_to_region_2d(region, rv3d, co)
565             bgl.glVertex2f(*co)
566         bgl.glEnd()
567
568         r1 = 1
569         r2 = 1.5
570         walpha = construct_roto_widget(alpha_0, alpha_1, fac, r1, r2, angstep)
571
572         r1 = 1.5
573         r2 = 2
574         wbeta_L = construct_roto_widget(90, 0, fac, r1, r2, angstep)
575
576         r1 = 1.5
577         r2 = 2
578         wbeta_D = construct_roto_widget(0, 90, fac, r1, r2, angstep)
579
580         circle = rotate_graphic(circle, ro_hor)
581         walpha = rotate_graphic(walpha, ro_hor)
582         wbeta_L = rotate_graphic(wbeta_L, ro_hor)
583         wbeta_D = rotate_graphic(wbeta_D, ro_hor)
584
585         circle = rotate_graphic(circle, q)
586         walpha = rotate_graphic(walpha, q)
587         wbeta_L = rotate_graphic(wbeta_L, q)
588         wbeta_D = rotate_graphic(wbeta_D, q)
589
590
591     elif flag == 'RUNTRANSSTART':
592         instruct = 'place start point'
593         keys_aff = 'LMB / ENT / NUMPAD ENT - confirm, CTRL - snap'
594         keys_nav = ''
595         keys_neg = 'ESC - quit'
596
597         hloc = helper.location
598         #np_print('hloc', hloc)
599         hlocb = hloc + n
600         #np_print('hlocb', hlocb)
601         #np_print('centerloc, n', centerloc, n)
602         proj_start = mathutils.geometry.intersect_line_plane(helper.location, (helper.location + n), centerloc, n)
603         NP020RM.proj_start = proj_start
604         if proj_start == centerloc: proj = centerloc + Vector((0.0, 0.0, 0.001))
605         #np_print('proj_start' , proj_start)
606
607         alpha_0, isohipse = get_angle_from_iso_planar(centerloc, n, proj_start)
608         alpha_1 = alpha_0
609         NP020RM.alpha_0 = alpha_0
610         NP020RM.alpha_1 = alpha_1
611         np_print('alpha_0', alpha_0)
612
613         ro_hor = NP020RM.ro_hor
614
615         bgl.glEnable(bgl.GL_BLEND)
616         bgl.glColor4f(1.0, 0.0, 0.0, 1.0)
617         bgl.glLineWidth(2)
618         bgl.glBegin(bgl.GL_LINE_STRIP)
619         for co in isohipse:
620             co = view3d_utils.location_3d_to_region_2d(region, rv3d, co)
621             bgl.glVertex2f(*co)
622         bgl.glEnd()
623
624         bgl.glEnable(bgl.GL_POINT_SMOOTH)
625         bgl.glPointSize(4)
626         bgl.glBegin(bgl.GL_POINTS)
627         for co in isohipse:
628             co = view3d_utils.location_3d_to_region_2d(region, rv3d, co)
629             bgl.glVertex2f(*co)
630         bgl.glEnd()
631
632         r1 = 1
633         r2 = 1.5
634         walpha = construct_roto_widget(alpha_0, alpha_1, fac, r1, r2, angstep)
635
636         r1 = 1.5
637         r2 = 2
638         wbeta_L = construct_roto_widget(alpha_1, 0, fac, r1, r2, angstep)
639
640         r1 = 1.5
641         r2 = 2
642         wbeta_D = construct_roto_widget(0, alpha_0, fac, r1, r2, angstep)
643
644
645         circle = rotate_graphic(circle, ro_hor)
646         walpha = rotate_graphic(walpha, ro_hor)
647         wbeta_L = rotate_graphic(wbeta_L, ro_hor)
648         wbeta_D = rotate_graphic(wbeta_D, ro_hor)
649
650         circle = rotate_graphic(circle, q)
651         walpha = rotate_graphic(walpha, q)
652         wbeta_L = rotate_graphic(wbeta_L, q)
653         wbeta_D = rotate_graphic(wbeta_D, q)
654
655         bgl.glEnable(bgl.GL_BLEND)
656         bgl.glColor4f(0.5, 0.5, 1.0, 1.0)
657         bgl.glLineWidth(1)
658         bgl.glBegin(bgl.GL_LINE_STRIP)
659         points = (helper.location, proj_start, centerloc)
660         for co in points:
661             co = view3d_utils.location_3d_to_region_2d(region, rv3d, co)
662             bgl.glVertex2f(*co)
663         bgl.glEnd()
664
665         co = view3d_utils.location_3d_to_region_2d(region, rv3d, proj_start)
666         bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
667         bgl.glEnable(bgl.GL_POINT_SMOOTH)
668         bgl.glPointSize(14)
669         bgl.glEnable(bgl.GL_BLEND)
670         bgl.glBegin(bgl.GL_POINTS)
671         bgl.glVertex2f(*co)
672         bgl.glEnd()
673
674
675     elif flag == 'RUNROTEND':
676         instruct = 'place end point'
677         keys_aff = 'LMB / ENT / NUMPAD ENT - confirm, CTRL - snap'
678         keys_nav = ''
679         keys_neg = 'ESC - quit'
680         for k, v in bpy.context.active_operator.properties.items():
681             np_print(k, v)
682         alpha_0 = NP020RM.alpha_0_def
683         hloc = helper.location
684         startloc = NP020RM.startloc
685         endloc = helper.location
686         proj_start = NP020RM.proj_start
687         #np_print('hloc', hloc)
688         hlocb = hloc + n
689         #np_print('hlocb', hlocb)
690         #np_print('centerloc, n', centerloc, n)
691         proj_end = mathutils.geometry.intersect_line_plane(helper.location, (helper.location + n), centerloc, n)
692         if proj_end == centerloc: proj_end = centerloc + Vector((0.0, 0.0, 0.001))
693         #np_print('proj_end' , proj_end)
694
695         alpha = get_angle_vector_from_vector(centerloc, proj_start, proj_end)
696         alpha_1 = alpha_0 + alpha
697         np_print('alpha_0', alpha_0)
698
699         ro_hor = NP020RM.ro_hor
700
701         rot_helper_0 = NP020RM.rot_helper_0
702         np_print('rot_helper_0 =', rot_helper_0)
703         rot_helper_1 = helper.rotation_euler
704         np_print('rot_helper_1 =', rot_helper_1)
705         alpha_real = get_eul_z_angle_diffffff_in_rotated_system(rot_helper_0, rot_helper_1, ndef)
706         np_print('alpha_real =', alpha_real)
707
708
709         delta = (abs(alpha_real) - (360 * int(abs(alpha_real) / 360 )))
710         if alpha_real >= 0:
711             if alpha_0 + delta < 360: alpha_1 = alpha_0 + delta
712             else: alpha_1 = delta - (360 - alpha_0)
713         else:
714             if delta < alpha_0:
715                 alpha_1 = alpha_0
716                 alpha_0 = alpha_1 - delta
717             else:
718                 alpha_1 = alpha_0
719                 alpha_0 = 360 - (delta - alpha_0)
720
721         if alpha_1 == alpha_0: alpha_1 = alpha_0 + 0.001
722         r1 = 1
723         r2 = 1.5
724         walpha = construct_roto_widget(alpha_0, alpha_1, fac, r1, r2, angstep)
725
726         r1 = 1.5
727         r2 = 2
728         wbeta_L = construct_roto_widget(alpha_1, alpha_0, fac, r1, r2, angstep)
729         '''
730         r1 = 1.5
731         r2 = 2
732         wbeta_D = construct_roto_widget(0, alpha_0, fac, r1, r2, angstep)
733         '''
734
735         circle = rotate_graphic(circle, ro_hor)
736         walpha = rotate_graphic(walpha, ro_hor)
737         wbeta_L = rotate_graphic(wbeta_L, ro_hor)
738         #wbeta_D = rotate_graphic(wbeta_D, ro_hor)
739
740         circle = rotate_graphic(circle, q)
741         walpha = rotate_graphic(walpha, q)
742         wbeta_L = rotate_graphic(wbeta_L, q)
743         #wbeta_D = rotate_graphic(wbeta_D, q)
744
745         bgl.glEnable(bgl.GL_BLEND)
746         bgl.glColor4f(0.5, 0.5, 1.0, 1.0)
747         bgl.glLineWidth(1)
748         bgl.glBegin(bgl.GL_LINE_STRIP)
749         points = (helper.location, proj_end, centerloc, proj_start)
750         for co in points:
751             co = view3d_utils.location_3d_to_region_2d(region, rv3d, co)
752             bgl.glVertex2f(*co)
753         bgl.glEnd()
754
755         co = view3d_utils.location_3d_to_region_2d(region, rv3d, proj_end)
756         bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
757         bgl.glEnable(bgl.GL_POINT_SMOOTH)
758         bgl.glPointSize(14)
759         bgl.glEnable(bgl.GL_BLEND)
760         bgl.glBegin(bgl.GL_POINTS)
761         bgl.glVertex2f(*co)
762         bgl.glEnd()
763
764
765
766
767
768         # NUMERICAL ANGLE:
769
770         bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
771         font_id = 0
772         blf.size(font_id, 20, 72)
773         ang_pos = view3d_utils.location_3d_to_region_2d(region, rv3d, centerloc)
774         blf.position(font_id, ang_pos[0]+2, ang_pos[1]-2, 0)
775         blf.draw(font_id, str(round(alpha_real,2)))
776         bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
777         blf.position(font_id, ang_pos[0], ang_pos[1], 0)
778         blf.draw(font_id, str(round(alpha_real,2)))
779
780
781
782
783     # DRAWING START:
784     bgl.glEnable(bgl.GL_BLEND)
785
786
787     # ON-SCREEN INSTRUCTIONS:
788
789     display_instructions(region, rv3d, instruct, keys_aff, keys_nav, keys_neg)
790
791
792     np_print('centerloc', centerloc)
793     circle = translate_graphic(circle, centerloc)
794
795     walpha = translate_graphic(walpha, centerloc)
796     wbeta_L = translate_graphic(wbeta_L, centerloc)
797     if flag is not 'RUNROTEND': wbeta_D = translate_graphic(wbeta_D, centerloc)
798
799
800     np_print('rv3d', rv3d)
801     bgl.glEnable(bgl.GL_BLEND)
802     bgl.glColor4f(1.0, 1.0, 1.0, 0.6)
803     bgl.glLineWidth(1)
804     bgl.glBegin(bgl.GL_LINE_STRIP)
805     for i, co in enumerate(circle):
806         co = view3d_utils.location_3d_to_region_2d(region, rv3d, co)
807         bgl.glVertex2f(*co)
808         circle[i] = co
809     bgl.glEnd()
810     np_print('centerloc', centerloc)
811
812
813     # drawing of walpha contours:
814     bgl.glColor4f(1.0, 1.0, 1.0, 0.6)
815     bgl.glLineWidth(1)
816     bgl.glBegin(bgl.GL_LINE_STRIP)
817     for i, co in enumerate(walpha):
818         co = view3d_utils.location_3d_to_region_2d(region, rv3d, co)
819         bgl.glVertex2f(*co)
820         walpha[i] = co
821     bgl.glEnd()
822     #np_print('walpha', walpha)
823     bgl.glColor4f(0.0, 0.0, 0.0, 0.5)
824
825     # drawing of walpha fields:
826     np_print('alpha_0, alpha_1 =', alpha_0, alpha_1)
827     if alpha_1 >= alpha_0: alpha = alpha_1 - alpha_0
828     else: alpha = alpha_1 + (360 - alpha_0)
829     sides = int(alpha / NP020RM.angstep) + 1
830     bgl.glBegin(bgl.GL_TRIANGLE_FAN)
831     bgl.glVertex2f(*walpha[0])
832     bgl.glVertex2f(*walpha[1])
833     bgl.glVertex2f(*walpha[2])
834     bgl.glVertex2f(*walpha[(sides * 2) + 1])
835     bgl.glEnd()
836     for i in range(1, sides):
837         bgl.glBegin(bgl.GL_TRIANGLE_FAN)
838         bgl.glVertex2f(*walpha[((sides * 2) + 2) - i])
839         bgl.glVertex2f(*walpha[i + 1])
840         bgl.glVertex2f(*walpha[2 + i])
841         bgl.glVertex2f(*walpha[((sides * 2) + 2) - (i + 1)])
842         bgl.glEnd()
843
844     # drawing of wbeta_L contours:
845     bgl.glColor4f(1.0, 1.0, 1.0, 0.6)
846     bgl.glLineWidth(1)
847     bgl.glBegin(bgl.GL_LINE_STRIP)
848     for i, co in enumerate(wbeta_L):
849         co = view3d_utils.location_3d_to_region_2d(region, rv3d, co)
850         bgl.glVertex2f(*co)
851         wbeta_L[i] = co
852     bgl.glEnd()
853     #np_print('wbeta_L', wbeta_L)
854     bgl.glColor4f(0.65, 0.85, 1.0, 0.35)
855
856     # drawing of wbeta_L fields:
857     if flag == 'RUNROTEND':
858         if alpha_0 >= alpha_1: alpha = alpha_0 - alpha_1
859         else: alpha = alpha_0 + (360 - alpha_1)
860     else: alpha = 360 - alpha_1
861     sides = int(alpha / NP020RM.angstep) + 1
862     bgl.glBegin(bgl.GL_TRIANGLE_FAN)
863     bgl.glVertex2f(*wbeta_L[0])
864     bgl.glVertex2f(*wbeta_L[1])
865     bgl.glVertex2f(*wbeta_L[2])
866     bgl.glVertex2f(*wbeta_L[(sides * 2) + 1])
867     bgl.glEnd()
868     for i in range(1, sides):
869         bgl.glBegin(bgl.GL_TRIANGLE_FAN)
870         bgl.glVertex2f(*wbeta_L[((sides * 2) + 2) - i])
871         bgl.glVertex2f(*wbeta_L[i + 1])
872         bgl.glVertex2f(*wbeta_L[2 + i])
873         bgl.glVertex2f(*wbeta_L[((sides * 2) + 2) - (i + 1)])
874         bgl.glEnd()
875
876
877     if flag is not 'RUNROTEND':
878         # drawing of wbeta_D contours:
879         bgl.glColor4f(1.0, 1.0, 1.0, 0.6)
880         bgl.glLineWidth(1)
881         bgl.glBegin(bgl.GL_LINE_STRIP)
882         for i, co in enumerate(wbeta_D):
883             co = view3d_utils.location_3d_to_region_2d(region, rv3d, co)
884             bgl.glVertex2f(*co)
885             wbeta_D[i] = co
886         bgl.glEnd()
887         #np_print('wbeta_D', wbeta_D)
888         bgl.glColor4f(0.35, 0.6, 0.75, 0.35)
889
890         # drawing of wbeta_D fields:
891
892         alpha = alpha_0
893         sides = int(alpha / NP020RM.angstep) + 1
894         bgl.glBegin(bgl.GL_TRIANGLE_FAN)
895         bgl.glVertex2f(*wbeta_D[0])
896         bgl.glVertex2f(*wbeta_D[1])
897         bgl.glVertex2f(*wbeta_D[2])
898         bgl.glVertex2f(*wbeta_D[(sides * 2) + 1])
899         bgl.glEnd()
900         for i in range(1, sides):
901             bgl.glBegin(bgl.GL_TRIANGLE_FAN)
902             bgl.glVertex2f(*wbeta_D[((sides * 2) + 2) - i])
903             bgl.glVertex2f(*wbeta_D[i + 1])
904             bgl.glVertex2f(*wbeta_D[2 + i])
905             bgl.glVertex2f(*wbeta_D[((sides * 2) + 2) - (i + 1)])
906             bgl.glEnd()
907
908     #ENDING
909
910     bgl.glLineWidth(1)
911     bgl.glDisable(bgl.GL_BLEND)
912     bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
913
914
915 # Restoring the object selection and system settings from before the operator activation:
916
917 class NPRMRestoreContext(bpy.types.Operator):
918     bl_idname = "object.np_rm_restore_context"
919     bl_label = "NP RM Restore Context"
920     bl_options = {'INTERNAL'}
921
922     def execute(self, context):
923         selob = NP020RM.selob
924         helper = NP020RM.helper
925         helper.hide = False
926         bpy.ops.object.select_all(action = 'DESELECT')
927         helper.select_set(True)
928         bpy.ops.object.delete('EXEC_DEFAULT')
929         for ob in selob:
930             ob.select_set(True)
931
932         bpy.context.tool_settings.use_snap = NP020RM.use_snap
933         bpy.context.tool_settings.snap_element = NP020RM.snap_element
934         bpy.context.tool_settings.snap_target = NP020RM.snap_target
935         bpy.context.space_data.pivot_point = NP020RM.pivot_point
936         bpy.context.space_data.transform_orientation = NP020RM.trans_orient
937         bpy.context.scene.cursor.location = NP020RM.curloc
938         if NP020RM.acob is not None:
939             bpy.context.view_layer.objects.active = NP020RM.acob
940             bpy.ops.object.mode_set(mode = NP020RM.edit_mode)
941         NP020RM.flag = 'RUNTRANSCENTER'
942         return {'FINISHED'}
943
944
945 # This is the actual addon process, the algorithm that defines the order of operator activation inside the main macro:
946
947 def register():
948
949     #bpy.app.handlers.scene_update_post.append(NPRM_scene_update)
950
951     NP020RotoMove.define('OBJECT_OT_np_rm_get_context')
952     NP020RotoMove.define('OBJECT_OT_np_rm_get_selection')
953     NP020RotoMove.define('OBJECT_OT_np_rm_get_mouseloc')
954     NP020RotoMove.define('OBJECT_OT_np_rm_add_helper')
955     NP020RotoMove.define('OBJECT_OT_np_rm_prepare_context')
956     NP020RotoMove.define('OBJECT_OT_np_rm_run_translate')
957     NP020RotoMove.define('OBJECT_OT_np_rm_bgl_plane')
958     NP020RotoMove.define('OBJECT_OT_np_rm_run_translate')
959     NP020RotoMove.define('OBJECT_OT_np_rm_prepare_context')
960     NP020RotoMove.define('OBJECT_OT_np_rm_run_rotate')
961     NP020RotoMove.define('OBJECT_OT_np_rm_restore_context')
962
963 def unregister():
964     #bpy.app.handlers.scene_update_post.remove(NPRM_scene_update)
965     pass