• Login
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 16 Oct 2010, 19:48

    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
    • T Offline
      thomthom
      last edited by 16 Oct 2010, 19:59

      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
      • H Offline
        honoluludesktop
        last edited by 16 Oct 2010, 22:06

        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 16 Oct 2010, 22:56

          @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
          • T Offline
            thomthom
            last edited by 17 Oct 2010, 06:38

            @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 18 Oct 2010, 19:23

              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
              • T Offline
                thomthom
                last edited by 18 Oct 2010, 20:55

                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 19 Oct 2010, 16:08

                  @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 19 Oct 2010, 16:10

                    @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
                    • T Offline
                      thomthom
                      last edited by 19 Oct 2010, 16:15

                      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
                      • T Offline
                        thomthom
                        last edited by 29 Oct 2010, 22:46

                        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
                        • H Offline
                          honoluludesktop
                          last edited by 4 Nov 2010, 03:53

                          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