It works like a charm!
Thanks a lot!
 Offline
Offline
It works like a charm!
Thanks a lot!
Hi,
How can I add a button to an object with python?
I'm trying to add a button to a Null Object, but only get a button userdata without button itself. Here is the code:
import c4d
def main():
    null_object = c4d.BaseObject(c4d.Onull)
    ud_btn_bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_BUTTON)
    ud_btn_bc.SetString(c4d.DESC_NAME, "Click")
    ud_btn_bc.SetString(c4d.DESC_SHORT_NAME, "click")
    null_object.AddUserData(ud_btn_bc)
    doc.InsertObject(null_object)
 
    c4d.EventAdd()
if __name__ == "__main__":
    main()
It seems that creating a button user data from GUI is different from Python. But I don't know how to do it correctly in Python.
Thanks!
Thank you @ferdinand for the detailed answer and code.
I will do more reading in the sdk document.
Thanks again @cairyn!
I will use the method your introduced, and keep this topic open, hoping someone could make this more clearly.
Thanks @cairyn! When i read c4d.IsCommandChecked(id), it says Forbidden to call in expressions (Python generator, tag, XPresso node, etc.). Is it safe to use this in a Interaction Tag?
Hi,
How can I get and set Move Tool's XYZ Axis Lock state? when I click the buttons, the Script Log display as:
c4d.CallCommand(12153) # X-Axis / Pitch
c4d.CallCommand(12154) # Y-Axis / Heading
c4d.CallCommand(12155) # Z-Axis / Bank

I append an Interaction Tag on a object, when I select this object, I want it automaticly change to Move Tool and lock the Y axis and Z axis,
when I deselect the object, it restore the original axis lock state, then change back to last active tool.
Here is the code I put in the tag:
import c4d
from c4d import gui
def onSelect():
    #Code for what happens when the object gets selected goes here
    global last_tool
    last_tool = doc.GetAction() # store the active tool
    
    c4d.CallCommand(c4d.ID_MODELING_MOVE) # change to Move Tool
    gui.ActiveObjectManager_SetObject( # change Attribute Manager to Object Mode
        c4d.ACTIVEOBJECTMODE_OBJECT, op, c4d.ACTIVEOBJECTMANAGER_SETOBJECTS_OPEN)
    # TODO: Get Move Tool current axis lock state, then change the state
def onDeselect():
    #Code for what happens when the object gets unselected goes here
    # TODO: Restore Move Tool's last axis lock state
    doc.SetAction(last_tool) # restore the last active tool
#def onHighlight():
    #Code for what happens when the object gets highlighted goes here
#def onUnhighlight():
    #Code for what happens when the object gets unhighlighted goes here
by the way, what is the difference between "onSelect" and "onHighlight"?
Thanks!
@s_bach thank you for your answer! I think I have the same question as mike do, so it has been solved now. Thank you again!
Hi, @m_adam
Thank you for your kindness and the inspiring answer! It's a GREAT Christmas present for me!
So sorry asking XPresso related questions in this forum.
The problem I faced is a little bit complex than this: I need sample Effectors' total Output Strengths in the position from a Polygon Object's Points, and store the result into a Vertex Color Map attached for further use.
This problem bothers me for months, and I didn't find any clue until your post. I have never think about using Python Node with global variable in XPresso Network can keep the data as I need and do the magic!
From the bottom of my heart, I want to say THANK YOU.
The answer you give not only solve this problem, but also inspire me re-thinking of ObjectList Node and Python Node, and how these nodes executed in an XPresso Network.
Just let me THANK YOU AGAIN!
Best wishes for you to have a wonderful holiday!
Hi,
I have a Null Object with an In-/Exclusion Userdata attached. In In-/Exclusion Userdata some Mograph Effector have been added. I want to use Sample Node to get all Strength of Mograph Effector, then add output Strength together. How can I do?
Here is the snapshot of the scene.

The problem I meet is that I can't use Python to sample the output of a Mograph Effector(Sample Node With Python), and I haven't found a way to cumulate output of an Object List Node.
Thanks!
Hi @r_gigante,
Thank you for replying. I'd like to know more about this topic: if I only know the Control Point Index from PointObject.GetPoint(id) of a spline, how could I get the Spline Position of this point?
Hi, here is a thread from the old forum: Sample Node With Python.
I don't know if there will be any solution for now.
hi @passion3d,
There is no actual n-gon in the underlying layer of Cinema 4D.
Adjacent polygons use hidden edge to create n-gon-like shape(s).
Following code creates a 5-side polygon object:
import c4d, math
from c4d import utils
#Welcome to the world of Python
def main():
    pointCount = 5
    polygonCount = math.ceil(pointCount/4.0)                    # caculate minimum needed polygon number
    polyObj = c4d.BaseObject(c4d.Opolygon)                      # create an empty polygon object
    polyObj.ResizeObject(pcnt=pointCount, vcnt=polygonCount)    # resize object to have 5 points, 2 polygons
    # manually set all point position
    polyObj.SetPoint(id=0, pos=c4d.Vector(200,0,-200))
    polyObj.SetPoint(id=1, pos=c4d.Vector(-200,0,-200))
    polyObj.SetPoint(id=2, pos=c4d.Vector(-200,0,200))
    polyObj.SetPoint(id=3, pos=c4d.Vector(200,0,200))
    polyObj.SetPoint(id=4, pos=c4d.Vector(300,0,0))
    # associate points into polygons
    polygon0 = c4d.CPolygon(t_a=0, t_b=1, t_c=2, t_d=3)
    polygon1 = c4d.CPolygon(t_a=0, t_b=3, t_c=4)
    # set polygon in polygon object
    polyObj.SetPolygon(id=0, polygon=polygon0)
    polyObj.SetPolygon(id=1, polygon=polygon1)
    # set hidden edge
    nbr = utils.Neighbor()
    nbr.Init(op=polyObj, bs=None)                               # create Neighor counting all polygon in
    edge = c4d.BaseSelect()
    edge.Select(num=3)                                          # set selection, which is the id of the edge to be hidden
    polyObj.SetSelectedEdges(e=nbr, pSel=edge, ltype=c4d.EDGESELECTIONTYPE_HIDDEN)  # hide the edge
    polyObj.Message(c4d.MSG_UPDATE)
    doc.InsertObject(polyObj)
    c4d.EventAdd()
if __name__=='__main__':
    main()
Hi @cmpxchg8b and @a_block ,
I don't know much about matrix, but here is what I found.
If the point with arrow should rotate to aim, then all the possible position of the point must lay on the sphere surface which sphere's center is the parent object.
And one point and a vector can form a line in space.
So the question becomes a line-sphere intersection problem.
After solving the equations, we can get 2 points: original point and transformed point(s).
After that, we can find the transform matrix between 2 points.
btw, please read the How to Post Questions, Q&A New Functionality.
I think it's better to move this question into Cinema 4D Development category 
Hi @bonsak,
Try use op.GetObject().GetDeformCache().GetPointCount() in a Python Tag on the Polygon Object.
Here you can get more information: GetDeformCache().
@s_bach, thank you, I'll start to do some hard reading!
[I have so many questions in this thread. So first, please let me thank you for taking time!  ]
]
Hi,
I want to access user data in a more "procedural way". Here is the code after I do lots of searching on the Python (and C++) SDK document:
import c4d
from c4d import gui
#Welcome to the world of Python
def main():
    obj = doc.GetActiveObject()
    objBc = obj.GetData()
    
    userdataList = obj.GetUserDataContainer()
    userdata = userdataList[0]
    
    userdataBc = userdata[1]
    
    DescIDList = userdata[0]
    id0 = DescIDList[0].id
    id1 = DescIDList[1].id
    print(objBc[id0][id1])
if __name__=='__main__':
    main()
After this, I really want to know how the data of a BaseObject organized and stored. And I make a picture:

I don't know if this reveals some of the data structure of BaseObject.
And I have some doubts in or out of the picture:
[In the picture] After I search in the BaseContainer of BaseObject, I don't find anything data related to a Userdata: long name, short name, min/max value/default value, etc.
Where is the BaseContainer of all these data stored?
[In the picture] Is DescID is similar to  UUID of a BaseContainer? And where are they stored?
[In the picture] What is CreatorId of DescLevel? I only find 0 in this field.
[Out the picture] As for now, is there any easier way to get a textual form of DescLevel.id and DescLevel.dtype? Comparing and searching in branches of *.h files is not friendly for us without C++ experience.
[Off topic] The name index in sample code of BaseContainer.__iter__() in Python SDK Document is confusing. Especially that all other function documents refer the same thing as id on the same page.
[Off topic] Is there any articles that have more detail about the foundation concepts for cinema 4d coding?
Here I find some pages in Python SDK Document:
Cookbook, Plugin Structure, Introduction into the GUI of Cinema 4D.
But they are lack of details and relation with other document.
Also, some foundation concepts only have few introduction paragraphs:
BaseList2D,BaseContainer, etc.
I don't mean to complain, but it's frustrating after spending hours and hours searching in the SDK and the Internet but only get some obscure results. I hope the document could be more friendly to new developers.
Thanks a lot!
@c4ds, don’t worry! Every steps (even the off-road one) make some progress, right? I appreciate the way you focusing on the problem solving, which I believe is also the wonderful thing of this forum: we do our best to solving the problem itself, discussing about the better/more accurate answers rather than “who is right, who is wrong”. Last but not least, thank you for taking time to reply! 
Hi @bentraje,
Here is the code that can do:
import c4d
def AddLongDataType(obj):
    if obj is None: return
    bc = c4d.GetCustomDataTypeDefault(c4d.DTYPE_LONG) # Create default container
    bc[c4d.DESC_NAME] = "Test" # Rename the entry
    element = obj.AddUserData(bc) # Add userdata container
    obj[element] = 30 # Assign a value
    c4d.EventAdd() # Update
def main():
    obj = doc.GetActiveObject()    # Here you get selected/active object from scene
    AddLongDataType(obj)           # Call the AddLongDataType function to add user data to selected object
if __name__=='__main__':           # The "actual" place that code start to execute 
    main()                         # Call "main" function, start the processing
@s_bach, thank you very much! Now I see the whole picture!