• Login
sketchucation logo sketchucation
  • Login
🤑 SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

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 5 Oct 2012, 21:30

    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 6 Oct 2012, 09:23

      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 Offline
        TIG Moderator
        last edited by 6 Oct 2012, 09:48

        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 6 Oct 2012, 11:31

          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 6 Oct 2012, 14:36

            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 Offline
              TIG Moderator
              last edited by 7 Oct 2012, 15:31

              @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 8 Oct 2012, 13:54

                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 Offline
                  TIG Moderator
                  last edited by 8 Oct 2012, 14:17

                  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 9 Oct 2012, 16:07

                    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 9 Oct 2012, 18:17

                      • 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 11 Oct 2012, 13:20

                        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 Offline
                          TIG Moderator
                          last edited by 11 Oct 2012, 18:31

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

                          Advertisement