• Login
sketchucation logo sketchucation
  • Login
ℹ️ GoFundMe | Our friend Gus Robatto needs some help in a challenging time Learn More

Boolean: how do I 'outershell' multiple groups/components?

Scheduled Pinned Locked Moved Developers' Forum
12 Posts 3 Posters 947 Views
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.
  • L Offline
    liquid98
    last edited by 12 Mar 2012, 16:29

    Hello,

    I have a question about the Boolean functions 'outer_shell' and 'union'.
    See attached file.
    If I select all (6 groups ) and use the mouse to 'outershell' I get the 3 single groups plus the new united group.

    How do I mimic this behavior in code??
    All I could imagine is this rather brute force technique:

    <span class="syntaxdefault">entlength </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">length <br />            for f in 0</span><span class="syntaxkeyword">...</span><span class="syntaxdefault">entlength<br />                for g in 0</span><span class="syntaxkeyword">...</span><span class="syntaxdefault">entlength<br />                    begin<br />                    entities</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">f</span><span class="syntaxkeyword">].</span><span class="syntaxdefault">outer_shell</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">entities</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">g</span><span class="syntaxkeyword">])<br /></span><span class="syntaxdefault">                    rescue<br />                    end<br />                end    <br />            end</span>
    

    any ideas are appreciated!

    Thnx , liquid

    question.skp

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

    1 Reply Last reply Reply Quote 0
    • D Offline
      Dan Rathbun
      last edited by 14 Mar 2012, 06:33

      Your code will fail for several reasons. If you are going to use for .. in, you must subtract 1 from the length of the array/set/collection. (It's better to use the each iterators, to avoid "fence post" errors.)

      Secondly, you must make an Array copy, of the entities (or any C++ collection,) if you will be making model changes during the iteration.

      Third you need to test the objects for class Sketchup::ComponentInstance or Sketchup::Group, etc., before doing something that you can only do to those class objects, and it's also safer to test if they are manifold, via ent.manifold?, before attempting boolean operations on them.

      Fourth, boolean methods are pro only, so a conditional to test Sketchup.is_pro? is also needed.

      Have you checked the [ Code Snippets ] Index in the Developers Forum ??
      Or searched the Developers Forum ?? (TIG has explained both basic and advanced entities iteration many times over.)

      I'm not here much anymore.

      1 Reply Last reply Reply Quote 0
      • L Offline
        liquid98
        last edited by 14 Mar 2012, 20:41

        Hi Dan,

        Thanx for your input. Used to post my questions in the 'plugins' section, my apologies for that.
        First thanx for pointing me out, the code snippet section was totally new for me, so that's a good one!

        I realize I was to quick posting my code. Indeed, the iteration range was not ok. The tree tests (right class?,
        manifold? and pro) aren't relevant in my situation.

        @dan rathbun said:

        Secondly, you must make an Array copy, of the entities (or any C++ collection,) if you will be making model changes during the iteration.
        This is the part I don't get. You say TIG wrote a lot about this subject..
        I'will look for it then, and come back here if I still don't get it.

        Thank you!

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

        1 Reply Last reply Reply Quote 0
        • D Offline
          Dan Rathbun
          last edited by 14 Mar 2012, 23:09

          @liquid98 said:

          The tree tests (right class?, manifold? and pro) aren't relevant in my situation.

          Yes they are.. you just do not realize it yet.
          You cannot call outer_shell() or manifold? on an entity, unless it is either a Sketchup::Group or Sketchup::ComponentInstance instance object.
          IF you call outer_shell() when Sketchup.is_pro? is false (Free edition,) an Error will be raised.

          @liquid98 said:

          @dan rathbun said:

          Secondly, you must make an Array copy, of the entities (or any C++ collection,) if you will be making model changes during the iteration.
          This is the part I don't get.

          Because when changes are made to the model on the C++ side, the objects in the C++ collections are shuffled around. Your iterator will "lose it's way," and miss processing some entities, and process others multiple times.

          So use the to_a method, to make an Array, of ONLY the groups in the C++ collection, like this:

          grps = []
          model.entities.to_a.each {|ent|
            grps << ent if ent.is_a?(Sketchup;;Group)
          }
          

          Or use the find_all method (which always returns an array.):

          grps = model.entities.find_all {|ent| ent.is_a?(Sketchup;;Group) }
          
          

          Then you can safely iterate using the members of the grps array (and when the entities collection rehashes itself, it will not effect your iteration.)

          unless grps.empty?
            grps.each {|grp|
              # process each group, one at a time
            }
          end
          

          I'm not here much anymore.

          1 Reply Last reply Reply Quote 0
          • L Offline
            liquid98
            last edited by 17 Mar 2012, 19:35

            Hi Dan,

            @dan rathbun said:

            Yes they are.. you just do not realize it yet.

            I do realize that. But the script I'm writing is for internal use. So everything
            this script will process meets the criteria already. But you couldn't know that.. 😒
            By the way ' outer_shell' is also available in free version, I think.

            The reason for adding the groups to an array is also clear to me now, otherwise the iteration process is not going well and SU could skip a few items.

            Now for the real problem:

            First I need to add all the candidates for the boolean unite operation to an array. In other words: only group-entities that intersect will be processed.

            I tried BoundingBox.intersect but it gives me false positives in cases of close
            proximity. So I've done some more reading and I ended up in the loops section of the SU API. Can the loop class help me here tot detect if groups really intersect??

            This is the only problem left, the boolean problem I solved by my self. ☀ ☀ This script unifies all intersecting groups to one solid:

            <span class="syntaxdefault">                file </span><span class="syntaxkeyword">=</span><span class="syntaxstring">"D;\\Desktop\\bool.skp"<br /></span><span class="syntaxdefault">            Sketchup</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">open_file</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">file</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">            <br />            model </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> Sketchup</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_model<br />            entities </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_entities <br />            <br />            foo</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> nonfoo </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">[],</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">[]<br /></span><span class="syntaxdefault">            grps </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">find_all </span><span class="syntaxkeyword">{|</span><span class="syntaxdefault">ent</span><span class="syntaxkeyword">|</span><span class="syntaxdefault"> ent</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">is_a</span><span class="syntaxkeyword">?(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Group</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">}<br /></span><span class="syntaxdefault">            <br />            grps</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">each </span><span class="syntaxkeyword">{</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">|</span><span class="syntaxdefault">a</span><span class="syntaxkeyword">|</span><span class="syntaxdefault"> unless a </span><span class="syntaxkeyword">==</span><span class="syntaxdefault"> grps</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">last <br />                            a</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">name </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxstring">'foo'</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> foo</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">push a<br />                        else<br />                            a</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">name </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxstring">'nonfoo'</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> nonfoo</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">push a<br />                        end <br />                        </span><span class="syntaxkeyword">}<br /></span><span class="syntaxdefault">            <br />            until foo</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">]</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">==</span><span class="syntaxdefault"> nil<br />                foo</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">each     </span><span class="syntaxkeyword">{</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">|</span><span class="syntaxdefault">ff</span><span class="syntaxkeyword">|</span><span class="syntaxdefault"> <br />                                if  </span><span class="syntaxkeyword">((</span><span class="syntaxdefault">ff</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">bounds</span><span class="syntaxkeyword">).</span><span class="syntaxdefault">intersect</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">nonfoo</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">].</span><span class="syntaxdefault">bounds</span><span class="syntaxkeyword">)).empty?</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">==</span><span class="syntaxdefault"> false<br />                                    </span><span class="syntaxkeyword">(</span><span class="syntaxdefault">ff</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">outer_shell</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">nonfoo</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">])).</span><span class="syntaxdefault">name </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxstring">'nonfoo'<br /></span><span class="syntaxdefault">                                end<br />                                 <br />                        </span><span class="syntaxkeyword">}<br /></span><span class="syntaxdefault">                foo </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">find_all </span><span class="syntaxkeyword">{|</span><span class="syntaxdefault">ent</span><span class="syntaxkeyword">|</span><span class="syntaxdefault"> ent</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">name </span><span class="syntaxkeyword">==</span><span class="syntaxdefault"> </span><span class="syntaxstring">'foo'</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">}</span><span class="syntaxdefault">    <br />                nonfoo </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">find_all </span><span class="syntaxkeyword">{|</span><span class="syntaxdefault">ent</span><span class="syntaxkeyword">|</span><span class="syntaxdefault"> ent</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">name </span><span class="syntaxkeyword">==</span><span class="syntaxdefault"> </span><span class="syntaxstring">'nonfoo'</span><span class="syntaxkeyword">}</span><span class="syntaxdefault">     <br />            end</span>
            

            bool.skp

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

            1 Reply Last reply Reply Quote 0
            • D Offline
              Dan Rathbun
              last edited by 17 Mar 2012, 20:50

              @liquid98 said:

              I tried BoundingBox.intersect but it gives me false positives in cases of close
              proximity.

              BoundingBox.intersect always returns a BoundingBox object.

              From memory.. either one of these Happen:

              (1) If it really is a 3D method: (I think,) you may have to test the result for dimension. In other words if there is no intersection, the result BoundingBox would have 0 for depth, width and height.

              (2) (And I think this is the case,) it's not a 3D method, it is a planar method. (I remember Jim explaining this in another topic, some time ago.) It sort of like the "projections" of each BB are cast onto the 3 axis planes. If there is no "interference" between the cast rectangles, then we consider there not to be an intersect. It is weird and confusing, and two groups that do not even touch each other, can have "projections" that intersect.

              So anyway.. IF your groups ARE manifold solids... why not use Group.intersect instead ??

              I'm not here much anymore.

              1 Reply Last reply Reply Quote 0
              • L Offline
                liquid98
                last edited by 19 Mar 2012, 20:37

                Hi Dan,

                I think the Boundingbox.intersect method is not really suitable for testing whether geometry is intersecting..
                It is true that Boundingbox.intersect returns an empty boundingbox if there is no 'intersection'.
                So we can test for that, but it is not reliable..

                Furthermore the Group.intersect method is just a Boolean method, it is not intended for testing intersection of solids..

                I feel the loop class can clarify things..

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

                1 Reply Last reply Reply Quote 0
                • thomthomT Offline
                  thomthom
                  last edited by 20 Mar 2012, 09:18

                  @dan rathbun said:

                  If you are going to use for .. in, you must subtract 1 from the length of the array/set/collection.

                  He did, because he used ... instead of .. in the Range.

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

                  1 Reply Last reply Reply Quote 0
                  • L Offline
                    liquid98
                    last edited by 20 Mar 2012, 14:48

                    Is it smart at all to test for intersecting geometry before attempting a Boolean operation??

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

                    1 Reply Last reply Reply Quote 0
                    • D Offline
                      Dan Rathbun
                      last edited by 20 Mar 2012, 15:03

                      Are you wishing to run this in batch-mode ??

                      As in: Pick a folder of SKP files, and open them one after the other, union the intersecting groups, save the model under a "differed" filename, ... loop until all files in directory have been "converted" ??

                      I'm not here much anymore.

                      1 Reply Last reply Reply Quote 0
                      • L Offline
                        liquid98
                        last edited by 20 Mar 2012, 17:11

                        good guess! that's the plan indeed.

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

                        1 Reply Last reply Reply Quote 0
                        • D Offline
                          Dan Rathbun
                          last edited by 21 Mar 2012, 08:15

                          @liquid98 said:

                          good guess! that's the plan indeed.

                          I did not guess ... I can read your mind (scary music: [Oooo ooOOooo ooooo])

                          No actually, I read your sample code in the post of 17 MAR ... the first two lines you are opening a skp file, within the code.

                          In that post, you wrote:

                          @liquid98 said:

                          But the script I'm writing is for internal use.

                          Is this to be used within a commercial setting (for commercial work.) ??

                          I'm not here much anymore.

                          1 Reply Last reply Reply Quote 0
                          • 1 / 1
                          1 / 1
                          • First post
                            2/12
                            Last post
                          Buy SketchPlus
                          Buy SUbD
                          Buy WrapR
                          Buy eBook
                          Buy Modelur
                          Buy Vertex Tools
                          Buy SketchCuisine
                          Buy FormFonts

                          Advertisement