Update for API change: scene.cursor_location -> scene.cursor.location
[blender-addons-contrib.git] / np_station / np_float_rectangle.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 '''
22 DESCRIPTION
23
24 Translates objects using anchor and target points.
25
26 Emulates the functionality of the standard 'rectangle' command in CAD applications, with start and end points. This way, it does pretty much what the basic 'grab' function does, only it locks the snap ability to one designated point in selected group, giving more control and precision to the user.
27
28 INSTALATION
29
30 Two ways:
31
32 A. Paste the the .py file to text editor and run (ALT+P)
33 B. Unzip and place .py file to addons_contrib. In User Preferences / Addons tab search under Testing / NP Anchor Translate and check the box.
34
35 Now you have the operator in your system. If you press Save User Preferences, you will have it at your disposal every time you run Bl.
36
37 SHORTCUTS
38
39 After succesful instalation of the addon, or it's activation from the text editor, the NP Float Rectangle operator should be registered in your system. Enter User Preferences / Input, and under that, 3DView / Object Mode. Search for definition assigned to simple M key (provided that you don't use it for placing objects into layers, instead of now almost-standard 'Layer manager' addon) and instead object.move_to_layer, type object.np_xxx_float_rectangle (xxx being the number of the version). I suggest asigning hotkey only for the Object Mode because the addon doesn't work in other modes. Also, this way the basic G command should still be available and at your disposal.
40
41 USAGE
42
43 Select one or more objects.
44 Run operator (spacebar search - NP Anchor Translate, or keystroke if you assigned it)
45 Select a point anywhere in the scene (holding CTRL enables snapping). This will be your anchor point.
46 Place objects anywhere in the scene, in relation to the anchor point (again CTRL - snap).
47 Middle mouse button (MMB) enables axis constraint, numpad keys enable numerical input of distance, and RMB and ESC key interrupt the operation.
48
49 IMPORTANT PERFORMANCE NOTES
50
51 Should be key-mapped only for Object Mode. Other modes are not supported and key definitions should not be replaced.
52
53 WISH LIST
54
55 Bgl overlay for snapping modes and eventualy the translate path
56 Blf instructions on screen, preferably interactive
57 Smarter code and faster performance
58
59 WARNINGS
60
61 None so far
62 '''
63
64 bl_info = {
65     'name': 'NP 020 Float Rectangle',
66     'author': 'Okavango & the Blenderartists community',
67     'version': (0, 2, 0),
68     'blender': (2, 75, 0),
69     'location': 'View3D',
70     'warning': '',
71     'description': 'Draws a mesh rectangle using snap points',
72     'wiki_url': '',
73     'category': '3D View'}
74
75 import bpy
76 import copy
77 import bgl
78 import blf
79 import mathutils
80 from mathutils import *
81 from math import *
82 #from math import sin, cos, tan, atan, degrees, radians, asin, acos
83 from bpy_extras import view3d_utils
84 from bpy.app.handlers import persistent
85
86 from .utils_geometry import *
87 from .utils_graphics import *
88 from .utils_function import *
89
90 # Defining the main class - the macro:
91
92 class NP020FloatRectangle(bpy.types.Macro):
93     bl_idname = 'object.np_020_float_rectangle'
94     bl_label = 'NP 020 Float Rectangle'
95     bl_options = {'UNDO'}
96
97
98 # 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:
99
100 class NP020FR:
101
102     flag = 'RUNTRANS0'
103     recob = None
104
105 # Defining the scene update algorithm that will track the state of the objects during modal transforms, which is otherwise impossible:
106 '''
107 @persistent
108 def NPFR_scene_update(context):
109
110     if bpy.data.objects.is_updated:
111         region = bpy.context.region
112         rv3d = bpy.context.region_data
113         helper = NP020FR.helper
114         co = helper.location
115 '''
116
117 # 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.
118
119 class NPFRGetContext(bpy.types.Operator):
120     bl_idname = 'object.np_fr_get_context'
121     bl_label = 'NP FR Get Context'
122     bl_options = {'INTERNAL'}
123
124     def execute(self, context):
125         NP020FR.use_snap = copy.deepcopy(bpy.context.tool_settings.use_snap)
126         NP020FR.snap_element = copy.deepcopy(bpy.context.tool_settings.snap_element)
127         NP020FR.snap_target = copy.deepcopy(bpy.context.tool_settings.snap_target)
128         NP020FR.pivot_point = copy.deepcopy(bpy.context.space_data.pivot_point)
129         NP020FR.trans_orient = copy.deepcopy(bpy.context.space_data.transform_orientation)
130         NP020FR.curloc = copy.deepcopy(bpy.context.scene.cursor.location)
131         NP020FR.acob = bpy.context.active_object
132         if bpy.context.mode == 'OBJECT':
133             NP020FR.edit_mode = 'OBJECT'
134         elif bpy.context.mode in ('EDIT_MESH', 'EDIT_CURVE', 'EDIT_SURFACE', 'EDIT_TEXT', 'EDIT_ARMATURE', 'EDIT_METABALL', 'EDIT_LATTICE'):
135             NP020FR.edit_mode = 'EDIT'
136         elif bpy.context.mode == 'POSE':
137             NP020FR.edit_mode = 'POSE'
138         elif bpy.context.mode == 'SCULPT':
139             NP020FR.edit_mode = 'SCULPT'
140         elif bpy.context.mode == 'PAINT_WEIGHT':
141             NP020FR.edit_mode = 'WEIGHT_PAINT'
142         elif bpy.context.mode == 'PAINT_TEXTURE':
143             NP020FR.edit_mode = 'TEXTURE_PAINT'
144         elif bpy.context.mode == 'PAINT_VERTEX':
145             NP020FR.edit_mode = 'VERTEX_PAINT'
146         elif bpy.context.mode == 'PARTICLE':
147             NP020FR.edit_mode = 'PARTICLE_EDIT'
148         return {'FINISHED'}
149
150
151 # Defining the operator for aquiring the list of selected objects and storing them for later re-calls:
152
153 class NPFRGetSelection(bpy.types.Operator):
154     bl_idname = 'object.np_fr_get_selection'
155     bl_label = 'NP FR Get Selection'
156     bl_options = {'INTERNAL'}
157
158     def execute(self, context):
159         # Reading and storing the selection:
160         NP020FR.selob = bpy.context.selected_objects
161         return {'FINISHED'}
162
163
164 # 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:
165
166 class NPFRGetMouseloc(bpy.types.Operator):
167     bl_idname = 'object.np_fr_get_mouseloc'
168     bl_label = 'NP FR Get Mouseloc'
169     bl_options = {'INTERNAL'}
170
171     def modal(self, context, event):
172         region = context.region
173         rv3d = context.region_data
174         co2d = ((event.mouse_region_x, event.mouse_region_y))
175         view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, co2d)
176         enterloc = view3d_utils.region_2d_to_origin_3d(region, rv3d, co2d) + view_vector*100
177         NP020FR.enterloc = copy.deepcopy(enterloc)
178         np_print('02_GetMouseloc_FINISHED', ';', 'NP020FR.flag = ', NP020FR.flag)
179         return{'FINISHED'}
180
181     def invoke(self,context,event):
182         args = (self, context)
183         context.window_manager.modal_handler_add(self)
184         np_print('02_GetMouseloc_INVOKED_FINISHED', ';', 'NP020FR.flag = ', NP020FR.flag)
185         return {'RUNNING_MODAL'}
186
187
188 # Defining the operator that will generate the helper object at the spot marked by mouse, preparing for translation:
189
190 class NPFRAddHelper(bpy.types.Operator):
191     bl_idname = 'object.np_fr_add_helper'
192     bl_label = 'NP FR Add Helper'
193     bl_options = {'INTERNAL'}
194
195     def execute(self, context):
196         np_print('03_AddHelper_START', ';', 'NP020FR.flag = ', NP020FR.flag)
197         enterloc = NP020FR.enterloc
198         bpy.ops.object.add(type = 'MESH',location = enterloc)
199         helper = bpy.context.active_object
200         helper.name = 'NP_FR_helper'
201         NP020FR.helper = helper
202         np_print('03_AddHelper_FINISHED', ';', 'NP020FR.flag = ', NP020FR.flag)
203         return{'FINISHED'}
204
205
206 # Defining the operator that will change some of the system settings and prepare objects for the operation:
207
208 class NPFRPrepareContext(bpy.types.Operator):
209     bl_idname = 'object.np_fr_prepare_context'
210     bl_label = 'NP FR Prepare Context'
211     bl_options = {'INTERNAL'}
212
213     def execute(self, context):
214
215         flag = NP020FR.flag
216         np_print('prepare, NP020FR.flag = ', flag)
217         if flag == 'RUNTRANS0':
218             helper = NP020FR.helper
219             bpy.ops.object.select_all(action = 'DESELECT')
220             helper.select_set(True)
221             bpy.context.view_layer.objects.active = helper
222             bpy.context.tool_settings.use_snap = False
223             bpy.context.tool_settings.snap_element = 'VERTEX'
224             bpy.context.tool_settings.snap_target = 'ACTIVE'
225             bpy.context.space_data.pivot_point = 'ACTIVE_ELEMENT'
226             bpy.context.space_data.transform_orientation = 'GLOBAL'
227             NP020FR.corner_brush = False
228             NP020FR.constrain = False
229             NP020FR.trans_custom = False
230             NP020FR.qdef = None
231             NP020FR.ndef = Vector((0.0, 0.0, 1.0))
232             NP020FR.ro_hor_def = 0
233
234         elif flag == 'RUNTRANS1_break':
235             NP020FR.flag = 'RUNTRANS1'
236             corner_brush = NP020FR.corner_brush
237             helper = NP020FR.helper
238             pointloc = NP020FR.pointloc
239             loc = copy.deepcopy(helper.location)
240             ndef = NP020FR.ndef
241             '''
242             matrix = NP020FR.matrix
243             np_print('matrix =' , matrix)
244             matrix_world = helper.matrix_world.to_3x3()
245             np_print('matrix_world =' , matrix_world)
246             matrix_world.rotate(matrix)
247             matrix_world.resize_4x4()
248             helper.matrix_world = matrix_world
249             helper.location = pointloc
250             bpy.ops.object.select_all(action = 'DESELECT')
251             helper.select = True
252             '''
253
254             ro_hor_def = NP020FR.ro_hor_def
255             ang_hor = ro_hor_def.to_euler()
256             ang_hor = ang_hor[2]
257             v1 = helper.location
258             v2 = helper.location + Vector ((0.0, 0.0, 1.0))
259             v3 = helper.location + ndef
260             rot_axis = Vector((1.0, 0.0, 0.0))
261             rot_axis.rotate(ro_hor_def)
262             rot_ang = Vector((0.0, 0.0, 1.0)).angle(ndef)
263             np_print('rot_axis, rot_ang =', rot_axis, rot_ang)
264
265             bpy.ops.object.select_all(action = 'DESELECT')
266             if corner_brush == False: helper.location = pointloc
267             helper.select_set(True)
268             bpy.ops.transform.rotate(value = ang_hor ,axis = Vector((0.0, 0.0, 1.0)))
269             bpy.ops.transform.rotate(value = rot_ang ,axis = rot_axis)
270             NP020FR.trans_custom = True
271             bpy.ops.transform.create_orientation(use = True)
272             bpy.context.view_layer.objects.active = helper
273             bpy.context.tool_settings.use_snap = False
274             bpy.context.tool_settings.snap_element = 'VERTEX'
275             bpy.context.tool_settings.snap_target = 'ACTIVE'
276             bpy.context.space_data.pivot_point = 'ACTIVE_ELEMENT'
277
278         elif flag == 'RUNTRANS2':
279             helper = NP020FR.helper
280             ndef = NP020FR.ndef
281             bpy.context.view_layer.objects.active = helper
282             bpy.context.tool_settings.use_snap = False
283             bpy.context.tool_settings.snap_element = 'VERTEX'
284             bpy.context.tool_settings.snap_target = 'ACTIVE'
285             bpy.context.space_data.pivot_point = 'ACTIVE_ELEMENT'
286
287         return{'FINISHED'}
288
289
290 # 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:
291
292 class NPFRRunTranslate(bpy.types.Operator):
293     bl_idname = 'object.np_fr_run_translate'
294     bl_label = 'NP FR Run Translate'
295     bl_options = {'INTERNAL'}
296
297     if NP020FR.flag == 'RUNTRANS0': np_print('04_RunTrans_START',';','NP020FR.flag = ', NP020FR.flag)
298     elif NP020FR.flag == 'RUNTRANS1': np_print('05_RunTrans_START',';','NP020FR.flag = ', NP020FR.flag)
299     elif NP020FR.flag == 'RUNTRANS2': np_print('06_RunTrans_START',';','NP020FR.flag = ', NP020FR.flag)
300
301
302     def modal(self, context, event):
303         context.area.tag_redraw()
304         flag = NP020FR.flag
305         helper = NP020FR.helper
306
307
308
309         if event.ctrl and event.type in ('LEFTMOUSE', 'NUMPAD_ENTER', 'SPACE'):
310             bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
311             self.co2d = ((event.mouse_region_x, event.mouse_region_y))
312             if flag == 'RUNTRANS0':
313                 NP020FR.p0 = copy.deepcopy(helper.location)
314                 NP020FR.ndef = copy.deepcopy(NP020FR.n)
315                 NP020FR.qdef = copy.deepcopy(NP020FR.q)
316                 NP020FR.ro_hor_def = copy.deepcopy(NP020FR.ro_hor)
317                 NP020FR.corner_brush = True
318                 NP020FR.flag = 'RUNTRANS1_break'
319             elif flag == 'RUNTRANS1':
320                 NP020FR.p1 = copy.deepcopy(helper.location)
321                 NP020FR.flag = 'RUNTRANS2'
322             elif flag == 'RUNTRANS2':
323                 NP020FR.p2 = copy.deepcopy(helper.location)
324                 NP020FR.rectangle[2] = NP020FR.p2
325                 NP020FR.rectangle[3] = NP020FR.p0 + (NP020FR.p2 - NP020FR.p1)
326                 NP020FR.flag = 'GENERATE'
327             np_print('04_RunTrans_left_enter_FINISHED',';','NP020FR.flag = ', NP020FR.flag)
328             return{'FINISHED'}
329
330         elif event.type in ('LEFTMOUSE', 'NUMPAD_ENTER', 'SPACE') and event.value == 'RELEASE':
331             bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
332             self.co2d = ((event.mouse_region_x, event.mouse_region_y))
333             if flag == 'RUNTRANS0':
334                 NP020FR.p0 = copy.deepcopy(NP020FR.pointloc)
335                 NP020FR.ndef = copy.deepcopy(NP020FR.n)
336                 NP020FR.qdef = copy.deepcopy(NP020FR.q)
337                 NP020FR.ro_hor_def = copy.deepcopy(NP020FR.ro_hor)
338                 NP020FR.flag = 'RUNTRANS1_break'
339             elif flag == 'RUNTRANS1':
340                 NP020FR.p1 = copy.deepcopy(helper.location)
341                 NP020FR.flag = 'RUNTRANS2'
342             elif flag == 'RUNTRANS2':
343                 NP020FR.p2 = copy.deepcopy(helper.location)
344                 NP020FR.rectangle[2] = NP020FR.p2
345                 NP020FR.rectangle[3] = NP020FR.p0 + (NP020FR.p2 - NP020FR.p1)
346                 NP020FR.flag = 'GENERATE'
347             np_print('04_RunTrans_left_enter_FINISHED',';','NP020FR.flag = ', NP020FR.flag)
348             return{'FINISHED'}
349
350         elif event.type == 'RET':
351             bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
352             if flag == 'RUNTRANS0':
353                 NP020FR.ndef = copy.deepcopy(NP020FR.n)
354                 NP020FR.qdef = copy.deepcopy(NP020FR.q)
355                 NP020FR.ro_hor_def = copy.deepcopy(NP020FR.ro_hor)
356                 NP020FR.constrain = True
357             elif flag == 'RUNTRANS1':
358                 NP020FR.p1 = copy.deepcopy(helper.location)
359                 NP020FR.flag = 'RUNTRANS2'
360             elif flag == 'RUNTRANS2':
361                 NP020FR.p2 = copy.deepcopy(helper.location)
362                 NP020FR.flag = 'GENERATE'
363             np_print('04_RunTrans_right_FINISHED',';','NP020FR.flag = ', NP020FR.flag)
364             return{'FINISHED'}
365
366
367
368
369         elif event.type in ('ESC', 'RIGHTMOUSE'):
370             bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
371             NP020FR.flag = 'EXIT'
372             np_print('04_RunTrans_esc_right_FINISHED',';','NP020FR.flag = ', NP020FR.flag)
373             return{'FINISHED'}
374
375         np_print('04_RunTrans_count_PASS_THROUGH',';','NP020FR.flag = ', NP020FR.flag)
376         return{'PASS_THROUGH'}
377
378     def invoke(self, context, event):
379         np_print('04_RunTrans_INVOKE_START')
380         helper = NP020FR.helper
381         flag = NP020FR.flag
382         selob = NP020FR.selob
383
384         if context.area.type == 'VIEW_3D':
385             if flag in ('RUNTRANS0', 'RUNTRANS1', 'RUNTRANS2'):
386                 self.co2d = ((event.mouse_region_x, event.mouse_region_y))
387                 args = (self, context)
388                 self._handle = bpy.types.SpaceView3D.draw_handler_add(DRAW_Overlay, args, 'WINDOW', 'POST_PIXEL')
389                 context.window_manager.modal_handler_add(self)
390                 if flag == 'RUNTRANS0':
391                     bpy.ops.transform.translate('INVOKE_DEFAULT')
392                     np_print('04_RunTrans1_INVOKED_RUNNING_MODAL',';','NP020FR.flag = ', NP020FR.flag)
393                 if flag == 'RUNTRANS1':
394                     bpy.ops.transform.translate('INVOKE_DEFAULT', constraint_axis=(True, False, False))
395                     np_print('04_RunTrans1_INVOKED_RUNNING_MODAL',';','NP020FR.flag = ', NP020FR.flag)
396                 if flag == 'RUNTRANS2':
397                     bpy.ops.transform.translate('INVOKE_DEFAULT', constraint_axis=(False, True, False))
398                     np_print('04_RunTrans1_INVOKED_RUNNING_MODAL',';','NP020FR.flag = ', NP020FR.flag)
399                 return {'RUNNING_MODAL'}
400             else:
401                 np_print('04_RunTrans_INVOKE_DECLINED_wrong_flag_FINISHED',';','NP020FR.flag = ', NP020FR.flag)
402                 return {'FINISHED'}
403         else:
404             self.report({'WARNING'}, "View3D not found, cannot run operator")
405             NP020FR.flag = 'EXIT'
406             np_print('04_RunTrans_INVOKE_DECLINED_no_VIEW_3D_FINISHED',';','NP020FR.flag = ', NP020FR.flag)
407             return {'FINISHED'}
408
409
410 # Defining the set of instructions that will draw the OpenGL elements on the screen during the execution of RunTranslate operator:
411
412 def DRAW_Overlay(self, context):
413
414     np_print('DRAW_Overlay_START',';','NP020FR.flag = ', NP020FR.flag)
415
416     '''
417     addon_prefs = context.preferences.addons[__package__].preferences
418     badge = addon_prefs.npfr_badge
419     badge_size = addon_prefs.npfr_badge_size
420     dist_scale = addon_prefs.npfr_dist_scale
421     '''
422     flag = NP020FR.flag
423     helper = NP020FR.helper
424     matrix = helper.matrix_world.to_3x3()
425     region = bpy.context.region
426     rv3d = bpy.context.region_data
427     rw = region.width
428     rh = region.height
429     qdef = NP020FR.qdef
430     ndef = NP020FR.ndef
431     ro_hor_def = NP020FR.ro_hor_def
432     constrain = NP020FR.constrain
433     np_print('rw, rh', rw, rh)
434     rmin = int(min(rw, rh) / 50)
435     if rmin == 0: rmin = 1
436     co2d = view3d_utils.location_3d_to_region_2d(region, rv3d, helper.location)
437     if qdef != None and constrain == False:
438         q = qdef
439         n = ndef
440         pointloc = helper.location
441         ro_hor = ro_hor_def
442
443     elif qdef != None and constrain == True:
444         q = qdef
445         n = ndef
446         pointloc = get_ro_normal_from_vertical(region, rv3d, co2d)[2]
447         ro_hor = ro_hor_def
448
449     else:
450         q = get_ro_normal_from_vertical(region, rv3d, co2d)[1]
451         n = get_ro_normal_from_vertical(region, rv3d, co2d)[0]
452         pointloc = get_ro_normal_from_vertical(region, rv3d, co2d)[2]
453         ro_hor, isohipse = get_ro_x_from_iso(region, rv3d, co2d, helper.location)
454
455     if pointloc == Vector((0.0, 0.0, 0.0)): pointloc = helper.location
456     np_print('n / q', n, q)
457     NP020FR.q = q
458     NP020FR.n = n
459     NP020FR.pointloc = pointloc
460     NP020FR.ro_hor = ro_hor
461     np_print('co2d, n, q', co2d, n, q)
462
463     # Acquiring factor for graphics scaling in order to be space - independent
464
465
466     fac = get_fac_from_view_loc_plane(region, rv3d, rmin, helper.location, q)
467     NP020FR.fac = fac
468
469
470     symbol = [[18, 37], [21, 37], [23, 33], [26, 33]]
471     badge_mode = 'RUN'
472
473
474     if qdef != None:
475         matrix.rotate(ro_hor)
476         matrix.rotate(qdef)
477     NP020FR.matrix = matrix
478
479     if flag == 'RUNTRANS0':
480         instruct = 'choose plane / place corner point'
481         keys_aff = 'LMB - select, CTRL - snap, ENT - lock plane'
482         keys_nav = ''
483         keys_neg = 'ESC, RMB - quit'
484         rectangle = [helper.location, helper.location, helper.location, helper.location]
485
486         message_main = 'CTRL+SNAP'
487         message_aux = None
488         aux_num = None
489         aux_str = None
490
491     elif flag == 'RUNTRANS1':
492         instruct = 'define the width of the rectangle'
493         keys_aff = 'LMB - select, CTRL - snap, NUMPAD - value'
494         keys_nav = ''
495         keys_neg = 'ESC, RMB - quit'
496         p0 = NP020FR.p0
497         rectangle = [p0, helper.location, helper.location, helper.location]
498
499         message_main = 'CTRL+SNAP'
500         message_aux = None
501         aux_num = None
502         aux_str = None
503
504     elif flag == 'RUNTRANS2':
505         instruct = 'define the length of the rectangle'
506         keys_aff = 'LMB - select, CTRL - snap, NUMPAD - value'
507         keys_nav = ''
508         keys_neg = 'ESC, RMB - quit'
509         p0 = NP020FR.p0
510         p1 = NP020FR.p1
511         rectangle = [p0, p1, helper.location, p0 + (helper.location-p1)]
512
513         message_main = 'CTRL+SNAP'
514         message_aux = None
515         aux_num = None
516         aux_str = None
517
518     # ON-SCREEN INSTRUCTIONS:
519
520     display_instructions(region, rv3d, instruct, keys_aff, keys_nav, keys_neg)
521
522
523
524     NP020FR.rectangle = rectangle
525
526     # drawing of rectangle:
527
528     rectangle_2d = []
529     bgl.glEnable(bgl.GL_BLEND)
530     bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
531     bgl.glLineWidth(1)
532     bgl.glBegin(bgl.GL_LINE_STRIP)
533     for i, co in enumerate(rectangle):
534         co = view3d_utils.location_3d_to_region_2d(region, rv3d, co)
535         bgl.glVertex2f(*co)
536         rectangle_2d.append(co)
537     bgl.glVertex2f(*rectangle_2d[0])
538     bgl.glEnd()
539     bgl.glColor4f(1.0, 1.0, 1.0, 0.25)
540     bgl.glBegin(bgl.GL_TRIANGLE_FAN)
541     for i, co in enumerate(rectangle_2d):
542         bgl.glVertex2f(*co)
543     bgl.glEnd()
544
545
546     # Drawing the small badge near the cursor with the basic instructions:
547
548
549
550
551
552     display_cursor_badge(co2d, symbol, badge_mode, message_main, message_aux, aux_num, aux_str)
553
554
555     # writing the dots for recwidget widget at center of scene:
556
557     geowidget_base = [(0.0 ,0.0 ,0.0), (5.0 ,0.0 ,0.0), (5.0 ,-3.0 ,0.0), (0.0, -3.0 ,0.0)]
558     geowidget_top = None
559     geowidget_rest = None
560
561     # ON-SCREEN DISPLAY OF GEOWIDGET:
562
563     display_geowidget(region, rv3d, fac, ro_hor, q, helper.location, n, qdef, geowidget_base, geowidget_top, geowidget_rest)
564
565
566
567
568     # ON-SCREEN DISTANCES AND OTHERS:
569     '''
570
571     if addon_prefs.npfr_suffix == 'None':
572         suffix = None
573
574     elif addon_prefs.npfr_suffix == 'km':
575         suffix = ' km'
576
577     elif addon_prefs.npfr_suffix == 'm':
578         suffix = ' m'
579
580     elif addon_prefs.npfr_suffix == 'cm':
581         suffix = ' cm'
582
583     elif addon_prefs.npfr_suffix == 'mm':
584         suffix = ' mm'
585
586     elif addon_prefs.npfr_suffix == 'nm':
587         suffix = ' nm'
588
589     elif addon_prefs.npfr_suffix == "'":
590         suffix = "'"
591
592     elif addon_prefs.npfr_suffix == '"':
593         suffix = '"'
594
595     elif addon_prefs.npfr_suffix == 'thou':
596         suffix = ' thou'
597     '''
598
599
600     # ON-SCREEN DISTANCES:
601
602     display_distance_between_two_points(region, rv3d, rectangle[0], rectangle[1])
603     display_distance_between_two_points(region, rv3d, rectangle[1], rectangle[2])
604
605
606     #ENDING:
607
608     bgl.glLineWidth(1)
609     bgl.glDisable(bgl.GL_BLEND)
610     bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
611
612
613 # Defining the operator that will generate the rectangle mesh from the collected points:
614
615 class NPFRGenerateGeometry(bpy.types.Operator):
616     bl_idname = 'object.np_fr_generate_geometry'
617     bl_label = 'NP FR Generate Geometry'
618     bl_options = {'INTERNAL'}
619
620     def execute(self, context):
621
622         flag = NP020FR.flag
623         wire = True
624         material = True
625         if flag == 'GENERATE':
626             recverts = NP020FR.rectangle
627             recedges = []
628             i = 0
629             for ve in recverts:
630                 if i == len(recverts) - 1:
631                     recedges.append((i, 0))
632                 else:
633                     recedges.append((i, i+1))
634                 i = i+1
635             recfaces = []
636             recme = bpy.data.meshes.new('float_rectangle')
637             np_print(recverts,recedges,recfaces)
638             recme.from_pydata(recverts,recedges,recfaces)
639             recob = bpy.data.objects.new('float_rectangle',recme)
640             recob.location = mathutils.Vector((0,0,0))
641             scn = bpy.context.scene
642             scn.objects.link(recob)
643             scn.objects.active = recob
644             scn.update()
645             bpy.ops.object.select_all(action = 'DESELECT')
646             recob.select_set(True)
647             bpy.ops.object.origin_set(type = 'ORIGIN_GEOMETRY')
648             bpy.ops.object.mode_set(mode = 'EDIT')
649             bpy.ops.mesh.select_all(action = 'SELECT')
650             bpy.ops.mesh.edge_face_add()
651             bpy.ops.object.mode_set(mode = 'OBJECT')
652             if wire:
653                 recob.show_wire = True
654             if material:
655                 mtl = bpy.data.materials.new('float_rectangle_material')
656                 mtl.diffuse_color = (1.0, 1.0, 1.0)
657                 recme.materials.append(mtl)
658             activelayer = bpy.context.scene.active_layer
659             np_print('activelayer:', activelayer)
660             layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
661             layers[activelayer] = True
662             layers = tuple(layers)
663             np_print(layers)
664             bpy.ops.object.move_to_layer(layers = layers)
665             NP020FR.recob = recob
666
667         return{'FINISHED'}
668
669 # Restoring the object selection and system settings from before the operator activation:
670
671 class NPFRRestoreContext(bpy.types.Operator):
672     bl_idname = "object.np_fr_restore_context"
673     bl_label = "NP FR Restore Context"
674     bl_options = {'INTERNAL'}
675
676     def execute(self, context):
677         selob = NP020FR.selob
678         helper = NP020FR.helper
679         recob = NP020FR.recob
680         helper.hide = False
681         bpy.ops.object.select_all(action = 'DESELECT')
682         helper.select_set(True)
683         bpy.ops.object.delete('EXEC_DEFAULT')
684         if recob == None:
685             for ob in selob:
686                 ob.select_set(True)
687             if NP020FR.acob is not None:
688                 bpy.context.view_layer.objects.active = NP020FR.acob
689                 bpy.ops.object.mode_set(mode = NP020FR.edit_mode)
690         else:
691             recob.select_set(True)
692             bpy.context.view_layer.objects.active = recob
693             bpy.ops.object.mode_set(mode = NP020FR.edit_mode)
694         if NP020FR.trans_custom: bpy.ops.transform.delete_orientation()
695         bpy.context.tool_settings.use_snap = NP020FR.use_snap
696         bpy.context.tool_settings.snap_element = NP020FR.snap_element
697         bpy.context.tool_settings.snap_target = NP020FR.snap_target
698         bpy.context.space_data.pivot_point = NP020FR.pivot_point
699         bpy.context.space_data.transform_orientation = NP020FR.trans_orient
700
701         NP020FR.flag = 'RUNTRANS0'
702         NP020FR.recob = None
703         return {'FINISHED'}
704
705
706 # This is the actual addon process, the algorithm that defines the order of operator activation inside the main macro:
707
708 def register():
709
710     #bpy.app.handlers.scene_update_post.append(NPFR_scene_update)
711
712     NP020FloatRectangle.define('OBJECT_OT_np_fr_get_context')
713     NP020FloatRectangle.define('OBJECT_OT_np_fr_get_selection')
714     NP020FloatRectangle.define('OBJECT_OT_np_fr_get_mouseloc')
715     NP020FloatRectangle.define('OBJECT_OT_np_fr_add_helper')
716     NP020FloatRectangle.define('OBJECT_OT_np_fr_prepare_context')
717     for i in range(1, 15):
718         NP020FloatRectangle.define('OBJECT_OT_np_fr_run_translate')
719     NP020FloatRectangle.define('OBJECT_OT_np_fr_prepare_context')
720     NP020FloatRectangle.define('OBJECT_OT_np_fr_run_translate')
721     NP020FloatRectangle.define('OBJECT_OT_np_fr_prepare_context')
722     NP020FloatRectangle.define('OBJECT_OT_np_fr_run_translate')
723     NP020FloatRectangle.define('OBJECT_OT_np_fr_generate_geometry')
724     NP020FloatRectangle.define('OBJECT_OT_np_fr_restore_context')
725
726 def unregister():
727     #bpy.app.handlers.scene_update_post.remove(NPFR_scene_update)
728     pass