sketchucation logo sketchucation
    • Login
    ℹ️ Licensed Extensions | FredoBatch, ElevationProfile, FredoSketch, LayOps, MatSim and Pic2Shape will require license from Sept 1st More Info

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

    Scheduled Pinned Locked Moved Developers' Forum
    12 Posts 3 Posters 947 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.
    • Dan RathbunD Offline
      Dan Rathbun
      last edited by

      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
      • liquid98L Offline
        liquid98
        last edited by

        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
        • Dan RathbunD Offline
          Dan Rathbun
          last edited by

          @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
          • liquid98L Offline
            liquid98
            last edited by

            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
            • Dan RathbunD Offline
              Dan Rathbun
              last edited by

              @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
              • liquid98L Offline
                liquid98
                last edited by

                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

                  @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
                  • liquid98L Offline
                    liquid98
                    last edited by

                    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
                    • Dan RathbunD Offline
                      Dan Rathbun
                      last edited by

                      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
                      • liquid98L Offline
                        liquid98
                        last edited by

                        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
                        • Dan RathbunD Offline
                          Dan Rathbun
                          last edited by

                          @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
                          • First post
                            Last post
                          Buy SketchPlus
                          Buy SUbD
                          Buy WrapR
                          Buy eBook
                          Buy Modelur
                          Buy Vertex Tools
                          Buy SketchCuisine
                          Buy FormFonts

                          Advertisement