rhino二次开发

这是本文档旧的修订版!


Rhino 7 二次开发教程

本文档使用 DokuWiki 语法编写,面向希望在 Rhino 7 中开发企业级插件、自动化工具和工程数据管线的开发者。主线技术为 RhinoCommon、C#、Rhino 命令系统、Eto.Forms、文件读写和插件发布。文档中的示例代码用于说明开发结构,实际项目应结合本机 Rhino 7、插件模板和官方 API 文档验证。

Rhino 7 二次开发的核心目标,是把人工建模步骤、企业规则、几何算法和数据交换流程封装成稳定工具。对于建筑、结构、幕墙、造价、工业设计或数字建造团队来说,Rhino 不是单纯的绘图软件,而是一个可扩展的三维几何平台。开发者可以通过 RhinoCommon、Rhino.Python、Grasshopper 组件、Eto UI、文件读写和包管理工具,把重复工作变成命令,把规则判断变成可审计代码,把跨软件的数据流变成可维护工程。

本教程以 Rhino 7 为主线,默认读者会使用 C#,了解基本面向对象编程,并能阅读 Rhino 界面中的命令行反馈。教程不会把每一个 API 枚举逐条抄写,而是围绕真实插件工程的路径展开:创建项目、编写命令、选择对象、构造几何、写入模型、显示预览、构建面板、导入导出、打包发布和维护升级。读完后,读者应能独立搭建一个 Rhino 7 插件,并把它扩展为企业内部工具集。

方向 适用场景 主要技术 典型成果
RhinoCommon 插件 长期维护、多人使用、需要发布安装 C#、.NET Framework 4.8、RHP 命令、面板、自动建模工具
Rhino.Python 脚本 快速验证、个人工具、批处理 Python、rhinoscriptsyntax、RhinoCommon 脚本命令、数据清洗、模型检查
Grasshopper 组件 参数化流程、设计推敲、算法原型 C# Script、GH SDK、RhinoCommon 自定义组件、参数化节点
外部数据管线 BIM、造价、数据库、Web 服务对接 JSON、CSV、SQLite、REST 模型属性同步、工程量表
  • Rhino 版本:Rhino 7,重点讨论 RhinoCommon 插件开发。
  • 开发语言:C#,示例以 Visual Studio 项目结构为基础。
  • 运行时:Rhino 7 插件面向 .NET Framework 4.8,而不是 Rhino 8 中常见的 .NET 7 路径。
  • 系统环境:Windows 是主要讲解环境;跨平台 UI 部分使用 Eto.Forms 的通用思路。
  • 工程目标:示例偏向建筑结构与造价工具,但几何、对象表和交互方法适用于多数 Rhino 插件。

二次开发的第一个误区,是把所有问题都看成“怎么调某个命令”。Rhino 的命令行确实强大,很多手动操作也可以用命令字符串重放,但插件工程更重要的是掌握对象模型:文档保存了对象,对象拥有几何和属性,视图负责显示,命令负责一次可撤销的交互流程。当工具变复杂时,直接拼接命令字符串会难以维护;使用 RhinoCommon 直接访问几何和文档对象,才能获得可测试、可组合、可扩展的结构。

RhinoCommon 是 Rhino 的 .NET SDK。它提供几何类型、文档对象、命令、显示管线、文件读写、UI 对接等能力。在 C# 插件中,`Rhino.Geometry.Point3d`、`Curve`、`Brep`、`Mesh` 等类型用于表达几何;`Rhino.RhinoDoc` 表示当前模型文档;`Rhino.DocObjects.ObjectAttributes` 表示对象名称、图层、颜色和用户字符串等属性;`Rhino.Commands.Command` 定义可被 Rhino 命令行调用的插件命令。

理解 RhinoCommon 的关键,是把“纯几何”和“文档对象”分开。一个 `Curve` 只是内存中的曲线,它可以被计算、复制、变换和分析;当它通过 `doc.Objects.AddCurve()` 写入文档后,Rhino 会创建一个拥有 Guid、属性、图层和撤销记录的文档对象。很多初学者在这一步混淆对象:修改了内存曲线,却没有替换文档对象;或者拿到了对象引用,却忘记提交变更并刷新视图。

一个最小 RhinoCommon 命令通常继承 `Command`,实现 `EnglishName`,并覆盖 `RunCommand`。命令的返回值不是普通布尔值,而是 `Result`,用于告诉 Rhino 此次命令成功、失败、取消或发生其他状态。这使插件命令能够融入 Rhino 的命令行、撤销栈和脚本运行机制。

using Rhino;
using Rhino.Commands;
 
namespace CostRhinoTools
{
  public class HelloRhinoCommand : Command
  {
    public override string EnglishName => "CostHelloRhino";
 
    protected override Result RunCommand(RhinoDoc doc, RunMode mode)
    {
      RhinoApp.WriteLine("Hello Rhino 7 secondary development.");
      RhinoApp.WriteLine($"Active model unit: {doc.ModelUnitSystem}");
      return Result.Success;
    }
  }
}

这个示例本身不复杂,但它展示了 Rhino 插件的三个基本事实:命令由 Rhino 调用,命令持有当前 `RhinoDoc`,命令通过 `RhinoApp.WriteLine` 向命令行写反馈。在生产工具中,所有复杂逻辑都应从这样的入口继续向外分层,而不是把几百行业务逻辑全部塞进 `RunCommand`。

开发路径规划 的开发视角

在 Rhino 7 二次开发中,开发路径规划 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Rhino.Commands`、`Rhino.RhinoDoc` 与 `Rhino.Geometry` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,先用小命令验证 API,再把可复用逻辑抽取到服务类,最后补充 UI、配置和打包。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把 Rhino 命令当作普通桌面程序入口,忽略撤销、取消和文档状态。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:写一个只输出当前单位、对象数量和当前图层名称的命令,然后把输出逻辑抽到单独类中。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

Rhino 7 插件开发的环境搭建不只是安装 Visual Studio。真正影响后续效率的是项目模板、调试启动程序、引用版本、输出路径、命令命名和日志方式。如果这些基础没有整理好,开发者会在“插件加载失败”“找不到命令”“代码已改但 Rhino 没变化”“依赖 DLL 丢失”等问题上反复耗时。

项目 建议 原因
Rhino Rhino 7 正式版 本教程围绕 Rhino 7 行为和插件运行时展开
Visual Studio Visual Studio 2019 或 2022 可使用 C# 项目、调试器和 NuGet 管理
.NET .NET Framework 4.8 Rhino 7 RhinoCommon 插件的主要目标框架
语言 C# 7.x/8.x 可用子集 兼顾 Rhino 7 项目兼容性与团队维护
版本控制 Git 或企业内部代码库 插件工程需要可追踪发布和回滚

开发时应把 RhinoCommon 引用的来源和版本固定下来。常见方式包括使用 Rhino 安装目录中的 RhinoCommon.dll,或通过官方模板与 NuGet 方式建立项目。团队项目要避免每个人手动引用不同机器上的 DLL 路径。更稳妥的做法,是把项目文件中的引用策略写进 README,并在新成员入职时用同一套模板创建工程。

一个可维护的 Rhino 插件项目通常不应只有一个 `Commands` 文件夹。命令只是入口,真正的业务逻辑应落在独立层。下面的结构适合中小型企业内部工具集;大型项目可以继续拆分为多个类库。

CostRhinoTools/
  CostRhinoTools.csproj
  Plugin/
    CostRhinoToolsPlugin.cs
  Commands/
    CostHelloRhinoCommand.cs
    CostAddReferencePointCommand.cs
  Geometry/
    CurveAnalysisService.cs
    BrepCreationService.cs
  Document/
    LayerService.cs
    AttributeService.cs
  UI/
    RuleSettingsDialog.cs
    CostPanel.cs
  IO/
    CsvExporter.cs
    JsonRuleLoader.cs
  Tests/
    GeometryUtilityTests.cs

这种组织的原则很简单:命令层负责和 Rhino 用户交互,服务层负责业务计算,文档层负责对象读写,UI 层负责显示与配置,IO 层负责外部数据。当命令需要修改时,开发者能够迅速定位入口;当几何算法需要测试时,又不必启动 Rhino 才能阅读核心逻辑。

调试 Rhino 插件时,通常把项目的调试启动程序设置为 Rhino.exe。启动后在 Rhino 中加载当前编译出的插件,再运行命令即可命中断点。如果插件已经被 Rhino 加载,重新编译可能因为 DLL 被占用而失败。开发阶段可以关闭 Rhino 后重新编译,或者使用不同输出目录和自动复制策略。

  • 在项目属性中设置外部启动程序为 Rhino 7 的 `Rhino.exe`。
  • 在命令类的 `RunCommand` 中设置断点,确认 Rhino 能进入调试器。
  • 用 `RhinoApp.WriteLine` 输出轻量日志,避免开发早期引入复杂日志系统。
  • 插件加载失败时先看 Rhino 命令行和 Visual Studio 输出窗口。
  • 调试几何算法时尽量把算法拆成无 Rhino UI 依赖的方法,便于单元测试。

Rhino 插件命令的英文名要稳定、唯一、可脚本化。建议给企业工具统一前缀,例如 `Cost`、`Struct` 或项目缩写。不要把命令名设计成容易和 Rhino 原生命令冲突的短词,也不要频繁改名,因为团队成员的脚本、按钮和文档可能已经引用这些命令。

using Rhino;
using Rhino.Commands;
using Rhino.Geometry;
 
namespace CostRhinoTools
{
  public class AddReferencePointCommand : Command
  {
    public override string EnglishName => "CostAddReferencePoint";
 
    protected override Result RunCommand(RhinoDoc doc, RunMode mode)
    {
      var point = new Point3d(0, 0, 0);
      var id = doc.Objects.AddPoint(point);
      if (id == System.Guid.Empty)
        return Result.Failure;
 
      doc.Views.Redraw();
      RhinoApp.WriteLine($"Created reference point: {id}");
      return Result.Success;
    }
  }
}

上例展示了最小的文档写入流程。代码创建一个 `Point3d`,通过 `doc.Objects.AddPoint` 写入当前文档,然后刷新视图。如果返回的 Guid 为空,说明对象没有成功写入。生产代码还会补充图层、名称、用户字符串、撤销语义和错误提示。

项目引用 的开发视角

在 Rhino 7 二次开发中,项目引用 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `RhinoCommon.dll`、目标框架和插件输出目录 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,建立项目后先运行最小命令,再逐步添加业务依赖,确保每一次依赖变化都能解释。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 复制旧项目时保留了错误的本机路径,导致其他开发机无法编译。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:在一台新环境上从零编译插件,并记录所有必须安装的组件。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

调试流程 的开发视角

在 Rhino 7 二次开发中,调试流程 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `RhinoApp.WriteLine`、Visual Studio 断点和 Rhino 命令行 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,先用命令行输出确认命令执行,再用断点观察对象引用、几何返回值和异常位置。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 只看界面现象,不读取命令返回值和异常信息。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:故意传入一个无效参数,观察命令如何返回 `Result.Failure` 或 `Result.Cancel`。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

目录分层 的开发视角

在 Rhino 7 二次开发中,目录分层 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Commands`、`Geometry`、`Document`、`UI` 与 `IO` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,让命令层尽可能薄,把业务计算放到普通 C# 类中,减少 Rhino UI 对算法的污染。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把选择、计算、写入、界面弹窗全部写在一个命令文件中。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:重构一个示例命令,把几何构造方法移动到 `Geometry` 文件夹下。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

Rhino 的命令系统是插件和用户之间最稳定的协议。一个好命令不只是“能运行”,还应该能被用户取消、能被脚本调用、能在预选对象上工作、能给出清晰提示,并且在失败时不污染模型。命令设计的质量,通常比单个几何算法更直接影响用户体验。

`RunCommand` 是每次命令执行的主入口。Rhino 会传入当前文档和运行模式。命令可以读取文档、询问用户、创建对象、打开对话框,也可以只做分析输出。命令结束时返回 `Result.Success`、`Result.Failure`、`Result.Cancel` 等状态。这个返回值会影响命令行记录,也会影响脚本调用者对命令是否成功的判断。

返回值 含义 建议使用场景
`Result.Success` 命令完成 输入有效、计算成功、写入成功
`Result.Cancel` 用户取消 按 Esc、取消选择、关闭对话框
`Result.Failure` 命令失败 数据无效、写入失败、无法恢复的异常
`Result.Nothing` 没有有效操作 可选输入为空且命令允许不处理

对象选择是 Rhino 插件最常见的输入形式。`GetObject` 允许设置提示文字、几何过滤器、是否允许预选、是否允许子对象等。选择后得到的通常是 `ObjRef`,开发者再从 `ObjRef` 中取出 Curve、Brep、Mesh 或 RhinoObject。

using Rhino;
using Rhino.Commands;
using Rhino.DocObjects;
using Rhino.Input.Custom;
 
namespace CostRhinoTools
{
  public class SelectCurveCommand : Command
  {
    public override string EnglishName => "CostSelectCurve";
 
    protected override Result RunCommand(RhinoDoc doc, RunMode mode)
    {
      var go = new GetObject();
      go.SetCommandPrompt("选择一条曲线");
      go.GeometryFilter = ObjectType.Curve;
      go.EnablePreSelect(true, true);
      go.Get();
 
      if (go.CommandResult() != Result.Success)
        return go.CommandResult();
 
      var objRef = go.Object(0);
      var curve = objRef.Curve();
      if (curve == null)
        return Result.Failure;
 
      RhinoApp.WriteLine($"Curve length: {curve.GetLength():F3}");
      return Result.Success;
    }
  }
}

注意示例中没有直接假设用户一定会选择曲线。代码先检查 `CommandResult`,再从 `ObjRef` 取曲线,并判断是否为空。这类防御式写法很重要,因为真实用户会预选错误对象、取消命令,或在运行过程中切换视图和对象状态。

很多 Rhino 原生命令都支持命令行选项,例如开关、距离、模式和枚举。插件命令也应遵循这种交互习惯。相比一开始就弹出复杂窗口,命令行选项更适合快速工具和脚本化流程;它还能被历史记录复用,适合工程批处理。

using Rhino;
using Rhino.Commands;
using Rhino.Input.Custom;
 
namespace CostRhinoTools
{
  public class OptionDemoCommand : Command
  {
    public override string EnglishName => "CostOptionDemo";
 
    protected override Result RunCommand(RhinoDoc doc, RunMode mode)
    {
      var preview = new OptionToggle(true, "Off", "On");
      var offset = new OptionDouble(100.0, 0.0, double.MaxValue);
 
      var get = new GetOption();
      get.SetCommandPrompt("设置偏移分析参数");
      get.AddOptionToggle("Preview", ref preview);
      get.AddOptionDouble("Offset", ref offset);
 
      while (true)
      {
        var result = get.Get();
        if (result == GetResult.Option)
        {
          RhinoApp.WriteLine($"Preview={preview.CurrentValue}, Offset={offset.CurrentValue}");
          continue;
        }
        if (result == GetResult.Nothing)
          break;
        return get.CommandResult();
      }
 
      return Result.Success;
    }
  }
}

`GetOption` 的关键是循环。用户每次修改一个选项,命令都可以输出当前状态或更新预览;当用户按回车或完成输入时,命令才进入真正执行阶段。对于需要交互预览的工具,可以把选项读取和显示管线结合,做到参数变化时即时刷新。

点输入 的开发视角

在 Rhino 7 二次开发中,点输入 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Rhino.Input.Custom.GetPoint` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,让用户在视图中拾取基准点,必要时约束到平面、线或对象。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 忽略用户取消,导致后续代码使用未初始化点。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:做一个拾取矩形左下角和右上角后生成闭合曲线的命令。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

距离输入 的开发视角

在 Rhino 7 二次开发中,距离输入 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `GetNumber`、`OptionDouble` 和模型单位 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,把用户输入解释为当前模型单位下的数值,显示时注明单位含义。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 在毫米模型和米模型之间复用硬编码数值。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:写一个输入高度后拉伸闭合曲线的命令,并测试不同单位文件。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

预选支持 的开发视角

在 Rhino 7 二次开发中,预选支持 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `EnablePreSelect` 与 `GetObject` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,先接受用户已选对象,再允许命令内继续选择,减少重复操作。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 强制用户重新选择已经选中的对象,破坏 Rhino 使用习惯。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:让长度统计命令同时支持预选曲线和命令内选择曲线。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

取消处理 的开发视角

在 Rhino 7 二次开发中,取消处理 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `CommandResult` 与 `Result.Cancel` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,每一次输入后都检查状态,用户取消时立即返回,不再修改文档。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 捕获取消后继续执行默认值,造成意外建模结果。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:在多步命令中逐步按 Esc,确认模型没有被部分写入。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

脚本化输入 的开发视角

在 Rhino 7 二次开发中,脚本化输入 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 命令英文名、选项名称和 `RunMode` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,保持命令名和选项名稳定,使批处理脚本能够可靠调用。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 频繁改选项文字,导致历史脚本失效。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:为一个命令写出可复制的命令行调用示例。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

Rhino 模型不是一个简单的几何列表。每个文档对象都包含几何、属性、图层、材质、显示状态、用户字符串和唯一标识。二次开发如果只关心几何形状,会很快遇到管理问题:对象找不到、分类丢失、图层混乱、导出数据没有来源。因此,本章把 `RhinoDoc`、对象表和属性作为核心内容。

`RhinoDoc` 表示当前打开的模型文档。它提供对象表、图层表、视图集合、单位设置、材质表、命名视图等入口。命令方法收到的 `doc` 参数通常就是插件最重要的上下文。除非明确处理多文档或后台文件,初学者不应随意缓存 `RhinoDoc` 的长期引用。

成员方向 常见入口 用途
对象 `doc.Objects` 新增、查找、替换、删除、选择文档对象
图层 `doc.Layers` 创建图层、设置当前图层、读取层级
视图 `doc.Views` 刷新显示、访问活动视图
单位 `doc.ModelUnitSystem` 理解当前模型长度单位
字符串 `doc.Strings` 保存插件级文档元数据

`ObjectAttributes` 是工程插件非常重要的类型。通过它可以设置对象名称、图层索引、颜色来源、线型、打印宽度、用户字符串等。如果插件要服务造价、结构或 BIM 数据流,建议把关键业务标识保存到用户字符串中,例如构件类型、楼层、规则版本、来源文件和计算状态。

using Rhino;
using Rhino.Commands;
using Rhino.DocObjects;
using Rhino.Geometry;
 
namespace CostRhinoTools
{
  public class AddNamedCurveCommand : Command
  {
    public override string EnglishName => "CostAddNamedCurve";
 
    protected override Result RunCommand(RhinoDoc doc, RunMode mode)
    {
      var points = new[]
      {
        new Point3d(0, 0, 0),
        new Point3d(5000, 0, 0),
        new Point3d(5000, 3000, 0),
        new Point3d(0, 3000, 0),
        new Point3d(0, 0, 0)
      };
      var polyline = new Polyline(points);
 
      var attributes = new ObjectAttributes
      {
        Name = "CostDemo_Rectangle",
        LayerIndex = doc.Layers.CurrentLayerIndex
      };
      attributes.SetUserString("CostCategory", "WallAxis");
 
      var id = doc.Objects.AddPolyline(polyline, attributes);
      if (id == System.Guid.Empty)
        return Result.Failure;
 
      doc.Views.Redraw();
      return Result.Success;
    }
  }
}

用户字符串不是数据库,但它适合作为 Rhino 对象和外部业务数据之间的轻量桥梁。例如一条轴线可以保存 `CostCategory=WallAxis`,一个构件 Brep 可以保存 `ElementId`、`Floor`、`MaterialCode`。当导出工程量或重新同步模型时,插件可以根据这些标识快速过滤对象。

新增对象 的开发视角

在 Rhino 7 二次开发中,新增对象 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `doc.Objects.AddCurve`、`AddBrep`、`AddMesh` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,先构造有效几何,再附带属性写入文档,最后刷新视图。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 对象写入失败后仍然继续使用空 Guid。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:写一个命令按当前图层新增命名矩形,并检查返回 Guid。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

替换对象 的开发视角

在 Rhino 7 二次开发中,替换对象 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `doc.Objects.Replace` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,在保持对象身份或用户选择语义时,用新几何替换旧对象。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 直接删除再新增,导致下游引用、名称或选择状态丢失。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:选择一条曲线,将其偏移结果替换原对象,并保留名称。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

删除对象 的开发视角

在 Rhino 7 二次开发中,删除对象 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `doc.Objects.Delete` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,删除前确认对象来源和筛选条件,必要时只删除插件创建的对象。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 用过宽条件删除用户手工模型。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:删除所有带有指定用户字符串的临时预览对象。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

图层管理 的开发视角

在 Rhino 7 二次开发中,图层管理 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `doc.Layers` 与 `Layer` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,按业务分类创建图层,写入对象前确定 LayerIndex。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把所有对象放在当前图层,后期无法分组管理。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:创建 `Cost::Axis` 和 `Cost::Result` 图层并分别写入对象。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

文档元数据 的开发视角

在 Rhino 7 二次开发中,文档元数据 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `doc.Strings` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,把插件版本、规则集名称、最近导入文件路径记录到文档级字符串。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把全局设置写到每个对象,造成冗余和同步困难。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:在模型中保存一条规则版本字符串,并写命令读取显示。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

撤销友好 的开发视角

在 Rhino 7 二次开发中,撤销友好 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 命令边界与对象表操作 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,把一次用户操作控制在一个命令内,让 Rhino 撤销栈能理解操作。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 在后台事件中悄悄修改对象,用户无法判断变化来源。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:执行命令后按 Ctrl+Z,确认新增对象能一次撤销。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

RhinoCommon 的几何库是二次开发的核心。无论是构件识别、轮廓生成、碰撞检查、面积统计还是工程量提取,最终都会落到点、向量、曲线、曲面、实体和网格。本章先讲基础几何类型,因为很多高级问题都源于基础概念混乱:坐标系不一致、向量没有单位化、平面法向错误、容差未考虑、变换矩阵顺序写反。

`Point3d` 表示位置,`Vector3d` 表示方向和位移。位置可以相减得到向量,位置可以加向量得到新位置,但两个位置直接相加通常没有工程意义。在建筑类模型中,很多算法先计算轴线方向,再沿法向偏移生成墙体边线;这时必须明确哪些变量是点,哪些变量是方向。

Point3d a = new Point3d(0, 0, 0);
Point3d b = new Point3d(5000, 0, 0);
Vector3d direction = b - a;
direction.Unitize();
 
Point3d moved = a + direction * 200.0;

`Plane` 是 Rhino 几何中非常重要的类型。很多二维算法不应该直接假设世界 XY 平面,而应在工作平面或对象局部平面上完成。例如立面轮廓、倾斜构件截面、任意方向剖切,都需要明确一个平面作为几何计算的坐标基准。

`Transform` 表示平移、旋转、缩放、镜像和坐标系变换。几何对象通常提供 `Transform` 方法修改自身,或者可以复制后再变换。在插件中,建议对原始输入几何保持谨慎:如果用户选择的是模型对象,不要在没有明确意图的情况下直接修改它。更稳妥的流程是复制几何、计算结果、确认后写回文档。

var copy = curve.DuplicateCurve();
var move = Transform.Translation(new Vector3d(0, 0, 3000));
copy.Transform(move);
doc.Objects.AddCurve(copy);
doc.Views.Redraw();

容差 的开发视角

在 Rhino 7 二次开发中,容差 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `doc.ModelAbsoluteTolerance` 与几何方法容差参数 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,根据当前模型容差判断点重合、曲线闭合和布尔结果。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 用固定 0.001 判断所有项目,导致不同单位模型行为不一致。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:读取模型绝对容差,并用它判断两点是否近似重合。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

向量方向 的开发视角

在 Rhino 7 二次开发中,向量方向 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Vector3d`、叉积和单位化 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,在偏移、法向和局部坐标计算前统一方向约定。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 未单位化向量就乘距离,偏移量随原线长度变化。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:给任意线段生成左侧 200mm 的平行线。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

局部坐标 的开发视角

在 Rhino 7 二次开发中,局部坐标 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Plane` 与 `Transform.PlaneToPlane` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,把复杂对象先转到局部平面计算,再转换回世界坐标。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 所有算法写死 WorldXY,遇到旋转构件立即失效。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:在任意平面上生成一个局部矩形并转换到世界坐标。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

几何复制 的开发视角

在 Rhino 7 二次开发中,几何复制 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `DuplicateCurve`、`DuplicateBrep` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,修改前复制输入,避免改变用户原对象或共享引用。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 直接修改从 ObjRef 取出的几何,难以判断是否影响文档。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:选择曲线后复制并移动,不改变原曲线。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

边界盒 的开发视角

在 Rhino 7 二次开发中,边界盒 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `BoundingBox` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,快速估算对象范围、定位标签、做粗略碰撞预筛选。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把边界盒面积当作真实投影面积。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:为选择对象绘制边界盒角点标记。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

数值稳定 的开发视角

在 Rhino 7 二次开发中,数值稳定 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `IsValid`、`IsTiny`、空值检查 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,每次复杂几何运算后检查返回对象有效性。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 假设所有 RhinoCommon 方法都会返回可用结果。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:故意输入退化曲线,观察算法如何提前返回失败。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

曲线是建筑和工程模型中最常见的数据形态。轴线、墙线、轮廓线、边界线、剖切线、路径线都可以用曲线表达。RhinoCommon 中的 `Curve` 是抽象基类,具体可能是 `LineCurve`、`PolylineCurve`、`ArcCurve`、`NurbsCurve` 等。写工具时应面向 `Curve` 编程,但在必要时识别具体类型以提高稳定性。

曲线常见分析包括长度、闭合性、端点、切向、曲率、分段、参数域和投影。注意曲线参数不等于长度,曲线的 Domain 只是内部参数范围。需要按距离取点时,应使用长度相关方法,而不是简单插值参数。

double length = curve.GetLength();
Point3d start = curve.PointAtStart;
Point3d end = curve.PointAtEnd;
bool closed = curve.IsClosed;
 
double t;
if (curve.LengthParameter(length * 0.5, out t))
{
  Point3d middle = curve.PointAt(t);
}

生成曲线时,尽量选择语义明确的类型。直线用 `Line` 或 `LineCurve`,多段线用 `Polyline`,圆弧用 `Arc`,自由曲线再使用 Nurbs。这不仅能提升性能,也能让后续算法更容易判断对象类型。

曲线闭合 的开发视角

在 Rhino 7 二次开发中,曲线闭合 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Curve.IsClosed` 与端点距离 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,先判断闭合性,再决定是否能生成面或实体。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 只看首尾点是否完全相等,忽略模型容差。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:选择多段线,如果首尾距离小于容差则补闭合线段。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

偏移 的开发视角

在 Rhino 7 二次开发中,偏移 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Curve.Offset` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,在明确平面、方向和距离后生成偏移线,并检查返回数组。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 没有指定合理平面就偏移三维曲线,结果不可预期。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:对闭合矩形向内偏移 200mm 并写入新图层。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

分割 的开发视角

在 Rhino 7 二次开发中,分割 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Curve.Split` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,用参数或交点把曲线切成多段,保留原曲线用于回溯。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把空间点误当作曲线参数。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:选择一条曲线并按中点参数分成两段。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

连接 的开发视角

在 Rhino 7 二次开发中,连接 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Curve.JoinCurves` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,按容差连接相邻曲线,连接后检查数量是否符合预期。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把未排序曲线直接连接后相信结果一定为一条。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:把多条边界线连接成闭合轮廓,并输出失败段数量。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

投影 的开发视角

在 Rhino 7 二次开发中,投影 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Curve.ProjectToPlane` 或投影到 Brep/Mesh 的相关方法 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,先确定投影目标和方向,区分二维投影与真实几何贴附。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把投影曲线当作原始三维曲线继续用于高度计算。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:把空间曲线投影到 WorldXY 后计算平面长度。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

相交 的开发视角

在 Rhino 7 二次开发中,相交 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Rhino.Geometry.Intersect.Intersection` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,用相交结果做节点识别、切割和拓扑分析。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 忽略重叠线段和多交点情况。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:统计一组轴线之间的交点,并在交点处添加点对象。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

轮廓识别 的开发视角

在 Rhino 7 二次开发中,轮廓识别 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `PolylineCurve`、`NurbsCurve` 与闭合区域 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,先标准化输入曲线,再判断是否形成可用平面区域。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 混合单位和重复线段导致区域生成失败。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:从选择曲线中提取闭合轮廓并生成 Hatch 或面边界。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

在造价或结构辅助工具中,曲线常被用作构件的控制线。墙体可以由中心线加厚得到,梁可以由轴线和截面规则生成,房间边界可以由闭合线计算面积。这类工具的关键不是一条曲线怎样偏移,而是输入曲线怎样被识别、分组、命名和追踪。

建议在写入控制线时给对象增加用户字符串,例如 `Role=ControlAxis`、`ElementType=Wall`、`RuleId=Wall_200_A`。后续命令再根据这些属性选择对象,而不是依赖图层名称或人工选择。这样,当模型规模增大时,工具仍能稳定识别自己的数据。

Brep 是 Rhino 中表达边界表示实体和曲面的核心类型。很多建筑构件、外壳、楼板、墙体、洞口和复杂产品外形都会落到 Brep。Brep 开发比曲线更容易出问题,因为它涉及面、边、环、方向、容差、闭合性和布尔运算。本章的目标不是穷尽所有建模算法,而是建立可靠的实体开发工作方法。

最常见的实体生成流程,是从闭合平面曲线开始,生成平面面片或挤出体。如果曲线不闭合、不共面或自交,后续 Brep 很可能无效。因此,实体生成命令应该先做输入验证,并把失败原因反馈给用户。

using Rhino.Geometry;
 
public static class GeometryUtility
{
  public static bool TryCreateBoxFromCurve(Curve baseCurve, double height, out Brep brep)
  {
    brep = null;
    if (baseCurve == null || !baseCurve.IsClosed || height <= 0)
      return false;
 
    var extrusion = Extrusion.Create(baseCurve, height, true);
    if (extrusion == null)
      return false;
 
    brep = extrusion.ToBrep();
    return brep != null && brep.IsValid;
  }
}

示例方法返回 `bool` 并通过 `out Brep` 输出结果。这样的形式适合服务层:调用者可以根据真假决定是否写入文档。真正命令中还应输出具体失败原因,例如曲线为空、曲线未闭合、高度不合法或生成结果无效。

布尔并、差、交是实体工具的常见需求,但它们不是无条件可靠的魔法按钮。输入 Brep 的有效性、面之间的距离、边界重合、容差设置、法向方向都会影响结果。工程插件应把布尔运算看作需要验证的步骤,而不是直接相信返回值。

平面面片 的开发视角

在 Rhino 7 二次开发中,平面面片 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Brep.CreatePlanarBreps` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,用闭合平面曲线生成面片,检查返回数组和面数量。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 输入曲线不共面却仍期望得到平面 Brep。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:选择闭合曲线生成楼板面,并写入指定图层。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

挤出 的开发视角

在 Rhino 7 二次开发中,挤出 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Extrusion.Create` 与 `ToBrep` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,用规则截面或闭合曲线生成可控实体。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 高度方向和模型 Z 轴混淆,导致构件向下生成。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:把闭合房间边界挤出为 3m 高空间体块。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

布尔差 的开发视角

在 Rhino 7 二次开发中,布尔差 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Brep.CreateBooleanDifference` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,先验证被减实体和工具实体,再按容差执行并检查结果。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 忽略工具体是否穿透主体,导致差集为空。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:用一个盒子从墙体 Brep 中扣出门洞。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

布尔并 的开发视角

在 Rhino 7 二次开发中,布尔并 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Brep.CreateBooleanUnion` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,只对确实相交或接触的实体尝试合并,失败时保留原结果。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把大量不相交实体一次性并集,性能差且结果不明确。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:合并同层相邻体块,并统计成功和失败数量。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

面与边遍历 的开发视角

在 Rhino 7 二次开发中,面与边遍历 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `brep.Faces`、`brep.Edges`、`brep.Loops` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,通过拓扑集合做面积、边界和洞口分析。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把渲染网格当作精确几何分析对象。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:遍历 Brep 面,输出每个面的近似面积和法向。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

实体有效性 的开发视角

在 Rhino 7 二次开发中,实体有效性 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Brep.IsValid` 与 `IsSolid` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,写入文档前判断对象是否有效、是否闭合实体。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 生成无效 Brep 后继续参与后续布尔。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:对一批 Brep 做有效性检查,把失败对象改名标记。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

体量统计 的开发视角

在 Rhino 7 二次开发中,体量统计 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `AreaMassProperties` 与 `VolumeMassProperties` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,按对象类型选择面积或体积属性计算方法。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 对开放曲面计算体积并相信结果。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:计算选中闭合 Brep 的体积并写入对象用户字符串。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

Mesh 在 Rhino 中既是可编辑几何类型,也是显示和分析的重要中间形态。很多导入模型、扫描数据、地形、复杂曲面显示和碰撞预筛选都依赖 Mesh。对于二次开发者来说,Mesh 的优势是速度快、结构直接;代价是精度和拓扑管理需要额外注意。

Mesh 由顶点、面、法线、纹理坐标、颜色等数据组成。在 RhinoCommon 中,开发者可以访问 `mesh.Vertices`、`mesh.Faces`、`mesh.Normals` 等集合。修改 Mesh 后通常需要重新计算法线、压缩无用数据,并检查有效性。

var mesh = new Mesh();
mesh.Vertices.Add(0, 0, 0);
mesh.Vertices.Add(1000, 0, 0);
mesh.Vertices.Add(1000, 1000, 0);
mesh.Vertices.Add(0, 1000, 0);
mesh.Faces.AddFace(0, 1, 2, 3);
mesh.Normals.ComputeNormals();
mesh.Compact();
 
if (mesh.IsValid)
  doc.Objects.AddMesh(mesh);

显示网格 的开发视角

在 Rhino 7 二次开发中,显示网格 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Mesh` 与视图显示 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,用 Mesh 做快速预览或粗略分析,最终精度仍以源几何为准。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把显示网格误当作精确实体边界。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:从 Brep 获取显示网格并比较其面积与 Brep 面积。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

顶点处理 的开发视角

在 Rhino 7 二次开发中,顶点处理 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `mesh.Vertices` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,批量处理顶点时注意索引稳定和拓扑更新。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 删除顶点后继续使用旧索引。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:把一个网格所有顶点沿 Z 方向抬高 1000mm。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

面处理 的开发视角

在 Rhino 7 二次开发中,面处理 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `mesh.Faces` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,区分三角面和四边面,必要时三角化。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 假设所有面都是四边形。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:遍历 Mesh 面并统计三角面和四边面数量。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

法线 的开发视角

在 Rhino 7 二次开发中,法线 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `mesh.Normals.ComputeNormals` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,修改顶点或面后重新计算法线,保证显示和分析一致。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 法线反向导致显示黑面或剖切判断错误。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:反转一个网格并观察法线变化。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

性能预筛选 的开发视角

在 Rhino 7 二次开发中,性能预筛选 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `BoundingBox` 与 Mesh 粗判 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,先用包围盒或简化 Mesh 缩小候选对象,再做精确计算。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 对所有 Brep 两两布尔或相交,导致工具卡死。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:用边界盒筛选可能相交的构件对。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

大模型处理 的开发视角

在 Rhino 7 二次开发中,大模型处理 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 批处理、分块和进度反馈 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,把上万对象处理拆成批次,保持 Rhino 响应和可取消。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 在 UI 线程中长时间循环且无任何反馈。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:处理 1000 个网格对象时每 50 个输出一次进度。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

Rhino 插件性能优化不应一开始就追求复杂并行。先减少不必要的文档读写、避免反复刷新视图、缓存可复用计算结果、缩小对象筛选范围,通常就能解决大部分问题。只有在算法已经清晰、数据边界已经固定后,才考虑多线程或更复杂的数据结构。

需要特别注意,Rhino 文档和 UI 通常不适合从任意后台线程直接修改。如果要做耗时计算,可以把纯几何数据复制出来在线程中分析,最后回到 Rhino 主流程提交结果。这条边界对于稳定性非常重要。

优秀的 Rhino 插件往往不是等用户点完确定才给结果,而是在选择和参数变化时就提供预览。显示管线可以在不写入文档的情况下绘制曲线、点、文字、网格和提示。这能避免临时对象污染模型,也能让用户在确认前理解工具会做什么。

`DisplayConduit` 允许开发者参与 Rhino 视图绘制过程。通常做法是创建一个继承类,保存要预览的几何,在绘制回调中调用 `e.Display.DrawCurve`、`DrawPoint`、`DrawMeshShaded` 等方法。使用完毕后关闭 conduit,并刷新视图。

using Rhino.Display;
using Rhino.Geometry;
using System.Collections.Generic;
using System.Drawing;
 
public class CostPreviewConduit : DisplayConduit
{
  public List<Curve> Curves { get; } = new List<Curve>();
 
  protected override void DrawForeground(DrawEventArgs e)
  {
    foreach (var curve in Curves)
      e.Display.DrawCurve(curve, Color.DeepSkyBlue, 3);
  }
}

显示管线中的几何不属于文档对象,不会被保存,也不会出现在图层中。这正是预览的价值:用户可以看到结果,但模型没有被改变。一旦用户确认,命令再把最终几何写入文档。

临时预览 的开发视角

在 Rhino 7 二次开发中,临时预览 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `DisplayConduit.Enabled` 与 `doc.Views.Redraw` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,参数变化时更新 conduit 数据并刷新视图,确认后写入文档。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 每次预览都新增真实对象,最后忘记清理。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:做一个偏移预览命令,用户确认后才添加曲线。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

前景绘制 的开发视角

在 Rhino 7 二次开发中,前景绘制 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `DrawForeground` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,绘制不受深度遮挡影响的文字、标记和屏幕提示。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把大量复杂几何放到前景绘制导致显示混乱。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:在对象中心绘制面积文字。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

三维绘制 的开发视角

在 Rhino 7 二次开发中,三维绘制 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `DrawObject`、`DrawOverlay` 等显示阶段 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,根据需要选择合适绘制阶段,兼顾遮挡关系和可读性。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 所有预览都用同一种绘制阶段。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:比较曲线在不同绘制阶段的遮挡效果。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

颜色与线宽 的开发视角

在 Rhino 7 二次开发中,颜色与线宽 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `System.Drawing.Color` 与显示方法参数 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,用统一颜色表达预览、警告、成功和错误状态。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 颜色意义不固定,用户无法判断结果。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:把有效对象画蓝色,无效对象画红色。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

交互刷新 的开发视角

在 Rhino 7 二次开发中,交互刷新 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 输入循环和视图刷新 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,参数变化后只刷新必要视图,减少卡顿。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 在大循环中每次对象处理都刷新全部视图。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:批量预览 200 条曲线并测试刷新频率。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

预览生命周期 的开发视角

在 Rhino 7 二次开发中,预览生命周期 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 命令开始、确认、取消和异常 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,用 try/finally 或清晰结构保证 conduit 被关闭。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 异常退出后预览残留在视图中。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:故意触发异常,确认命令结束后预览不再显示。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

Rhino 插件可以只依靠命令行,但当工具涉及配置、表格、规则管理、批处理结果和复杂选项时,就需要图形界面。Rhino 7 支持 Eto.Forms,用于构建跨平台 UI。即使团队只在 Windows 使用 Rhino,也建议把 UI 逻辑和业务逻辑分开,避免窗口事件直接修改模型。

对话框适合一次性设置参数,例如规则前缀、构件类型、导出路径。命令打开对话框,用户确认后命令读取参数,再进入模型处理阶段。对话框本身不应承担复杂几何计算,它只是收集和展示数据。

using Eto.Forms;
using Eto.Drawing;
 
public class RuleSettingsDialog : Dialog<bool>
{
  public TextBox PrefixTextBox { get; } = new TextBox { Text = "Cost" };
 
  public RuleSettingsDialog()
  {
    Title = "规则设置";
    ClientSize = new Size(360, 140);
 
    var ok = new Button { Text = "确定" };
    ok.Click += (s, e) => Close(true);
 
    var cancel = new Button { Text = "取消" };
    cancel.Click += (s, e) => Close(false);
 
    Content = new StackLayout
    {
      Padding = 12,
      Spacing = 8,
      Items =
      {
        new Label { Text = "对象名称前缀" },
        PrefixTextBox,
        new StackLayout
        {
          Orientation = Orientation.Horizontal,
          Spacing = 8,
          Items = { null, ok, cancel }
        }
      }
    };
  }
}

示例对话框返回 `bool`,命令可以根据返回值判断用户是否确认。真实项目里可以把参数封装成配置对象,例如 `RuleSettings`,由对话框负责编辑,由服务类负责应用。

模态对话框 的开发视角

在 Rhino 7 二次开发中,模态对话框 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Eto.Forms.Dialog<T>` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,用于短流程设置,关闭后命令继续执行。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 对话框中直接保存大量全局状态。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:做一个输入图层名和对象前缀的设置对话框。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

非模态面板 的开发视角

在 Rhino 7 二次开发中,非模态面板 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 Rhino 面板与 Eto 控件 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,用于长期停靠工具、对象检查器和批处理结果。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把所有命令都做成停靠面板,增加使用成本。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:设计一个显示选中对象用户字符串的面板。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

数据绑定 的开发视角

在 Rhino 7 二次开发中,数据绑定 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 配置对象与控件值同步 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,用明确模型对象承载 UI 状态,便于保存和测试。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 从多个控件直接散乱读取值。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:把对话框参数保存为 JSON 配置。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

错误提示 的开发视角

在 Rhino 7 二次开发中,错误提示 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `MessageBox` 与命令行反馈 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,轻量问题写命令行,阻塞性问题再弹窗。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 每个小警告都弹窗打断用户。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:批处理完成后只弹一次汇总信息。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

界面线程 的开发视角

在 Rhino 7 二次开发中,界面线程 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 UI 更新和 Rhino 文档修改边界 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,界面负责收集意图,命令或主流程负责提交文档修改。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 在后台事件随意修改 RhinoDoc。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:按钮点击后触发命令,而不是直接遍历文档。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

可用性 的开发视角

在 Rhino 7 二次开发中,可用性 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 默认值、记忆值和输入校验 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,给常用参数合理默认值,并在确认前提示非法输入。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 允许空路径、负高度或无效图层名进入业务逻辑。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:为高度输入框增加大于零校验。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

企业插件很少只在 Rhino 内部循环。真实工作流通常涉及 DWG、3DM、CSV、Excel、JSON、数据库、Web API 或 BIM 平台。RhinoCommon 提供 `File3dm` 等文件能力,普通 .NET 也提供丰富的文本和网络库。开发者需要把几何数据、对象属性和业务数据之间的映射设计清楚。

`File3dm` 可用于读写 3DM 文件,而不一定依赖当前 Rhino 文档。它适合做离线导出、模板生成、批量数据转换等任务。注意当前文档对象和 File3dm 对象不是同一个上下文,图层、材质和属性需要显式迁移或重建。

using Rhino.FileIO;
using Rhino.Geometry;
 
public static class File3dmExportExample
{
  public static bool WriteCurves(string path, Curve[] curves)
  {
    var file = new File3dm();
    foreach (var curve in curves)
      file.Objects.AddCurve(curve);
 
    return file.Write(path, 7);
  }
}

JSON 适合保存层级规则、构件配置、用户设置和复杂导出结果;CSV 适合给表格软件和造价系统传递扁平清单。导出时不要只写几何数值,应写清楚对象 Guid、名称、图层、类型、单位、规则版本和计算时间。这样当外部系统发现异常时,团队能回到 Rhino 模型定位来源对象。

字段 示例 说明
ObjectId 5b1d… Rhino 文档对象 Guid
ElementType Wall 业务构件类型
Layer Cost::Wall 对象图层
Quantity 12.35 工程量数值
Unit m2 工程量单位
RuleVersion 2026.06 计算规则版本

3DM 读写 的开发视角

在 Rhino 7 二次开发中,3DM 读写 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Rhino.FileIO.File3dm` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,把离线文件处理和当前文档处理分开设计。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 以为 File3dm 修改会自动影响当前打开模型。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:创建一个只包含几条曲线的新 3DM 文件。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

CSV 导出 的开发视角

在 Rhino 7 二次开发中,CSV 导出 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 .NET 文本写入与字段转义 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,把扁平工程量清单导出给表格和造价系统。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 字段中包含逗号或换行却不做转义。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:导出选中对象的名称、图层和长度。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

JSON 配置 的开发视角

在 Rhino 7 二次开发中,JSON 配置 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 System.Text.Json 或 Newtonsoft.Json 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,用 JSON 保存规则集和插件设置。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把配置硬编码在命令类里,发布后无法调整。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:从 JSON 读取墙厚规则并用于生成墙体。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

DWG 交互 的开发视角

在 Rhino 7 二次开发中,DWG 交互 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 Rhino 导入导出命令与对象清理 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,把 DWG 看作外部协作格式,导入后做图层和对象标准化。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 直接在混乱导入图层上运行业务算法。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:导入后把指定图层曲线复制到插件标准图层。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

数据库 的开发视角

在 Rhino 7 二次开发中,数据库 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 SQLite 或企业数据库访问层 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,只把稳定业务结果写入数据库,几何大对象谨慎存储。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 插件命令直接拼 SQL 字符串且无事务。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:用 SQLite 保存构件清单和计算时间。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

Web API 的开发视角

在 Rhino 7 二次开发中,Web API 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 HTTP 客户端与数据契约 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,把网络请求封装在服务层,明确超时和失败策略。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 UI 线程等待慢接口导致 Rhino 卡死。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:调用一个本地测试接口上传导出 JSON。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

虽然 RhinoCommon 应是插件工程的主要 API,但脚本化运行 Rhino 原生命令仍有价值。有些 Rhino 功能已经通过命令提供了成熟交互,插件只需要在特定场景下触发它。关键是要知道何时桥接命令,何时直接使用 RhinoCommon。

`RhinoApp.RunScript()` 可以运行 Rhino 命令字符串。官方文档提醒开发者要谨慎使用这种能力,特别是不要在一个脚本运行过程中依赖另一个脚本命令保留的运行时数据库对象。在插件中使用脚本桥接时,应优先选择无状态、可重复、结果明确的命令。

using Rhino;
using Rhino.Commands;
 
namespace CostRhinoTools
{
  [CommandStyle(Style.ScriptRunner)]
  public class ScriptBridgeCommand : Command
  {
    public override string EnglishName => "CostScriptBridge";
 
    protected override Result RunCommand(RhinoDoc doc, RunMode mode)
    {
      RhinoApp.RunScript("_SelNone", false);
      RhinoApp.RunScript("_Zoom _Extents", false);
      return Result.Success;
    }
  }
}

上例只运行选择和缩放命令,风险较低。如果要运行会创建对象、修改选择集或弹出交互提示的命令,就必须清楚命令字符串、选项、语言环境和运行模式。对于核心业务逻辑,仍建议使用 RhinoCommon 直接实现。

命令字符串 的开发视角

在 Rhino 7 二次开发中,命令字符串 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `RhinoApp.RunScript` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,用于触发成熟 Rhino 命令或简单视图操作。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把复杂业务流程全部拼接成字符串。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:写一个命令运行 Zoom Extents 并输出结果。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

ScriptRunner 的开发视角

在 Rhino 7 二次开发中,ScriptRunner 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `CommandStyle(Style.ScriptRunner)` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,当插件命令内部需要运行脚本时声明合适命令风格。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 忽略命令风格导致脚本执行行为异常。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:为脚本桥接命令添加 CommandStyle 并测试。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

语言环境 的开发视角

在 Rhino 7 二次开发中,语言环境 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 英文命令名与下划线前缀 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,在脚本中使用稳定的英文命令形式,降低本地化影响。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 使用中文界面显示文字作为脚本命令。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:把常用脚本命令整理为英文形式清单。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

选择状态 的开发视角

在 Rhino 7 二次开发中,选择状态 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `_SelNone` 与对象选择 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,运行脚本前明确选择集,运行后恢复或解释选择变化。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 依赖用户当前选择,导致结果不可重复。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:运行脚本前清空选择并在结束后选择新对象。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

批处理 的开发视角

在 Rhino 7 二次开发中,批处理 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 命令行自动化与插件命令 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,把可脚本化命令设计成稳定参数入口。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 让批处理依赖鼠标点击和弹窗。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:为导出命令设计完整命令行选项。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

日志 的开发视角

在 Rhino 7 二次开发中,日志 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `RhinoApp.WriteLine` 与外部日志 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,自动化流程要记录输入、输出和失败原因。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 批处理失败只显示一个泛泛错误。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:把批处理每个文件的处理结果写到日志文件。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

很多 Rhino 团队同时使用 Grasshopper 和 RhinoCommon 插件。Grasshopper 适合参数化探索、快速搭建算法流程和设计阶段推敲;Rhino 插件适合封装稳定工具、管理模型对象、发布给非开发用户。两者不是替代关系,而是可以分工协作。

当算法仍在变化、参数关系需要频繁调整、设计师需要可视化控制流程时,Grasshopper 更合适。当流程已经稳定,需要一键处理模型、写入属性、接入外部系统或统一部署时,应考虑 RhinoCommon 插件。很多团队的成熟路径是:先用 Grasshopper 验证算法,再把核心逻辑迁移到 C# 服务层,最后封装为 Rhino 命令或自定义 GH 组件。

算法原型 的开发视角

在 Rhino 7 二次开发中,算法原型 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 Grasshopper C# Script 与 RhinoCommon 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,快速验证几何逻辑,再迁移到类库。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 在 Grasshopper 里长期维护大量复制脚本。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:把一个曲线偏移算法先写成 C# Script 再抽为静态方法。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

自定义组件 的开发视角

在 Rhino 7 二次开发中,自定义组件 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 GH SDK 与 RhinoCommon 几何类型 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,把可复用算法封装成组件,保持参数和输出清晰。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 组件输出含义不明,用户只能看源码理解。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:设计一个输入曲线和高度、输出 Brep 的组件。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

插件共享逻辑 的开发视角

在 Rhino 7 二次开发中,插件共享逻辑 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 独立核心类库 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,Rhino 命令和 GH 组件引用同一套几何服务。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 同一算法在命令和组件中复制两份。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:把面积统计服务同时用于命令和组件。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

数据树 的开发视角

在 Rhino 7 二次开发中,数据树 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 Grasshopper 数据结构 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,在 GH 侧保留分组语义,进入 Rhino 插件前转换为清晰集合。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把数据树展平后丢失楼层或构件分组。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:把按楼层分组的曲线转换为命名结果。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

Bake 策略 的开发视角

在 Rhino 7 二次开发中,Bake 策略 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 对象属性与图层 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,烘焙到 Rhino 文档时写入名称、图层和用户字符串。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 只烘焙几何,后续无法识别来源。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:烘焙墙体结果并写入 `ElementType=Wall`。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

版本管理 的开发视角

在 Rhino 7 二次开发中,版本管理 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 GH 文件、插件 DLL 和规则配置 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,把算法版本写入结果,避免文件和插件不匹配。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 不同项目使用不同旧版组件却没有记录。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:在组件输出中附带规则版本字符串。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

Rhino 插件常被误认为只能靠手动测试。事实上,只要把核心几何和业务规则从命令中分离出来,就可以做大量普通单元测试。不能自动测试的部分,至少也应形成固定的手工验收清单。本章关注让工具从“作者能用”变成“团队可维护”。

可测试的第一步是分层。命令负责获取输入和提交输出,服务类负责计算。几何服务方法尽量接收 `Curve`、`Brep`、`double`、配置对象等普通参数,返回结果对象或明确失败状态。这样即使不启动 Rhino UI,也能对大量几何输入做测试。

using NUnit.Framework;
using Rhino.Geometry;
 
[TestFixture]
public class GeometryUtilityTests
{
  [Test]
  public void RectangleArea_IsExpected()
  {
    var rect = new Rectangle3d(Plane.WorldXY, 5000.0, 3000.0);
    var curve = rect.ToNurbsCurve();
    Assert.That(curve.GetLength(), Is.GreaterThan(0.0));
  }
}

示例测试只展示思路。真实项目应覆盖空输入、退化输入、边界数值、不同单位、不同容差和典型工程样例。如果某些 RhinoCommon 类型必须在 Rhino 进程中运行,仍可以把纯业务判断和数据转换部分拆出去测试。

错误返回 的开发视角

在 Rhino 7 二次开发中,错误返回 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `Result` 与自定义结果对象 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,命令返回 Rhino 状态,服务层返回带原因的业务结果。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 服务层直接弹窗,导致无法测试和复用。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:定义一个 `GeometryBuildResult` 包含成功标志和错误信息。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

异常处理 的开发视角

在 Rhino 7 二次开发中,异常处理 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `try/catch/finally` 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,只在边界捕获异常,记录上下文并清理预览资源。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 吞掉所有异常并返回成功。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:让命令在异常时关闭 DisplayConduit。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

日志 的开发视角

在 Rhino 7 二次开发中,日志 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 命令行、文件日志和批处理记录 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,开发期写命令行,生产批处理写结构化日志。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 用户报告错误时没有任何输入记录。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:把导出过程的对象数量和失败原因写入日志。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

单元测试 的开发视角

在 Rhino 7 二次开发中,单元测试 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 NUnit/xUnit 与几何服务 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,优先测试无 UI、无文档依赖的核心算法。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 所有逻辑都依赖 `RhinoDoc` 导致无法测试。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:为曲线长度分类方法写三个测试。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

手工验收 的开发视角

在 Rhino 7 二次开发中,手工验收 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 固定模型与检查清单 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,为每个命令准备小、中、大三个样例模型。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 只用当前打开模型随手试一下。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:建立一份命令验收表,记录输入、步骤和期望输出。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

代码规范 的开发视角

在 Rhino 7 二次开发中,代码规范 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 命名、分层和注释 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,命令名、类名、用户字符串键名保持一致。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 同一概念在不同文件有多个名字。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:统一 `ElementType`、`RuleId`、`SourceId` 三个键名。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

插件写完并不等于完成。真正交付给团队使用,还要考虑安装、版本、依赖、升级、回滚、文档和兼容性。Rhino 7 提供 Package Manager,底层包工具通常称为 Yak,可用于分发 Rhino 和 Grasshopper 插件包。对于企业内部工具,也可以先使用共享目录或安装包,但版本纪律仍然必不可少。

一个插件发布包通常至少包含 `.rhp` 插件文件、依赖 DLL、图标或资源、说明文档、版本记录和示例模型。如果插件需要配置文件,应说明默认位置、搜索路径、升级策略和缺省值。不要假设用户知道开发者机器上的目录结构。

内容 说明 检查点
RHP Rhino 插件主体 能在干净 Rhino 7 环境加载
依赖 DLL 第三方库或内部类库 版本一致且没有遗漏
配置 规则、映射、默认参数 路径明确且缺省可运行
文档 安装、命令、示例 用户能按文档完成第一步
示例模型 验收用 3DM 文件 覆盖主要命令
版本记录 变更、修复、兼容性 便于回滚和追责

版本号 的开发视角

在 Rhino 7 二次开发中,版本号 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 语义化版本或企业规则版本 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,把插件版本和规则版本分开记录。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 只看 DLL 修改时间判断版本。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:在命令中输出插件版本和规则版本。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

Yak 包 的开发视角

在 Rhino 7 二次开发中,Yak 包 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 Rhino Package Manager 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,用包管理器分发可安装插件并声明兼容 Rhino 版本。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 手工复制文件导致用户版本不一致。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:整理一个包清单草案,列出插件文件和依赖。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

依赖管理 的开发视角

在 Rhino 7 二次开发中,依赖管理 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 NuGet、内部 DLL 和复制策略 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,构建时明确依赖来源,发布时检查输出目录。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 开发机有依赖,用户机没有依赖。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:在干净目录模拟发布包并尝试加载。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

升级策略 的开发视角

在 Rhino 7 二次开发中,升级策略 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 配置迁移和兼容处理 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,新版本读取旧配置时提供迁移或默认值。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 升级后旧项目文件无法打开或规则丢失。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:为配置对象增加 Version 字段并写迁移逻辑。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

用户文档 的开发视角

在 Rhino 7 二次开发中,用户文档 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 DokuWiki、README 和命令帮助 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,按任务写文档,而不是只列 API。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 文档只写安装,不写常见失败处理。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:为一个命令写输入、步骤、输出和错误处理说明。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

支持流程 的开发视角

在 Rhino 7 二次开发中,支持流程 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 问题模板和日志收集 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,让用户反馈模型、版本、日志和复现步骤。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 只收到一句“不能用”无法排查。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:制作一个插件问题反馈模板。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

本章用一个综合案例把前面内容串起来。目标是设计一个 Rhino 7 插件,用于从建筑或结构控制线生成可计量的构件对象,并把关键工程量导出为表格。案例偏向结构造价场景,但方法适用于幕墙、景观、装饰和工业产品的规则化建模。

  • 用户选择一组闭合房间边界或墙体轴线。
  • 插件根据规则生成楼板、墙体或空间体块。
  • 生成对象写入标准图层,附带名称和用户字符串。
  • 插件提供预览,用户确认后才写入文档。
  • 插件能统计面积、长度或体积,并导出 CSV。
  • 工具需要可撤销、可取消、可重复运行。

案例中的数据模型不应直接等同于 Rhino 几何。建议建立业务对象,例如 `ElementRule`、`ElementResult`、`QuantityRecord`。几何只是业务对象的一部分,其他字段包括类型、楼层、规则编号、单位、来源对象和错误信息。

public class QuantityRecord
{
  public string ObjectId { get; set; }
  public string ElementType { get; set; }
  public string Layer { get; set; }
  public double Quantity { get; set; }
  public string Unit { get; set; }
  public string RuleVersion { get; set; }
}

综合命令可以分为七步:读取配置、选择对象、验证输入、生成预览、确认参数、写入文档、导出结果。每一步都应有明确的失败返回。例如选择为空时返回取消或无操作,曲线不闭合时返回失败并高亮问题对象,导出路径无效时提示用户重新选择。

规则读取 的开发视角

在 Rhino 7 二次开发中,规则读取 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 JSON 配置与默认规则 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,命令开始时读取规则,并把版本写入后续结果。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 规则散落在代码常量中,项目间无法切换。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:为墙厚、楼板厚度和材料编码建立规则 JSON。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

输入识别 的开发视角

在 Rhino 7 二次开发中,输入识别 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `GetObject`、用户字符串和图层过滤 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,优先识别插件标准对象,也允许用户手动选择曲线。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 完全依赖当前选择集且不验证类型。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:筛选 `Cost::Axis` 图层上的闭合曲线。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

预览生成 的开发视角

在 Rhino 7 二次开发中,预览生成 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 几何服务与 DisplayConduit 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,用内存几何生成预览,确认后再写入对象表。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 预览过程污染模型并影响撤销。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:为楼板生成半透明边界预览。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

对象写入 的开发视角

在 Rhino 7 二次开发中,对象写入 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `ObjectAttributes` 与用户字符串 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,写入图层、名称、ElementType、RuleId、SourceId。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 只写几何不写属性,后续无法统计。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:生成墙体后写入来源曲线 Guid。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

工程量计算 的开发视角

在 Rhino 7 二次开发中,工程量计算 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 `AreaMassProperties`、长度和体积 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,根据构件类型选择合适计算方法并记录单位。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 把面积、体积和长度混在一个无单位字段。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:导出墙长、楼板面积和体块体积三类结果。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

结果校核 的开发视角

在 Rhino 7 二次开发中,结果校核 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 高亮异常对象与日志 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,对失败对象标红或输出列表,方便用户修模。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 失败后只提示总数,用户不知道改哪里。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:给不闭合曲线添加红色点标记。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

导出交付 的开发视角

在 Rhino 7 二次开发中,导出交付 不应只被理解为一个孤立功能,而应被放进 Rhino 文档、对象表、命令生命周期和用户交互的整体链路中。插件代码通常从命令入口获得 `RhinoDoc`,再围绕 CSV 和模型属性 完成数据读取、几何计算、对象写入或界面反馈。这一思路能让代码保持可测试、可复用,也能避免把建模逻辑散落在按钮事件、命令字符串和临时脚本中。

实际项目里,导出的每一行都能回查到 Rhino 对象。开发者应先明确输入对象的类型、坐标单位、图层与属性约束,再决定是否新建对象、替换对象或只计算结果。如果代码需要修改模型,建议把选择、验证、计算、提交四个阶段拆开;如果代码只做分析,则应尽量把结果以临时显示、表格或日志形式返回,减少对当前文件的侵入。

常见问题是 外部表格只有数量没有对象 ID。这类问题通常不是单个 API 调用错误,而是缺少边界检查、容差意识或文档状态判断。Rhino 的几何对象可以在内存中存在,也可以作为文档对象持久化存在;两者拥有不同的生命周期。因此,教程中的示例会反复区分 `Rhino.Geometry` 下的纯几何、`Rhino.DocObjects` 下的文档对象,以及 `RhinoDoc` 中对象表的增删改查。

练习建议:导出后用 ObjectId 回到 Rhino 中选择对应对象。练习完成后,不要只检查命令是否能运行,还要检查撤销记录、图层归属、对象名称、单位变化、空选择、取消操作和异常输入。这些检查看起来琐碎,却决定了插件能否从演示代码走向真实生产工具。

不要试图一次性写出覆盖全部构件的巨型插件。更稳妥的路线是先完成一个闭环:选择闭合曲线,生成楼板面,写属性,统计面积,导出 CSV。这个闭环跑通后,再扩展墙、梁、柱、洞口、楼层、规则库和 UI 面板。每扩展一种构件,都用同样的验收清单检查输入、预览、写入、撤销、导出和错误处理。

综合案例的价值不在于某一段代码,而在于形成可复制的工程方法。Rhino 7 二次开发真正要解决的是几何平台和业务规则之间的长期协作问题。只要命令边界清晰、几何服务可测试、对象属性可追踪、发布流程可回滚,插件就能逐步从小工具演化为团队基础设施。

命名空间 类型 用途
`Rhino` `RhinoDoc` 当前文档上下文
`Rhino` `RhinoApp` 命令行输出、运行脚本、应用级操作
`Rhino.Commands` `Command` 插件命令基类
`Rhino.Geometry` `Point3d` 三维点
`Rhino.Geometry` `Vector3d` 三维向量
`Rhino.Geometry` `Plane` 局部坐标平面
`Rhino.Geometry` `Curve` 曲线基类
`Rhino.Geometry` `Brep` 边界表示曲面或实体
`Rhino.Geometry` `Mesh` 网格
`Rhino.DocObjects` `ObjectAttributes` 对象属性
`Rhino.Input.Custom` `GetObject` 选择对象
`Rhino.Display` `DisplayConduit` 自定义显示预览
`Rhino.FileIO` `File3dm` 3DM 文件读写
  • 命令名是否唯一、稳定、可脚本化。
  • 用户取消任意一步时是否不修改模型。
  • 空选择、错误类型、退化几何是否有明确提示。
  • 新增对象是否有正确图层、名称和用户字符串。
  • 写入后是否刷新视图,撤销是否符合预期。
  • 预览是否在确认前不污染模型。
  • 导出结果是否包含对象 ID、单位和规则版本。
  • 错误日志是否能帮助开发者复现问题。

以下链接用于继续查阅 Rhino 7 二次开发的官方资料。实际开发时,应以官方文档和本机 Rhino 版本的 API 为准。

Rhino 的 .NET SDK,C# 插件、Rhino.Python 和 Grasshopper 开发都会接触它。

Rhino 插件文件扩展名,插件编译后通常以此形式加载到 Rhino。

当前 Rhino 模型文档对象,提供对象表、图层表、视图和单位等上下文。

Boundary Representation,边界表示曲面或实体。

由顶点和面组成的网格,适合显示、导入数据和部分分析场景。

Rhino 显示管线扩展点,可用于临时预览。

Rhino 插件包管理相关工具链,用于打包和分发插件。

以下练习题用于把教程内容迁移到真实项目。每个练习都要求读者完成命令、测试样例和验收记录。练习不追求一次写完全部功能,而是训练 Rhino 7 二次开发中最常见的输入、计算、预览、写入和导出闭环。

关键词:轴线编号、交点识别、轴网偏移、图层标准化。轴线通常来自 DWG,存在重复线、断线和轻微错位。插件应先清洗,再进入构件生成。

练习 1.1:围绕“建筑轴网”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 1.2:围绕“建筑轴网”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 1.3:围绕“建筑轴网”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 1.4:围绕“建筑轴网”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 1.5:围绕“建筑轴网”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 1.6:围绕“建筑轴网”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

关键词:中心线加厚、端部连接、洞口扣减、材质规则。墙体工具要明确内外侧方向,否则偏移和扣洞会在不同楼层产生相反结果。

练习 2.1:围绕“墙体生成”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 2.2:围绕“墙体生成”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 2.3:围绕“墙体生成”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 2.4:围绕“墙体生成”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 2.5:围绕“墙体生成”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 2.6:围绕“墙体生成”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

关键词:闭合边界、面积统计、厚度规则、标高管理。楼板从二维边界变成三维构件时,必须记录边界来源和标高。

练习 3.1:围绕“楼板识别”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 3.2:围绕“楼板识别”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 3.3:围绕“楼板识别”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 3.4:围绕“楼板识别”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 3.5:围绕“楼板识别”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 3.6:围绕“楼板识别”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

关键词:轴线、截面、端点、楼层、体量统计。梁柱不只是几何体,还需要截面规格、构件编号和规则来源。

练习 4.1:围绕“梁柱构件”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 4.2:围绕“梁柱构件”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 4.3:围绕“梁柱构件”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 4.4:围绕“梁柱构件”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 4.5:围绕“梁柱构件”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 4.6:围绕“梁柱构件”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

关键词:门窗洞、设备洞、预留洞、扣减规则。洞口应作为独立业务对象保存,不能只在布尔后消失。

练习 5.1:围绕“洞口处理”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 5.2:围绕“洞口处理”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 5.3:围绕“洞口处理”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 5.4:围绕“洞口处理”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 5.5:围绕“洞口处理”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 5.6:围绕“洞口处理”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

关键词:重叠、断点、非法图层、无属性对象。检查工具应给出可定位的问题对象,而不是只输出数量。

练习 6.1:围绕“模型检查”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 6.2:围绕“模型检查”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 6.3:围绕“模型检查”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 6.4:围绕“模型检查”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 6.5:围绕“模型检查”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 6.6:围绕“模型检查”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

关键词:长度、面积、体积、分类汇总、单位换算。导出结果必须能回查对象,否则后期对量无法闭环。

练习 7.1:围绕“工程量导出”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 7.2:围绕“工程量导出”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 7.3:围绕“工程量导出”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 7.4:围绕“工程量导出”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 7.5:围绕“工程量导出”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 7.6:围绕“工程量导出”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

关键词:版本、日志、样例模型、用户反馈。二次开发工具只有被稳定安装和理解,才算真正交付。

练习 8.1:围绕“协同交付”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 8.2:围绕“协同交付”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 8.3:围绕“协同交付”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 8.4:围绕“协同交付”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 8.5:围绕“协同交付”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

练习 8.6:围绕“协同交付”建立一个小命令。第一步从 Rhino 文档中选择或生成测试对象;第二步把对象转换为明确的 RhinoCommon 几何和业务数据;第三步进行容差检查、属性写入和结果输出;第四步在命令取消、空输入、错误图层和重复运行时验证行为。完成后,把命令的输入条件、输出对象、用户字符串键名、失败提示和撤销结果写入项目文档。如果练习涉及外部表格,还要确认导出的每一行都包含对象 Guid、业务类型、单位和规则版本。

本附录面向真实项目维护。Rhino 7 二次开发中的很多问题并不来自某一个 API,而来自环境、状态、容差、对象生命周期和发布流程的组合。排错时不要只看界面现象,应回到命令输入、文档对象、几何有效性、属性写入、视图刷新和日志证据。

现象:Rhino 命令行提示插件加载失败,或插件管理器中显示错误状态。

处理思路:检查目标框架、RhinoCommon 引用、依赖 DLL、插件位数和输出目录。Rhino 7 插件应特别注意 .NET Framework 4.8 运行时和依赖复制策略。

验证方法:在干净测试机上只放发布包内容,逐一确认 RHP 与依赖 DLL 是否齐全。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:插件加载后输入命令没有反应,或 Rhino 提示未知命令。

处理思路:确认命令类继承 `Command`,`EnglishName` 唯一且没有拼写错误,类是 public,并且项目确实重新编译后被 Rhino 加载。

验证方法:新增一个最小命令输出版本号,用它验证当前加载的是不是最新 DLL。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:Visual Studio 已启动 Rhino,但命令执行时不进入断点。

处理思路:检查启动程序是否是目标 Rhino 7,调试配置是否为 Debug,符号文件是否匹配,Rhino 是否加载了另一个目录下的旧插件。

验证方法:在命令行输出程序集路径,确认 Rhino 实际加载的 DLL 位置。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:代码返回成功,但视图中没有新对象。

处理思路:检查对象是否写入隐藏图层、坐标是否远离当前视图、几何是否无效,以及是否调用 `doc.Views.Redraw()`。

验证方法:写入对象后执行 Zoom Extents,或输出对象边界盒定位坐标范围。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:一次命令需要多次撤销,或撤销后仍残留临时对象。

处理思路:把真实文档修改集中在命令确认阶段完成,预览使用 DisplayConduit,不要用临时真实对象模拟预览。

验证方法:执行命令后按一次 Ctrl+Z,检查所有新增对象和属性是否同时回退。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:Offset 返回空数组,或结果方向与预期相反。

处理思路:确认曲线平面、闭合性、偏移距离、容差和方向点。对三维曲线不要默认使用 WorldXY。

验证方法:把输入曲线投影或转换到明确平面后再偏移,并输出失败曲线名称。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:布尔差、并、交返回空结果或无效 Brep。

处理思路:先检查输入 Brep 是否有效、是否闭合、是否真实相交;再按模型容差执行布尔,并保留失败对象供人工检查。

验证方法:对每一组布尔输入输出边界盒、体积和有效性状态。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:同一命令在不同模型中结果尺寸相差 1000 倍。

处理思路:不要硬编码米或毫米假设。读取 `doc.ModelUnitSystem`,在配置和导出中明确单位,并对外部数据做单位换算。

验证方法:分别在毫米模型和米模型中运行同一测试,记录输入和输出单位。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:按 Esc 后模型中出现部分结果。

处理思路:每一步输入后立即检查 `CommandResult()`,取消时返回 `Result.Cancel`,不要让后续代码继续使用默认值。

验证方法:在命令的每个输入阶段按 Esc,检查是否没有任何新增对象。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:用户先选对象再运行命令,但命令仍要求重新选择。

处理思路:在 `GetObject` 中启用预选,并正确处理预选与命令内选择的组合。

验证方法:分别测试预选、无预选、错误预选三种情况。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:生成对象后无法根据业务字段筛选。

处理思路:写入对象时使用 `ObjectAttributes.SetUserString`,替换对象时注意属性是否被保留或重新设置。

验证方法:对象生成、替换、保存、重开文件后读取用户字符串。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:CSV 中只有工程量,没有来源对象。

处理思路:导出每一行都写入对象 Guid、名称、图层、业务类型、单位和规则版本。

验证方法:从导出表任取一行,用 Guid 回到 Rhino 中选择对象。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:处理上千对象时 Rhino 长时间无响应。

处理思路:先缩小对象筛选范围,减少视图刷新,使用边界盒预筛选,必要时分批处理并提供进度。

验证方法:记录对象数量、候选数量、成功数量、失败数量和总耗时。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:停靠面板显示的数据和当前选择不一致。

处理思路:把 UI 状态和文档查询分开,选择变化时刷新视图模型,不要让控件直接持有过期 RhinoObject。

验证方法:切换选择、删除对象、撤销后检查面板刷新是否正确。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:新版本插件读取旧 JSON 后报错。

处理思路:配置文件增加版本字段,读取时提供默认值和迁移逻辑。不要假设所有字段都存在。

验证方法:准备旧版配置样例,作为升级测试固定输入。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:RunScript 在不同语言界面或选择状态下行为不同。

处理思路:使用英文命令形式,运行前明确选择集,避免把核心业务依赖复杂命令字符串。

验证方法:把脚本命令复制到 Rhino 命令行单独运行,确认无交互歧义。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:插件生成对象散落在当前图层或用户图层。

处理思路:写入前创建或查找标准图层,把 LayerIndex 写入 ObjectAttributes。

验证方法:换当前图层后运行命令,确认结果仍写入标准图层。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

现象:用户反馈失败但开发者无法复现。

处理思路:日志至少记录插件版本、Rhino 版本、命令名、输入数量、失败对象和异常消息。

验证方法:制作问题反馈模板,让用户附带模型、日志和复现步骤。如果验证仍然失败,应把问题拆成最小模型、最小命令和最小输入,确认是环境问题、几何问题、文档状态问题还是业务规则问题。排错记录要写入团队文档,避免同一类问题在不同项目中反复出现。

工程建议:为这类问题准备一个固定测试文件和固定命令步骤。每次插件升级后,至少运行一次相关验收。如果问题和用户数据有关,应保留脱敏后的样例对象,并把失败对象的 Guid、图层、名称、用户字符串和几何有效性写进日志。这样开发者在没有用户现场环境的情况下,也能复盘命令的输入和输出。

该主题尚不存在

您访问的页面并不存在。如果允许,您可以使用创建该页面按钮来创建它。

  • rhino二次开发.1780298201.txt.gz
  • 最后更改: 2026/06/01 15:16
  • 张叶安