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
```

1 Like

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
```

1 Like

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`

`edge.faces.one?`

`false`

`edges.find_all`

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âŚ

1 Like

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.

1 Like

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.

1 Like

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)
```

1 Like

Sirďźthe âsort_pointsâ sort_points I output according to your code still has the triangulated problem.

For example,I chose two square grids,and the result is:

```
[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ďź