Last active
December 27, 2016 18:13
-
-
Save Eterea/9df25da1b68b230170ec20d4e6b648cd to your computer and use it in GitHub Desktop.
MODO-Python hack to solve the problem when your handles for Move, Scale, Rotate, appears giant or dwarf when seeing from your Camera.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#python | |
# ------------------------------------------------------------------------------------------------ | |
# NAME: etr_fixHandlesFromCamera.py | |
# VERS: 1.0 | |
# DATE: December, 27 - 2016 | |
# | |
# MADE: Cristobal Vila, etereaestudios.com | |
# | |
# USES: This is hack to solve the problem when your handles for Move, Scale, Rotate, | |
# appears giant or dwarf when looking through your Camera. | |
# | |
# It calculates the distance from Camera to the center of selection and use this value to | |
# change the Target Distance on Camera, automatically. | |
# | |
# For the moment it only works for Components (TO DO: work with any selected Item/s) | |
# ------------------------------------------------------------------------------------------------ | |
import lx | |
import math | |
# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
# | |
# FUNCTIONS | |
# | |
# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
# Query selection mode | |
def fn_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 | |
# Dialog with advices in case of wrong selection mode or nothing selected | |
def fn_dialogAdvice(): | |
lx.eval('dialog.setup info') | |
lx.eval('dialog.title {Eterea Fix Handles From Camera}') | |
lx.eval('dialog.msg {Use when your handle appears giant or dwarf when looking through your Camera.\n\ | |
\n\ | |
For the moment you can only work in Vertex, Edge or Poly Mode.\n\ | |
Works with these handles: Move, Rotate, Axis Rotate, Scale, Uniform Scale and Transform.}') | |
lx.eval('dialog.open') | |
sys.exit() | |
# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
# | |
# PRELIMINARY STUFF | |
# | |
# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
# If not in edge or poly mode, launch dialog with advices | |
mySelMode = fn_selmode() | |
allowedModes = ['vertex', 'edge', 'polygon'] | |
if mySelMode not in allowedModes: | |
fn_dialogAdvice() | |
# If nothing is selected, launch dialog with advices | |
dic_comp = {'edge': 'edges', 'polygon': 'polys'} | |
components = lx.evalN('query layerservice %s ? selected' % dic_comp[mySelMode]) | |
if len(components) == 0: | |
fn_dialogAdvice() | |
# Check which transform handle is active (if any) to recover it at end. It must be an easier and direct method for this... | |
myActiveTool = [] | |
if lx.eval('tool.set TransformMove ?') == 'on': | |
myActiveTool = 'TransformMove' | |
elif lx.eval('tool.set TransformScale ?') == 'on': | |
myActiveTool = 'TransformScale' | |
elif lx.eval('tool.set TransformUScale ?') == 'on': | |
myActiveTool = 'TransformUScale' | |
elif lx.eval('tool.set TransformRotate ?') == 'on': | |
myActiveTool = 'TransformRotate' | |
elif lx.eval('tool.set Transform ?') == 'on': | |
myActiveTool = 'Transform' | |
elif lx.eval('tool.set xfrm.rotate ?') == 'on': | |
myActiveTool = 'xfrm.rotate' | |
else: | |
fn_dialogAdvice() | |
# Query Current Layer and be sure to select it on Item List. Query also the meshItem, to return back later | |
currentLayer = lx.eval1('query layerservice layer.index ? main') | |
mainFGlayer = lx.eval1('query layerservice layer.id ? fg') | |
lx.eval('select.subItem {%s} set mesh;locator' % mainFGlayer) | |
myCurrentMesh = lx.eval('query sceneservice selection ? mesh') | |
# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
# | |
# CORE | |
# | |
# ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
# Query Bounding Box of selected components using external script 'calculate_bbox.py' by Farfarer | |
# http://community.thefoundry.co.uk/discussion/post.aspx?f=119&t=93824&p=839842 | |
boundBox = lx.evalN('ffr.getbbox ? world') # Get world space boundBox as (+X, +Y, +Z, -X, -Y, -Z) | |
# Calculate average (arithmetic mean) of resulting coords to get the Center for that Bounding Box | |
# http://stackoverflow.com/questions/7716331/calculating-arithmetic-mean-average-in-python | |
def average(numbers): | |
return float(sum(numbers)) / max(len(numbers), 1) | |
avgX = average([boundBox[0], boundBox[3]]) | |
avgY = average([boundBox[1], boundBox[4]]) | |
avgZ = average([boundBox[2], boundBox[5]]) | |
myTargetPos = (avgX, avgY, avgZ) # This is the average/center position for selected components | |
lx.out('myTargetPos:', myTargetPos) | |
# Calculate world position for last active Camera selected in our 3D viewport (if any) | |
myCam = lx.eval('view3d.cameraItem ?') | |
if myCam: | |
myCamPos = lx.eval('query sceneservice camera.worldPos ? %s' % myCam) | |
lx.out('myCamPos:', myCamPos) | |
else: | |
fn_dialogAdvice() | |
# Calculate distance from Camera to selected stuff using Pythagoras Theorem | |
ABX = myTargetPos[0] - myCamPos[0] | |
ABY = myTargetPos[1] - myCamPos[1] | |
ABZ = myTargetPos[2] - myCamPos[2] | |
AB_distance = math.sqrt(ABX**2 + ABY**2 + ABZ**2) #Pythagoras Theorem | |
lx.out('Distance:', AB_distance) | |
myTarget = AB_distance*0.35 # Direct experience reveals that using 'distance*0.35' gives a more balanced size for handles | |
# Apply this value to our Camera Target Distance | |
lx.eval('select.item %s' % myCam) | |
lx.eval('query layerservice layer.index ? selected') | |
# Since it's very probable that our camera is locked, check it first | |
lockStatus = lx.eval('item.channel locator$lock ?') | |
# If not locked for sure ('off') then we can proceed to change target distance | |
if lockStatus == 'off': | |
lx.eval('item.channel camera$target %s' % myTarget) | |
# If locked for sure ('on') or 'maybe' ('default'), change temporarily to 'off', apply myTarget and recover previous state | |
else: | |
lx.eval('item.channel locator$lock off') | |
lx.eval('item.channel camera$target %s' % myTarget) | |
lx.eval('item.channel locator$lock %s' % lockStatus) | |
# Return back to our original mesh item, selection mode and active tool | |
lx.eval('select.item %s set' % myCurrentMesh) | |
lx.eval('query layerservice layer.index ? selected') | |
lx.eval('select.typeFrom %s' % mySelMode) | |
lx.eval('tool.set %s on' % myActiveTool) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment