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.8b introduces important bugfixes for Fredo's Extensions Update

    Best way to iterate all nested entities

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

            Yea so you can also do this:

            verts = entities.grep(Sketchup::Edge).find_all {|edge| is_vertical?(edge) } entities.erase_entities(verts) unless verts.empty?

            💭

            P.S. @TT Yea I knew grep() is an iterator, but I usually avoid using a block with it, as it returns an array of block results which is a bit weird. (Especially when you expect a smaller subset than the whole.)
            I tend to just use it as a filter, and then call another method on the filtered results. IMHO the code is more readable. (.. and I don't confuse myself as much.)

            I'm not here much anymore.

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

              @dan rathbun said:

              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) }

              Thanks Dan! The grep method worked great!

              @dan rathbun said:

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

              Your example for how to test for a vertical edge did not work for me, which could be entirely my fault. TIG's code from the other forum I mentioned did.

              edge.line[1].z.abs==1
              
              1 條回覆 最後回覆 回覆 引用 0
              • tt_suT 離線
                tt_su
                最後由 編輯

                To use the same tolerance as SketchUp does, use the methods built into the Ruby API:

                vector = edge.line[1] vector.samedirection?(Z_AXIS)

                http://www.sketchup.com/intl/en/developer/docs/ourdoc/vector3d.php#samedirection?

                The components of a vector are floating point values so they should never be compared without a tolerance. For more information about floating point precision: http://floating-point-gui.de/

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

                  @tt_su said:

                  To use the same tolerance as SketchUp does, use the methods built into the Ruby API:

                  vector = edge.line[1] vector.samedirection?(Z_AXIS)

                  http://www.sketchup.com/intl/en/developer/docs/ourdoc/vector3d.php#samedirection?

                  The components of a vector are floating point values so they should never be compared without a tolerance. For more information about floating point precision: http://floating-point-gui.de/

                  Excellent advice! Do you know whether Point3d#on_line? and #on_plane? also include the tolerance? The API docs don't say.

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

                    Yes it does. Do does Geom::Point3d, Geom::Vector3d and Length - which is why it's recommended you use those types when doing calculations, instead of using arrays and floats.

                    Also note that Length + Length == Float (annoyingly). So you need to ensure you have a Length before outputting that to a string.

                    1 條回覆 最後回覆 回覆 引用 0
                    • dkendigD 離線
                      dkendig
                      最後由 編輯

                      definition.instances.empty? won't give you an accurate indicator of the usefulness of a definition unfortunately. It can cut out some obvious ones to skip, but not all of the useless ones. If an instance is used in a definition, and that parent definition isn't instanced anywhere, the first definition will still say it has one instance. It's not wrong... but it's not helpful either. It would be nice to know if a definition is actually used in your model somewhere. Of course if you purge unused first, you should be fine. This can be especially frustrating when working with a model in which you are not allowed to purge unused definitions.

                      Example:

                      1. Make a cube
                      2. Make the cube a component
                      3. Make a copy of the component instance
                      4. Make a new component out of the two instances
                      5. Delete the resulting component instance
                      6. Type this in the ruby console: Sketchup.active_model.definitions.each{|df| puts "definition #{df.name} instance count: #{df.instances.size}"};nil

                      Devin Kendig
                      Developer

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

                        Ah yes - very good point.

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

                          To check if a defn with instances actually has one or more if these inserted in the model, or also it is inside a 'container' that is itself inserted in the model, OR inside something else that is inserted in the model... etc...
                          Start count=0.
                          Look at each instance in turn and get its parent.
                          If its parent is the model then it is inserted (count+=1).
                          Elsif its parent is another component-defn you'll need to check if that definition has instances and iterate those and if their parent is the model (count+=1 and break) but if its parent is another component-defn repeat the nested testing of that definition having instances etc...

                          With an instance of Component#1 inside Component#2, and two instances of both in model.

                          ` instance_counter()

                          Component Name: Component#1
                          All Instances: 4
                          Inserted Instances: 2
                          Nested Instances: 2

                          Component Name: Component#2
                          All Instances: 1
                          Inserted Instances: 1
                          Nested Instances: 0

                          true`

                          With only 2 instances of Component#1

                          ` instance_counter()

                          Component Name: Component#1
                          All Instances: 2
                          Inserted Instances: 0
                          Nested Instances: 2

                          Component Name: Component#2
                          All Instances: 1
                          Inserted Instances: 1
                          Nested Instances: 0

                          true`

                          This is only to demonstrate the principal - clearly you'd want to hae a proper model/method that returned the counts for you...

                          require('sketchup.rb')
                          def instance_counter()
                          	def instances?(d)
                          		model=Sketchup.active_model
                          		cont=0
                          		d.instances.each{|i|
                          			parent=i.parent
                          			if parent==model
                          				cont+=1
                          			else
                          				cont+=instances?(parent)
                          			end
                          		}
                          		return cont
                          	end
                          	model=Sketchup.active_model
                          	puts
                          	model.definitions.each{|d|
                          		next if d.image? || d.group?
                          		puts "Component Name; \t#{d.name}"
                          		puts "All Instances;  \t#{d.instances.length}"
                          		count=0
                          		ncount=0
                          		d.instances.each{|i|
                          			parent=i.parent
                          			if parent==model
                          				count+=1
                          			else
                          				ncount+=instances?(parent)
                          			end
                          		}
                          		puts "Inserted Instances; \t#{count}"
                          		puts "Nested Instances;   \t#{ncount}"
                          		puts
                          	}
                          	return true
                          end
                          

                          Perhaps a method that takes the defn as its argument and returns the instances count in three arrayed integers [all, model, nested] ... [4, 2, 2] - like this:

                          def instance_count(d=nil) #d=defintion
                          	return nil if !d || !d.is_a?(Sketchup;;ComponentDefinition)
                          	return false if d.image? || d.group?
                          	def instances?(d)
                          		model=Sketchup.active_model
                          		cont=0
                          		d.instances.each{|i|
                          			parent=i.parent
                          			if parent==model
                          				cont+=1
                          			else
                          				cont+=instances?(parent)
                          			end
                          		}
                          		return cont
                          	end
                          	model=Sketchup.active_model
                          	count_array=[d.instances.length]
                          	count=0
                          	ncount=0
                          	d.instances.each{|i|
                          		parent=i.parent
                          		if parent==model
                          			count+=1
                          		else
                          			ncount+=instances?(parent)
                          		end
                          	}
                          	count_array << count
                          	count_array << ncount
                          	return count_array
                          end
                          

                          TIG

                          1 條回覆 最後回覆 回覆 引用 0
                          • dkendigD 離線
                            dkendig
                            最後由 編輯

                            yes, generally this tends to do the trick, but we found that it was a tad faster to have your own lookup table that keeps track of definition relevance. The only downside, is that you are at the mercy of the observer system in that case, but the observers these days seem fairly stable, so that isn't currently an issue.

                            Devin Kendig
                            Developer

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

                            Advertisement