Adding edges to the initial manual selection following a snake’s skeleton pattern. Please, help! Thanks


#1

Folks,
This is my first post. I am a novice just learning the ropes using SketchUp manually, as well as trying my first ruby scripts. Please, bear with me. I know my code is neither elegant nor efficient. I am sure there are far better ways to do what I am trying to do, but right now I’d just be happy if the code works. :smiley:
I’d really appreciate if I can get some help on this seemly simple code that has gotten already too many hours of fruitless work. Thanks in advance to those from whom I get some help.

MODEL: I have a structure that resembles a snake’s skeleton. Basically ribs attached to a spine. It consists of a series of short edges connected forming a long snake-like elongated s-shaped curve. I call this curve “the spine”, where each short edge is like a “vertebrae”. To each one of the short vertebrae edges, there are two longer edges (I call them “ribs”) connected roughly perpendicularly to the short edge at the end of it, where it also connects to the next short edge. So, I have this curvy spine constituted of short edge vertebrae, to which longer edge ribs are connected in roughly perpendicular fashion. Please, see uploaded picture for reference.

GOAL: I want my script to add a given number of consecutive short edge vertebrae to the selection starting from whichever short edge vertebrae I select manually.

PROBLEM: With the script as it is, depending on where I start, sometimes it adds a couple of short edges and sometimes it adds a few more, but never the full amount that I specify in the script. It seems like after adding a few of the short edges to the initial manual selection it just stops adding them.

CODE:

model = Sketchup.active_model # Access the model
ents = model.entities # Access the entities in the model
sel = model.selection # Access selection object

vertex_array = []
edges2 = []

for _Count1 in 1…7

vertex_array.clear # Clears the vertex_array to repopulate it with the newly added edge’s vertices
vertex_array = sel[_Count1 - 1].vertices
edges2.clear # Clears the edges2 array to repopulate it with the newly added edge’s vertices

# Since the connector/short (spine) edges connecting the long (rib) edges are always descending, ...
# ... find the vertex with the lowest value for the z-coordinate to identify the next set of edges, ...
# ... where to find the next short (vertebrae) edge.
if vertex_array[0].position.z.to_mm > vertex_array[1].position.z.to_mm
  edges2 = vertex_array[1].edges # Gathers the edges connected to the second vertex (index 1) to the array of edges
else
  edges2 = vertex_array[0].edges # Gathers the edges connected to the first vertex (index 0) to the array of edges
end

Now we get rid of the short edge that was last added to the selection, since it was included …

… in the edges2 array, as it is also connected to the vertex used to gather the edges.

after removingt this edge there would only be 3 edges in the edges2 array.

_LastSelId = sel[_Count1 - 1].object_id.to_s
for myCount in 0…(edges2.length - 1)
if edges2[myCount].object_id.to_s == _LastSelId
edges2.delete_at(myCount)
end
end

After getting rid of the short edge that was last added to the selection, of the 3 edges left, …

the shortest one (a vertebrae) should be the one to be the next edge to add to the selection.

_MinLengthEdge = [edges2[0].length, edges2[1].length, edges2[2].length].min
for myCount2 in 0…(edges2.length - 1)
if edges2[myCount2].length == _MinLengthEdge
_MinLengthEdge = myCount2
end
end

Now we just add the edge previously identified as the shortest in the edges2 array to the selection

sel.add edges2[_MinLengthEdge]

end

The above code is also available in a text file I uploaded in this post.

Please, help me figure this out. There are probably amongst us some SketchUp code gods (and hopefully goddesses too) that would figure out what’s wrong with my code in a second. Also, feel free to point enhancement (both in elegance and efficiency) to my code.
Thanks in advance.
Raoul
Software-Sketchup-Code-Qusetions-01-SnakeSpineAndRibs.txt (2.1 KB)


#2

1) Please wrap code (properly indented using 2 space indents)
in the forum between triple backtick lines, like this:

```ruby

# code goes here

```

(The first code delimiter line should include the name of the
coding language,ie: text, javascript, ruby, c, html, css, etc.)


2) Ruby code files should be ".rb" extension.
IF the forum doesn’t like them, wrap them up in a zip archive.


#3

The comment:

Clears the vertex_array to repopulate it with the newly added edge’s vertices

is untrue. Ie, the clear() call is frivolous, as in the next statement, you are actually reassigning the reference to point at a newly created array instance (returned by the vertices() call.)

It also does not make sense to do this:

 for _Count1 in 1..7

and use it like this:

vertex_array = sel[_Count1 - 1].vertices

If you KNOW there are 7 objects to iterate then perhaps:

7.times do |i|
  vertex_array = sel[i].vertices
  # other code
end

It is dangerous to assume that the selection set contains only a certain class of object.
You should always filter it with grep, thus:

edges = sel.grep(Sketchup::Edge)

Lastly, You’d make your life easier if the spine was a curve object, that you could just iterate the edges it belongs to.


#4

Dan,
Thank you so much for your help.
My apologies for not formatting the code properly, uploading it as a text file instead of using an .rb extension and not indicating the error I was getting.
Learned a great deal from your comments. In particular the grep filter is a real gem.
Thank you


#5

Here is a little something for the benefit of the community, from the least-likely contributor (a novice).
I finally figured out what was preventing my atrocious code from accomplishing what I wanted. As inelegant, inefficient, redundant and … (feel free to add your own expletive) as it was, it should have been able to accomplish what I wanted it to do, if not for some very odd behavior exhibited by how Sketchup organizes the elements inside the selection array.

Starting from my initial edge selection (manually selected), my original code would find all the edges connected to the vertex with lowest z-value, since the middle (spine) edges were always descending, and choose the shortest one (the next vertebrae in the spine) to add to the selection. I incorrectly assumed that the entities in the selection array were organized based on the order in which they were selected (unless selected in bulk), more so if the entities were added to the selection programmatically (following a specific order). Turns out that is not the case at all. :confounded:

See the following forum discussion: http://sketchucation.com/forums/viewtopic.php?f=180&t=29869
In the discussion, you will find the following statement copied verbatim from the API docs: “the order of entities (selection[0], selection[1] and so on) in the set is in no particular order and should not be assumed to be in the same order as the user selected the entities.” Even the veterans in the discussion do not seem to agree on what is the principle, if any, governing how the entities in the selection array are organized. :anguished:

My code would assume that the last edge added to the selection array would be the last element in the array. Makes sense. Right? Wrong! Because of this odd behavior exhibited by how Sketchup organizes the elements inside the selection array, sometimes the last edge added would be placed somewhere else in the array. When my code would be looking for the last edge added to the selection in the selection array’s last position, instead it would find some other edge that was previously-added (prior to the last addition). Then, identifying the shortest edge connected to the lowest vertex of that previously-added edge would produce an edge that had been also previously-added to the selection. The selection array would not protest the addition of an entity already existing in the array without producing a warning or duplicates. As a result, the array would not grow in size. Therefore, in the next iteration the code would be looking for a position in the selection array that was one element higher than the array’s size, since the array did not grow in the last iteration because the addition of an already existing edge in the selection had been accepted by the selection array. In short, the code was looking for an index that was too high for the array’s size.

Hope this helps others.


#6

Most of the SketchUp API classes have the core Ruby library module Enumerable mixed in. See:
http://ruby-doc.org/core-2.2.4/Enumerable.html

In Ruby, when a module is “mixed-in” (via include,) that module then appears in the “mixee” object’s ancestor chain, as if it was a superclass.

Sketchup::Selection.ancestors
#=> [Sketchup::Selection, Enumerable, Object, ..., Kernel, BasicObject]

(Modules added by the JSON library omitted for brevity.)

The list of modules included appear at the top of a class’ API documentation page.


It is true, you cannot rely upon the order of the objects in the selection set.

Which is why I suggested using a curve object for the spine.


#7

Dan, you-da-man!!!
Thanks for spreading the knowledge.


#8

This topic was automatically closed after 91 days. New replies are no longer allowed.