Dear Sir,
How to get the outer points of a curved terrain? The example is as follows, the selected terrain is in blue.
Dear Sir,
How to get the outer points of a curved terrain? The example is as follows, the selected terrain is in blue.
one possible quick code snippet:
sel = Sketchup.active_model.selection # Current selection
edges = sel.grep(Sketchup::Edge) # grep out the edges
vertices = edges.collect(&:vertices).flatten.uniq # find out vertices
points = vertices.map(&:position) # get the positions
⌠then âŚ
outer_edges = edges.find_all { |edge| edge.faces.size == 1 }
vertices = outer_edges.map(&:vertices).flatten.uniq
points = vertices.map(&:position) # get the positions
Oh, I missed the word âouterââŚ
Taking a closer look at the original image and thinking over, maybe itâs even better:
sel = Sketchup.active_model.selection # Current selection
edges = sel.grep(Sketchup::Edge) # grep out the edges
outer_edges = edges.find_all{ |edge| edge.faces.one?{ |face| sel.include?(face) } }
vertices = outer_edges.map(&:vertices).flatten.uniq
points = vertices.map(&:position) # get the positions
I disagree with this. It is not necessary to force the iteration of each and every face in each and every edgeâs faces collection. (ie, the Enumerable#one?
method must iterate every member of a collection.)
It will be much faster to just check that the size of an edgeâs faces collection has only 1 member.
Secondly, sel.include?(face)
is going to be true
for every face of every edge , since they are ALL selected. Therefore edge.faces.one?
is always going to return false
, which will cause edges.find_all
to always return an empty array.
I have to argue.
We probably interpret the task in different ways?
I made a very simplified version of the âterrainâ, it is a 3x3 inch square grid just to easy simulate some selection and result of the sample snippet.
test_outer_points.skp (15.8 KB)
def test_outer_points
sel = Sketchup.active_model.selection
edges = sel.grep(Sketchup::Edge)
outer_edges_da = edges.find_all { |edge| edge.faces.size == 1 }
outer_edges_de = edges.find_all{ |edge|
edge.faces.one?{ |face| sel.include?(face) }
}
vertices_da = outer_edges_da.map(&:vertices).flatten.uniq
vertices_de = outer_edges_de.map(&:vertices).flatten.uniq
points_da = vertices_da.map(&:position)
points_de = vertices_de.map(&:position)
puts "Dan: #{points_da}\nDez: #{points_de}"
end
Let see what will be the result with different selections: (see screenshots)
__
Test 1
test_outer_points
Dan: []
Dez: [Point3d(1, 2, 0), Point3d(2, 2, 0), Point3d(1, 1, 0), Point3d(2, 1, 0)]
__
Test 2
test_outer_points
Dan: [Point3d(0, 0, 0), Point3d(1, 0, 0), Point3d(0, 1, 0)]
Dez: [Point3d(0, 0, 0), Point3d(1, 0, 0), Point3d(0, 1, 0), Point3d(1, 1, 0)]
__
Test 3
test_outer_points
Dan: [Point3d(3, 1, 0), Point3d(3, 2, 0)]
Dez: [Point3d(1, 2, 0), Point3d(2, 2, 0), Point3d(3, 1, 0), Point3d(3, 2, 0), Point3d(2, 1, 0), Point3d(1, 1, 0)]
What do you think?
You get a point if it is outer of all terrian, I get a point as the selectionâs outerâŚ
I know you cheated by changing the terms of the exercise.
The OP stipulated a terrain mesh, which is triangulated.
I fail to see how that makes a difference in the results.
I donât think the terms were cheated, but sure my simplified example does not triangulated. This is does not make any difference about the result, as @Neil_Burkholder mentioned.
(Just out of curiosity, I downloaded one model from 3DWH and checked on it. I have got similar result.)
If you apply the code to the selected part of the terrain mesh as shown in the first post, your method for outer_edges
will result an empty array.
This is not necessarily a bad thing, but this is a fact.
You and me interpreted the âterms of the exerciseâ differently.
__
My interpretation: it will find all
that edges where only one
of the faces of the edge included
in a selection.
Actually itt will find a outer edges of the selection. Let say, this is a the border or bounding edges of selection. This is not necessarily a good thing, but this is a fact.
I know that myself and perhaps the original poster do not speak English at the native level ⌠this can of course cause some misunderstanding and âbadâ explanation. Maybe thatâs the case. Sorry.
Sir,I have a question,is the mesh must be triangulated?The order of points acquired in this way is a bit messy.For example,in Test3, can I get test_outer_points output in a certain order?Like this:
Example:[Point3d(1, 1, 0), Point3d(2, 1, 0), Point3d(3, 1, 0), Point3d(3, 2, 0), Point3d(2, 2, 0), Point3d(1, 2, 0)]
You asked Dan, but since I made the method, I will answer if you donât mindâŚ
No
Yes, it will be always like âmessyâ.
No. Not from test_outer_points
method. You have to write an other one to get the right order.
NO, I had a brain fart. Never mind what I said.
My eyes did not see the mesh outside the selection. So testing for 1 member face arrays would not work.
Sorry.
Oh,thanks for your answer,maybe I didnât express it clearlyďźthe question I want to ask is is there any way to output the outer_points in a certain order
I guess you want the order of the points, where you can connect one after other with edges, to get a closed loop. Donât you?
If you have SU 2020.1 or later, I have a relatively simple method in my mind (using Entities#weld-instance_method ). I can do it later today, if you wishâŚ
If you are using SU 2018, as indicated in your profile, it will be more complex but can be done too. Maybe I can find some time to think about moreâŚ
Yes! Thatâs what I want,but I use SU 2018, if you can help me solve the problem, I would be very grateful!Waiting for your reply
Something like this should work for 2018
def outer_edges
sel = Sketchup.active_model.selection
edges = sel.grep(Sketchup::Edge)
edges.find_all { |edge| edge.faces.one? { |face| sel.include?(face) } }
end
def sort_points(edges)
last_edge = edges.pop
sorted = [last_edge]
for i in (0..(edges.count - 1)) do
last_edge = edges.find do |edge|
edge.start.position == last_edge.start.position ||
edge.start.position == last_edge.end.position ||
edge.end.position == last_edge.start.position ||
edge.end.position == last_edge.end.position
end
sorted.push(last_edge)
edges.delete(last_edge)
end
sorted.map { |e| [e.start.position, e.end.position] }.flatten.uniq(&:to_s)
end
sort_points(outer_edges)
Sirďźthe âsort_pointsâ sort_points I output according to your code still has the triangulated problem.
[Point3d(0, 0, 0), Point3d(39.3701, 0, 0), Point3d(0, 39.3701, 0), Point3d(39.3701, 39.3701, 0), Point3d(78.7402, 39.3701, 0), Point3d(78.7402, 0, 0)]
Obviously the output points are not in orderďźI am not sure if there is some problems with my operation.
I seem to have succeeded here too, I donât know where I made a mistake in the code before, thank you again for your helpďź