Hello everyone, hope all is well in your respective worlds.
I am trying to make a selection of multiple components and their children unique. I started with this thread. The following code, as far as I can figure, should work. But it makes the wrong components unique (video) and I can’t figure out why!?!? . It’s the exact opposite result of what I want, how do I flip it? I have been poking at this for a while now and am out of ideas, any help is deeply appreciated.
The Video:
The Code:
# Makes (supposed to) an array of components and their children unique,
# with similar instances being made unique to one new definition.
def filter_instances(selection) # Grabs Groups and Components.
selection.grep(Sketchup::Group).concat(selection.grep(Sketchup::ComponentInstance))
end
def select_children(inst, family)
# Grab Groups and Components that are children - 2nd level.
children = filter_instances(inst.definition.entities)
# Add them to family array.
family.concat(children)
# Repeat with 2nd level to get 3rd level, etc...
children.each { |child| select_children(child, family) }
end
def make_all_unique()
model = Sketchup.active_model
selection = model.selection
parents = filter_instances(selection)
family = []
family.concat(parents)
parents.each { |inst| select_children(inst, family) }
cdefs = Hash.new # cdefs = {old_cdef: new_cdef}
family.each do |dc|
old_cdef = dc.definition
if cdefs.key?(old_cdef) # If the definition has already been made unique.
dc.definition = cdefs[old_cdef] # Replace the old definition with the new one.
else # If the instances' definition is not in the hash.
dc.make_unique # Make the instance unique, creating a new definition.
# Pair the new definition with the old definition in the cdefs hash.
new_cdef = dc.definition
cdefs[old_cdef] = new_cdef
end
end
end
make_all_unique()
Hope there isn’t a boulder in every post hole these days
Maybe this:
With this:
Code
def filter_instances(selection)
selection.grep(Sketchup::Group).concat(selection.grep(Sketchup::ComponentInstance))
end
def make_children_unique(inst)
children = filter_instances(inst.definition.entities)
children.each do |child|
child.make_unique
make_children_unique(child) # recurse deeper
end
end
def make_all_unique()
model = Sketchup.active_model
selection = model.selection
parents = filter_instances(selection)
return if parents.empty?
model.start_operation("Make Selected Unique", true)
\# Stage 1: make first parent unique
first = parents.shift
first.make_unique
new_parent_def = first.definition
\# Stage 2: reassign other selected parents to same new definition
parents.each { |inst| inst.definition = new_parent_def }
\# Stage 3: inside the new parent definition, make children unique
make_children_unique(first)
model.commit_operation
end
make_all_unique()
OK so with a little help from James @3DxJFD I have it figured out I think. The secret sauce was sorting all of the collected instances first.
def filter_instances(selection) # Grabs Groups and Components.
selection.grep(Sketchup::Group).concat(selection.grep(Sketchup::ComponentInstance))
end
def select_children(inst, family)
# Grab Groups and Components that are children - 2nd level.
children = filter_instances(inst.definition.entities)
# Add them to family array.
family.concat(children)
# Recurse deeper collecting all selected instances.
children.each { |child| select_children(child, family) }
end
def make_all_unique()
model = Sketchup.active_model
sel = model.selection
parents = filter_instances(sel)
family = []
family.concat(parents)
parents.each { |inst| select_children(inst, family) }
# Collect instances by their definitions.
groupt = family.group_by { |inst| inst.definition }
groupt.each_value do |array|
# Make the first instance of each collection unique.
first = array.shift
first.make_unique
new_cdef = first.definition
# Assign the remaining instances to the new definition.
array.each do |inst|
inst.definition = new_cdef
end
end
end