Ruby Sketchup Programmatic Union of Multiple items  Topic is solved

Ruby Sketchup Programmatic Union of Multiple items

Postby hank » Sun Apr 16, 2017 5:23 pm

Hello. If you want to union multiple solids programmatically, how would you do it? With the union tool (Tools > Solid Tools > Union [Pro Only]) you pick one solid, then another but can continue to pick solids, adding to the Union Result. Using #union(group) however, I am having trouble keeping a handle on the union result in order to continue adding to it.

If I do

Code: Select all
union_result = group_a.union(group_b)


I can't seem to refer to union_result when I try to run union again for subsequent objects.

Here is the total picture that may provided more insight...

Disclaimer: this seems like a dumb way to do this but, because when I loop through all my target groups, I need something to union the first one with, I am creating a small dummy group like so...

Code: Select all
mod = Sketchup.active_model
ent = mod.active_entities

# create a dummy object for initiating union
dummy_face = ent.add_face([0,0,0],[1,0,0],[1,1,0],)
dummy_group = ent.add_group(dummy_face)
dummy_group.name = 'DUMMY GROUP'
dummy_face.pushpull(1,true)


Then here is the actual iterating (WARNING - BUG SPLATS!):

Code: Select all
ent.grep(Sketchup::Group).each_with_index do |item, i|
   next if item.name!='MY_TARGET_GROUPS'
   if i <= 1 # first run so union with dummy
      union_temp = item.union(dummy_group)
      union_temp.name = 'TEMP_RESULT'
   else # subsequent runs can union with prior union result
      union_final = item.union(union_temp)
      union_final.name = 'UNION_RESULT'
   end
end


I also tried using entities[-1] for the last created entity and that ALSO BUG SPLATS:

Code: Select all
union_final = item.union(ent[-1])


Perhaps there is something I am misunderstanding about iterating that "clears" the variables created during each loop? Do I need a global or something using the @ designation?

Also, instead of using a dummy object, perhaps I should just skip the first group - but then I would need a handle to be able to refer to it during the next iteration?
Your thoughts would be appreciated.
0

hank 
 

Re: Ruby Sketchup Programmatic Union of Multiple items  Topic is solved

Postby Dan Rathbun » Mon Apr 17, 2017 2:34 am

Yes other coders use dummy groups, but usually just push a cpoint into it, which can be easily removed later.

Iterating collections. You cannot modify the same collection that you are iterating, ie changing the number of members. The iteration loses it's way, and members are either skipped, or referenced after they've been deleted. (We've said this so many time here, you'll likely get search hits on "iterate" etc.)
So we usually make a copy of the collection, and iterate the copy. Also check each iterative reference for validity and loop next if it's no longer valid. Ie:
next unless item.valid?
1
    I'm not here much anymore. But a PM will fire email notifications.
    User avatar
    Dan Rathbun 
    PluginStore Author
    PluginStore Author
     

    Re: Ruby Sketchup Programmatic Union of Multiple items

    Postby hank » Mon Apr 17, 2017 3:38 am

    Perfect Dan - Thank you. That was a two for: next unless item.valid? will be so helpful too.

    BTW, I tried @variables and skipping the first element as shown below and it worked!

    Code: Select all
    ent.grep(Sketchup::Group).each_with_index do |item, i|
        next if item.name!='MY_TARGET_GROUPS'
       if i < 1
          puts "skipping first iteration for item: #{item} | #{i}"
          @first_one = item
       elsif i == 1
          @first_union = @first_one.union(item)
          @subsequent_handle = @first_union
       else
          @result_union = @subsequent_handle.union(item)
       end
    end


    So the @variable was "remembered" as TIG explained to me here which seemed to be what I needed.

    Now I just have to streamline the iteration BEFORE the loop because this method uses an index that can't see the next if item.name!='MY_TARGET_GROUPS' check. If I have 10 groups and only 3 of them qualify, the index will be off and I might save the wrong @first_one. If I could get grep to do a Group check AND a name check, I could iterate with an accurate index. Can grep be passed multiple patterns in one call?
    0

    hank 
     

    Re: Ruby Sketchup Programmatic Union of Multiple items

    Postby Dan Rathbun » Tue Apr 18, 2017 11:38 pm

    hank wrote:If I could get grep to do a Group check AND a name check, I could iterate with an accurate index. Can grep be passed multiple patterns in one call?

    grep() can be passed a block.

    OR, you can call another of the iterative filter methods from Enumerable.

    And read the Ruby core docs when you wish to know what a method can and cannot do.
    http://ruby-doc.org/core-2.2.4/Enumerable.html
    Enumerable is a mixin library module that is mixed into most all collection classes.

    Would something like this also work ?

    Code: Select all
    grps = ent.grep(Sketchup::Group).find_all {|g| g.name = 'MY_TARGET_GROUPS' }
    # check here to be sure grps is not empty
    @union = grps.shift # slice the first member from grps array
    grps.each do |item|
      next unless item.valid?
      @union = @union.union(item)
    end
    # after the loop, refs in "grps" are all likely invalid:
    grps.clear




    P.S. - Ruby uses 2 space indents. There is NO coding language in the world that uses odd number of spaces in indents. (Really annoying.)
    1
      I'm not here much anymore. But a PM will fire email notifications.
      User avatar
      Dan Rathbun 
      PluginStore Author
      PluginStore Author
       

      Re: Ruby Sketchup Programmatic Union of Multiple items

      Postby hank » Sat Apr 22, 2017 2:20 pm

      Dan, that is genius. Thank you.

      I think this

      Code: Select all
      g.name = 'MY_TARGET_GROUPS'


      needs to be changed to

      Code: Select all
      g.name == 'MY_TARGET_GROUPS'


      Right? It changed set all group names rather than testing for equivalence.

      Anyway, grep with a more complex block seems like such a more efficient way of getting objects than getting an array then looping it to test for certain properties, then looping THAT array to test for others, and so on... which is what I felt like I was doing before. This will be really helpful generally.

      And got it about the 2 spaces... Just didn't paste in from Dreamweaver cleanly but will do!
      0

      hank 
       

      SketchUcation One-Liner Adverts

      by Ad Machine » 5 minutes ago



      Ad Machine 
      Robot
       



       

      Return to Developers' Forum

      Who is online

      Users browsing this forum: No registered users and 4 guests

      Visit our sponsors: