Accessing object container in C++.



  • Hello! How can i do the same in C++?
    4727d1e4-611b-473e-b695-f6352e8f42c1-image.png
    The point is to set specific data by DescID. In python i can simply do what is on screenshot.

    But for C++ case isn't that simple.
    What i've tried already:

    • GetDataInstance();
      In this case i can only access Object Properties container, but not Coordinates.

    19131513-1e1e-4043-9ca4-9df7a5c64cc2-image.png

    • GetDescription();
      Also tried to use GetDescription(); and go through using GetNext();, but the problem is that BaseContaner is const, so i can't modify it.

    How to properly access any container of object?
    Thanks!



  • Hi,

    I do not think that this is possible in the way you want to do it. Certain parameters are simply not stored in the BaseContainer of a node. You have to use the specific methods for them. Also the Python side of things does not quite work out as your posting suggests (or at least how I do read it). Se below for details.

    Cheers,
    zipit

    """The feature you are looking for is actually not a feature of c4dpy's
    BaseContainer, but of its BaseList2D.__getitem__() and .__setitem().
    
    The code below demonstrates that things even in Python do not quite work out
    as your posting suggests. The reason for that is that certain attributes are
    not stored in the BaseContainer of a node. See C++ docs on BaseList2D::
    GetData() for details.
    """
    
    import c4d
    
    def main():
        """
        """
        if op is None:
            return
        
        # Using the Python wrapper via BaseList2D.__getitem__ to access the world
        # position of an object.
        print ("__getitem__ access:", op[c4d.ID_BASEOBJECT_ABS_POSITION])
        
        # Getting the data container instance.
        data = op.GetDataInstance()
    
        # There is no world position in there.
        # Note: The return value here being None obviously only works the first
        # time the script is being run, because below we will write the null
        # vector to this ID. 
        print ("container access:", data[c4d.ID_BASEOBJECT_ABS_POSITION])
        
        # We can write to that ID, but Cinema won't' respect it.
        data[c4d.ID_BASEOBJECT_ABS_POSITION] = c4d.Vector()
        print ("__getitem__ access after container write attempt:", 
               op[c4d.ID_BASEOBJECT_ABS_POSITION])
        
        # We have to use __setitem__ to make use of the nice unified parameter
        # access the Python wrapper does offer.
        op[c4d.ID_BASEOBJECT_ABS_POSITION] = c4d.Vector(100)
        print ("__getitem__ access after __setitem__ write attempt:", 
               op[c4d.ID_BASEOBJECT_ABS_POSITION])
    
        # The only way in C++ is to use BaseObject::GetMg() or the respective
        # position specific method. You will have to handle these DescIDs manually.
        
    
    if __name__=='__main__':
        main()
    
    __getitem__ access: Vector(-155.012, 70.587, -119.76)
    container access: None
    __getitem__ access after container write attempt: Vector(-155.012, 70.587, -119.76)
    __getitem__ access after __setitem__ write attempt: Vector(100, 100, 100)
    >>> 
    


  • Hi,

    I do not think that this is possible in the way you want to do it. Certain parameters are simply not stored in the BaseContainer of a node. You have to use the specific methods for them. Also the Python side of things does not quite work out as your posting suggests (or at least how I do read it). Se below for details.

    Cheers,
    zipit

    """The feature you are looking for is actually not a feature of c4dpy's
    BaseContainer, but of its BaseList2D.__getitem__() and .__setitem().
    
    The code below demonstrates that things even in Python do not quite work out
    as your posting suggests. The reason for that is that certain attributes are
    not stored in the BaseContainer of a node. See C++ docs on BaseList2D::
    GetData() for details.
    """
    
    import c4d
    
    def main():
        """
        """
        if op is None:
            return
        
        # Using the Python wrapper via BaseList2D.__getitem__ to access the world
        # position of an object.
        print ("__getitem__ access:", op[c4d.ID_BASEOBJECT_ABS_POSITION])
        
        # Getting the data container instance.
        data = op.GetDataInstance()
    
        # There is no world position in there.
        # Note: The return value here being None obviously only works the first
        # time the script is being run, because below we will write the null
        # vector to this ID. 
        print ("container access:", data[c4d.ID_BASEOBJECT_ABS_POSITION])
        
        # We can write to that ID, but Cinema won't' respect it.
        data[c4d.ID_BASEOBJECT_ABS_POSITION] = c4d.Vector()
        print ("__getitem__ access after container write attempt:", 
               op[c4d.ID_BASEOBJECT_ABS_POSITION])
        
        # We have to use __setitem__ to make use of the nice unified parameter
        # access the Python wrapper does offer.
        op[c4d.ID_BASEOBJECT_ABS_POSITION] = c4d.Vector(100)
        print ("__getitem__ access after __setitem__ write attempt:", 
               op[c4d.ID_BASEOBJECT_ABS_POSITION])
    
        # The only way in C++ is to use BaseObject::GetMg() or the respective
        # position specific method. You will have to handle these DescIDs manually.
        
    
    if __name__=='__main__':
        main()
    
    __getitem__ access: Vector(-155.012, 70.587, -119.76)
    container access: None
    __getitem__ access after container write attempt: Vector(-155.012, 70.587, -119.76)
    __getitem__ access after __setitem__ write attempt: Vector(100, 100, 100)
    >>> 
    


  • Hello. You can use GetParameter()/SetParameter().

    Those functions should usually work for all DescIDs and parameters belonging to an object, if I remember right.



  • Hi internally as stated in the documentation of GeListNode._setitem__ and GeListNode._getitem__ it's just a wrapper arround respectively C4DAtom.SetParameter and C4DAtom.GetParameter.

    Then Set/GetParameter will call the respective NodeData.G/SetDParameter of the GeListNode implementation. This method lets you define how the parameter access is done (aka retrieving the data from a local member variable or reading the base container made by the description).

    So if we go back to the s/getitem, internally in python it builds automatically a DescId based on the data provided doing a stupid If pyData.Class == PyBool: DescId(pyData, DTYPE_BOOL, 0) so you can easily reproduce this part too. But I don't think in C++ you can't support multiple arguments in the bracket operator see C++ [] array operator with multiple arguments?, so you could somehow hack around with the usual () operator, but our classic API doesn't really provide a mean of inspection so you will need to either do a lot of overrides or have unsafe void pointer arguments while PythonObject always has a type attached to them so you can at any time accept a PyObject* and retrieve is real DataType, and this is exactly what is possible to do with the MAXON API where you register datatype as MAXON_DATATYPE then they all can be retrieved in the form of a maxon::Data but you still have access to its maxon::Id and you can know the datatype ID and doing a safe casting.

    Hope this answers your questions.
    Cheers,
    Maxime.