Trimming a Solid Group
-
My next problem to solve is how to delete all of the entities (edges, faces) that are on one side or the other side of a plane. I can easily enough collect all of the entities in a (solid) group but I'm not seeing a way to select only the entities of a group that are on side of the bisecting plane.
-
@medeek said:
My next problem to solve is how to delete all of the entities (edges, faces) that are on one side or the other side of a plane. I can easily enough collect all of the entities in a (solid) group but I'm not seeing a way to select only the entities of a group that are on side of the bisecting plane.
This trims all edges on the backside of the face
mod = Sketchup.active_model ent = mod.active_entities fac = ent.grep(Sketchup;;Face)[0] grp = ent.grep(Sketchup;;Group)[0] ge = grp.entities; gt = grp.transformation ge.intersect_with(true,gt,ge,gt,false,fac) vts = ge.grep(Sketchup;;Edge).map{|e|e.vertices}.flatten.uniq nrm = fac.normal; pln = fac.plane; remove = [] vts.each{|v| vp=v.position.transform(gt) next if vp.on_plane?(pln) next if vp.project_to_plane(pln).vector_to(vp).samedirection?(nrm) remove << v.edges } remove.flatten!.uniq!.reverse! ent.erase_entities(remove)
-
Started working on this problem in earnest tonight. I've got the tool selecting the plane and then selecting the correct entity if it is a solid group or component. It then finds all of the edges (lines) that intersect this cutting plane and stores them in an array. However this is not quite good enough I need to determine if the intersection point of the line (edge) and plane actually falls on the edge itself (between the two vertices that make up the edge). If it does not then the plane does not cut through the edge and I can safely ignore it. I appreciate everyone's help thus far.
-
@medeek said:
Started working on this problem in earnest tonight. I've got the tool selecting the plane and then selecting the correct entity if it is a solid group or component. It then finds all of the edges (lines) that intersect this cutting plane and stores them in an array. However this is not quite good enough I need to determine if the intersection point of the line (edge) and plane actually falls on the edge itself (between the two vertices that make up the edge). If it does not then the plane does not cut through the edge and I can safely ignore it. I appreciate everyone's help thus far.
Compute the intersection point of the edge and the plane then test to verify the the point lies on the edge and the face.
mod = Sketchup.active_model ent = mod.active_entities sel = mod.selection vue = mod.active_view edg = sel.grep(Sketchup;;Edge)[0] fac = sel.grep(Sketchup;;Face)[0] ip = Geom.intersect_line_plane(edg.line,fac.plane) if edg.bounds.contains?(ip)&&[1,2,4].include?(fac.classify_point(ip)) puts 'Trim this edge' end
-
Your first block of code has me intrigued. I've been testing the intersect method which I did not know existed. It definitely has some potential. I am having a couple problems with it though.
1.) The intersecting member may not intersect with the face itself but intersects with the plane defined by the face. How do I specify the plane and not the face with this function (intersect_with).
2.) Most of the time the group (solid) that I am intersecting with the plane is nested within another component and then that component is inside of another group. Testing my script with an un-nested group works fine but if its nested it does not work. There is probably a simple work around for this, just need to figure it out.
-
Here is the current tool in its entirety. At this point it kind of works. I've got some debugging code embedded in the mix so don't let that confuse you:
module TrimTools # -------- MINOR ROOF POSITIONING TOOL ------------------------------------------------ # Positions the minor roof assembly. This tool allows the user # to place the assembly using the mouse to select two # corners of the structure. Choose the following corners in order; # left front # right front # # Note that the corners should be the corners of the bearing walls not the corners # of the roof at the overhangs. class PlaneSelectionTool include Math # these are the states that a tool can be in STATE_EDIT = 0 if not defined? STATE_EDIT STATE_PICK = 1 if not defined? STATE_PICK STATE_PICK_NEXT = 2 if not defined? STATE_PICK_NEXT STATE_PICK_LAST = 3 if not defined? STATE_PICK_LAST STATE_MOVING = 4 if not defined? STATE_MOVING STATE_SELECT = 5 if not defined? STATE_SELECT def initialize(licensemode) @Licensemode = licensemode @tool_name = "TRIM TOOL" @type = "trim tool" end def reset @pts = [] @state = STATE_PICK # This sets the label for the VCB Sketchup;;set_status_text "MEDEEK TOOLS", SB_VCB_LABEL Sketchup;;set_status_text "[#{@tool_name}] Click Trimming Plane" @drawn = false end def activate @ip1 = Sketchup;;InputPoint.new @ip = Sketchup;;InputPoint.new self.reset end def deactivate(view) view.invalidate if @drawn @ip1 = nil end def get_member(x, y, view) model = Sketchup.active_model view = model.active_view entities = model.active_entities ph2 = view.pick_helper ph2.do_pick(x, y) # Iterate all pick-routes; ph2.count.times { |pick_path_index| @Pickdepth2 = ph2.depth_at(pick_path_index) @Pickpath2 = ph2.path_at(pick_path_index) @TRroof2 = ph2.transformation_at(pick_path_index) } @pickcount2 = ph2.count best_entity = ph2.best_picked # puts "Plane Trans; #{@TRroof2} Pick Depth; #{@Pickdepth2} Pick Path; #{@Pickpath2}" # puts "Pick Count; #{@pickcount2} Best Entity; #{best_entity}" if @Pickpath2.nil? # Do nothing else pathsize2 = @Pickpath2.size - 1 for step in 0..pathsize2 entityi = @Pickpath2[step] typei = entityi.typename if (typei == "ComponentInstance") || (typei == "Group") definitioni = entityi.definition namei = definitioni.name manifoldi = entityi.manifold? # puts "#{step} #{entityi} Type; #{typei} Name; #{namei} Definition; #{definitioni} Manifold; #{manifoldi}" if manifoldi # Selects Group or Component Instance that is a solid p0x = @pts[0].x.to_f p0y = @pts[0].y.to_f p0z = @pts[0].z.to_f p1x = @pts[1].x.to_f p1y = @pts[1].y.to_f p1z = @pts[1].z.to_f puts "P0; #{p0x} #{p0y} #{p0z} P1; #{p1x} #{p1y} #{p1z}" @group_entities = entityi.entities @group_trans = entityi.transformation # puts @group_entities @Intersectpoints = [] @Intersectpoints2 = [] @Newfacepoints = [] @Newfacepoints2 = [] @Interents = [] counter0 = 0 counter1 = 0 # Checks each entity (edge) in group to see if it intersects with trimming plane @group_entities.each do |ent| if ent.typename == "Edge" line = ent.line intersect_point = Geom.intersect_line_plane(line, @trim_plane) if intersect_point # puts "Intersect point detected at #{intersect_point}" @Intersectpoints[counter0] = intersect_point @Intersectpoints2[counter0] = intersect_point.transform @TRroof2 counter0 = counter0 + 1 # Checks that intersection point is within bounds of edge usedbyedge = ent.bounds.contains?(intersect_point) if usedbyedge @Newfacepoints[counter1] = intersect_point @Interents[counter1] = ent @Newfacepoints2[counter1] = intersect_point.transform @TRroof2 counter1 = counter1 + 1 end end end end # puts @Newfacepoints # puts @Interents if @Newfacepoints.empty? UI.messagebox ("Member does not intersect trimming plane, click OK to proceed.") Sketchup.active_model.select_tool(nil) else # new_face1 = @group_entities.add_face @Newfacepoints # @group_entities.intersect_with(true, @group_trans, @group_entities, @group_trans, false, @member_face) @group_entities.intersect_with(true, @TRroof2, @group_entities, @TRroof2, false, @member_face) # Remove edges on other side of plane vts = @group_entities.grep(Sketchup;;Edge).map{|e|e.vertices}.flatten.uniq nrm = @member_face.normal pln = @member_face.plane remove = [] vts.each{|v| # vp= v.position.transform(@group_trans) vp= v.position.transform(@TRroof2) next if vp.on_plane?(pln) next if vp.project_to_plane(pln).vector_to(vp).samedirection?(nrm) remove << v.edges } remove.flatten!.uniq!.reverse! entities.erase_entities(remove) end break end else definitioni = "Not Defined" namei = "Not Defined" manifoldi = "Not Defined" # puts "#{step} #{entityi} Type; #{typei} Name; #{namei} Definition; #{definitioni} Manifold; #{manifoldi}" end end end end def get_plane(x, y, view) model = Sketchup.active_model view = model.active_view ph = view.pick_helper ph.do_pick(x, y) # Iterate all pick-routes; ph.count.times { |pick_path_index| # puts ph.transformation_at(pick_path_index) @TRroof = ph.transformation_at(pick_path_index) @Pickdepth = ph.depth_at(pick_path_index) } # UI.messagebox ("Plane Trans; #{@TRroof} \n Pick Depth; #{@Pickdepth}") # best_entity = ph.best_picked @member_face = ph.picked_face @face_vertices = @member_face.vertices # trim_plane = @member_face.plane @Vertices = [] counter = 0 for xi in @face_vertices vertexi = @face_vertices[counter].position @Vertices[counter] = vertexi.transform @TRroof counter = counter + 1 end @trim_plane = Geom.fit_plane_to_points(@Vertices[0], @Vertices[1], @Vertices[2]) # puts @member_face # puts counter # puts @Vertices puts @trim_plane end def set_current_point(x, y, view) if (!@ip.pick(view, x, y, @ip1)) return false end need_draw = true # Set the tooltip that will be displayed view.tooltip = @ip.tooltip # Compute points case @state when STATE_PICK @pts[0] = @ip.position need_draw = @ip.display? || @drawn when STATE_PICK_NEXT @pts[1] = @ip.position end view.invalidate if need_draw end def onMouseMove(flags, x, y, view) self.set_current_point(x, y, view) end def update_state case @state when STATE_PICK @ip1.copy! @ip Sketchup;;set_status_text "[#{@tool_name}] Click entity you wish to trim" @state = STATE_PICK_NEXT when STATE_PICK_NEXT # @ip1.clear Sketchup;;set_status_text "[#{@tool_name}] Trimming entity" @state = STATE_PICK_LAST when STATE_PICK_LAST Sketchup.active_model.select_tool(nil) end end def onLButtonDown(flags, x, y, view) case @state when STATE_PICK self.set_current_point(x, y, view) self.get_plane(x, y, view) self.update_state when STATE_PICK_NEXT self.set_current_point(x, y, view) self.get_member(x, y, view) self.update_state when STATE_PICK_LAST self.update_state end end def onCancel(flag, view) view.invalidate if @drawn reset end def draw(view) @drawn = false # Show the current input point if( @ip.valid? && @ip.display? ) @ip.draw(view) @drawn = true end case @state when STATE_PICK # Do Nothing when STATE_PICK_NEXT view.drawing_color = [0, 200, 0] view.line_width = 5 view.draw(GL_LINE_LOOP, @Vertices) @drawn = true when STATE_PICK_LAST view.draw_points(@Intersectpoints2, 10, 4, "red") view.draw_points(@Newfacepoints2, 12, 3, "blue") @drawn = true else #do nothing end end end # class Tool
-
@medeek said:
Your first block of code has me intrigued. I've been testing the intersect method which I did not know existed. It definitely has some potential. I am having a couple problems with it though.
1.) The intersecting member may not intersect with the face itself but intersects with the plane defined by the face. How do I specify the plane and not the face with this function (intersect_with).
intersect_with only works with entities. You could create a large temporary face that matches the plane.
2.) Most of the time the group (solid) that I am intersecting with the plane is nested within another component and then that component is inside of another group. Testing my script with an un-nested group works fine but if its nested it does not work. There is probably a simple work around for this, just need to figure it out.
Handling embedded groups and component instances is very tricky. You will need to combine the local transformation with all of the 'above' transformations to get to the real world position.
-
@medeek said:
Here is the current tool in its entirety. At this point it kind of works.
How does it fail?
-
The temporary face seems to do the trick. I've only have two main issues left.
-
Nested groups is causing me grief and sometimes the tool cannot detect the intersection. I need to dig into this further.
-
The intersect routine works great but how do I get it to draw a face where it created the edges so that the solid is reclosed when trimmed?
-
-
@medeek said:
The temporary face seems to do the trick. I've only have two main issues left.
-
Nested groups is causing me grief and sometimes the tool cannot detect the intersection. I need to dig into this further.
-
The intersect routine works great but how do I get it to draw a face where it created the edges so that the solid is reclosed when trimmed?
- Here is an example of how I solve the problem of nested components/groups
def recurse(ents,tran) ents.each{|e| if ["ComponentInstance","Group"].include?(e.typename) ee = e.typename=="Group" ? e.entities ; e.definition.entities; if ee.grep(Sketchup;;ComponentInstance) || ee.grep(Sketchup;;Group) tr = tran * e.transformation; recurse(ee,tr) end end } self.trim(ents,tran) end
- Let Sketchup create the face by using .find_faces for each edge that is on the cutting plane.
-
-
When I use the truss plugin to create complex roofs I would like to be able to use the trim tool to trim some of the members (ie. a hip roof):
https://3dwarehouse.sketchup.com/model.html?id=uade0f021-a386-402c-b784-087189478ecb
Advertisement