how to split an edge by multiple points at once?
as I split A edge into B edge and C edge. A → B + C
will edge A be deleted?
what should I do to continue to split edge A?
how to split a curve?
I get out of the an edge which makes up the curve, and applies a .split(p3d) on it, however, only the edge (straight line) is split, the curve didn’t change.
fortunately, I solved it. I just leave the code here, in case someone needs it.
def sort_index(arg, arr)
indices = 0
arr.each do |ar|
if arg < ar
indices -= 1
else
indices += 1
end
end
return indices
end
def sort_sequence(arr)
indices = Hash.new
arr.each do |arg|
indices[sort_index(arg, arr)] = arg
end
_index = Array.new
indices.sort.each do |ar|
_index << ar[1]
end
return _index
end
def advanced_split(ed, p3ds)
it = sort_sequence(p3ds).reverse
it.each do |p3d|
ed.split(p3d)
end
end
Here is my concept for a single method that would take multiple point arguments.
It wraps the splitting in an undo operation. Fully commented.
(Tested with a simple 100 inch edge lying along the x axis.)
…
# Split an edge given multiple points. Returns an array of the new edges
# along with the original now shorter edge (in no particular order.)
# @param edge [Sketchup::Edge] the edge to split.
# @param points [Array<Geom::Point3d,Array<Float,Float,Float>]
# @return [Array<Sketchup::Edge>] an array of the edges with the original.
def split_multiple(edge,*points)
# Convert any 3 element Float arrays to a Geom::Point3d:
points.map! do |pt|
next pt if pt.is_a?(Geom::Point3d)
next Geom::Point3d.new(pt[0..2]) if pt.is_a?(Array)
nil
end
points.compact! # Remove any nils
# Remove any points not on the edge's line:
eline = edge.line
points.delete_if {|pt|
next true if !pt.on_line?(eline)
Geom::point_in_polygon_2D(
pt, [edge.start.position, edge.end.position], true
) ? false : true
}
# Sort the points using the API's < method which is based upon ORIGIN
# Use a transformation to the ORIGIN within the sort block:
t = edge.start.position.vector_to(ORIGIN)
points.sort! do |a,b|
a = a.transform(t)
b = b.transform(t)
a == b ? 0 : a < b ? -1 : 1
end
unless points.empty?
# Take an array snapshot of the existing entities edges:
before = edge.parent.entities.grep(Sketchup::Edge)
# Split the edge using the sorted points in reverse order:
Sketchup.active_model.start_operation("MultiSplit Edge",true)
#
points.reverse.each do |point|
edge.split(point)
end
#
Sketchup.active_model.commit_operation
# Remove the target edge's reference from the before array:
before.delete(edge)
# Return an array of the edge and it's split off edges:
edge.parent.entities.grep(Sketchup::Edge) - before
else
# Just return an array with the original edge:
[edge]
end
end
And here is a slightly modified edition that returns the edge array in edge joined order (the now shortened original edge first.)
# Split an edge given multiple points. Returns an array of the new edges
# along with the original now shorter edge first (in edge joined order.)
# @param edge [Sketchup::Edge] the edge to split.
# @param points [Array<Geom::Point3d,Array<Float,Float,Float>]
# @return [Array<Sketchup::Edge>] an array of the edges with the original.
def split_multiple_ordered(edge,*points)
# Convert any 3 element Float arrays to a Geom::Point3d:
points.map! do |pt|
next pt if pt.is_a?(Geom::Point3d)
next Geom::Point3d.new(pt[0..2]) if pt.is_a?(Array)
nil
end
points.compact! # Remove any nils
# Remove any points not on the edge's line:
eline = edge.line
points.delete_if {|pt|
next true if !pt.on_line?(eline)
Geom::point_in_polygon_2D(
pt, [edge.start.position, edge.end.position], true
) ? false : true
}
# Sort the points using the API's < method which is based upon ORIGIN
# Use a transformation to the ORIGIN within the sort block:
t = edge.start.position.vector_to(ORIGIN)
points.sort! do |a,b|
a = a.transform(t)
b = b.transform(t)
a == b ? 0 : a < b ? -1 : 1
end
unless points.empty?
# The edge array to return:
edges = []
# Split the edge using the sorted points in reverse order:
Sketchup.active_model.start_operation("MultiSplit Edge",true)
#
points.reverse.each do |point|
edges << edge.split(point)
end
#
Sketchup.active_model.commit_operation
# Return an array of the edge and it's split off edges:
edges << edge
# Reverse and remove any nils returned by edge.split
edges.reverse.compact
else
# Just return an array with the original edge:
[edge]
end
end
Retested and edited several times to deal with issues, like when the args result in no valid points, the undo operation needs to be skipped, and when the split method returns nil these need to be removed from the result array.
Thank you so much for providing this dedicate answer. ^v^
What I am coding, is an extension that connects all stray edges || curves || connected-edges by only one click. the aim is to facilitate users during importing an imperfect pattern with many tiny edges missing.
Therefore, I have developed an extension that add edges to the entities, but intersection appears to be a problem. The edges generated by the extension: if it’s crossed by another edge, it won’t automatically split.
You may wonder why I don’t simply apply Sketchup.break_edges = true
as adding edges, I can’t do this because there are some special circumstances in user’s expectation. In other word, I want the user to be able to decide what to do with outcome edges, and delete or split the ones they don’t want. To make the code more flexible. ^v^
Now, what I have already gained is a hash, which the keys are single edge each, that has been proved to be crossed. Meanwhile the values are an array each, consists of one or more p3d arguments which represents intersections.
To split each of the edges, I thought I could do “split(*p3ds)” to split one edge at multiple points, however, it failed as split only takes one arguments. v_v
I work out there are two ways to split the same edge: ed = #<Sketchup::Edge:0x0000021d25b1edd0> if p3d1<p3d2
Method 2 is perfect in my circumstance, what I needed is a sort function that helps me to determine which p3d is closer to the origin.
in the my code above, as I already have hash = {edge=>[*p3ds], edge2=>[*p3ds]}
simply call advance_split(ed, p3ds)
it resolves all the problem. ^v^
I can remember some of my previous questions are answered by you.
I appreciate your passion and contribution.
cheers