【Rhino】【Python】对包含特定关键词的文字的MTEXT对象添加指定内容

本文通过一个实际案例------批量为图纸中的文字添加 "(U.S.S.)" 后缀,来介绍 Rhino Python 中文字对象的读取与修改方法。


1. 案例需求

在结构图纸中,需要为钢构件标注添加 "(U.S.S.)"(Unless Otherwise Specified)后缀,但要排除以下情况:

  • 包含特定关键词的文字(如 BASE PLATE、GROUT 等)
  • 已经有后缀的文字

2. 代码结构总览

python 复制代码
#coding=utf-8
import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc

# 1. 定义配置
skip_keywords = [...]

# 2. 获取所有对象
all_objects = rs.AllObjects()

# 3. 遍历并筛选文字对象
for obj_id in all_objects:
    if rs.ObjectType(obj_id) == 512:
        # 4. 读取文字内容
        # 5. 判断是否需要修改
        # 6. 修改文字

# 7. 刷新视图
sc.doc.Views.Redraw()

3. 关键概念

3.1 rs vs Rhino vs sc

模块 层级 适用场景
rhinoscriptsyntax (rs) 高级封装 日常操作,语法简洁
Rhino RhinoCommon API 需要精细控制时使用
scriptcontext (sc) 文档上下文 访问当前文档、修改对象属性

为什么这个案例需要用 Rhinosc

rs 模块没有提供直接修改 MText 内容的函数,必须通过 RhinoCommon 来操作。


4. 文字对象操作详解

4.1 识别文字对象

python 复制代码
obj_type = rs.ObjectType(obj_id)

if obj_type == 512:  # Annotation 类型
    # 这是标注类对象(包括文字、尺寸标注等)

4.2 获取底层几何对象

python 复制代码
rhino_obj = sc.doc.Objects.Find(obj_id)
geom = rhino_obj.Geometry
对象 说明
obj_id GUID,对象的唯一标识符
rhino_obj RhinoObject,包含几何和属性
geom GeometryBase,纯几何信息

4.3 判断是否为文字实体

python 复制代码
if isinstance(geom, Rhino.Geometry.TextEntity):
    # 确认是文字对象

TextEntity 是 Rhino 中表示文字的几何类型,包括:

  • 单行文字 (Text)
  • 多行文字 (MText)

4.4 读取文字内容

python 复制代码
old_text = geom.PlainText
属性 说明
PlainText 纯文本内容,不含格式
RichText 富文本,包含格式代码

4.5 修改文字内容

python 复制代码
geom.PlainText = new_text
rhino_obj.CommitChanges()

⚠️ 重要 : 修改几何属性后必须调用 CommitChanges() 才能生效!


5. 字符串处理技巧

5.1 大小写转换

python 复制代码
text_upper = old_text.upper()  # 转大写
text_lower = old_text.lower()  # 转小写

用于不区分大小写的比较。

5.2 关键词检查

python 复制代码
skip_keywords = ["BASE PLATE", "CAST-IN", "GROUT"]

should_skip = False
for keyword in skip_keywords:
    if keyword in text_upper:
        should_skip = True
        break

更简洁的写法:

python 复制代码
should_skip = any(keyword in text_upper for keyword in skip_keywords)

5.3 检查子字符串

python 复制代码
if "(U.S.S.)" in old_text:
    # 已包含后缀

5.4 字符串拼接

python 复制代码
new_text = old_text + "(U.S.S.)"

6. 对象修改的完整流程

复制代码
┌─────────────────┐
│   rs.AllObjects()   │  获取对象 ID 列表
└────────┬────────┘
         ▼
┌─────────────────┐
│ sc.doc.Objects.Find() │  获取 RhinoObject
└────────┬────────┘
         ▼
┌─────────────────┐
│  rhino_obj.Geometry   │  获取几何对象
└────────┬────────┘
         ▼
┌─────────────────┐
│   修改属性值         │  geom.PlainText = ...
└────────┬────────┘
         ▼
┌─────────────────┐
│ rhino_obj.CommitChanges() │  提交修改
└────────┬────────┘
         ▼
┌─────────────────┐
│ sc.doc.Views.Redraw()    │  刷新视图
└─────────────────┘

7. 文字对象的其他属性

7.1 读取属性

python 复制代码
# 文字高度
height = geom.TextHeight

# 对齐方式
justification = geom.Justification

# 字体
font = geom.Font.FamilyName

# 插入点
plane = geom.Plane
insertion_point = plane.Origin

7.2 修改属性

python 复制代码
# 修改文字高度
geom.TextHeight = 2.5

# 修改后必须提交
rhino_obj.CommitChanges()

8. 对齐方式详解

python 复制代码
justification = geom.Justification
说明
TextJustification.Left 左对齐
TextJustification.Center 居中
TextJustification.Right 右对齐
TextJustification.TopLeft 左上
TextJustification.BottomCenter 底部居中
... 共 9 种组合

9. 使用 rs 模块的替代方案

对于简单的文字操作,也可以用 rs 模块:

9.1 创建文字

python 复制代码
text_id = rs.AddText("Hello", [0, 0, 0], height=2.5)

9.2 读取文字内容

python 复制代码
text = rs.TextObjectText(text_id)

9.3 修改文字内容

python 复制代码
rs.TextObjectText(text_id, "New Text")

注意 : rs.TextObjectText() 对某些复杂的 MText 可能不生效,此时需要用 RhinoCommon 方法。


10. 错误处理

10.1 检查 None

python 复制代码
rhino_obj = sc.doc.Objects.Find(obj_id)
if rhino_obj:  # 确保对象存在
    geom = rhino_obj.Geometry

10.2 检查文字内容

python 复制代码
old_text = geom.PlainText
if old_text:  # 确保文字不为空
    # 处理文字

10.3 Try-Except 包裹

python 复制代码
try:
    geom.PlainText = new_text
    rhino_obj.CommitChanges()
    count += 1
except Exception as e:
    print("修改失败: {}".format(e))

11. 性能优化

11.1 批量操作时关闭重绘

python 复制代码
rs.EnableRedraw(False)

# 批量操作...
for obj_id in all_objects:
    # 修改对象

rs.EnableRedraw(True)
sc.doc.Views.Redraw()

11.2 使用对象过滤器

python 复制代码
# 只获取 Annotation 类型的对象
annotations = rs.ObjectsByType(512)

比获取所有对象后再筛选更高效。


12. 完整代码解析

python 复制代码
#coding=utf-8
import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc

# 配置:不需要添加后缀的关键词
skip_keywords = ["BASE PLATE", "CAST-IN", "IN-SITU", 
                 "EMBEDDED", "GROUT", "SHIM"]

# 获取所有对象
all_objects = rs.AllObjects()

count = 0

if all_objects:
    for obj_id in all_objects:
        obj_type = rs.ObjectType(obj_id)
        
        # 筛选 Annotation 类型
        if obj_type == 512:
            rhino_obj = sc.doc.Objects.Find(obj_id)
            
            if rhino_obj:
                geom = rhino_obj.Geometry
                
                # 确认是文字对象
                if isinstance(geom, Rhino.Geometry.TextEntity):
                    old_text = geom.PlainText
                    
                    if old_text:
                        text_upper = old_text.upper()
                        
                        # 检查是否应该跳过
                        should_skip = any(kw in text_upper 
                                         for kw in skip_keywords)
                        
                        # 检查是否已有后缀
                        if "(U.S.S.)" in old_text:
                            should_skip = True
                        
                        # 执行修改
                        if not should_skip:
                            geom.PlainText = old_text + "(U.S.S.)"
                            rhino_obj.CommitChanges()
                            count += 1

sc.doc.Views.Redraw()
print("完成!修改了 {} 个 MText".format(count))

13. 扩展应用

13.1 批量替换文字

python 复制代码
geom.PlainText = old_text.replace("OLD", "NEW")

13.2 添加前缀

python 复制代码
geom.PlainText = "PREFIX-" + old_text

13.3 根据图层筛选

python 复制代码
layer = rs.ObjectLayer(obj_id)
if layer == "TEXT":
    # 只处理 TEXT 图层的对象

13.4 统计文字内容

python 复制代码
text_dict = {}
for obj_id in all_objects:
    if rs.ObjectType(obj_id) == 512:
        rhino_obj = sc.doc.Objects.Find(obj_id)
        if rhino_obj:
            geom = rhino_obj.Geometry
            if isinstance(geom, Rhino.Geometry.TextEntity):
                text = geom.PlainText
                text_dict[text] = text_dict.get(text, 0) + 1

for text, count in text_dict.items():
    print("{}: {}".format(text, count))

14. 常见问题

Q: 为什么 rs.TextObjectText() 不起作用?

A: 某些复杂的多行文字(MText)需要用 RhinoCommon 的 TextEntity.PlainText 来操作。

Q: 修改后看不到变化?

A: 确保调用了 rhino_obj.CommitChanges()sc.doc.Views.Redraw()

Q: 如何撤销脚本的修改?

A: 在脚本开头添加 rs.EnableRedraw(False),结束时 rs.EnableRedraw(True)。这样整个操作会被记录为一次撤销步骤。


总结

文字对象处理的核心流程:

  1. 获取对象rs.AllObjects()rs.ObjectsByType(512)
  2. 转换为 RhinoObjectsc.doc.Objects.Find(obj_id)
  3. 获取几何rhino_obj.Geometry
  4. 类型检查isinstance(geom, Rhino.Geometry.TextEntity)
  5. 读写文字geom.PlainText
  6. 提交修改rhino_obj.CommitChanges()
  7. 刷新视图sc.doc.Views.Redraw()

掌握这个流程,就能实现各种文字批量处理任务。


参考资源

相关推荐
小草cys10 小时前
在 openEuler 上安装 DDE 图形桌面环境(适用于华为鲲鹏服务器/PC)
运维·服务器
天才奇男子18 小时前
HAProxy高级功能全解析
linux·运维·服务器·微服务·云原生
学嵌入式的小杨同学18 小时前
【Linux 封神之路】信号编程全解析:从信号基础到 MP3 播放器实战(含核心 API 与避坑指南)
java·linux·c语言·开发语言·vscode·vim·ux
酥暮沐18 小时前
iscsi部署网络存储
linux·网络·存储·iscsi
❀͜͡傀儡师19 小时前
centos 7部署dns服务器
linux·服务器·centos·dns
好家伙VCC19 小时前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
Dying.Light19 小时前
Linux部署问题
linux·运维·服务器
S190119 小时前
Linux的常用指令
linux·运维·服务器
小义_19 小时前
【RH134知识点问答题】第7章 管理基本存储
linux·运维·服务器
前端玖耀里20 小时前
如何使用python的boto库和SES发送电子邮件?
python