ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Tekla OpenAPI二次开发实战:从Reference到参数化建模

Tekla OpenAPI二次开发实战:从Reference到参数化建模 简介Tekla OpenAPI 是 Tekla Structures 官方提供的开发接口这份参考文档适合结构工程二次开发工程师、BIM 集成开发者以及希望实现建模自动化的 Tekla 进阶用户。文档以 API 参考页面为主体涵盖对象模型、常用接口函数、事件驱动机制、访问权限、错误处理、IFC/DWG 数据交换、调试与性能优化等关键知识点同时说明基于 .NET 的多种编程语言调用方式并可在网页中翻译为中文后查阅便于快速理解接口用法与对象关系。资源为 RAR 压缩包约 21.72MB当前解析到的文件总数为 0未给出具体文件类型明细实际内容应以解压后的离线页面为准。已有 487 人学习或下载适合需要系统梳理 Tekla OpenAPI 知识体系、开发自定义插件或与外部系统对接的工程师收藏使用有助于减少重复建模操作并提升自动化程度。1. TeklaOpenAPI Reference为什么多数人下载后第一反应是关掉聊到 Tekla OpenAPI 二次开发很多人第一反应是去翻那份 Reference 文档。但以我做钢结构深化设计插件这几年的观察真正能把这份文档用起来的人十个里面不超过三个。多数人的流程是下载、解压、打开命名空间列表看到几万个类和成员然后默默关掉回到手工建模。这份资源解决的根本不是Tekla 有没有 API的问题而是API 到底怎么调、参数从哪来、返回结果怎么处理的落地问题。它适合那些在 Tekla 里做参数化建模、写自动化脚本、或者想摆脱重复劳动的深化设计师和软件工程师。这篇文章我会从引用 DLL 讲到插件骨架再到参数化建模实战最后给到避坑经验和进阶技巧全程按我自己的踩坑记录来写希望帮你在 OpenAPI 这条路上少走点弯路。2. 把引用吃透四个核心 DLL 与第一条通路2.1 别急着写代码先搞懂 Reference 里四个核心 DLLTekla OpenAPI 的 Reference 文档看起来像个黑匣子几万个类堆在命名空间里很容易把人劝退。但其实你日常开发真正会用到的核心程序集就四个把它们的关系理清楚Reference 文档里 80% 的内容都能迅速定位。DLL 名称核心命名空间主要职责Tekla.Structures.dllTekla.Structures基础连接、几何点、线、向量定义所有二次开发的地基Tekla.Structures.Model.dllTekla.Structures.Model访问模型数据库操作零件、构件、螺栓、焊缝等实体Tekla.Structures.Drawing.dllTekla.Structures.Drawing图纸自动化视图、标注、尺寸、构件图处理Tekla.Structures.CustomProperty.dllTekla.Structures.CustomProperty自定义属性读写插件与图纸/模型之间传参的关键我最开始踩的一个坑就是一股脑把四个 DLL 全引用进去结果项目编译出一堆版本冲突警告。后来学乖了做模型自动化只引用前两个做图纸自动化再引入 Drawing做属性扩展才碰 CustomProperty。Reference 文档里每个类都有个Assembly标注你照着那个找就行别贪多。2.2 最小可复现模型连接与遍历不管你后面要做什么功能第一步永远是建立 API 与当前模型的连接。这个连接如果没建立起来后面所有代码都会在Model对象上直接抛空引用异常。我一般会写一个最小可复现模型来验证通路代码量不大但能排查掉 90% 的环境问题。using Tekla.Structures; using Tekla.Structures.Model; public class TeklaConnectionTest { public bool ConnectAndReadModel() { // 1. 建立与 Tekla 进程的全局连接 TeklaStructures.Connect(); ConnectionStatus status TeklaStructures.Connect(); if (status ! ConnectionStatus.ConnectionStatusOK) { return false; // 连接失败检查 Tekla 是否以完整模式启动 } // 2. 实例化 Model 对象代表当前打开的模型 Model model new Model(); if (!model.GetConnectionStatus()) { return false; // 连接状态为 false 时后续操作全部无效 } // 3. 获取模型中的梁对象验证读取通道 ModelObjectSelector selector model.GetModelObjectSelector(); var beams selector.GetAllObjectsWithTypeBeam(); int count 0; foreach (var obj in beams) { count; if (obj is Beam beam) { // 这里先不修改只读属性确保 API 通路完全打通 string profile beam.Profile.ProfileString; string material beam.Material.MaterialString; } } // 4. 断开连接释放 API 占用的句柄 TeklaStructures.Disconnect(); return count 0; } }这段代码里有几个参数值得注意。ConnectionStatus.ConnectionStatusOK是唯一能继续往下走的状态如果你看到的是ConnectionStatusConnectionFailed多半是 Tekla 软件没开或者你开了但没进入任意模型。GetAllObjectsWithTypeBeam()是泛型过滤它等价于你在 Reference 里查到的GetAllObjectsWithType(Type type)的重载版本用泛型写可以省掉后面的类型判断。beam.Profile.ProfileString返回的是截面名称字符串比如HN400x200这是后面批量修改的基础。读属性不需要事务改属性才需要这个区别我放在第 4 章细讲。2.3 从 Reference 中提取参数不要死记硬背Tekla OpenAPI 的 Reference 文件chm 或网页格式里有完整的类继承关系和属性说明但直接搜的效率非常低。我一般会先在 Reference 里定位类所在的程序集然后直接用代码补全来探索属性。你按下CtrlSpace看智能提示会看到InsertionPoint、CoordinateSystem、Class、Name这些常见属性这些都是ModelObject基类里定义好的。真正要查数据库字段对应关系时Reference 里每个属性下面会有一段Description里面经常藏着数据库字段名比如Part.PART_ID。这个 ID 在你后面写跨模块同步功能时特别有用先记着就好。提示如果你用 Visual Studio把 Tekla 安装目录下的nt\bin\net加到项目引用路径里面就是这些 DLL。不要从C:\Windows\Microsoft.NET里乱找版本完全对不上。3. 从参考到运行搭一个能挂进 Tekla 的插件骨架3.1 为什么是插件dll而不是宏csTekla 自带宏录制功能很多初学者会用宏录一段操作然后导成 C# 代码来改。宏的本质是调用 OpenAPI 把界面操作重放一遍它的问题是逻辑全在一个Main函数里没有输入定义也没有异常隔离。你要做一个给别人用的批量建模工具宏的代码结构撑不住。插件的优势在于它实现了 Tekla 规定的接口能拿到用户拾取的点、对象列表、甚至能把自己挂到菜单和工具栏上。从 Reference 的角度看插件核心就是PluginBase和PluginLoaderBase两个类后者负责把插件加载到 Tekla 环境前者负责业务逻辑。3.2 插件骨架DefineInput 与 Run 的分工写插件的第一步是创建类库项目目标框架选.NET Framework 4.7.2或更高具体看你用的 Tekla 版本。不要选.NET CoreTekla 的 API 底层是 .NET Framework选错了连引用都加不进去。下面是一个最简插件骨架你可以在任何空项目里跑起来。using System; using System.Collections.Generic; using Tekla.Structures; using Tekla.Structures.Model; using Tekla.Structures.Model.UI; using Tekla.Structures.Plugin; namespace MyTeklaPlugin { // 告诉 Tekla 这个类的插件名称会显示在菜单里 [Plugin(MyFirstPlugin)] public class MyFirstPlugin : PluginBase { // DefineInput 负责定义这个插件需要用户提供什么 public override ListInputDefinition DefineInput() { ListInputDefinition inputs new ListInputDefinition(); // 让用户拾取一个点作为插入点 inputs.Add(new InputDefinition(InputType.PickPoint)); return inputs; } // Run 是插件的主入口insertionPoint 就是用户拾取的点 public override bool Run(Point insertionPoint) { try { // 在这里写你的核心逻辑 return true; } catch (Exception ex) { // 插件环境里异常不能直接抛给 Tekla先记录再返回 false return false; } } } }这段代码的骨架作用很关键。DefineInput里可以添加多个InputDefinition比如先拾取一个点再拾取一组对象对应的InputType分别是PickPoint和PickObjects。Run方法里的insertionPoint参数是PickPoint拾取到的那个点在世界坐标系下的坐标很多新手以为插件不需要这个参数结果在Run里自己又去创建点绕了一圈反而丢了精度。插件编译通过后把生成的 dll 复制到 Tekla 的C:\Program Files\Tekla Structures\版本\nt\bin\plugins目录下重启 Tekla 就能在应用菜单里看到它。3.3 选择过滤PickObjects 的正确打开方式很多实际场景里用户不是点一个点而是框选一批梁或柱来批量处理。这时候InputDefinition要换成PickObjects并且在Run里用Selection对象来取。我见过不少人在这里翻车Run里拿不到Selection是因为 Tekla 的拾取结果不是实时传递到插件的而是要先从模型里把选中对象捞回来。public override bool Run(Point insertionPoint) { // 注意不是直接遍历 UI 里的 Selection而是通过 ModelObjectSelector Model model new Model(); ModelObjectSelector selector model.GetModelObjectSelector(); // 从当前模型中选择被选中的对象 var selected selector.GetObjectsByType(Beam.BeamType); foreach (var obj in selected) { if (obj is Beam beam) { // 这时才拿到用户选中的梁对象 } } return true; }这里要留意Beam.BeamType这个静态字段它替代了旧版本里写在ModelObject上的类型枚举。你在 Reference 里查Beam类时会发现它继承自Part而Part继承自ModelObject所以Beam天然拥有Name、Class、Material、Profile这些属性。正确的捞对象姿势是直接用GetObjectsByType(Beam.BeamType)而不是先用GetAllObjectsWithTypeModelObject()再自己做类型判断。后者会把模型里所有的零件、螺栓、焊缝全捞一遍性能差一截。4. 参数化建模实战改截面、加螺栓的 API 路径4.1 构件层级Beam、Part 与 ModelObject 的关系在修改参数之前先花 30 秒看清 Tekla 的类继承树。Reference 里Beam的继承链是这样的ModelObject-Part-Beam。ModelObject负责的是 ID、名称、坐标系这些基础数据Part增加了Profile、Material、Class、Position这些构件属性Beam则增加了起点、终点和方向向量。这个结构决定了你改截面时能调到什么程度。Profile是Profile类型它有一个ProfileString属性直接改这个字符串就能换截面。但很多初学者不知道的是改完必须调用Modify()否则 Tekla 的内存模型里还是旧数据。using Tekla.Structures.Model; public void ChangeBeamProfile(string beamId, string newProfile) { Model model new Model(); // 通过 ID 直接拿到对象ID 是字符串类型 ModelObject obj model.GetModelObjectByID(beamId); if (obj is Beam beam) { // 修改前先记录旧截面方便回滚 string oldProfile beam.Profile.ProfileString; beam.Profile.ProfileString newProfile; // 关键步骤Modify 把内存里的修改同步到模型数据库 bool success beam.Modify(); if (!success) { // 修改失败要回滚 beam.Profile.ProfileString oldProfile; beam.Modify(); } } }参数说明就藏在代码里。GetModelObjectByID(string)里面传的 ID是你在第 2 章最小可复现模型里拿到的那种字符串 ID不是数据库自增整数。Modify()的返回值是bool如果返回false通常意味着当前线程没有开启事务。我在这地方翻过车以为Modify()内部会自己处理事务结果静默失败模型上什么都没变。后面才意识到OpenAPI 里所有写操作都必须包在Transaction里。public bool UpdateBeamWithTransaction(string beamId, string newProfile) { Model model new Model(); // 开启一个事务事务名建议写清楚用途 Transaction transaction new Transaction(model); transaction.Start(Change Profile); ModelObject obj model.GetModelObjectByID(beamId); if (obj is Beam beam) { beam.Profile.ProfileString newProfile; beam.Modify(); // 事务提交这里才是真正落库 return transaction.Commit(); } // 出错时回滚不留半截数据 transaction.RollBack(); return false; }事务的作用是让一系列操作要么全部成功要么全部不生效。Start方法里传入的字符串会显示在模型历史记录里方便你排查是哪个插件改了模型。我看到很多 macaroon 生成的代码里事务名是默认的但我建议你养成写清楚事务名的习惯模型出问题时这是第一手线索。4.2 加螺栓BoltGroup 参数与正向轴陷阱螺栓比改截面复杂得多因为它涉及一个方向问题。BoltGroup是一个附着在零件上的连接对象它有三个核心参数组螺栓定义大小、标准、孔定义直径、长圆孔、位置定义坐标、方向。坑就在方向里。using Tekla.Structures.Geometry3d; using Tekla.Structures.Model; public void AddBoltGroupToBeam(Beam beam, Point position, Vector direction) { // 这个螺栓组要加到 Beam 的一端 BoltGroup boltGroup new BoltGroup(); boltGroup.BoltSize 20.0; // M20 螺栓 boltGroup.BoltStandard ISO 4014; // 普通六角头螺栓标准 boltGroup.BoltType BoltGroup.BoltTypeEnum.BOLT_TYPE_NORMAL; boltGroup.HoleDiameter 22.0; // 比螺栓大 2mm 的圆孔 // 位置参数参考点、方向向量、旋转角度 Position positionDef new Position(); positionDef.Plane Position.PlaneEnum.MIDDLE; // 螺栓在构件中部 positionDef.Rotation Position.RotationEnum.BOLT_HOLE_ALIGNED; // 螺栓孔对齐 boltGroup.Position positionDef; // 正向轴决定螺栓打进来的方向这个最容易踩坑 boltGroup.PositiveAxis direction; // 把螺栓组关联到目标零件 boltGroup.AddToModel(beam); boltGroup.Insert(); }这个代码里最玄学的就是PositiveAxis。它是个Vector表示螺栓从哪边打进来。如果方向反过来螺栓就会出现在构件另一侧在图纸上表现为完全相反。我第一次写的时候直接用了new Vector(0, 0, 1)结果在斜梁上全部打反了。后来才注意到 Reference 里对PositiveAxis的描述是 螺栓组正方向轴向量需要根据梁的坐标系计算。更稳妥的做法是从梁的起点、终点算出方向Vector GetBeamPositiveAxis(Beam beam) { Point start beam.StartPoint; Point end beam.EndPoint; // 从起点指向终点的单位向量 Vector direction new Vector(end.X - start.X, end.Y - start.Y, end.Z - start.Z); direction.Normalize(); return direction; }用这个方法得到的轴向永远不会跟梁身拧着。这里也引出一个通用教训凡是 Reference 里带Axis、Plane、Rotation的参数都是从几何坐标语义出发的不能拍脑袋给全局坐标。多花两分钟查一下当前构件的坐标系能省掉后面一小时的返工。5. 避坑指南OpenAPI 开发中五个高频翻车现场5.1 异常Object reference not set to an instance of an object.现象运行插件时软件直接弹这个错指向某一行代码但那一行看起来没问题。原因最常见的是Model实例没有成功获取到当前模型。比如在宏代码里直接new Model()但 Tekla 当前只在打开软件、没打开具体模型的状态。第二个常见原因是GetModelObjectByID()返回了null但你没做判空就调用Profile属性。解决首先在所有 API 调用前检查Model.GetConnectionStatus()其次对GetModelObjectByID等返回值为对象的方法一律判空再继续。这个习惯能避免 90% 的空引用异常。5.2 事务未提交模型被锁死现象插件跑完发现模型处于只读状态所有按钮变灰必须重启 Tekla 才能动。原因某个分支里Transaction.Start()了但因为异常或提前return没有走到Commit()或RollBack()事务一直攥在持有它的大旗里。解决把事务放进try-catch-finally在finally里判断事务是否还开着开着就回滚。我通常写一个壳子Transaction transaction new Transaction(model); transaction.Start(safe batch op); try { // 业务逻辑 transaction.Commit(); } catch { transaction.RollBack(); throw; }这样不管中间发生什么事务都不会泄漏。5.3 GetAllObjectsWithType 返回空集合现象在某个模型里能正常遍历梁到另一个模型里返回空。原因第一种情况是当前模型是空的但用户一般不会拿空模型来调插件。第二种情况是过滤条件用的类型不匹配比如模型里的梁实际是ContourPlate你用Beam去捞自然捞不到。第三种情况是模型数据库状态未更新Geometry或Analysis视图下 OpenAPI 访问的是不同的数据库分支。解决先用GetAllObjectsWithTypeModelObject()确认模型里到底有哪些类型再换成具体类型同时确保模型处于完全打开状态不是只打开了某个子视图。5.4 DLL 版本与运行中的 Tekla 不匹配现象编译时没有报错运行时报Could not load file or assembly Tekla.Structures.Model, Version...或者直接BadImageFormatException。原因你本机装了多个 Tekla 版本VS 项目里引用的 DLL 是旧版安装路径下的但当前启动的是新版 Tekla。OpenAPI 的 DLL 是强命名程序集版本号完全匹配才认账。解决每次切换 Tekla 版本时把项目里所有 Tekla 相关引用删掉重新从当前版本的nt\bin\net添加。血泪经验不要用相对路径引用直接引用绝对路径并关掉本地复制选项跑之前人工核对版本。5.5 独立工具连不上模型的玄学现象写了个 exe 工具双击打开能正常启动但调用Connect()时返回失败或者连接成功后Model对象拿到的是空模型。原因Tekla 的 OpenAPI 连接要求调用方以管理员身份运行并启用交互桌面。如果你用任务计划程序或者从 CI 工具里启动 exe运行上下文是 Session 0几乎没有桌面访问权API 自然连不上。解决交互式运行时右键以管理员身份运行如果确实需要无人值守运行得把 Tekla 本身提前打开并加载好目标模型工具只负责连接、不负责拉起软件。注意如果你要开发的是 C 环境下的 Tekla 扩展你会遇到一堆undefined reference to的链接错误那是编译器在告诉你某个符号没有实现本质跟 C# 里空引用异常类似都是没找到该找的东西。先检查库路径再检查函数签名。6. 进阶技巧用反射把 Reference 变成你的内部工具库到了这个阶段你应该已经能熟练增删改查模型对象了。但 Reference 那个黑匣子依然让人头大查一个属性要层层展开。我的做法是用反射直接扫描 DLL把 Tekla 的类结构拉平成一个自己看得懂的 Markdown 文件相当于给自己做一份精简版 Reference。using System; using System.Collections.Generic; using System.Reflection; using System.Text; public class ApiRefGenerator { public static void GenerateSummary(string dllPath, string outputPath) { Assembly asm Assembly.LoadFrom(dllPath); Type[] types asm.GetTypes(); Array.Sort(types, (t1, t2) string.Compare(t1.FullName, t2.FullName, StringComparison.Ordinal)); StringBuilder sb new StringBuilder(); sb.AppendLine(# Tekla API Quick Reference); sb.AppendLine($Generated from {dllPath}); foreach (Type type in types) { // 过滤掉编译器生成的嵌套类 if (type.IsNested type.IsSealed) continue; sb.AppendLine($\n## {type.FullName}); sb.AppendLine($Base Type: {type.BaseType?.FullName ?? none}); // 重点提取属性和方法名这就是你日常查的东西 var props type.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var prop in props) { sb.AppendLine($ - Property: {prop.PropertyType.Name} {prop.Name}); } var methods type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); foreach (var method in methods) { if (method.IsSpecialName) continue; // 跳过 getter/setter 自动生成的方法 sb.AppendLine($ - Method: {method.ReturnType.Name} {method.Name}(...)); } } System.IO.File.WriteAllText(outputPath, sb.ToString()); } }这个反射工具的参数很直接dllPath指向你当前 Tekla 版本目录下的Tekla.Structures.Model.dlloutputPath指向你要生成的 Markdown 文件。生成的表格里会包含每个类的基类、属性类型和方法签名这样你写代码前先翻自己的 Markdown脑子里就有了整个 API 的地图而不是在一片混沌里瞎找。我每次升级 Tekla 版本都会重新生成一份并 diff 两份文档之间新增了哪些类这样新版本有什么能力变化一目了然。另外一个值得养成的习惯是再用反射把枚举值也导出来。Reference 文档里枚举是最难查的比如Position.RotationEnum具体有哪些成员反映到代码里就是BOLT_HOLE_ALIGNED、TOP、BELOW这些值。我记得有一次给现场写批量出图工具因为没做事务回滚把一整层钢梁的截面全改错了老板盯着屏幕看我一行行找回旧参数那叫一个狼狈。从那以后我每次写批量修改工具都会强制走一遍流程先建事务并备份涉及构件的旧参数然后在测试模型里跑一次最后再切到真实模型上执行。顺序永远不要颠倒——备份、测试、执行。这是一个老工程师最笨也最稳的套路。希望这篇文章能帮你在 Tekla OpenAPI 的路上减少几个失眠夜也让你在遇到 Reference 文档翻车时知道自己不是一个人。本文还有配套的精品资源点击获取
返回列表