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

    Intersecting Hollow Objects using intersect_with

    Scheduled Pinned Locked Moved Developers' Forum
    12 Posts 3 Posters 714 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.
    • P Offline
      pmagans
      last edited by

      So I am attempting to use planes to cut a hollow object. I am having trouble with the weird conditions such as:
      Plane cutting a line in the object
      intersect.pngintersect2.png

      The array comparisons don't seem to work on faces and entities reliably? any thoughts?
      I did some Array math to help myself out but I think I'm confusing how Sketchup creates entities.

      array1 = [1,2,3,4,5]
      array2 = [1,3,5,6]
      
      array3 = array1 | array2
      array4 = array1 & array2
      array5 = array1 - array2
      array6 = array1 + array2
      array7 = array2 | array1
      array8 = array2 & array1
      array9 = array2 - array1
      array10 = array2 + array1
      array11 = (array1 | array2) - (array1 & array2)
      
      puts "array1 = " + array1.to_s
      puts "array2 = " +array2.to_s
      puts "UNION 1&2 = " +array3.to_s
      puts "INT 1&2 = " +array4.to_s
      puts "Diff 1-2 = " +array5.to_s
      puts "Add 1+2 = " +array6.to_s
      puts "UNION 2&1 = " +array7.to_s
      puts "INT 2&1 = " +array8.to_s
      puts "Diff 2-1 = " +array9.to_s
      puts "Add 2+1 = " +array10.to_s
      puts "UN 1-2 - int 1-2 = " +array11.to_s
      
      =begin
      ARRAY MATH EXAMPLE
      array1 = 12345
      array2 = 1356
      
      UNION 1&2 = 123456 same but order changed UNION 2&1 = 135624
      INT 1&2 = 135 and INT 2&1 are SAME!
      Diff 1-2 = 24
      Add 1+2 = 123451356 same but order changed Add 2+1 = 135612345
      
      
      Diff 2-1 = 6
      
      UN 1-2 - int 1-2 = 246
      =end
      
      module PMA_Intersect
      	require 'sketchup.rb'
      
      	mod = Sketchup.active_model
      	ents = mod.entities
      	
      	#Just test geometry
      	pt1 = [0,0,0]
      	pt2 = [10,0,0]
      	pt3 = [10,10,0]
      	pt4 = [0,10,0]
      
      	group = ents.add_group
      
      	face = group.entities.add_face pt1,pt2,pt3,pt4
      
      	off = 1
      	pt1_in = [0+off,0+off,0]
      	pt2_in = [10-off,0+off,0]
      	pt3_in = [10-off,10-off,0]
      	pt4_in = [0+off,10-off,0]
      	face2 = group.entities.add_face pt1_in,pt2_in,pt3_in,pt4_in
      	face2.erase! 
      	face.reverse!
      	face.pushpull 20
      	
      	#Creating Test Cutgroup
      	cut_group = ents.add_group
      	cut_group.entities.add_face pt1,pt2,pt3,pt4
      	t1 = Geom;;Transformation.translation [0,0,10]
      	t2 = Geom;;Transformation.scaling [5,5,0], 3
      	tr1 = Geom;;Transformation.rotation [0, 0, 16.5], [1, 0, 0], 10.degrees
      
      	cut_group.transform! t1 * t2 * tr1
      
      	cut_tran = cut_group.transformation
      	group_tran = group.transformation 
      
      
      #Entity to cut will be transformed based on the cutting cut_group
      #provided. Both entity and cut_group need to be a group passed
        original_faces = []
        original_edges = []
        group.entities.each do |e|
          original_faces << e if e.is_a? Sketchup;;Face
          original_edges << e if e.is_a? Sketchup;;Edge
        end
      
        cut_trans = cut_group.transformation
        entity_trans = group.transformation
        
        #entities.intersect_with recurse, trans1, entities1, trans2, hidden, entities2
        result = ents.add_group(cut_group.entities.intersect_with( true, cut_tran, group, group_tran , true, group))
      
      	cut_group.erase!
        result.erase!
      
        new_faces  = []
        group.entities.each do |e|
          new_faces << e if e.is_a? Sketchup;;Face
        end
      
      # Array Union and subtraction to find the unique faces
        unique_faces = []
        unique_faces = (original_faces | new_faces) - (original_faces & new_faces)
        
        face_selection = []
        new_faces.each do |e|
          unique_faces.each do |eo|
            if eo.vertices == e.vertices
              face_selection << e
            end
          end
        end
      
        face_selection.each do |e|
         e.erase!
        end
      
        left_faces  = []
        left_edges = []
        group.entities.each do |e|
          left_faces << e if e.is_a? Sketchup;;Face
          left_edges << e if e.is_a? Sketchup;;Edge
        end
       
        to_erase = []
        left_edges.each do |e|
          if e.faces[0] == nil
            e.erase!
             #to_erase << e
          end
        end
      
      end #of PMA_Intersect module 
      
      1 Reply Last reply Reply Quote 0
      • Dan RathbunD Offline
        Dan Rathbun
        last edited by

        SketchUp is not a solid modeler.. it's a surface modeler.

        So of course there will be no face where the plane cuts it.

        However, you might take advantage of the "left-over geometry". try moving the vertices in the left over face, up to those vertices (directly above them z-wise,) on the bottom of the hollow object.

        Or .. if it is easier, draw a new face on the bottom of the hollow object, insect it with the group. Find the inner face and delete it, leaving a new "ring face".

        I'm not here much anymore.

        1 Reply Last reply Reply Quote 0
        • TIGT Online
          TIG Moderator
          last edited by

          You are making it more complicated than it needs to be.
          Instead of slicing a plane through the object and producing some edges, and then having to do complicated checks to see what is to be erased and then what faces need creating on the cut plane etc.... why not use the 'solid' tools available to you in the API as a Pro users?
          Now you have an object_group [that is a 'solid'], and you want to 'chop' a piece off it - so you make another temp_group including the plane on the cut-line which is bigger than the object_group [as you are already doing for the intersect_with].
          Now offset that plane-face's 4 corners vertically down until they are all below the object_group.bounds.min.z.
          You now have a distorted 'box' in outline as temp_group.
          Add faces to its edges so it becomes another solid form with 6 faces in all.

          There are various methods available to Pro users that can cut/combine/trim 'solids'.
          In this case you'd want to use ' subtract'.
          Thus:
          result_group = object_group.subtract(temp_group)
          The result is a group that's still a 'solid' with faces added on the 'cut' plane etc...
          Note that the ' result_group' is a new group - the original ' object_group' and ' temp_group' no longer exist after the operation, so before doing the operation you will need to get references to the reference/name/layer/material/attribute_dictionaries [if any] for the ' object_group' and then reapply them to the new ' result_group'... Thus to the user it will look as if you have cut a piece off the original ' object_group' but actually the operation results in the destruction of the two solids used and the new solid that results has been reconfigured to match the original object in every way except it has modified geometry...

          See the API for 'group' and the various 'solid' tools it lists...

          TIG

          1 Reply Last reply Reply Quote 0
          • Dan RathbunD Offline
            Dan Rathbun
            last edited by

            That sounds better... I ruled out boolean tools because I knew a face cannot be made into a solid group.

            Wouldn't it be nice if SketchUp DID allow solid trimming with a face. We could specify the "trim direction" which is the direction to remove geometry. (In this case the -z direction.)

            I'm not here much anymore.

            1 Reply Last reply Reply Quote 0
            • P Offline
              pmagans
              last edited by

              Thanks TIG,
              I will definitely give that a go. I'll have to start up my work computer to give it a try though. I use the "free" version on a mac at home and the Pro windows version on my work laptop.

              Dan your thoughts are exactly where I wanted to go with being able to pick a direction for the cut. I envisioned a future user prompt to pick a side. I still think I could make it look like a plane being cut using TIG's described method by creating the geometry after the pick. But as a tool it would only be usable on a Pro machine it sounds.

              I thought using the array comparisons would be a quick check of the entities created, but actually it didn't work out well because it looks as though Sketchup "redraws" entities like lines and faces when the intersect_with happens even if it's basically the same location. That's why I started down the checking edges, then checking vertices, etc.

              1 Reply Last reply Reply Quote 0
              • TIGT Online
                TIG Moderator
                last edited by

                @dan rathbun said:

                That sounds better... I ruled out boolean tools because I knew a face cannot be made into a solid group.

                Wouldn't it be nice if SketchUp DID allow solid trimming with a face. We could specify the "trim direction" which is the direction to remove geometry. (In this case the -z direction.)
                Try this http://sketchucation.com/forums/viewtopic.php?p=433723#p433723

                TIG

                1 Reply Last reply Reply Quote 0
                • P Offline
                  pmagans
                  last edited by

                  Thanks for the plugins, TIG! Those are awesome starting points for me. I will need to modify them so that they work for any plane that is non-orthogonal to the orgin. But I think that's just a matter of creating a "plane" through code and not choosing it like the plugin. Thanks again!

                  intersect_with_plane.jpg

                  1 Reply Last reply Reply Quote 0
                  • TIGT Online
                    TIG Moderator
                    last edited by

                    My plugins do cut on any plane that is defined by any three non-co-linear points: these don't need to be orthogonal, drawing a temp-grouped face, WorkPlane or even some guidelines to snap onto will define the plane for you...
                    To hard-code it you simply need to define the three points used in @pts...
                    Because a face has a plane and you can project a point onto a plane it's relatively straightforward to use an existing face to derive the plane, and thereby the points - you just need to project any point onto the face.plane (to be @pts[0]) then offset that original point 1.0 in the X and re-project for @pts[1], then 1.0 in the Y and re-project for @pts[2]... You'll need 'a trap' to ensure that the face isn't in an orientation that gives coincident/co-linear points for some projections - for example a face with a normal parallel to the X_AXIS will make @pts[1]==@pts[0] when it projects back onto the plane !
                    A simple way is to convert the projected points into arrays [point.to_a] as you save them into @pts, and also to project more than you'll need - e.g. @pts[3] as Z 1.0, then doing a @pts.uniq! should leave you with at least three points that are on the plane and not co-linear or the same points... Use @pts[0..2] to be sure of a good set...

                    TIG

                    1 Reply Last reply Reply Quote 0
                    • P Offline
                      pmagans
                      last edited by

                      Thanks TIG. I am still working on this and will post my results.

                      On a side note:
                      I tried to create a function in the module I wrapped everything in and it won't load in Sketchup but works fine outside of the function block.
                      ex.

                      module PMA_INT_TEST
                       ..code here to create geometry
                      end #of module
                      

                      load PMA_INT_TEST.rb into Sketchup works fine

                      then I changed:

                      module PMA_INT_TEST
                      create_geometry()
                      
                      def create_geometry()
                       exact same..code here to create geometry
                      end
                      end #of module
                      

                      load PMA_INT_TEST.rb into Sketchup get:
                      Error: #<NoMethodError: undefined method `create_geometry' for PMA_INT_TEST:Module>

                      1 Reply Last reply Reply Quote 0
                      • Dan RathbunD Offline
                        Dan Rathbun
                        last edited by

                        • You have two issues.

                        (1) The obvious. As the interpreter reads the module definition (for the first time,) it encounters a call to a method that is not yet defined, so the module's private method method_missing() is called passing the unknown method name in as a symbol.

                        Your module has no local override of this error handler, so Ruby passes the call on up the inheritance chain, superclass by superclass. When it finds a root handler, the error is handled. In this case the default from class Module just raises a NoMethodError exception.

                        The exception's message is what you see, which should have also told you the error originated on line 2.
                        If not.. at the console you can get a reference to the last exception instance object, via the global $!, and it's backtrace via the global $@.

                        So the general rule, is to define all your static objects first, usually in this order: constants, class/module @@variables, nested class or module defintions, class methods / module functions (grouping private and public together,) instance methods (grouping private and public together,) and finally "Run Once" init code that runs the first time the module or class is loaded.

                        "Run Once" init code is usually within a conditional block, such as:
                        ` unless file_loaded?(File.basename(FILE))

                        add menu items only once in here

                        end # Run Once`

                        If you have code that always runs each time you reload the module, then put it at the very end.

                        Keep in mind that the Ruby keywords module and class mean "open for editing (and create first if needed.)"

                        (2) The not so obvious quirk of instance methods inside modules.

                        Instance methods inside modules are allowed for a specific purpose. And that is so the module can be used as a "mixin" library module, to include or extend other module or class definitions.

                        You are not creating a "mixin" module, but you would still like to have internal methods that can be called like instance methods with no parent qualification.

                        The answer is a trick called an anonymous singleton proxy class.
                        Proxy class objects are associated with a proxy object, are opened for definition with the syntax:
                        ` class << proxy_object

                        end`

                        In the case of a custom module instance, the proxy object association is to the module it self.

                        SO... within a module, define instance methods as you would inside a normal class definition, but instead put them inside a proxy class definition block (grouping private and public together.)

                        module PMA_INT_TEST
                        
                          require("sketchup.rb")
                        
                          # Constants here;
                          THISFILE = "#{self.name};#{File.basename(__FILE__)}"
                        
                          # Module Variables here
                        
                          class << self
                        
                            # instance variables here
                        
                            public
                        
                            def use_my_tool()
                              # call an internal method
                            end
                        
                            private
                        
                            def create_geometry()
                              # code here to create geometry
                            end
                        
                          end # proxy class
                        
                          # RUN ONCE
                          unless file_loaded?(THISFILE)
                            # create menus and menuitems,
                            # populate a toolbar, etc.
                            file_loaded(THISFILE) # adds to $loaded_files array
                          end
                        
                          # ALWAYS RUN WHEN LOADED CODE here
                        
                        end #of module
                        

                        The global methods file_loaded() and file_loaded?() are defined in "Tools/sketchup.rb" so that file must be require'd if you use them. (Do not specify the "Tools" dir as it is already one of the members of the [ruby:1ngdxd24]$LOAD_PATH[/ruby:1ngdxd24] array that is used by require.)

                        💭

                        I'm not here much anymore.

                        1 Reply Last reply Reply Quote 0
                        • P Offline
                          pmagans
                          last edited by

                          Well I've been using the "solid" tools for the last few days and it is a whole lot easier than what I was trying before. It would be nice to find a non-Pro version, for home use. The following is my test_code. I will re-write using Dan's previous post as a guide. It's a little over my head at this moment and I'm still trying to completly understand it.

                          module PMA_INT_TEST
                          	require('sketchup.rb')
                          	
                          	l = 1.50
                          	w = 1.50
                          	t = 0.078
                          	h = 20
                          
                          	model = Sketchup.active_model
                          	ents = model.entities
                          	
                          	#Just test geometry
                          	pt1 = [0,0,0]
                          	pt2 = [l,0,0]
                          	pt3 = [l,w,0]
                          	pt4 = [0,w,0]
                          	object_group = ents.add_group()
                          	object_group.name = "OBJECT GROUP"
                          	cpt = object_group.entities.add_cpoint(ORIGIN)
                          	face1 = object_group.entities.add_face pt1,pt2,pt3,pt4
                          	cpt.erase!
                          	pt1 = [0+t,0+t,0]
                          	pt2 = [l-t,0+t,0]
                          	pt3 = [l-t,w-t,0]
                          	pt4 = [0+t,w-t,0]
                          	face2 = object_group.entities.add_face pt1,pt2,pt3,pt4
                          	face2.erase! 
                          	face1.reverse!
                          	face1.pushpull h
                          	
                          	#Creating Test Cutgroup1
                          	cut_group1 = ents.add_group()
                          	cpt = cut_group1.entities.add_cpoint(ORIGIN)
                          
                          	pt1 = [0,0,0]
                          	pt2 = [l,0,0]
                          	pt3 = [l,w,0]
                          	pt4 = [0,w,0]
                          	face3 = cut_group1.entities.add_face pt1,pt2,pt3,pt4
                          	face3.reverse!
                          	face3.pushpull h
                          	t1 = Geom;;Transformation.translation [0,0,10]
                          	ts1 = Geom;;Transformation.scaling [l/2,w/2,0], 10
                          	tr1 = Geom;;Transformation.rotation [0, 0, 0], [1, 0, 0], 10.degrees
                          	cut_group1.transform! tr1 * t1 * ts1  
                          	cut_group1.name = "CUT GROUP1"
                          	cpt.erase!
                          	
                          	#Creating Test Cutgroup2
                          	cut_group2 = ents.add_group()
                          	cpt = cut_group2.entities.add_cpoint(ORIGIN)
                          
                          	pt1 = [0,0,0]
                          	pt2 = [l,0,0]
                          	pt3 = [l,w,0]
                          	pt4 = [0,w,0]
                          	face4 = cut_group2.entities.add_face pt1,pt2,pt3,pt4
                          	face4.pushpull h
                          	t2 = Geom;;Transformation.translation [0,0,1]
                          	tr2 = Geom;;Transformation.rotation [0, 0, 0], [1, 0, 0], -10.degrees
                          	cut_group2.transform! tr2 * t2 * ts1  
                          	cut_group2.name = "CUT GROUP2"
                          	cpt.erase!
                          	
                          	#Create "NEW" group from cut group and from object group
                          	UI.messagebox("CUTTING")
                          	
                          	cut_group = cut_group1.subtract(object_group)
                          	cut_group = cut_group2.subtract(cut_group)
                          	cut_group.name = "NEW NAME"
                          
                          end #of module PMA_INT_TEST
                          
                          1 Reply Last reply Reply Quote 0
                          • TIGT Online
                            TIG Moderator
                            last edited by

                            There's BoolTools http://www.Smustard.com, for just $10...
                            There's also Oscarlok's Boolean ODCoolean toolset, in the Plugins Index, which is free... http://sketchucation.com/forums/viewtopic.php?p=112055#p112055
                            These both replicate several of the solid tools in Free that are available only in Pro...

                            TIG

                            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