最近用 C# 对 ORD
进行二次开发,做一个自动出图工具。其中必不可少的就是标注,被各种标注折腾得死去活来,特别是引线标注,坑特别多,特记录下来,供和大家学习交流,若有不正确之处,还请斧正。
简介
在 C# 中,引线标注采用的是 NoteCellHeaderElement
这个类。具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 TextBlock textBlock = new TextBlock(_dimensionCreateData.GetTextStyle(), DgnModel); textBlock.AppendText(annotation); NoteCellHeaderElement header = new NoteCellHeaderElement(out Element leaderElement, textBlock, this ._dimensionCreateData.GetDimensionStyle(), DgnModel, new DPoint3d[] { arrowHeadPoint, arrowTailPnt }); DimensionElement dim = leaderElement as DimensionElement; DimensionStyle ds = dim.GetDimensionStyle(); ds.SetIntegerProp(0 , DimStyleProp.MLNote_HorAttachment_INTEGER); dim.ApplyDimensionStyle(ds, true ); header.AddToModel(out dim,dgnModel);
下面详细分析为了得出上面的几行代码,需要处理的技术问题。
_dimensionCreateData
怎么来的?
_dimensionCreateData
是 DimensionCreateData
的实例,查看 DimensionCreateData
定义,我们可以看到,它是一个抽象类,不能实例化它,所以就想着,看在 ORD
的程序集里面找一个实现它的类,可以查找无果,最后,从优先社区中得知,需要自己子类化一下它,代码如下(代码是项目中的一部分,没有简化,不能开箱即用,仅供参考)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 using Bentley.DgnPlatformNET;using Bentley.DgnPlatformNET.Elements;using Bentley.GeometryNET;using Bentley.MstnPlatformNET;using swOpenRoadsSDK;using SwTools.SimpleCAD.Enum.Extension;using System.Collections.Generic;namespace SwTools.RebarTools.SDK.Dimension { class SwDimesionCreateData : DimensionCreateData { private static Dictionary<SwDimensionStyle, DimensionStyle> _dimensionStyleDic = new Dictionary<SwDimensionStyle, DimensionStyle>(); private static Dictionary<SwTextStyle, DgnTextStyle> _textStyleDic = new Dictionary<SwTextStyle, DgnTextStyle>(); private static Dictionary<SwLevel, LevelId> _levelDic = new Dictionary<SwLevel, LevelId>(); private readonly Symbology _symbology; private readonly DirectionFormatter _directionFormatter; public DimensionStyle DimensionStyle { get ; } public DgnTextStyle DgnTextStyle { get ; } public LevelId LevelId { get ; } public SwDimesionCreateData (DimensionStyle dimStyle, DgnTextStyle textStyle, Symbology symb, LevelId levelId, DirectionFormatter formatter ) { DimensionStyle = dimStyle; DgnTextStyle = textStyle; LevelId = levelId; _symbology = symb; _directionFormatter = formatter; } public SwDimesionCreateData (SwDimensionStyle swDimensionStyle,SwTextStyle swTextStyle,Symbology symb, SwLevel swLevel,DirectionFormatter formatter ) { if (_dimensionStyleDic.TryGetValue(swDimensionStyle,out DimensionStyle value1)) { DimensionStyle = value1; } else { DimensionStyle = DimensionHelper.GetDimensionStyle(swDimensionStyle.ToString()); _dimensionStyleDic.Add(swDimensionStyle, DimensionStyle); } if (_textStyleDic.TryGetValue(swTextStyle,out DgnTextStyle value2)) { DgnTextStyle = value2; } else { DgnTextStyle = DrawingHelper.GetTextStyle(swTextStyle.ToStringValue()); _textStyleDic.Add(swTextStyle, DgnTextStyle); } if (_levelDic.TryGetValue(swLevel,out LevelId value3)) { LevelId = value3; } else { LevelHandle levelByName = Session.Instance.GetActiveDgnFile().GetLevelCache().GetLevelByName(swLevel.ToString()); LevelId = levelByName.LevelId; _levelDic.Add(swLevel, LevelId); } _symbology = symb; _directionFormatter = formatter; } public override DimensionStyle GetDimensionStyle () { return DimensionStyle; } public override DgnTextStyle GetTextStyle () { return DgnTextStyle; } public override Symbology GetSymbology () { return _symbology; } public override LevelId GetLevelId () { return LevelId; } public override int GetViewNumber () { return 0 ; } public override DMatrix3d GetDimensionRotation () { return DMatrix3d.Identity; } public override DMatrix3d GetViewRotation () { return DMatrix3d.Identity; } public override DirectionFormatter GetDirectionFormatter () { return _directionFormatter; } #region 静态方法 public static SwDimesionCreateData GetSwBridgeAnnotationCreateData () { return new SwDimesionCreateData(SwDimensionStyle.SW_Bridge, SwTextStyle.CB_25, new Symbology(), SwLevel.sw_尺寸, null ); } public static DgnTextStyle GetDgnTextStyle (SwTextStyle swTextStyle ) { if (_textStyleDic.TryGetValue(swTextStyle, out DgnTextStyle style)) { return style; } else { DgnTextStyle styleNew = DrawingHelper.GetTextStyle(swTextStyle.ToStringValue()); _textStyleDic.Add(swTextStyle, styleNew); return styleNew; } } #endregion } }
它的第 1
个点代表引线箭头的坐标,后面的点代表引线导线的关键点。一般传入两个点就可以了。
怎么实现引线和文字关联?
开始 new NoteCellHeaderElement 对象的时候,看到它 out 了一个
element
, 便直接将它和 header
添加到了
model。这时查看模型元素后,发现它们俩是分开的,拽文字引线不跟着动,很难受。后面在众多相似的方法中,在
NoteCellHeaderElement
中找到一个
AddToModel
的重载,它是这样的:
1 public BentleyStatus AddToModel (out Element leaderElement, DgnModel dgnCache ) ;
从上面的定义里面,我们知道,它会 out
一个元素出来,但是,这个其实就是个坑,一个大坑。这个参数真正的意思是要将从上文得到的
leaderElement 传入进去,它里面会与 header 进行关联,并添加到 model
中。
所以,真正的用法应该是开篇示例代码那样。
怎么让文字水平吸附为自动?
如上图,如果不对参数进行设置,默认生成的引线标注是 1 和 2
的样式,如果要得到 3 ,需要设置它的对齐方式。就是下面的代码:
1 2 3 4 DimensionElement dim = leaderElement as DimensionElement; DimensionStyle ds = dim.GetDimensionStyle(); ds.SetIntegerProp(0 , DimStyleProp.MLNote_HorAttachment_INTEGER); dim.ApplyDimensionStyle(ds, true );
怎么知道要设置哪个属性值呢?
上面是直接贴出了代码,可能就有人会问,为什么就知道是设置DimStyleProp.MLNote_HorAttachment_INTEGER
这个属性呢?下面介绍一下怎么去解决这种类似的问题。这种问题,我称之为
“操作代码化”
问题,就是说用户可以使用软件手动操作生成出来,但是现在需要用程序来实现。
这种问题的突破口就是要回归操作
在应用程序中,手动放置需要生成的元素,然后通过 key-in
analyze element
这个命令去查看元素的详细信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // 部分信息如下 Element ID: 160542 File Name: C:\WorkSets\codeTesting\dgn\柱测试.dgn Model Name: 桩_图纸 Last Modified: 2020/08/27 00:52:41 Type Specific Details: Dimension Type : IsAnnotation : Yes Proxy Cell : <None> Height : 0.00000 Point #0 : 0.50705, 0.26187 Point #1 : 0.50178, 0.26847 A Rotation : | 1.0000000 0.0000000 0.0000000 | |-0.0000000 1.0000000 0.0000000 | | 0.0000000 0.0000000 1.0000000 | ......
画一个对照元素,也通过命令查看元素的详细信息
将两个详细信息进行对比,差异的部分就是导致两个元素表征显示不一样的原因,然后在程序里面去找到相应的设置。
那么现在又有一个问题了,程序里面的获得元素,都是 Element
这个父类黑箱子,而要设置,就要进行拆箱,我们不知道究竟拆成什么类型?
这个问题,可以在运行时,通过 .GetType()
来获取类型,就知道应该转成什么类型了。