Hey @JoelJohera,
it is kind of hard to follow your question and solution, as the former lacks a scene for context and for the latter I am not quite sure what you fixed. But when it works for you I am happy 
Cheers,
Ferdinand
Hey @JoelJohera,
it is kind of hard to follow your question and solution, as the former lacks a scene for context and for the latter I am not quite sure what you fixed. But when it works for you I am happy 
Cheers,
Ferdinand
Hey @BretBays,
Thank you for your clarification. I think I understand a bit better what you want, but there are still some question marks for me.
The edge loop and ring loop tool work via point indices (and a bunch of other settings). I.e., you set MDATA_LOOP_FIRST_VERTEX and MDATA_LOOP_SECOND_VERTEX and that determines the edge you want to loop (the screenshot above is for toolloopselection.h, the file which defines the loop tool IDs). As I said above, some of the modelling command options can be bit finnicky, but I would help you crossing that bridge when we are there. But we would have to have a foundation we can work on to get started.
But from what I understand, you do not primarily want to select loops, but rather sort existing selections into loops, or more generalized: edge strips you consider to be semantically/topologically connected. For something like shown in your screenshot, this is trivial, but a general solution is not. That you have an existing selection is almost irrelevant, it is only slightly easier to solve than the general problem of sorting all edges of a mesh into strips.
I wrote something like this myself a long time ago (while still at university at not a member of Maxon) and struggled quite a bit then to get it right, because you have then to deal with intersecting strips, self intersections of strips, etc. The problem of yours lies generally in the field of topological sorting, which is pretty wide, the concrete term used for the particular problem is often 'edge extraction in mesh processing'. The popular Python mesh processing library PyVista implements for example edge extraction.
If your concrete problem is solvable, depends entirely on how well you define it. For just an given input set of edges, there exist often many solutions. You have to define things like a maximum angle of change between edges in a strip, how to deal with intersections of strips, if you want continuity of non-manifold edges, etc. And even then, you will often end up with multiple solutions. E.g., in the example below, there are three possible ways to sort these edges into two strips (and even more when you do set this conditions to minimize the number of strips). Which can be deemed undesirable.

I do not understand all details of your tool, but when edge selections are part of it, you could also 'simply' integrate them. Your tool looks currently more like a dialog/command and you could also do it there, but an actual ToolData would be better.
The general drill would be to add a button/mode with which the user can select edges. Once running, you would use c4d.utils.ViewportSelect to get the points/edges the user is clicking or hovering. Once the user wants to commit to a selection, you get the two relevant hoovered points (i.e., edge) and run ID_MODELING_LOOP_TOOL with it. Because you would inspect the user creating the loops one by one yourself, you would naturally know what is a strip in the final selection.
Here are also some hoops to jump through and there might also be obstacles you cannot overcome which I do not see at first glance either (as actual ToolData tools are not very often implemented in Python and therefore a bit niche), but generally this should be possible and this might be less costly than writing a full blown edge extraction solver.
If you want to sort edge selections without intersections (or touching), this is relatively easy to implement, you only have to get the selected edges, convert them into point pairs, and then sort them into strips by finding point pairs where one point matches the end of another pair. The problem of this route is that it is pretty much guaranteed not to suffice in real world scenarios.
Cheers,
Ferdinand
Hey @BretBays,
Thank you for reaching out to us. Yes, that is possible but we cannot write the script for you. We can only help you when you make the first steps yourself. You will find all the necessary building blocks in the modeling example scripts.
MCOMMAND_CURRENTSTATETOOBJECT.SendModellingCommand with ID_MODELING_LOOP_TOOL. Sometimes modelling commands can be a bit bumpy ride, when you want to do more niche things. But at the first glance everything you will need seems to be there:
Cheers,
Ferdinand
Hey @WickedP,
As I hinted at above, markers are eternally persistent. I.e., you can unload, load, and modify a scene S or the non-cache* node N in it, the node N will always have the same marker.
The flag you found has a very special purpose and also very misleading documentation (I just fixed that). Each node in a scene must have a unique marker, as otherwise not only BaseLink but also things like undo and more won't work properly when not each node has exactly one marker and each marker exactly one node (i.e., a bijective or 'one-to-one' relation).
But there can be bad actors such as bugs in our codebase or third party plugins which violate that rule. To combat that, Cinema 4D checks the uniqueness of markers of nodes when a scene is being loaded. When it finds duplicate markers, it will open a question dialog, asking the user if he/she wants to repair that scene. When the user says 'yes', only the nodes which had duplicate markers will get a new marker each (so that they are in a bijective marker relation again).
This flag you found will suppress this whole behavior, i.e., it will let you load corrupted scenes as is. I would not recommend using it. I am currently not 100% sure what happens when your LoadDocument call is not DIALOGSALLOWED, it looks a bit like that this check then always never runs (which sounds a bit dangerous).
Cheers,
Ferdinand
edit: okay now I see it, the question dialog part has been commented out, so this runs always without asking the user (and with that also without DIALOGSALLOWED), unless you pass the flag NONEWMARKERS.
[*] Object and other nodes in caches, i.e., the partial scene graph returned by BaseObject::GetCache and generated by ObjectData::GetVirtualObjects, are allocated each time the cache is being built and therefore also have a new marker each time. But you cannot (or better should not) try to build base links, undos, xrefs, etc. for object and other nodes in caches. TLDR: Markers do not work for caches.
Hey @ECHekman,
I currently use INCLUDE Massign in my .res file. However i would like to do this dynamically so that I can change the order at which it is placed in the Material Editor and Attribute Editor. Is there a way to do this?
There is no INCLUDE which you could call programmatically in GetDDescription, but there is Description::LoadDescription. When Cinema 4D is asking you to update a certain part of your description, you could try to call it on your description instance but not with its id, but Massign. This is however very likely to fail or cause crashes, because your description is already being processed, I never tried this myself though.
Another approach could be to allocate a dummy description, then load your resource (e.g., Massign) into that dummy description, to then copy parameters bit by bit into your active/actual description passed into GetDDescription.
But the whole approach of a 'dynamic include' is a bit backwards without context why it has to be this way. Because when you dynamically include something, this also means you have to remove existing data where it shall not be included anymore. Which is possible but unnecessary extra work. Also copying a whole partial description is not a great idea performance wise, GetDDescription is being called a lot.
The better approach would be to just include your partial description in your res file in the a place where it might appear and then dynamically change the parent of that container. As this workflow would be the common dynamic description workflow.
Additionally Also is there a way to hide settings from the Obaselist group or hide settings in the Material Editor but keep them in the Attribute editor?
No, both managers are more or less just a DescriptionCustomGui, they will always show the same data, unless you have access to the implementation (which you do not). When you would implement your own material dialog, with your own DescriptionCustomGui in it, you could mangle what is shown in this particular description view to your liking, there are multiple methods to highlight, filter, and modify a description on that class. To operate this dialog you would then set this description GUI to the material, shader or whatever BaseList2D you want to display, and then either filter or outright modify the description which is being displayed.
Cheers,
Ferdinand
Hey @mogh,
I forgot this thread a bit, sorry. That sounds all very mysterious. When I summarize your issue, I would describe it as follows. I assume that is the gist of it?
I have a workstation and experience there micro- and macro-stutters in the viewport performance. This happens primarily in low performing scenes with a heavy payload. The odd thing is though, that these performance dips only happen on one machine. On other comparable machines I have an an order of magnitude better performance.
This is very hard to debug, but I would say there are two main cases of what could be going wrong.
What I would do:
Preferences/Viewport Hardware and start dialing knobs to see if you can make a difference. Cinema 4D has unfortunately not a software viewport renderer anymore with which you could do a baseline test.There could also be a bug in Cinema 4D but with numbers as shown below that strikes me as a very unlikely cause. This sounds more like damaged hardware or a really nasty driver issue.
- laptop with ~60 FPS (Quadro 2000)
- on my workstation with ~8 FPS (RTX 3090)
Cheers,
Ferdinand
Hey @Simon-Lucas,
Welcome to the Maxon developers forum and its community, it is great to have you with us!
Before creating your next postings, we would recommend making yourself accustomed with our forum and support procedures. You did not do anything wrong, we point all new users to these rules.
It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: How to Ask Questions.
Do you really mean you are on R25? Or do you mean you are on 2025? Anyway, please share an example scene and the code you have so far. Otherwise we won't be able to help you.
Cheers,
Ferdinand
FYI, I have not overlooked this question here. Will post an answer soon(ish).
Hey @moghurt,
this is on our radar, but I cannot give an ETA when this will be auotmated.
Cheers,
Ferdinand
Hey @ymoon,
Thank you for your question. First of all, your code is more complicated than it has to be. You can just call BaseObject.GetTag to get the first tag of a specific type on an object. Also, your code already does what you are asking for, it selects the tag and therefore causes Cinema 4D to draw the vertex map in the viewport (equivalent to single clicking the tag).
To have the Paint Tool enabled (i.e., what happens when you double click a vertex map), you could either activate the tool yourself, or just send MSG_EDIT to the tag, the message which is sent to scene elements when they are double clicked.
Cheers,
Ferdinand
import c4d
doc: c4d.documents.BaseDocument # The currently active document.
op: c4d.BaseObject | None # The primary selected object in `doc`. Can be `None`.
def main() -> None:
"""Called by Cinema 4D when the script is being executed.
"""
if not op:
return c4d.gui.MessageDialog("Please select an object.")
tag: c4d.BaseTag | None = op.GetTag(c4d.Tvertexmap)
if not tag:
return c4d.gui.MessageDialog("The selected object has no Vertex Map tag.")
doc.SetActiveTag(tag, c4d.SELECTION_NEW)
tag.Message(c4d.MSG_EDIT)
c4d.EventAdd()
if __name__ == '__main__':
main()