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

    Does XRef or XRef simple are now accessible with Python?

    Cinema 4D SDK
    2023 python s26
    2
    7
    1.3k
    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.
    • mocolocoM
      mocoloco
      last edited by mocoloco

      Hi all,

      After some research on plugincafe, I found many old threads saying that XRef is not scriptable with Python. They are all from 2018, so, maybe in between the situation has changed and is it possible now to:

      • Change the c4d.ID_CA_XREF_FILE file referenced on the fly with Python
      • Change the Pivot vectors c4d.ID_CA_XREF_PIVOT_POS, c4d. c4d.ID_CA_XREF_PIVOT_ROT and c4d.ID_CA_XREF_PIVOT_SCL
      • Force a reload with c4d.ID_CA_XREF_REFRESH if the file referenced has changed?

      I do know that's a lot of question, but prior investigated and spending time on this subject I would prefer to be sure that is possible. @ferdinand, your inputs on this are more than welcome!

      Thanks a lot,
      Cheers,

      Christophe

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

        Hey @mocoloco,

        Thank you for reaching out to us. I am not quite sure where you found the information that Oxref is 'not scriptable', but that information does not seem quite right to me. You just have to be a bit more verbose when setting parameters. Find an example below.

        Cheers,
        Ferdinand

        Result:
        Screenshot 2022-12-20 at 13.24.42.png

        Code:

        """Provides an example for setting Xref object parameters.
        """
        import c4d
        
        doc: c4d.documents.BaseDocument # The active document.
        
        def main() -> None:
            """
            """
            xref: c4d.BaseObject = c4d.BaseObject(c4d.Oxref)
            if not xref:
                raise MemoryError("Could not allocate Xref object.")
            
            # Add the Xref to the document and define the url for the 'Pillow Decorative' object asset.
            doc.InsertObject(xref)
            assetUrl: str = "asset:///file_0de9c0c9d02f0d77~.c4d"
        
            # The sort of trick is here, that you must be a bit more verbose with setting parameters,
            # and and cannot use the high level __setitem__, e.g., `node[myId]` access. Instead, you must
            # use the lower level C4DAtom.Get/SetParameter access and simulate a user interaction. The Xref
            # object is a bit special :D
            
            # The DescID for the things you want to write, Get/SetParameter only accepts fully formed DescID.
            fileId: c4d.DescID = c4d.DescID(c4d.DescLevel(c4d.ID_CA_XREF_FILE, c4d.DTYPE_FILENAME, 0))
            posId: c4d.DescID = c4d.DescID(c4d.DescLevel(c4d.ID_CA_XREF_PIVOT_POS, c4d.DTYPE_VECTOR, 0))
            rotId: c4d.DescID = c4d.DescID(c4d.DescLevel(c4d.ID_CA_XREF_PIVOT_ROT, c4d.DTYPE_VECTOR, 0))
        
            # Set the Xref to the asset and write some pivot data.
            xref.SetParameter(fileId, assetUrl, c4d.DESCFLAGS_SET_USERINTERACTION)
            xref.SetParameter(posId, c4d.Vector(0, 100, 0), c4d.DESCFLAGS_SET_USERINTERACTION)
            xref.SetParameter(rotId, c4d.Vector(c4d.utils.DegToRad(30)), c4d.DESCFLAGS_SET_USERINTERACTION)
        
            c4d.EventAdd()
        
            # Clicking the button is not necessary the xref is already correctly setup after the event.
        
        if __name__ == "__main__":
            main()
        
        

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 1
        • mocolocoM
          mocoloco
          last edited by mocoloco

          Hello @ferdinand,

          Thanks a lot for your reactivity. Like said is was through old post here from 2018 and nothing more relevant to go through it.

          Does the FileName have to start with asset::///?

          I'm on MacOSX and when I'm writing the following below the file parameter in XRef remains blank without raising any error on console. Even if it seems I understood the DescID formatting.

          xRefFile = "Assets/default_xref.c4d"
          
          xRefPivot = baseDoc.SearchObject('mPivot')
               if xRefPivot is not None:
                    print ("mPivot found")
                    if (baseDoc.SearchObject('mXRef')) is None:
                         mXRefObj = c4d.BaseObject(c4d.Oxref) #c4d.BaseObject(c4d.Oxrefsimple) # R2023 only
                         mXRefObj.InsertUnder(xRefPivot) 
                         mXRefObj.SetName("mXRef")
                  
                    mXRefObj = baseDoc.SearchObject('mXRef')
                    # Assign paramters on mXRef
                    print(f"File: { XRefFile }" )
                    descID = c4d.DescID(c4d.DescLevel(c4d.ID_CA_XREF_FILE, c4d.DTYPE_FILENAME, 0))
                    mXRefObj.SetParameter(descID, XRefFile, c4d.DESCFLAGS_SET_PARAM_SET)
                    print('Model successfully imported')
                    c4d.EventAdd()
                else:
                    print("Model can't be imported")
          

          The only difference was about c4d.DESCFLAGS_SET_PARAM_SET while you are using c4d.DESCFLAGS_SET_USERINTERACTION. But in that case, could we consider this as a User interaction?

          Thanks

          1 Reply Last reply Reply Quote 0
          • mocolocoM
            mocoloco
            last edited by mocoloco

            Indeed, the problem was caused by using c4d.DESCFLAGS_SET_PARAM_SET instead of c4d.DESCFLAGS_SET_USERINTERACTION.

            After reading the SDK documentation again, as far as I understand the XRef Filename is considered as a User Interactive Element. That way, it seems mandatory to have c4d.DESCFLAGS_SET_USERINTERACTION to set the parameter. I assume that's the case for all the parameter accessible by the user in a Ge.

            Thanks for the example @ferdinand, it helped me to point this out!

            One more question; I'm continuing to explore XRef and I can't really find if there returned value or flag by XRef when the object is correctly loaded.
            Is there such a thing, or do I need to check if the Xref object have childs which means somehow that the load happened correctly?

            Cheers,
            Christophe

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

              Hi @mocoloco,

              Does the FileName have to start with asset::///?

              No, I only used an asset here so that example runs on any machine (and does not require a specific file on a local volume).

              The string assetUrl is deliberately named this way, because we effectively define a maxon.Url here. The parameter ID_CA_XREF_FILE is of type Filename. The type does not explicitly exist in the Python API and is instead represented by str. Internally, all Filename are however converted to and represented as maxon::Url. Filename is just a classic API thin wrapper for maxon::Url.

              asset:/// is the scheme of this URL and maxon::Url supports many schemes; asset and file are just two of them. To define a URL in the file scheme you can either do it implicitly, provide no scheme, or be explicit.

              assetUrl: str = r"E:/cube.c4d" # Implicitly in the file scheme
              assetUrl: str = r"file:///E:/cube.c4d"
              

              it seems mandatory to have c4d.DESCFLAGS_SET_USERINTERACTION to set the parameter. I assume that's the case for all the parameters accessible by the user in a Ge.

              I am not sure what you meant with 'Ge', but in general that is not the case. In most cases you can use GeListNode.__getitem__ and GeListNode.__setitem__ to access parameters. For more complex parameter access you sometimes need C4DAtom.Get/SetParameter, usually with the flags DESCFLAGS_GET_NONE and DESCFLAGS_SET_NONE. It is only in very rare cases that you have to simulate a user interaction with DESCFLAGS_SET_USERINTERACTION. This happens when the internal data of a node is much more complex than its parameters make it look like and the node must manage the data on each parameter change. Oxref is an example and also the new Orscamera, i.e., the new standard camera.

              One more question; I'm continuing to explore XRef and I can't really find if there returned value or flag by XRef when the object is correctly loaded.

              I do not think so, that would be very uncharacteristic for the classic API. Message streams are there sealed, i.e., not accessible for outside observers. Sometimes nodes write a state into a hidden parameter, but looking at the Xref description I cannot see such parameter.

              Where would that be relevant for you? Once you have passed the EventAdd() in my script, the object should be finalized. You could technically also send xref.Message(c4d.MSG_CHANGE) to the atom, but this is a bit pointless since you do not get a response for this message and the node is updating anyways.

              Cheers,
              Ferdinand

              MAXON SDK Specialist
              developers.maxon.net

              1 Reply Last reply Reply Quote 0
              • mocolocoM
                mocoloco
                last edited by mocoloco

                Good morning @ferdinand,

                Thanks a lot for all the explanation, I really appreciate, it clarify a lot of stuff and fill the gap. I consider this thread Solved. Thanks.

                "Where would that be relevant for you? Once you have passed the EventAdd() in my script, the object should be finalized"

                Should, that's why I asked. Maybe the XRef plugin raise an error or a dialog box saying that something wrong happened. I also had a look on the XRef description, and thought at first that LOADED parameter what was I was looking, but it is not.

                PS: I used 'Ge' to design all the user interactive elements such as Sliders, Input for value vector etc. It was maybe a wrong designation, sorry.

                Cheer,
                Christophe

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

                  Hey @mocoloco,

                  Should, that's why I asked.

                  Yeah, that is not the style of the classic API, there are only little error messages and things like that. What you can also do, is use the return value of SetParameter, a boolean. It will be False when setting the parameter failed.

                  I used 'Ge' to design all [...]

                  Eh, I understand, you mean from GeDialog, or what? I think it just stands for GenericDialog, it also pops up in thing like GeListNode or GeClipMap. There are some really old entities in the classic API and naming conventions were different then šŸ˜‰ Ge is at least not a name for interface gadgets in our APIs.

                  Cheers,
                  Ferdinand

                  MAXON SDK Specialist
                  developers.maxon.net

                  1 Reply Last reply Reply Quote 0
                  • B BackendKG referenced this topic on
                  • First post
                    Last post