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
    • Recent
    • Tags
    • Users
    • Login

    Selecting objects via partial name

    Scheduled Pinned Locked Moved PYTHON Development
    6 Posts 0 Posters 505 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H Offline
      Helper
      last edited by

      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.
      eg.
      Layer panel
      Layer panel
      Layer window
      Layer window
      Streetlamp
      Streetlamp_02

      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

      Tom

      1 Reply Last reply Reply Quote 0
      • H Offline
        Helper
        last edited by

        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() :
                        result.append(node)
            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.

        1 Reply Last reply Reply Quote 0
        • H Offline
          Helper
          last edited by

          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:  
                return  
            
            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)  
                null.SetName(name)  
                for obj in objects:  
                    doc.AddUndo(c4d.UNDOTYPE_CHANGE, obj)  
                    obj.Remove()  
                    obj.InsertUnderLast(null)  
                doc.AddUndo(c4d.UNDOTYPE_NEW, null)  
                doc.InsertObject(null, root, prev)  
                prev = null  
            
            c4d.EventAdd()  
            
          main()  
          

          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.

          1 Reply Last reply Reply Quote 0
          • H Offline
            Helper
            last edited by

            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() :

            1 Reply Last reply Reply Quote 0
            • H Offline
              Helper
              last edited by

              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:  
                mapping[:-13]  
              

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

              1 Reply Last reply Reply Quote 0
              • H Offline
                Helper
                last edited by

                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]
                        else:
                            return data
                    return None
                  
                ...
                  
                mylist = cliplist(mylist, 11)
                
                1 Reply Last reply Reply Quote 0
                • First post
                  Last post