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

Trimming a Solid Group

Scheduled Pinned Locked Moved Developers' Forum
12 Posts 2 Posters 1.4k Views 2 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.
  • M Offline
    medeek
    last edited by 23 Jul 2016, 22:55

    I'm trying to develop a module/tool in my plugin that will allow the user to select a roof rafter and then a face from another roof member and have the roof rafter be trimmed to this face. I'm running into a number of problems in the developing the algorithm for doing this and wondering if anyone has attempted this sort of thing before and my have some pointers.

    One problem is determining which edge(s) to select as needing to be trimmed.

    Nathaniel P. Wilkerson PE
    Medeek Engineering Inc
    design.medeek.com

    1 Reply Last reply Reply Quote 0
    • M Offline
      medeek
      last edited by 24 Jul 2016, 06:51

      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.

      Nathaniel P. Wilkerson PE
      Medeek Engineering Inc
      design.medeek.com

      1 Reply Last reply Reply Quote 0
      • S Offline
        sdmitch
        last edited by 24 Jul 2016, 16:32

        @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)
        

        erase backside.gif

        Nothing is worthless, it can always be used as a bad example.

        http://sdmitch.blogspot.com/

        1 Reply Last reply Reply Quote 0
        • M Offline
          medeek
          last edited by 1 Aug 2016, 04:17

          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.

          Nathaniel P. Wilkerson PE
          Medeek Engineering Inc
          design.medeek.com

          1 Reply Last reply Reply Quote 0
          • S Offline
            sdmitch
            last edited by 1 Aug 2016, 13:22

            @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
            
            

            Nothing is worthless, it can always be used as a bad example.

            http://sdmitch.blogspot.com/

            1 Reply Last reply Reply Quote 0
            • M Offline
              medeek
              last edited by 3 Aug 2016, 05:29

              @Sdmitch

              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.

              Nathaniel P. Wilkerson PE
              Medeek Engineering Inc
              design.medeek.com

              1 Reply Last reply Reply Quote 0
              • M Offline
                medeek
                last edited by 3 Aug 2016, 07:22

                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
                

                Nathaniel P. Wilkerson PE
                Medeek Engineering Inc
                design.medeek.com

                1 Reply Last reply Reply Quote 0
                • S Offline
                  sdmitch
                  last edited by 3 Aug 2016, 16:38

                  @medeek said:

                  @Sdmitch

                  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.

                  Nothing is worthless, it can always be used as a bad example.

                  http://sdmitch.blogspot.com/

                  1 Reply Last reply Reply Quote 0
                  • S Offline
                    sdmitch
                    last edited by 3 Aug 2016, 16:46

                    @medeek said:

                    Here is the current tool in its entirety. At this point it kind of works.

                    How does it fail?

                    Nothing is worthless, it can always be used as a bad example.

                    http://sdmitch.blogspot.com/

                    1 Reply Last reply Reply Quote 0
                    • M Offline
                      medeek
                      last edited by 17 Aug 2016, 04:53

                      The temporary face seems to do the trick. I've only have two main issues left.

                      1. Nested groups is causing me grief and sometimes the tool cannot detect the intersection. I need to dig into this further.

                      2. 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?

                      Nathaniel P. Wilkerson PE
                      Medeek Engineering Inc
                      design.medeek.com

                      1 Reply Last reply Reply Quote 0
                      • S Offline
                        sdmitch
                        last edited by 17 Aug 2016, 14:22

                        @medeek said:

                        The temporary face seems to do the trick. I've only have two main issues left.

                        1. Nested groups is causing me grief and sometimes the tool cannot detect the intersection. I need to dig into this further.

                        2. 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?

                        1. 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
                        
                        
                        1. Let Sketchup create the face by using .find_faces for each edge that is on the cutting plane.

                        Nothing is worthless, it can always be used as a bad example.

                        http://sdmitch.blogspot.com/

                        1 Reply Last reply Reply Quote 0
                        • M Offline
                          medeek
                          last edited by 21 Aug 2016, 20:19

                          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):

                          Link Preview Image
                          3D Warehouse

                          3D Warehouse is a website of searchable, pre-made 3D models that works seamlessly with SketchUp.

                          favicon

                          (3dwarehouse.sketchup.com)

                          Nathaniel P. Wilkerson PE
                          Medeek Engineering Inc
                          design.medeek.com

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

                          Advertisement