• Target Tag not fixing to target

    r21 python
    8
    0 Votes
    8 Posts
    2k Views
    A
    Hi @Cairyn, Understood and works like a charm! Many thanks guys
  • Get a Deformed Point Position Over Time

    windows python s24
    7
    0 Votes
    7 Posts
    656 Views
    ferdinandF
    Hello @blastframe, yes, there is a loop in that script which is like my pseudo-code one. If they are doing the same thing is a bit a point of view. The script evaluates each frame to do something each frame, while my pseudo code evaluates all frames to do something after that. So, for clarity again as pseudo code: # Evaluate all frames and do something for each frame, i.e., what Maxime's # script does. for frame in FRAMES: for item in document: item = evaluate(item, frame) DoSomthing(item) # Evaluate all frames and after that do something, i.e., what I am proposing. # From a more abstract point of view, both are doing the same thing. The only # difference here is that we are not interested in the intermediate results, # only in updating an item with is prior state: `item = evaluate(item, frame)` for frame in FRAMES: for item in document: item = evaluate(item, frame) DoSomthing(someItem) If you say, you are fine with not respecting this than this will simplify things. And most things that impact (deform) caches, won't be impacted by that. But there are direct cases which are affected, e.g. cloth simulations, some deformers like for example the collision the deformer and more. And indirect cases like when you have a particle system whose state over three corners will impact some deformation. And yes, this is very taxing to do, because you must evaluate a lot of stuff each frame. And you will have likely to execute all passes (animation, expressions, and caches); in the end it depends on how a specific scene is setup. The performant way to do this is cache the required data yourself. Like for example the collision deformer can do it; i.e., you click a button and then all data is calculated which then later is only played back. I would not say that it is impossible to do this in Python, but you will lack some important types to store such data in Python that are exposed in our C++ API. Python is also in general not well suited for such task, due to its inherent slowness of iteration. But that does not mean that with some smart thinking you could not make it work in Python in a performant way. This all depends on what you are exactly trying to do and is more of a general complexity of an algorithm or project design question (and therefore out of scope of support). The bottom line is that your initial question of Get a Deformed Point Position Over Time might contain more complexity than anticipated by you, because it implies something is the recursive function itself and time. Which is always a pain in the *** to handle. Cheers, Ferdinand
  • Detecting a Change in Position/Rotation Keyframes from Tag

    windows python s24
    5
    0 Votes
    5 Posts
    620 Views
    ?
    @ferdinand Thank you. I'll try to cache myself.
  • SplineCustomGui settings issue

    r21 python windows
    11
    2
    0 Votes
    11 Posts
    2k Views
    ferdinandF
    You need to call NodeData.InitAttr() in NodeData.Init. E.g.: def Init(self, node): """ """ self.InitAttr(node, float, c4d.PY_TUBEOBJECT_RAD) self.InitAttr(node, float, c4d.PY_TUBEOBJECT_IRADX) node[c4d.PY_TUBEOBJECT_RAD] = 200.0 node[c4d.PY_TUBEOBJECT_IRADX] = 50.0 return True But you should check the allocation problem first, it is the most likely culprit. Se the edit in my last posting. Cheers, Ferdinand
  • HUD Text issues

    r23 python
    9
    1
    0 Votes
    9 Posts
    1k Views
    K
    Oh! sorry @fwilleke80 I misread your first message. @ferdinand, I think I got confused from the beginning. I made a copy of my code from an objectData plugin to a scenehook plugin without changing DRAWPASS to SCENEHOOKDRAW Everything is working just fine now(... except the aliasing) but the result is acceptable. [image: 1627633821978-ok.png] Thanks to both of you! Best Regards,
  • Python Cloner/Scatter plugin

    python
    4
    0 Votes
    4 Posts
    1k Views
    C
    Thanks to both of you! This helps alot! You guys are so nice and helpful
  • How to Highlight a Button

    python
    2
    0 Votes
    2 Posts
    531 Views
    ferdinandF
    Hello @Ling, thank you for reaching out to us. Please remember to open a new topic of you own when you have a question and not to hijack other topics. The exception to that rule is when you have a question that aligns exactly with a currently ongoing topic. The reason we enforce this, is so that the form remains a nicely searchable knowledge base. I have forked your question for that very reason; it did not align with the other topic. About your question: It depends on what you mean by it. You cannot modify the background color of a Button element. What you can do, is create a LONG element and define QUICKTABRADIO as its custom GUI; here is how the muscle object in Cinema makes use of this GUI element: LONG ID_CA_MUSCLE_OBJECT_STATE { SCALE_H; ANIM OFF; PARENTCOLLAPSE; CUSTOMGUI QUICKTABRADIO; CYCLE { ID_CA_MUSCLE_OBJECT_STATE_RELAX; ID_CA_MUSCLE_OBJECT_STATE_COMPRESSED; ID_CA_MUSCLE_OBJECT_STATE_EXTENDED; } } This will give you the tabs look as shown in many places in Cinema 4D. You will however need multiple elements to make this useful, as this is effectively an options group. What you could also do, is create a BITMAPBUTTON and then have different images for its normal and pressed stated. Cheers, Ferdinand
  • Modifying Scene On First Open or Before Save?

    s24 python
    5
    0 Votes
    5 Posts
    1k Views
    dskeithbuckD
    @C4DS @kbar @ferdinand - Thank you so much for the in-depth responses. @kbar I'll see if I can get my employer to pony up for a license for Call Python as that seems like the simplest root. Although, this is potentially a light enough lift that I can finally make the transition into C++ development. @ferdinand Helpful to know that I won't be able to interrupt the save process (probably a good thing from the user POV).
  • Calculation Errors and Best Practices

    5
    1
    0 Votes
    5 Posts
    931 Views
    ferdinandF
    Hello @orestiskon, well, are you experiencing "drift"? I am not 100% sure what you mean by drift, but I assume you mean just an error with that. As I lined out above, floating point error at 64 bits is usually not something you have to worry about in the scenario of what you are doing. There will be an error, but if you are only interested in visually representing something, it will be negligible when you meet the conditions I did line out above. I also do not get quite why you have to store the scale of the matrix. When you transform an input matrix with another matrix that has the scale of (1,1,1), then scale of the result will have the same scale as the input matrix, since x * 1 is still x. In general, you try to avoid doing multiple arithmetic operations in a row (see example at the end). Which is also the reason I proposed interpolations. But again, for just moving a cube around, you should be fine. Cheers, Ferdinand """Showcases the impact of doing the same calculation in 'different' ways. """ import math # List of ten 1.1's, 1.1 cannot be represented by 64 bit floats. items = [1.1] * 10 # This will amass the precision error of ten additions of a not representable # value. print (sum(items)) # This won't. print ((1.1 * 10)) # And this won't either. print (9.9 + 1.1) # One of Python's floating point tricks, fsum is addition with an error term. print (math.fsum(items)) 10.999999999999998 11.0 11.0 11.0
  • DRAGANDDROP_FLAG_FORBID

    c++ r21
    2
    1
    0 Votes
    2 Posts
    432 Views
    M
    Hi @AiMiDi, MSG_DRAGANDROP will be received when the host receive a drag, I didn't tried but I guess only dialog can react to this message. In you case you will need to set the NBIT NBIT_NO_DD like so op.ChangeNBit(c4d.NBIT_NO_DD, c4d.NBITCONTROL_SET). Cheers, Maxime.
  • how can I make popup like snap popup

    6
    0 Votes
    6 Posts
    851 Views
    L
    @m_adam I know the PLUGINFLAG_COMMAND_STICKY, but i do not know how can I judge the key down and key up in execute() called back function of the command data. Do you know a way to do this? Thanks!
  • Get and Set Move Tool's XYZ Axis Lock State

    python
    7
    1
    0 Votes
    7 Posts
    1k Views
    eZioPanE
    Thank you @ferdinand for the detailed answer and code. I will do more reading in the sdk document.
  • Selection associated with a texture tag

    4
    0 Votes
    4 Posts
    648 Views
    M
    Hi @Kantronin, I don't have a lot to add Thanks @Cairyn , for more information about the console, please read Python Console. Cheers, Maxime.
  • Polygon corresponding to a selection

    5
    2
    0 Votes
    5 Posts
    950 Views
    M
    Hi @Kantronin I don't think there is that much to add but I want to mention that c4d.CallCommand automatically add an undo to the undo stack, while c4d.utils.SendModelingCommand with it's flags arguments can be defined. But you need to start and end the undo with the c4d.utils.SendModelingCommand, so this way you can have multiple SendModelingCommand within an undo. See basedocument_undo example for undo management. Cheers, Maxime.
  • ZipFile OpenEncrypted for read not working

    c++ r21 sdk
    7
    0 Votes
    7 Posts
    1k Views
    ferdinandF
    Hello @kbar, in case you are interested in it for academic purposes or someone else is, here is a full example for how to use some stuff within the maxon::StreamConversions namespace. I included examples for hashing, encrypting, and compressing inputs. The example also reverses the operation for compression and encryption. This might be helpful, because there is a bug in the Stream Conversions Manual AES encryption example code, which cause the code to fail due to not filling up the plain text message to the correct block size. There are also some minor bits and bobs which might not be obvious. I have reached out to the developers about some problems of mine regarding the example code in the docs (which was provided by them, not us) and how Cinema deals with the term block size in the context of AES encryptions. My variant does run and does what I would expect it to do. I will report back here if there are any relevant updates (which I would not anticipate being the case). Cheers, Ferdinand The output: Password: wubba lubba dub-dub, Secret: d7a2f8231c17aabc885683fb4781a648 Content: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd guber, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Encrypted content: {0,0,3,22,120,-38,-43,-110,49,110,3,49,12,4,-65,-78,15,48,-18,15,-23,-35,-27,5,60,-119,56,48,-106,-60,-117,72,30,-32,-33,-121,118,82,36,-123,-35,-91,112,-53,37,119,23,3,-98,117,114,-121,-20,22,29,85,-101,78,-104,56,-88,-77,-97,80,116,24,59,123,-28,-112,106,-18,20,25,27,-72,-119,-49,19,-116,43,-86,80,-57,-48,17,-3,10,-106,-39,-75,-62,-71,-17,105,34,-29,-112,26,-61,17,-114,70,107,-122,-128,-3,59,-128,-47,105,27,4,106,-14,25,-41,52,-32,73,-2,-53,-17,-48,22,-69,7,45,120,115,28,60,21,-84,118,-69,-90,82,-62,110,-5,-114,-113,48,87,-44,-48,31,-53,-69,-50,-124,-55,107,-12,5,-17,89,26,37,123,18,46,100,21,-40,98,-27,-20,60,52,99,8,78,23,-23,-108,-94,-47,40,30,121,108,-114,-13,67,16,-53,19,-19,15,-92,23,36,115,7,-77,77,30,-1,14,-25,-91,62,-24,11,106,-106,31,-35,0,94,-62,-56,-61,-127,58,-108,-54,89,-93,-64,10,-42} Decrypted content: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd guber, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. The code: // Example for a maxon API conformant implementation to encrypt and compress text data. // // This mostly showcases the maxon::StreamConversions namespace which contains operations for // streams of data, not just text. The example showcases the three important functionalities of // compression, encryption and hashing of StreamConversions. // // This will effectively take an input string and compress and then encrypt it, and after that // reverse the operation. I deliberately left out file operations here, to make this a bit more // streamlined. File operations would have to be done with maxon::BaseStreamInterface types (in- // and output streams) within the maxon API. // // As discussed in: // https://developers.maxon.net/forum/topic/13449 #include "c4d.h" #include "c4d_symbols.h" #include "maxon/cryptography.h" #include "maxon/cryptography_hash.h" #include "maxon/datacompression.h" #include "maxon/iostreams.h" #include "maxon/secure_random.h" #include "maxon/streamconversion.h" /// ----------------------------------------------------------------------------------------------- /// Hashes a password into a 32 characters secret. /// /// Could also be done with maxon::GetPasswordHash() and maxon::HashPasswordWithSalt() in a more /// convenient form. /// /// @param[in] password The password to hash. /// @return The hashed password. /// ----------------------------------------------------------------------------------------------- maxon::Result<maxon::String>GetAES128Secret(const maxon::String password) { iferr_scope; // The input password and a temporary hash result as arrays. const maxon::BaseArray<maxon::Char> secret = password.GetCString() iferr_return; maxon::BaseArray<maxon::UChar> hash; // Use the StreamConverions MD5 hash to hash the password into a 32 characters secret. const maxon::StreamConversionRef md5 = maxon::StreamConversions::HashMD5().Create() iferr_return; md5.ConvertAll(secret, hash) iferr_return; // Get the hash as a hex string. const maxon::String result = maxon::GetHashString(hash) iferr_return; return result; } /// ----------------------------------------------------------------------------------------------- /// Compresses and encrypts an input string. /// /// @param[in] content The input text to compress and encrypt. /// @param[in] secret The encryption secret. /// @return The compressed and encrypted content as a char array. /// ----------------------------------------------------------------------------------------------- maxon::Result<maxon::BaseArray<maxon::Char>>GetEncrypted( const maxon::String content,const maxon::String secret) { iferr_scope; // The in- and output as char arrays. maxon::BaseArray<maxon::Char> plaintextContent = content.GetCString() iferr_return; maxon::BaseArray<maxon::Char> encryptedContent; // The compression settings, the compression rate can lie between 0 and 9, where 9 is the // strongest (and slowest) compression. maxon::DataDictionary settings; settings.Set(maxon::STREAMCONVERSION::ZIP::ENCODER::COMPRESSION, maxon::Int(9)) iferr_return; settings.Set(maxon::STREAMCONVERSION::ZIP::ENCODER::WRITESIZE, true) iferr_return; // Build a CryptoKey for an AES encryption. const maxon::Id encoderID = maxon::StreamConversions::AesEncoder.GetId(); const maxon::Int blockSize = 128; const maxon::Int keySize = 128; const maxon::BaseArray<maxon::Char> key = secret.GetCString() iferr_return; const maxon::CryptoKey cryptoKey (encoderID, blockSize, key.GetFirst(), keySize); maxon::DataDictionary cryptoSettings; cryptoSettings.Set(maxon::CryptographyOptions::CRYPTOKEY, cryptoKey) iferr_return; // We can either compress first and then encrypt the data or do it the other way around. I did // choose to compress first, since trying to decompress data first is relatively common attack // pattern. Encrypting first and then compressing might yield more favorable compression rates. // This will be most impactful when the plain text is relatively small, due to us filling // up the plain text message up to the AES encryption block size further down below. So, if the // compressed message happens to be 17 bytes long, the code below will fill it up to 32 bytes. // If we compress after encrypting, we will also compress that "filling up". But since the // maximum overhead due to this is 15 bytes, it can be ignored IMHO. const maxon::StreamConversionRef zipEncoder = maxon::StreamConversions::ZipEncoder().Create(settings) iferr_return; zipEncoder.ConvertAll(plaintextContent, encryptedContent) iferr_return; // Make sure the compressed data is null terminated. We are going to have to fill up this data to // the fixed block size of an AES encryption. And we are going to use this null as a marker when // we later decrypt the data and then have to separate the message from the "fill-up"-content. encryptedContent.Append(0) iferr_return; // Setup an AES encoder. const maxon::StreamConversionRef aesEncoder = maxon::StreamConversions::AesEncoder().Create(cryptoSettings) iferr_return; // Determine if the data does match the fixed block size (128 bits) of an AES encryption. const maxon::Int initialSize = encryptedContent.GetCount(); const maxon::Int aesBlockSize = aesEncoder.GetBlockSize(); const maxon::Int targetSize = (((8 * initialSize) / blockSize) + 1) * aesBlockSize; const maxon::Int diff = targetSize - initialSize; // Fill the difference of the data to the block size stride with random bits/bytes. if (diff > 0) { encryptedContent.Resize(targetSize) iferr_return; maxon::UChar* randomDataStart = (maxon::UChar*)(encryptedContent.GetFirst()) + initialSize; const maxon::Int randomDataSize = diff; const auto randomDataBlock = maxon::ToBlock<maxon::UChar>(randomDataStart, randomDataSize); const maxon::SecureRandomProvider provider = maxon::SecureRandom::GetDefaultProvider(); maxon::SecureRandom::GetRandomNumber(provider, randomDataBlock); } // Check if the encoder does support in place conversions. if (!aesEncoder.SupportInplaceConversion()) return maxon::UnexpectedError(MAXON_SOURCE_LOCATION); // Encrypt the data in place. aesEncoder.ConvertAllInplace(encryptedContent) iferr_return; return encryptedContent; } /// ----------------------------------------------------------------------------------------------- /// Decrypts and decompresses a message that has been encoded with GetEncrypted(). /// /// @param[in] content The input text to decompress and decrypt. /// @param[in] secret The encryption secret. /// @return The decompressed and decrypted content as a string. /// ----------------------------------------------------------------------------------------------- static maxon::Result<maxon::String>GetDecrypted( const maxon::BaseArray<maxon::Char>& encryptedContent, const maxon::String secret) { iferr_scope; // The compression settings, the compression rate can lie between 0 and 9, where 9 is the // strongest (and slowest) compression. maxon::DataDictionary settings; settings.Set(maxon::STREAMCONVERSION::ZIP::ENCODER::COMPRESSION, maxon::Int(9)) iferr_return; settings.Set(maxon::STREAMCONVERSION::ZIP::ENCODER::WRITESIZE, true) iferr_return; // Build a CryptoKey for an AES encryption. const maxon::Id encoderID = maxon::StreamConversions::AesEncoder.GetId(); const maxon::Int blockSize = 128; const maxon::Int keySize = 128; maxon::BaseArray<maxon::Char> key = secret.GetCString() iferr_return; const maxon::CryptoKey cryptoKey(encoderID, blockSize, key.GetFirst(), keySize); // Setup an AES decoder. maxon::DataDictionary cryptoSettings; cryptoSettings.Set(maxon::CryptographyOptions::CRYPTOKEY, cryptoKey) iferr_return; const maxon::StreamConversionRef aesDecoder = maxon::StreamConversions::AesDecoder().Create(cryptoSettings) iferr_return; // Check if decoder supports in place conversions. if (!aesDecoder.SupportInplaceConversion()) return maxon::UnexpectedError(MAXON_SOURCE_LOCATION); // Decrypt the message in place. aesDecoder.ConvertAllInplace(encryptedContent) iferr_return; // Decompress the data up to the null termination within the decrypted message now written into // encryptedContent. maxon::BaseArray<maxon::Char> decompressed; const maxon::StreamConversionRef zipDecoder = maxon::StreamConversions::ZipDecoder().Create(settings) iferr_return; zipDecoder.ConvertAll(encryptedContent, decompressed) iferr_return; return maxon::String (decompressed); } /// ----------------------------------------------------------------------------------------------- /// Runs the example. /// /// @param doc Not needed, requirement of private interface. /// ----------------------------------------------------------------------------------------------- static maxon::Result<void> RunExample(BaseDocument* doc) { iferr_scope; //The password and some mock data to encrypt. const maxon::String password = "wubba lubba dub-dub"_s; const maxon::Char* content = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, " "sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam " "voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd " "guber, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, " "consetetur elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna " "aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. " "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem " "ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt " "ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo " "duo dolores et ea rebum."; const maxon::String inputContent (content); // Variables for the encrypted & decrypted content and secret. maxon::BaseArray<maxon::Char> encryptedContent; maxon::String decryptedContent, secret; // Hash the password. iferr(secret = GetAES128Secret(password)) ApplicationOutput("Failed to hash password."); // Compress and encrypt the content. iferr (encryptedContent = GetEncrypted(inputContent, secret)) ApplicationOutput("Failed to encrypt data."); // Decrypt and decompress the content. iferr(decryptedContent = GetDecrypted(encryptedContent, secret)) ApplicationOutput("Failed to decrypt data."); ApplicationOutput("Password: @, Secret: @", password, secret); ApplicationOutput("Content: @", inputContent); ApplicationOutput("Encrypted content: @", encryptedContent); ApplicationOutput("Decrypted content: @", decryptedContent); return maxon::OK; }
  • Some basic questions on BaseContainer

    python
    8
    0 Votes
    8 Posts
    2k Views
    ferdinandF
    Hi @orestiskon, thank you for flagging the topic as answered. Cheers, Ferdinand
  • Face associated with a selection

    Moved python
    4
    1
    0 Votes
    4 Posts
    688 Views
    KantroninK
    Thanks for your quick replies I used GetBaseSelect() which allowed me to have the selected faces for each selection list_polygon = obj.GetAllPolygons() dim = len(list_polygon) L = [] tag = obj.GetFirstTag() while tag: if tag.GetType() == c4d.Tpolygonselection: sel = tag.GetBaseSelect() L2 = [] for i in range(0,dim): if sel.IsSelected(i): L2.append(i) L.append([tag.GetName(),L2]) tag = tag.GetNext() for item in L: print item[0] print item[1]
  • Buttons do not work when opening dialog with "DLG_TYPE_ASYNC"

    python s24
    9
    0 Votes
    9 Posts
    2k Views
    M
    Hello! @ferdinand ,@Cairyn Thank you for politely teaching me! I was able to solve the title problem. I will use an external editor. I also understood loading plugins! I was restarting the software many times. I have a new question, but if you study a little more and don't solve it, let me ask you another thread. I'm really thankful to you!
  • Is ObjectIterator() parsing depreciated under R23 and higher?

    5
    0 Votes
    5 Posts
    856 Views
    ferdinandF
    Hello @mocoloco, without any further replies or questions, we will consider this thread as solved by Thursday and flag it accordingly. Thank you for your understanding, Ferdinand
  • Encouraging evaluation when a document is opened

    python
    3
    0 Votes
    3 Posts
    614 Views
    ferdinandF
    Hello @pyr, without any further replies or questions, we will consider this thread as solved by Thursday and flag it accordingly. Thank you for your understanding, Ferdinand