Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python 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. Cairyn
    3. Topics
    • Profile
    • Following 0
    • Followers 6
    • Topics 40
    • Posts 387
    • Best 110
    • Controversial 0
    • Groups 0

    Topics created by Cairyn

    • CairynC

      Custom GUI Linkbox checking for Accepted types?

      Cinema 4D SDK
      • r23 python • • Cairyn
      3
      0
      Votes
      3
      Posts
      710
      Views

      CairynC

      @ferdinand Thanks for the reply! Ah, of course, I should have considered that Command is actually the last message I get for that operation. This Message stuff totally got me on the wrong track.

      Naturally, resetting the link and thereby cancelling and reverting the user's drag or pick operation is not as nice as showing a "stop sign" mouse pointer during the operation. Since the ACCEPT clause in a Resource allows setting accepted types, I wonder why there is no API functionality allowing the same. It's not even in the C++ implementation. I suppose people should use external resources anyway, but seeing stuff in the API makes functionality clearer to me at least.

      Regarding PyCapsule, no, I didn't happen across that previously, I just took code from some other thread on this forum to get into the message. I was lazy and looked for PyCapsule in the Cinema 4D API doc, and assumed it undocumented when it wasn't found. Totally my fault, I should have checked the web too. Never program in an unfamiliar scope past midnight! 😹

      Nice code btw.

    • CairynC

      Using AddCustomGui for primitive controls

      Cinema 4D SDK
      • python r23 • • Cairyn
      4
      0
      Votes
      4
      Posts
      939
      Views

      J

      Hello @Cairyn ,

      without further questions or postings, we will consider this topic as solved by Friday 11th of august 2023 and flag it accordingly.

      Thank you for your understanding,
      Maxon SDK Group

    • CairynC

      What is my Clipboardowner for a script?

      Cinema 4D SDK
      • c++ python • • Cairyn
      4
      0
      Votes
      4
      Posts
      685
      Views

      ferdinandF

      Hey @cairyn,

      yeah, you are right. @m_adam already pointed this out too. I screwed up and overwrote my clipboard when I tried this out. I have edited my initial posting, to not confuse future readers.

      GetC4DClipboardOwner works fine in regards to the Picture Viewer and Bodypaint, but the argument ownerid of CopyBitmapToClipboard is effectively meaningless in the public API, as it lacks the window handle context to actually cause the ownerid to be stored. The owner id will always be set to 0.

      And to underline the answer to your major question: It seems very unlikely that you could crash Cinema 4D with writing a made-up owner id into the clipboard (in the case the function would work properly and actually store the id). It is hard to give here absolute answers, as there is a lot of code in our code base. In the context of the clipboard alone, crashing can be excluded, but there could be other parts of Cinema 4D which make assumptions based on the owner id. Which is why I would recommend not using the predefined ones (which is rather theoretical due to said limitations of CopyBitmapToClipboard).

      Cheers,
      Ferdinand

    • CairynC

      MoData's GetFalloffs() returns only 0 while rendering

      Cinema 4D SDK
      • python r23 • • Cairyn
      7
      0
      Votes
      7
      Posts
      1.1k
      Views

      CairynC

      Aaaand of course I forgot a crucial point: After modifying the clone positions in marr, you need to write them back to the MoData, but the last parameter apply_strength must be False:

      moData.SetArray(c4d.MODATA_MATRIX, marr, False)

      This is at first glance unintuitive since we want the strength to be present but when looking closely, you can fathom that the function will internally multiply with the falloff strength that it calculated itself, and that probably comes from GetFalloffs() again, so it's 0 and nothing is won. We do not want SetArray to do that at all, because we have already applied the falloffs that we calculated ourselves, and SetArray should keep its buggy hands off it!

    • CairynC

      How do I put objects into the timeline?

      Cinema 4D SDK
      • r23 python • • Cairyn
      5
      0
      Votes
      5
      Posts
      865
      Views

      ferdinandF

      Hello @Cairyn,

      thank you for reaching out to us.

      Clarification: I am not looking for the iteration of objects, for the selection, or for the folding. Just for the method that will show the object/the track in timeline xxx.

      I wouldn't mind if someone could confirm that there is no access at all to the Timeline elements, or present an alternative...)

      You can add BaseList2D to a Timeline Manger by simply adding a CTrack to them. But you are probably after the special case where an object is being placed by drag and drop into a Timeline. This is a special case since the object has then no track. When you delete the last track of an object in a Timeline, then the object will be removed. This makes the drag and drop case a special case. Internally, the objects of a Timeline Manager are tracked in a list-like structure which is populated by traversing a document and events like object creation or drag and drop. It will automatically ingest all BaseList2D that have a track (and remove such that do not have tracks anymore). Nodes without a track that have been dragged and dropped into a Timeline are added "manually" to that list without being deleted. This works as far as I understand with a GeMarker being added to them. So technically, one might be able to replicate this in C++ by also adding that marker, but its content is not public and might carry other side effects.

      What I found out while playing around with tracks, is that one can add "fake" tracks by either completely making up a track id, which are then called just "track", or incomplete ids, e.g., for the position of an object. This could serve as a clean slate if desired but could also have side effects.

      ac3dd38c-8e5d-4f48-a3cd-941ae2c987cc-image.png

      descId = c4d.DescID(c4d.DescLevel(c4d.ID_BASEOBJECT_REL_POSITION, c4d.DTYPE_VECTOR, 0)) track = c4d.CTrack(op, descId) op.InsertTrackSorted(track) c4d.EventAdd()

      Preventing the object being removed from the Timeline when deleting its last track is not possible in Python. At least I do not see a way to do it at the moment.

      Cheers,
      Ferdinand

    • CairynC

      Overriding arrow keys in the Object Manager?

      Cinema 4D SDK
      • r23 python • • Cairyn
      9
      0
      Votes
      9
      Posts
      1.4k
      Views

      ManuelM

      @cairyn said in Overriding arrow keys in the Object Manager?:

      I guess they didn't make the cut at all...)

      Good guess, there's no particular reason for not being there.

    • CairynC

      What's really happening inside a CKey?

      Cinema 4D SDK
      • c++ python r23 • • Cairyn
      10
      0
      Votes
      10
      Posts
      1.5k
      Views

      CairynC

      DTYPE_LONG can be used with SetGeData if the track category is CTRACK_CATEGORY_DATA, see the third post in this thread. This is the only ambiguous datatype at the moment, and as other datatypes wouldn't make sense with SetValue I think it will remain the only one. But I do claim that the category of the track determines whether you need to use SetValue or SetGeData. (That is almost the same in effect... but in case of DTYPE_LONG not quite.)

    • CairynC

      Checking Object Manager Filtering

      Cinema 4D SDK
      • r23 python • • Cairyn
      3
      0
      Votes
      3
      Posts
      474
      Views

      CairynC

      @m_magalhaes Thanks for the confirmation.

      I have meanwhile found that while the API doesn't cover the OM window states, you can still call CallCommand and IsCommandChecked on the functions.

      c4d.CallCommand(100004762) # Show Search Bar c4d.CallCommand(100004719) # Show Path Bar c4d.CallCommand(100004746) # Show Filter

      They only address the last used OM though; it doesn't seem to be possible to target a specific OM (like it is possible with the Open/Close flags which are stored as NBITs). And of course it doesn't tell me anything about the current visibility of an object in the OM.

      If the developers will think about commands to cover the filter/search/root conditions, they may want to go one step back and think about a more general concept to handle the multi-copy windows (Object Manager, Attribute Manager, Timeline) in some way that allows me to ask what was the last window, the active window, a window by index.

    • CairynC

      VariableChanged Struct is missing its maps?

      Cinema 4D SDK
      • r23 c++ windows • • Cairyn
      8
      0
      Votes
      8
      Posts
      1.1k
      Views

      CairynC

      @ferdinand said in VariableChanged Struct is missing its maps?:

      TEST TEST forbidden to post?

      No, it's not

      Sorry, that's the message from the system that I got in the other thread, repeatedly. So I tried it here, and it posted without difficulty. Then I tried in the other thread again, and it worked. Then I deleted all these postings. But as the original message that I tried to post was lost to the error, I didn't bother to write it again.

      Quite strange error, haven't seen it before, and it didn't come with any explanation WHY it was forbidden to post.

    • CairynC

      RenderDocument flags and return values?

      Bugs
      • python r23 • • Cairyn
      11
      0
      Votes
      11
      Posts
      2.2k
      Views

      César VoncC

      Just for the info, calling the command to open the PictureViewer and RenderDocument with both c4d.RENDERFLAGS_CREATE_PICTUREVIEWER and c4d.RENDERFLAGS_OPEN_PICTUREVIEWER works just fine for me :

      c4d.CallCommand(430000700) # Picture Viewer c4d.documents.RenderDocument(doc, rdData, bmp, c4d.RENDERFLAGS_EXTERNAL | c4d.RENDERFLAGS_CREATE_PICTUREVIEWER | c4d.RENDERFLAGS_OPEN_PICTUREVIEWER)
    • CairynC

      Is MSG_TRANSLATE_POINTS still in use?

      Cinema 4D SDK
      • c++ r23 windows • • Cairyn
      5
      0
      Votes
      5
      Posts
      687
      Views

      CairynC

      thank you for looking! Looks as if that message is indeed dead. Without a translation map, it would be fairly useless...

      The original use I had for it was in a Morph plugin (goes back to R8) so the various morph shapes could keep track of changes done to the original mesh. It's not properly working there any more; guess I know now why 😉

      My current use is a Symmetry plugin I just finished. Right now, it only works by mapping right points and left points, and duplicating positional changes. I am now looking into possibilities to track added or removed points (and maybe polygons) on one side to duplicate that too. The TRANSLATE messages used to do that, including special information like "point A was merged with point B", but naturally all tools need to support that, and apparently the new kernel has moved on to some other method.

      I guess I'll investigate whether MSG_POINTS_CHANGED is now carrying the required information...

    • CairynC

      No scrolling, no paging...?

      General Talk
      • • • Cairyn
      8
      0
      Votes
      8
      Posts
      1.4k
      Views

      kbarK

      Pagination settings! So good. Welcome back my little numbered friends.

    • CairynC

      Python and the GUI Separator

      Cinema 4D SDK
      • python c++ r21 r23 • • Cairyn
      8
      0
      Votes
      8
      Posts
      1.4k
      Views

      CairynC

      Good to hear, thanks!

    • CairynC

      Snap settings issues in R21/R23?

      Cinema 4D SDK
      • r21 r23 python • • Cairyn
      12
      0
      Votes
      12
      Posts
      2.0k
      Views

      CairynC

      @zipit Thanks, I thought so... but you never know whether some functionality has a hidden internal purpose. Deprecating it will probably be the best solution.

    • CairynC

      Does QUANTIZE_GRID actually do anything?

      Cinema 4D SDK
      • r23 python • • Cairyn
      3
      0
      Votes
      3
      Posts
      499
      Views

      CairynC

      Thanks for the confirmation.

      (Follow-up questions moved to a separate post)

    • CairynC

      The asymmetric matrix inversion issue

      General Talk
      • python • • Cairyn
      6
      1
      Votes
      6
      Posts
      1.1k
      Views

      ferdinandF

      Hi,

      @Cairyn said in The asymmetric matrix inversion issue:

      I guess it depends on the point you want to make...

      I would mostly agree, but my point point was more the other way around. Not that shearing is a thing you commonly want to do, but the fact the you should be aware that c4d.Matrix will not enforce an orthogonal basis. Because if you thought it does, you could for example think that

      my_frame = c4d.Matrix(v3=my_normal)

      would be a sufficient way to construct an orthogonal frame where my_normal is k and then carry out some transforms with it and wonder what the heck is going wrong.

      @Cairyn said in The asymmetric matrix inversion issue:

      This has, in fact, been a point I thought long and hard about...

      What I meant with that passage was the story which has been attributed to many famous programmers who left a complicated piece of code only commented with "and here comes the tricky part". Usually told as a testament to both their technical genius and their communicative shortcomings. The often (at least silently) admired notion is that "everything is self explanatory for a smart person". Which of course is neither true nor very "cool". I feel you are drifting a bit into that direction.

      About the linear algebra stuff. In my opinion there is no wrong or right there, you can do a good job with a very coarse and with a very fine model. Although I think often the geometrical meaning of linear algebra has been neglected in teachings about it. Especially Cinema's "matrices" (which in my book do not really qualify as matrices) can be very well explained as linear maps which will automatically will make all four principal transforms intuitively clear. Everything that is left then is to explain that matrices are just another way to write a linear map, i.e. a linear combination of vectors representing a coordinate system.

      Cheers,
      zipit

    • CairynC

      Matrix and Vector access

      Cinema 4D SDK
      • r23 python • • Cairyn
      7
      0
      Votes
      7
      Posts
      1.3k
      Views

      ferdinandF

      Hey @datamilch,

      Thank you for reaching out to us. In general we prefer if users open new threads for their questions. You are of course welcome to link to an existing topic and say that your question relates to that. The reason for that is that even when the question of another user is right on-topic as it is here the case with your question (which in the most other cases will not be true), it still tends to derail a thread. I have not forked your question since you are on-topic.

      About your Question

      I think this thread can be a bit opaque for beginners as @Cairyn and @m_adam have approached this topic on a very technical level.

      The important thing to understand, is that both BaseObject.GetMg() and the fields of a c4d.Matrix, i.e., off, v1, v2, and v3 return a copy of the requested object, not an instance. In plain terms this means that the matrix/vector one retrieves is not the one used by the object/matrix but a copy of it.

      So, we can totally do this:

      >>> mg Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (0, 0, 0)) >>> mg.off.x = 5

      but it does not do what we think it would do, we changed the x-value of the returned copy, not the off vector used by the mg instance.

      >>> mg.off.x 0.0 >>> mg Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (0, 0, 0))

      But we can certainly set the x-component of the global offset of an object in one line.

      import c4d cube: c4d.BaseObject = c4d.BaseObject(c4d.Ocube) # ONE: Using parameter access # We set the the x component of the global position and the global rotation using parameter access. # There are also parameters for the relative, aka local, transform values, as well as special things # like a frozen transform. There are also functions on BaseObject which do the same thing but at # least I never use them. # See: https://developers.maxon.net/docs/py/2024_3_0/classic_resource/base_list/obase.html cube[c4d.ID_BASEOBJECT_GLOBAL_POSITION,c4d.VECTOR_X] = 9.9 cube[c4d.ID_BASEOBJECT_GLOBAL_ROTATION] = c4d.Vector(0, 0, c4d.utils.DegToRad(45)) # TWO: Use matrix and vector constructors # In three steps ... mg: c4d.Matrix = cube.GetMg() mg.off = c4d.Vector(9.9, mg.off.y, mg.off.z) cube.SetMg(mg) # ... or in two steps, although this is a bit stupid. mg: c4d.Matrix = cube.GetMg() cube.SetMg(c4d.Matrix(c4d.Vector(9.9, mg.off.y, mg.off.z), mg.v1, mg.v2, mg.v3)) # THREE: Using transforms # This is not exactly the same as the two other cases, but it is the most common operation. Here we # do not set the global x-position of #cube to 9.9, but we move it 9.9 units in the x-direction. # In code we often operate on objects with the identity transform/matrix, i.e., which "sit at origin # with the standard size and orientation". In that case transforms act the same as if we would just # set these values. The other case is that you have an object at (1, 2, 3) and then move it (3, 2, 1) # units, transforms also work for this. For the case where the object is at (1, 2, 3) and you want # to _set_ it to (9.9, 2, 3) a transform won't work unless you do the math. # Freshly instantiated objects have the identity transform, we can just pile transforms on top of # that to "set" the values. sphere: c4d.BaseObject = c4d.BaseObject(c4d.Osphere) # Just move it 9.9 units in the x-direction. sphere.SetMg(sphere.GetMg() * c4d.utils.MatrixMove(c4d.Vector(9.9, 0, 0))) # Or first move it 9.9 units in the x-direction and then rotate it 45 degrees around the z-axis. This # would also "pile" onto the previous transform we have already applied. Note that matrix # multiplication is also not commutative, i.e., first moving something and then rotating it (might) # yield something different than first rotating and then moving. sphere.SetMg(sphere.GetMg() * c4d.utils.MatrixMove(c4d.Vector(9.9, 0, 0)) * c4d.utils.MatrixRotZ(c4d.utils.DegToRad(45)))

      Cheers,
      Ferdinand

    • CairynC

      Adding camera calibration lines by script?

      Cinema 4D SDK
      • • • Cairyn
      3
      0
      Votes
      3
      Posts
      552
      Views

      CairynC

      ok, thanks for the confirmation!

    • CairynC

      What is Vector.GetLengthSquared() really meant for?

      Cinema 4D SDK
      • r21 python • • Cairyn
      5
      0
      Votes
      5
      Posts
      825
      Views

      CairynC

      @zipit said in What is Vector.GetLengthSquared() really meant for?:

      My major point was that there are certain programming assumptions (multiplication is better than division, never take the square root if avoidable, cubic complexity is uncomputable, etc.) that should be taken with a grain of salt due to the fact that they rely on a certain "state" of hardware. I.e. all these three do not really hold true anymore to the extent they once did. (...)

      That goes without saying... ultimately, any effort towards optimization needs to be checked for effectivity.

      Nevertheless, I was curious and abused a plugin of mine to execute some timer checks in C++, just for comparison (code excerpt only):

      using namespace std::chrono; Vector v(100.0, 100.0, 100.0); float f; milliseconds ms1, ms2, diff; ms1 = duration_cast<milliseconds>( system_clock::now().time_since_epoch() ); for (int i = 0; i < 100000000; i++) { f = 0; // v.GetLength(); } ms2 = duration_cast<milliseconds>( system_clock::now().time_since_epoch() ); diff = ms2 - ms1; GePrint(maxon::String("Time counter Empty:") + maxon::String::IntToString(diff.count())); ms1 = duration_cast<milliseconds>( system_clock::now().time_since_epoch() ); for (int i = 0; i < 100000000; i++) { f = v.GetLength(); } ms2 = duration_cast<milliseconds>( system_clock::now().time_since_epoch() ); diff = ms2 - ms1; GePrint(maxon::String("Time counter GetLength:") + maxon::String::IntToString(diff.count())); ms1 = duration_cast<milliseconds>( system_clock::now().time_since_epoch() ); for (int i = 0; i < 100000000; i++) { f = v.GetSquaredLength(); } ms2 = duration_cast<milliseconds>( system_clock::now().time_since_epoch() ); diff = ms2 - ms1; GePrint(maxon::String("Time counter GetSquaredLength:") + maxon::String::IntToString(diff.count()));

      Switching off all optimizations, I get (for multiple button presses):

      Time counter Empty:185 Time counter GetLength:921 Time counter GetSquaredLength:228 Time counter Empty:184 Time counter GetLength:922 Time counter GetSquaredLength:228 Time counter Empty:183 Time counter GetLength:921 Time counter GetSquaredLength:228 Time counter Empty:183 Time counter GetLength:922 Time counter GetSquaredLength:228 Time counter Empty:185 Time counter GetLength:921 Time counter GetSquaredLength:228 Time counter Empty:183 Time counter GetLength:921 Time counter GetSquaredLength:227

      That is far more like what I expected (double so if you consider that the loop with a constant assignment already takes 185ms).

      Considering that I had to up the loop count to a hundred million to get measurable results, it is practically guaranteed that any difference between GetLength and GetLengthSquared in the Python sample is drowned in the Python interpreter's overhead, and any result from my initial tests must be attributed to sheer randomness.

    • CairynC

      What's the state of Ngons in Python?

      Cinema 4D SDK
      • python classic api r21 • • Cairyn
      9
      0
      Votes
      9
      Posts
      1.3k
      Views

      CairynC

      @m_magalhaes said in What's the state of Ngons in Python?:

      About the bugs on the forum, we have introduce few month ago new tags "Bug report" and "Bug Fixed". We are also adding some tag in our bug database to retrieve faster the post on the forum. I know it's not perfect and sometimes we may forgot to add this tag on the first post of the thread. But it's better than nothing.

      Yeah, I'll try to use that in the future although it probably won't affect existing threads (a lot of valuable knowledge still resides in the "old forum" parts).

      @Cairyn said in What's the state of Ngons in Python?:

      Anyway, I don't think this issue is of huge interest as you said there's a replacement in the new kernel already, which will probably come with a diferent tesselation algorithm, so I present it here as a curiosity.

      Don't get me wrong, all modeling command have been migrated to the new modeling kernel. If you are using SendModelingCommand, it will use the new kernel.
      So what you see now in S22 and R23 (ok you will see in R23) IS the new kernel. There will be no better tesselation.
      I consider this as a bug.

      As a Perpetual user, I'm still on R21 (as tagged) so is this also the new kernel? AFAIK the new kernel has been working behind the API for a while now, being gradually introduced into the functionality, so it's possible that this bug still persists.

      I can't test it on a demo of S22 for you, as the current licensing does not allow me to install one.

      The new modeling kernel isn't exposed yet. But it is used. I understand, it's a bit confusing. We are moving Cinema4D to the new core. But as long as some part of Cinema4D are using the old system (object manager for exemple), the new core need to "translate" that to the classic API. (...)
      I hope it's clear.

      Sure, I have a few decades of programming under the belt. It's just a bit difficult as non-Maxon developer to see the details. Seeing only the API (and therefore the user-side of the translation layer), I can't always tell what the underlying data model really is; what's stored as attribute, what's calculated on the fly, what's internally cached for fast access, what's abstracted and what's plainly stored... I may make wrong assumptions on the internal workings.

      this look like a valid ngon but i will ask 🙂

      It probably is valid - I don't see a reason why it should be forbidden. I just notice that the tesselation algorithm tends to avoid such "inner polygons". That may not be intentional (based on a rule) though, but just a consequence of how the algorithm works.

      Thanks again,
      -- Cairyn --