Hello once again;
I have expanded some scripted automatisms for CTrack, CCurve and CKey from pure float values to other types, and it turned out to be somewhat irritating. The class
CKey provides two different methods to set/get values:
SetGeData. Documentation tells me that the former is for floats, the latter for "any", as Python does not have a
Although... the doc now gets cryptic.
SetGeData precisely says it sets "the data" of the key - not "the value". The C++ doc tells me to use
SetValue only for floats and "Use
GetParameter() to read non-real values" (with an example).
SetGeData in the C++ docs says "Sets the data of the key" as well; it's so consistent that I begin to suspect "value" and "data" of a key are actually two different things.
SetValue works fine for floats, I try
SetGeData for a
DTYPE_LONG track anyway (
PRIM_CUBE_SUBX). Doesn't work as expected. In the Timeline, the result is always 0, and the animation widget in the Attribute Manager shows up as a yellow circle as if that frame doesn't have any key.
On the other hand, for a
SetGeData works fine.
After some searching, I get an answer on this very forum: I must take the track category into account.
CTRACK_CATEGORY_PLUGIN, well, I still have not the slightest idea, but I suppose
GetParameter may be the thing here?
I'm doing the following test script:
(this works only for a selected cube primitive and creates keys for the Fillet boolean parameter and the X segments value)
import c4d from c4d import gui def SetKey (currentTime, obj, parameterDesc, value): track = obj.FindCTrack(parameterDesc) print ("To set:", value, type(value)) if track == None: # create track for this parameter track = c4d.CTrack(obj, parameterDesc) obj.InsertTrackSorted(track) curve = track.GetCurve() # always present cat = track.GetTrackCategory() if cat == c4d.CTRACK_CATEGORY_PLUGIN: print ("Track is Plugin") return elif cat == c4d.CTRACK_CATEGORY_VALUE: print ("Track is Value") elif cat == c4d.CTRACK_CATEGORY_DATA: print ("Track is Data") else: print ("Track is unknown") return def SetKey_Value(key, value): if cat == c4d.CTRACK_CATEGORY_VALUE: origData = key.GetValue() print ("Orig:", origData, type(origData)) key.SetValue(curve, value) postData = key.GetValue() print ("Post:", postData, type(postData)) elif cat == c4d.CTRACK_CATEGORY_DATA: origData = key.GetGeData() print ("Orig:", origData, type(origData)) key.SetGeData(curve, value) postData = key.GetGeData() print ("Post:", postData, type(postData)) currentKey = curve.FindKey(currentTime) if currentKey: key = currentKey['key'] # key reference to change doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, key) SetKey_Value(key, value) curve.SetKeyDirty() # Key attributes found under C++ API doc: ckvalue.h File Reference else: defkey, dub = doc.GetDefaultKey() # new key to insert key = defkey.GetClone() # needed? SetKey_Value(key, value) key.SetTime(curve, currentTime) # key.SetInterpolation(curve, c4d.CINTERPOLATION_SPLINE) curve.InsertKey(key, True) doc.AddUndo(c4d.UNDOTYPE_NEW, key) def main(): if op == None : return descSubX = c4d.DescID(c4d.DescLevel(c4d.PRIM_CUBE_SUBX, c4d.DTYPE_LONG, 0)) descFillet = c4d.DescID(c4d.DescLevel(c4d.PRIM_CUBE_DOFILLET, c4d.DTYPE_BOOL, 0)) doc.StartUndo() val = op[c4d.PRIM_CUBE_SUBX] SetKey (doc.GetTime(), op, descSubX, val) val = op[c4d.PRIM_CUBE_DOFILLET] SetKey (doc.GetTime(), op, descFillet, val) doc.EndUndo() c4d.EventAdd() if __name__=='__main__': main()
This works fine, and tells me in the console output that actually a
DTYPE_LONG DescID has created a track of category
CTRACK_CATEGORY_VALUE, and my integer value that I'm trying to pass to the key is converted into a
float. And the
DTYPE_BOOL DescID has created a track of category
CTRACK_CATEGORY_DATA, and my Boolean value that I'm trying to pass to the key is converted into an
While I now have a function that seems to work for two track categories (I haven't even started on the "plugin" category), this is not what I would have expected from the documentation. I later discover the track category thing in the C++ CKey manual as well, but there it only again mentions
- Is my solution for
DTYPE_LONGeven correct? It works, but the solution is pretty much not what I gather from the API docs.
- So a
CKeystores an int as float, and a bool as int, and... what's the mapping here?
- Are the
Set/GetValueLeft/Rightfunctions similarly dispositioned? The Python docs say "Just for keys with float values." but right now I suspect that they will also work for
DTYPE_LONGtracks as the according keys seem to work with floats internally. (Also, the Timeline shows me tangents.)
- Checking the track categories, I find that a PLA track (as the C++ CKey API doc shows as an example) is a Plugin track. So, am I right with my theory that Plugin tracks need
GetParameter, just like Value tracks need
GetValueand Data tracks need
GetGeData? The doc says "Use
GetParameter()to read non-real values." in the same place, but that is not taking
GetGeDatain account at all? (I'm not even going to mention that