Batch Update Object Properties
Background
When working with engineering drawings in Rhino, it’s often necessary to associate text information with corresponding object properties. This tutorial demonstrates how to use RhinoScript Python to automatically capture text above objects and update their properties.
CASE 1: Fetch value from above(Y-direction) “Text” object
Ver.1
import rhinoscriptsyntax as rs
def update_pile_values():
try:
# Get preselected objects
objects = rs.GetObjects("Select objects to update PILE property", preselect=True)
if not objects: return
# Get text objects
text_objects = rs.ObjectsByLayer("PILE MARK")
if not text_objects:
print("No text found on PILE MARK layer")
return
count = 0
skipped = 0
# Disable redraw for better performance
rs.EnableRedraw(False)
# Process each object
for obj in objects:
# Get object bounding box
bbox = rs.BoundingBox(obj)
if not bbox: continue
# Calculate object center Y coordinate
obj_y = (bbox[0][1] + bbox[6][1])/2
# Find closest text above
closest_text = None
min_dist = float('inf')
for text in text_objects:
if not rs.IsText(text): continue
text_point = rs.TextObjectPoint(text)
if not text_point: continue
# Only consider text above the object
if text_point[1] <= obj_y: continue
# Calculate horizontal distance
dx = text_point[0] - (bbox[0][0] + bbox[6][0])/2
dz = text_point[2] - (bbox[0][2] + bbox[6][2])/2
dist = (dx*dx + dz*dz)**0.5
if dist < min_dist:
min_dist = dist
closest_text = text
# Update PILE property
if closest_text and min_dist < 100: # 100 is max distance limit
text_content = rs.TextObjectText(closest_text)
if rs.SetUserText(obj, "PILE", text_content):
count += 1
else:
skipped += 1
else:
skipped += 1
# Output results
print("Process completed:")
print("- Successfully updated: {} objects".format(count))
if skipped > 0:
print("- Skipped/Failed: {} objects".format(skipped))
except Exception as e:
print("Error occurred: {}".format(str(e)))
finally:
rs.EnableRedraw(True)
# Run function
update_pile_values()
Ver.20241210
import rhinoscriptsyntax as rs
def update_pile_values(max_distance=1000, min_vertical_offset=0):
"""
更新选中对象的PILE属性
max_distance: 最大搜索距离
min_vertical_offset: 最小垂直偏移量
"""
try:
# 检查图层
if not rs.IsLayer("PILE MARK"):
print("错误: 未找到'PILE MARK'图层")
return
# 获取预选对象
objects = rs.GetObjects("选择要更新PILE属性的对象", preselect=True)
if not objects:
print("未选择任何对象")
return
# 获取文本对象
text_objects = rs.ObjectsByLayer("PILE MARK")
if not text_objects:
print("在'PILE MARK'图层上未找到文本")
return
# 验证文本对象
valid_texts = []
for text in text_objects:
if rs.IsText(text) and rs.TextObjectText(text):
valid_texts.append(text)
if len(valid_texts) == 0:
print("未找到有效的文本对象")
return
# 初始化计数器
count = 0
skipped = 0
# 关闭重绘以提高性能
rs.EnableRedraw(False)
# 处理每个对象
for obj in objects:
try:
# 获取对象边界框
bbox = rs.BoundingBox(obj)
if not bbox:
print("跳过对象 {0}: 无法获取边界框".format(obj))
skipped += 1
continue
# 计算对象中心点
obj_point = (
(bbox[0][0] + bbox[6][0])/2,
(bbox[0][1] + bbox[6][1])/2,
(bbox[0][2] + bbox[6][2])/2
)
# 寻找最近的文本
closest_text = None
min_dist = float('inf')
for text in valid_texts:
text_point = rs.TextObjectPoint(text)
if not text_point: continue
# 计算垂直偏移(Y轴)
vertical_offset = text_point.Y - obj_point[1]
# 只考虑在对象上方的文本
if vertical_offset < min_vertical_offset: continue
# 计算平面距离(XY平面)
dist = ((text_point.X - obj_point[0])**2 +
(text_point.Y - obj_point[1])**2)**0.5
if dist < min_dist and dist < max_distance:
min_dist = dist
closest_text = text
# 更新PILE属性
if closest_text:
text_content = rs.TextObjectText(closest_text)
if rs.SetUserText(obj, "PILE", text_content):
count += 1
print("对象 {0} 已配对文本: {1} (距离: {2:.2f})".format(obj, text_content, min_dist))
else:
skipped += 1
print("对象 {0}: 无法设置PILE属性".format(obj))
else:
skipped += 1
print("对象 {0}: 未找到合适的文本 (最小距离: {1:.2f})".format(obj, min_dist))
except Exception as e:
print("处理对象 {0} 时出错: {1}".format(obj, str(e)))
skipped += 1
continue
# 输出结果
print("\n处理完成:")
print("- 成功更新: {0} 个对象".format(count))
if skipped > 0:
print("- 跳过/失败: {0} 个对象".format(skipped))
except Exception as e:
print("发生错误: {0}".format(str(e)))
finally:
rs.EnableRedraw(True)
# 运行函数
if __name__ == "__main__":
update_pile_values()
# CASE 2: Fetch value from below(Y-direction) “Text” object
#coding=utf-8
import rhinoscriptsyntax as rs
def update_pc_values():
try:
# Get objects
objects = rs.GetObjects("Select objects to update PC property", preselect=True)
if not objects: return
# Get text objects from PILE CAP MARK layer
text_objects = rs.ObjectsByLayer("PILE CAP MARK")
if not text_objects:
print("No text found on PILE CAP MARK layer")
return
count = 0
skipped = 0
# Disable redraw for better performance
rs.EnableRedraw(False)
# Process each object
for obj in objects:
# Get object bounding box
bbox = rs.BoundingBox(obj)
if not bbox: continue
# Calculate center point Y coordinate
obj_y = (bbox[0][1] + bbox[6][1])/2
# Find closest text below
closest_text = None
min_dist = float('inf')
for text in text_objects:
if not rs.IsText(text): continue
text_point = rs.TextObjectPoint(text)
if not text_point: continue
# Only consider text below the object
if text_point[1] >= obj_y: continue # Changed from <= to >=
# Calculate horizontal distance
dx = text_point[0