Group Details Private

administrators

RE: Best practice getting all objects in a certain Null

hi,

In that case, i would open the document in a memory file structure, run my cleaning functions, save it on the memory file structure and merge the saved document.

if you really need to merge first, i would retrieve the first object of the document before merging the documents and check if i hit it.

Cheers,
Manuel

posted in General Talk
RE: Draw Icon (maxon id) into treeview list geUserArea()

Hi,

You should use the function DrawCell to draw your icon. That is probably what you are doing but it's not clear.

This thread should help you to understand how to do it.

You can retrieve any icon with the command c4d.gui.GetIcon(lIconID)

You can find the IDs of the icons on that page

Cheers,
Manuel

posted in Cinema 4D SDK
RE: Compare Matrices Matrix with matrix.__eq__

Hi @mogh I'm not able to reproduce our issue, here it's reliable, would it be possible to share with us a scene?

Just in case the __eq__ is the magic method for the == operator, so you could use obj.GetMg() == obj.GetUp().GetMg()

EDIT: After checking internal code, the == operator of Matrix, use the == operator of the Vector which then use the == operator of the C++ double. But due to Floating Point Issue this operation could fail.

So the best way to compare a Matrix is to manually check for each Vector component like so:

import c4d
import math

def compare_vec(v1, v2, eps=1e-5):
    values_to_compare = [(v1.x, v2.x), (v1.y, v2.y), (v1.z, v2.z)]
    for value_v1, value_v2 in values_to_compare:
        if not math.isclose(value_v1, value_v2, rel_tol=eps):
            return False
    
    return True

def compare_matrix(m1, m2, eps=1e-5):
    values_to_compare = [(m1.v1, m2.v1), (m1.v2, m2.v2), (m1.v3, m2.v3), (m1.off, m2.off)]
    for value_m1, value_m2 in values_to_compare:
        if not compare_vec(value_m1,value_m2, eps):
            return False
    
    return True

def main():
    print(compare_matrix(op.GetMg(), op.GetUp().GetMg()))

# Execute main()
if __name__=='__main__':
    main()

Documentation will be improved in this regards.

Cheers,
Maxime.

posted in Cinema 4D SDK
RE: What are the AES specifications for the AES encryption in C4D SDK ?

Hi without more information from your side it's very hard to help you. Would it be possible to share some code?

Cheers,
Maxime.

posted in Cinema 4D SDK
RE: Best practice getting all objects in a certain Null

hi,

there is no function to do it, you must retrieve the next object yourself in the hierarchy. Something like this exemple but you would need to test if the current object is not your null object, otherwise you would go outside the hierarchy.

Cheers,
Manuel

posted in General Talk
RE: How to track user changes to parameter animation

hi,

There is no really way of doing it. The only way is to keep track of what is going on. the number of keys, the position, values etc.
When setDparameter is called you need to compare and update your data.
You could just store the dirty state or a lot more information. Keep in mind that you can have mutiple tracks for the position. This is tricky and long to do but possible.

Cheers,
Manuel

posted in Cinema 4D SDK
RE: What are the AES specifications for the AES encryption in C4D SDK ?

Hi @C5D first of all welcome in the PluginCafe community 🙂

This is the old way of doing and may be removed in the future, instead you should use the maxon::StreamConversions::AesEncoder() as demonstrated in ZipFile OpenEncrypted for read not working

Cheers,
Maxime.

posted in Cinema 4D SDK
RE: How to track user changes to parameter animation

hi,

As kent said you must override SetDParameter. This function should be caled who/whatever have changed the value of the attribut.

You can have information on this post about the difference with SetDParameter and MSG_DESCRIPTION_POSTSETPARAMETER

As the post suggest, you can have more information in our manual about SetDParameter and Messages specially MSG_DESCRIPTION_POSTSETPARAMETER

Cheers,
Manuel

posted in Cinema 4D SDK
RE: Assign materials to Objects using Python Un-subscribe from this thread

hi,

welcome to the forum.

I would change the fact that if no material is found with the right name, we can just continue the loop with the next object.
This will add a new material tag to the alembic object and link the tag to the material. That is exactly what you want to do?

import re
import c4d

def main():
  doc = c4d.documents.GetActiveDocument()
  oplist = doc.GetObjects()
  if not oplist: 
    return
  # Check if there is at leat one material in the document otherwise return 
  mat = doc.GetFirstMaterial()
  if not mat: 
    return

  # we already checked if oplist is not empty we do not need it twice
  for op in oplist:
    opname = op.GetName()
    mat = doc.SearchMaterial(opname)
    # If there is no material with the same name, we can continue the loop to the next object
    if not mat:
      continue
      
    mname = mat.GetName()
    match = re.match(opname, mname)
    if match:
      textag = c4d.TextureTag()
      textag.SetMaterial(mat)
      textag[c4d.TEXTURETAG_PROJECTION]=c4d.TEXTURETAG_PROJECTION_UVW
      op.InsertTag(textag)
  c4d.EventAdd()
  
if __name__== '__main__':
  main()

Cheers,
Manuel

posted in Cinema 4D SDK
RE: Python Generator and texte

Hello @bureaudesprojets,

welcome to the Plugin Café and thank you for reaching out to us. That looks like a fun project you have there.

However, there are a few problems with your code.

You redefine your null on each step of the loop, causing only the last iteration to be returned. It is:

if ((x // 26)-1 == -1):
   null = c4d.BaseObject(c4d.Onull)
   ...
   texte.InsertUnder(null)
else:
   null = c4d.BaseObject(c4d.Onull)
   ...
   texte.InsertUnder(null)

But it should be:

null = c4d.BaseObject(c4d.Onull)
for x in range( number):
    if ((x // 26)-1 == -1):
        ...
        texte.InsertUnder(null)
    else:
       ...
        texte.InsertUnder(null)

This was what caused your major problem, but there were also other problems with how you set the distance between the elements with texte[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Z] = x* distance, which was outside of the loop, and I also did not understand the whole "aeronautical numerations" thing in your code.

Find below an example of how I would do it.

Cheers,
Ferdinand

The result:
abcd.gif

The file:
abcd.c4d

The code:

"""Simple example for building caches for a Python Generator object.
"""

import c4d
import itertools

# The upper case letters from their ASCII range.
ALPHABET = tuple(chr (i) for i in range(65, 91))


def GetNumerationList(a: int, b: int) -> list[str]:
    """Returns a list of numerations following your scheme from index #a
    to #b.
    """
    # I have no clue what aeronautical numerations are, but I guess
    # you just want A-Z, AA-AZ, BA-BZ, ..., ZA-ZZ, AAA - AAZ, and so on.
    # I do not really see how your code was supposed to do that. I did
    # provide below a simple version using itertools.

    assert(a < b)

    # Build the full array, we could also be more elegant here, and only
    # build what we need, but that would be up to you. I create here quite
    # a lot of entries to avoid index errors. range(1, 4) means we create
    # everything from A to ZZZ, i.e., 26 + 26² + 26³ ~ 18,000 items. Python's
    # iteration is slow, and you should optimize this.
    result = []
    for i in range(1, 4):
        result += ("".join(item)
                   for item in itertools.product(ALPHABET, repeat=i))

    # And return the slice we have been asked for.
    return result[a:b]


def main():
    """Executed by Cinema 4D to build the cache of the Python Generator.
    """
    # Instantiate a null object to parent the "numerations" to.
    null = c4d.BaseObject(c4d.Onull)
    if not isinstance(null, c4d.BaseObject):
        raise MemoryError()

    # Get the user data.
    a = op[c4d.ID_USERDATA, 1] # The starting index.
    b = op[c4d.ID_USERDATA, 2] # The end index.
    distance = op[c4d.ID_USERDATA, 3] # The distance between elements.

    # Iterate over all numerations between the index #a and #b.
    for i, item in enumerate(GetNumerationList(a, b)):
        # Instantiate a text object.
        node = c4d.BaseObject(1019268)
        if not isinstance(node, c4d.BaseObject):
            raise MemoryError("Could not allocate object.")

        # Set the text to the yielded numeration item.
        node[c4d.PRIM_TEXT_TEXT] = item
        # Set the distance on the x-axis in the local space of the parent, 
        # the null object.
        node.SetMl(c4d.Matrix(off=c4d.Vector(i * distance, 0, 0)))
        # Parent the text object to the null object.
        node.InsertUnder(null)

    # Return the cache.
    return null
posted in Cinema 4D SDK