Selecting objects via partial name

  • On 15/07/2013 at 08:14, xxxxxxxx wrote:

    Hey guys,

    I was just wondering if there was a way to select objects in a scene with the same beginning of the name.
    Layer panel
    Layer panel
    Layer window
    Layer window

    so if I ran the plugin it would then select everything with 'Layer' in or 'Street'

    My master plan is to create a script that selects all objects with the same 12 characters at the beginning of their name, groups them into a null, then names the null with those 12 characters.

    When importing fbx files to work on, its bringing in 10000 objects, This will help speed up work greatly.

    Cheers in advance


  • On 15/07/2013 at 09:48, xxxxxxxx wrote:

    1. c4d has that functionality built in (the magnifying glass icon in the om).
    2. yes it is possible, although c4d has not a special method for that exact case. there are the 
    search methods in BaseDocument. but they will always only return the first match. a custom 
    method could look like that( where nodelist is a list of GeListNodes ) :

    def FilterNodeByName( nodelist, filterstring ) :
        result = []
        if isinstance(nodelist, list) :
            for node in nodelist:
                if isinstance(node, c4d.BaseList2D) and filterstring in node.GetName() :
        else: return None
        return result

    edit : fyi you might have to modify the filter string and the name string. i always forget if __contains__ () is case sensitive for strings, but i think it is, so for an insensitive search you would have to force both strings into lower or upper case.

  • On 19/08/2013 at 03:45, xxxxxxxx wrote:

    Hey littledevil,

    cheers for the reply, sorry its been a while, just coming back to this now.
    Here is a script I've found:

    import c4d  
    def main() :  
      mapping = {}  
      context = doc.GetActiveObject() or doc.GetFirstObject()  
      if not context:  
      root = context.GetUp()  
      # Go to the first object in the context.  
      while context.GetPred() :  
          context = context.GetPred()  
      # Fill the mapping.  
      while context:  
          mapping.setdefault(context.GetName(), []).append(context)  
          context = context.GetNext()  
      # Create Null-Objects.  
      items = sorted(mapping.iteritems(), key=lambda x: x[0])  
      prev = None  
      for name, objects in items:  
          null = c4d.BaseObject(c4d.Onull)  
          for obj in objects:  
              doc.AddUndo(c4d.UNDOTYPE_CHANGE, obj)  
          doc.AddUndo(c4d.UNDOTYPE_NEW, null)  
          doc.InsertObject(null, root, prev)  
          prev = null  

    I'm trying to tweak it, maybe by adding a range(13) in there to select the characters?

    In the section of #Fill The Mapping. I was trying to get in a range, so it only gets the first 12 characters of a name, but the .GetName() takes no arguments.

  • On 19/08/2013 at 04:06, xxxxxxxx wrote:

    strings are arrays of chars (or more pythonic lists).

    string = '01234567'
    print len(string)
    \>> 8
    print string[4]
    \>> 4
    print string[1:4]
    \>> 1234
    print string[:-1]
    \>> 0123456

    I did use sort of this quality of strings in my first snippet, when i did call __contains__ on a string
    which is an enumerator object method.

    > if filterstring in node.GetName() :

  • On 19/08/2013 at 05:18, xxxxxxxx wrote:

    I'm trying to go about removing the last few characters from the end of each string in the list

    for x in mapping:  

    Or do you think it would be more to do with the first line of the #Create Null-Objects.?

  • On 19/08/2013 at 07:54, xxxxxxxx wrote:

    a negative index does indicate an inverted index order.

    > mapping[:-13]

    is the short (implicit) form for

    > mapping[0:-13]
    which means take the list mapping and copy its content form the first index to the last index - 13.
    so for a list with 15 indices list[:-13] and list[:2] are the same result list. also not assigning the 
    copied list to a variable does not really make any sense. if you do want to copy a list from its first 
    to its nth component it is simply mylist[:nth].

    mylist = mylist[:11]
    or a bit more extensive including checking for oor exceptions :
    def cliplist(data, n) :
        if isinstance(data, list) and isinstance(n, int) :
            if len(data) > n-1:
                return data[:n]
                return data
        return None
    mylist = cliplist(mylist, 11)

Log in to reply