Skip to content

Instantly share code, notes, and snippets.

@lukpazera
Created July 2, 2013 11:11
Show Gist options
  • Save lukpazera/5908473 to your computer and use it in GitHub Desktop.
Save lukpazera/5908473 to your computer and use it in GitHub Desktop.
This is python translation of Matt Cox's matchXfrm.cpp C++ command and was done as an exercise while learning MODO python API. Matt's original: https://gist.github.com/mattcox/4742206
#python
""" Match Item Transforms.
Command matches transforms of one item to another.
Select 2 or more items and all items will be matched to last selected one.
I'm not author of this command.
This is python translation of Matt Cox's matchXfrm.cpp C++ equivalent
and was done as an exercise while learning MODO python API.
Matt's original:
https://gist.github.com/mattcox/4742206
"""
import lx
import lxifc
import lxu.command
import lxu.select
import traceback
CMD_NAME = 'item.matchXfrm'
class CmdMatchXfrm(lxu.command.BasicCommand):
def __init__(self):
lxu.command.BasicCommand.__init__(self)
self.command_service = lx.service.Command()
self.selection_service = lx.service.Selection()
def basic_Enable(self, msg):
""" The command will be enabled if at least 2 items are selected.
"""
if self.selection_service.Count(lx.symbol.iSEL_ITEM) >= 2:
return True
else:
return False
def cmd_Flags(self):
return lx.symbol.fCMD_UNDO
def basic_Execute(self, msg, flags):
""" Main command method.
"""
try:
lx.out('--- item.matchXFrm Log ---')
scene_service = lx.service.Scene()
value_service = lx.service.Value()
""" Command won't do any action if less then 2 items are selected. """
sel_count = self.selection_service.Count(lx.symbol.iSEL_ITEM)
if sel_count < 2:
msg.SetCode(lx.symbol.e_FAILED)
return
""" get current item selection as a list of Item objects. """
item_sel = lxu.select.ItemSelection()
""" Localize last selected item,
it'll be our target item. We're going to match all
other selected items to target item's transforms. """
target_item = lx.object.Item(item_sel.current()[sel_count - 1])
if not target_item.test():
msg.SetCode(lx.symbol.e_FAILED)
return
""" We will need to read some transform channels values.
This is done via ChannelRead interface that we need to initialize.
ChannelRead interface can be obtained from Scene object so we need to get
that object too.
For reading channel values have to say at what time we want to read channel values,
we'll do it at current time.
Finally, we need to define action that we will tak channel values from.
By passing None as first argument to scene.Channels we tell MODO
that we are interested in evaluated values. This is the only choice
for reading matrices, as they do not exist as user set values. """
scene = lx.object.Scene(target_item.Context())
cur_time = self.selection_service.GetTime()
""" These are choices for initializing ChannelRead interface action:
lx.symbol.s_ACTIONLAYER_EDIT """
chanRead = lx.object.ChannelRead(scene.Channels(None, cur_time))
""" Find World Position matrix channel index by its name. """
wposMatrixI = target_item.ChannelLookup(lx.symbol.sICHAN_XFRMCORE_WPOSMATRIX)
""" Read World Position matrix as Value object.
To use that object it needs to be localized to Matrix object. """
valObj = chanRead.ValueObj(target_item, wposMatrixI)
posMatrix = lx.object.Matrix(valObj)
""" The same as above is done to read and localize rotation and scale matrices. """
valObj = chanRead.ValueObj(target_item, target_item.ChannelLookup(lx.symbol.sICHAN_XFRMCORE_WROTMATRIX))
rotMatrix = lx.object.Matrix(valObj)
valObj = chanRead.ValueObj(target_item, target_item.ChannelLookup(lx.symbol.sICHAN_XFRMCORE_WSCLMATRIX))
sclMatrix = lx.object.Matrix(valObj)
""" Make sure all Matrice objects are initialized properly. """
if not posMatrix.test() or not rotMatrix.test() or not sclMatrix.test():
msg.SetCode(lx.symbol.e_FAILED)
return
""" Now we need to get transform information that we will apply.
For position - we need position vector that can be extracted from World Position matrix
using matrix GetOffset method. """
posVector = posMatrix.GetOffset()
""" To be able to apply rotation and scale transforms we need to convert
matrices to values.
Let's create empty values first.
Rotation matrix is of matrix3 value type and
scale matrix needs to be matrix4. """
rotMatrix3 = value_service.CreateValue('matrix3')
sclMatrix4 = value_service.CreateValue('matrix4')
""" Fill values with data pulled from Matrice objects. """
rotMatrix3 = rotMatrix.Get3()
sclMatrix4 = sclMatrix.Get4()
""" All that's left now is to initialize ChannelWrite interface that will allow us
to set new channel values for all matched items.
We're initializing it for writing on current edit action layer and at current time. """
chanWrite = lx.object.ChannelWrite(scene.Channels(lx.symbol.s_ACTIONLAYER_EDIT, cur_time))
""" Loop through all selected items (but the last one) and apply transforms. """
for x in xrange(sel_count - 1):
""" Use locator interface to get access to transform methods
such as SetPosition, etc. """
curItem = lx.object.Locator(item_sel.current()[x])
if not curItem.test():
continue
""" All transforms are applied in world space mode.
MODO will calculate correct local transform values. """
curItem.SetPosition(chanRead, chanWrite, posVector, lx.symbol.iLOCATOR_WORLD, 0)
curItem.SetRotation(chanRead, chanWrite, rotMatrix3, lx.symbol.iLOCATOR_WORLD, 0)
curItem.SetScale(chanRead, chanWrite, sclMatrix4, lx.symbol.iLOCATOR_WORLD, 0)
except:
lx.out(traceback.format_exc())
raise
lx.bless(CmdMatchXfrm, CMD_NAME)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment