Intersect between a plane and a group

Hi,
Any idea how can I find faces that are the result of an intersection between a plane and a group?
Thank you in advance,

:bulb: The intersect_plane_plane method is used to compute the intersection of two planes.

possible method snippet (did not tested):

def find_intersect_faces(faces_in_group, myplane)
  intersection = []
  faces_in_group.each{|face|
    if Geom.intersect_plane_plane(myplane, face.plane)
      intersection<<face
    end
  }
  intersection
end

call it with the arguments : faces and plane in question
You may need to take care about some transformation for face.plane… depends how deep the group is nested.

Edit:
Then you need some more comparation if the intersection line is “inside” a group face…

1 Like

Hello Dezmo,
I want to find created faces that are the result of plane and group intersect. I should explain it more clear.

The result of an intersection is a set of edges:

intersection_edges = entities.intersect_with (...)

The newly created faces are attached to those edges.

2 Likes

intersect_with will find the intersection between 2 groups or entities but I wish to find the intersection between a plane and a group. The plane is not an entity or group or component. I wish to use edges in drawing so creating a face find intersect and deleting it is not a good way for it.

Thank you Dezmo, in the first step I should find the intersection between all faces in the group and my plane that will be some lines. In the second step, I should find the intersections between these lines that will be some edges. I will try for it.
P.S.
It is not working because the plane of faces that didn’t cut by plane will have interset.

an other :bulb: :

EDIT: removed, my concept was wrong... :-(

In your special case above this face is what you want… I guess

In your picture, in face face_to_intersec is my plane. Your code made me confused.
When a plane cuts a group, some edges will intersect. I am looking for those edges.
For example, if the group is a ball, its intersect with a plane will be a circle and I wish to have points of that circle.

Draw a temp grouped face onto the plane, so that its extents are bigger that your main group’s bounds.
Intersect the face’s group with your main group and put the results into another new 3rd group.
That 3rd group now contains the resultant edges of any intersection…
Erase the temp face’s group.
Do what you need to do with the intersection’s edges - e.g. add faces etc.

Tig, in fact, I wish to move the plane by mouse pointer and highlight the intersection between plane and group. I cannot create and delete a group when the mouse moves.

That is totally different than you asked originally… :wink:

my main problem is finding " Intersect between a plane and a group". am I right?

The main problem is that we could not understand what you really want to achieve…

Do you really want to do something with the resulted “face” or you just to want to show how will it look like the intersection temporally?

Perhaps ???:

glintersect

class Testtool
  def initialize
    @ip = Sketchup::InputPoint.new
    @plane_normal = Geom::Vector3d.new(1,1,1)
  end
  
  def onMouseMove(_flags, x, y, view)
    @ip.pick(view, x, y)
    @pts = poly_points( @ip.position, 100, @plane_normal)
    view.invalidate
  end

  def poly_points( center = ORIGIN, radius = 1, norm = Z_AXIS, xaxis = norm.axes[0], seg = 24 )
    ang = 2*Math::PI/seg
    tr = Geom::Transformation.rotation( center, norm, ang )
    pts = []
    pts[0] = center.offset( xaxis, radius )
    (1...seg).each{ |i| pts[i] = pts[i-1].transform(tr) }
    pts
  end
  
  def draw(view)
    if @pts
      view.drawing_color = [0,128,128, 128]
      view.draw( GL_POLYGON, @pts )
    end
  end
    
    def getExtents
      bb = Sketchup.active_model.bounds
      return bb unless @pts && @pts.size > 0
      bb.add @pts
    end
end
Sketchup.active_model.select_tool(Testtool.new)
2 Likes

I don’t want a face I want something temporary.

In this video yellow square move with the mouse pointer is fixed but I wish always it will be around of group.

Do you mean you wish the yellow plane to be constrained to the group’s bounds ?

Yes sir, exactly. Any solution for it?

I don’t think so. I guess you want to follow the contour of the group, which is not equal to bounding box (cuboid). You may want same as the section plane do. Don’t you?

If yes (even if not :wink: ), here are some “finger exercises”, just an idea, not fully engineered :

section_toolB

.
.

Code snippet
class TesttoolB

  def initialize
    @ip = Sketchup::InputPoint.new
    @ro_backup = nil
    ro_backup_and_set()
    reset()
  end
  
  def reset(view = Sketchup.active_model.active_view)
    @picked = false
    @start_pts = nil
    @gr_edges = nil
    @sp.erase! if @sp && @sp.valid?
    # not that elegant, but remove the 
    # "track" of section plane operations
    # from undo stack:
    Sketchup.active_model.abort_operation
    view.invalidate
  end
  
  def onCancel(reason, view)
    reset(view)
  end
  
  def deactivate(view)
    reset(view)
    ro_restore() if @ro_backup
  end
  
  def get_trans_at(obj, ph)
   ph.count.times{|i|
     if ph.leaf_at(i) == obj
       return ph.transformation_at(i)
     end
   }
   return IDENTITY
  end
  
  def get_trans_pts(face)
    face.outer_loop.vertices.map{ |v| v.position.transform(@tr) }
  end
  
  def onMouseMove(_flags, x, y, view)
    @ip.pick(view, x, y)
    if @picked
      pos = @ip.position.transform(@tr.inverse)
      @sp = @sp.set_plane(pos, @normal.reverse)
    else
      ph = view.pick_helper
      ph.do_pick(x, y, 5)
      @ph_face = ph.picked_face
      if @ph_face
        @tr = get_trans_at(@ph_face, ph) 
        @start_pts = get_trans_pts(@ph_face)
      else
        @start_pts = nil
      end
    end
    view.invalidate
  end
  
  def onLButtonDown(flags, x, y, view)
    if !@picked && @ip.face
      @normal = @ph_face.normal
      gr_ents = @ph_face.parent.entities
      @gr_edges = gr_ents.grep(Sketchup::Edge)
      Sketchup.active_model.start_operation("Operation will be aborted")
      @sp = gr_ents.add_section_plane(@ip.position, @normal.reverse)
      @sp.activate
      @picked = true
    else
      reset(view)
    end
  end

  def draw(view)
    @ip.draw(view) if @ip.display?
    view.tooltip = @ip.tooltip
    # draw the start face contour:
    if @start_pts && @start_pts.size > 2
      view.drawing_color = "dodgerblue"
      view.line_width = 4
      view.draw( GL_LINE_LOOP, @start_pts ) 
    end
    # highlight all edges in group: 
    if @gr_edges 
      view.drawing_color = "peru"
      view.line_width = 2
      @gr_edges.each{|e|
        epts = e.vertices.map{|v| v.position.transform(@tr)}
        view.draw( GL_LINES, epts ) 
      }
    end
  end
    
  def getExtents
    bb = Sketchup.active_model.bounds
    return bb unless @pts && @pts.size > 0
    bb.add @pts
  end
  
  # to display the section "properly"
  # set it up as you need, but before that
  # make a backup
  # you may need to consider more properties to change
  # this is just a "most important"
  def ro_backup_and_set
    rend_ops = Sketchup.active_model.rendering_options
    @ro_backup = {
      "DisplaySectionPlanes" => rend_ops["DisplaySectionPlanes"],
      "DisplaySectionCuts" => rend_ops["DisplaySectionCuts"],
      "SectionCutFilled" => rend_ops["SectionCutFilled"]
    }
    rend_ops["DisplaySectionPlanes"] = false
    rend_ops["DisplaySectionCuts"] = true
    rend_ops["SectionCutFilled"] = true
  end
  
  # restore the above rendering_options
  # to state before the tool was started
  def ro_restore
    @ro_backup.each{|k,v|
      Sketchup.active_model.rendering_options[k] = v
    }
  end
  
end
Sketchup.active_model.select_tool(TesttoolB.new)

.

1 Like

Now exactly. I wish the yellow plane to be constrained to the group.

You are right. Your code is so strong and I can learn so much from it. Your code shocked me and I am so excited that we can do something so interesting by code. You are great. Thank you so much.
At the end of the day, it seems there is not a simple and direct way to find the intersection between a group and a plane. (we can create a face on a plane and find the intersection between face and group and delete face but not good for the “draw” method.)

2 Likes

Refutation (kind of) :wink:
Motto: Man can do everything, just a matter of time (and :coffee: or :beers: ) . :innocent:

My third conceptual idea is:

section_toolC
.
.

Code snippet C
class TesttoolC

  def initialize
    @ip = Sketchup::InputPoint.new
    reset()
  end
  
  def reset(view = Sketchup.active_model.active_view)
    @picked = false
    @start_pts = nil
    @pts_pairs = nil
    @gr_edges = nil
    view.invalidate
  end
  
  def onCancel(reason, view)
    reset(view)
  end
  
  def deactivate(view)
    reset(view)
  end
  
  def get_trans_at(obj, ph)
   ph.count.times{|i|
     if ph.leaf_at(i) == obj
       return ph.transformation_at(i)
     end
   }
   return IDENTITY
  end
  
  def get_trans_pts(face)
    face.outer_loop.vertices.map{ |v| v.position.transform(@tr) }
  end
  
  def onMouseMove(_flags, x, y, view)
    @ip.pick(view, x, y)
    if @picked
      pos = @ip.position.transform(@tr.inverse)
      @pts_pairs = find_intersect_pts( [pos, @normal] )
    else
      ph = view.pick_helper
      ph.do_pick(x, y, 5)
      @ph_face = ph.picked_face
      if @ph_face
        @tr = get_trans_at(@ph_face, ph) 
        @start_pts = get_trans_pts(@ph_face)
      else
        @start_pts = nil
      end
    end
    view.invalidate
  end
  
  def onLButtonDown(flags, x, y, view)
    if !@picked && @ip.face
      @normal = @ph_face.normal
      gr_ents = @ph_face.parent.entities
      @gr_edges = gr_ents.grep(Sketchup::Edge)
      @picked = true
    else
      reset(view)
    end
  end

  def draw(view)
    @ip.draw(view) if @ip.display?
    view.tooltip = @ip.tooltip
    # draw the start face contour:
    if @start_pts && @start_pts.size > 2
      view.drawing_color = "dodgerblue"
      view.line_width = 4
      view.draw( GL_LINE_LOOP, @start_pts ) 
    end
    # highlight intersect
    if @pts_pairs
      view.drawing_color = "peru"
      view.line_width = 4
      @pts_pairs.each{|pair|
        trpts = pair.map{|p| p.transform(@tr)}
        view.line_width = 4
        view.line_stipple = ""
        view.draw( GL_LINE_STRIP, trpts )
        view.line_width = 3
        view.line_stipple = "-"
        view.draw2d( GL_LINE_STRIP, trpts.map{|pt| view.screen_coords(pt)} ) 
      }
    end
  end
    
  def getExtents
    bb = Sketchup.active_model.bounds
  end
  
  def point_between?(point, point1, point2)
    return true if point == point1 || point == point2
    !( point.vector_to(point1).samedirection?( point.vector_to(point2) ) )
  end

  def dig_pts_faces(plane)
    dig_pts = []
    faces = []
    @gr_edges.each{|edge|
      pt = Geom.intersect_line_plane(edge.line, plane)
      if pt 
        pt1,pt2 = edge.vertices.map{|v| v.position}
        if point_between?(pt, pt1, pt2)
          dig_pts<<pt 
          faces += edge.faces
        end
      end
    }
    [dig_pts, faces]
  end

  def find_intersect_pts(plane)
    dig_pts, faces = dig_pts_faces(plane)
    lines = []
    faces.each{|face|
      line = Geom.intersect_plane_plane(plane, face.plane)
      lines<<line if line && !lines.include?(line)
    }
    pts_pairs = []
    lines.each{|line|
      pts_pairs<<dig_pts.select{|pt| pt.on_line?(line)}
    }
    pts_pairs
  end
  
end
Sketchup.active_model.select_tool(TesttoolC.new)

4 Likes

In Sketchup, you can do everything. Your code is so advanced and you find very interesting solutions for the problems. Thanks again.

1 Like