Created
July 2, 2013 11:11
-
-
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
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 | |
""" 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