简介:这份资源面向钢结构详图设计与TEKLA二次开发初学者,聚焦图纸模块的编程入门,帮助读者理解如何通过API扩展TEKLA功能、实现图纸管理与数据提取的自动化。内容围绕载入模型图纸列表、选择模型图纸、打开模型图纸、取图纸数值四个核心环节展开,涉及数据库查询、UI交互、视图控制与几何属性读取等知识点,适合具备一定C#或VB.NET基础、希望提升工作效率的工程师参考。资源包共20个文件,以cs源代码文件为主,辅以resx资源文件、csproj项目文件、sln解决方案及config配置等,整体约74KB,结构紧凑,可直接在Visual Studio中打开学习。目前已有785人学习下载。通过实际源码示例,读者能掌握TEKLA图纸数据的读取与展示思路,理解二次开发中界面绑定与事件处理的实现方式,并借鉴几何数值提取的编程逻辑,为后续定制化工作流打下基础。
1. TEKLA二次开发图纸入门:从一根梁的自动标注说起
如果你正在用 TEKLA Structures 做钢结构深化,每天重复着「打开图纸 → 手动标注构件 → 导出 → 改图 → 再导出」这套动作,那你大概率已经想过:这些活儿能不能让程序替我干?TEKLA 二次开发图纸入门这件事,核心就是回答这个问题——用代码去驱动图纸里的视图、标注、零件标记和图纸布局,把重复劳动交给脚本。它适合两类人:一类是深化设计出身、想把手上的重复操作自动化但没写过几行代码的工程师;另一类是写过 C# 或 Python、但对 TEKLA 图纸对象模型不熟的程序员。源代码在这里不是让你抄一份就完事,而是让你看懂「一根梁从模型到图纸再到标注」这条链路上,哪些对象是可编程的、哪些参数是必须调的。我见过太多人卡在第一步:不知道从哪打开 API,也不知道图纸对象和模型对象根本是两套体系。这篇就把这条链路拆开讲透。
2. 搞懂 TEKLA 图纸 API 的对象模型:别把模型对象当图纸对象用
2.1 模型对象和图纸对象是两套体系
TEKLA 的 Open API 里,模型侧和图纸侧是分开的。模型侧你操作的是ModelObject、Beam、Part、Connection这些;图纸侧你操作的是Drawing、DrawingObject、ViewBase、PartMark、Dimension这些。很多人第一次写图纸脚本翻车,就是因为拿着Beam对象去图纸里找,结果发现图纸里根本没有Beam,只有PartMark和Dimension。
图纸的本质是模型的一个「快照 + 注释层」。模型里一根梁,到了图纸里变成三样东西:几何线(Line、Arc等DrawingObject)、零件标记(PartMark)、尺寸标注(Dimension)。你要改标注,操作的是Dimension;你要改标记内容,操作的是PartMark;你要改视图范围,操作的是ViewBase的属性和View.ViewRectangle。
所以入门第一件事,是把下面这张对应关系记牢:
| 模型侧对象 | 图纸侧对应对象 | 典型用途 |
|---|---|---|
Beam/Part | PartMark | 读取/修改零件标记内容 |
Beam的几何 | Line/Arc/Circle | 遍历图纸几何、判断位置 |
Model的坐标 | ViewBase.ViewCoordinateSystem | 视图坐标系转换 |
Part的尺寸 | Dimension | 自动标注、批量改标注 |
Drawing本身 | Drawing+Sheet | 图纸布局、图框、导出 |
2.2 打开图纸和遍历图纸对象的最小代码
下面这段 C# 代码是入门必跑的最小闭环:连接 TEKLA、拿到当前打开的图纸、遍历图纸里的所有对象并打印类型。跑通它,你才算真正摸到了图纸 API 的门。
using Tekla.Structures.Model; using Tekla.Structures.Drawing; using Tekla.Structures.Geometry3d; public class DrawingWalker { public void WalkCurrentDrawing() { // 拿到当前打开的图纸,如果没有打开图纸会返回 null DrawingHandler drawingHandler = new DrawingHandler(); Drawing currentDrawing = drawingHandler.GetActiveDrawing(); if (currentDrawing == null) { // 没有活动图纸,直接退出,别硬跑 return; } // 遍历图纸下的所有 Sheet(通常一张图纸一个 Sheet) DrawingObjectEnumerator sheets = currentDrawing.GetSheetObjects(); while (sheets.MoveNext()) { DrawingObject obj = sheets.Current as DrawingObject; if (obj == null) continue; // 打印对象类型和 ID,先看清楚图纸里到底有什么 System.Console.WriteLine( "Type: " + obj.GetType().Name + " | ID: " + obj.GetIdentifier().ID ); // 如果是视图,继续往里遍历视图内的对象 if (obj is ViewBase view) { DrawingObjectEnumerator viewObjs = view.GetObjects(); while (viewObjs.MoveNext()) { DrawingObject inner = viewObjs.Current as DrawingObject; if (inner == null) continue; System.Console.WriteLine( " ViewObj: " + inner.GetType().Name ); } } } } }逻辑说明:DrawingHandler.GetActiveDrawing()是入口,拿不到就说明当前没有活动图纸,直接返回,不要继续。GetSheetObjects()拿的是图纸页级别的对象,通常是图框、视图、表格。ViewBase.GetObjects()才是视图内部的几何和标注。参数说明:GetIdentifier().ID是 TEKLA 内部唯一 ID,后面你要定位某个对象、做增量修改,全靠它。注意DrawingObjectEnumerator是单向迭代器,MoveNext()之后才能读Current,不能随机访问。
2.3 图纸坐标系和模型坐标系的转换
这是第二个高频翻车点。模型里一根梁的起点坐标是(12000, 3000, 0),到了图纸视图里,这个坐标可能变成(350, 200),因为视图有自己的坐标系和比例。你要在图纸上按模型位置放标注,就必须做转换。
常见做法是用ViewBase.ViewCoordinateSystem和ViewBase.ModelToView这类转换方法。我一般会先拿视图的坐标系原点,再把模型点转成视图点,最后用视图点去创建Dimension或PartMark。如果你跳过这一步,直接拿模型坐标去图纸里画线,结果就是标注飞到图纸外面,找都找不回来。
// 假设 view 是一个 ViewBase 对象,modelPoint 是模型坐标 Point modelPoint = new Point(12000, 3000, 0); // 模型坐标转视图坐标 Point viewPoint = view.ModelToView(modelPoint); // 反过来,视图坐标转模型坐标 Point backToModel = view.ViewToModel(viewPoint);参数说明:ModelToView返回的是视图内的二维点(Z 通常为 0),ViewToModel是逆变换。注意这两个方法依赖视图的当前坐标系,如果视图被旋转过,转换结果会跟着变。所以做自动标注前,先确认视图没有被人手动旋转过,否则你的标注位置会整体偏掉。
3. 用源代码跑通第一个自动标注:从零件标记到尺寸标注
3.1 自动创建零件标记的完整流程
零件标记(PartMark)是图纸里最常见的注释。自动创建它的流程是:找到视图 → 找到视图里的零件几何 → 在几何附近插入PartMark→ 设置标记内容和位置。
下面这段代码演示在视图里给每个零件插入一个零件标记:
using Tekla.Structures.Drawing; using Tekla.Structures.Geometry3d; public class AutoPartMark { public void InsertMarks(ViewBase view) { DrawingObjectEnumerator objs = view.GetObjects(); while (objs.MoveNext()) { // 只处理零件几何,通常是 Line 或 Arc DrawingObject obj = objs.Current as DrawingObject; if (obj == null) continue; // 拿对象的中点作为标记插入位置 Point insertPoint = GetObjectCenter(obj); if (insertPoint == null) continue; // 创建零件标记,关联到当前对象 PartMark mark = new PartMark(obj, insertPoint); // 设置标记内容,这里用默认模板,实际项目要换成自己的模板 mark.Attributes.Content = "PART_POS"; mark.Insert(); } } private Point GetObjectCenter(DrawingObject obj) { // 简化处理:实际项目里要根据对象类型取包围盒中心 if (obj is Line line) { return new Point( (line.StartPoint.X + line.EndPoint.X) / 2, (line.StartPoint.Y + line.EndPoint.Y) / 2, 0 ); } return null; } }逻辑说明:PartMark的构造函数第一个参数是关联对象,第二个是插入点。Attributes.Content决定标记显示什么内容,常见值有PART_POS(零件位置)、PROFILE(截面)、MATERIAL(材质)。Insert()才是真正写入图纸,不调用它什么都不会发生。参数说明:插入点用视图坐标,不是模型坐标,所以如果你从模型坐标来,先做ModelToView转换。注意PartMark插入后如果位置重叠,TEKLA 不会自动避让,需要你自己算偏移。
3.2 自动创建尺寸标注的两种方式
尺寸标注比零件标记复杂,因为要指定标注的两个端点、标注方向、标注类型。TEKLA 图纸 API 里常用的有Dimension和DimensionSet。入门阶段先用Dimension单条创建,跑通后再考虑批量。
using Tekla.Structures.Drawing; using Tekla.Structures.Geometry3d; public class AutoDimension { public void CreateLinearDimension(ViewBase view, Point p1, Point p2) { // 把模型点转成视图点 Point v1 = view.ModelToView(p1); Point v2 = view.ModelToView(p2); // 创建线性尺寸,方向为水平 Dimension dimension = new Dimension( view, v1, v2, new Vector(1, 0, 0) // 水平方向 ); // 设置尺寸类型为线性 dimension.Attributes.Type = DimensionType.LINEAR; dimension.Insert(); } }逻辑说明:Dimension构造函数需要视图、两个端点、标注方向向量。方向向量决定标注是水平、垂直还是斜向。Attributes.Type设置标注类型,常见有LINEAR、ANGULAR、RADIAL。参数说明:两个端点必须是视图坐标,方向向量是单位向量。注意如果两个端点太近,TEKLA 可能拒绝创建,实际项目里要加距离判断。
3.3 批量标注的参数化思路
单条标注跑通后,批量标注的关键是「参数化」:把标注位置、偏移量、标注类型做成可配置的参数,而不是写死在代码里。我一般会用一个配置类来管理这些参数:
public class DimensionConfig { public double OffsetX { get; set; } = 100; // 水平偏移 public double OffsetY { get; set; } = 50; // 垂直偏移 public DimensionType Type { get; set; } = DimensionType.LINEAR; public bool SkipShortEdges { get; set; } = true; // 跳过太短的边 public double MinEdgeLength { get; set; } = 200; // 最短标注边长 }参数说明:OffsetX和OffsetY控制标注离几何的距离,太小会重叠,太大会跑出视图。MinEdgeLength是过滤短边的阈值,避免给几毫米的倒角也标尺寸。这些参数没有万能值,要根据你的图纸比例和视图大小调。我一般先在单张图纸上试,调好了再批量跑。
4. 避坑与排查:图纸二次开发最常见的 5 个翻车现场
4.1 现象:脚本跑完图纸没变化,但也没报错
原因:最常见的是忘了调用Insert()或Modify()。TEKLA 的图纸对象是「先创建、后提交」的模式,你new了一个PartMark,不调Insert(),它只存在于内存里,图纸上什么都不会出现。另一个原因是当前没有活动图纸,GetActiveDrawing()返回 null,后面所有操作都作用在 null 上,但 C# 不会自动报错。
解决:在每个创建操作后强制调用Insert(),并在入口处加 null 判断。我习惯在脚本开头写一句if (drawing == null) throw new Exception("没有活动图纸");,让问题尽早暴露。
4.2 现象:标注位置全部偏移,整体飞到图纸外面
原因:模型坐标和视图坐标混用。你拿模型坐标去创建PartMark或Dimension,TEKLA 把它当视图坐标处理,结果就是位置完全不对。另一个原因是视图被旋转过,ModelToView的结果和你预期不一致。
解决:所有进入图纸 API 的坐标,先做ModelToView转换。如果视图可能被旋转,先读ViewBase.ViewCoordinateSystem确认坐标系,再决定要不要做额外变换。调试时先把转换后的坐标打印出来,和图纸上手动量出来的位置对比。
4.3 现象:批量标注后图纸卡顿,打开要几十秒
原因:一次性插入了大量Dimension和PartMark,每个对象都触发一次图纸重绘。TEKLA 图纸对象越多,重绘越慢。如果你在循环里每插一个就刷新一次,性能会崩。
解决:把插入操作放在一个事务里,或者先收集所有要插入的对象,最后统一Insert()。另外,过滤掉不需要标注的短边和小零件,能减少一半以上的对象数量。我一般会先统计要标注的数量,超过 500 条就分批跑,每批之间让用户确认。
4.4 现象:零件标记内容显示为空白或乱码
原因:Attributes.Content设了一个当前模板里不存在的字段。TEKLA 的标记内容依赖图纸模板,模板里没有的字段,显示出来就是空白。另一个原因是编码问题,中文内容在某些模板下会乱码。
解决:先用 TEKLA 手动创建一个标记,看它默认的Content是什么,照着设。中文内容尽量用模板里的字段引用,不要直接写死字符串。如果必须写中文,确认模板文件编码是 UTF-8。
4.5 现象:脚本在别人电脑上跑不通,报找不到程序集
原因:TEKLA Open API 的程序集路径依赖安装目录和版本。你本机引用的Tekla.Structures.Drawing.dll路径,在别人电脑上可能不存在,或者版本不一致。
解决:不要用绝对路径引用 DLL,改用 NuGet 包或者把 DLL 放在项目相对目录下。如果团队里 TEKLA 版本不统一,先确认版本号,再决定用哪个版本的 API。我一般会在脚本开头打印 TEKLA 版本,方便排查。
5. 进阶技巧:用配置驱动图纸标注,让脚本能复用
入门跑通之后,真正决定这套东西能不能在项目里落地的,是「可复用性」。你不可能每张图纸都改一遍代码,所以要把标注规则抽成配置。我常用的做法是写一个 JSON 配置文件,描述「哪些零件要标、标什么内容、偏移多少」,脚本读配置执行。
{ "rules": [ { "partType": "Beam", "markContent": "PART_POS", "offsetX": 100, "offsetY": 50, "dimensionType": "LINEAR", "minEdgeLength": 200 }, { "partType": "Column", "markContent": "PROFILE", "offsetX": 150, "offsetY": 80, "dimensionType": "LINEAR", "minEdgeLength": 300 } ] }读取配置的代码:
using System.IO; using System.Text.Json; public class RuleLoader { public List<MarkRule> LoadRules(string path) { string json = File.ReadAllText(path); var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; return JsonSerializer.Deserialize<List<MarkRule>>(json, options); } } public class MarkRule { public string PartType { get; set; } public string MarkContent { get; set; } public double OffsetX { get; set; } public double OffsetY { get; set; } public string DimensionType { get; set; } public double MinEdgeLength { get; set; } }逻辑说明:RuleLoader把 JSON 反序列化成规则列表,脚本遍历规则,对每类零件应用对应的标注参数。参数说明:PartType对应模型里的零件类型,MarkContent对应PartMark.Attributes.Content,OffsetX/Y控制标注偏移,MinEdgeLength过滤短边。这样改规则不用改代码,换个项目只换 JSON 文件就行。
验证方法:跑完脚本后,不要只看图纸「有没有标注」,要抽查三类零件:最长的一根梁、最短的一根梁、一个柱。看标注位置是否合理、内容是否正确、有没有重叠。我一般会随机抽 5 张图纸,手动量 3 个标注的位置,和脚本输出的坐标对比,误差在 5 毫米以内就算通过。
一个具体技巧:如果你的项目里图纸数量多,不要一次性全跑。先跑一张,确认没问题,再跑十张,最后全量。每次跑完把日志写到一个文本文件里,记录「图纸名、插入标注数、耗时、异常」。出问题时,日志比图纸本身更有用。
我自己踩过最深的坑,是早期写脚本时没做坐标转换,结果一批图纸的标注全部偏到图框外面,甲方审图时才发现,返工了两天。从那以后,我养成了一个习惯:任何涉及坐标的脚本,先打印转换前后的值,确认无误再往下写。希望帮到你。
本文还有配套的精品资源,点击获取