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

    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

      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
      • TIGT Offline
        TIG Moderator
        last edited by

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

          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

            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
            • TIGT Offline
              TIG Moderator
              last edited by

              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

                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

                  TIG, please, can you help me with that.

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

                    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

                      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
                      • TIGT Offline
                        TIG Moderator
                        last edited by

                        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

                          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
                          • TIGT Offline
                            TIG Moderator
                            last edited by

                            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

                              	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
                              • TIGT Offline
                                TIG Moderator
                                last edited by

                                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

                                  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
                                  • TIGT Offline
                                    TIG Moderator
                                    last edited by

                                    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

                                      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
                                      • TIGT Offline
                                        TIG Moderator
                                        last edited by

                                        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

                                          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
                                          • TIGT Offline
                                            TIG Moderator
                                            last edited by

                                            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