I have a Python script that I have written (with some help from ChatGPT) to replace a certain set of block instances with another set of block instances. A bit like BlockReplace, but for multiple blocks at the same time based on a specific naming scheme.
It works great and does what we need now, but there is one strange thing. Right at the last step where it places all the block instances, I have to click the Rhino viewport once or it does nothing and just sits there. It’s like Rhino needs to have focus again so it can complete the step.
Is this a known issue? Is there a remedy for this?
Here is my script:
import Rhino
import scriptcontext as sc
import rhinoscriptsyntax as rs
import os
################################## VARIABLES ##################################
# Specify the path to your cell set files directory
cell_set_dir = 'J:\\Studio JHH Dropbox\\JHH SERVER\\1_PROJEKTE\\119_Origin Infinite\\01_O-I_BIBLIOTHEKEN\\CELL SETS' # Replace with your actual directory path
################################## DEFINITIONS ##################################
def get_target_block_type():
"""Get the target block type."""
options = ['OG', 'RG', 'CNC', 'DIA']
target_block_type = rs.GetString("Select target block type",'CNC',options)
return target_block_type
def identify_unique_blocks(selected_instances):
"""Identify unique blocks in the selected instances."""
block_definitions = []
for instance in selected_instances:
block_name = rs.BlockInstanceName(instance)
block_definitions.append(block_name)
return list(set(block_definitions))
def form_target_block_names(block_definitions, target_block_type):
"""Form the names of the target blocks."""
target_block_names = []
for block_name in block_definitions:
components = block_name.split("_")
shortcode = components[0] # Extract the shortcode from the block name
number = components[-1]
inv_status = "_inv" in block_name
if inv_status:
number = number.replace("inv", "")
target_block_name = "{}_{}_inv_{}".format(shortcode, target_block_type, number)
else:
target_block_name = "{}_{}_{}".format(shortcode, target_block_type, number)
target_block_names.append(target_block_name)
return target_block_names, shortcode
def import_cell_set_file(cell_set_file):
"""Import the cell set file into the current document."""
cmd = '_-Import "{}" _Enter'.format(cell_set_file)
rs.Command(cmd)
def get_block_instances_and_transforms(block_name, selected_instances):
"""Get the selected instances and transforms of a block."""
block_instances = [instance for instance in selected_instances if rs.BlockInstanceName(instance) == block_name]
if not block_instances:
return []
transforms = []
for instance in block_instances:
rhobj = sc.doc.Objects.Find(instance)
if type(rhobj.Geometry) is Rhino.Geometry.InstanceReferenceGeometry:
iref = rhobj.Geometry
xform = iref.Xform
transforms.append(xform)
return transforms
def replace_block_instances(old_block_name, new_block_name, selected_instances):
"""Replace instances of a block with instances of a new block."""
if new_block_name not in rs.BlockNames():
print("Block {} does not exist.".format(new_block_name))
return
transforms = get_block_instances_and_transforms(old_block_name, selected_instances)
for instance, transform in zip(selected_instances, transforms):
new_instance = rs.InsertBlock2(new_block_name, transform)
old_instance_layer = rs.ObjectLayer(instance)
rs.ObjectLayer(new_instance, old_instance_layer)
# Hide the originally selected instances
def handle_original_objects(selected_instances, option):
"""Handle the original objects based on the user's selection."""
if option == "Delete":
rs.DeleteObjects(selected_instances)
elif option == "Hide":
rs.HideObjects(selected_instances)
# Leave does nothing, so we don't need an elif clause for that
################################## COMMAND ##################################
# Ask user to select instances
selected_instances = rs.GetObjects("Select instances to replace", rs.filter.instance)
if not selected_instances:
print("No instances selected. Exiting.")
exit()
# Get the target block type
target_block_type = get_target_block_type()
if not target_block_type:
print("No target block type specified. Exiting.")
exit()
# Identify unique blocks in the selected instances
block_definitions = identify_unique_blocks(selected_instances)
print("Found {} unique block definitions: {}".format(len(block_definitions), block_definitions))
# Form the names of the target blocks and extract shortcode
target_block_names, shortcode = form_target_block_names(block_definitions, target_block_type)
print("Formed {} target block names: {}".format(len(target_block_names), target_block_names))
# Check if target blocks exist in the document
missing_blocks = [block for block in target_block_names if block not in rs.BlockNames()]
cell_set_file = ''
if missing_blocks:
print("The following blocks do not exist in the document: {}".format(missing_blocks))
# Check if a file exists in the directory that matches the shortcode
cell_set_file = os.path.join(cell_set_dir, shortcode + '.3dm')
print(cell_set_file)
if not os.path.isfile(cell_set_file):
cell_set_file = rs.OpenFileName("Select the cell set file")
if cell_set_file:
import_cell_set_file(cell_set_file)
else:
print("No cell set file specified. Exiting.")
exit()
# Before replacing the instances, prompt the user to decide how to handle the original objects
handle_option = rs.GetString("Keep original cells?", "Delete", ["Delete", "Hide", "Keep"])
if not handle_option:
print("No action selected. Exiting.")
exit()
# Replace the instances of the unique blocks with instances of the target blocks
transform_count = 0
for old_block_name, new_block_name in zip(block_definitions, target_block_names):
old_transforms = get_block_instances_and_transforms(old_block_name, selected_instances)
replace_block_instances(old_block_name, new_block_name, selected_instances)
transform_count += len(old_transforms)
# Hide, delete or keep the original cell blocks
handle_original_objects(selected_instances, handle_option)
# Print success message
print("Successfully replaced {} instances".format(transform_count))
It get’s stuck basically at the third to last block where it replaces the blocks. No error messages are there and if I click the viewport it executes just fine.
Is there a way to give focus to Rhino again just before that step?
Thanks for any hints.