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,
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…
The result of an intersection is a set of edges:
intersection_edges = entities.intersect_with (...)
The newly created faces are attached to those edges.
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.
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… ![]()
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 ???:

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)
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
), here are some “finger exercises”, just an idea, not fully engineered :

.
.
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)
.
You may want the same as the section plane do
Now exactly. I wish the yellow plane to be constrained to the group.
If yes (even if not
), here are some “finger exercises”, just an idea, not fully engineered :
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.)
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.
Refutation (kind of) ![]()
Motto: Man can do everything, just a matter of time (and
or
) . ![]()
My third conceptual idea is:

.
.
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)
Man can do everything
In Sketchup, you can do everything. Your code is so advanced and you find very interesting solutions for the problems. Thanks again.

