sketchucation logo sketchucation
    • Login
    πŸ€‘ SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

    Recursive print_group_tree() help

    Scheduled Pinned Locked Moved Developers' Forum
    12 Posts 3 Posters 483 Views 3 Watching
    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.
    • D Offline
      draftomatic
      last edited by

      Hi all,

      I'm writing a recursive method that will find all the groups in a tree-like fashion and print their names. I think I have something that works, but recursion always makes me nervous, so I'm hoping someone can check my reasoning... maybe it's not very optimized etc etc...

      
        #
        # recursively print the group tree
        #
        def print_group_tree()
          @model.definitions.each { |d|
            if (d.group? && d.instances[0].parent.is_a?(Sketchup;;Model) )
              if (d.instances[0].is_a?(Sketchup;;Group))   # Assume Groups are unique
                puts d.instances[0].name
                recurse_group(d.instances[0])
              end
            end
          }
        end
      
        def recurse_group(group)
          group.entities.select { |e| 
            e.is_a?(Sketchup;;Group) 
          }.each { |g| 
            puts g.name
            recurse_group(g) 
          }
        end
      

      I'm making Groups unique before I run this, just to be sure (I know SketchUp can be touchy about Groups and uniqueness...)

      Thanks!

      1 Reply Last reply Reply Quote 0
      • thomthomT Offline
        thomthom
        last edited by

        1. You're getting a tree of the entities in a model - would it not be better to start with model.entities instead of scanning model.definitions for instances with parent that is model?

        2. Your code makes the assumption that all instances has instances, this might not be the case.

        3. You can not assume groups are all unique - group definitions often has group instances. At least from what I observe from the models at our office and the warehouse.

        4. if (d.group? && d.instances[0].parent.is_a?(Sketchup::Model) ) if (d.instances[0].is_a?(Sketchup::Group))
          Somewhat reduntant checks there - you first check the definition if it's a group, then you check it's instances. No need to that double check.

        
          def recurse_group(group)
            group.entities.select { |e|
              e.is_a?(Sketchup;;Group)
            }.each { |g|
              puts g.name
              recurse_group(g)
            }
          end
        
        

        Could be made more efficient. At the moment you first scan the entities collection to filter out groups, then you scan those results again. Making double iteration over all groups.

        
          def recurse_group(group)
            group.entities.each { |e|
              next unless e.is_a?(Sketchup;;Group)
              puts e.name
              recurse_group(e)
            }
          end
        
        

        There - small change, but ensure you only iterate each entity only once.

        Thomas Thomassen β€” SketchUp Monkey & Coding addict
        List of my plugins and link to the CookieWare fund

        1 Reply Last reply Reply Quote 0
        • honoluludesktopH Offline
          honoluludesktop
          last edited by

          Tom, didn't know that a method can call itself. Boy I've got a lot to learn. What happens to the variables? Guess they are they recreated each time the method is called.

          1 Reply Last reply Reply Quote 0
          • D Offline
            draftomatic
            last edited by

            @thomthom said:

            1. You're getting a tree of the entities in a model - would it not be better to start with model.entities instead of scanning model.definitions for instances with parent that is model?

            Seems wasteful to iterate all of the entities when all I want is the Group tree. There will normally be less Definitions/Groups than Entities, no?

            @unknownuser said:

            1. Your code makes the assumption that all instances has instances, this might not be the case.

            What if I purge the model before I run this code?

            @model.definitions.purge_unused
            

            @unknownuser said:

            1. You can not assume groups are all unique - group definitions often has group instances. At least from what I observe from the models at our office and the warehouse.

            I'm using this routine to make all Groups unique before I run this code:

            
                @model.definitions.each { |d|
                  if (d.group?())
                    d.instances.each { |i|
                      i.make_unique
                    }
                  end
                }
            
            
            1 Reply Last reply Reply Quote 0
            • thomthomT Offline
              thomthom
              last edited by

              @draftomatic said:

              Seems wasteful to iterate all of the entities when all I want is the Group tree. There will normally be less Definitions/Groups than Entities, no?

              Yes, but you iterate the entities of the groups, so you're only skipping a few entities at the root. In most models I've seen, the root contains mostly groups or components, so there would be little to gain. You could be feeding your recursive method entities collections, starting with model. entities. You'd then have less code.

              @draftomatic said:

              What if I purge the model before I run this code?

              You could, but it's only an extra check to verify there is instances. And maybe some users don't want their model purged without their knowing.

              @honoluludesktop said:

              Tom, didn't know that a method can call itself. Boy I've got a lot to learn. What happens to the variables? Guess they are they recreated each time the method is called.

              method variables are local to each calling of the method, yes.
              Beware of recursive methods though, if you call it too many time you end up with stack overflow - which will crash SU. Very easy to do if you iterate entities with recursive methods.

              Thomas Thomassen β€” SketchUp Monkey & Coding addict
              List of my plugins and link to the CookieWare fund

              1 Reply Last reply Reply Quote 0
              • D Offline
                draftomatic
                last edited by

                Thanks thomthom... is this better?

                  def print_group_tree()
                    @model.entities.each { |e|
                      if (e.is_a?(Sketchup;;Group))
                          puts e.name
                          recurse_group(e)
                      end
                    }
                  end
                  
                  def recurse_group(group)
                    group.entities.each { |e|
                      next unless e.is_a?(Sketchup;;Group)
                      puts e.name
                      recurse_group(e)
                    }
                  end
                
                1 Reply Last reply Reply Quote 0
                • thomthomT Offline
                  thomthom
                  last edited by

                  Yes - though, is this just a framework of what it will do? As it is now it looks like it prints out the names in a pretty flat list...

                  I mean, the code traverses the model tree, but from the code I don't see any reason to do a tree traversal. A flat traversal of model.definitions would be the same?

                  What is the more abstract purpose of outputting the group names?

                  Thomas Thomassen β€” SketchUp Monkey & Coding addict
                  List of my plugins and link to the CookieWare fund

                  1 Reply Last reply Reply Quote 0
                  • D Offline
                    draftomatic
                    last edited by

                    @thomthom said:

                    I mean, the code traverses the model tree, but from the code I don't see any reason to do a tree traversal. A flat traversal of model.definitions would be the same?

                    I'm writing an XML exporter that exports the Group tree along with the rest of the model... XML = tree.

                    Obviously my real code is doing more than just printing names. But it's top-secret! πŸ˜ƒ

                    1 Reply Last reply Reply Quote 0
                    • D Offline
                      draftomatic
                      last edited by

                      @honoluludesktop said:

                      Tom, didn't know that a method can call itself. Boy I've got a lot to learn. What happens to the variables? Guess they are they recreated each time the method is called.

                      Look up "Recursion" =). Each call has its own scope.

                      Link Preview Image
                      Recursion (computer science) - Wikipedia

                      favicon

                      (en.wikipedia.org)

                      One of the best examples is computing the Fibonacci sequence.

                      1 Reply Last reply Reply Quote 0
                      • thomthomT Offline
                        thomthom
                        last edited by

                        Righti'o!

                        Thomas Thomassen β€” SketchUp Monkey & Coding addict
                        List of my plugins and link to the CookieWare fund

                        1 Reply Last reply Reply Quote 0
                        • thomthomT Offline
                          thomthom
                          last edited by

                          Recursing works generally for digging down the model tree with groups and components, but if you use it to process edges and faces - like traversing connected geometry, then you will run into stack overflow.

                          Thomas Thomassen β€” SketchUp Monkey & Coding addict
                          List of my plugins and link to the CookieWare fund

                          1 Reply Last reply Reply Quote 0
                          • honoluludesktopH Offline
                            honoluludesktop
                            last edited by

                            tt, This recursive stuff really works! Below drills down into component instances. Now, on to add groups.

                            def get_ci(ci_array)
                              entities = Sketchup.active_model.entities
                              entities.each do |ent|
                                if ent.is_a? Sketchup;;ComponentInstance
                                  ci_array.push ent
                                end
                              end
                              return ci_array
                            end
                            
                            def explode_ci_array(ci_array)
                              ci_sub_array=[]
                              ci_array.each do |ci|
                                if ci.is_a? Sketchup;;ComponentInstance
                                  ci_sub_array=ci.explode
                                end
                              end
                              return ci_sub_array
                            end
                            
                            ci_array=[]
                            found = false
                            while found == false
                              ci_array=get_ci(ci_array)
                              ci_array=explode_ci_array(ci_array)
                              if ci_array[0] == nil
                                found = true
                              end
                            end
                            
                            1 Reply Last reply Reply Quote 0
                            • 1 / 1
                            • First post
                              Last post
                            Buy SketchPlus
                            Buy SUbD
                            Buy WrapR
                            Buy eBook
                            Buy Modelur
                            Buy Vertex Tools
                            Buy SketchCuisine
                            Buy FormFonts

                            Advertisement