Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    How to Manually Build the Cache for a Vector Import Instance?

    Cinema 4D SDK
    2
    3
    522
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • I
      InterfaceGuy
      last edited by

      Hello,

      now with the updated Vector Import object in S26 I thought there might be a more elegant way to import an SVG directly to a spline.
      But after playing around with it for a bit I am struggling to extract the spline from the setup using python only.

      Here is my code:

              vector_import = c4d.BaseObject(1057899)
              self.document.InsertObject(vector_import)
              # set file path
              file_path = os.path.join(SVG_PATH, self.file_name + ".svg")
              vector_import[c4d.ART_FILE] = file_path
              # extract spline from hierarchy
              vector_import[c4d.ART_SHOW_HIERARCHY] = True
              c4d.CallButton(vector_import, c4d.ART_RELOAD)
              c4d.EventAdd()
              spline = vector_import.GetDown().GetDown().GetDownLast()
      

      The problem seems to be that even after calling the reload button and c4d.EventAdd() which makes the hierarchy containing the spline visible in the GUI, C4D does not recognise that the vector_import object now has children.

      Help would be appreciated!

      ferdinandF 1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand @InterfaceGuy
        last edited by ferdinand

        Hello @interfaceguy,

        Thank you for reaching out to us. Please open a new topic for new questions as lined out in our Forum Guidelines: Rules of Conduct. This is not a follow up question to your initial question. I have forked your question, for future cases we might refuse to answer your questions when this rule is not followed.

        About your question, the following statement is not true:

        calling the reload button and c4d.EventAdd() which makes the hierarchy containing the spline visible in the GUI, C4D does not recognize that the vector_import object now has children.

        Invoking the button and EventAdd will not build the caches for your object. It is only after your script has ended that Cinema 4D will do that automatically for you. Which is probably why you came to that conclusion, but when you call GetDown() on your vector_import, it still has no children. You must execute the passes on an object/document when you want to access/build the caches of it immediately after a parameter change or when the object has been newly instantiated.

        Find an example at the end of this posting.

        Cheers,
        Ferdinand

        The result:

        ecd4127d-5788-4245-9b5b-22298018b8aa-image.png

        The code:

        """Simple example for evaluating the cache of a generator.
        """
        
        import c4d
        import typing
        
        doc: c4d.documents.BaseDocument  # The active document
        op: typing.Optional[c4d.BaseObject]  # The active object, None if unselected
        
        def AssertType(item: any, t: typing.Union[typing.Type, tuple[typing.Type]], lbl: str) -> any:
            """Asserts #item to be of type #t.
        
            When the assertion succeeds, #item is passed through, otherwise a type error with #lbl referring
            to #item is being raised.
            """
            if not isinstance(item, t):
                raise TypeError(f"Expected item of type '{t}' for '{lbl}'. Received: {type(item)}")
            
            return item
        
        def main() -> None:
            """
            """
            # Instantiate the vector import object.
            node: c4d.BaseObject = AssertType(c4d.BaseObject(1057899), c4d.BaseObject, "node")
        
            # Due to a bug in the vector import object, Cinema 4D will crash when attempting to write the
            # ART_FILE parameter without the node being attached to a document. Normally we would set here
            # this parameter, as this would make more sense, now it has been moved to line 44 for this
            # reason.
        
            # The node #node has now no caches, i.e., the generator has not run yet and no amount of button
            # clicking and EventAdd() will change that. We must build the caches by executing the passes
            # on #node. For that #node must be part of a document. We could insert #node into the active 
            # document and execute the passes there, but this has two drawbacks:
            #
            #   1. This cannot be done in any non-main thread context, as it might then crash Cinema 4D.
            #   2. This can also be slow, as it will also revaluate everything else which is in the active
            #      document.
            #
            # So, we are going to do this in a temporary document.
        
            BaseDocument = c4d.documents.BaseDocument
            temp: BaseDocument = AssertType(BaseDocument(), BaseDocument, "temp")
            temp.InsertObject(node)
        
            # Set the parameter for the file.
            node[c4d.ART_FILE] = "E:\myFile.svg"
        
            # Build all caches in the document.
            temp.ExecutePasses(
                bt=None, animation=False, expressions=False, caches=True, flags=c4d.BUILDFLAGS_NONE)
        
            # Node now has a cache, and also its hierarchy would be populated if we had set 
            # ART_SHOW_HIERARCHY to True. But we can also just reach into the cache now when we want
            # to access the output of the generator. We can also remove #node now from the temporary
            # document, as the cache is bound to the node itself. We also must do this if we want to
            # insert #node into another document (or return it in a GVO method), as a node can only
            # be part of one document.
            node.Remove()
        
            # Get the cache.
            cache: c4d.BaseObject = AssertType(node.GetCache(), c4d.BaseObject, "cache")
            print (f"{cache = }")
        
            # Some like this should never be done, as every step in this chained function call can return
            # a null-pointer, i.e., None in Python.
            # spline = vector_import.GetDown().GetDown().GetDownLast()
        
            # Get the sort of thing you wanted to get. It is in general not safe to navigate hierarchies in
            # this predetermined manner but this will at least not stop your code when the assumption
            # fails inevitably.
            if cache.GetDown():
                cache = cache.GetDown()
                if cache.GetDown():
                    cache = cache.GetDown()
                    if cache.GetDownLast():
                        cache = cache.GetDownLast()
        
            # Do stuff with this part of the cache.
            if isinstance(cache, c4d.PointObject):
                for p in cache.GetAllPoints():
                    print (p)
        
            # When we wanted to insert this part of the cache into the active (or any other) document, we
            # must clone it first.
            clone: c4d.BaseObject = AssertType(cache.GetClone(c4d.COPYFLAGS_0), c4d.BaseObject, "clone")
        
            # Insert both the generator and a copy of a part of its cache.
            doc.InsertObject(node)
            doc.InsertObject(clone)
            
            c4d.EventAdd()
        
        if __name__ == '__main__':
            main()
        

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • I
          InterfaceGuy
          last edited by

          works like a charm, thank you!

          1 Reply Last reply Reply Quote 0
          • First post
            Last post