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

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


参考资源

相关推荐
linux kernel2 小时前
第四部分:传输层
服务器·网络
ICT董老师2 小时前
通过OpenSSL 生成自签名证书
linux·运维·服务器·https·ssl
詹某某34112 小时前
什么是 IP SSL 证书?该如何申请
服务器·https·ssl
skywalk81632 小时前
cbsd的clonos/control-pane web管理页面一直闪烁和网页打开显示500error 的问题解决(500error问题未解决)
服务器·前端·freebsd·cbsd
2501_945837432 小时前
火山引擎边缘云服务器,AI+5G协同赋能实时场景
服务器
egoist20232 小时前
[linux仓库]线程池(单例模式)、线程安全与重入、死锁[线程·拾]
linux·单例模式·饿汉模式·懒汉模式·线程安全·死锁·重入问题
qq_192779872 小时前
将Python Web应用部署到服务器(Docker + Nginx)
jvm·数据库·python
weixin_436525072 小时前
若依多租户版 - modules中创建子模块
java·服务器·前端
亿牛云爬虫专家2 小时前
解析规则交给 AI,是效率提升还是系统隐患?
python·html·xpath·ai编程·爬虫代理·代理ip·解析规则