Hi. I am attempting to create a tool in which the user selects some geometry. I want to include a method in which all faces that are connected with soft edges get selected at once when one of the faces is selected. I have a method which does that using all_connected. I can collect the faces and store them in @entities for example. However I also want to add the selection visually so that the user can see which elements are selected. What I am finding is that when I implement a method that tries to get all_connected from the input more than one face or edge will not be selectable from a set of connected geometry. The elements get saved to my @entities collection but the visual selection only shows the last selection. The visual selection does work for elements that are not connected. This happens irregardless of whether the there are soft edges or not.
Here is a simplified version which demonstrates the problem:
def onLButtonDown(flags, x, y, view)
@pickhelper.do_pick(x, y)
input = @pickhelper.best_picked
get_entities(input)
view.invalidate
end
def get_entities(input)
if test(input)
puts "test " + test(input).to_s
end
@entities << input
puts @entities.to_s
@model.selection.add(input)
end
def test(input)
x = input.all_connected
true
end
I added the unless condition as you recommend. As for clearing the selection I am doing that in the reset tool.
I have a shift deselect code also, and all together it works well as long as I do not implement any method that that uses .all_connected.
I contrived a workaround that is so far so good. I wrote my own method to find all connected faces.
This is the input collection method currently, which is working
def get_entities(value, view)
Sketchup.status_text = 'select items to skew, press enter to complete selection...1'
if @picked == true and value_unlocked?(value)
unless @entities.include?(value)
if value.class == Sketchup::Face
if is_surface?(value)
puts "is_surface? " + is_surface?(value).to_s
value = get_surface(value)
value.each{|e| @model.selection.add(e)}
value.each{|e| @entities << e}
end
end
@entities << value
@model.selection.add(value)
else
if @shift_is_pressed == true
puts "shift is pressed"
# deselect when shift is pressed..
# but not if it isn't already selected...
if @entities.include?(value)
if is_surface?(value)
value = get_surface(value)
value.each{|e| @model.selection.remove(e)}
else
@model.selection.remove(value) unless value == nil
@entities.delete(value) unless value == nil
end
else
if is_surface?(value)
puts "is_surface? " + is_surface?(value).to_s
value = get_surface(value)
value.each{|e| @model.selection.add(e)}
value.each{|e| @entities << e}
else
@model.selection.add(value)
@entities << value
end
end
end
end
elsif @picked == false
unless @resume == true
Sketchup.status_text = 'Nothing got selected, try again or press enter to complete selection'
end
elsif @picked == true and value_unlocked?(value) == false
unless @resume == true
@model.selection.add(value)
Sketchup.status_text = 'selection is locked. please make a different selection.'
end
end
@picked = false
@resume = false
puts "@entities " + @entities.to_s
end
I will try to state the issue I was having more succinctly. Say there are several assemblies of face and edges in the model. Each is connected internally but they are not connected to each other. Say I do a pick, using the tool as summarized in my first post. So when the mouse button is pressed and the cursor is over a face or an edge, the tool will save that element to an array and should highlight the element in the model. When the pick is made the tool will also define x = input.all_connected. To no purpose in the example, but just to show that it happened. On the first pick all is good, the selection is highlighted and the element is saved. On the next pick, if the pick is on the same assembly of faces, the previous selection will be deselected and only the current selection will be highlighted. If the pick is on another assembly of faces, ( and or edges ), the first pick will remain highlighted, as well as the second pick. However when I comment out the test method, which runs .all_connected, I can pick from the same assembly of elements and the previous highlighting will not be deselected. In either case the array of saved elements is appended with each subsequent pick. To my inexperienced eye this seems like an out of scope situation. What ever happens in the test method should not be influencing what happens outside of it.
This is how I did my own version of .all_connected . But I am sure there is a slicker way (hint, hint)
def get_connected_faces(face)
# get all the connected faces that have soft edges
mod = Sketchup.active_model
ents = mod.entities
search_set = ents.find_all{|e| e.class == Sketchup::Face}
search_set.delete_if{|f| f == face}
connected = [face]
# get the first batch of adjacent soft faces
adjacent_next = adjacent_next([face], search_set)
# collect the newfound adjacent soft faces
adjacent_next.each{|face| connected << face}
# purge the search set
for f in adjacent_next
search_set.delete_if{|face| face == f}
end
# count the newfound adjacent soft faces
find_count = adjacent_next.length
# collect again until no new candidates are found
count = 0
until (find_count == 0) or (count == search_set.length)
found_set = adjacent_next
adjacent_next = adjacent_next(found_set, search_set)
adjacent_next.each{|face| connected << face}
# purge the search set
for f in adjacent_next
search_set.delete_if{|face| face == f}
end
find_count = adjacent_next.length
count += 1
end
connected
end
def adjacent_next(found_set, search_set)
adjacent_next = []
for face in found_set
edges = face.edges
contiguous_faces = []
for edge in edges
contiguous_faces << search_set.find_all{|face| face.edges.include?(edge)}
end
contiguous_faces = contiguous_faces.flatten.uniq
contiguous_faces.delete_if{|f| f == face}
contiguous_faces.each{|e|adjacent_next << e}
end
adjacent_next = adjacent_next.uniq
end