#python | |
# --------------------------------------------------------------------------------- | |
# NAME: etr_move_nudge_xyz.py | |
# VERS: 1.4 | |
# DATE: August 5, 2020 | |
# | |
# MADE: Cristobal Vila, etereaestudios.com | |
# | |
# USES: To move nudge (and duplicate, optionally) fixed amounts along XYZ axis | |
# TODO: Make it more Clean and Robust | |
# Allow duplicate items (instance, better) | |
# --------------------------------------------------------------------------------- | |
# ------------------------------------------------------------------------------------------------ | |
# | |
# FUNCTIONS | |
# | |
# ------------------------------------------------------------------------------------------------ | |
# TO KNOW OUR SELECTION MODE | |
# ------------------------------------------------------------------------------------------------ | |
def selmode(*types): | |
if not types: | |
types = ('vertex', 'edge', 'polygon', 'item', 'pivot', 'center', 'ptag') | |
for t in types: | |
if lx.eval("select.typeFrom %s;vertex;edge;polygon;item;pivot;center;ptag ?" %t): | |
return t | |
mySelMode = selmode() | |
elements = ['vertex', 'edge', 'polygon', 'item'] | |
components = ['vertex', 'edge', 'polygon'] | |
# DIALOG FOR WHEN NOTHING IS SELECTED AND USER TRY TO DUPLICATE THINGS (BAD IDEA) | |
# ------------------------------------------------------------------------------------------------ | |
def fn_dialogAdviceDupli(): | |
lx.eval("dialog.setup info") | |
lx.eval("dialog.title {Eterea Move Nudge - Duplicate}") | |
lx.eval("dialog.msg {You are trying to move things with DUPLICATE option, but NOTHING is selected!\n\ | |
This is not allowed because bad things could occur (ie: generate co-located geometry)\n\ | |
You need to select something before, to be duplicated using these tools.}") | |
lx.eval("dialog.open") | |
sys.exit() | |
# ------------------------------------------------------------------------------------------------ | |
# | |
# ARGUMENTS AND USER VALUES | |
# | |
# ------------------------------------------------------------------------------------------------ | |
# Query our arguments, 'axis' for XYZ or multiaxis situations and 'sign' for pos +1 / neg -1 direction | |
axis = lx.args()[0] | |
sign = int(lx.args()[1]) | |
# Query our external user values | |
dupli = lx.eval("user.value etr_nudge_move_duplistate ?") | |
mastat_x = lx.eval("user.value etr_nudge_move_multiaxis_x ?") | |
mastat_y = lx.eval("user.value etr_nudge_move_multiaxis_y ?") | |
mastat_z = lx.eval("user.value etr_nudge_move_multiaxis_z ?") | |
# For this nudge move tool we need to create first of all 3 variables for distX,Y,Z equal to zero | |
# NOTE: this is necesary because user.values here are 'temporary' (we don't need this with scale & rotate nudges) | |
distX = 0 | |
distY = 0 | |
distZ = 0 | |
# -------------------------------------------------------------------------------------------------- | |
# BUG: LACK OF PRECISION WITH USER VALUES DEFINED ON A CFG vs DEFINED ON A SCRIPT | |
# | |
# If you define a 'userValue' through an external config file (CFG) you will suffer a nasty | |
# limitation with precision: no more than 2 decimals will show (!) | |
# | |
# Instead, defining the lifetime of your user value as 'temporary', inside a script, | |
# this limitation disappear and you are allowed to use up to 4 decimals. | |
# | |
# Example: using a script the value will be printed '67.4955cm'. Using a 'config', it will be '67.5cm' | |
# | |
# On the other hand, using a userValue for 'Distance' defined on a CFG you will never | |
# be able to introduce a really small distance, like 15um. It will round to 0. | |
# | |
# For these reasons these user values are defined here, instead of using an external CGF. | |
# | |
# DISCUSED HERE: | |
# https://community.foundry.com/discuss/topic/91732 | |
# -------------------------------------------------------------------------------------------------- | |
# Lets query if our userValues are cr eated or not | |
etr_move_x_query = lx.eval("query scriptsysservice userValue.isDefined ? etr_nudge_move_x") | |
etr_move_y_query = lx.eval("query scriptsysservice userValue.isDefined ? etr_nudge_move_y") | |
etr_move_z_query = lx.eval("query scriptsysservice userValue.isDefined ? etr_nudge_move_z") | |
# Create or update userValues depending on previous queries | |
if etr_move_x_query == 0: | |
lx.eval("user.defNew etr_nudge_move_x distance temporary") | |
distX = lx.eval("user.value etr_nudge_move_x 0.0") | |
else: | |
distX = lx.eval("user.value etr_nudge_move_x ?") | |
if etr_move_y_query == 0: | |
lx.eval("user.defNew etr_nudge_move_y distance temporary") | |
distY = lx.eval("user.value etr_nudge_move_y 0.0") | |
else: | |
distY = lx.eval("user.value etr_nudge_move_y ?") | |
if etr_move_z_query == 0: | |
lx.eval("user.defNew etr_nudge_move_z distance temporary") | |
distZ = lx.eval("user.value etr_nudge_move_z 0.0") | |
else: | |
distZ = lx.eval("user.value etr_nudge_move_z ?") | |
# ------------------------------------------------------------------------------------------------ | |
# | |
# PRELIMINARY STUFF | |
# | |
# ------------------------------------------------------------------------------------------------ | |
# FOR WHEN PALETTE IS ALREADY OPEN BUT MOVE IS DISABLED | |
# ------------------------------------------------------------------------------------------------ | |
# Just in case that nudge form is open but move tool is disabled, | |
# because user didn't arrived here through launcher script | |
# NOTE: we do NOT perform the nudge operation on this step and just activate the Move tool | |
# because the center of movement could be away from the center of selection | |
if lx.eval("tool.set TransformMove ?") != 'on': | |
lx.eval("tool.set TransformMove on") | |
sys.exit() | |
# NEEDED FOR MULTIAXIS OPERATIONS | |
# ------------------------------------------------------------------------------------------------ | |
# Create a 'Multi Axis Status' dictionary to be used for negate multi axis move | |
mastatneg_dict = { | |
'0': '0', | |
'1': '2', | |
'2': '1', | |
} | |
# Use that dictionary to negate multiaxis move only if our argument is 'multineg' | |
if axis == 'multineg': | |
mastat_x = (mastatneg_dict[mastat_x]) | |
mastat_y = (mastatneg_dict[mastat_y]) | |
mastat_z = (mastatneg_dict[mastat_z]) | |
# NEEDED FOR 'DUPLICATE' OPTION | |
# ------------------------------------------------------------------------------------------------ | |
# Try to see if a third argument exists (no matter what it's) | |
# If so, change 'dupli' variable to 1 | |
# This is to allow nudge+duplication using an alternate command, with a key modifier. | |
# We use 'dupli' as a third argument, but it really does not matter. Could be 'smith' or '42' also. | |
try: | |
lx.args()[2] | |
dupli = 1 | |
except: | |
pass | |
# Define a dictionary for different component modes to get plural (needed for next lines) | |
comp_dict = { | |
'vertex': 'verts', | |
'edge': 'edges', | |
'polygon': 'polys', | |
} | |
# Check if something is selected when in component mode. This is important when 'Duplicate' option is enabled | |
# If nothing is selected in our selection modo, then a 'dupliAlert = 1' is generated, to be used later | |
dupliAlert = 0 | |
if mySelMode in components: | |
selComp = lx.evalN("query layerservice %s ? selected" % comp_dict[mySelMode]) | |
if len(selComp) == 0: | |
dupliAlert = 1 | |
# STEPS IF 'DUPLICATE' IS ENABLED (NO MATTER IF THROUGH 'USER.VALUE' OR BY A THIRD ARGUMENT EXISTENCE) | |
# ------------------------------------------------------------------------------------------------ | |
if dupli == 1 and mySelMode in components: | |
# In case that nothing is selected we abort the scritp, launching a dialog with advices | |
if dupliAlert == 1: | |
fn_dialogAdviceDupli() | |
# Query current prefs about copy and paste behaviour | |
copyDeSelectionState = lx.eval("pref.value application.copyDeSelection ?") | |
pasteSelectionState = lx.eval("pref.value application.pasteSelection ?") | |
pasteDeSelectionState = lx.eval("pref.value application.pasteDeSelection ?") | |
# Change all those Prefs to 'false' temporarily. | |
lx.eval("pref.value application.copyDeSelection false") | |
lx.eval("pref.value application.pasteSelection false") | |
lx.eval("pref.value application.pasteDeSelection false") | |
# Copy and paste our geometry (our selected one will remain selected, not the pasted) | |
lx.eval('copy') | |
lx.eval('paste') | |
# Return prefs on copy & paste to the original conditions | |
lx.eval("pref.value application.copyDeSelection %s" % copyDeSelectionState) | |
lx.eval("pref.value application.pasteSelection %s" % pasteSelectionState) | |
lx.eval("pref.value application.pasteDeSelection %s" % pasteDeSelectionState) | |
elif dupli == 1 and mySelMode == 'item': # HERE IS FROM WHERE I'M HAVING THE PROBLEM !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
lx.eval("item.duplicate true locator false true") | |
# ------------------------------------------------------------------------------------------------ | |
# | |
# PERFORM THE NUDGE MOVE OPERATIONS | |
# | |
# ------------------------------------------------------------------------------------------------ | |
# Apply nudge depending on all of the above | |
if axis == 'X': | |
lx.eval("tool.attr xfrm.transform TX %s" % (distX*sign)) | |
elif axis == 'Y': | |
lx.eval("tool.attr xfrm.transform TY %s" % (distY*sign)) | |
elif axis == 'Z': | |
lx.eval("tool.attr xfrm.transform TZ %s" % (distZ*sign)) | |
# This is for Multi Axis Move Nudge (valid for both arguments 'multi' and 'multineg') | |
else: | |
# We need specific variables here for each axis sign (positive or negative) | |
# Let's start defining all as positive | |
signX = 1 | |
signY = 1 | |
signZ = 1 | |
# Our strings '...', 'pos X' and 'neg X' in our 'user.value' multi axis | |
# give us the strings '0', '1' and '2' | |
if mastat_x == '0': | |
distX = 0 | |
elif mastat_x == '1': | |
signX = 1 | |
else: | |
signX = -1 | |
if mastat_y == '0': | |
distY = 0 | |
elif mastat_y == '1': | |
signY = 1 | |
else: | |
signY = -1 | |
if mastat_z == '0': | |
distZ = 0 | |
elif mastat_z == '1': | |
signZ = 1 | |
else: | |
signZ = -1 | |
lx.eval("tool.attr xfrm.transform TX %s" % (distX*signX)) | |
lx.eval("tool.attr xfrm.transform TY %s" % (distY*signY)) | |
lx.eval("tool.attr xfrm.transform TZ %s" % (distZ*signZ)) | |
lx.eval("tool.doApply") | |
# These last off / on commands are to re-center the handles around selection after each nudge step | |
lx.eval("tool.set TransformMove off") | |
lx.eval("tool.set TransformMove on") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment