• Login
sketchucation logo sketchucation
  • Login
πŸ€‘ SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

How to cut from object

Scheduled Pinned Locked Moved Developers' Forum
47 Posts 4 Posters 3.9k Views 4 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.
  • A Offline
    ado130
    last edited by ado130 13 Sept 2016, 20:11

    Hi, I'm new in Ruby and sketch, so I learnt to do a couple of simple objects (blocks, cylinders), then I tried do a drill - it works, but I do not know how do a cut.
    I can do a hole - drill if the center is in the object, but I have no idea, how do a cut, when the center is out of the object. I know just x y z position, radius and depth of the drill.

    Thanks for any help.

    1 Reply Last reply Reply Quote 0
    • T Offline
      TIG Moderator
      last edited by 13 Sept 2016, 21:22

      Because you say you only have Make, then you do not have access to the Pro tools in SketchUp - like 'Solid Tools' and their equivalents in the Ruby API...

      But you can still do it, but it is more involved...

      Intersect the forms and use the API's pushpull to make the 'hole' or 'notch', this works if the two opposing faces you are 'punching' are parallel.
      If they are not, then it is even more convoluted, but still not impossible...

      TIG

      1 Reply Last reply Reply Quote 0
      • D Offline
        Dan Rathbun
        last edited by 14 Sept 2016, 02:38

        Topics should not be prefixed with "[code]" unless the post is a code snippet or example.

        I'm not here much anymore.

        1 Reply Last reply Reply Quote 0
        • A Offline
          ado130
          last edited by 14 Sept 2016, 16:08

          Ou, sorry about that.
          Tig, you are right, now I'm using Sketchup 2016, just a trial version, but soon I'll use Sketchup 8, is it still possible?
          For better imagination, for Ex. I've this

          http://i.imgur.com/G46UlIJ.png

          and I need sth like this

          http://i.imgur.com/hafBjP7.png

          of course without edges.
          So, now I have a object and position(center) of "imagination" drill - there's no face, but the drill will do "notch".
          Can you help me?
          Maybe write a example code or a little tutorial how to do it and I'll try it myself.

          Thanks very much.

          .. sorry for my english

          Edit: I just installed SU8 and I'm not sure, but is it possible there? It looks very different, not so much in design but in functions that I can use.

          1 Reply Last reply Reply Quote 0
          • T Offline
            TIG Moderator
            last edited by 15 Sept 2016, 10:57

            Learn this http://ruby.sketchup.com/
            πŸ˜‰
            Let's assume you understand how entities-context separates geometry.
            Let's assume that the rectangular block form is inside a group's entities.
            In Pro you'd make another temporary group containing the cylinder, position it, and subtract that from the block, making a new group in the process, that has the notch cut out.

            In Make, to subtract geometry to make the notch, consider this...
            Add a temporary cylinder group inside the block group's entities.
            Adding the group, then adding a circle into it, and then adding a face to that.
            You save the normal of the circular face for later.
            Now pushpull the circular face along a single line - with its length set as the width of the block, to make the 3d cylinder.
            Make a collection of the faces in the block group and use entities intersect_with(...), using the cylinder group as the 'cutter'.
            It should have 'cut' the form of the notch into the block's faces [return as the result of the operation]
            Now you can erase the cylinder group.
            You can see the cuts.
            From the returned new faces one will have the same normal as the cylinder's initial circular face, i.e. the first of the two half-moon faces.
            Use pushpull on that to subtract the notch from the block's geometry...

            If you want to subtract random sized objects from each other, then its more involved.
            Consider doing the intersect_with twice, once putting the new geometry into the block and next into the cylinder.

            When testing it do it in steps so you can see what is getting done at each one...

            TIG

            1 Reply Last reply Reply Quote 0
            • A Offline
              ado130
              last edited by 15 Sept 2016, 14:23

              About groups, I'm not sure, if I'm doing it right.
              Rectangel blocks:

              
              group = Sketchup.active_model.entities.add_group 
              entities = group.entities
              ptA = [x[0+i*8], y[0+i*8], z[0+i*8]].map(&;to_f)
              ...
              entities.add_line(ptA, ptB)
              ...
              bottom = entities.add_face(ptA, ptB, ptC, ptD)
              ...
              bottom.material = blockMaterial[i]
              ...
              bottom.back_material = blockMaterial[i]
              ...
              
              

              Similarly cylinders (just using entities.add_circle).
              Is it a right way?

              Now for make a drill (not a notch), I need to find a face, so I'm trying sth like this

              	model = Sketchup.active_model 
              	entities = model.entities
              
              	face = nil
              	entities.grep( Sketchup;;Group ).each{|e|
              	  puts "Group #{e.name.empty? ? e.definition.name.inspect ; e.name.inspect};"
              	  faces = e.definition.entities.grep( Sketchup;;Face )
              	  if faces.empty?
              		puts "  +-- No faces in group!"
              	  else
              		for f in faces
              		  if f.classify_point(center) == Sketchup;;Face;;PointInside then
              		   face = f
              		  end
              		end
              	  end
              	}
              

              It works - it finds right face, but after, when I execute code from here http://sketchucation.com/forums/viewtopic.php?t=19556, the result is, that the block disappear and stay just a circle edge.

              When I add group.explode at the end of block for making rectangles and cylinders works fine this:

              	entities.each { |entity| 								# Get all entities
              		if entity.typename == "Face" then					# Get all faces from entities
              			result = entity.classify_point(center)
              			if result == Sketchup;;Face;;PointInside then	# Get our face 
              				face = entity
              			end		
              		end
              	}
              

              If I think properly, gourp.explore deletes that group, but I need it for use in intersect_with.
              So, is this process right: delete that group via group.explode (for making drills) and before making notch, create new group of block and temporary cylinder?

              I learn from this https://www.sketchup.com/intl/en/developer/docs/ and forum.

              Thanks

              Edit:

              	baseGroup = nil
              	Sketchup.active_model.entities.each{|g|
              		next unless g.is_a?(Sketchup;;Group)
              		g.entities.each{|f|
              			next unless f.is_a?(Sketchup;;Face)
              			next if f.classify_point(notchPoint) == Sketchup;;Face;;PointInside	
              			baseGroup = g
              		}	
              	}	
              	
                      baseTrans = baseGroup.transformation
              	
                      cutGroup=entities.add_group
                      cutGroupEntities=cutGroup.entities	
              	dir = Geom;;Vector3d.new(-1,0,0)
              	cutCircle = cutGroupEntities.add_circle(notchPoint, dir, cylinderRadius[0])
              	cutFace   = cutGroupEntities.add_face cutCircle 
              	cutNormal = cutFace.normal
              	cutFace.reverse!
              	cutFace.pushpull cylinderHeight[0]	
              	cutTrans = cutGroup.transformation	
              	
              	cutGroupEntities.intersect_with(false, cutTrans, baseGroup, baseTrans , true, baseGroup)
              
              	cutGroup.explode
              

              In baseGroup variable I need to find a group where I'll do a notch - and yeah, it does not work at well (now I have just 1 block, so just 1 group, but later I'll have a lot of blocks/groups).
              Then I do a temporary cylinders and trying execute intersect_with, but I'm not sure if is it correct. Can you help me?

              Thanks a lot.

              1 Reply Last reply Reply Quote 0
              • A Offline
                ado130
                last edited by 26 Sept 2016, 13:08

                TIG, please, can you help me with that.

                1 Reply Last reply Reply Quote 0
                • T Offline
                  TIG Moderator
                  last edited by 26 Sept 2016, 13:47

                  Let's step back.
                  Let's agree what is is you want to do...
                  In words, not code...
                  I think it's this...

                  You want to add a cylindrical hole into grouped block.
                  Let us assume the radius and depth are fixed - once you have something working you can always add an inputbox to get parameters...

                  Let's assume you have a rectangular block already made and it's a group.
                  Let's also assume that the hole you want to add to this is centered on its top and then passes right through the block.

                  So it's relatively straightforward...

                  model = Sketchup.active_model
                  group = model.selection.grep(Sketchup;;Group)[0] ### first group in selection
                  gents = group.entities
                  bb = group.bounds
                  ct = bb.center
                  max = bb.max
                  ctop = ct.clone.transform!(group.transformation.inverse)
                  ctop.z = max.z ### move onto top
                  dist = bb.depth ### full depth
                  rad = 10.0
                  seg = 12
                  edges = gents.add_circle(ctop, Z_AXIS, rad, seg) ### note axis
                  fac = nil
                  edges[0].faces.each{|f|fac = f unless f.loops[1]}
                  fac.pushpull(-dist)
                  

                  Now all you have to do is extend this to your real needs ?

                  TIG

                  1 Reply Last reply Reply Quote 0
                  • A Offline
                    ado130
                    last edited by 27 Sept 2016, 18:26

                    Thanks for a reply.
                    Yes, I have all rectangular blocks grouped, radius and depth are fixed (from a txt file).
                    I'm not sure, but that code do a drill in center of some rectangular block, but what I need to do is make a notch (like in pic in my prev post) - the center position of this imaginary cylinder may not be on that block.
                    Do you know what I mean?

                    1 Reply Last reply Reply Quote 0
                    • T Offline
                      TIG Moderator
                      last edited by 27 Sept 2016, 18:49

                      OK.
                      I only gave the example to show that is a relatively few lines of code you can drill a hole.
                      I centered it on the top because that was easy to do.
                      If you want it elsewhere you need to decide how the point is decided upon.
                      You need to implement a Tool class to allow you to to actually capture a picked point...
                      Perhaps do that a separate process to see how it works, then combine it with your 'driller'.
                      I punched it through the block as it was easy to do.
                      However, you could ask the user with an inputbox for both depth [and radius/diam].
                      Then instead of using the block's size to determine the through punch use the entered depth instead...

                      TIG

                      1 Reply Last reply Reply Quote 0
                      • A Offline
                        ado130
                        last edited by 27 Sept 2016, 19:34

                        I rewrote your code to do a drill and it looks fine (works πŸ˜„ )

                        def drill(x, y, z, radius, depth, direction)
                        	countOfDrills = x.length.to_i
                        	countOfDrills.times do |i|
                        		model = Sketchup.active_model 
                        		entities = model.entities
                        
                        		case direction[i]
                        			when "N"
                        				dir = Geom;;Vector3d.new(0,0,1)
                        			when "E"
                        				dir = Geom;;Vector3d.new(-1,0,0)
                        			when "S"
                        				dir = Geom;;Vector3d.new(0,0,-1)
                        			when "W"
                        				dir = Geom;;Vector3d.new(1,0,0)		
                        			when "F"
                        				dir = Geom;;Vector3d.new(0,-1,0)	
                        			when "B"
                        				dir = Geom;;Vector3d.new(0,1,0)				
                        			else
                        				dir = Geom;;Vector3d.new(0,0,1)		
                        		end		
                        		
                        		center = [x[i], y[i], z[i]].map(&;to_f)
                        		group = nil
                        		face = nil
                        		Sketchup.active_model.entities.each{|g|
                        			next unless g.is_a?(Sketchup;;Group)
                        			g.entities.each{|f|
                        				next unless f.is_a?(Sketchup;;Face)
                        				if f.classify_point(center) == Sketchup;;Face;;PointInside then
                        					group = g
                        					face = f
                        				end
                        			}	
                        		}
                        		
                        		gents = group.entities	
                        		edges = gents.add_circle(center, dir, radius[i]) ### note axis
                        		fac = nil
                        		edges[0].faces.each{|f|fac = f unless f.loops[1]}	
                        		normal = face.normal
                        		other_entities = face.all_connected
                        		reversed_normal = normal.reverse
                        		
                        		circleface = nil
                        
                        		for other in other_entities
                        			if other.typename == "Face" and other.classify_point(center) == Sketchup;;Face;;PointInside then
                        				circleface = other
                        			end
                        		end		
                        		for other in other_entities
                        			if other.valid? and other.typename=="Face" then
                        				if reversed_normal.samedirection? other.normal then
                        					point_on_other_face = center.project_to_plane other.plane
                        					if other.classify_point(point_on_other_face) == Sketchup;;Face;;PointInside then
                        						dist = point_on_other_face.vector_to(center).length
                        					end
                        				end
                        			end
                        		end
                        		if depth[i] != 0 then
                        			dist = depth[i]
                        		end			
                        	
                        		fac.pushpull(-dist)
                        
                        	end
                        	
                        	return
                        end
                        

                        But still, I'm not sure how to do a notch.
                        I can't add a inputbox for user, because all of my input data are from txt file - there I have x y z positions of imaginary center then radius, depth and if I need to know direction also.

                        1 Reply Last reply Reply Quote 0
                        • T Offline
                          TIG Moderator
                          last edited by 27 Sept 2016, 20:01

                          Some ideas...

                          Before you do anything, get a collection of all of the existing [active] edges.
                          active_edges = model.active_entities.grep(Sketchup::Edge)
                          We need that later...
                          If the punching-face is not wholly on the top surface then some of new edges will not intersect or only partially intersect with the 'block'.
                          So add the circle [say], then check its edges for their faces and save the first with edge.faces[0] for later...
                          Before doing anything else...
                          new_edges = model.active_entities.grep(Sketchup::Edge) - active_edges
                          Then delete those in new_edges which have no faces, using...
                          ! edge.faces[0]
                          Finally pushpull the new face by the desired depth...
                          ??

                          TIG

                          1 Reply Last reply Reply Quote 0
                          • A Offline
                            ado130
                            last edited by 29 Sept 2016, 13:33

                            	active_edges = model.active_entities.grep(Sketchup;;Edge)
                            	group = Sketchup.active_model.active_entities.add_group()
                            	gents = group.entities
                            	edges = gents.add_circle(center, dir, notchRadius[0]) 
                            	first = edges[0].faces[0]
                            	new_edges = model.active_entities.grep(Sketchup;;Edge) - active_edges	
                            

                            Now, should I delete those in new_edges which have no faces, but I'm not sure, how to find them. And you said, thath I need to check its edges for their faces , what do you mean there?

                            Thanks

                            1 Reply Last reply Reply Quote 0
                            • T Offline
                              TIG Moderator
                              last edited by 29 Sept 2016, 14:30

                              After making the array of edges before you start [active_edges]...
                              Then after adding your new edges etc...
                              new_edges = model.active_entities.grep(Sketchup::Edge) - active_edges new_edges.each{|edge| edge.erase! unless edge.faces[0] }

                              There is a more efficient way, collecting then deleting them at the end but since you'll only have a few to erase it's probably not worth it...
                              But FYI here it is...
                              new_edges = model.active_entities.grep(Sketchup::Edge) - active_edges togos = [] ### empty array new_edges.each{|edge| togos << edge unless edge.faces[0] } model.active_entities.erase_entities(togos) if togos[0]

                              TIG

                              1 Reply Last reply Reply Quote 0
                              • A Offline
                                ado130
                                last edited by 29 Sept 2016, 19:48

                                So, is this correct? Now just pushpull the new face (which?) and it should be done.

                                		active_edges = model.active_entities.grep(Sketchup;;Edge)
                                		group = Sketchup.active_model.active_entities.add_group()
                                		gents = group.entities
                                		edges = gents.add_circle(center, dir, radius[i])
                                		first = edges[0].faces[0]
                                		puts first
                                		new_edges = model.active_entities.grep(Sketchup;;Edge) - active_edges
                                		togos = [] ### empty array
                                		new_edges.each{|edge| togos << edge unless edge.faces[0] }
                                		model.active_entities.erase_entities(togos) if togos[0]
                                
                                1 Reply Last reply Reply Quote 0
                                • T Offline
                                  TIG Moderator
                                  last edited by 29 Sept 2016, 20:23

                                  You are a "bit over your head"...
                                  As you don't seem to understand what you are trying to do at each step...

                                  All the code we have been talking about recently is to erase the unwanted edges if the new circle is not wholly within the targeted face.

                                  Earlier code - which already worked - will find the face associated with any new edges which you just added and which have a face... and then you just do a pushpull on that that...
                                  πŸ˜•

                                  TIG

                                  1 Reply Last reply Reply Quote 0
                                  • A Offline
                                    ado130
                                    last edited by 30 Sept 2016, 08:00

                                    Yeah, you're right, I don't get it completely.

                                    1. save now active edges
                                      active_edges = model.active_entities.grep(Sketchup::Edge)

                                    2. make a new group and add there circle
                                      group = Sketchup.active_model.active_entities.add_group() gents = group.entities edges = gents.add_circle(center, dir, radius[i])

                                    3. select edges, which makes this circle
                                      new_edges = model.active_entities.grep(Sketchup::Edge) - active_edges

                                    4. erase the unwanted edges
                                      togos = [] ### empty array new_edges.each{|edge| togos << edge unless edge.faces[0] } model.active_entities.erase_entities(togos) if togos[0]

                                    5. now last step, that you said; find the face associated with any new edges which I just added and which have a face
                                      fac = nil new_edges.faces.each{|f|fac = f unless f.loops[1]} fac.pushpull(-10)

                                    Is it correct now? I'd like to learn it (understand it), not only copy and paste the code.

                                    1 Reply Last reply Reply Quote 0
                                    • T Offline
                                      TIG Moderator
                                      last edited by 30 Sept 2016, 11:48

                                      We are adding the circle onto an existing face [you never showed that step or set up the values for the circle itself ??]

                                      You don't need to add the edges to a new group.
                                      raw it directly over the face in the active_entities.
                                      edges = Sketchup.active_model.active_entities.add_circle(center, dir, radius, segs)
                                      Where center is a point on the face [or the plane of the face],
                                      dir is the face.normal, radius is the circle's radius [NOT an array it's a dimension], and segs is the number of sides the circle will have.

                                      When you draw the circle's edges there are three possible outcomes...
                                      a) The circle intersects fully with the face and then all of those edges have two faces - so there's nothing to tidy up - next you can find/use the new face supported by one of the circle's edges and pushpull it to form the hole or notch [i.e. no face.loops[1]].
                                      b) The circle misses the face completely, so all of its edges are faceless, so they all need deleting and the code exits.
                                      c) The circle straddles the edge of the face. Now some edges are faceless and need deleting. At least one other circle's edge will support two faces and one of them is new - again this can be used for the pushpull...

                                      The use of the togos array to remove any faceless edges is OK.
                                      The finding the face fac and pushpulling it is OK.

                                      Unfortunately since your code added the circle into a group no new edges are found in the active_entities. So nothing to find with a face etc, so nothing to pushpull.


                                      I suggest you first get it working in the active_context, then learn how to do it ALL inside a group.entities context to separate the geometry from the rest of the model and make finding new stuff easier...

                                      TIG

                                      1 Reply Last reply Reply Quote 0
                                      • A Offline
                                        ado130
                                        last edited by 1 Oct 2016, 11:27

                                        I know, that the circle's radius is not an array, but that's not a whole code.

                                        def notch(x, y, z, radius, depth, direction)
                                        	countOfNotch = x.length.to_i
                                        	countOfNotch.times do |i|
                                        		model = Sketchup.active_model 
                                        		center = [x[i], y[i], z[i]].map(&;to_f)				
                                        		case direction[i]
                                        			when "N"
                                        				dir = Geom;;Vector3d.new(0,0,1)
                                        			when "E"
                                        				dir = Geom;;Vector3d.new(-1,0,0)
                                        			when "S"
                                        				dir = Geom;;Vector3d.new(0,0,-1)
                                        			when "W"
                                        				dir = Geom;;Vector3d.new(1,0,0)		
                                        			when "F"
                                        				dir = Geom;;Vector3d.new(0,-1,0)	
                                        			when "B"
                                        				dir = Geom;;Vector3d.new(0,1,0)				
                                        			else
                                        				dir = Geom;;Vector3d.new(0,0,1)		
                                        		end		
                                        		
                                        		active_edges = model.active_entities.grep(Sketchup;;Edge)					
                                        		edges = Sketchup.active_model.active_entities.add_circle(center, dir, radius[i])
                                        		new_edges = model.active_entities.grep(Sketchup;;Edge) - active_edges
                                        		togos = [] ### empty array
                                        		new_edges.each{|edge| togos << edge unless edge.faces[0] }
                                        		model.active_entities.erase_entities(togos) if togos[0]
                                        		fac = nil
                                        		new_edges.faces.each{|f|fac = f unless f.loops[1]}
                                        		fac.pushpull(-depth)
                                        	end
                                        end
                                        

                                        Is it necessary set the seg?, I think there is a default value.
                                        So I add circle into active_entities.

                                        For point a) I've a separate code (the above code) - make drill; I use it, when I know, that the drill (circle) intersects fully with the face (i.e. block).

                                        1 Reply Last reply Reply Quote 0
                                        • T Offline
                                          TIG Moderator
                                          last edited by 1 Oct 2016, 12:35

                                          You are right in that the 'segments' in add_circle will default to 24 if you do not pass a final argument, but you might well want to make the circle less segmented if it's very small or more segmented if it's very large - it depends on what you are to do with it next...
                                          If it's in 3d-printing look up 'versine' as the segment's length should never be 1/1000" or less, and of course this depends on the radius and number of segments...

                                          A circle's radius is a dimension, but your code method seems to receive an argument, which you name radius but you then treat it as an array, to take radius[i] with i derived from the notch counter...
                                          So it is an array ?
                                          If so, then I think it'd be clearer for anyone reading it [including yourself] to call it say radii, rads or radiuses and then set rad = rads[i] before using it...
                                          Also your direction sees to be an array too !

                                          Without seeing all of your related code it is all but impossible to deduce what you are doing at each step.

                                          Common practice is to name a 'collection' - like an array - plural and then take an element in it named in the singular...
                                          rads >>> rad
                                          dirs >>> dir
                                          pts >>> pt
                                          edges >>> edge
                                          faces >>> face
                                          etc

                                          Another minor thing...
                                          model = Sketchup.active_model can be set at the start of the method, resetting it at each iteration will slow its processing up slightly.

                                          If you have other code checking that the drilled hole is wholly on the face so there is no 'part-circle' side holes, then the new edge collection and unfaced edge deletion is superfluous, since every edge of the circle is faced... try ### out parts to see what's not needed...

                                          TIG

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

                                          Advertisement