2 # BEGIN GPL LICENSE BLOCK #####
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.
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.
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.
18 # END GPL LICENSE BLOCK #####
24 Measures distance using start and end points. Emulates the functionality of the standard 'distance' command in CAD applications. User is now able to change snap target while operating.
29 Unzip and place .py file to scripts / addons_contrib folder. In User Preferences / Addons tab, search with Testing filter - NP Point Distance and check the box.
30 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 Blender.
35 After successful installation of the addon, the NP Point Distance operator should be registered in your system. Enter User Preferences / Input, and under that, 3DView / Global mode. At the bottom of the list click the 'Add new' button. In the operator field type object.np_point_distance_xxx (xxx being the number of the version) and assign a key of yor prefference. At the moment i am using 'T' for 'tape measure'. I have my 'T' and 'N' keys free because of new 'Z' and 'X' keys assigned to toolshelf and properties (under the left hand, no need to look down).
40 Run operator (spacebar search - NP Point Distance, or keystroke if you assigned it)
41 Select a point anywhere in the scene (holding CTRL enables snapping). This will be your start point.
42 Move your mouse anywhere in the scene, in relation to the start point (again CTRL - snap). The addon will show the distance between your start and end points.
43 Middle mouse button (MMB) enables axis constraint, numpad keys enable numerical input of distance, ENTER key changes snap target and RMB and ESC key interrupt the operation.
48 Below the addon name in the user preferences / addon tab, you can find a couple of settings that control the behavior of the addon:
50 Unit scale: Distance multiplier for various unit scenarios
51 Suffix: Unit abbreviation after the numerical distance
52 Custom colors: Default or custom colors for graphical elements
53 Mouse badge: Option to display a small cursor label
56 IMPORTANT PERFORMANCE NOTES
58 Now can start in all 3D modes, the operator temporarily exits the mode and enters the object mode, does the task and returns to original mode.
63 X/Y/Z distance components
64 Custom colors, fonts and unit formats
65 Navigation enabled during use
66 Smarter code and faster performance
72 Custom colors, fonts and unit formats, custom colors for badge, aistance num on top
73 Navigation enabled during use
74 Smarter code and faster performance
84 'name': 'NP 020 Point Distance',
85 'author': 'Okavango & the Blenderartists community',
87 'blender': (2, 75, 0),
90 'description': 'Measures distance between two snapped points',
92 'category': '3D View'}
99 from bpy_extras
import view3d_utils
100 from bpy
.app
.handlers
import persistent
101 from mathutils
import Vector
, Matrix
102 from blf
import ROTATION
103 from math
import radians
105 from .utils_geometry
import *
106 from .utils_graphics
import *
107 from .utils_function
import *
109 # Defining the main class - the macro:
111 class NP020PointDistance(bpy
.types
.Macro
):
112 bl_idname
= 'object.np_020_point_distance'
113 bl_label
= 'NP 020 Point Distance'
114 bl_options
= {'UNDO'}
117 # Defining the storage class that will serve as a variable-bank for
118 # exchange among the classes. Later, this bank will receive more variables
119 # with their values for safe keeping, as the program goes on:
123 startloc3d
= (0.0, 0.0, 0.0)
124 endloc3d
= (0.0, 0.0, 0.0)
133 # Defining the first of the classes from the macro, that will gather the
134 # current system settings set by the user. Some of the system settings
135 # will be changed during the process, and will be restored when macro has
136 # completed. It also acquires the list of selected objects and storing them
137 # for later re-call (the addon doesn't need them for operation):
139 class NP020PDGetSelection(bpy
.types
.Operator
):
140 bl_idname
= 'object.np_pd_get_selection'
141 bl_label
= 'NP PD Get Selection'
142 bl_options
= {'INTERNAL'}
144 def execute(self
, context
):
146 # First, storing all of the system preferences set by the user, that
147 # will be changed during the process, in order to restore them when the
148 # operation is completed:
150 np_print('01_get_selection_START')
151 NP020PD
.use_snap
= bpy
.context
.tool_settings
.use_snap
152 NP020PD
.snap_element
= bpy
.context
.tool_settings
.snap_element
153 NP020PD
.snap_target
= bpy
.context
.tool_settings
.snap_target
154 NP020PD
.pivot_point
= bpy
.context
.space_data
.pivot_point
155 NP020PD
.trans_orient
= bpy
.context
.space_data
.transform_orientation
156 NP020PD
.show_manipulator
= bpy
.context
.space_data
.show_manipulator
157 NP020PD
.acob
= bpy
.context
.active_object
158 np_print('NP020PD.acob =', NP020PD
.acob
)
159 np_print(bpy
.context
.mode
)
160 if bpy
.context
.mode
== 'OBJECT':
161 NP020PD
.edit_mode
= 'OBJECT'
162 elif bpy
.context
.mode
in ('EDIT_MESH', 'EDIT_CURVE', 'EDIT_SURFACE', 'EDIT_TEXT', 'EDIT_ARMATURE', 'EDIT_METABALL', 'EDIT_LATTICE'):
163 NP020PD
.edit_mode
= 'EDIT'
164 elif bpy
.context
.mode
== 'POSE':
165 NP020PD
.edit_mode
= 'POSE'
166 elif bpy
.context
.mode
== 'SCULPT':
167 NP020PD
.edit_mode
= 'SCULPT'
168 elif bpy
.context
.mode
== 'PAINT_WEIGHT':
169 NP020PD
.edit_mode
= 'WEIGHT_PAINT'
170 elif bpy
.context
.mode
== 'PAINT_TEXTURE':
171 NP020PD
.edit_mode
= 'TEXTURE_PAINT'
172 elif bpy
.context
.mode
== 'PAINT_VERTEX':
173 NP020PD
.edit_mode
= 'VERTEX_PAINT'
174 elif bpy
.context
.mode
== 'PARTICLE':
175 NP020PD
.edit_mode
= 'PARTICLE_EDIT'
177 # Reading and storing the selection:
178 selob
= bpy
.context
.selected_objects
179 NP020PD
.selob
= selob
180 # De-selecting objects in prepare for other processes in the script:
183 np_print('01_get_selection_END')
186 # Defining the operator that will read the mouse position in 3D when the
187 # command is activated and store it as a location for placing the start
188 # and end points under the mouse:
191 class NP020PDReadMouseLoc(bpy
.types
.Operator
):
192 bl_idname
= 'object.np_pd_read_mouse_loc'
193 bl_label
= 'NP PD Read Mouse Loc'
194 bl_options
= {'INTERNAL'}
196 def modal(self
, context
, event
):
197 np_print('02_read_mouse_loc_START')
198 region
= context
.region
199 rv3d
= context
.region_data
200 co2d
= ((event
.mouse_region_x
, event
.mouse_region_y
))
201 view_vector
= view3d_utils
.region_2d_to_vector_3d(region
, rv3d
, co2d
)
202 pointloc
= view3d_utils
.region_2d_to_origin_3d(
203 region
, rv3d
, co2d
) + view_vector
/ 5
205 NP020PD
.pointloc
= pointloc
206 np_print('02_read_mouse_loc_END')
209 def invoke(self
, context
, event
):
210 np_print('02_read_mouse_loc_INVOKE_a')
211 args
= (self
, context
)
212 context
.window_manager
.modal_handler_add(self
)
213 np_print('02_read_mouse_loc_INVOKE_b')
214 return {'RUNNING_MODAL'}
217 # Defining the operator that will generate start and end points at the
218 # spot marked by mouse and select them, preparing for translation:
221 class NP020PDAddPoints(bpy
.types
.Operator
):
222 bl_idname
= 'object.np_pd_add_points'
223 bl_label
= 'NP PD Add Points'
224 bl_options
= {'INTERNAL'}
226 def execute(self
, context
):
227 np_print('03_add_points_START')
228 pointloc
= NP020PD
.pointloc
229 if bpy
.context
.mode
not in ('OBJECT'):
230 bpy
.ops
.object.mode_set(mode
='OBJECT')
231 bpy
.context
.space_data
.show_manipulator
= False
232 bpy
.ops
.object.add(type='MESH', location
=pointloc
)
233 start
= bpy
.context
.object
234 start
.name
= 'NP_PD_start'
235 NP020PD
.start
= start
236 bpy
.ops
.object.add(type='MESH', location
=pointloc
)
237 end
= bpy
.context
.object
238 end
.name
= 'NP_PD_end'
240 start
.select_set(True)
242 bpy
.context
.tool_settings
.use_snap
= False
243 bpy
.context
.tool_settings
.snap_element
= NP020PD
.snap
244 bpy
.context
.tool_settings
.snap_target
= 'ACTIVE'
245 bpy
.context
.space_data
.pivot_point
= 'MEDIAN_POINT'
246 bpy
.context
.space_data
.transform_orientation
= 'GLOBAL'
247 np_print('03_add_points_END')
251 # Defining the operator that will draw the OpenGL line across the screen
252 # together with the numerical distance and the on-screen instructions in
253 # normal, translation mode:
255 def draw_callback_px_TRANS(self
, context
):
257 np_print('04_callback_TRANS_START')
259 addon_prefs
= context
.preferences
.addons
[__package__
].preferences
261 scale
= addon_prefs
.nppd_scale
262 badge
= addon_prefs
.nppd_badge
263 step
= addon_prefs
.nppd_step
264 info
= addon_prefs
.nppd_info
265 clip
= addon_prefs
.nppd_clip
266 xyz_lines
= addon_prefs
.nppd_xyz_lines
267 xyz_distances
= addon_prefs
.nppd_xyz_distances
268 xyz_backdrop
= addon_prefs
.nppd_xyz_backdrop
269 stereo_cage
= addon_prefs
.nppd_stereo_cage
270 gold
= addon_prefs
.nppd_gold
272 if addon_prefs
.nppd_col_line_main_DEF
== False:
273 col_line_main
= addon_prefs
.nppd_col_line_main
275 col_line_main
= (1.0, 1.0, 1.0, 1.0)
277 if addon_prefs
.nppd_col_line_shadow_DEF
== False:
278 col_line_shadow
= addon_prefs
.nppd_col_line_shadow
280 col_line_shadow
= (0.1, 0.1, 0.1, 0.25)
282 if addon_prefs
.nppd_col_num_main_DEF
== False:
283 col_num_main
= addon_prefs
.nppd_col_num_main
285 col_num_main
= (0.95, 0.95, 0.95, 1.0)
287 if addon_prefs
.nppd_col_num_shadow_DEF
== False:
288 col_num_shadow
= addon_prefs
.nppd_col_num_shadow
290 col_num_shadow
= (0.0, 0.0, 0.0, 0.75)
292 if addon_prefs
.nppd_suffix
== 'None':
295 elif addon_prefs
.nppd_suffix
== 'km':
298 elif addon_prefs
.nppd_suffix
== 'm':
301 elif addon_prefs
.nppd_suffix
== 'cm':
304 elif addon_prefs
.nppd_suffix
== 'mm':
307 elif addon_prefs
.nppd_suffix
== 'nm':
310 elif addon_prefs
.nppd_suffix
== "'":
313 elif addon_prefs
.nppd_suffix
== '"':
316 elif addon_prefs
.nppd_suffix
== 'thou':
319 # sel=bpy.context.selected_objects
320 phase
= NP020PD
.phase
321 start
= NP020PD
.start
323 startloc3d
= start
.location
324 endloc3d
= end
.location
325 endloc3dx
= copy
.deepcopy(startloc3d
)
326 endloc3dx
[0] = endloc3d
[0]
327 endloc3dy
= copy
.deepcopy(startloc3d
)
328 endloc3dy
[1] = endloc3d
[1]
329 endloc3dz
= copy
.deepcopy(startloc3d
)
330 endloc3dz
[2] = endloc3d
[2]
331 region
= context
.region
332 rv3d
= context
.region_data
333 startloc2d
= view3d_utils
.location_3d_to_region_2d(
334 region
, rv3d
, startloc3d
)
335 endloc2d
= view3d_utils
.location_3d_to_region_2d(region
, rv3d
, endloc3d
)
336 endloc2dx
= view3d_utils
.location_3d_to_region_2d(region
, rv3d
, endloc3dx
)
337 endloc2dy
= view3d_utils
.location_3d_to_region_2d(region
, rv3d
, endloc3dy
)
338 endloc2dz
= view3d_utils
.location_3d_to_region_2d(region
, rv3d
, endloc3dz
)
339 if startloc2d
is None:
340 startloc2d
= (0.0, 0.0)
341 endloc2d
= (0.0, 0.0)
342 np_print(startloc2d
, endloc2d
)
344 dist
= (mathutils
.Vector(endloc3d
) - mathutils
.Vector(startloc3d
))
345 distgold
= dist
/ 1.6180339887
346 goldloc3d
= mathutils
.Vector(startloc3d
) + distgold
347 goldloc2d
= view3d_utils
.location_3d_to_region_2d(
348 region
, rv3d
, goldloc3d
)
349 distn
= dist
.length
* scale
350 distn
= str(abs(round(distn
, 2)))
352 dist
= dist
.length
* scale
354 if suffix
is not None:
355 dist
= str(abs(round(dist
, 2))) + suffix
357 dist
= str(abs(round(dist
, 2)))
360 # This is for correcting the position of the numerical on the screen if
361 # the endpoints are far out of screen:
364 startx
= startloc2d
[0]
365 starty
= startloc2d
[1]
368 if startx
> region
.width
:
369 startx
= region
.width
374 if starty
> region
.height
:
375 starty
= region
.height
380 if endx
> region
.width
:
386 if endy
> region
.height
:
392 numloc
.append((startx
+ endx
) / 2)
393 numloc
.append((starty
+ endy
) / 2)
396 instruct
= 'select start point'
399 instruct
= 'select end point'
401 if NP020PD
.flag
== 'HOLD':
402 instruct
= 'inspect result'
406 bgl
.glEnable(bgl
.GL_BLEND
)
409 # ON-SCREEN INSTRUCTIONS:
412 if NP020PD
.flag
== 'HOLD':
413 keys_aff
= 'LMB, ENT, SPACE - continue'
415 keys_neg
= 'ESC, RMB - quit'
418 keys_aff
= 'LMB - select, CTRL - snap, ENT - change snap, MMB - lock axis'
419 keys_nav
= 'SPACE - change to navigate'
420 keys_neg
= 'ESC, RMB - quit'
422 display_instructions(region
, rv3d
, instruct
, keys_aff
, keys_nav
, keys_neg
)
428 if phase
== 1 and stereo_cage
:
430 startloc3dx
= copy
.deepcopy(endloc3d
)
431 startloc3dx
[0] = startloc3d
[0]
432 startloc3dy
= copy
.deepcopy(endloc3d
)
433 startloc3dy
[1] = startloc3d
[1]
434 startloc3dz
= copy
.deepcopy(endloc3d
)
435 startloc3dz
[2] = startloc3d
[2]
436 startloc2dx
= view3d_utils
.location_3d_to_region_2d(
437 region
, rv3d
, startloc3dx
)
438 startloc2dy
= view3d_utils
.location_3d_to_region_2d(
439 region
, rv3d
, startloc3dy
)
440 startloc2dz
= view3d_utils
.location_3d_to_region_2d(
441 region
, rv3d
, startloc3dz
)
443 bgl
.glColor4f(0.5, 0.5, 0.5, 0.5)
445 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
446 bgl
.glVertex2f(*endloc2d
)
447 bgl
.glVertex2f(*startloc2dx
)
450 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
451 bgl
.glVertex2f(*endloc2d
)
452 bgl
.glVertex2f(*startloc2dy
)
455 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
456 bgl
.glVertex2f(*endloc2d
)
457 bgl
.glVertex2f(*startloc2dz
)
460 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
461 bgl
.glVertex2f(*endloc2dy
)
462 bgl
.glVertex2f(*startloc2dx
)
463 bgl
.glVertex2f(*endloc2dz
)
464 bgl
.glVertex2f(*startloc2dy
)
465 bgl
.glVertex2f(*endloc2dx
)
466 bgl
.glVertex2f(*startloc2dz
)
467 bgl
.glVertex2f(*endloc2dy
)
470 if phase
== 1 and xyz_lines
== False and stereo_cage
== True:
472 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
473 bgl
.glVertex2f(*startloc2d
)
474 bgl
.glVertex2f(*endloc2dx
)
477 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
478 bgl
.glVertex2f(*startloc2d
)
479 bgl
.glVertex2f(*endloc2dy
)
482 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
483 bgl
.glVertex2f(*startloc2d
)
484 bgl
.glVertex2f(*endloc2dz
)
489 bgl
.glColor4f(*col_line_shadow
)
491 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
492 bgl
.glVertex2f((startloc2d
[0] - 1), (startloc2d
[1] - 1))
493 bgl
.glVertex2f((endloc2d
[0] - 1), (endloc2d
[1] - 1))
496 bgl
.glColor4f(*col_line_main
)
498 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
499 bgl
.glVertex2f(*startloc2d
)
500 bgl
.glVertex2f(*endloc2d
)
505 if phase
== 1 and xyz_lines
:
507 bgl
.glColor4f(1.0, 0.0, 0.0, 1.0)
509 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
510 bgl
.glVertex2f(*startloc2d
)
511 bgl
.glVertex2f(*endloc2dx
)
514 bgl
.glColor4f(0.0, 0.75, 0.0, 1.0)
516 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
517 bgl
.glVertex2f(*startloc2d
)
518 bgl
.glVertex2f(*endloc2dy
)
521 bgl
.glColor4f(0.0, 0.0, 1.0, 1.0)
523 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
524 bgl
.glVertex2f(*startloc2d
)
525 bgl
.glVertex2f(*endloc2dz
)
528 # bgl.glEnable(bgl.GL_BLEND)
531 bgl
.glColor4f(1.0, 0.0, 0.0, 1.0)
532 bgl
.glBegin(bgl
.GL_POINTS
)
533 bgl
.glVertex2f(*endloc2dx
)
537 bgl
.glColor4f(0.0, 0.75, 0.0, 1.0)
538 bgl
.glBegin(bgl
.GL_POINTS
)
539 bgl
.glVertex2f(*endloc2dy
)
543 bgl
.glColor4f(0.0, 0.0, 1.0, 1.0)
544 bgl
.glBegin(bgl
.GL_POINTS
)
545 bgl
.glVertex2f(*endloc2dz
)
551 # Drawing the small badge near the cursor with the basic instructions:
555 endloc
= end
.location
556 mouseloc
= view3d_utils
.location_3d_to_region_2d(region
, rv3d
, endloc
)
557 if badge
and NP020PD
.flag
!= 'HOLD':
558 square
= [[17, 30], [17, 40], [27, 40], [27, 30]]
559 rectangle
= [[27, 30], [27, 40], [67, 40], [67, 30]]
560 snapsquare
= [[17, 30], [67, 30], [67, 20], [17, 20]]
561 arrow
= [[20, 33], [18, 35], [20, 37], [18, 35],
562 [26, 35], [24, 33], [26, 35], [24, 37]]
563 dots1
= [[19, 31], [20, 31]]
564 dots2
= [[22, 31], [23, 31]]
565 dots3
= [[25, 31], [26, 31]]
569 co
[0] = round((co
[0] * size
), 0) - 20 + mouseloc
[0]
570 co
[1] = round((co
[1] * size
), 0) - 50 + mouseloc
[1]
572 co
[0] = round((co
[0] * size
), 0) - 20 + mouseloc
[0]
573 co
[1] = round((co
[1] * size
), 0) - 50 + mouseloc
[1]
574 for co
in snapsquare
:
575 co
[0] = round((co
[0] * size
), 0) - 20 + mouseloc
[0]
576 co
[1] = round((co
[1] * size
), 0) - 50 + mouseloc
[1]
578 co
[0] = round((co
[0] * size
), 0) - 20 + mouseloc
[0]
579 co
[1] = round((co
[1] * size
), 0) - 50 + mouseloc
[1]
581 co
[0] = round((co
[0] * size
), 0) - 20 + mouseloc
[0]
582 co
[1] = round((co
[1] * size
), 0) - 50 + mouseloc
[1]
584 co
[0] = round((co
[0] * size
), 0) - 20 + mouseloc
[0]
585 co
[1] = round((co
[1] * size
), 0) - 50 + mouseloc
[1]
587 co
[0] = round((co
[0] * size
), 0) - 20 + mouseloc
[0]
588 co
[1] = round((co
[1] * size
), 0) - 50 + mouseloc
[1]
589 ipx
= round((ipx
* size
), 0) - 20 + mouseloc
[0]
590 ipy
= round((ipy
* size
), 0) - 50 + mouseloc
[1]
592 bgl
.glColor4f(0.0, 0.0, 0.0, 0.0)
593 bgl
.glBegin(bgl
.GL_TRIANGLE_FAN
)
597 bgl
.glColor4f(1.0, 0.5, 0.0, 1.0)
598 bgl
.glBegin(bgl
.GL_TRIANGLE_FAN
)
599 for x
, y
in rectangle
:
602 bgl
.glColor4f(0.4, 0.15, 0.75, 1.0)
603 bgl
.glBegin(bgl
.GL_TRIANGLE_FAN
)
604 for x
, y
in snapsquare
:
607 bgl
.glColor4f(1.0, 1.0, 1.0, 1.0)
608 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
612 bgl
.glColor4f(1.0, 1.0, 1.0, 1.0)
613 blf
.position(font_id
, ipx
- (10 * size
), ipy
- (10 * size
), 0)
614 blf
.size(font_id
, ipsize
, 72)
615 blf
.draw(font_id
, NP020PD
.snap
)
616 bgl
.glColor4f(1.0, 1.0, 1.0, 1.0)
617 blf
.position(font_id
, ipx
, ipy
, 0)
618 blf
.size(font_id
, ipsize
, 72)
619 blf
.draw(font_id
, 'CTRL+SNAP')
620 if step
== 'continuous':
621 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
625 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
629 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
634 if gold
and phase
!= 0:
636 goldtriangle = [[0, 0], [-1, 1], [1, 1]]
637 for co in goldtriangle:
638 co[0] = round((co[0] * 10), 0) + goldloc2d[0]
639 co[1] = round((co[1] * 10), 0) + goldloc2d[1]
640 bgl.glColor4f(1.0, 0.5, 0.0, 1.0)
641 bgl.glBegin(bgl.GL_TRIANGLE_FAN)
642 for x, y in goldtriangle:
646 goldvec1
= mathutils
.Vector((1.0 , 0.0))
647 goldvec2
= endloc2d
- startloc2d
648 ang
= goldvec1
.angle_signed(goldvec2
, None)
650 coy
= round(cos(ang
), 8)
651 cox
= round(sin(ang
), 8)
652 goldtick
= [[-cox
, -coy
], [0, 0], [cox
, coy
]]
654 co
[0] = round((co
[0] * 10), 0) + goldloc2d
[0]
655 co
[1] = round((co
[1] * 10), 0) + goldloc2d
[1]
656 bgl
.glColor4f(0.95, 0.55, 0.0, 1.0)
658 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
659 for x
, y
in goldtick
:
664 distgold_first
= (goldloc3d
- startloc3d
).length
* scale
665 distgold_first
= str(abs(round(distgold_first
, 2)))
666 distgold_sec
= (endloc3d
- goldloc3d
).length
* scale
667 distgold_sec
= str(abs(round(distgold_sec
, 2)))
668 goldloc_first
= [((startloc2d
[0] + goldloc2d
[0]) / 2), ((startloc2d
[1] + goldloc2d
[1]) / 2)]
669 goldloc_sec
= [((goldloc2d
[0] + endloc2d
[0]) / 2), ((goldloc2d
[1] + endloc2d
[1]) / 2)]
671 bgl
.glColor4f(1.0, 0.5, 0.0, 1.0)
672 bgl
.glBegin(bgl
.GL_TRIANGLE_FAN
)
673 bgl
.glVertex2f(goldloc_first
[0]-2, goldloc_first
[1]-2)
674 bgl
.glVertex2f(goldloc_first
[0]-2, goldloc_first
[1]+10)
675 bgl
.glVertex2f(goldloc_first
[0]+50, goldloc_first
[1]+10)
676 bgl
.glVertex2f(goldloc_first
[0]+50, goldloc_first
[1]-2)
678 bgl
.glColor4f(0.95, 0.55, 0.0, 1.0)
680 bgl
.glColor4f(1.0, 1.0, 1.0, 1.0)
681 blf
.position(font_id
, goldloc_first
[0], goldloc_first
[1], 0)
682 blf
.draw(font_id
, distgold_first
)
684 bgl
.glColor4f(1.0, 0.5, 0.0, 1.0)
685 bgl
.glBegin(bgl
.GL_TRIANGLE_FAN
)
686 bgl
.glVertex2f(goldloc_sec
[0]-2, goldloc_sec
[1]-2)
687 bgl
.glVertex2f(goldloc_sec
[0]-2, goldloc_sec
[1]+10)
688 bgl
.glVertex2f(goldloc_sec
[0]+50, goldloc_sec
[1]+10)
689 bgl
.glVertex2f(goldloc_sec
[0]+50, goldloc_sec
[1]-2)
691 bgl
.glColor4f(0.95, 0.55, 0.0, 1.0)
693 bgl
.glColor4f(1.0, 1.0, 1.0, 1.0)
694 blf
.position(font_id
, goldloc_sec
[0], goldloc_sec
[1], 0)
695 blf
.draw(font_id
, distgold_sec
)
698 # NUMERICAL DISTANCE:
700 square
= [[17, 30], [17, 40], [27, 40], [27, 30]]
702 co
[0] = round((co
[0] * size
), 0) - 20 + mouseloc
[0]
703 co
[1] = round((co
[1] * size
), 0) - 50 + mouseloc
[1]
704 badgeloc
= [(square
[0][0] + 6), (square
[0][1] - 8)]
705 numlocdistx
= abs(badgeloc
[0] - numloc
[0])
706 numlocdisty
= abs(badgeloc
[1] - numloc
[1])
707 if numlocdistx
< 96 and numlocdisty
< 30:
708 numloc
[0] = square
[0][0]
709 numloc
[1] = square
[0][1] - 40
711 if startloc3d
[0] == endloc3d
[0] and startloc3d
[1] == endloc3d
[1]:
712 col_num_main
= (0.0, 0.0, 0.80, 0.75)
713 elif startloc3d
[1] == endloc3d
[1] and startloc3d
[2] == endloc3d
[2]:
714 col_num_main
= (0.85, 0.0, 0.0, 0.75)
715 elif startloc3d
[0] == endloc3d
[0] and startloc3d
[2] == endloc3d
[2]:
716 col_num_main
= (0.0, 0.60, 0.0, 0.75)
718 bgl
.glColor4f(*col_num_shadow
)
721 blf
.size(font_id
, 20, 72)
722 blf
.position(font_id
, (numloc
[0] - 1), (numloc
[1] - 1), 0)
723 blf
.draw(font_id
, dist
)
725 bgl
.glColor4f(*col_num_main
)
728 blf
.size(font_id
, 20, 72)
729 blf
.position(font_id
, numloc
[0], numloc
[1], 0)
730 blf
.draw(font_id
, dist
)
734 if phase
== 1 and xyz_distances
:
736 badgeloc
[0] = badgeloc
[0] + 27
737 badgeloc
[1] = badgeloc
[1] - 15
739 blf
.size(font_id
, 12, 72)
742 numloccen
[0] = numloc
[0] + 15
743 numloccen
[1] = numloc
[1] + 2
745 distx
= (endloc3dx
[0] - startloc3d
[0]) * scale
746 distx
= str(abs(round(distx
, 2)))
747 if distx
not in (dist
, distn
):
749 (startloc2d
[0] + endloc2dx
[0]) / 2),
750 ((startloc2d
[1] + endloc2dx
[1]) / 2)]
753 numlocx
) - mathutils
.Vector(
755 numlocdistx
= abs(numlocx
[0] - numloccen
[0])
756 numlocdisty
= abs(numlocx
[1] - numloccen
[1])
757 if numlocdistx
< 60 and numlocdisty
< 16:
758 numlocx
[0] = numloc
[0]
759 numlocx
[1] = numloc
[1] - 15
761 elif run
== 'OUT' or numlocbadge
< 65:
762 numlocx
[0] = numloc
[0]
763 numlocx
[1] = numloc
[1] - 15
765 # bgl.glColor4f(*col_num_shadow)
766 # blf.position(font_id, numlocx[0]-1, numlocx[1]-1, 0)
767 # blf.draw(font_id, distx)
769 bgl
.glColor4f(1.0, 0.0, 0.0, 1.0)
770 bgl
.glBegin(bgl
.GL_TRIANGLE_FAN
)
771 bgl
.glVertex2f(numlocx
[0]-2, numlocx
[1]-2)
772 bgl
.glVertex2f(numlocx
[0]-2, numlocx
[1]+10)
773 bgl
.glVertex2f(numlocx
[0]+50, numlocx
[1]+10)
774 bgl
.glVertex2f(numlocx
[0]+50, numlocx
[1]-2)
776 bgl
.glColor4f(0.85, 0.0, 0.0, 1.0)
778 bgl
.glColor4f(1.0, 1.0, 1.0, 1.0)
779 blf
.position(font_id
, numlocx
[0], numlocx
[1], 0)
780 blf
.draw(font_id
, distx
)
782 disty
= (endloc3dy
[1] - startloc3d
[1]) * scale
783 disty
= str(abs(round(disty
, 2)))
784 if disty
not in (dist
, distn
):
786 (startloc2d
[0] + endloc2dy
[0]) / 2),
787 ((startloc2d
[1] + endloc2dy
[1]) / 2)]
790 numlocy
) - mathutils
.Vector(
792 numlocdistx
= abs(numlocy
[0] - numloccen
[0])
793 numlocdisty
= abs(numlocy
[1] - numloccen
[1])
794 if numlocdistx
< 60 and numlocdisty
< 16:
795 numlocy
[0] = numloc
[0]
796 numlocy
[1] = numloc
[1] - ((slide
* 12) + 15)
798 elif run
== 'OUT' or numlocbadge
< 65:
799 numlocy
[0] = numloc
[0]
800 numlocy
[1] = numloc
[1] - ((slide
* 12) + 15)
803 bgl
.glColor4f(0.0 ,0.65 ,0.0 ,1.0)
804 bgl
.glBegin(bgl
.GL_TRIANGLE_FAN
)
805 bgl
.glVertex2f(numlocy
[0]-2, numlocy
[1]-2)
806 bgl
.glVertex2f(numlocy
[0]-2, numlocy
[1]+10)
807 bgl
.glVertex2f(numlocy
[0]+50, numlocy
[1]+10)
808 bgl
.glVertex2f(numlocy
[0]+50, numlocy
[1]-2)
810 bgl
.glColor4f(0.0 ,0.75 ,0.0 ,1.0)
812 bgl
.glColor4f(1.0, 1.0, 1.0, 1.0)
813 blf
.position(font_id
, numlocy
[0], numlocy
[1], 0)
814 blf
.draw(font_id
, disty
)
816 distz
= (endloc3dz
[2] - startloc3d
[2]) * scale
817 distz
= str(abs(round(distz
, 2)))
818 if distz
not in (dist
, distn
):
820 (startloc2d
[0] + endloc2dz
[0]) / 2),
821 ((startloc2d
[1] + endloc2dz
[1]) / 2)]
824 numlocz
) - mathutils
.Vector(
826 numlocdistx
= abs(numlocz
[0] - numloccen
[0])
827 numlocdisty
= abs(numlocz
[1] - numloccen
[1])
828 if numlocdistx
< 60 and numlocdisty
< 16:
829 numlocz
[0] = numloc
[0]
830 numlocz
[1] = numloc
[1] - ((slide
* 12) + 15)
831 elif run
== 'OUT' or numlocbadge
< 65:
832 numlocz
[0] = numloc
[0]
833 numlocz
[1] = numloc
[1] - ((slide
* 12) + 15)
835 bgl
.glColor4f(0.0, 0.0, 0.85, 1.0)
836 bgl
.glBegin(bgl
.GL_TRIANGLE_FAN
)
837 bgl
.glVertex2f(numlocz
[0]-2, numlocz
[1]-2)
838 bgl
.glVertex2f(numlocz
[0]-2, numlocz
[1]+10)
839 bgl
.glVertex2f(numlocz
[0]+50, numlocz
[1]+10)
840 bgl
.glVertex2f(numlocz
[0]+50, numlocz
[1]-2)
842 bgl
.glColor4f(0.0, 0.0, 1.0, 1.0)
844 bgl
.glColor4f(1.0, 1.0, 1.0, 1.0)
845 blf
.position(font_id
, numlocz
[0], numlocz
[1], 0)
846 blf
.draw(font_id
, distz
)
849 bgl
.glDisable(bgl
.GL_BLEND
)
850 bgl
.glColor4f(0.0, 0.0, 0.0, 1.0)
857 bgl
.glDisable(bgl
.GL_BLEND
)
858 bgl
.glColor4f(0.0, 0.0, 0.0, 1.0)
860 np_print('04_callback_TRANS_END')
863 def scene_update(context
):
864 # np_print('00_scene_update_START')
866 if bpy
.data
.objects
.is_updated
:
867 phase
= NP020PD
.phase
869 start
= NP020PD
.start
873 startloc3d
= start
.location
874 endloc3d
= end
.location
875 NP020PD
.startloc3d
= startloc3d
876 NP020PD
.endloc3d
= endloc3d
878 # np_print('00_scene_update_END')
881 # Defining the operator that will let the user translate start and end to
882 # the desired point. It also uses some listening operators that clean up
883 # the leftovers should the user interrupt the command. Many thanks to
884 # CoDEmanX and lukas_t:
887 class NP020PDRunTranslate(bpy
.types
.Operator
):
888 bl_idname
= 'object.np_pd_run_translate'
889 bl_label
= 'NP PD Run Translate'
890 bl_options
= {'INTERNAL'}
892 np_print('04_run_TRANS_START')
895 def modal(self
, context
, event
):
896 context
.area
.tag_redraw()
898 selob
= NP020PD
.selob
899 start
= NP020PD
.start
901 phase
= NP020PD
.phase
904 bpy
.ops
.transform
.translate('INVOKE_DEFAULT')
905 np_print('04_run_TRANS_count_1_INVOKE_DEFAULT')
907 elif event
.type in ('LEFTMOUSE', 'NUMPAD_ENTER') and event
.value
== 'RELEASE':
908 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
909 NP020PD
.flag
= 'PASS'
910 np_print('04_run_TRANS_left_release_FINISHED')
913 elif event
.type == 'RET' and event
.value
== 'RELEASE':
914 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
915 if bpy
.context
.tool_settings
.snap_element
== 'VERTEX':
916 bpy
.context
.tool_settings
.snap_element
= 'EDGE'
917 NP020PD
.snap
= 'EDGE'
918 elif bpy
.context
.tool_settings
.snap_element
== 'EDGE':
919 bpy
.context
.tool_settings
.snap_element
= 'FACE'
920 NP020PD
.snap
= 'FACE'
921 elif bpy
.context
.tool_settings
.snap_element
== 'FACE':
922 bpy
.context
.tool_settings
.snap_element
= 'VERTEX'
923 NP020PD
.snap
= 'VERTEX'
924 NP020PD
.flag
= 'TRANSLATE'
925 np_print('04_run_TRANS_enter_PASS')
928 elif event
.type == 'SPACE':
929 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
932 NP020PD
.flag
= 'NAVIGATE'
933 np_print('04_run_TRANS_space_FINISHED_flag_NAVIGATE')
936 elif event
.type in ('ESC', 'RIGHTMOUSE'):
937 # this actually begins when user RELEASES esc or rightmouse, PRESS is
938 # taken by transform.translate operator
939 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
940 bpy
.ops
.object.select_all(action
='DESELECT')
941 start
.select_set(True)
943 bpy
.ops
.object.delete('EXEC_DEFAULT')
946 NP020PD
.startloc3d
= (0.0, 0.0, 0.0)
947 NP020PD
.endloc3d
= (0.0, 0.0, 0.0)
952 NP020PD
.flag
= 'TRANSLATE'
953 NP020PD
.snap
= 'VERTEX'
954 bpy
.context
.tool_settings
.use_snap
= NP020PD
.use_snap
955 bpy
.context
.tool_settings
.snap_element
= NP020PD
.snap_element
956 bpy
.context
.tool_settings
.snap_target
= NP020PD
.snap_target
957 bpy
.context
.space_data
.pivot_point
= NP020PD
.pivot_point
958 bpy
.context
.space_data
.transform_orientation
= NP020PD
.trans_orient
959 bpy
.context
.space_data
.show_manipulator
= NP020PD
.show_manipulator
960 if NP020PD
.acob
is not None:
961 bpy
.context
.view_layer
.objects
.active
= NP020PD
.acob
962 bpy
.ops
.object.mode_set(mode
=NP020PD
.edit_mode
)
963 np_print('04_run_TRANS_esc_right_CANCELLED')
966 np_print('04_run_TRANS_PASS_THROUGH')
967 return{'PASS_THROUGH'}
969 def invoke(self
, context
, event
):
971 np_print('04_run_TRANS_INVOKE_a')
972 np_print('flag=', flag
)
973 if flag
== 'TRANSLATE':
974 if context
.area
.type == 'VIEW_3D':
975 args
= (self
, context
)
976 self
._handle
= bpy
.types
.SpaceView3D
.draw_handler_add(
977 draw_callback_px_TRANS
, args
, 'WINDOW', 'POST_PIXEL')
978 context
.window_manager
.modal_handler_add(self
)
979 np_print('04_run_TRANS_INVOKE_a_RUNNING_MODAL')
980 return {'RUNNING_MODAL'}
984 "View3D not found, cannot run operator")
985 np_print('04_run_TRANS_INVOKE_a_CANCELLED')
988 np_print('04_run_TRANS_INVOKE_a_FINISHED')
992 # Defining the operator that will draw the graphicall reprezentation of
993 # distance in navigation mode if user calls it:
996 def draw_callback_px_NAV(self
, context
):
998 np_print('05_callback_NAV_START')
1000 addon_prefs
= context
.preferences
.addons
[__package__
].preferences
1002 scale
= addon_prefs
.nppd_scale
1003 badge
= addon_prefs
.nppd_badge
1004 step
= addon_prefs
.nppd_step
1005 info
= addon_prefs
.nppd_info
1006 clip
= addon_prefs
.nppd_clip
1008 if addon_prefs
.nppd_col_line_main_DEF
== False:
1009 col_line_main
= addon_prefs
.nppd_col_line_main
1011 col_line_main
= (1.0, 1.0, 1.0, 1.0)
1013 if addon_prefs
.nppd_col_line_shadow_DEF
== False:
1014 col_line_shadow
= addon_prefs
.nppd_col_line_shadow
1016 col_line_shadow
= (0.1, 0.1, 0.1, 0.25)
1018 if addon_prefs
.nppd_col_num_main_DEF
== False:
1019 col_num_main
= addon_prefs
.nppd_col_num_main
1021 col_num_main
= (0.95, 0.95, 0.95, 1.0)
1023 if addon_prefs
.nppd_col_num_shadow_DEF
== False:
1024 col_num_shadow
= addon_prefs
.nppd_col_num_shadow
1026 col_num_shadow
= (0.0, 0.0, 0.0, 0.75)
1028 if addon_prefs
.nppd_suffix
== 'None':
1031 elif addon_prefs
.nppd_suffix
== 'km':
1034 elif addon_prefs
.nppd_suffix
== 'm':
1037 elif addon_prefs
.nppd_suffix
== 'cm':
1040 elif addon_prefs
.nppd_suffix
== 'mm':
1043 elif addon_prefs
.nppd_suffix
== 'nm':
1046 elif addon_prefs
.nppd_suffix
== "'":
1049 elif addon_prefs
.nppd_suffix
== '"':
1052 elif addon_prefs
.nppd_suffix
== 'thou':
1055 # Calculating the 3d points for the graphical line while in NAVIGATE flag:
1056 phase
= NP020PD
.phase
1057 region
= context
.region
1058 rv3d
= context
.region_data
1060 view_vector
= view3d_utils
.region_2d_to_vector_3d(region
, rv3d
, co2d
)
1061 pointloc
= view3d_utils
.region_2d_to_origin_3d(
1062 region
, rv3d
, co2d
) + view_vector
/ 5
1064 np_print('phase=', phase
)
1066 startloc3d
= (0.0, 0.0, 0.0)
1067 endloc3d
= (0.0, 0.0, 0.0)
1070 startloc3d
= NP020PD
.startloc3d
1073 # Calculating the 2D points for the graphical line while in NAVIGATE flag
1076 startloc2d
= view3d_utils
.location_3d_to_region_2d(
1077 region
, rv3d
, startloc3d
)
1078 endloc2d
= view3d_utils
.location_3d_to_region_2d(region
, rv3d
, endloc3d
)
1080 if startloc2d
is None:
1081 startloc2d
= (0.0, 0.0)
1082 endloc2d
= (0.0, 0.0)
1083 np_print(startloc2d
, endloc2d
)
1085 dist
= (mathutils
.Vector(endloc3d
) - mathutils
.Vector(startloc3d
))
1086 dist
= dist
.length
* scale
1087 if suffix
is not None:
1088 dist
= str(abs(round(dist
, 2))) + suffix
1090 dist
= str(abs(round(dist
, 2)))
1094 # This is for correcting the position of the numerical on the screen if
1095 # the endpoints are far out of screen:
1097 startx
= startloc2d
[0]
1098 starty
= startloc2d
[1]
1101 if startx
> region
.width
:
1102 startx
= region
.width
1105 if starty
> region
.height
:
1106 starty
= region
.height
1109 if endx
> region
.width
:
1113 if endy
> region
.height
:
1114 endy
= region
.height
1117 numloc
.append((startx
+ endx
) / 2)
1118 numloc
.append((starty
+ endy
) / 2)
1121 instruct
= 'navigate for better placement of start point'
1124 instruct
= 'navigate for better placement of end point'
1128 bgl
.glEnable(bgl
.GL_BLEND
)
1130 # ON-SCREEN INSTRUCTIONS:
1132 keys_aff
= 'MMB, SCROLL - navigate'
1133 keys_nav
= 'LMB, SPACE - leave navigate'
1134 keys_neg
= 'ESC, RMB - quit'
1136 display_instructions(region
, rv3d
, instruct
, keys_aff
, keys_nav
, keys_neg
)
1141 bgl
.glColor4f(*col_line_shadow
)
1142 bgl
.glLineWidth(1.4)
1143 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
1144 bgl
.glVertex2f((startloc2d
[0] - 1), (startloc2d
[1] - 1))
1145 bgl
.glVertex2f((endloc2d
[0] - 1), (endloc2d
[1] - 1))
1148 bgl
.glColor4f(*col_line_main
)
1149 bgl
.glLineWidth(1.4)
1150 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
1151 bgl
.glVertex2f(*startloc2d
)
1152 bgl
.glVertex2f(*endloc2d
)
1157 # Drawing the small badge near the cursor with the basic instructions:
1161 square
= [[17, 30], [17, 40], [27, 40], [27, 30]]
1162 rectangle
= [[27, 30], [27, 40], [67, 40], [67, 30]]
1163 arrow
= [[20, 33], [18, 35], [20, 37], [18, 35],
1164 [26, 35], [24, 33], [26, 35], [24, 37]]
1165 dots1
= [[19, 31], [20, 31]]
1166 dots2
= [[22, 31], [23, 31]]
1167 dots3
= [[25, 31], [26, 31]]
1172 co
[0] = round((co
[0] * size
), 0) - 20 + co2d
[0]
1173 co
[1] = round((co
[1] * size
), 0) - 50 + co2d
[1]
1174 for co
in rectangle
:
1175 co
[0] = round((co
[0] * size
), 0) - 20 + co2d
[0]
1176 co
[1] = round((co
[1] * size
), 0) - 50 + co2d
[1]
1178 co
[0] = round((co
[0] * size
), 0) - 20 + co2d
[0]
1179 co
[1] = round((co
[1] * size
), 0) - 50 + co2d
[1]
1181 co
[0] = round((co
[0] * size
), 0) - 20 + co2d
[0]
1182 co
[1] = round((co
[1] * size
), 0) - 50 + co2d
[1]
1184 co
[0] = round((co
[0] * size
), 0) - 20 + co2d
[0]
1185 co
[1] = round((co
[1] * size
), 0) - 50 + co2d
[1]
1187 co
[0] = round((co
[0] * size
), 0) - 20 + co2d
[0]
1188 co
[1] = round((co
[1] * size
), 0) - 50 + co2d
[1]
1189 ipx
= round((ipx
* size
), 0) - 20 + co2d
[0]
1190 ipy
= round((ipy
* size
), 0) - 50 + co2d
[1]
1192 bgl
.glColor4f(0.0, 0.0, 0.0, 0.0)
1193 bgl
.glBegin(bgl
.GL_TRIANGLE_FAN
)
1195 bgl
.glVertex2f(x
, y
)
1197 bgl
.glColor4f(0.5, 0.75, 0.0, 1.0)
1198 bgl
.glBegin(bgl
.GL_TRIANGLE_FAN
)
1199 for x
, y
in rectangle
:
1200 bgl
.glVertex2f(x
, y
)
1202 bgl
.glColor4f(1.0, 1.0, 1.0, 1.0)
1203 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
1205 bgl
.glVertex2f(x
, y
)
1207 bgl
.glColor4f(1.0, 1.0, 1.0, 1.0)
1208 blf
.position(font_id
, ipx
, ipy
, 0)
1209 blf
.size(font_id
, ipsize
, 72)
1210 blf
.draw(font_id
, 'NAVIGATE')
1211 if step
== 'continuous':
1212 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
1214 bgl
.glVertex2f(x
, y
)
1216 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
1218 bgl
.glVertex2f(x
, y
)
1220 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
1222 bgl
.glVertex2f(x
, y
)
1225 # NUMERICAL DISTANCE:
1227 bgl
.glColor4f(*col_num_shadow
)
1230 blf
.size(font_id
, 20, 72)
1231 blf
.position(font_id
, (numloc
[0] - 1), (numloc
[1] - 1), 0)
1232 blf
.draw(font_id
, dist
)
1234 bgl
.glColor4f(*col_num_main
)
1237 blf
.size(font_id
, 20, 72)
1238 blf
.position(font_id
, numloc
[0], numloc
[1], 0)
1239 blf
.draw(font_id
, dist
)
1242 bgl
.glDisable(bgl
.GL_BLEND
)
1243 bgl
.glColor4f(0.0, 0.0, 0.0, 1.0)
1247 bgl
.glDisable(bgl
.GL_BLEND
)
1248 bgl
.glColor4f(0.0, 0.0, 0.0, 1.0)
1249 np_print('05_callback_NAV_END')
1252 # Defining the operator that will enable navigation if user calls it:
1254 class NP020PDRunNavigate(bpy
.types
.Operator
):
1255 bl_idname
= "object.np_pd_run_navigate"
1256 bl_label
= "NP PD Run Navigate"
1257 bl_options
= {'INTERNAL'}
1259 def modal(self
, context
, event
):
1260 np_print('05_run_NAV_START')
1261 context
.area
.tag_redraw()
1262 selob
= NP020PD
.selob
1263 start
= NP020PD
.start
1265 phase
= NP020PD
.phase
1267 if event
.type == 'MOUSEMOVE':
1268 np_print('05_run_NAV_mousemove_a')
1269 self
.co2d
= ((event
.mouse_region_x
, event
.mouse_region_y
))
1270 np_print('05_run_NAV_mousemove_b')
1272 elif event
.type in {'LEFTMOUSE', 'SPACE'} and event
.value
== 'PRESS':
1273 np_print('05_run_NAV_left_space_press_START')
1274 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
1275 self
.co2d
= ((event
.mouse_region_x
, event
.mouse_region_y
))
1276 phase
= NP020PD
.phase
1277 region
= context
.region
1278 rv3d
= context
.region_data
1280 view_vector
= view3d_utils
.region_2d_to_vector_3d(
1282 pointloc
= view3d_utils
.region_2d_to_origin_3d(
1283 region
, rv3d
, co2d
) + view_vector
/ 5
1284 start
= NP020PD
.start
1288 np_print('phase=', phase
)
1290 startloc3d
= (0.0, 0.0, 0.0)
1291 endloc3d
= (0.0, 0.0, 0.0)
1292 start
.location
= pointloc
1293 end
.location
= pointloc
1295 startloc3d
= NP020PD
.startloc3d
1297 end
.location
= pointloc
1298 NP020PD
.start
= start
1300 NP020PD
.startloc3d
= startloc3d
1301 NP020PD
.endloc3d
= endloc3d
1302 NP020PD
.flag
= 'TRANSLATE'
1303 np_print('05_run_NAV_left_space_press_FINISHED_flag_TRANSLATE')
1306 elif event
.type in ('ESC', 'RIGHTMOUSE'):
1307 np_print('05_run_NAV_esc_right_any_START')
1308 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
1309 bpy
.ops
.object.select_all(action
='DESELECT')
1312 start
.select_set(True)
1313 end
.select_set(True)
1314 bpy
.ops
.object.delete('EXEC_DEFAULT')
1317 NP020PD
.startloc3d
= (0.0, 0.0, 0.0)
1318 NP020PD
.endloc3d
= (0.0, 0.0, 0.0)
1320 NP020PD
.start
= None
1323 NP020PD
.flag
= 'TRANSLATE'
1324 NP020PD
.snap
= 'VERTEX'
1325 bpy
.context
.tool_settings
.use_snap
= NP020PD
.use_snap
1326 bpy
.context
.tool_settings
.snap_element
= NP020PD
.snap_element
1327 bpy
.context
.tool_settings
.snap_target
= NP020PD
.snap_target
1328 bpy
.context
.space_data
.pivot_point
= NP020PD
.pivot_point
1329 bpy
.context
.space_data
.transform_orientation
= NP020PD
.trans_orient
1330 bpy
.context
.space_data
.show_manipulator
= NP020PD
.show_manipulator
1331 if NP020PD
.acob
is not None:
1332 bpy
.context
.view_layer
.objects
.active
= NP020PD
.acob
1333 bpy
.ops
.object.mode_set(mode
=NP020PD
.edit_mode
)
1334 np_print('05_run_NAV_esc_right_any_CANCELLED')
1337 elif event
.type in {'MIDDLEMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE'}:
1338 np_print('05_run_NAV_middle_wheel_any_PASS_THROUGH')
1339 return {'PASS_THROUGH'}
1340 np_print('05_run_NAV_RUNNING_MODAL')
1341 return {'RUNNING_MODAL'}
1343 def invoke(self
, context
, event
):
1344 np_print('05_run_NAV_INVOKE_a')
1346 np_print('flag=', flag
)
1347 self
.co2d
= ((event
.mouse_region_x
, event
.mouse_region_y
))
1348 if flag
== 'NAVIGATE':
1349 args
= (self
, context
)
1350 self
._handle
= bpy
.types
.SpaceView3D
.draw_handler_add(
1351 draw_callback_px_NAV
, args
, 'WINDOW', 'POST_PIXEL')
1352 context
.window_manager
.modal_handler_add(self
)
1353 np_print('05_run_NAV_INVOKE_a_RUNNING_MODAL')
1354 return {'RUNNING_MODAL'}
1356 np_print('05_run_NAV_INVOKE_a_FINISHED')
1360 # Changing the mode of operating and leaving start point at the first
1361 # snap, continuing with just the end point:
1363 class NP020PDChangePhase(bpy
.types
.Operator
):
1364 bl_idname
= "object.np_pd_change_phase"
1365 bl_label
= "NP PD Change Phase"
1366 bl_options
= {'INTERNAL'}
1368 def execute(self
, context
):
1369 np_print('06_change_phase_START')
1371 np_print('NP020PD.phase=', NP020PD
.phase
)
1372 start
= NP020PD
.start
1374 startloc3d
= start
.location
1375 endloc3d
= end
.location
1376 NP020PD
.startloc3d
= startloc3d
1377 NP020PD
.endloc3d
= endloc3d
1378 bpy
.ops
.object.select_all(action
='DESELECT')
1379 end
.select_set(True)
1380 bpy
.context
.tool_settings
.use_snap
= False
1381 bpy
.context
.tool_settings
.snap_element
= NP020PD
.snap
1382 bpy
.context
.tool_settings
.snap_target
= 'ACTIVE'
1383 bpy
.context
.space_data
.pivot_point
= 'ACTIVE_ELEMENT'
1384 bpy
.context
.space_data
.transform_orientation
= 'GLOBAL'
1385 NP020PD
.flag
= 'TRANSLATE'
1386 np_print('06_change_phase_END_flag_TRANSLATE')
1390 # Defining the operator that will hold the end result in the viewport and let the user navigate around it for documentation
1392 class NP020PDHoldResult(bpy
.types
.Operator
):
1393 bl_idname
= 'object.np_pd_hold_result'
1394 bl_label
= 'NP PD Hold Result'
1395 bl_options
= {'INTERNAL'}
1397 np_print('07_HOLD_START')
1399 def modal(self
, context
, event
):
1400 context
.area
.tag_redraw()
1401 selob
= NP020PD
.selob
1402 start
= NP020PD
.start
1405 if event
.type == 'MOUSEMOVE':
1406 self
.co2d
= ((event
.mouse_region_x
, event
.mouse_region_y
))
1408 elif event
.type in ('LEFTMOUSE', 'RET', 'NUMPAD_ENTER', 'SPACE') and event
.value
== 'PRESS':
1409 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
1410 NP020PD
.flag
= 'PASS'
1411 np_print('07_HOLD_left_release_FINISHED')
1414 elif event
.type in ('ESC', 'RIGHTMOUSE'):
1415 # this actually begins when user RELEASES esc or rightmouse, PRESS is
1416 # taken by transform.translate operator
1417 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
1418 bpy
.ops
.object.select_all(action
='DESELECT')
1419 start
.select_set(True)
1420 end
.select_set(True)
1421 bpy
.ops
.object.delete('EXEC_DEFAULT')
1424 NP020PD
.startloc3d
= (0.0, 0.0, 0.0)
1425 NP020PD
.endloc3d
= (0.0, 0.0, 0.0)
1427 NP020PD
.start
= None
1430 NP020PD
.flag
= 'TRANSLATE'
1431 NP020PD
.snap
= 'VERTEX'
1432 bpy
.context
.tool_settings
.use_snap
= NP020PD
.use_snap
1433 bpy
.context
.tool_settings
.snap_element
= NP020PD
.snap_element
1434 bpy
.context
.tool_settings
.snap_target
= NP020PD
.snap_target
1435 bpy
.context
.space_data
.pivot_point
= NP020PD
.pivot_point
1436 bpy
.context
.space_data
.transform_orientation
= NP020PD
.trans_orient
1437 bpy
.context
.space_data
.show_manipulator
= NP020PD
.show_manipulator
1438 if NP020PD
.acob
is not None:
1439 bpy
.context
.view_layer
.objects
.active
= NP020PD
.acob
1440 bpy
.ops
.object.mode_set(mode
=NP020PD
.edit_mode
)
1441 np_print('07_HOLD_esc_right_CANCELLED')
1444 np_print('07_HOLD_PASS_THROUGH')
1445 return{'PASS_THROUGH'}
1447 def invoke(self
, context
, event
):
1449 np_print('flag=', flag
)
1450 np_print('07_HOLD_INVOKE_a')
1451 addon_prefs
= context
.preferences
.addons
[__package__
].preferences
1452 hold
= addon_prefs
.nppd_hold
1454 if context
.area
.type == 'VIEW_3D':
1455 args
= (self
, context
)
1456 self
._handle
= bpy
.types
.SpaceView3D
.draw_handler_add(
1457 draw_callback_px_TRANS
, args
, 'WINDOW', 'POST_PIXEL')
1458 context
.window_manager
.modal_handler_add(self
)
1459 NP020PD
.flag
= 'HOLD'
1460 np_print('07_HOLD_INVOKE_a_RUNNING_MODAL')
1461 return {'RUNNING_MODAL'}
1465 "View3D not found, cannot run operator")
1466 np_print('07_HOLD_INVOKE_a_CANCELLED')
1467 return {'CANCELLED'}
1469 np_print('07_HOLD_INVOKE_a_FINISHED')
1473 # Deleting the anchors after succesfull translation and reselecting
1474 # previously selected objects:
1476 class NP020PDDeletePoints(bpy
.types
.Operator
):
1477 bl_idname
= "object.np_pd_delete_points"
1478 bl_label
= "NP PD Delete Points"
1479 bl_options
= {'INTERNAL'}
1481 def execute(self
, context
):
1482 addon_prefs
= context
.preferences
.addons
[__package__
].preferences
1484 step
= addon_prefs
.nppd_step
1485 info
= addon_prefs
.nppd_info
1486 clip
= addon_prefs
.nppd_clip
1487 np_print('07_delete_points_START')
1490 self
.report({'INFO'}, dist
)
1492 startloc3d
= NP020PD
.startloc3d
1493 endloc3d
= NP020PD
.endloc3d
1496 endloc3d
) - mathutils
.Vector(
1498 le
= str(abs(round(le
, 4)))
1499 bpy
.context
.window_manager
.clipboard
= le
1500 selob
= NP020PD
.selob
1501 start
= NP020PD
.start
1503 bpy
.ops
.object.select_all(action
='DESELECT')
1504 start
.select_set(True)
1505 end
.select_set(True)
1506 bpy
.ops
.object.delete('EXEC_DEFAULT')
1509 NP020PD
.startloc3d
= (0.0, 0.0, 0.0)
1510 NP020PD
.endloc3d
= (0.0, 0.0, 0.0)
1512 if step
== 'simple':
1513 NP020PD
.snap
= 'VERTEX'
1514 NP020PD
.flag
= 'TRANSLATE'
1515 NP020PD
.start
= None
1518 bpy
.context
.tool_settings
.use_snap
= NP020PD
.use_snap
1519 bpy
.context
.tool_settings
.snap_element
= NP020PD
.snap_element
1520 bpy
.context
.tool_settings
.snap_target
= NP020PD
.snap_target
1521 bpy
.context
.space_data
.pivot_point
= NP020PD
.pivot_point
1522 bpy
.context
.space_data
.transform_orientation
= NP020PD
.trans_orient
1523 bpy
.context
.space_data
.show_manipulator
= NP020PD
.show_manipulator
1524 if NP020PD
.acob
is not None:
1525 bpy
.context
.view_layer
.objects
.active
= NP020PD
.acob
1526 bpy
.ops
.object.mode_set(mode
=NP020PD
.edit_mode
)
1528 if step
== 'simple':
1529 np_print('07_delete_points_END_cancelled')
1530 return {'CANCELLED'}
1531 if step
== 'continuous':
1532 np_print('07_delete_points_END_FINISHED')
1537 # This is the actual addon process, the algorithm that defines the order
1538 # of operator activation inside the main macro:
1542 #bpy.app.handlers.scene_update_post.append(scene_update)
1544 for i
in range(1, 15):
1545 NP020PointDistance
.define('OBJECT_OT_np_pd_get_selection')
1546 NP020PointDistance
.define('OBJECT_OT_np_pd_read_mouse_loc')
1547 NP020PointDistance
.define('OBJECT_OT_np_pd_add_points')
1548 for i
in range(1, 15):
1549 NP020PointDistance
.define('OBJECT_OT_np_pd_run_translate')
1550 NP020PointDistance
.define('OBJECT_OT_np_pd_run_navigate')
1551 NP020PointDistance
.define('OBJECT_OT_np_pd_change_phase')
1552 for i
in range(1, 15):
1553 NP020PointDistance
.define('OBJECT_OT_np_pd_run_translate')
1554 NP020PointDistance
.define('OBJECT_OT_np_pd_run_navigate')
1555 NP020PointDistance
.define('OBJECT_OT_np_pd_hold_result')
1556 NP020PointDistance
.define('OBJECT_OT_np_pd_delete_points')
1561 # bpy.app.handlers.scene_update_post.remove(scene_update)