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 4.0k 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.
    • 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
                                        • A Offline
                                          ado130
                                          last edited by

                                          Yes, radius, depth and direction are arrays with the float numbers.
                                          In another part of code I only read txt file line by line and split it into this arrays.

                                          I've two arrays, in first array are "drills" (coordinates, depth, etc), that are whole on the face, and second array, where I don't know if the imaginary center of notch is on the face or not.
                                          So, function for drill works fine, but still I've problem with notches.

                                          The whole code has 460 lines, so .. if you want, I can send it via PM.

                                          Thanks for the advice of the name.

                                          In future πŸ˜„ if it will work, I wanna buy Pro version and do sth like client-server. This script will run on the server, and i.e. you like a client send points (These can be generated from the C# program) and send to server. He process them, sent back Sketchup model to the client and client can open it with Sketchup View.
                                          So I've one more question. Is this possible?, I think the part where Pro version can automaticaly open ruby script and save the model.

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

                                            In both SketchUp versions, all scripts automatically load from the Plugins folder as SketchUp starts.
                                            If their code includes some 'self-running' lines, then those will start a process you desire...
                                            For example, this happens with Observers etc - like my LayerWatcher toolset, which adds an observer to the model's layers, and also some extra functions to the context-menu etc...

                                            Also once some process has completed then you can use various API methods to save the model as a SKP [even with different version] or other exportable formats [more are available in Pro], you do not have to prompt for a file-name, although it is an option, your code can [re]set the file name so the original is not overwritten, even make a new sub-folder to take the file[s] etc...

                                            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