3 # ##### BEGIN GPL LICENSE BLOCK #####
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software Foundation,
17 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 # ##### END GPL LICENSE BLOCK #####
25 Makes a copy (duplicate) of objects using snap points. Emulates the functionality of the standard 'copy' command in CAD applications, with vertex snapping. Optionally, using selected objects and last distance used, makes an array of selected objects.
30 Unzip and place .py file to scripts / addons_contrib folder. In User Preferences / Addons tab, search with Testing filter - NP Point Copy and check the box.
31 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.
36 After successful installation of the addon, the NP Point Copy operator should be registered in your system. Enter User Preferences / Input, and under that, 3DView / Object mode. At the bottom of the list click the 'Add new' button. In the operator field type object.np_point_copy_xxx (xxx being the number of the version) and assign a shortcut key of your preference. At the moment i am using 'C' for 'copy', as in standard CAD applications. I rarely use circle selection so letter 'C' is free.
41 You can run the operator with spacebar search - NP Point Copy, or shortcut key if you assigned it.
42 Select a point anywhere in the scene (holding CTRL enables snapping). This will be your 'take' point.
43 Move your mouse and click to a point anywhere in the scene with the left mouse button (LMB), in relation to the 'take' point and the operator will duplicate the selected objects at that position (again CTRL - snap enables snapping to objects around the scene). You can continue duplicating objects in the same way. When you want to finish the process, press ESC or RMB. If you want to make an array of the copied objects in relation to the last pair, press the 'ENTER' button (ENT). The command will automatically read the direction and the distance between the last pair of copied objects and present an interface to specify the number of arrayed copies. You specify the number with CTRL + mouse scroll, with the possibility to go below the amount of 2 which changes the mode of array to division. You confirm the array with RMB / ENTER / TAB key or cancel it with ESC. Pressing RMB at the end will confirm the array and keep it as a modifier in the modifier stack, ENTER will apply the modifier as a single object and remove the modifier, while TAB would apply the modifier as an array of separate individual objects and remove the modifier from the modifier stack.
44 If at any point you lose sight of the next point you want to snap to, you can press SPACE to go to NAVIGATION mode in which you can change the point of view. When your next point is clearly in your field of view, you return to normal mode by pressing SPACE again or LMB.
45 Middle mouse button (MMB) enables axis constraint during snapping, while numpad keys enable numerical input for the copy distance.
50 Below the addon name in the user preferences / addon tab, you can find a couple of settings that control the behavior of the addon:
52 Unit scale: Distance multiplier for various unit scenarios
53 Suffix: Unit abbreviation after the numerical distance
54 Custom colors: Default or custom colors for graphical elements
55 Mouse badge: Option to display a small cursor label
58 IMPORTANT PERFORMANCE NOTES:
65 'name':'NP 020 Point Copy',
66 'author':'Okavango & the Blenderartists community',
68 'blender': (2, 75, 0),
71 'description': 'Duplicates selected objects using "take" and "place" snap points',
73 'category': '3D View'}
81 from bpy_extras
import view3d_utils
82 from bpy
.app
.handlers
import persistent
83 from mathutils
import Vector
, Matrix
84 from blf
import ROTATION
85 from math
import radians
86 from bpy
.props
import *
88 from .utils_geometry
import *
89 from .utils_graphics
import *
90 from .utils_function
import *
92 # Defining the main class - the macro:
94 class NP020PointCopy(bpy
.types
.Macro
):
95 bl_idname
= 'object.np_020_point_copy'
96 bl_label
= 'NP 020 Point Copy'
100 # 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:
106 takeloc3d
= (0.0,0.0,0.0)
107 placeloc3d
= (0.0,0.0,0.0)
111 deltavec
= Vector ((0, 0, 0))
112 deltavec_safe
= Vector ((0, 0, 0))
116 # Defining the scene update algorithm that will track the state of the objects during modal transforms, which is otherwise impossible:
119 def NPPC_scene_update(context
):
121 #np_print('00_SceneUpdate_START')
122 if bpy
.data
.objects
.is_updated
:
123 np_print('NPPC_update1')
126 #np_print(mode, flag)
128 place
= NP020PC
.place
129 if flag
in ('RUNTRANSZERO', 'RUNTRANSFIRST','RUNTRANSNEXT', 'NAVTRANSZERO', 'NAVTRANSFIRST', 'NAVTRANSNEXT'):
130 np_print('NPPC_update2')
131 NP020PC
.takeloc3d
= take
.location
132 NP020PC
.placeloc3d
= place
.location
134 #np_print('00_SceneUpdate_FINISHED')
137 # 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.
139 class NPPCGetContext(bpy
.types
.Operator
):
140 bl_idname
= 'object.np_pc_get_context'
141 bl_label
= 'NP PC Get Context'
142 bl_options
= {'INTERNAL'}
144 def execute(self
, context
):
145 if bpy
.context
.selected_objects
== []:
146 self
.report({'WARNING'}, "Please select objects first")
148 NP020PC
.use_snap
= copy
.deepcopy(bpy
.context
.tool_settings
.use_snap
)
149 NP020PC
.snap_element
= copy
.deepcopy(bpy
.context
.tool_settings
.snap_element
)
150 NP020PC
.snap_target
= copy
.deepcopy(bpy
.context
.tool_settings
.snap_target
)
151 NP020PC
.pivot_point
= copy
.deepcopy(bpy
.context
.space_data
.pivot_point
)
152 NP020PC
.trans_orient
= copy
.deepcopy(bpy
.context
.space_data
.transform_orientation
)
153 NP020PC
.curloc
= copy
.deepcopy(bpy
.context
.scene
.cursor
.location
)
154 NP020PC
.acob
= bpy
.context
.active_object
155 if bpy
.context
.mode
== 'OBJECT':
156 NP020PC
.edit_mode
= 'OBJECT'
157 elif bpy
.context
.mode
in ('EDIT_MESH', 'EDIT_CURVE', 'EDIT_SURFACE', 'EDIT_TEXT', 'EDIT_ARMATURE', 'EDIT_METABALL', 'EDIT_LATTICE'):
158 NP020PC
.edit_mode
= 'EDIT'
159 elif bpy
.context
.mode
== 'POSE':
160 NP020PC
.edit_mode
= 'POSE'
161 elif bpy
.context
.mode
== 'SCULPT':
162 NP020PC
.edit_mode
= 'SCULPT'
163 elif bpy
.context
.mode
== 'PAINT_WEIGHT':
164 NP020PC
.edit_mode
= 'WEIGHT_PAINT'
165 elif bpy
.context
.mode
== 'PAINT_TEXTURE':
166 NP020PC
.edit_mode
= 'TEXTURE_PAINT'
167 elif bpy
.context
.mode
== 'PAINT_VERTEX':
168 NP020PC
.edit_mode
= 'VERTEX_PAINT'
169 elif bpy
.context
.mode
== 'PARTICLE':
170 NP020PC
.edit_mode
= 'PARTICLE_EDIT'
172 # Changing to OBJECT mode which will be the context for the procedure:
173 if bpy
.context
.mode
not in ('OBJECT'):
174 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
175 # De-selecting objects in prepare for other processes in the script:
176 bpy
.ops
.object.select_all(action
= 'DESELECT')
177 np_print('01_ReadContext_FINISHED', ';', 'flag = ', NP020PC
.flag
)
181 # Defining the operator for aquiring the list of selected objects and storing them for later re-calls:
183 class NPPCGetSelection(bpy
.types
.Operator
):
184 bl_idname
= 'object.np_pc_get_selection'
185 bl_label
= 'NP PC Get Selection'
186 bl_options
= {'INTERNAL'}
188 def execute(self
, context
):
189 # Reading and storing the selection:
190 NP020PC
.selob
= bpy
.context
.selected_objects
194 # 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 'take' and 'place' points under the mouse:
196 class NPPCGetMouseloc(bpy
.types
.Operator
):
197 bl_idname
= 'object.np_pc_get_mouseloc'
198 bl_label
= 'NP PC Get Mouseloc'
199 bl_options
= {'INTERNAL'}
201 def modal(self
, context
, event
):
202 region
= context
.region
203 rv3d
= context
.region_data
204 co2d
= ((event
.mouse_region_x
, event
.mouse_region_y
))
205 view_vector
= view3d_utils
.region_2d_to_vector_3d(region
, rv3d
, co2d
)
206 enterloc
= view3d_utils
.region_2d_to_origin_3d(region
, rv3d
, co2d
) + view_vector
/5
207 NP020PC
.enterloc
= copy
.deepcopy(enterloc
)
208 #np_print('02_RadMouseloc_FINISHED', ';', 'flag = ', NP020PC.flag)
211 def invoke(self
,context
,event
):
212 args
= (self
,context
)
213 context
.window_manager
.modal_handler_add(self
)
214 #np_print('02_ReadMouseloc_INVOKED_FINISHED', ';', 'flag = ', NP020PC.flag)
215 return {'RUNNING_MODAL'}
218 # Defining the operator that will generate 'take' and 'place' points at the spot marked by mouse, preparing for translation:
220 class NPPCAddHelpers(bpy
.types
.Operator
):
221 bl_idname
= 'object.np_pc_add_helpers'
222 bl_label
= 'NP PC Add Helpers'
223 bl_options
= {'INTERNAL'}
225 def execute(self
, context
):
226 np_print('03_AddHelpers_START', ';', 'flag = ', NP020PC
.flag
)
227 enterloc
= NP020PC
.enterloc
228 bpy
.ops
.object.add(type = 'MESH',location
= enterloc
)
229 take
= bpy
.context
.active_object
230 take
.name
= 'NP_PC_take'
232 bpy
.ops
.object.add(type = 'MESH',location
= enterloc
)
233 place
= bpy
.context
.active_object
234 place
.name
= 'NP_PC_place'
235 NP020PC
.place
= place
239 # Defining the operator that will change some of the system settings and prepare objects for the operation:
241 class NPPCPrepareContext(bpy
.types
.Operator
):
242 bl_idname
= 'object.np_pc_prepare_context'
243 bl_label
= 'NP PC Prepare Context'
244 bl_options
= {'INTERNAL'}
246 def execute(self
, context
):
248 place
= NP020PC
.place
249 take
.select_set(True)
250 place
.select_set(True)
251 bpy
.context
.view_layer
.objects
.active
= place
252 bpy
.context
.tool_settings
.use_snap
= False
253 bpy
.context
.tool_settings
.snap_element
= 'VERTEX'
254 bpy
.context
.tool_settings
.snap_target
= 'ACTIVE'
255 bpy
.context
.space_data
.pivot_point
= 'ACTIVE_ELEMENT'
256 bpy
.context
.space_data
.transform_orientation
= 'GLOBAL'
257 NP020PC
.flag
= 'RUNTRANSZERO'
261 # Defining the operator that will let the user translate take and place points to the desired 'take' location. It also uses some listening operators that clean up the leftovers should the user interrupt the command. Many thanks to CoDEmanX and lukas_t:
263 class NPPCRunTranslate(bpy
.types
.Operator
):
264 bl_idname
= 'object.np_pc_run_translate'
265 bl_label
= 'NP PC Run Translate'
266 bl_options
= {'INTERNAL'}
268 #np_print('04_RunTrans_START',';','NP020PC.flag = ', NP020PC.flag)
271 def modal(self
,context
,event
):
272 context
.area
.tag_redraw()
275 place
= NP020PC
.place
276 selob
= NP020PC
.selob
280 bpy
.ops
.transform
.translate('INVOKE_DEFAULT')
281 np_print('04_RunTrans_count_1_INVOKE_DEFAULT', ';', 'flag = ', NP020PC
.flag
)
283 elif event
.type in ('LEFTMOUSE','RET','NUMPAD_ENTER') and event
.value
== 'RELEASE':
284 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
285 if flag
== 'RUNTRANSZERO':
286 take
.select_set(False)
287 place
.select_set(False)
288 NP020PC
.firsttake3d
= copy
.deepcopy(take
.location
)
291 bpy
.ops
.object.duplicate()
292 NP020PC
.nextob
= bpy
.context
.selected_objects
293 NP020PC
.prevob
= selob
294 place
.select_set(True)
295 NP020PC
.flag
= 'RUNTRANSFIRST_break'
296 elif flag
== 'RUNTRANSFIRST':
297 NP020PC
.deltavec_safe
= copy
.deepcopy(NP020PC
.deltavec
)
298 np_print('deltavec_safe = ', NP020PC
.deltavec_safe
)
299 NP020PC
.ar13d
= copy
.deepcopy(take
.location
)
300 NP020PC
.ar23d
= copy
.deepcopy(place
.location
)
301 place
.select_set(False)
302 bpy
.ops
.object.duplicate()
303 prevob
= NP020PC
.prevob
304 nextob
= NP020PC
.nextob
305 NP020PC
.arob
= prevob
306 NP020PC
.prevob
= nextob
307 NP020PC
.nextob
= bpy
.context
.selected_objects
308 NP020PC
.selob
= nextob
309 take
.location
= copy
.deepcopy(place
.location
)
310 place
.select_set(True)
311 NP020PC
.flag
= 'RUNTRANSNEXT_break'
312 elif flag
== 'RUNTRANSNEXT':
313 NP020PC
.deltavec_safe
= copy
.deepcopy(NP020PC
.deltavec
)
314 np_print('deltavec_safe = ', NP020PC
.deltavec_safe
)
315 NP020PC
.ar13d
= copy
.deepcopy(take
.location
)
316 NP020PC
.ar23d
= copy
.deepcopy(place
.location
)
317 place
.select_set(False)
318 bpy
.ops
.object.duplicate()
319 prevob
= NP020PC
.prevob
320 nextob
= NP020PC
.nextob
321 NP020PC
.arob
= prevob
322 NP020PC
.prevob
= nextob
323 NP020PC
.nextob
= bpy
.context
.selected_objects
324 NP020PC
.selob
= nextob
325 take
.location
= copy
.deepcopy(place
.location
)
326 place
.select_set(True)
327 NP020PC
.flag
= 'RUNTRANSNEXT_break'
329 np_print('UNKNOWN FLAG')
330 NP020PC
.flag
= 'EXIT'
331 np_print('04_RunTrans_left_FINISHED',';','flag = ', NP020PC
.flag
)
334 elif event
.type == 'SPACE' and event
.value
== 'RELEASE':
335 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
338 self
.co2d
= ((event
.mouse_region_x
, event
.mouse_region_y
))
340 region
= context
.region
341 rv3d
= context
.region_data
342 away
= view3d_utils
.region_2d_to_origin_3d(region
, rv3d
, co2d
) - place
.location
344 placeloc3d
= NP020PC
.placeloc3d
345 awayloc
= copy
.deepcopy(placeloc3d
)
346 NP020PC
.awayloc
= awayloc
347 NP020PC
.away
= copy
.deepcopy(away
)
348 if flag
== 'RUNTRANSZERO':
349 NP020PC
.flag
= 'NAVTRANSZERO'
350 elif flag
== 'RUNTRANSFIRST':
351 nextob
= NP020PC
.nextob
354 NP020PC
.flag
= 'NAVTRANSFIRST'
355 elif flag
== 'RUNTRANSNEXT':
356 nextob
= NP020PC
.nextob
359 NP020PC
.flag
= 'NAVTRANSNEXT'
361 np_print('UNKNOWN FLAG')
362 NP020PC
.flag
= 'EXIT'
363 np_print('04_RunTrans_space_FINISHED',';','flag = ', NP020PC
.flag
)
366 elif event
.type == 'RIGHTMOUSE':
367 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
368 if flag
== 'RUNTRANSZERO':
369 NP020PC
.flag
= 'EXIT'
370 elif flag
== 'RUNTRANSFIRST':
371 place
.select_set(False)
372 prevob
= NP020PC
.prevob
373 nextob
= NP020PC
.nextob
374 bpy
.ops
.object.delete('EXEC_DEFAULT')
377 NP020PC
.selob
= prevob
378 NP020PC
.flag
= 'EXIT'
379 elif flag
== 'RUNTRANSNEXT':
380 place
.select_set(False)
381 prevob
= NP020PC
.prevob
382 nextob
= NP020PC
.nextob
383 bpy
.ops
.object.delete('EXEC_DEFAULT')
386 NP020PC
.selob
= prevob
387 NP020PC
.flag
= 'EXIT'
389 np_print('UNKNOWN FLAG')
390 NP020PC
.flag
= 'EXIT'
391 np_print('04_RunTrans_rmb_FINISHED',';','flag = ', NP020PC
.flag
)
394 elif event
.type == 'ESC':
395 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
396 if flag
== 'RUNTRANSZERO':
397 NP020PC
.flag
= 'EXIT'
398 elif flag
== 'RUNTRANSFIRST':
399 place
.select_set(False)
400 prevob
= NP020PC
.prevob
401 nextob
= NP020PC
.nextob
402 bpy
.ops
.object.delete('EXEC_DEFAULT')
405 NP020PC
.flag
= 'EXIT'
406 elif flag
== 'RUNTRANSNEXT':
407 place
.select_set(False)
408 prevob
= NP020PC
.prevob
409 nextob
= NP020PC
.nextob
410 NP020PC
.selob
= prevob
411 bpy
.ops
.object.delete('EXEC_DEFAULT')
414 NP020PC
.flag
= 'EXIT'
416 np_print('UNKNOWN FLAG')
417 NP020PC
.flag
= 'EXIT'
418 np_print('04_RunTrans_rmb_FINISHED',';','flag = ', NP020PC
.flag
)
421 np_print('04_RunTrans_count_PASS_THROUGH',';','flag = ', NP020PC
.flag
)
422 return{'PASS_THROUGH'}
424 def invoke(self
, context
, event
):
425 #np_print('04_RunTrans_INVOKE_START')
427 selob
= NP020PC
.selob
428 #np_print('flag = ', flag)
429 if context
.area
.type == 'VIEW_3D':
430 if flag
in ('RUNTRANSZERO', 'RUNTRANSFIRST', 'RUNTRANSNEXT'):
431 args
= (self
, context
)
432 self
._handle
= bpy
.types
.SpaceView3D
.draw_handler_add(DRAW_RunTranslate
, args
, 'WINDOW', 'POST_PIXEL')
433 context
.window_manager
.modal_handler_add(self
)
434 np_print('04_RunTrans_INVOKED_RUNNING_MODAL',';','flag = ', NP020PC
.flag
)
435 return {'RUNNING_MODAL'}
437 #np_print('04_RunTrans_INVOKE_DECLINED_FINISHED',';','flag = ', flag)
440 self
.report({'WARNING'}, "View3D not found, cannot run operator")
443 np_print('04_RunTrans_INVOKE_DECLINED_FINISHED',';','flag = ', NP020PC
.flag
)
447 # Defining the set of instructions that will draw the OpenGL elements on the screen during the execution of RunTranslate operator:
449 def DRAW_RunTranslate(self
, context
):
451 np_print('04_DRAW_RunTrans_START',';','flag = ', NP020PC
.flag
)
453 addon_prefs
= context
.preferences
.addons
[__package__
].preferences
456 takeloc3d
= NP020PC
.takeloc3d
457 placeloc3d
= NP020PC
.placeloc3d
459 region
= context
.region
460 rv3d
= context
.region_data
462 if flag
in ('RUNTRANSZERO', 'RUNTRANSFIRST', 'RUNTRANSNEXT'):
463 takeloc2d
= view3d_utils
.location_3d_to_region_2d(region
, rv3d
, takeloc3d
)
464 placeloc2d
= view3d_utils
.location_3d_to_region_2d(region
, rv3d
, placeloc3d
)
465 if flag
== 'NAVTRANSZERO':
466 takeloc2d
= self
.co2d
467 placeloc2d
= self
.co2d
468 if flag
in ('NAVTRANSFIRST', 'NAVTRANSNEXT'):
469 takeloc2d
= view3d_utils
.location_3d_to_region_2d(region
, rv3d
, takeloc3d
)
470 placeloc2d
= self
.co2d
473 if flag in ('RUNTRANSNEXT', 'NAVTRANSNEXT'):
474 ardist_num = NP020PC.ar23d - NP020PC.ar13d
475 ardist_num = ardist_num.length * dist_scale
476 ar12d = view3d_utils.location_3d_to_region_2d(region, rv3d, NP020PC.ar13d)
477 ar22d = view3d_utils.location_3d_to_region_2d(region, rv3d, NP020PC.ar23d)
478 ardist_num = abs(round(ardist_num,2))
479 if suffix is not None:
480 ardist = str(ardist_num)+suffix
482 ardist = str(ardist_num)
483 NP020PC.ardist = ardist
484 ardist_loc = (ar12d + ar22d) /2
488 bgl
.glEnable(bgl
.GL_BLEND
)
490 if flag
== 'RUNTRANSZERO':
491 instruct
= 'select the take point'
492 keys_aff
= 'LMB - confirm, CTRL - snap, MMB - lock axis, NUMPAD - value'
493 keys_nav
= 'SPACE - navigate'
494 keys_neg
= 'ESC / RMB - cancel copy'
497 message_main
= 'CTRL+SNAP'
502 elif flag
== 'RUNTRANSFIRST':
503 instruct
= 'select the placement point'
504 keys_aff
= 'LMB - confirm, CTRL - snap, MMB - lock axis, NUMPAD - value'
505 keys_nav
= 'SPACE - navigate'
506 keys_neg
= 'ESC / RMB - cancel copy'
509 message_main
= 'CTRL+SNAP'
514 elif flag
== 'RUNTRANSNEXT':
515 instruct
= 'select the placement point'
516 keys_aff
= 'LMB - confirm, CTRL - snap, MMB - lock axis, NUMPAD - value'
517 keys_nav
= 'SPACE - navigate'
518 keys_neg
= 'ESC / RMB - cancel current'
521 message_main
= 'CTRL+SNAP'
526 elif flag
== 'NAVTRANSZERO':
527 instruct
= 'navigate for better placement of take point'
528 keys_aff
= 'MMB / SCROLL - navigate'
529 keys_nav
= 'LMB / SPACE - leave navigate'
530 keys_neg
= 'ESC / RMB - cancel copy'
533 message_main
= 'NAVIGATE'
538 elif flag
== 'NAVTRANSFIRST':
539 instruct
= 'navigate for better selection of placement point'
540 keys_aff
= 'MMB / SCROLL - navigate'
541 keys_nav
= 'LMB / SPACE - leave navigate'
542 keys_neg
= 'ESC / RMB - cancel copy'
545 message_main
= 'NAVIGATE'
550 elif flag
== 'NAVTRANSNEXT':
551 instruct
= 'navigate for better selection of placement point'
552 keys_aff
= 'MMB / SCROLL - navigate'
553 keys_nav
= 'LMB / SPACE - leave navigate'
554 keys_neg
= 'ESC / RMB - cancel current'
557 message_main
= 'NAVIGATE'
562 # ON-SCREEN INSTRUCTIONS:
564 display_instructions(region
, rv3d
, instruct
, keys_aff
, keys_nav
, keys_neg
)
572 symbol
= [[23, 34], [23, 32], [19, 32], [19, 36], [21, 36], [21, 38], [25, 38], [25, 34], [23, 34], [23, 36], [21, 36]]
574 display_cursor_badge(co2d
, symbol
, badge_mode
, message_main
, message_aux
, aux_num
, aux_str
)
578 display_line_between_two_points(region
, rv3d
, takeloc3d
, placeloc3d
)
582 display_distance_between_two_points(region
, rv3d
, takeloc3d
, placeloc3d
)
583 NP020PC
.deltavec
= copy
.deepcopy(display_distance_between_two_points(region
, rv3d
, takeloc3d
, placeloc3d
)[0])
587 bgl
.glDisable(bgl
.GL_BLEND
)
588 bgl
.glColor4f(0.0, 0.0, 0.0, 1.0)
589 np_print('04_DRAW_RunTrans_FINISHED',';','flag = ', NP020PC
.flag
)
592 # Defining the operator that will enable navigation if user calls it:
594 class NPPCNavTranslate(bpy
.types
.Operator
):
595 bl_idname
= "object.np_pc_nav_translate"
596 bl_label
= "NP PC Nav Translate"
597 bl_options
= {'INTERNAL'}
599 np_print('04a_NavTrans_START',';','flag = ', NP020PC
.flag
)
601 def modal(self
,context
,event
):
602 context
.area
.tag_redraw()
605 place
= NP020PC
.place
607 if event
.type == 'MOUSEMOVE':
608 self
.co2d
= ((event
.mouse_region_x
, event
.mouse_region_y
))
609 region
= context
.region
610 rv3d
= context
.region_data
612 view_vector
= view3d_utils
.region_2d_to_vector_3d(region
, rv3d
, co2d
)
613 pointloc
= view3d_utils
.region_2d_to_origin_3d(region
, rv3d
, co2d
) + view_vector
* NP020PC
.away
614 NP020PC
.placeloc3d
= copy
.deepcopy(pointloc
)
615 np_print('04a_NavTrans_mousemove',';','flag = ', NP020PC
.flag
)
617 elif event
.type in {'LEFTMOUSE', 'SPACE'} and event
.value
== 'PRESS':
618 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
619 self
.co2d
= ((event
.mouse_region_x
, event
.mouse_region_y
))
620 region
= context
.region
621 rv3d
= context
.region_data
623 view_vector
= view3d_utils
.region_2d_to_vector_3d(region
, rv3d
, co2d
)
624 enterloc
= view3d_utils
.region_2d_to_origin_3d(region
, rv3d
, co2d
) + view_vector
*NP020PC
.away
625 placeloc3d
= NP020PC
.placeloc3d
626 navdelta
= enterloc
- NP020PC
.awayloc
629 np_print('flag = ', flag
)
630 if flag
== 'NAVTRANSZERO':
632 placeloc3d
= enterloc
633 take
.location
= enterloc
634 place
.location
= enterloc
635 NP020PC
.flag
= 'RUNTRANSZERO'
636 elif flag
== 'NAVTRANSFIRST':
637 takeloc3d
= NP020PC
.takeloc3d
638 placeloc3d
= enterloc
639 place
.location
= enterloc
640 nextob
= NP020PC
.nextob
643 place
.select_set(False)
644 bpy
.ops
.transform
.translate(value
= navdelta
)
645 place
.select_set(True)
646 NP020PC
.flag
= 'RUNTRANSFIRST'
647 elif flag
== 'NAVTRANSNEXT':
648 takeloc3d
= NP020PC
.takeloc3d
649 placeloc3d
= enterloc
650 place
.location
= enterloc
651 nextob
= NP020PC
.nextob
654 place
.select_set(False)
655 bpy
.ops
.transform
.translate(value
= navdelta
)
656 place
.select_set(True)
657 NP020PC
.flag
= 'RUNTRANSNEXT'
659 np_print('UNKNOWN FLAG')
660 NP020PC
.flag
= 'EXIT'
662 NP020PC
.place
= place
663 NP020PC
.takeloc3d
= takeloc3d
664 NP020PC
.placeloc3d
= placeloc3d
665 np_print('04a_NavTrans_left_space_FINISHED',';','flag = ', NP020PC
.flag
)
668 elif event
.type == 'RIGHTMOUSE':
669 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
672 if flag
== 'NAVTRANSZERO':
673 place
.select_set(False)
674 NP020PC
.flag
= 'EXIT'
675 elif flag
== 'NAVTRANSFIRST':
676 place
.select_set(False)
677 prevob
= NP020PC
.prevob
678 nextob
= NP020PC
.nextob
681 bpy
.ops
.object.delete('EXEC_DEFAULT')
684 NP020PC
.flag
= 'EXIT'
685 elif flag
== 'NAVTRANSNEXT':
686 place
.select_set(False)
687 prevob
= NP020PC
.prevob
688 nextob
= NP020PC
.nextob
691 bpy
.ops
.object.delete('EXEC_DEFAULT')
694 bpy
.ops
.object.delete('EXEC_DEFAULT')
695 NP020PC
.flag
= 'ARRAYTRANS'
697 np_print('UNKNOWN FLAG')
698 NP020PC
.flag
= 'EXIT'
699 np_print('04a_NavTrans_rmb_FINISHED',';','flag = ', NP020PC
.flag
)
702 elif event
.type == 'ESC':
703 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
706 if flag
== 'NAVTRANSZERO':
707 place
.select_set(False)
708 NP020PC
.flag
= 'EXIT'
709 elif flag
== 'NAVTRANSFIRST':
710 place
.select_set(False)
711 prevob
= NP020PC
.prevob
712 nextob
= NP020PC
.nextob
715 bpy
.ops
.object.delete('EXEC_DEFAULT')
718 NP020PC
.flag
= 'EXIT'
719 elif flag
== 'NAVTRANSNEXT':
720 place
.select_set(False)
721 prevob
= NP020PC
.prevob
722 nextob
= NP020PC
.nextob
723 NP020PC
.selob
= prevob
726 bpy
.ops
.object.delete('EXEC_DEFAULT')
729 NP020PC
.flag
= 'EXIT'
731 np_print('UNKNOWN FLAG')
732 NP020PC
.flag
= 'EXIT'
733 np_print('04a_NavTrans_esc_FINISHED',';','flag = ', NP020PC
.flag
)
736 elif event
.type in {'MIDDLEMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE'}:
737 np_print('04a_NavTrans_middle_wheel_any_PASS_THROUGH')
738 return {'PASS_THROUGH'}
740 np_print('04a_NavTrans_INVOKED_RUNNING_MODAL',';','flag = ', NP020PC
.flag
)
741 return {'RUNNING_MODAL'}
743 def invoke(self
, context
, event
):
744 #np_print('04a_NavTrans_INVOKE_START')
746 #np_print('flag = ', flag)
747 self
.co2d
= ((event
.mouse_region_x
, event
.mouse_region_y
))
748 if flag
in ('NAVTRANSZERO', 'NAVTRANSFIRST', 'NAVTRANSNEXT'):
749 args
= (self
, context
)
750 self
._handle
= bpy
.types
.SpaceView3D
.draw_handler_add(DRAW_RunTranslate
, args
, 'WINDOW', 'POST_PIXEL')
751 context
.window_manager
.modal_handler_add(self
)
752 np_print('04a_run_NAV_INVOKE_a_RUNNING_MODAL',';','flag = ', NP020PC
.flag
)
753 return {'RUNNING_MODAL'}
755 #np_print('04a_run_NAV_INVOKE_a_FINISHED',';','flag = ', flag)
759 # Defining the operator that will enable the return to RunTrans cycle by reseting the 'break' flag:
761 class NPPCPrepareNext(bpy
.types
.Operator
):
762 bl_idname
= 'object.np_pc_prepare_next'
763 bl_label
= 'NP PC Prepare Next'
764 bl_options
= {'INTERNAL'}
766 def execute(self
, context
):
767 np_print('05_PrepareNext_START',';','flag = ', NP020PC
.flag
)
768 if NP020PC
.flag
== 'RUNTRANSFIRST_break':
769 NP020PC
.flag
= 'RUNTRANSFIRST'
770 if NP020PC
.flag
== 'RUNTRANSNEXT_break':
771 NP020PC
.flag
= 'RUNTRANSNEXT'
772 np_print('05_PrepareNext_FINISHED',';','flag = ', NP020PC
.flag
)
776 # Defining the operator that will collect the necessary data and the generate the array with an input dialogue for number of items:
778 class NPPCArrayTranslate(bpy.types.Operator):
779 bl_idname = "object.np_pc_array_translate"
780 bl_label = "NP PC Array Translate"
781 bl_options = {'INTERNAL'}
783 np_print('06_ArrayTrans_START',';','flag = ', NP020PC.flag)
785 def modal(self,context,event):
786 np_print('06_ArrayTrans_START',';','flag = ', NP020PC.flag)
787 context.area.tag_redraw()
789 ardict = NP020PC.ardict
791 np_print('ardict = ', ardict)
793 if event.type == 'MOUSEMOVE':
794 self.co2d = ((event.mouse_region_x, event.mouse_region_y))
795 np_print('04a_NavTrans_mousemove',';','flag = ', NP020PC.flag)
797 elif event.type in ('LEFTMOUSE', 'RIGHTMOUSE') and event.value == 'PRESS':
798 bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
799 NP020PC.flag = 'EXIT'
800 np_print('06_ArrayTrans_rmb_FINISHED',';','flag = ', NP020PC.flag)
803 elif event.ctrl and event.type == 'WHEELUPMOUSE' or event.type == 'UP_ARROW' and event.value == 'PRESS':
806 deltavec_start = Vector(ardict[ob][1])
807 count = ardict[ob][2]
808 if ar.fit_type == 'FIXED_COUNT':
809 ar.count = ar.count+1
811 elif ar.fit_type == 'FIT_LENGTH' and count == 3:
812 ar.fit_type = 'FIXED_COUNT'
813 ar.constant_offset_displace = deltavec_start
816 elif ar.fit_type == 'FIT_LENGTH' and count >3:
818 ar.constant_offset_displace.length = ar.fit_length/(count-1)
819 ardict[ob][2] = count
820 NP020PC.fit_type = ar.fit_type
821 NP020PC.count = count
822 bpy.context.view_layer.update()
824 elif event.ctrl and event.type == 'WHEELDOWNMOUSE' or event.type == 'DOWN_ARROW' and event.value == 'PRESS':
827 deltavec_start = Vector(ardict[ob][1])
828 count = ardict[ob][2]
829 if ar.fit_type == 'FIXED_COUNT' and count > 2:
830 ar.count = ar.count-1
832 elif ar.fit_type == 'FIXED_COUNT' and count == 2:
833 ar.fit_type = 'FIT_LENGTH'
834 ar.fit_length = deltavec_start.length
835 ar.constant_offset_displace.length = ar.fit_length/2
837 elif ar.fit_type == 'FIT_LENGTH':
839 ar.constant_offset_displace.length = ar.fit_length/(count-1)
840 ardict[ob][2] = count
841 NP020PC.fit_type = ar.fit_type
842 NP020PC.count = count
843 bpy.context.view_layer.update()
845 elif event.type in ('RET', 'NUMPAD_ENTER') and event.value == 'PRESS':
846 bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
847 selob = bpy.context.selected_objects
848 bpy.ops.object.select_all(action='DESELECT')
851 bpy.ops.object.modifier_apply(modifier = ardict[ob][0].name)
855 NP020PC.flag = 'EXIT'
856 np_print('06_ArrayTrans_enter_FINISHED',';','flag = ', NP020PC.flag)
859 elif event.ctrl and event.type == 'TAB' and event.value == 'PRESS':
860 bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
861 if NP020PC.fit_type == 'FIXED_COUNT':
862 value = NP020PC.ar23d - NP020PC.ar13d
864 value = (NP020PC.ar23d - NP020PC.ar13d)/(NP020PC.count - 1)
865 selob = bpy.context.selected_objects
866 bpy.ops.object.select_all(action='DESELECT')
869 ob.modifiers.remove(ardict[ob][0])
870 np_print('NP020PC.count', NP020PC.count)
871 for i in range(1, NP020PC.count):
872 bpy.ops.object.duplicate(linked = True)
873 bpy.ops.transform.translate(value = value)
874 bpy.ops.object.select_all(action='DESELECT')
877 NP020PC.flag = 'EXIT'
878 np_print('06_ArrayTrans_ctrl_tab_FINISHED',';','flag = ', NP020PC.flag)
881 elif event.type == 'TAB' and event.value == 'PRESS':
882 bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
883 if NP020PC.fit_type == 'FIXED_COUNT':
884 value = NP020PC.ar23d - NP020PC.ar13d
886 value = (NP020PC.ar23d - NP020PC.ar13d)/(NP020PC.count - 1)
887 selob = bpy.context.selected_objects
888 bpy.ops.object.select_all(action='DESELECT')
891 ob.modifiers.remove(ardict[ob][0])
892 np_print('NP020PC.count', NP020PC.count)
893 for i in range(1, NP020PC.count):
894 bpy.ops.object.duplicate()
895 bpy.ops.transform.translate(value = value)
896 bpy.ops.object.select_all(action='DESELECT')
899 NP020PC.flag = 'EXIT'
900 np_print('06_ArrayTrans_tab_FINISHED',';','flag = ', NP020PC.flag)
903 elif event.type == 'ESC' and event.value == 'PRESS':
904 bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
906 ob.modifiers.remove(ardict[ob][0])
907 NP020PC.flag = 'EXIT'
908 np_print('06_ArrayTrans_esc_FINISHED',';','flag = ', NP020PC.flag)
911 elif event.type in {'MIDDLEMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE'}:
912 np_print('06_ArrayTrans_middle_wheel_any_PASS_THROUGH')
913 return {'PASS_THROUGH'}
915 np_print('06_ArrayTrans_INVOKED_RUNNING_MODAL',';','flag = ', NP020PC.flag)
916 return {'RUNNING_MODAL'}
918 def invoke(self, context, event):
919 np_print('06_ArrayTrans_INVOKE_START')
921 self.co2d = ((event.mouse_region_x, event.mouse_region_y))
922 if flag == 'ARRAYTRANS':
924 np_print('deltavec_safe = ', NP020PC.deltavec_safe)
927 deltavec = copy.deepcopy(NP020PC.deltavec_safe)
928 np_print('deltavec = ', deltavec)
929 loc, rot, sca = ob.matrix_world.decompose()
930 rot = ob.rotation_euler
931 rot = rot.to_quaternion()
933 np_print(loc, rot, sca, ob.matrix_world)
934 np_print('deltavec = ', deltavec)
935 deltavec.rotate(rot.conjugated())
936 np_print('sca.length', sca.length)
937 deltavec[0] = deltavec[0] / sca[0]
938 deltavec[1] = deltavec[1] / sca[1]
939 deltavec[2] = deltavec[2] / sca[2]
940 np_print('deltavec = ', deltavec)
941 deltavec_trans = deltavec.to_tuple(4)
942 arcur = ob.modifiers.new(name = '', type = 'ARRAY')
943 arcur.fit_type = 'FIXED_COUNT'
944 arcur.use_relative_offset = False
945 arcur.use_constant_offset = True
946 arcur.constant_offset_displace = deltavec_trans
949 ardict[ob].append(arcur)
950 ardict[ob].append(deltavec_trans)
951 ardict[ob].append(arcur.count)
953 NP020PC.ardict = ardict
955 NP020PC.fit_type = 'FIXED_COUNT'
956 selob = NP020PC.selob
957 lenselob = len(selob)
958 for i, ob in enumerate(selob):
961 bpy.context.scene.objects.active = ob
962 args = (self, context)
963 self._handle = bpy.types.SpaceView3D.draw_handler_add(DRAW_ArrayTrans, args, 'WINDOW', 'POST_PIXEL')
964 context.window_manager.modal_handler_add(self)
965 np_print('06_ArayTrans_INVOKE_a_RUNNING_MODAL',';','flag = ', NP020PC.flag)
966 return {'RUNNING_MODAL'}
968 np_print('06_ArrayTrans_INVOKE_DENIED',';','flag = ', NP020PC.flag)
973 # Defining the set of instructions that will draw the OpenGL elements on the screen during the execution of ArrayTrans operator:
975 def DRAW_ArrayTrans(self, context):
977 np_print('06a_DRAW_ArrayTrans_START',';','flag = ', NP020PC.flag)
979 addon_prefs = context.preferences.addons[__package__].preferences
980 badge = addon_prefs.nppc_badge
981 badge_size = addon_prefs.nppc_badge_size
984 bgl.glEnable(bgl.GL_BLEND)
988 square = [[17, 30], [17, 40], [27, 40], [27, 30]]
989 rectangle = [[27, 30], [27, 40], [67, 40], [67, 30]]
990 icon = copy.deepcopy(NP020PC.icon)
991 np_print('icon', icon)
995 co[0] = round((co[0] * badge_size),0) -(badge_size*10) + self.co2d[0]
996 co[1] = round((co[1] * badge_size),0) -(badge_size*25) + self.co2d[1]
998 co[0] = round((co[0] * badge_size),0) -(badge_size*10) + self.co2d[0]
999 co[1] = round((co[1] * badge_size),0) -(badge_size*25) + self.co2d[1]
1001 co[0] = round((co[0] * badge_size),0) -(badge_size*10) + self.co2d[0]
1002 co[1] = round((co[1] * badge_size),0) -(badge_size*25) + self.co2d[1]
1003 ipx = round((ipx * badge_size),0) -(badge_size*10) + self.co2d[0]
1004 ipy = round((ipy * badge_size),0) -(badge_size*25) + self.co2d[1]
1005 ipsize = int(6* badge_size)
1006 bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
1007 bgl.glBegin(bgl.GL_TRIANGLE_FAN)
1011 bgl.glColor4f(0.5, 0.75, 0.0, 1.0)
1012 bgl.glBegin(bgl.GL_TRIANGLE_FAN)
1013 for x,y in rectangle:
1016 bgl.glColor4f(0.2, 0.15, 0.55, 1.0)
1017 bgl.glBegin(bgl.GL_TRIANGLE_FAN)
1018 for x,y in rectangle:
1019 bgl.glVertex2f(x,(y-(badge_size*35)))
1021 bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
1023 blf.position(font_id,ipx,ipy,0)
1024 blf.size(font_id,ipsize,72)
1025 blf.draw(font_id,'NAVIGATE')
1026 blf.position(font_id,ipx,(ipy-(badge_size*35)),0)
1027 blf.size(font_id,ipsize,72)
1028 blf.draw(font_id,'CTRL+SCRL')
1029 bgl.glColor4f(1,1,1,1)
1030 blf.position(font_id,ipx,(int(ipy-badge_size*25)),0)
1031 blf.size(font_id,(int(badge_size*24)),72)
1032 if NP020PC.fit_type == 'FIT_LENGTH':
1033 blf.draw(font_id,'/' + str(NP020PC.count))
1035 blf.draw(font_id,str(NP020PC.count))
1036 bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
1037 bgl.glBegin(bgl.GL_LINE_STRIP)
1042 # ON-SCREEN INSTRUCTIONS:
1044 bgl.glColor4f(1,1,1,0.35)
1045 blf.size(font_id,88,72)
1046 blf.position(font_id,5,74,0)
1047 blf.draw(font_id,'N')
1048 blf.size(font_id,28,72)
1049 blf.position(font_id,22,74,0)
1050 blf.draw(font_id,'P')
1051 blf.enable(font_id, ROTATION)
1052 bgl.glColor4f(1,1,1,0.40)
1054 blf.size(font_id,19,72)
1055 blf.rotation(font_id,ang)
1056 blf.position(font_id,78,73,0)
1057 blf.draw(font_id,'PC 002')
1058 blf.disable(font_id, ROTATION)
1060 main='SPECIFY NUMBER OF ITEMS IN ARRAY'
1061 bgl.glColor4f(0,0.5,0,1)
1062 blf.size(font_id,11,72)
1063 blf.position(font_id,93,105,0)
1064 blf.draw(font_id,'MMB, SCROLL - navigate')
1065 blf.position(font_id,93,90,0)
1066 blf.draw(font_id,'CTRL+SCROLL, UPARROW / DOWNARROW - number of items')
1067 blf.position(font_id,93,75,0)
1068 blf.draw(font_id,'LMB, RMB - confirm and keep array, ENTER - apply as one, TAB - apply as separate, CTRL+TAB - apply as instanced')
1069 bgl.glColor4f(1,0,0,1)
1070 blf.position(font_id,93,60,0)
1071 blf.draw(font_id,'ESC - cancel array')
1072 bgl.glColor4f(0.0, 0.0, 0.0, 0.5)
1073 blf.position(font_id,93,124,0)
1074 blf.size(font_id,16,72)
1075 blf.draw(font_id,main)
1076 bgl.glColor4f(1,1,1,1)
1077 blf.position(font_id,94,125,0)
1078 blf.size(font_id,16,72)
1079 blf.draw(font_id,main)
1082 region = context.region
1083 rv3d = context.region_data
1084 ar12d = view3d_utils.location_3d_to_region_2d(region, rv3d, NP020PC.ar13d)
1085 ar22d = view3d_utils.location_3d_to_region_2d(region, rv3d, NP020PC.ar23d)
1086 ardist = NP020PC.ardist
1087 ardist_loc = (ar12d + ar22d) /2
1090 markersize = badge_size*2.5
1091 triangle = [[0, 0], [-1, 1], [1, 1]]
1092 triangle = [[0, 0], [-1, 1], [1, 1]]
1094 co[0] = int(co[0] * markersize * 3) + ar12d[0]
1095 co[1] = int(co[1] * markersize * 3) + ar12d[1]
1096 bgl.glColor4f(0.4, 0.15, 0.75, 1.0)
1097 bgl.glBegin(bgl.GL_TRIANGLE_FAN)
1098 for x,y in triangle:
1101 triangle = [[0, 0], [-1, 1], [1, 1]]
1103 co[0] = int(co[0] * markersize * 3) + ar22d[0]
1104 co[1] = int(co[1] * markersize * 3) + ar22d[1]
1105 bgl.glColor4f(0.4, 0.15, 0.75, 1.0)
1106 bgl.glBegin(bgl.GL_TRIANGLE_FAN)
1107 for x,y in triangle:
1111 # AR NUMERICAL DISTANCE:
1112 np_print('ardist = ', ardist, 'ardist_loc = ', ardist_loc)
1113 bgl.glColor4f(0.4, 0.15, 0.75, 1.0)
1115 blf.size(font_id, 20, 72)
1116 blf.position(font_id, ardist_loc[0], ardist_loc[1], 0)
1117 blf.draw(font_id, ardist)
1121 bgl.glDisable(bgl.GL_BLEND)
1122 bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
1123 np_print('06a_DRAW_ArrayTrans_FINISHED',';','flag = ', NP020PC.flag)
1126 # Restoring the object selection and system settings from before the operator activation. Deleting the helpers after successful translation, reseting all viewport options and reselecting previously selected objects:
1128 class NPPCRestoreContext(bpy
.types
.Operator
):
1129 bl_idname
= "object.np_pc_restore_context"
1130 bl_label
= "NP PC Restore Context"
1131 bl_options
= {'INTERNAL'}
1133 def execute(self
, context
):
1134 np_print('07_CleanExit_START',';','flag = ', NP020PC
.flag
)
1136 selob
= NP020PC
.selob
1138 place
= NP020PC
.place
1139 bpy
.ops
.object.select_all(action
='DESELECT')
1140 take
.select_set(True)
1141 place
.select_set(True)
1142 bpy
.ops
.object.delete('EXEC_DEFAULT')
1143 lenselob
= len(selob
)
1144 for i
, ob
in enumerate(selob
):
1147 bpy
.context
.view_layer
.objects
.active
= ob
1149 NP020PC
.place
= None
1150 NP020PC
.takeloc3d
= (0.0,0.0,0.0)
1151 NP020PC
.placeloc3d
= (0.0,0.0,0.0)
1153 NP020PC
.mode
= 'MOVE'
1154 NP020PC
.flag
= 'NONE'
1156 NP020PC
.deltavec
= Vector ((0, 0, 0))
1157 NP020PC
.deltavec_safe
= Vector ((0, 0, 0))
1158 bpy
.context
.tool_settings
.use_snap
= NP020PC
.use_snap
1159 bpy
.context
.tool_settings
.snap_element
= NP020PC
.snap_element
1160 bpy
.context
.tool_settings
.snap_target
= NP020PC
.snap_target
1161 bpy
.context
.space_data
.pivot_point
= NP020PC
.pivot_point
1162 bpy
.context
.space_data
.transform_orientation
= NP020PC
.trans_orient
1163 #if NP020PC.acob is not None:
1164 #bpy.context.scene.objects.active = NP020PC.acob
1165 #bpy.ops.object.mode_set(mode = NP020PC.edit_mode)
1167 np_print('07_CleanExit_FINISHED',';','flag = ', NP020PC
.flag
)
1172 # Defining the settings of the addon in the User preferences / addons tab:
1174 class NPPCPreferences(bpy.types.AddonPreferences):
1175 # this must match the addon name, use '__package__'
1176 # when defining this in a submodule of a python package.
1177 bl_idname = __name__
1179 dist_scale = bpy.props.FloatProperty(
1181 description='Distance multiplier (for example, for cm use 100)',
1187 suffix = bpy.props.EnumProperty(
1189 items=(("'","'",''), ('"','"',''), ('thou','thou',''), ('km','km',''), ('m','m',''), ('cm','cm',''), ('mm','mm',''), ('nm','nm',''), ('None','None','')),
1191 description='Add a unit extension after the numerical distance ')
1193 badge = bpy.props.BoolProperty(
1195 description='Use the graphical badge near the mouse cursor',
1198 badge_size = bpy.props.FloatProperty(
1200 description='Size of the mouse badge, the default is 2.0',
1206 col_line_main_DEF = bpy.props.BoolProperty(
1208 description='Use the default color',
1211 col_line_shadow_DEF = bpy.props.BoolProperty(
1213 description='Use the default color',
1216 col_num_main_DEF = bpy.props.BoolProperty(
1218 description='Use the default color',
1221 col_num_shadow_DEF = bpy.props.BoolProperty(
1223 description='Use the default color',
1226 col_line_main = bpy.props.FloatVectorProperty(name='', default=(1.0, 1.0, 1.0, 1.0), size=4, subtype="COLOR", min=0, max=1, description = 'Color of the measurement line, to disable it set alpha to 0.0')
1228 col_line_shadow = bpy.props.FloatVectorProperty(name='', default=(0.1, 0.1, 0.1, 0.25), size=4, subtype="COLOR", min=0, max=1, description = 'Color of the line shadow, to disable it set alpha to 0.0')
1230 col_num_main = bpy.props.FloatVectorProperty(name='', default=(0.1, 0.1, 0.1, 0.75), size=4, subtype="COLOR", min=0, max=1, description = 'Color of the number, to disable it set alpha to 0.0')
1232 col_num_shadow = bpy.props.FloatVectorProperty(name='', default=(1.0, 1.0, 1.0, 1.0), size=4, subtype="COLOR", min=0, max=1, description = 'Color of the number shadow, to disable it set alpha to 0.0')
1234 def draw(self, context):
1235 layout = self.layout
1236 split = layout.split()
1237 col = split.column()
1238 col.prop(self, "dist_scale")
1239 col = split.column()
1240 col.prop(self, "suffix")
1241 split = layout.split()
1242 col = split.column()
1243 col.label(text='Line Main COLOR')
1244 col.prop(self, "col_line_main_DEF")
1245 if self.col_line_main_DEF == False:
1246 col.prop(self, "col_line_main")
1247 col = split.column()
1248 col.label(text='Line Shadow COLOR')
1249 col.prop(self, "col_line_shadow_DEF")
1250 if self.col_line_shadow_DEF == False:
1251 col.prop(self, "col_line_shadow")
1252 col = split.column()
1253 col.label(text='Numerical Main COLOR')
1254 col.prop(self, "col_num_main_DEF")
1255 if self.col_num_main_DEF == False:
1256 col.prop(self, "col_num_main")
1257 col = split.column()
1258 col.label(text='Numerical Shadow COLOR')
1259 col.prop(self, "col_num_shadow_DEF")
1260 if self.col_num_shadow_DEF == False:
1261 col.prop(self, "col_num_shadow")
1262 split = layout.split()
1263 col = split.column()
1264 col.prop(self, "badge")
1265 col = split.column()
1266 if self.badge == True:
1267 col.prop(self, "badge_size")
1268 col = split.column()
1269 col = split.column()
1272 # This is the actual addon process, the algorithm that defines the order of operator activation inside the main macro:
1276 #bpy.utils.register_class(NPPCPreferences)
1277 #bpy.utils.register_module(__name__)
1278 bpy
.app
.handlers
.scene_update_post
.append(NPPC_scene_update
)
1280 NP020PointCopy
.define('OBJECT_OT_np_pc_get_context')
1281 NP020PointCopy
.define('OBJECT_OT_np_pc_get_selection')
1282 NP020PointCopy
.define('OBJECT_OT_np_pc_get_mouseloc')
1283 NP020PointCopy
.define('OBJECT_OT_np_pc_add_helpers')
1284 NP020PointCopy
.define('OBJECT_OT_np_pc_prepare_context')
1285 for i
in range(1, 50):
1286 for i
in range(1, 10):
1287 NP020PointCopy
.define('OBJECT_OT_np_pc_run_translate')
1288 NP020PointCopy
.define('OBJECT_OT_np_pc_nav_translate')
1289 NP020PointCopy
.define('OBJECT_OT_np_pc_prepare_next')
1290 #NP020PointCopy.define('OBJECT_OT_np_pc_array_translate')
1291 NP020PointCopy
.define('OBJECT_OT_np_pc_restore_context')
1295 #bpy.utils.unregister_class(NPPCPreferences)
1296 #bpy.utils.unregister_module(__name__)
1297 bpy
.app
.handlers
.scene_update_post
.remove(NPPC_scene_update
)