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.
    • medeekM Offline
      medeek
      last edited by

      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
      • medeekM Offline
        medeek
        last edited by

        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
        • sdmitchS Offline
          sdmitch
          last edited by

          @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
          • medeekM Offline
            medeek
            last edited by

            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
            • sdmitchS Offline
              sdmitch
              last edited by

              @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
              • medeekM Offline
                medeek
                last edited by

                @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
                • medeekM Offline
                  medeek
                  last edited by

                  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
                  • sdmitchS Offline
                    sdmitch
                    last edited by

                    @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
                    • sdmitchS Offline
                      sdmitch
                      last edited by

                      @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
                      • medeekM Offline
                        medeek
                        last edited by

                        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
                        • sdmitchS Offline
                          sdmitch
                          last edited by

                          @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
                          • medeekM Offline
                            medeek
                            last edited by

                            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