Track View > Selected Keys > How to get controller info from keys?

Track View > Selected Keys > How to get controller info from keys?

Anonymous
Not applicable
1,112 Views
7 Replies
Message 1 of 8

Track View > Selected Keys > How to get controller info from keys?

Anonymous
Not applicable

My goal: I'm trying to store the info of selected keys in the track view so I can paste them onto other tracks in the track view. 

 

My question: How do you get the controller information from an array of keys?

 

For example, I loop though all my selected, keyable tracks and save the keys in an array. How do I access the information regarding the controller the key came from in each key? 

 

When I run this on myKeys array that contains two keys:

for k in myKeys do format "Time = % : Value = %\n" k.time k.value

 

I get this result:

 

Time = 156f : Value = -0.194065
Time = 223f : Value = -0.180666

 

Is there a value stored in the key that references the controller the key belongs to? For example (paraphrased):

 

for k in myKeys do format "Controller Name = %\n" k.controller

 

Result: "controller.pos.x" ...etc

 

Thanks

 

 

0 Likes
1,113 Views
7 Replies
Replies (7)
Message 2 of 8

Swordslayer
Advisor
Advisor

I don't think you can easily do it that way as MAXKey derives from Value not MaxObject so functions like refs.dependents won't help here. On the other hand, as you are in control of getting the keys in the first place what about collecting some additional info in the process? For example

 

(
	struct keyInfo (ctrl, index, keys, parentCtrl, name = getSubAnimName parentCtrl index)

	local currentTV = trackViews.current
	local selCount = currentTV.numSelTracks()

	for i = 1 to selCount
		where (local ctrl = currentTV.getSelected i).keyable collect
			keyInfo ctrl:ctrl keys:ctrl.keys \
				index:(currentTV.getSelectedSubNum i) \
				parentCtrl:(currentTV.getParentOfSelected i)
)

 Or anything else that would better suit your needs.

 

0 Likes
Message 3 of 8

Anonymous
Not applicable

That's really helpful! Thanks. I will give it a try.

0 Likes
Message 4 of 8

Anonymous
Not applicable

Hey SwordSlayer, 

 

A couple quick follow up noob questions.

 

How does the "name" part of the struct definition work? In the parentCtrl section, you'd get something like "Controller:Euler_XYZ". 

 

"name = getSubAnimName parentCtrl index"

 

Where is the "index" number coming from? Is that the index in the struct definition or the index of the parentCtrl? When I step through the function, "1, 2...etc" The "name" doesn't return the correct name. But when I execute your code, it works. 

 

2nd question: As you go through each selected track in the track view

 

(local ctrl = currentTV.getSelected i)

 

Is there a way to test whether the track is rotation, translation, or scale? 

 

For example (I'm paraphrasing, I know this won't work exactly), 

 

if keyInfo[1].ctrl.isRotationController == true do

 

I suppose I could search through the "name" and look for the string "rotation", but that seems like a hack and could run into problems later. 

 

Thanks!

 

 

0 Likes
Message 5 of 8

Swordslayer
Advisor
Advisor

Hi, the index is a part of the struct constructor, it is passed when the struct is initialized in the line index:(currentTV.getSelectedSubNum i). This returns the subanim index of the controller relative to its parent, getSubAnimName works the other way, it returns the name of the indexed subanim of the parent.

 

As for the second question, you can test if a controller is of a certain type using isKindOf function with the target class, here it would be RotationController, ScaleController or PositionController. I suppose you will want to test if it is a subcontroller of a RotationController (it can be for example a X_Rotation part of a Rotation_List controller), so wrapping it in a simple while-loop should make sense:

 

 

(
	struct keyInfo (ctrl, index, keys, parentCtrl, name = getSubAnimName parentCtrl index)

	fn isRotationController ctrlTrack currentTV rotController:false =
	(
		while isController ctrlTrack AND NOT rotController do
		(
			rotController = isKindOf ctrlTrack RotationController
			ctrlTrack = currentTV.getParent (currentTV.getIndex ctrlTrack)
		)
		rotController
	)

	local currentTV = trackViews.current
	local selCount = currentTV.numSelTracks()

	for i = 1 to selCount
		where (local ctrl = currentTV.getSelected i).keyable AND
			isRotationController ctrl currentTV collect
			keyInfo ctrl:ctrl keys:ctrl.keys \
				index:(currentTV.getSelectedSubNum i) \
				parentCtrl:(currentTV.getParentOfSelected i)
)

 

0 Likes
Message 6 of 8

Anonymous
Not applicable

That description of how to use a struct really helped me out a lot. I've been using it in other scripts and I love it.

 

I'm running into one issue regarding using a struct of key arrays and "deepcopy". I'm saving the selected keys in the track view into a struct that defines arrays of the keys (the struct also holds the other info Swordslayer suggested). 

 

I'm trying to make that key array a unique array that no longer points to the actual keys in the track editor from which they came. The reason I want to do this is, so I can paste those keys back onto the same track (but perhaps with a value offset). It seems like they need to be a separate entity as altering the tracks keys would alter the keys in my array and cause unexpected results. 

 

Here's an example (from Swordslayer):

 

struct keyInfo (ctrl, index, keys, parentCtrl, name = getSubAnimName parentCtrl index)
local currentTV = trackViews.current
local selCount = currentTV.numSelTracks()

 

global copyTracks = for i = 1 to selCount
where (local ctrl = currentTV.getSelected i).keyable = true) collect
keyInfo ctrl:ctrl keys:ctrl.keys \
index:(currentTV.getSelectedSubNum i) \
parentCtrl:(currentTV.getParentOfSelected i)

 

------------------------

 

After getting the values for this struct's arrays, I want to be able to do stuff to the tracks and their keys without changing the values in the struct arrays. 

 

Maxscript Help describes using "deepcopy" to do this, but it doesn't work for me. I tried

 

copyTracks = deepcopy copyTracks

myKeys = deepcopy copyTracks[1].keys

 

Both times, if I did something like this:

 

myKeys[1].value = 25, it would ALSO assign 25 to copyTracks[1].keys[1].value. 

 

How do I do this?

 

Thanks

0 Likes
Message 7 of 8

Steve_Curley
Mentor
Mentor
Tip. ALWAYS put your code inside a code block - there's a button for it above where you type your posts. Code with smiley faces in the middle of it makes it less than readable.

Max 2016 (SP1/EXT1)
Win7Pro x64 (SP1). i5-3570K @ 4.4GHz, 8Gb Ram, DX11.
nVidia GTX760 (2GB) (Driver 430.86).

0 Likes
Message 8 of 8

Anonymous
Not applicable
struct keyInfo (ctrl, index, keys, parentCtrl, name = getSubAnimName parentCtrl index)
local currentTV = trackViews.current
local selCount = currentTV.numSelTracks()
 
global copyTracks = for i = 1 to selCount		
where ((local ctrl = currentTV.getSelected i).keyable = true collect
keyInfo ctrl:ctrl keys:ctrl.keys \
index:(currentTV.getSelectedSubNum i) \
parentCtrl:(currentTV.getParentOfSelected i)

 

0 Likes