Copy Texturetags to same named Objects

On 08/09/2016 at 00:13, xxxxxxxx wrote:

Hi Guys,

Maybe you can help me.
Iam not a coder and Iam stuck with my code. I learned a bit of PHP back in the days but its a long time ago. I tried to figure out to do the following:

I want to make a script which checks currently selected objects if they have tags and if they have, if there is a texturetag, and if this condition is true, try to find the same named object from an array which contains the object, which were not selected from the beginning.
So I tried to build a routine which checks all arrayobjects one by one if they have a texturetag or not and then if they have check out the other array if there is an object with the same name and copy the Texture with just the right Material and Selection. I always get errors and I dont know what I did wrong here..
I get the errormessage:

Traceback (most recent call last) :  
  File "'scriptmanager'", line 36, in <module>  
  File "'scriptmanager'", line 21, in main  
TypeError: list indices must be integers, not str  

Heres the code:

import c4d  
from c4d import gui  
#Welcome to the world of Python  
def main() :  
### Alle relevanten Objekte selektieren  
  k = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER)                        ## Alle Selektierten Objekte in ein Array schreiben  
  s = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER)                        ## Alle Selektierten Objekte umkehren und in ein Array schreiben  
  r = len(k)                                                                               ## Anzahl der Objekte im Array  
  z = len(s)     
  b = 0                                                                            ## Anzahl der Objekte im Array                                                                             
  while b < r:                                                                             ## So lange Variable kleiner als die Anzahl der im Array vorhandenen Objekte ist tue...  
      if k[b].GetTags:                                                            ## ... und das gerade aus dem Array gewählte Objekt Texturtags hat  
          for tag in k[b].GetTags() :                                                      ## Ermittle mir die Tags aus dem Objekt  
              if (tag.CheckType(c4d.Ttexture)) :                                        ## Wenn eines der Tags ein Texturtag ist  
                  a = tag.GetMaterial()                                                ## Material des Texturtags  
                  b = tag[c4d.TEXTURETAG_RESTRICTION]                                  ## Texturtagselektionstag  
                  c = k[b].GetName()  
                  j = 0  
                  while j < z:  
                      d = s[j].GetName()  
                      if doc.SearchObject(d) == c:  
                          z[j].MakeTag(c4d.Ttexture)                                              ## Generiere neues Texturtag  
                          y = z[j].GetFirstTag()                                                  ## Erstes Tag  
                          y.SetMaterial(a)                                                     ## Setze Material für neues Texturtag  
                          y()[c4d.TEXTURETAG_RESTRICTION]=b                                    ## Setze Material Selektion  
                      j = j+1                                                       
      b = b+1  
if __name__=='__main__':  
  doc = c4d.documents.GetActiveDocument()  
  obj = doc.GetActiveObject()  

On 08/09/2016 at 08:40, xxxxxxxx wrote:


welcome to the Plugin Café forums 🙂

You are getting the error message, because the parameter TEXTURETAG_RESTRICTION of the texture tag is a string, the name of the Selection tag restricting the texture tag. You can't use that to index the objects array k. The entire code doesn't look like you want to assign something to b at that point (line 20).
Then later on in line 25 you do a SearchObject(), which returns a BaseObject. But you compare against a string. Not sure why. Isn't a comparison of c and d, what you want to do there?
And if the comparison succeeds, you are creating a new tag, while I think you could simply copy the tag from one object to another (CopyTo()).
And line 29 is probably a typo, at least I have no idea, what y()[...] is supposed to do.

A few additional notes:
There's no need to get the active object and document in a script. There are predefined global variables op and doc for that purpose.
In the end of your script you almost certainly want to do a c4d.EventAdd() to make C4D aware of your changes.

And one final request from my side, I hope you don't mind:
Getting into your code was a bit tricky and prone to misunderstanding due to the single character variable naming. For the future, besides noting that we (MAXON's SDK Team) usually don't do customer's code review and debugging, I highly recommend, for the sake of code maintainability and readability, to use some more self-explanatory variable names. Avoiding German comments could definitely raise the acceptance in our mostly international community increasing their "supportiveness" or contribution to your code.

On 08/09/2016 at 09:10, xxxxxxxx wrote:


Yeah, you probably weren't looking for a whole lesson, but choosing variable names that give a clue as to what they're for is not only helpful to other people who might look at your code, but also to you; it can make things a lot easier to debug and remind you what does what when you look back at it in the future.  (Not that you can replace good commenting.)

Here's an example--it might not be *the best*, but other people can chime in if I'm doing something wrong:

import c4d
from c4d import gui
#Welcome to the world of Python
def main() :
### Alle relevanten Objekte selektieren
    sourceObjects = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER|c4d.GETACTIVEOBJECTFLAGS_CHILDREN)    ## Alle Selektierten Objekte in ein Array schreiben
    checkObjects = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER|c4d.GETACTIVEOBJECTFLAGS_CHILDREN)     ## Alle Selektierten Objekte umkehren und in ein Array schreiben
    for sourceObject in sourceObjects:                                               ## So lange Variable kleiner als die Anzahl der im Array vorhandenen Objekte ist tue...
        for checkObject in checkObjects:                                             ## Maybe there's a smarter way, but this double-loop is fine
            if sourceObject.GetName() == checkObject.GetName() :             
                tags = sourceObject.GetTags()
                selectionTag = None
                for tag in tags:                                           ## Ermittle mir die Tags aus dem Objekt                    
                    if (tag.CheckType(c4d.Ttexture)) :                                        ## Wenn eines der Tags ein Texturtag ist                        
                        #Uncomment these (delete the "'s) if you want to copy the selection tag over, as well
                        selection = tag[c4d.TEXTURETAG_RESTRICTION]
                        for selTag in tags:
                            if selTag.CheckType(c4d.Tpolygonselection) and selTag.GetName() == selection:
                                selectionTag = selTag.GetClone()
                        newTag = tag.GetClone()
                        if selectionTag:
                        print tag.GetName() + " with " + tag[c4d.TEXTURETAG_MATERIAL].GetName() + " copied to " + checkObject.GetName()
                #You can add a 'break' here if there's only going to be one object with the same name, but it's not too important
    doc.SetActiveObject(None) #Personal preference
if __name__=='__main__':
    doc = c4d.documents.GetActiveDocument()
    obj = doc.GetActiveObject()

Going 'for object in myList' will iterate over every item in a list without you having to clutter things up with integer iterators.  And after all my time with Python and C4D I still didn't know/forgot about CopyTo() (that Andreas mentioned), so that's probably better, but the GetClone() + InsertTag() is pretty much identical, I suspect.

I did not add comments (the shame!) so feel free to ask about anything I did or if something doesn't make sense 🙂

On 08/09/2016 at 09:19, xxxxxxxx wrote:

That's why I like our community so much. Great input 🙂

And yes, GetClone() and CopyTo() are pretty much doing the same thing (GetClone returning a new, cloned object, while CopyTo copies into an existing object), depending on situation which is better suited. And in this situation I have to admit, GetClone() is actually nicer.