Python - InExcludeData initialization problem



  • I had a problem (again) with InExcludeData. this time with initializing the thing

    Also, it seems like there is no way to merge two different InExcludeData fields to make a single InExcludeData list with no object duplicates on it.

    Can any of you can explain to me how can I really do this using Python?
    8333ccd7-1f71-49e9-aa85-e7296b4a2eee-image.png
    It basically was unclear for me as of now...



  • Hi,

    the docs are trying to tell you that the argument v is an optional argument. For the rest, see the attached example.

    Cheers,
    zipit

    """ Run this in the Script Manager.
    
    You will need to select an object in your scene, which has InExcludeData 
    fields as its first and second user data element. The fields should be
    ideally populated with overlapping sets of objects (e.g. [a, b, c] and [b, 
    c, d]). The script will write the union of those two object sets to the first
    InExcludeData field.
    """
    
    import c4d
    
    def get_objects(doc, op):
        """Returns the objects referenced by an InExcludeData as a list.
        
        Args:
            doc (c4d.documents.BaseDocument): The document the referenced 
             objects are attached to.
            op (c4d.InExcludeData): The InExcludeData to get the objects from.
        
        Returns:
            list[c4d.BaseObject]: The referenced objects.
        """
        return [op.ObjectFromIndex(doc, i) 
                for i in range(op.GetObjectCount())]
    
    def main():
        """
        """
        if op is None:
            return
    
        # The two InExcludeData
        inex_a = op[c4d.ID_USERDATA, 1]
        inex_b = op[c4d.ID_USERDATA, 2]
    
        # Get the objects 
        nodes_a = get_objects(doc, inex_a)
        nodes_b = get_objects(doc, inex_b)
        print "nodes in inex_a:", nodes_a
        print "nodes in inex_b:", nodes_b
    
        # Create a new InExcludeData, using the default constructor.
        inex_c = c4d.InExcludeData()
        # Unsurprisingly there is nothing in there.
        print "nodes in inex_c:", get_objects(doc, inex_c)
    
        # Create a new InExcludeData, using the copy constructor.  
        inex_d = c4d.InExcludeData(inex_a)
        # Since we copied from inex_a, it references the same objects.
        print "nodes in inex_d:", get_objects(doc, inex_d)
    
        # Adding the union of the object sets a and b to a new InExcludeData is
        # a little bit convoluted, because the type InExcludeData is not a set
        # by nature and nodes not being hashable prevents us from using Python's
        # sets.
        nodes_union = nodes_a + [n for n in nodes_b if n not in nodes_a]
        inex_union = c4d.InExcludeData()
        for node in nodes_union:
            inex_union.InsertObject(node, 0)
    
        # Write the union back to the first InExcludeData. 
        op[c4d.ID_USERDATA, 1] = inex_union
        c4d.EventAdd()
    
    
    if __name__=='__main__':
        main()```


  • Hi @SolarPH, thanks for reaching out us.

    With regard to your question, actually initializing the InExcludeData has nothing to do with having the list not including duplicates.
    The v parameter pointed out in the documentation is used to fill the to-be-created InExcludeData with the values found in the passed InExcludeData as @zipit has shown in line 48.
    To avoid duplication instead you've to manually browse the items in the lists and pickup from the second only those not found in the first. Again @zippit code perfectly shows this.

    Cheers, R



  • @zipit Thanks for sharing the code. Now I know that initializing the InExcludeData is not InExcludeData.__init__ and the correct way was c4d.InExcludeData(), which I really did not think of when initializing specialized data containers.



  • Hi,

    @SolarPH said in Python - InExcludeData initialization problem:

    Now I know that initializing the InExcludeData is not InExcludeData.__init__ and the correct way was c4d.InExcludeData(), ...

    I am not quite sure how you did mean this, but InExcludeData.__init__ is one of the methods called when you invoke c4d.InExcludeData(). Like all double underscore methods __init__ implements an operator, in that case the construction operator. Invoking SomeClass() will first call the constructor SomeClass.__new__ and after that the initialisator SomeClass.__init__. Due to the fact that __new__ only rarely has to be implemented explicitly and because people are accustomed to talking about constructor functions, __init__ is also often called a constructor, while technically it is just the initialisator. A prime example would be both the InExcludeData documentation and my example code, which both talk about a copy constructor, but are actually referring to __init__ and not __new__.

    Cheers,
    zipit


Log in to reply