【Rhino】【Python】Batch Update Attribute User Text Value from another object

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hmywillstronger

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值