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
    1. Maxon Developers Forum
    2. pim
    3. Topics
    P
    • Profile
    • Following 0
    • Followers 0
    • Topics 92
    • Posts 279
    • Best 8
    • Controversial 0
    • Groups 0

    Topics created by pim

    • P

      Graphic card

      General Talk
      • off-topic • • pim
      4
      0
      Votes
      4
      Posts
      816
      Views

      P

      Great input, thanks.
      I will have a look at the Mac mini, if not, I will go back to a windows desktop.
      Again, thank you both.

      Regards,
      pim

    • P

      Setting Noise as the Shader in a Displacer

      Cinema 4D SDK
      • python 2023 • • pim
      4
      0
      Votes
      4
      Posts
      851
      Views

      P

      Ok, I understand it now better, thanks.

    • P

      Best way to detect an object has been deleted?

      Cinema 4D SDK
      • python 2023 • • pim
      5
      0
      Votes
      5
      Posts
      1.1k
      Views

      P

      Thanks again for the great explanation.
      I guess I will go for a different workflow then.

    • P

      Insert my own command in main render Tab

      Cinema 4D SDK
      • python 2023 • • pim
      7
      0
      Votes
      7
      Posts
      1.4k
      Views

      P

      I really do appreciate all your effort and I will take your warning seriously and create my own menu Tab.
      Thanks again.

      Regards,
      Pim

    • P

      Getting only the last value of the slider (slide)

      Bugs
      • 2023 python • • pim
      5
      0
      Votes
      5
      Posts
      1.3k
      Views

      P

      Great work!!!
      Thank you.

      Regards,
      Pim

    • P

      Storing an object link and a mat link in a hyperfile

      Cinema 4D SDK
      • 2023 python • • pim
      3
      0
      Votes
      3
      Posts
      583
      Views

      i_mazlovI

      Hi @pim,

      Thanks for reaching out to us. The links are document-specific so they only make any sense in the context of the document that they were created in. It means that once stored, restoring them back would only correspond to the exact same objects in the exact same document. If it's not your case, then you'd need to define the criteria of what you mean by two objects being the same (is it only a name or a combination of the name with any other properties, e.g. hierarchy?).

      However, if the context of these objects stays the same, then you can use the same trick as @ferdinand mentioned in the point selection thread. Namely, using MAXON_CREATOR_ID for extracting the UUIDs of the objects. These UUIDs can be stored in the Hyperfile (just as simple strings). So whenever you need to restore them, you would need to traverse the document tree and compare the actual object UUID with the one you're restoring.

      One can also use GetClassification() function to retrieve the type of the object, which would make traversing the document a little more efficient.

      Please find the sample script implementing the explained approach below.

      Let me know if you have any further questions.
      Cheers,
      Ilia

      Cinema_4D_IfZOkEU8lw.gif

      import c4d LINK_OBJ_ID = 1001 LINK_MAT_ID = 1002 BTN_SAVE_ID = 1003 BTN_LOAD_ID = 1004 BTN_RESET_ID = 1005 HF_IDENT = 49545 PATH = 'd:\\_tmp\\lnkbox.bin' class MainDialog(c4d.gui.GeDialog): def __init__(self): self.linkBoxes : dict[int, c4d.gui.BaseCustomGui] = {} def CreateLayout(self): self.GroupBegin(2001, c4d.BFH_FIT, cols=1) self.linkBoxes[0] = self.AddCustomGui(LINK_OBJ_ID, c4d.CUSTOMGUI_LINKBOX, "Obj", c4d.BFH_SCALEFIT, 100, 4) self.linkBoxes[1] = self.AddCustomGui(LINK_MAT_ID, c4d.CUSTOMGUI_LINKBOX, "Mat", c4d.BFH_SCALEFIT, 100, 4) self.GroupEnd() self.GroupBegin(2002, c4d.BFH_FIT, cols=3) self._btnSave = self.AddButton(BTN_SAVE_ID, c4d.BFH_SCALEFIT, name="Store links") self._btnLoad = self.AddButton(BTN_RESET_ID, c4d.BFH_SCALEFIT, name="Reset links") self._btnSave = self.AddButton(BTN_LOAD_ID, c4d.BFH_SCALEFIT, name="Load links") self.GroupEnd() return True def Command(self, id, msg): if id == BTN_SAVE_ID: self.save(PATH) elif id == BTN_LOAD_ID: self.load(PATH) elif id == BTN_RESET_ID: self.reset() return True @staticmethod def GetUUID(node: c4d.C4DAtom) -> bytes: """Returns an UUID for #node which identifies it over reallocation boundaries""" if not isinstance(node, c4d.C4DAtom): raise TypeError(f"{node = }") data: memoryview = node.FindUniqueID(c4d.MAXON_CREATOR_ID) if not isinstance(data, memoryview): raise RuntimeError(f"Could not access UUID for: {node}") return bytes(data) @staticmethod def traverseSubtree(bl : c4d.BaseList2D): """Half-recursively iterates over baselist elements and its children""" while bl: yield bl for child in MainDialog.traverseSubtree(bl.GetDown()): yield child bl = bl.GetNext() @staticmethod def traverseDocument(doc : c4d.documents.BaseDocument, callBack, classification): """Executes callback for each document element depending on classification""" if doc is None: raise ValueError("doc is None") bl : c4d.BaseList2D = None if classification == c4d.Obase: bl = doc.GetFirstObject() elif classification == c4d.Mbase: bl = doc.GetFirstMaterial() for op in MainDialog.traverseSubtree(bl): if not callBack(op): # callback returns false if no further traversing needed return def reset(self): """Reset links in the gui""" for lnkbox in self.linkBoxes.values(): lnkbox.SetLink(None) def save(self, path): """Store links UUID and Classification in the Hyperfile""" bcFile = c4d.BaseContainer() hf = c4d.storage.HyperFile() if hf.Open(ident=HF_IDENT, filename=path, mode=c4d.FILEOPEN_WRITE, error_dialog=c4d.FILEDIALOG_NONE): for idx, lnkbox in self.linkBoxes.items(): lnk : c4d.BaseList2D = lnkbox.GetLink(c4d.documents.GetActiveDocument()) if lnk is None: print("No link selected!") continue uuid : str = MainDialog.GetUUID(lnk).hex() bc = c4d.BaseContainer() bc[0], bc[1] = uuid, lnk.GetClassification() bcFile.SetContainer(idx, bc) hf.WriteContainer(bcFile) else: c4d.gui.MessageDialog("Couldn't open file for writing") hf.Close() def load(self, path): """Unpack UUIDS from Hyperfile and search for corresponding objects""" uuid : str = None obj : c4d.BaseObject = None classification : int = 0 def process(op): """Callback lambda: store object once the correct one has been found""" nonlocal obj if op is not None and MainDialog.GetUUID(op).hex() == uuid: obj = op return False return True hf = c4d.storage.HyperFile() if hf.Open(ident=HF_IDENT, filename=path, mode=c4d.FILEOPEN_READ, error_dialog=c4d.FILEDIALOG_NONE): bcFile : c4d.BaseContainer = hf.ReadContainer() for idx, lnkbox in self.linkBoxes.items(): bc : c4d.BaseContainer = bcFile.GetContainer(idx) uuid, classification = bc[0], bc[1] MainDialog.traverseDocument(c4d.documents.GetActiveDocument(), process, classification) if uuid is not None and obj is not None: lnkbox.SetLink(obj) else: c4d.gui.MessageDialog("Couldn't open file for reading") hf.Close() if __name__=='__main__': dlg = MainDialog() dlg.Open(c4d.DLG_TYPE_ASYNC, defaultw=256, xpos=-2, ypos=-2)
    • P

      Create User Data with Data Type Spline

      Cinema 4D SDK
      • python 2023 • • pim
      4
      0
      Votes
      4
      Posts
      849
      Views

      ferdinandF

      Hey @pim,

      It is great to hear that your problem is solved. And to be clear: You can use ChatGPT and Co. to write your code; I would simply ask you to disclose it if you post code (partially) generated by a bot.

      We understand and agree that chat bots can be a useful tool especially for beginners. But they also have a tendency to write code that is just made up gibberish. When we know that the code has been written by a bot, we can say "that is just noise/garbage". If we do not, we have to point out all problems individually, not only to not offend the author by calling his or her code "garbage", but to also to help the user to understand his or her mistakes.

      Cheers,
      Ferdinand

    • P

      Getting the spline from the SplineCustomGui

      Cinema 4D SDK
      • python 2023 • • pim
      2
      0
      Votes
      2
      Posts
      461
      Views

      ferdinandF

      Hello @pim,

      Thank you for reaching out to us. As announced here, Maxon is currently conducting a company meeting. Please understand that our capability to answer questions is therefore limited at the moment.

      The custom GUI for SplineData has its own dedicated GUI type, c4d.gui.SplineCustomGui as pointed out by yourself. So, you must use SplineCustomGui.GetSplineData instead of the generic BaseCustomGui.GetData.

      Cheers,
      Ferdinand

    • P

      Using / copying object properties dialog

      Cinema 4D SDK
      • python 2023 • • pim
      5
      0
      Votes
      5
      Posts
      685
      Views

      P

      Thanks for the clear answer.
      I know the difference between description and dialog, but I was hoping I could re-use already defined description in a dialog.
      But I follow your advise and recreate the settings.

      Regards,
      Pim

    • P

      Checking for ALT GetInputState() issue

      Cinema 4D SDK
      • python 2023 • • pim
      6
      0
      Votes
      6
      Posts
      1.1k
      Views

      P

      Great, thank you
      Glad I can help to improve this great program.

    • P

      Place multiple objects on spline and align

      Cinema 4D SDK
      • python 2023 • • pim
      5
      0
      Votes
      5
      Posts
      1.6k
      Views

      P

      And once again, thank you!

    • P

      Setting Material Preview for 1 material

      Cinema 4D SDK
      • 2023 python • • pim
      3
      0
      Votes
      3
      Posts
      520
      Views

      P

      Thank you.

    • P

      Snap to grid while MouseDrag()

      Cinema 4D SDK
      • 2023 python • • pim
      2
      0
      Votes
      2
      Posts
      409
      Views

      ferdinandF

      Hello @pim,

      Thank you for reaching out to us. It depends a bit on what you expect to happen here.

      There is the snapping module of Cinema 4D but you cannot actually get values out of it, i.e., you cannot compute the snapped value of x with it, you can only define the snap settings with it.

      But when I understand your correctly, you just want to quantize some mouse inputs for a plugin and for that you must indeed compute the values yourself. It is best to also draw a snapping location onto the screen, so that user can see where the actual input is in relation to the mouse.

      How the snapping works in detail depends on what you want to do exactly when quantizing your plane drawing. The snapping module might become relevant here, because with it you can retrieve the working planes, which might be useful when placing planes.

      Cheers,
      Ferdinand

    • P

      Plugin opens on Mac not correctly

      Cinema 4D SDK
      • 2023 python macos • • pim
      13
      0
      Votes
      13
      Posts
      1.6k
      Views

      ferdinandF

      Hello @pim,

      In addition to my answer via mail, I will also answer here, as this might be interesting for the rest of the community.

      Cheers,
      Ferdinand

      So, the question was here "Why does my tree view not open with the right size?". The easy answer to this is that:

      You did neither set a minimum size for the dialog in GeDialog.Open(). Nor one for the tree view itself via GeDialog.AddCustomGui().

      Both in conjunction did result in your dialog collapsing down to zero height.

      What can I do?

      Not much, the TreeViewCustomGui is not designed to scale to the size of its content. The underlying question is what you expect to happen here.

      a. Just have the tree view have some fixed minimum size, regardless of its content.
      b. Have the tree view initialize automatically to size, i.e., when the view has 10 items upon opening, it should have exactly 10 items height.

      When it is (a.) what you want, then this is easily doable with the minimum size passed to GeDialog.AddCustomGui(). When it is (b.), then you are more or less out of luck, as a tree view cannot scale automatically to the size of its content.

      You can adjust the minimum size dynamically based on the content which is going to be placed in the tree view, but when the content changes, you will have to flush your layout in order to be able to set a new minimum size.

      On a practical level it is also not so desirable to have a tree view scale like this, as this minimum height is not well defined. Should it be all items, or just all top level items, i.e., fully collapsed or fully expanded (which is implied by your example as all nodes start out as expanded). Let's say we choose fully collapsed. What happens when you have so many root nodes that the tree view will not fit on screen when making space for all root nodes.

      Example Result

      The dialog is set to have a minimum height which matches the total number of nodes in it.

      58d6b1aa-de83-484f-9d48-d6a0d327a98f-image.png

      Code

      I had to cut here a bit, but the relevant parts are:

      class TreeNode: # ... def __len__(self): """(f_hoppe): Counts all descendants of this node, including the node itself. Implemented fully recursively. Should be implemented iteratively for production due to stack overflows and Python's recursion limit preventing them. Or the data should be acquired when textures are collected. """ count: int = 1 for child in self.children: count += len(child) class ListView(c4d.gui.TreeViewFunctions): COLUMN_COUNT: int = 1 MIN_LINE_HEIGHT: int = 24 MIN_WIDTH: int = 500 def __init__(self): # The root nodes of the tree view. self._rootNodes: list[TreeNode] = [] def __len__(self): """(f_hoppe): Returns the number of tree nodes in the instance. """ return sum([len(node) for node in self._rootNodes]) def GetMinSize(self) -> tuple[int, int]: """(f_hoppe): Returns the minimum GUI size for the data of this ListView instance. """ # But all these classic API pixel values are quite wonky anyways and the tree view does # many custom things. So we must do some ugly magic number pushing. Subtracting nine units # from the actual height of each row gave me sort of the best results, but the tree view # GUI does not scale linearly in height with the number of rows. Meaning that what looks # good for 5 items might not look good for 50 items. return (ListView.MIN_WIDTH, (ListView.MIN_LINE_HEIGHT - 9) * len(self)) def GetColumnWidth(self, root: TreeNode, userdata: None, obj: TreeNode, col: int, area: c4d.gui.GeUserArea): """(f_hoppe): This cannot be a constant value, as we will otherwise clip data. """ return area.DrawGetTextWidth(obj.textureName) + 24 def GetLineHeight(self, root, userdata, obj, col, area): """(f_hoppe): Used constant value. """ return ListView.MIN_LINE_HEIGHT # ... class SimpleDialog (c4d.gui.GeDialog): ID_TRV_TEXTURES: int = 1000 def __init__(self) -> None: self._treeView: c4d.gui.TreeViewCustomGui = None # This builds the tree node data so that self._listView._rootNodes holds the top level # node(s) for the tree managed by this ListView instance. self._listView: ListView = self.GetTree() super().__init__() def CreateLayout(self) -> bool: """(f_hoppe): I substantially rewrote this. """ # Because we already initialized the ListView data, we can use it to compute the minimum # size of the gadget. w, h = self._listView.GetMinSize() print(f"{self._listView.GetMinSize() = }, {len(self._listView) = }") # Use these values to define a default size so that it shows all columns. What you want to # be done here is sort of not intended by the TreView GUI, although admittedly desirable. # The closest thing we can do is set the minimum size for the gadget, so that all lines # will fit into it. This will then ofc also have the side effect that the GUI cannot be # scaled down beyond this point. You might want to implement ListView.GetMinSize() in a # different manner, so that it does not take into account all nodes and instead just the # top level nodes. self._treeView = self.AddCustomGui( id=SimpleDialog.ID_TRV_TEXTURES, pluginid=c4d.CUSTOMGUI_TREEVIEW, name="", flags=c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, minw=w, minh=h, customdata=SimpleDialog.SETTINGS_TREEVIEW) if not isinstance(self._treeView, c4d.gui.TreeViewCustomGui): raise MemoryError(f"Could not allocate tree view.") # If you want to do this at runtime, i.e., load a new texture path, you would have to # call GeDialog.LayoutChanged() on the layout group which contains the tree view, add # the tree view again (with new min size values), and then call GeDialog.LayoutChanged() # on the group. It might be easier to just live with a fixed minimum size just as # (300, 300) return True # ...
    • P

      Get material / texture resolution.

      Cinema 4D SDK
      • 2023 python • • pim
      3
      0
      Votes
      3
      Posts
      559
      Views

      P

      Thanks for the good explanation and the example.

      Regards,
      Pim

    • P

      Redshift constants

      Cinema 4D SDK
      • 2023 python • • pim
      7
      0
      Votes
      7
      Posts
      1.4k
      Views

      ferdinandF

      Hey @fastrube,

      The bump map type is an integer value as explained above by @Manuel and as explained here in a bit more verbose form in the graph description manual.

      Cheers,
      Ferdinand

    • P

      Create RS Standard Material instead of RS Material

      Cinema 4D SDK
      • 2023 python • • pim
      6
      0
      Votes
      6
      Posts
      913
      Views

      P

      Ok, thank you.

    • P

      Creating standaard node material with several nodes (and connections)?

      Cinema 4D SDK
      • 2023 python • • pim
      8
      0
      Votes
      8
      Posts
      1.2k
      Views

      P

      Thanks for the good explanation.

    • P

      Mac M1 bug?

      Cinema 4D SDK
      • r25 python • • pim
      8
      0
      Votes
      8
      Posts
      1.1k
      Views

      ferdinandF

      Hello @pim,

      without any further questions and other postings, we will consider this topic as solved and flag it as such by Friday, 17/06/2022.

      Thank you for your understanding,
      Ferdinand

    • P

      Create a Take

      Cinema 4D SDK
      • r23 python • • pim
      5
      0
      Votes
      5
      Posts
      697
      Views

      ferdinandF

      Hello @pim,

      without any further feedback or questions, we will consider this topic as solved by Wednesday and flag it accordingly.

      Thank you for your understanding,
      Ferdinand