sketchucation logo sketchucation
    • 登入
    Oops, your profile's looking a bit empty! To help us tailor your experience, please fill in key details like your SketchUp version, skill level, operating system, and more. Update and save your info on your profile page today!
    ⚠️ Important | Libfredo 15.6b introduces important bugfixes for Fredo's Extensions Update

    Best way to iterate all nested entities

    已排程 已置頂 已鎖定 已移動 Developers' Forum
    29 貼文 9 Posters 6.5k 瀏覽 9 Watching
    正在載入更多貼文
    • 從舊到新
    • 從新到舊
    • 最多點贊
    回覆
    • 在新貼文中回覆
    登入後回覆
    此主題已被刪除。只有擁有主題管理權限的使用者可以查看。
    • liquid98L 離線
      liquid98
      最後由 編輯

      Lets say I've got a model full of nested groups/components.

      And I want to find all faces with a particular property in that model .

      What is a good solution to this problem?

      I tried:

      entities.each { |ent| 
      	if ent.is_a? Sketchup;;ComponentInstance or ent.is_a? Sketchup;;Group
      		#group
      		ent.entities.each { |ent| 
      			if ent.is_a? Sketchup;;ComponentInstance or ent.is_a? Sketchup;;Group
      				#nested group
      				ent.entities.each { |ent| 	
      					if
      						..
      					end
      				}
      			end	
      		}	
      	end
      }
      

      But I don't know how deep I have to dig!!

      Other solution I was thinking of: keep exploding everything until everything is free, then get my faces, undo the exploding part
      and move on..

      Any ideas are appreciated,

      thnx liquid

      Things that flourish fall into decay. This is not-Tao, And what is not-Tao soon ends ~ Lao tse

      1 條回覆 最後回覆 回覆 引用 0
      • liquid98L 離線
        liquid98
        最後由 編輯

        @dan rathbun said:

        So it is much more efficient to iterate the model's DefinitionList collection, and access the instances through a definitions instances collection.

        ah... that makes sense!

        @dan rathbun said:

        It is their definition that has the entities collection. (The group.entities() method is a shortcut that often deceives novices into thinking that the group instance has entities. It actually is a wrapper method for group.parent.entities )

        I'll remember that one 😄 😄, thank you!

        Liquid

        Extra :

        					@model.definitions.each { |d|
        			if d.group?
        				puts d.instances[0].class #==> Sketchup;;Group
        			end	
        			}
        

        Things that flourish fall into decay. This is not-Tao, And what is not-Tao soon ends ~ Lao tse

        1 條回覆 最後回覆 回覆 引用 0
        • TIGT 離線
          TIG Moderator
          最後由 編輯

          ### IF they aren't inside a context other than the model.entities
          matching_faces=[]
          Sketchup.active_model.entities.each{|face|
            next unless face.is_a?(Sketchup;;Face)
            ### check for compliance with some 'property' and then
            matching_faces << face if match
          }
          ### then find all others...
          Sketchup.active_model.definitions.each{|defn|
            defn.entities.each{|face|
              next unless face.is_a?(Sketchup;;Face)
              ### check for compliance with some 'property' and then
              matching_faces << face if match
            }
          }
          

          'matching_faces' is now the array containing ALL matching faces in the model and all components...
          Use if ! defn.instances[0] if you want to skip its inclusion because it is 'unused'...

          TIG

          1 條回覆 最後回覆 回覆 引用 0
          • Dan RathbunD 離線
            Dan Rathbun
            最後由 編輯

            @tig said:

            if ! defn.instances[0] you might want to skip its inclusion because it is 'unused'...

            Which would inserted as line 9.5 (above):
            next if defn.instances.empty?

            I'm not here much anymore.

            1 條回覆 最後回覆 回覆 引用 0
            • TIGT 離線
              TIG Moderator
              最後由 編輯

              Correct.
              We can't of course anticipate exactly what he wants - my method returns ALL matching faces - even those not included in the current model [or other container's entities]...
              By including what I/you suggested he can skip unused definitions using next... 🤓

              TIG

              1 條回覆 最後回覆 回覆 引用 0
              • Dan RathbunD 離線
                Dan Rathbun
                最後由 編輯

                Yup.. he should be on the right track now.

                👍

                I'm not here much anymore.

                1 條回覆 最後回覆 回覆 引用 0
                • thomthomT 離線
                  thomthom
                  最後由 編輯

                  When iterating the definitions of a model keep in mind that Image entities also has definitions, and you dont really want to mess around with the entities of this special definition. So make sure to test for definition.image?.

                  I've detailed SketchUp definitions and instances in this article: http://www.thomthom.net/thoughts/2012/02/definitions-and-instances-in-sketchup/

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

                  1 條回覆 最後回覆 回覆 引用 0
                  • liquid98L 離線
                    liquid98
                    最後由 編輯

                    Gentlemen,

                    Thanks! I wrote my code indeed along the lines TIG wrote..
                    edit:
                    Thomthom ok I'll do that!, thnx

                    Things that flourish fall into decay. This is not-Tao, And what is not-Tao soon ends ~ Lao tse

                    1 條回覆 最後回覆 回覆 引用 0
                    • TIGT 離線
                      TIG Moderator
                      最後由 編輯

                      TT makes a good point because Images do not have a '.entities' method - unless you create one...
                      so at the start of the code dealing with definitions use

                      ...
                      Sketchup.active_model.definitions.each{|defn|
                        next if defn.image?
                        defn.entities.each{|face|.....
                      

                      to skip all Images.
                      Similarly defn.group? spots a ' group', while anything else in the definitions is a ' component'...

                      TIG

                      1 條回覆 最後回覆 回覆 引用 0
                      • D 離線
                        david.
                        最後由 編輯

                        This method is fine if you are iterating over the entire model. I have situations when I only want to iterate over a selection. There is no definitions method in that case. I've been using recursion to iterate over a list of components/groups in the selection.

                        1 條回覆 最後回覆 回覆 引用 0
                        • TIGT 離線
                          TIG Moderator
                          最後由 編輯

                          matching_faces=[]
                          Sketchup.active_model.selection.each{|e|
                              if e.is_a?(Sketchup;;Face)
                                ### check for compliance with some 'property' and then
                                matching_faces << e if match
                              elsif e.is_a?(Sketchup;;Group)
                                e.entities.parent.entities.each{|face|
                                  next unless face.is_a?(Sketchup;;Face)
                                  ### check for compliance with some 'property' and then
                                  matching_faces << face if match
                                }
                              elsif e.is_a?(Sketchup;;ComponentInstance)
                                e.parent.entities.each{|face|
                                  next unless face.is_a?(Sketchup;;Face)
                                  ### check for compliance with some 'property' and then
                                  matching_faces << face if match
                                }       
                              end
                          }
                          

                          etc...
                          You can of course use the matching to do any number of things... that's up to you to decide... 😕

                          TIG

                          1 條回覆 最後回覆 回覆 引用 0
                          • Dan RathbunD 離線
                            Dan Rathbun
                            最後由 編輯

                            @david. said:

                            I've been using recursion ...

                            The bad news is that recursion is bad in Ruby, and worse in embedded Ruby.

                            It can cause a stack overflow, which crashes Ruby, and in the case of SketchUp embedded Ruby, will then crash SketchUp.

                            The good news is that you can write a method to collect the definitions whose instances are present in the selection.

                            I'm not here much anymore.

                            1 條回覆 最後回覆 回覆 引用 0
                            • Dan RathbunD 離線
                              Dan Rathbun
                              最後由 編輯

                              @dan rathbun said:

                              @david. said:

                              I've been using recursion ...

                              The bad news is that recursion is bad in Ruby, and worse in embedded Ruby.

                              It can cause a stack overflow, which crashes Ruby, and in the case of SketchUp embedded Ruby, will then crash SketchUp.

                              The good news is that you can write a method to collect the definitions whose instances are present in the selection.

                              I posted examples in a separate Code Snippet topic:
                              [ Code ] (Iterating) Finding Definitions

                              💭

                              I'm not here much anymore.

                              1 條回覆 最後回覆 回覆 引用 0
                              • Dan RathbunD 離線
                                Dan Rathbun
                                最後由 編輯

                                In reality,... instances (Group or Component,) do NOT really have entities collections.

                                It is their definition that has the entities collection. (The group.entities() method is a shortcut that often deceives novices into thinking that the group instance has entities. It actually is a wrapper method for group.entities.parent.entities )

                                Also a the Group class is a special kind of ComponentInstance class.

                                Both have a parent ComponentDefinition

                                So it is much more efficient to iterate the model's DefinitionList collection, and access the instances through a definitions instances collection.


                                EDIT: Fixed second paragraph, group.entities.parent.entities was group.parent.entities in error.

                                I'm not here much anymore.

                                1 條回覆 最後回覆 回覆 引用 0
                                • thomthomT 離線
                                  thomthom
                                  最後由 編輯

                                  @dan rathbun said:

                                  @david. said:

                                  I've been using recursion ...

                                  The bad news is that recursion is bad in Ruby, and worse in embedded Ruby.

                                  It can cause a stack overflow, which crashes Ruby, and in the case of SketchUp embedded Ruby, will then crash SketchUp.

                                  The good news is that you can write a method to collect the definitions whose instances are present in the selection.

                                  I use recursion for digging into nested components levels - because the recursion level is not going to max out the call stack unless you have a model that was designed to crash it. Nobody nests geometry that deep.

                                  Recursing when traversing over connected geometry on the other hand will quickly hit the limit of the call stack.

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

                                  1 條回覆 最後回覆 回覆 引用 0
                                  • S 離線
                                    shannonnovus
                                    最後由 編輯

                                    @tig said:

                                    
                                    >     elsif e.is_a?(Sketchup;;ComponentInstance)
                                    >       e.parent.entities.each{|face|
                                    >         next unless face.is_a?(Sketchup;;Face)
                                    >         ### check for compliance with some 'property' and then
                                    >         matching_faces << face if match
                                    >       }       
                                    >     end
                                    > }
                                    

                                    One comment: This section of the code for components didn't work for me. It wasn't giving any error messages, it just wasn't making any changed to the components in my model. I changed the second line to e.definition.entities.each .... and that worked.

                                    One question: I'm not processing faces like this example, but edges. I'm modifying another script from TIG to delete all vertical edges in my model. I need it to also recurse into groups and components, so I've combined it with the script here.

                                    So ... the first time I run the script, it deletes all vertical lines that are not within groups/components. From groups/components, however, it leaves one vertical line in each. (This is run on a simple test file that has three cubes, one is ungrouped, one is a group, the last in a component.) If I run the script a second time, it deletes the remaining vertical lines from the groups/components. I'd appreciate if anyone could explain what's going on here, and if there is a way to write the code such that each vertical edge is dealt with in the first go.

                                    Many thanks,
                                    Shannon

                                    1 條回覆 最後回覆 回覆 引用 0
                                    • Dan RathbunD 離線
                                      Dan Rathbun
                                      最後由 編輯

                                      The API's Entities collection(s), is/are actually thinly-exposed (to Ruby,) C++ collection(s).

                                      You CANNOT safely both iterate such a set AND delete items from the set AT THE SAME TIME.

                                      Doing so creates a "fence post error" in which the iteration reference skips one (or more) items in the set.

                                      This has been covered so many times before. (Here and in other forums.)

                                      Seems every newbie must fall for this boo boo.

                                      Use the standard Ruby to_a() or grep() method to take a "snapshot" Ruby array copy of API collections.
                                      Then iterate THAT Ruby copy, viz:
                                      entities.grep(Sketchup::Edge).each {|e| e.erase! if is_vertical?(e) }

                                      is_vertical?() is a hypothetical utility query method within your plugin's class or module.

                                      Would be something like:

                                      def is_vertical?(edge)
                                        vec = edge.start.position.vector_to(edge.end.position).normalize
                                        vec == [0,0,1] || vec == [0,0,-1]
                                      end
                                      

                                      Note that some of those old examples were written before we knew how very fast the grep() method was.
                                      USE it to filter collections when you want only one class of object. It is FAST!
                                      (This method comes from the mixin module Enumerable, which is mixed into many collection classes.)

                                      I'm not here much anymore.

                                      1 條回覆 最後回覆 回覆 引用 0
                                      • Dan RathbunD 離線
                                        Dan Rathbun
                                        最後由 編輯

                                        When "drilling down" into the entities of component or groups, it is so very much faster to go through the model's definitions collection, checking each definition if it's instances collection has size > 0, (and possibly if it is image? == false,) and if so...

                                        ... delete from the definitions entities collection, and all instances are changed.

                                        I'm not here much anymore.

                                        1 條回覆 最後回覆 回覆 引用 0
                                        • tt_suT 離線
                                          tt_su
                                          最後由 編輯

                                          .grep is an iterator itself - so no need for .each:

                                          entities.grep(Sketchup::Edge) {|edge| edge.erase! if is_vertical?(edge) }

                                          1 條回覆 最後回覆 回覆 引用 0
                                          • tt_suT 離線
                                            tt_su
                                            最後由 編輯

                                            Saying that - bulk methods is much faster than individual actions. Use entities.erase_entities when you erase multiple entities - it also avoids the pitfall of erasing the collection you are erasing from.

                                            1 條回覆 最後回覆 回覆 引用 0
                                            • 1
                                            • 2
                                            • 1 / 2
                                            • 第一個貼文
                                              最後的貼文
                                            Buy SketchPlus
                                            Buy SUbD
                                            Buy WrapR
                                            Buy eBook
                                            Buy Modelur
                                            Buy Vertex Tools
                                            Buy SketchCuisine
                                            Buy FormFonts

                                            Advertisement