【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()

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


参考资源

相关推荐
孟健9 小时前
Karpathy 用 200 行纯 Python 从零实现 GPT:代码逐行解析
python
码路飞11 小时前
写了个 AI 聊天页面,被 5 种流式格式折腾了一整天 😭
javascript·python
曲幽13 小时前
FastAPI压力测试实战:Locust模拟真实用户并发及优化建议
python·fastapi·web·locust·asyncio·test·uvicorn·workers
chlk12316 小时前
Linux文件权限完全图解:读懂 ls -l 和 chmod 755 背后的秘密
linux·操作系统
舒一笑17 小时前
Ubuntu系统安装CodeX出现问题
linux·后端
改一下配置文件17 小时前
Ubuntu24.04安装NVIDIA驱动完整指南(含Secure Boot解决方案)
linux
敏编程17 小时前
一天一个Python库:jsonschema - JSON 数据验证利器
python
前端付豪17 小时前
LangChain记忆:通过Memory记住上次的对话细节
人工智能·python·langchain
databook18 小时前
ManimCE v0.20.1 发布:LaTeX 渲染修复与动画稳定性提升
python·动效
深紫色的三北六号1 天前
Linux 服务器磁盘扩容与目录迁移:rsync + bind mount 实现服务无感迁移(无需修改配置)
linux·扩容·服务迁移