Additive position function in python


#1

I’m trying to create a function where, if there is a value increase in a set of data, then add the difference to a stored value . This is what I got so far, but it throws an error:

import c4d

op[12345] = 0

def main():
    global Output1, Output2
    if Input1 > Input2:
        Output1 = Input1 - Input2
    else:
        Output1 = 0
    op[12345] = op[12345] + Output1
    Output2 = op[12345]

If I do something like op[12345] = op[12345] + 1 it will iteratively add a value of 1 after each frame, but if I do something like op[12345] = op[12345] + Output1 it hangs up the code.

I’m using the Memory node in xpresso to calculate Input1 & Input2 from the position of objectA, and trying to use the difference of that data to additively increase the position of objectB.

Any suggestions would be helpful. I’ve done some C.O.F.F.E.E. in the past, but totally new to Python.


#2

I can’t understand all your code & also I’ve never really used python in tags, always in the Script manager. (I assume you’re coding in a tag because of the ‘op’)

But anyway python has the += operator, so if you write:
a += 5
that’s equivalent to a = a + 5

maybe it will be helpful.


#3

I’m pretty sure, he’s using this in a Xpresso Python node in conjunction with a Memory node.

@jhsu: Can you maybe post the scene, so I could take look?


#4

@MighT42 Here’s a test file: 191120-test_track-2.c4d (304.7 KB)

And a screenshot of the xpresso editor:

Thanks for taking a look

@Decade I saw that += operator snooping around as well, thanks for the tip


#5

In general I recommend, whenever you work with Python, have the Python Console open and docked somewhere easily visible into your layout.

When adding the above line to your example scene, you get the following error message in the Console window:

Traceback (most recent call last):
File “Python”, line 12, in main
TypeError: setitem expected int or bool, not float

This happens, when you try to write (setitem) a value into a BaseContainer. A BaseContainer is kind of type safe, so if you store a integer value under a certain ID, you can not change the datatype of that entry by overwriting it with another datatype (you’d need to remove the entry first, if needed). And in your calculation you are leaving the integer land by adding the Y position (which is a Float) to the counter, turning it into a Float value.
The simple solution, change the Y position to an int and maybe you are green (basically if you can live with the rounding implied in this step):

op[12345] += int(Output1)

The other way would be to indeed remove the stored integer from the BaseContainer (get it from op via GetDataInstance()) and always store floats. Instead of using the __setitem__ ([ ]) operator, you could for example simply use the typed access functions (SetInt32(), SetFloat(), …).


#6

Oh, one more hint:
Instead of storing data at an arbitrary ID in the Python tag’s BaseContainer, you may want to consider User Data. Simply create a User Data with the needed data type (note down it’s user data ID) on the Python tag.
Instead of doing:

op[12345]

You can then do:

op[c4d.ID_USERDATA, the UDID you noted down above]

Then you can also live watch such data in the UI and also even change it from the UI.


#7

Ah yes, I noticed if I even tried adding a decimal number to the op variable it would break the script. That explains it, also thanks for pointing out the console.

I tried calling userdata in the script, but I got this error AttributeError: parameter access failed

I ended up just falling back to xpresso and pulled in the userdata through a node, in the end I was able to get everything working. Here’s a screenshot and the file:

191120-test_track-3.c4d (274.7 KB)

Works like a charm, thanks for the help!


#8

Welcome, glad it’s working now.

Where did you put the user data? On the object or the tag? Or the node?
I’m sorry, I think I wrote to put it onto the tag, totally ignoring, that the code is in a Xpresso node. It’s a bit unfortunate (although actually logical), that op has different meanings, depending on where the Python code is executed (Tag, Xpresso, Generator, Script,…). op is actually always the “entity” the code belongs to. In this case the Python node. When you add the user data to the Xpresso Python node it will work, although that’s obviously not very convenient.

I’m currently not sure, if there are predefined global variables for tthe tag or the object inside of the Python node.
But you can get it from the node itself:
pytag = op.GetNodeMaster().GetOwner()

And then the object is:
pytagHostObject = pytag.GetObject()

These references should not be used to alter anything from within the Python node (you are doing it exactly right, processing inputs, generating outputs), but only for reading purposes (storing of values in the BaseContainer should be ok, yet with user data you wouldn’t even need to do this, as you could write the value via an output as well).

Cheers


#9

I put the user data on the xpresso tag, I actually never thought you could put user data on nodes within xpresso, just learned something else.

Yea it get’s confusing with so many different contexts to using python in c4d. I realize xpresso creates a lot of redundancies, but I’ll really miss it if they ever stop supporting it. I’m just not a coder and when it comes to objects and classes I really get lost.

Thanks again for the help!