API框架介绍

MicroStation CE 托管应用开发架构主要分为六大块:
底层由两块组成,
一个是几何库(GeometryNET),它主要负责的是几何层面的一些东西,几何库并不依赖于MicroStation ,其他平台也能应用该几何库,它里面包含很多几何相关的API,比如空间点、变换矩阵、旋转矩阵、平面几何等。
另一个是属性表达库(ECObjects),它主要负责EC相关的API。
DgnPlatformNET:DGN平台库,它主要负责加载底层的两个库,将底层对象跟DGN文件的格式进行关联,在内存里加载操作dgn文件、模型、元素等。它并不关心图形的显示及用户的交互操作,它只是后台读写dgn文件。
DgnDisplayNET:DGN文件显示库,它主要负责将dgn文件的内容显示及交互式工具。
MstnPlatformNet:MicroStation层面的应用库,里面包括管理器、会话等应用。
最顶层就是用户自定义的Addins工具,该工具可以加载下面所有的库。

基础平台API介绍 - 图1

几何API

几何API是几何库(GeometryNET)提供的相关接口,它主要是面向应用程序提供几何运算方面的支持,它提供了通用的几何图元(点\线\面\定位运算\变换),并提供了用于构造元素的数据结构。

主要功能

  1. 几何对象创建;
  2. 定位,通过定位能算出一些特征量,从而判断该特征量是否位于某一个区间内。

下面列举了几种定位的情况:

  1. 将画出来的东西准确的放到三维空间中的某一个点并让其拥有特定的空间姿态(DTransform3D\DMatrix3D);
  2. 判断一个点是否在某一条曲线上;
  3. 判断画出来的元素是否在某一个空间区域内;
  4. 判断两条曲线是否重合;

  5. 相交计算(延长\修剪\拼接等),几何库内的线元,基本上都包含了相交运算。

几何类型

基本几何:

  • 空间点(Point): DPoint2d/DPoint3d/DPoint4d
  • 向量(Vector): DVec2d/DVec3d
  • 平面(Plane): DPlane3d/DPlane3dByVectors
  • 轴对齐的包围盒(AABB): DRange1d/DRange2d/DRange3d
  • 矩阵(Matrix): DMatrix4d/Transform/RotMatrix

参数化几何:
曲线(Curve):

  1. - 线段(Line segment): DSegment1d/DSegment3d
  2. - 射线(Ray): DRay3d,射线的作用主要是用来算相交;
  3. - 螺旋线(Spiral): DSpiral2dBase (Clothid) k = k1+lamd*k2
  4. - \圆\椭\椭圆弧(Arc/Circle/Ellipse/EllipseArc): DEllipse3d
  5. - 非均匀有理样条曲线(NURBS): MSBsplineCurve
  6. - 差值曲线(Interpolation curve): MSInterpolationCurve

复杂曲线(Complex Curve):

  1. - CurveVector:它既能包含单条曲线,又能包含曲线集合。集合里面的曲线能以层次状或者树状的形式分布,共同组合来表达开放式曲线、闭合式曲线、单区域及组合区域等。

曲面(Surface):

  1. - 参数化曲面(Parametric surface): 曲面的外形可以通过参数来控制,可以精确的表达参数所代表的表面,MSBsplineSurface
  2. - 离散化曲面(Discrete surface(Mesh)): PolyfaceQuery/PolyfaceHeader

体(Solid):

  1. - 基本体(SolidPrimitive):它是Bentley自带的几何类型,本质上用闭合的PolyfaceHeader来表达一个Solid,因此这种几何数据量比较小执行速度快易于处理,它主要包含以下几类:

圆管(TorusPipe)
圆台、圆锥、圆柱(Cone)
圆球(Sphere)
拉伸体(Extrusion):一个断面,一个拉伸方向和长度形成一个体;
旋转体(RotationalSweep):一个断面绕着一个给定的轴旋转后形成的体;
扫略体(RuledSweep):一个截面沿着一条线扫略形成一个体;

  1. - 智能实体(ISolidKernelEntity): 边界表达实体(BRep entity)是基于西门子 ParaSolid技术,它是由点(Vertex)构成边(Edge),由边(Edge)构成边环(Loops),由环(Loops)构成面(Face),由面(Face)构成翼(Fins),由翼(Fins)构成体(Solid),各个层次直接都有对应的拓扑关系(Topology)。它主要包括下面三种类型:

Wire :由线组成的Body,形成线框体;
Sheet:将没有厚度的一个面称为薄板(Sheet Body);
Solid body:有厚度和尺寸的实体;

几何与元素

元素\几何转换:

  • 线:LineElement 🡸🡺DSegment3d
  • 点串/线串/形:PointStringElement / LineStringElement / ShapeElement 🡸🡺DPoint3ds
  • B样条曲线:BSplineCurveElement 🡸🡺MSBsplineCurve
  • B样条曲面:BSplineSurfaceElement 🡸🡺MSBsplineSurface
  • 圆/椭圆:ArcElement / EllipseElement 🡸🡺DEllipse3d

提取/修改元素几何对象:

  • CurveVector:

提取(CurvePathQuery)
例子:
var curveVector = Bentley.DgnPlatformNET.Elements.CurvePathQuery.ElementToCurveVector(element);
修改(CurvePathEdit)
例子:
Bentley.DgnPlatformNET.Elements.CurvePathEdit pe = element.AsCurvePathEdit();

  • SolidPrimitive :

提取(SolidPrimitiveQuery)
例子:
var solidprimitive= Bentley.DgnPlatformNET.Elements.SolidPrimitiveQuery.GetAsSolidPrimitiveQuery(element) ;
修改(SolidPrimitiveEdit)
例子:
Bentley.DgnPlatformNET.Elements. SolidPrimitiveEdit pe = Bentley.DgnPlatformNET.Elements.SolidPrimitiveEdit.GetAsSolidPrimitiveEdit(element);

  • BsplineSurface:

提取(BsplineSurfaceQuery)
例子:
var bsplinesurfaceQuery = Bentley.DgnPlatformNET.Elements.BsplineSurfaceQuery.GetAsBsplineSurfaceQuery (element) ;
修改(BsplineSurfaceEdit)
例子:
Bentley.DgnPlatformNET.Elements. BsplineSurfaceEdit pe = Bentley.DgnPlatformNET.Elements.BsplineSurfaceEdit. GetAsBsplineSurfaceEdit (element) ;

  • Mesh

提取(MeshQuery)
例子:
var meshQuery = Bentley.DgnPlatformNET.Elements. MeshQuery. GetAsMeshQuery (element) ;
修改(MeshEdit)
例子:
Bentley.DgnPlatformNET.Elements. MeshEdit pe = Bentley.DgnPlatformNET.Elements. MeshEdit. GetAsMeshEdit (element) ;

  • Brep

修改(BRepEdit)
例子:
Bentley.DgnPlatformNET.Elements. BRepEdit pe = Bentley.DgnPlatformNET.Elements. BRepEdit. GetAsBRepEdit (element) ;

  • Text

提取(TextQuery)
例子:
var textQuery = Bentley.DgnPlatformNET.Elements. TextQuery. GetAsTextQuery (element) ;
修改(TextEdit)
例子:
Bentley.DgnPlatformNET.Elements. TextEdit pe = Bentley.DgnPlatformNET.Elements. TextEdit. GetAsTextEdit (element) ;

  • Dimension

提取(DimensionQuery)
例子:
var dimensionQuery = Bentley.DgnPlatformNET.Elements. DimensionQuery. GetAsDimensionQuery (element) ;
修改(DimensionEdit)
例子:
Bentley.DgnPlatformNET.Elements. DimensionEdit pe = Bentley.DgnPlatformNET.Elements. DimensionEdit. GetAsDimensionEdit (element) ;

  • ElementGraphicsProcessor

该类能把任何基于几何数据绘制出来的元素(Element)上的几何数据提取出来然后转换成另外一种几何数据,除了几何转换,它还支持变换栈(transform stack),也就是说它可以把复杂几何分解成维度更低的几何集。
具体用法可以参考MicroStationAPI.chm文档关于ElementGraphicsProcessor介绍:
基础平台API介绍 - 图2

  • DraftingElementSchema

该方法主要是把一组特定类型的几何对象直接转成元素(Element),它内部提供一组静态函数,每个静态函数负责完成一种特定类型的几何对象转成Element对象,该方法优点在于简单、快捷、易用。

以下类型可以将几何对象转成非扩展元素(Non-extended Element)对象:

  1. - CurveVector
  2. - ISolidPrimitive
  3. - ICurvePrimitive
  4. - MSBsplineSurface
  5. - PolyfaceQuery
  6. - ISolidKernelEntity

例子:
CurveVector cv = Bentley.DgnPlatformNET.Elements.CurvePathQuery.ElementToCurveVector(fenceElement);
if (cv != null)
{
Element element = DraftingElementSchema.ToElement(this.ActiveDgnModel, cv, null);
}

  • SolidUtil

该类主要是针对Solid的应用类,包含创建、查询和修改智能实体的功能。在使用前需要在C#项目中引用Bentley.DgnDisplayNet.dll库后就有SolidUtil类了,并且在Microstation SDK Update 10以后的版本才有某些方法(例如BodyFromLoft)的.Net封装。

该类包含下面若干个方法:

  1. - Body Create: SolidUtil::Create::BodyFromXXX
  2. - Body Convert: SolidUtil::Convert::ElementToBody/BodyToElement
  3. - GetBodyFaces / GetBodyEdges / GetBodyVertices
  4. - GetFaceEdges / GetFaceVertices
  5. - GetEdgeFaces / GetEdgeVertices
  6. - GetVertexFaces / GetVertexEdges
  7. - EvaluateFace / EvaluateEdge / EvaluateVertex
  8. - GetEntityRange / GetSubEntityRange / GetFaceParameterRange / GetEdgeParameterRange
  9. - ClosePoint / ClosePointToFace / ClosePointToEdge
  10. - IsPointInsideBody
  11. - BooleanIntersect / BooleanSubtract / BooleanUnion / BooleanCut
  12. - Emboss (Protrusion) / SweepBody / SpinBody / SewBodies / TransformBody
  13. - ThickenSheet
  14. - BlendEdges / ChamferEdges
  15. - HollowFaces / OffsetFaces / TransformFaces / SweepFaces / SpinFaces / DeleteFaces
  16. - ImprintCurveVectorOnBody / ImprintWiresOnFace
  17. - DeleteRedundantTopology

重要的几何类

1.CurveVector

CurveVector是一个多功能类,它包含了CurvePrimitive的向量容器;它既能包含单条曲线,又能包含曲线集合。集合里面的曲线能以层次状或者树状的形式分布,共同组合来表达开放式曲线、闭合式曲线、单区域及组合区域等。
CurveVector的表达方式分为:开放式曲线(Open curves), 闭合式曲线(closed curves),区域(regions ) 三种。

  1. - 开放式曲线(Open curves

首先创建一个CurveVector,类型是BOUNDARY_TYPE_Open,然后存放若干个CurvePrimitive,这些CurvePrimitive可以是一些线段;
CurveVector::BOUNDARY_TYPE_Open prim1 prim2 … primN

  1. - 单个闭合曲线(Single closed curve

首先创建一个CurveVector,类型是BOUNDARYTYPE Outer,然后存放若干个CurvePrimitive,这些CurvePrimitive可以是一些线段;
CurveVector::BOUNDARY_TYPE_Outer prim1 prim2 … primN

  1. - 多个独立的闭合曲线(Multiple standalone closed curves

首先创建一个CurveVector,类型是BOUNDARYTYPE UnionRegion,然后再创建若干个CurveVector,类型为CurveVector::BOUNDARY_TYPE_Outer,将这些CurveVector添加到第一级的 CurveVector里面去,次级的CurveVector添加若干个曲线构成一个环;
CurveVector::BOUNDARY_TYPE_UnionRegion
CurveVector::BOUNDARY_TYPE_Outer prim1 prim2 … primN
CurveVector::BOUNDARY_TYPE_Outer prim1 prim2 … primN
CurveVector::BOUNDARY_TYPE_Outer prim1 prim2 … primN

  1. - 区域联合(Union of regions

首先创建一个CurveVector,类型是BOUNDARYTYPE ParityRegion(独立区域),然后再创建一个CurveVector,类型为CurveVector::BOUNDARY_TYPE_Outer,将这个CurveVector添加到第一级的 CurveVector里面去,次级的CurveVector添加若干个曲线构成一个环,然后添加若干个类型为BOUNDARY_TYPE_Inner(内边界)的CurveVector,同样将这些CurveVector添加到第一级的CurveVector里面去;
最终运算的时候,所有的内边界都会作为空洞从外边界扣除掉。
CurveVector::BOUNDARY_TYPE_ParityRegion
CurveVector::BOUNDARY_TYPE_Outer prim1 prim2 … primN
CurveVector::BOUNDARY_TYPE_Inner prim1 prim2 … primN
CurveVector::BOUNDARY_TYPE_Inner prim1 prim2 … primN

  1. - 判断CurveVector类型:

var curveVector = Bentley.DgnPlatformNET.Elements.CurvePathQuery.ElementToCurveVector(element);
switch (curveVector.GetBoundaryType())
{
case CurveVector.BoundaryType.Open:
break;
case CurveVector.BoundaryType.Inner:
break;
case CurveVector.BoundaryType.None:
break;
case CurveVector.BoundaryType.ParityRegion:
break;
case CurveVector.BoundaryType.UnionRegion:
break;
}

2.PolyfaceHeader

该类主要用于表达三维的离散网格(mesh),它由一个主类和一堆辅助类构成。它跟地形的网格区别在于,它本身是三维的,而地形的网格是二维的,地形网格是基于平面构建网格,Z轴只是地形网格的一个属性。另外,PolyfaceHeader既能表达闭合的网格,也能表达非闭合的网格。

PolyfaceHeader特性:

  1. - PolyfaceHeader并不是普通的三角网(triangle-mesh), 它在实际构造的时候可以是每一个面都拥有不同的顶点数,并且PolyfaceHeader不光能表达空间形状,还能表达渲染用的材质及光照用的法向。
  2. - PolyfaceHeader能被IDrawGeomViewContext)支持,直接通过IDrawGeom画出来,IDrawGeom类中对应PolyfaceHeader的方法如下:

void DrawPolyface (BGEO.PolyfaceHeader meshData, bool filled);

  1. - PolyfaceHeader还支持工程上运用的额外计算,比如土方运算、地形布尔运算等。

构造PolyfaceHeader:
通过Bentley.GeometryNET.PolyfaceConstruction构造PolyfaceHeader,参考如下:
GeometryNET.FacetOptions options = new FacetOptions();
options.SetCurveDefaultsDefaults();
GeometryNET.PolyfaceConstruction construction = new PolyfaceConstruction(options);
construction.AddSolidPrimitive(primitive);
PolyfaceHeader polyface = construction.GetClientMesh();

3.Transform

变换矩阵分为:标准变换矩阵(Standard transform matrix)、刚体变换矩阵(Rigidbody transform)和非刚体变换矩阵(Non-rigidbody transform);

  1. - 标准变换矩阵

Bentley的标准变换矩阵是以列为主要的存储顺序(column-order),它通常是4X4矩阵,左上角部分的矩阵(3X3矩阵)支持:缩放(scale)、旋转(rotate)、镜像(mirror)和剪切(shear)四种变换,最后一列是一个平移量(tranalstion),最后一行是[0 0 0 1],起到对齐的作用。

  1. - 刚体变换矩阵

刚体变换就是指不影响物体形状的,只影响物体位置及空间姿态的变换。刚体变换矩阵只包含平移(translate)和旋转(rotate)部分,并且刚体变换等价于局部坐标系CS(Coordinate System)。

  1. - 非刚体变换矩阵

非刚体变换就是指影响物体形状及位置的变换。非刚体变换不等价于局部坐标系CS(Coordinate System)。

4.CurvePrimitive

创建直线:
GeometryNET.CurvePrimitive primitive = GeometryNET.CurvePrimitive.CreateLine(new DSegment3d(new DPoint3d(0, 0, 0), new DPoint3d(1000 * uorPerM, 0, 0)));

创建线串:
DPoint3d[] points = { new DPoint3d(100, 100), new DPoint3d(600, 110), new DPoint3d(1000, 105) };
CurvePrimitive cp = CurvePrimitive.CreateLineString(points);

创建点串:
DPoint3d[] points = { new DPoint3d(100, 100), new DPoint3d(600, 110), new DPoint3d(1000, 105) };
CurvePrimitive cp = CurvePrimitive.CreatePointString (points);

获取:
List loop = new List();
DSegment3d segment;
DEllipse3d ellipse;
foreach (CurvePrimitive primitive in cv)
{
IList pts = new List();
if (primitive.TryGetLineString(pts))
{
}
else if (primitive.TryGetLine(out segment))
{
}
else if (primitive.TryGetArc (out ellipse))
{
}
}

判断CurvePrimitive类型:
var curveVector = Bentley.DgnPlatformNET.Elements.CurvePathQuery.ElementToCurveVector(element);
foreach (CurvePrimitive primitive in curveVector)
{
CurvePrimitive.CurvePrimitiveType type = primitive.GetCurvePrimitiveType();
switch (type)
{
case CurvePrimitive.CurvePrimitiveType.PointString:
break;
case CurvePrimitive.CurvePrimitiveType.Line:
break;
case CurvePrimitive.CurvePrimitiveType.LineString:
break;
case CurvePrimitive.CurvePrimitiveType.Arc:
break;
case CurvePrimitive.CurvePrimitiveType.Spiral:
break;
case CurvePrimitive.CurvePrimitiveType.BsplineCurve:
break;
}
}

5.SolidPrimitive

SolidPrimitive包括:DgnBox、DgnCone、DgnExtrusion、DgnRotationalSweep、DgnRuledSweep、DgnSphere、DgnTorusPipe几大类,每一种类都对应了一种detail。
构造这些种类的几何需要配合各自的detail进行创建。

创建及获取:
SolidPrimitive clonedSolid = null;

switch (solid.PrimitiveType)
{
case SolidPrimitiveType.DgnBox:
clonedSolid = SolidPrimitive.CreateDgnBox (solid.TryGetDgnBoxDetail());
break;
case SolidPrimitiveType.DgnCone:
clonedSolid = SolidPrimitive.CreateDgnCone (solid.TryGetDgnConeDetail());
break;
case SolidPrimitiveType.DgnExtrusion:
clonedSolid =
SolidPrimitive.CreateDgnExtrusion (solid.TryGetDgnExtrusionDetail());
break;
case SolidPrimitiveType.DgnRotationalSweep:
clonedSolid = SolidPrimitive.CreateDgnRotationalSweep(solid.TryGetDgnRotationalSweepDetail());
break;
case SolidPrimitiveType.DgnRuledSweep:
clonedSolid =
SolidPrimitive.CreateDgnRuledSweep (solid.TryGetDgnRuledSweepDetail());
break;
case SolidPrimitiveType.DgnSphere:
clonedSolid =
SolidPrimitive.CreateDgnSphere (solid.TryGetDgnSphereDetail());
break;
case SolidPrimitiveType.DgnTorusPipe:
clonedSolid =
SolidPrimitive.CreateDgnTorusPipe (solid.TryGetDgnTorusPipeDetail());
break;
}

6.FacetOptions

函数:
FacetOptions.BsplineCurveStrokeCount(Bentley.GeometryNET.MSBsplineCurve)
该函数主要是计算bspline曲线打散后的点数。
FacetOptions.EllipseStrokeCount(Bentley.GeometryNET.DEllipse3d)
该函数主要计算半个椭圆打散后的点数。
FacetOptions.FullEllipseStrokeCount(Bentley.GeometryNET.DEllipse3d)
该函数主要计算一个完整椭圆打散后的点数。
FacetOptions.SegmentStrokeCount(Bentley.GeometryNET.DSegment3d)
该函数主要计算一个线段打散后的点数。
FacetOptions.SetCurveDefaultsDefaults()
该函数将所有参数设置为曲线的默认值。
FacetOptions.SetDefaults()
将所有参数设置为默认值

变量:
FacetOptions.AngleTolerance: 角度容差值;
FacetOptions.ChordTolerance:弦长容差值;
FacetOptions.CombineFacets 设置组合面;
FacetOptions.ConvexFacetsRequired: 设置凸面;
FacetOptions.CurvedSurfaceMaxPerFace:最大面数;
FacetOptions.EdgeHiding:是否隐藏边;
FacetOptions.MaxEdgeLength:最大边长;
FacetOptions.MaxPerBezier:贝塞尔曲线最大值;
FacetOptions.MaxPerFace: 最大面;
FacetOptions.NormalsRequired:法向量要求;

7.PolyfaceVisitor

GeometryNET.FacetOptions options = new FacetOptions();
options.SetCurveDefaultsDefaults();
GeometryNET.PolyfaceConstruction construction = new PolyfaceConstruction(options);
construction.AddSolidPrimitive(primitive);
PolyfaceHeader polyface = construction.GetClientMesh();

PolyfaceVisitor visitor = PolyfaceVisitor.Attach(polyface, true);
visitor.NumberWrap = 1;
// 重复每个循环末尾的第一个索引和坐标,以简化提取。
for (visitor.Reset (); visitor.AdvanceToNextFace (); )
{
int numEdgesThisFace = (int)visitor.NumberEdgesThisFace ();
System.Collections.Generic.List points = new System.Collections.Generic.List (visitor.Point);
for (int iA = 0, iB; iA < numEdgesThisFace; iA = iB)
{
for (int iA = 0, iB; iA < numEdgesThisFace; iA = iB)
{
int tmp;
bool visible;
visitor.TryGetClientZeroBasedPointIndex (iA, out tmp, out visible);
}
}
}

元素API

MicroStation有很多种类型的元素,我们可以将其分成图形元素和非图形元素(控制元素)。

命名空间:Bentley.DgnPlatformNET.Elements
下表列出了MicroStation中支持的大多数图形元素,同时也列出了创建元素的方法:

元素类型 图形表达 创建函数 复杂元素 备注
Line(线) 基础平台API介绍 - 图3 LineElement CreateLineElement2(Element Template, ref Point3d StartPoint, ref Point3d EndPoint); 由两个点组成的一段直线。
PointString(点串) 基础平台API介绍 - 图4 PointStringElement CreatePointStringElement1(Element Template, ref Point3d[] Vertices, bool Disjoint); 最多由2000多个点组成的离散点。
LineString(线串) 基础平台API介绍 - 图5 LineStringElement(DgnModel dgnModel, Element templateElement, DPoint3d[] points); 最多由5000个点组成的多段直线。
Shape(形) 基础平台API介绍 - 图6 ShapeElement(DgnModel dgnModel, Element templateElement, DPoint3d[] points); 最多由5000个点组成的封闭直线段 。
Arc(弧) 基础平台API介绍 - 图7 ArcElement.ArcElement(Bentley.DgnPlatformNET.DgnModel, Bentley.DgnPlatformNET.Elements.Element, Bentley.GeometryNET.DEllipse3d)
Ellipse(椭圆) 基础平台API介绍 - 图8 EllipseElement.EllipseElement(Bentley.DgnPlatformNET.DgnModel, Bentley.DgnPlatformNET.Elements.Element,Bentley.GeometryNET.DEllipse3d) 圆和椭圆是同一种元素类型。
ComplexString(复杂链)\ ComplexShape(复杂型) 基础平台API介绍 - 图9 ComplexStringElement.ComplexStringElement(Bentley.DgnPlatformNET.DgnModel,Bentley.DgnPlatformNET.Elements.Element)

ComplexShapeElement.ComplexShapeElement(Bentley.DgnPlatformNET.DgnModel,Bentley.DgnPlatformNET.Elements.Element)
该函数建立复杂元素,包含弧、直线等元素,最终构成复杂链或者复杂形
Curve(曲线) 基础平台API介绍 - 图10 CurveElement.CurveElement(Bentley.DgnPlatformNET.DgnModel,Bentley.DgnPlatformNET.Elements.Element,Bentley.GeometryNET.DPoint3d[]) 这时一类简单的曲线,曲线本身会经过指定点。
BsplineCurve(B样条曲线) 基础平台API介绍 - 图11 BSplineCurveElement.BSplineCurveElement(Bentley.DgnPlatformNET.DgnModel,Bentley.DgnPlatformNET.Elements.Element,Bentley.GeometryNET.MSBsplineCurve)
MultLine(多线) 基础平台API介绍 - 图12 MultilineElement.CreateMultilineElement(Bentley.DgnPlatformNET.DgnModel,Bentley.DgnPlatformNET.Elements.Element,Bentley.DgnPlatformNET.MultilineStyle, double, Bentley.GeometryNET.DVector3d, Bentley.GeometryNET.DPoint3d[]) 最多可由16条平行线组成的多段直线
Text(文本) 基础平台API介绍 - 图13 TextHandlerBase ::TextHandlerBase CreateElement(Element templateElement, TextBlock value1); 文字元素
Tag(标签) 基础平台API介绍 - 图14 TagElement.TagElement(Bentley.DgnPlatformNET.DgnModel,Bentley.DgnPlatformNET.Elements.Element,string,string,object,Bentley.DgnPlatformNET.DgnTextStyle,bool,Bentley.GeometryNET.DPoint3d,Bentley.GeometryNET.DMatrix3d,Bentley.DgnPlatformNET.Elements.Element) 与图形元素关联的一种文字
Dimension(标注) 基础平台API介绍 - 图15 DimensionElement.DimensionElement(Bentley.DgnPlatformNET.DgnModel,Bentley.DgnPlatformNET.Elements.DimensionCreateData,Bentley.DgnPlatformNET.DimensionType) 标注元素看起来很复杂,其实在MicroStation中却是一种简单元素
Cell(单元) 基础平台API介绍 - 图16 CellHeaderElement.CellHeaderElement(Bentley.DgnPlatformNET.DgnModel,string,Bentley.GeometryNET.DPoint3d,Bentley.GeometryNET.DMatrix3d,System.Collections.Generic.IList)

CellHeaderElement.CreateOrphanCellElement(Bentley.DgnPlatformNET.DgnModel,string,System.Collections.Generic.IList)
ShareCell(共享单元) 基础平台API介绍 - 图17 SharedCellElement.SharedCellElement(Bentley.DgnPlatformNET.DgnModel,Bentley.DgnPlatformNET.Elements.Element,string,Bentley.GeometryNET.DPoint3d,Bentley.GeometryNET.DMatrix3d,Bentley.GeometryNET.DPoint3d) 多个共享单元实例共用一个共享单元定义,因而对于多个相同复杂单元的情况,使用共享单元大大节省模型容量
Cone(圆锥体) 基础平台API介绍 - 图18 ConeElement.ConeElement(Bentley.DgnPlatformNET.DgnModel,Bentley.DgnPlatformNET.Elements.Element,double,double,Bentley.GeometryNET.DPoint3d,Bentley.GeometryNET.DPoint3d,Bentley.GeometryNET.DMatrix3d, bool) 该函数可创建圆柱体和圆锥体
Surface或Solid(拉伸
和旋转面或体)
基础平台API介绍 - 图19 SurfaceOrSolidElement.CreateProjectionElement(Bentley.DgnPlatformNET.DgnModel,Bentley.DgnPlatformNET.Elements.Element,Bentley.DgnPlatformNET.Elements.Element,Bentley.GeometryNET.DPoint3d,Bentley.GeometryNET.DVector3d, Bentley.GeometryNET.DTransform3d, bool)
SurfaceOrSolidElement.CreateRevolutionElement(Bentley.DgnPlatformNET.DgnModel,Bentley.DgnPlatformNET.Elements.Element,Bentley.DgnPlatformNET.Elements.Element,Bentley.GeometryNET.DPoint3d,Bentley.GeometryNET.DVector3d, double, bool)
SurfaceOrSolidElement.CreateRevolutionElement(Bentley.DgnPlatformNET.DgnModel,Bentley.DgnPlatformNET.Elements.Element,Bentley.DgnPlatformNET.Elements.Element,Bentley.GeometryNET.DPoint3d,Bentley.GeometryNET.DVector3d, double, bool, int)
SmartSolid(智能实体) 基础平台API介绍 - 图20 SolidPrimitive.CreateDgnBox;
SolidPrimitive.CreateDgnCone;
SolidPrimitive.CreateDgnExtrusion;
SolidPrimitive.CreateDgnRotationalSweep;
SolidPrimitive.CreateDgnRuledSweep;
SolidPrimitive.CreateDgnSphere;
SolidPrimitive.CreateDgnTorusPipe;
智能实体借助ParaSolid内核来处理几何图形,而普通实体则不借助。因此,对于一些基本的三维体,既可以用普通实体来创建也可以用智能实体来创建。前者执行效率比后者要高,但不能表达复杂的实体。
BsplineSurface(B样条曲面) 基础平台API介绍 - 图21 BSplineSurfaceElement.BSplineSurfaceElement(Bentley.DgnPlatformNET.DgnModel,Bentley.DgnPlatformNET.Elements.Element,Bentley.GeometryNET.MSBsplineSurface)


精确的曲面表达方式
Mesh(网格曲面) 基础平台API介绍 - 图22 MeshHeaderElement.MeshHeaderElement(Bentley.DgnPlatformNET.DgnModel,Bentley.DgnPlatformNET.Elements.Element,Bentley.GeometryNET.PolyfaceHeader)

网格曲面最适合用来表达大型地模数据,精度会比B样条曲面差

一般通用创建元素的方法:DraftingElementSchema::ToElement;
一般将元素添加到模型中 需要调用:Element.AddToModel;
一般将元素从模型中删除,需要调用:Element.DeleteFromModel;

下面介绍几种常见元素的创建:

1.LineElement

(1)创建:
DSegment3d seg = new DSegment3d (…);
LineElement lineElem = new LineElement(dgnModel, null, seg);
lineElem.AddToModel();

(2)获取GetCurveVector()方法:
CurveVector curveVector = null;
curveVector = (element as LineElement).GetCurveVector();

(3)设置SetCurveVector(Bentley.GeometryNET.CurveVector)方法:
DgnPlatformNET.Elements.LineElement lineElement = element as DgnPlatformNET.Elements.LineElement;
double uorPerM = element.DgnModel.GetModelInfo().UorPerMeter;
CurveVector lineCurveVector = CurveVector.Create(CurveVector.BoundaryType.Open);
GeometryNET.CurvePrimitive primitive = GeometryNET.CurvePrimitive.CreateLine(new DSegment3d(new DPoint3d(0, 0, 0), new DPoint3d(1000 * uorPerM, 0, 0)));
lineCurveVector.Add(primitive);
lineElement.SetCurveVector(lineCurveVector);
lineElement.ReplaceInModel(lineElement);

2. LineStringElement

(1)创建:
DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
ModelInfo modelInfo = dgnModel.GetModelInfo();
DPoint3d[] ptArr = new DPoint3d[5];
ptArr[0] = new DPoint3d(15 UorPerMas, 10 UorPerMas, 0 UorPerMas);
ptArr[1] = new DPoint3d(16
UorPerMas, 12 UorPerMas, 0 UorPerMas);
ptArr[2] = new DPoint3d(18 UorPerMas, 8 UorPerMas, 0 UorPerMas);
ptArr[3] = new DPoint3d(20
UorPerMas, 12 UorPerMas, 0 UorPerMas);
ptArr[4] = new DPoint3d(21 UorPerMas, 10 UorPerMas, 0 * UorPerMas);
LineStringElement lineStrEle = new LineStringElement(dgnModel, null, ptArr);
lineStrEle.AddToModel();

(2)获取GetCurveVector()方法:
CurveVector curveVector = null;
curveVector = (element as LineStringElement).GetCurveVector();

3.ComplexStringElement和ComplexShapeElement

(1)创建:
ComplexStringElement cStrElem = new ComplexStringElement(dgnModel, null);
cStrElem.AddComponentElement (compElem); //多次调用该函数
cStrElem.AddComponentComplete();
cStrElem.AddToModel();

(2)获取GetCurveVector()方法:
CurveVector curveVector = null;
curveVector = (element as ComplexStringElement).GetCurveVector();

3. Text

(1)创建:
DgnFile dgnFile = Session.Instance.GetActiveDgnFile();
DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
TextBlockProperties txtBlockProp = new TextBlockProperties(dgnModel);
txtBlockProp.IsViewIndependent = true;
ParagraphProperties paraProp = new ParagraphProperties(dgnModel);
paraProp.Justification = TextElementJustification.CenterMiddle;
DgnTextStyle txtStyle = DgnTextStyle.GetSettings(dgnFile);
RunProperties runProp = new RunProperties(txtStyle, dgnModel);
TextBlock txtBlock = new TextBlock(txtBlockProp, paraProp, runProp, dgnModel);
txtBlock.AppendText(“This is a textBlock Element”);
TextHandlerBase txtHandlerBase = TextHandlerBase.CreateElement(null, txtBlock);
DTransform3d trans = DTransform3d.Identity;
trans.Translation = new DVector3d(6 UorPerMas, 2 UorPerMas, 3 * UorPerMas); //UOR unit
TransformInfo transInfo = new TransformInfo(trans);
txtHandlerBase.ApplyTransform(transInfo);
txtHandlerBase.AddToModel();

(2)GetTextPart(Bentley.DgnPlatformNET.TextPartId) 和GetTextPartIds(Bentley.DgnPlatformNET.TextQueryOptions)方法:
DGN.Elements.TextElement textElmt = elmt as DGN.Elements.TextElement;
DGN.TextPartId part = textElmt.GetTextPartIds (new DGN.TextQueryOptions ())[0];
string text = textElmt.GetTextPart (part).ToString ();

4. cell

(1)创建
DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
DPoint3d[] ptArr = new DPoint3d[5];
ptArr[0] = new DPoint3d(-15 UorPerMas, -5 UorPerMas, 0 UorPerMas);
ptArr[1] = new DPoint3d(-15
UorPerMas, 5 UorPerMas, 0 UorPerMas);
ptArr[2] = new DPoint3d(-5 UorPerMas, 5 UorPerMas, 0 UorPerMas);
ptArr[3] = new DPoint3d(-5
UorPerMas, -5 UorPerMas, 0 UorPerMas);
ptArr[4] = new DPoint3d(-15 UorPerMas, -5 UorPerMas, 0 UorPerMas);
ShapeElement shapeEle = new ShapeElement(dgnModel, null, ptArr);
DPlacementZX dPlaceZX = DPlacementZX.Identity;
dPlaceZX.Origin = new DPoint3d(-10
UorPerMas, 0, 0);
DEllipse3d ellipse = new DEllipse3d(dPlaceZX, 5 UorPerMas, 5 UorPerMas, Angle.Zero, Angle.TWOPI);
EllipseElement elliEle = new EllipseElement(dgnModel, null, ellipse);
List listEle = new List();
listEle.Add(shapeEle);
listEle.Add(elliEle);
DPoint3d ptOri = new DPoint3d();
DMatrix3d rMatrix = DMatrix3d.Identity;
DPoint3d ptScale = new DPoint3d(1, 1, 1);
CellHeaderElement cellHeaderEle = new CellHeaderElement(dgnModel, “CellElementSample”, ptOri, rMatrix, listEle);
cellHeaderEle.AddToModel();

(2)CellQuery:
CellHeaderElement cellElement = element as CellHeaderElement;
CellQuery cellQuery = CellQuery.GetAsCellQuery(cellElement);
cellQuery.ApplyTransform(transform);
cellQuery.ReplaceInModel(cellElement);

5. Dimension

(1)创建
DgnFile dgnFile = Session.Instance.GetActiveDgnFile();
DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
double uorPerMast = dgnModel.GetModelInfo().UorPerMaster;
DimensionStyle dimStyle = new DimensionStyle(“DimStyle”, dgnFile);
dimStyle.SetBooleanProp(true, DimStyleProp.Placement_UseStyleAnnotationScale_BOOLINT);
dimStyle.SetDoubleProp(1, DimStyleProp.Placement_AnnotationScale_DOUBLE);
dimStyle.SetBooleanProp(true, DimStyleProp.Text_OverrideHeight_BOOLINT);
dimStyle.SetDistanceProp(0.5 uorPerMast, DimStyleProp.Text_Height_DISTANCE, dgnModel);
dimStyle.SetBooleanProp(true, DimStyleProp.Text_OverrideWidth_BOOLINT);
dimStyle.SetDistanceProp(0.4
uorPerMast, DimStyleProp.Text_Width_DISTANCE, dgnModel);
dimStyle.SetBooleanProp(true, DimStyleProp.General_UseMinLeader_BOOLINT);
dimStyle.SetDoubleProp(0.01, DimStyleProp.Terminator_MinLeader_DOUBLE);
dimStyle.SetBooleanProp(true, DimStyleProp.Value_AngleMeasure_BOOLINT);
dimStyle.SetAccuracyProp((byte)AnglePrecision.Use1Place, DimStyleProp.Value_AnglePrecision_INTEGER);
int alignInt = (int)DimStyleProp_General_Alignment.True;
StatusInt status = dimStyle.SetIntegerProp(alignInt, DimStyleProp.General_Alignment_INTEGER);
int valueOut;
dimStyle.GetIntegerProp(out valueOut, DimStyleProp.General_Alignment_INTEGER);
DgnTextStyle textStyle = new DgnTextStyle(“TestStyle”, dgnFile);
LevelId lvlId = Settings.GetLevelIdFromName(“Default”);
CreateDimensionCallbacks callbacks = new CreateDimensionCallbacks(dimStyle, textStyle, new Symbology(), lvlId, null);
DimensionElement dimEle = new DimensionElement(dgnModel, callbacks, DimensionType.SizeArrow);
if (dimEle.IsValid)
{
DPoint3d pt1 = DPoint3d.Zero, pt2 = DPoint3d.FromXY(uorPerMast 10, uorPerMast 0);
dimEle.InsertPoint(pt1, null, dimStyle, -1);
dimEle.InsertPoint(pt2, null, dimStyle, -1);
dimEle.SetHeight(uorPerMast);
DMatrix3d rMatrix = DMatrix3d.Identity;
dimEle.SetRotationMatrix(rMatrix);
dimEle.AddToModel();
}

6. BsplineCurve)

(1)创建
DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
DPoint3d[] ptArr = new DPoint3d[5];
ptArr[0] = new DPoint3d(0 UorPerMas, 15 UorPerMas, 0 UorPerMas);
ptArr[1] = new DPoint3d(5
UorPerMas, 25 UorPerMas, 0 UorPerMas);
ptArr[2] = new DPoint3d(10 UorPerMas, 15 UorPerMas, 0 UorPerMas);
ptArr[3] = new DPoint3d(15
UorPerMas, 25 UorPerMas, 0 UorPerMas);
ptArr[4] = new DPoint3d(20 UorPerMas, 15 UorPerMas, 0 * UorPerMas);
MSBsplineCurve msBsplineCurve = MSBsplineCurve.CreateFromPoles(ptArr, null, null, 3, false, true);
CurvePrimitive curvePri = CurvePrimitive.CreateBsplineCurve(msBsplineCurve);
Element ele = DraftingElementSchema.ToElement(dgnModel, curvePri, null);
ele.AddToModel();

(2)获取GetCurveVector()方法:
CurveVector curveVector = null;
curveVector = (element as BsplineCurve).GetCurveVector();

(3)获取GetCurveVector()方法:
CurveVector curveVector = null;
curveVector = (element as BsplineCurve).GetCurveVector();

7.Cone

(1)创建
DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
DPoint3d ptTop = new DPoint3d(2 UorPerMas, -15 UorPerMas, 0 UorPerMas);
DPoint3d ptBottom = new DPoint3d(2
UorPerMas, -15 UorPerMas, 3 UorPerMas);
DMatrix3d rMatrix = DMatrix3d.Identity;
ConeElement coneEle = new ConeElement(dgnModel, null, 2 UorPerMas, 1 UorPerMas, ptTop, ptBottom, rMatrix, true);
coneEle.AddToModel();

8. TagElement

创建:
DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
string CellIndexTagName = “CellIndex”;
DGN.Elements.TagElement tagElement = new DGN.Elements.TagElement (dgnModel, null, CellIndexTagName, “test”, (Int16)0, textStyle, true, Bentley.GeometryNET.DPoint3d.Zero, Bentley.GeometryNET.DMatrix3d.Identity, element);
tagElement.AddToModel ();

获取:
DGN.Elements.TagElement tagElem = dependentEl as DGN.Elements.TagElement;
if (null != tagElem)
{
if (tagElem.TagName == “test”)
object tagValue = tagElem.GetTagValue ();
}

9. Mesh

(1)创建
PolyfaceConstruction polyConstruct = new PolyfaceConstruction();
DPoint3d xx = new DPoint3d(0, 0, 0); //增加4个点
polyConstruct.FindOrAddPoint(ref xx);
DPoint3d xx1 = new DPoint3d(100000, 0, 0);
polyConstruct.FindOrAddPoint(ref xx1);
DPoint3d xx2 = new DPoint3d(100000, 100000, 0);
polyConstruct.FindOrAddPoint(ref xx2);
DPoint3d xx3 = new DPoint3d(0, 100000, 0);
polyConstruct.FindOrAddPoint(ref xx3);

polyConstruct.AddPointIndex(0, true);
polyConstruct.AddPointIndex(1, true);
polyConstruct.AddPointIndex(2, true);
polyConstruct.AddPointIndex(3, true);
polyConstruct.AddPointIndexTerminator();
PolyfaceHeader polyHeader = polyConstruct.GetClientMesh();
MeshHeaderElement meshElem = new MeshHeaderElement(dgnModel, null, polyHeader);
meshElem.AddToModel();

(2)GetMeshData()方法:
PolyfaceHeader mesh = meshElem.GetMeshData();
if (null != mesh && mesh.FacetCount > 0){
}

10. ParametricCellElement

DgnFile dgnFile = Session.Instance.GetActiveDgnFile();
DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
var pcDef = ParametricCellDefinitionElement.FindByName(cellName, dgnFile);
var pc = ParametricCellElement.Create(pcDef, setName, dgnModel);

11.TextTableElement

参见examples\Elements\ManagedTextTableExample

12. SurfaceOrSolidElement

DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
ComplexShapeElement profile = new ComplexShapeElement(dgnModel, null);
List outPts = new List();
outPts.Add(new DPoint3d(0, 0, 100000));
outPts.Add(new DPoint3d(0, 0, 180000));
LineStringElement le = new LineStringElement(dgnModel, null, outPts.ToArray());
profile.AddComponentElement(le);

DEllipse3d de = new DEllipse3d(new DPoint3d(0, 0, 100000), new DVector3d(50000, 0, 0), new DVector3d(0, 0, 80000), Angle.Zero, Angle.FromRadians(Math.PI 90 / 180));
ArcElement arcElem = new ArcElement(dgnModel, null, de);
profile.AddComponentElement(arcElem);
outPts = new List();
outPts.Add(new DPoint3d(50000, 0, 100000));
outPts.Add(new DPoint3d(0, 0, 100000));
le = new LineStringElement(dgnModel, null, outPts.ToArray());
profile.AddComponentElement(le);
profile.AddToModel();
DPoint3d ptCenter = new DPoint3d(0, 0, 100000);
DVector3d dVec = new DVector3d(0, 0, 10000);
profile.AddSolidFill(3, true);
Element ele = SurfaceOrSolidElement.CreateRevolutionElement(dgnModel, null, profile, ptCenter, dVec, Math.PI
2, true);
ele.AddToModel();

13. AnnotationHandler

添加注释:
AnnotationHandler ah = AnnotationHandler.GetAsAnnotationHandler(el);
ah.AddAnnotationScale(Session.Instance.GetActiveDgnModelRef);
ah.AddToModel()

删除注释:
long id = 787;
ElementId elId = new ElementId(ref id);
Bentley.DgnPlatformNET.Elements.Element el = Session.Instance.GetActiveDgnModel().FindElementById(elId);

DgnModel model = Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnModel();
AnnotationHandler anno = AnnotationHandler.GetAsAnnotationHandler(el);
anno.RemoveAnnotationScale();
anno.AddToModel();

14.AreaFillPropertiesEdit

GroupedHoleElement groupedHoleElement = element as GroupedHoleElement;
AreaFillPropertiesEdit areaEdit = AreaFillPropertiesEdit.GetAsAreaFillPropertiesEdit(groupedHoleElement);
areaEdit.ApplyTransform(transform);
areaEdit.ReplaceInModel(groupedHoleElement);

15. AreaFillPropertiesQuery

AreaFillPropertiesQuery filled = (Element != null) ? AreaFillPropertiesQuery.GetAsAreaFillPropertiesQuery(Element) : null;
if (filled != null)
{
bool isHole;
if (filled.GetAreaType(out isHole))
{
uint fillColor;
bool alwaysFilled;
if (filled.GetSolidFill(out fillColor, out alwaysFilled))
{
}
}
}

16. CellQuery

Transform3d trans3d = DTransform3d.FromTranslation(0.0, -100, 0.0);
TransformInfo transform = new TransformInfo(trans3d);
CellHeaderElement cellElement = element as CellHeaderElement;
CellQuery cellQuery = CellQuery.GetAsCellQuery(cellElement);
cellQuery.ApplyTransform(transform);
cellQuery.ReplaceInModel(cellElement);

17.ChildElementCollection

Bentley.DgnPlatformNET.Elements.ChildElementCollection elmts = cellElement.GetChildren ();
foreach (Bentley.DgnPlatformNET.Elements.Element elmt in elmts)
{
}

18.CurvePathEdit

DSegment3d segment2 = new DSegment3d(100, 100, 100, 1100, 1100, 1100);
Bentley.DgnPlatformNET.Elements.LineElement lineEeh2 = new Bentley.DgnPlatformNET.Elements.LineElement(GetDgnModel(GetGeometricModel().ThreeDSpace), null, segment2);
Bentley.DgnPlatformNET.Elements.CurvePathEdit cpEdit2 = lineEeh2.AsCurvePathEdit();
CurveVector cVector2 = cpEdit2.GetCurveVector();
pe.SetCurveVector(cVector2);
pe.ReplaceInModel(GetElement(ent));

19.CurvePathQuery

long id = 787;
ElementId elId = new ElementId(ref id);
Bentley.DgnPlatformNET.Elements.Element el = Session.Instance.GetActiveDgnModel().FindElementById(elId);
var curveVector = Bentley.DgnPlatformNET.Elements.CurvePathQuery.ElementToCurveVector(el);

20.DisplayableElement

Bentley.DgnPlatformNET.Elements.DisplayableElement dElem = msElmt as Bentley.DgnPlatformNET.Elements.DisplayableElement;
Bentley.GeometryNET.DRange3d range;
dElem.CalcElementRange (out range);

21.DraftingElementSchema

CurveVector curveVector = null;
switch (element.ElementType)
{
case MSElementType.ComplexString:
curveVector = (element as ComplexStringElement).GetCurveVector();
break;
case MSElementType.LineString:
curveVector = (element as LineStringElement).GetCurveVector();
break;
case MSElementType.Line:
curveVector = (element as LineElement).GetCurveVector();
break;
}
if (null != curveVector)
{
foreach (CurvePrimitive cPrim in curveVector)
{
Element cElem = DraftingElementSchema.ToElement(element.DgnModel, cPrim, null);
}
}

22.MeshQuery

MeshQuery meshQuery = MeshQuery.GetAsMeshQuery(mesh);
if ( meshQuery == null )
return null;
Bentley.GeometryNET.PolyfaceHeader meshData = meshQuery.GetMeshData();
Bentley.GeometryNET.DPoint3d[][] geometry = new bgeo.DPoint3d[meshData.FacetCount][];
for ( int i = 0; i < geometry.Length; i++ )
{
}

23.ParametricCellDefinitionElement

查询cell definition是否存在:
string cellname =“test”;
if (string.IsNullOrEmpty (cellname))
{
return;
}
var dgnfile = Session.Instance.GetActiveDgnFile();
CellDefinition = ParametricCellDefinitionElement.FindByName (cellname, dgnfile);
if (null != CellDefinition)
{
return;
}

创建cell definition:
var cellModel = LocateCellModel (cellname);
var hdlr = DgnComponentDefinitionHandler.GetForModel (cellModel);
var defHdlr = null != hdlr ? hdlr.DefinitionModelHandler : null;
var status = null != defHdlr ? defHdlr.CreateCellDefinition (dgnfile) : ParameterStatus.Error;
if (ParameterStatus.Success == status)
CellDefinition = ParametricCellDefinitionElement.FindByName (cellname, dgnfile);
if (null == CellDefinition)
{
return;
}

24.ParametricCellElement

创建:
Bentley.DgnPlatformNET.Elements.ParametricCellElement parametricCellElement = null;
parametricCellElement = Bentley.DgnPlatformNET.Elements.ParametricCellElement.Create(cellDefinition, “”, threeDDgnModel);
parametricCellElement.AddToModel();

提取:
ParametricCellElement pce = element as ParametricCellElement;
if (pce != null)
{
}

25. SharedCellDefinitionElement

创建:
SharedCellDefinitionElement celldefEl = new SharedCellDefinitionElement(Session.Instance.GetActiveDgnModel(), “SharedCellDefExample”);
celldefEl.IsAnnotation = true;
celldefEl.AddChildElement(el);
celldefEl. AddChildComplete ();
celldefEl.AddToModel();

获取:
foreach (Bentley.DgnPlatformNET.Elements.SharedCellDefinitionElement element in Session.Instance.GetActiveDgnFile ().GetNamedSharedCellDefinitions ())
{
if (element.CellName == cellName)
return element.ElementId;
}

26.SharedCellElement

创建:
string cellName = “Test”;
Bentley.GeometryNET.DPoint3d cellOrigin = Bentley.GeometryNET.DPoint3d.FromXY (0, 0);
DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
SharedCellElement element = new SharedCellElement(dgnModel, null, cellName, cellOrigin, DMatrix3d.Identity, new DPoint3d(1, 1, 1));
element.AddToModel ();

27.TextEdit

long id = 787;
ElementId elId = new ElementId(ref id);
Bentley.DgnPlatformNET.Elements.Element el = Session.Instance.GetActiveDgnModel().FindElementById(elId);
Transform3d trans3d = DTransform3d.FromTranslation(0.0, -100, 0.0);
TransformInfo transform = new TransformInfo(trans3d);
if (el is TextElement)
{
TextEdit textEdit = TextEdit.GetAsTextEdit(el);
textEdit.ApplyTransform(tInfo);
textEdit.ReplaceInModel(el);
}

28.TextHandlerBase

long id = 787;
ElementId elId = new ElementId(ref id);
Bentley.DgnPlatformNET.Elements.Element el = Session.Instance.GetActiveDgnModel().FindElementById(elId);
Bentley.DgnPlatformNET.Elements.TextHandlerBase textElement = textElmt as Bentley.DgnPlatformNET.Elements.TextHandlerBase;
if (null != textElement)
{
Bentley.DgnPlatformNET.TextPartId textId = textElement.GetTextPartIds (new DGN.TextQueryOptions ())[0];
Bentley.DgnPlatformNET.TextBlock textBlk = textElement.GetTextPart (textId);
string fullText = textBlk.ToString ();
}

29.TextNodeElement

long id = 787;
ElementId elId = new ElementId(ref id);
Bentley.DgnPlatformNET.Elements.Element el = Session.Instance.GetActiveDgnModel().FindElementById(elId);
Bentley.DgnPlatformNET.Elements.TextElement textElement = elmt as Bentley.DgnPlatformNET.Elements.TextElement;
DGN.Elements.TextNodeElement textNodeElement = elmt as DGN.Elements.TextNodeElement;
if (null != textNodeElement || null != textNodeElement)
{
}

30.TextTable

创建:
DgnModel activeModel = Session.Instance.GetActiveDgnModel ();
DgnFile ActiveDgnFile = Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnFile ();
double mUor = Session.Instance.GetActiveDgnModel().GetModelInfo().UorPerMeter;
uint numOfRows = 5;
uint numOfColumns = 6;
double backupTextSize = 5 * mUor;
DgnTextStyle textstyle;
textstyle = DgnTextStyle.GetByName (“TextTable Style”, ActiveDgnFile);
TextTable tTable = TextTable.Create(numOfRows, numOfColumns, textstyle.Id, backupTextSize,activeModel);
TextTableElement tableElement = new TextTableElement(tTable);
tableElement.AddToModel();

获取:
Element elem = Session.Instance..GetActiveDgnModel().FindElementById(tableElementId);
TextTableElement tableElem = (TextTableElement)elem;
TextTable tTable = tableElem.ExtractTextTable();

for (uint row = 0; row < tTable.RowCount; row++)
{
TextTableCell cell = tTable.GetCell(index);
TextBlock tb = cell.TextBlock;
}

31.Namegroup

  1. DgnModel model = Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnModel();<br /> NamedGroupCollection coll = new NamedGroupCollection(model);<br /> if(coll.NameUnused("123"))<br /> {<br /> NamedGroup group = new NamedGroup("123", "", new NamedGroupFlags(), model);<br /> int num = coll.Count();//个数是0 查看界面namegroup也没有 <br /> if (group != null)<br />{ <br />group.WriteToFile (true);<br />return true;<br />}<br /> }

模型API

MicroStation有两种模型,一种是本身Dgn文件中的模型(DgnModel),另一种是参考模型(DgnAtttchment),其中DgnModel是表示文件中的(根)模型的对象,而DgnAtttchment则是表示文件中参考模型的对象。模型的API都在Bentley.DgnPlatformNET.dll文件中定义,关于模型的介绍在前面的章节中我们已经详细介绍了本章节就不在阐述。下面主要针对DgnModel和DgnAtttchment介绍各自主要的几个API方法。
基础平台API介绍 - 图23

1.获取当前激活模型

DgnModel是表示文件中的(根)模型的对象,它包含一个或者多个元素,一般从Dgn文件获取模型需要通过下面方法调用:
DgnFile activeDgn = MstnPlatformNET.Session.Instance.GetActiveDgnFile();
DgnModel activeModel = MstnPlatformNET.Session.Instance.GetActiveDgnModel();

2.获取元素集合

一般DgnModel模型包含两组元素列表,分别是控制元素集和图形元素集,当获取模型后可以通过下面两个方法获取各自的元素集合:
控制元素集合(Control ElementList)
通过DgnModel.GetControlElements()方法能获取模型里面所有控制元素集。

IEnumerable elements = null;
DgnModel activeModel = MstnPlatformNET.Session.Instance.GetActiveDgnModel();
elements = activeModel. GetControlElements ();

图形元素集合(Graphic ElementList)
通过DgnModel.GetGraphicElements()方法能获取模型里面所有控制元素集。

IEnumerable elements = null;
DgnModel activeModel = MstnPlatformNET.Session.Instance.GetActiveDgnModel();
elements = activeModel. GetGraphicElements ();

所有元素集合(Control & Graphic Elements)
通过DgnModel.GetElements() 方法能获取模型里面所有元素集。

IEnumerable elements = null;
DgnModel activeModel = MstnPlatformNET.Session.Instance.GetActiveDgnModel();
elements = activeModel. GetElements ();

3.获取Dgn文件模型集

当读取Dgn文件后,遍历该文件的模型,如果需要某一个模型内的元素从物理文件读入内存,那么需要调用FillSections ()这个方法:
foreach (DgnPlatformNET.ModelIndex modelIndex in dgnFile.GetModelIndexCollection ())
{
DgnPlatformNET.DgnModel dgnModel = dgn.LoadRootModelById(out status, modelIndex.Id);
dgnModel.FillSections( DgnModelSections.All );
}

4.清空模型内的所有元素

通过调用Empty ()方法,可以将模型内的元素清空。

5.获取模型内元素数量

通过调用GetElementCount ()方法,可以获取模型内元素个数,DgnModelSections可以设置具体的元素类型(GraphicElements\Dictionary\ ControlElements\ALL)。
uint elements = dgnConnection.DgnModel.GetElementCount(DgnModelSections.GraphicElements);

6.获取模型内某个元素

通过给定的一个ElementId,获取模型中对应的元素:
long id = 5457;
ElementId elId = new ElementId(ref id);
DgnModel activeModel = MstnPlatformNET.Session.Instance.GetActiveDgnModel();
Element elmFound = activeModel.FindElementById(elementId);

7.设置模型信息

通过SetModelInfo方法可以设置模型信息:
DgnPlatformNET.ModelInfo defaultModelInfo = dgnDefaultModel.GetModelInfo();
defaultModelInfo.Name = “123”;
defaultModelInfo.Description = “123”;
defaultModelInfo.IsInCellList = false;

dgnDefaultModel.SetModelInfo(defaultModelInfo);
dgnDefaultModel.SaveModelSettings();

8.获取模型信息

可以通过GetModelInfo方法获取模型信息,一般可以获取模型的UOR等信息:
Bentley.DgnPlatformNET.DgnModel currentmodel = Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnModel();
double UPM = currentmodel.GetModelInfo().UorPerMeter;

9.获取模型对应的DGN文件

可以通过GetDgnFile方法获取对应DGN文件从而获取dgn文件信息:
string fileName = model.GetDgnFile().GetFileName();

10.获取模型是否是只读

可以通过IsReadOnly变量获取模型是否是只读:
bool isReadOnly = model. IsReadOnly;

11.获取模型是否是字典模型

可以通过IsDictionaryModel变量获取模型是否是字典模型:
bool isDictionary = dgnModel.IsDictionaryModel;

12. 模型信息(ModelInfo)

模型信息主要是存储一个模型的若干属性,包括模型的名称、类型、描述、单位等。
名称:
ModelInfo info = m_activeModel.GetModelInfo ();
String name = info.Name;

描述:
String description = info.Description;

类型:
类型分为Normal, Sheet, Drawing三种;
String modelType = info.ModelType;

单位:
通过下面若干方法,可以获取模型的各种单位:
UorPerStorage (), GetStorageUnit, GetMasterUnit (), GetSubUnit ();

double UPM = currentmodel.GetModelInfo().UorPerMeter;

模型属性:
模型属性(Is3D, Hidden, Locked, IsCell, UseBackgroundColor, IsMarkup, IsDrawing等),通过标识,可以判断该模型是否具备一些特定属性。

其他模型信息:
GetSheetDefinition() 和:获取SheetModel 定义。

13. DgnModelRef

DgnModelRef是DgnModel(本地模型)和DgnAttachment(参考模型)的基类,通过它可以获取本地模型对象及参考模型对象。它可通过GetActiveDgnModelRef获取当前模型的DgnModelRef:
DgnModelRef modelRef = Session.Instance.GetActiveDgnModelRef ();

DgnModelRef类除了包含本地模型,还能通过该类的方法创建和获取参考模型:

(1)创建DgnAttachment:
通过CreateDgnAttachment方法创建DgnAttachment:
Bentley.DgnPlatformNET.DgnModel currentmodel = Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnModel();
DgnDocumentMoniker geometryMoniker = currentmodel.GetDgnFile().GetDocument().GetMoniker();
string geometryModelName = currentmodel.GetModelInfo().Name;
DgnAttachment ref1 = dModel.CreateDgnAttachment (geometryMoniker, geometryModelName);

(2)获取DgnModel中的DgnAttachment
一般有两种方法:
第一种是通过DgnModel,调用GetDgnAttachments获取该模型里面所有的DgnAttachments:
DgnModel activeModel = MstnPlatformNET.Session.Instance.GetActiveDgnModel();
DgnAttachmentCollection attachments = activeModel.GetDgnAttachments();
foreach (DgnAttachment d in attachments)
{
….
}

第二种通过FindDgnAttachmentByElementID方法,根据指定元素ID获取该元素的DgnAttachment:
DgnAttachment attachelm = model.FindDgnAttachmentByElementId(id);

(3)删除DgnAttachment:
通过DeleteDgnAttachment删除指定DgnAttachment:
DgnAttachmentCollection dgnAttachmentCollection = model.GetDgnAttachments ();
DgnAttachment ref1 = null;
foreach (DgnAttachment d in dgnAttachmentCollection)
{
ref1 = d;
}
StatusInt status = model.DeleteDgnAttachment (ref1);

14. 参考模型(DgnAttachment)

它是DgnModelRef的子类,它体现了将模型附加到另一个(父)模型的操作,也就是我们常说的参考模型。它可以依附于自己,也就是参考自身,也可以同时被参考多次。一个模型能够参考一个或者多个其他的模型。
参考模型分为直接参考(Direct Attachment)和嵌套参考(Nested Attachment)两种;
直接参考(Direct Attachment):它的上一级就是本地模型(DgnModelRef);
嵌套参考(Nested Attachment):它的上一级是另外一个参考模型;

一般对于直接参考(Direct Attachment)而言,可以直接通过GetParent()方法获取其父模型对象,而对于嵌套参考(Nested Attachment)来说就需要分两种情况了:
第一种情况,如果想直接获取其参考模型最顶端本地模型对象,则需要调用GetBaseDgnAttachment()方法;
第二种情况,如果想获取其上一级的参考模型,那么需要调用GetParentDgnAttachment()方法;

15. 参考模型相关变量及方法

相关变量:
AttachDescription:参考模型描述;
AttachFileName:参考模型所在的dgn文件名称;
AttachModelName:参考模型的模型名称;
DgnAttachmentLevel:参考模型中的图层;
NestDepth:嵌套深度;
DisplayScale:显示比例;
DoNotDisplayAsNested:作为嵌套时不显示;
LogicalName:逻辑名称,每个参考都可以有一个逻辑名称,如果两个参考来自同一个模型,那么每个参考都应该有一个唯一的逻辑名称。
IsLocateLocked:是否锁定选择,如果false则是无法对参考模型的对象进行选择。
IsDisplayed:是否显示模型对象;
IsSnapLocked:是否锁定捕捉;

相关方法:
SetUniqueLogical方法:
该方法主要是设置逻辑名称唯一。
DgnAttachment dgnAttachment = CurrentModel.CreateDgnAttachment(geometryMoniker, geometryModelName);
dgnAttachment. SetUniqueLogical ();
dgnAttachment.WriteToModel(true);

SetLocateLock(bool)方法:
该方法主要设置是否可以在视图中选择已显示的参考模型内的对象。
DgnAttachment dgnAttachment = CurrentModel.CreateDgnAttachment(geometryMoniker, geometryModelName);
dgnAttachment.SetLocateLock(true);
dgnAttachment.WriteToModel(true);

AppendClipVoidPoints(Bentley.GeometryNET.DPoint2d[], Bentley.GeometryNET.DMatrix3d)方法:
把视图坐标系中的点附加进剪裁边界点。

SetIsDisplayed(bool, bool, bool)方法:
该方法主要是设置是否在视图中显示参考模型内的对象。
DgnAttachment dgnAttachment = CurrentModel.CreateDgnAttachment(geometryMoniker, geometryModelName);
dgnAttachment. SetIsDisplayed (true,true,true);
dgnAttachment.WriteToModel(true);

SetSnapLock(bool)方法:
该方法主要是设置参考模型的捕捉锁定标志。
DgnAttachment dgnAttachment = CurrentModel.CreateDgnAttachment(geometryMoniker, geometryModelName);
dgnAttachment. SetSnapLock (true);
dgnAttachment.WriteToModel(true);

WriteToModel(bool)方法:
每次对模型进行设置后都需要调用该方法,将设置持久化到文件里。
DgnAttachment dgnAttachment = CurrentModel.CreateDgnAttachment(geometryMoniker, geometryModelName);
dgnAttachment. SetSnapLock (true);
dgnAttachment.WriteToModel(true);

SetMasterOrigin(Bentley.GeometryNET.DPoint3d)方法:
设置本地模型中应显示被参考模型的位置。
DgnAttachment dgnAttachment = CurrentModel.CreateDgnAttachment(geometryMoniker, geometryModelName);
DPoint3d pt = new DPoint3d(0, 0, 0);
dgnAttachment. SetMasterOrigin (pt);
dgnAttachment.WriteToModel(true);

SetClipBoundFromViewPoints(Bentley.GeometryNET.DPoint2d[], Bentley.GeometryNET.DMatrix3d, Bentley.GeometryNET.DPoint3d, double, bool)方法:
从视图坐标系中的点设置剪裁边界点。

SetClipRotMatrix(Bentley.GeometryNET.DMatrix3d)方法:
设置参考裁剪旋转变换。

GetMasterOrigin(Bentley.GeometryNET.DPoint3d)方法:
获取本地模型中应显示被参考模型的位置。
DgnAttachment dgnAttachment = CurrentModel.CreateDgnAttachment(geometryMoniker, geometryModelName);
DPoint3d pt = new DPoint3d();
dgnAttachment. GetMasterOrigin (pt);

GetNamedView ()方法:
获取参考文件中此参考模型的命名视图。

GetParent() ()方法:
在直接参考中,获取本地模型。

GetRefOrigin ()方法:
获取参考模型中的原点。
DgnAttachment dgnAttachment = CurrentModel.CreateDgnAttachment(geometryMoniker, geometryModelName);
DPoint3d pt = new DPoint3d();
pt = dgnAttachment.GetRefOrigin ();

SetRefOrigin(Bentley.GeometryNET.DPoint3d)方法:
设置参考模型中的位置,该位置应与父模型中的主原点重合。
DgnAttachment dgnAttachment = CurrentModel.CreateDgnAttachment(geometryMoniker, geometryModelName);
DPoint3d pt = new DPoint3d(0, 0, 0);
dgnAttachment. SetRefOrigin (pt);
dgnAttachment.WriteToModel(true);

GetScaleMode ()方法:
获取显示参考模型中的元素时要应用的缩放类型。
DgnAttachment dgnAttachment = CurrentModel.CreateDgnAttachment(geometryMoniker, geometryModelName);
int mode = dgnAttachment. GetScaleMode ();

SetScaleMode(Bentley.DgnPlatformNET.DgnAttachment.ScaleMode) 方法:
设置显示参考模型中的图元时要应用的缩放类型。
DgnAttachment dgnAttachment = CurrentModel.CreateDgnAttachment(geometryMoniker, geometryModelName);
dgnAttachment. SetScaleMode (DgnAttachment.ScaleMode.Direct);
dgnAttachment.WriteToModel(true);

GetTransformToParent(Bentley.GeometryNET.DTransform3d, bool)方法:
获取从参考模型显示时要应用的矩阵变换。

GetRotMatrix()方法:
获得从参考模型显示时要应用的旋转变换。

SetRotMatrix(Bentley.GeometryNET.DMatrix3d)方法:
设置从参考模型显示时要应用的旋转变换。

GetClipPoints()方法:
获得剪裁边界点。
DgnAttachment dgnAttachment = CurrentModel.CreateDgnAttachment(geometryMoniker, geometryModelName);
List Points = new List();
Points = dgnAttachment. GetClipPoints ();

SetClipPoints(Bentley.GeometryNET.DPoint2d[])方法:
设置剪裁边界点。
DgnAttachment dgnAttachment = CurrentModel.CreateDgnAttachment(geometryMoniker, geometryModelName);
List Points = new List();
dgnAttachment. SetClipPoints (Points);

SetLevelControlsDisplay(bool) 方法:
该方法主要是设置是否仅在显示参考级别时才显示参考模型内容。
DgnAttachment dgnAttachment = CurrentModel.CreateDgnAttachment(geometryMoniker, geometryModelName);
dgnAttachment. SetLevelControlsDisplay (true);
dgnAttachment.WriteToModel(true);

GetBaseDgnAttachment()方法:
在嵌套参考中,获得本地模型。

GetParentDgnAttachment()方法:
在嵌套参考中,获得上一级参考模型。

GetAttachFullFileSpec(bool)方法:
该方法是获取其参考模型所在的dgn文件的文件路径:
foreach (var attachment in model.GetDgnAttachments())
{
string attachmentFilename = attachment.GetAttachFullFileSpec(false);
}

文件API

Dgn文件主要包括两部分:Dictionary和DgnModel;
Dictionary(数据字典模型)其实是一个非模型的模型,在这个模型中存储了大量控制整个文件的元素,比如整个dgn文件存储的第一个元素
(Type=9)的元素,它是整个文件的头,存储整个文件需要的参数。还有就是层表(Level Table)、样式定义、字体表(Font Table)、EC Schema等都是存储在数据字典模型中。

DgnModel(图形模型)包括控制元素(ControlElms)和图形元素(GraphicElms),该模型可以有多个,但提供的种子文件只有一个,可以根据种子文件创建多个相同的模型。一个文件可以包含一个或者多个模型。

DgnDocument和DgnFile区别

DgnDocument是存在在磁盘上面的对象,而DgnFile是在MicroStation从磁盘上打开dgn文件,将该dgn文件装载到内存中的对象。

DgnFile类

DgnFile类是继承于DgnFileBase,所以关于文件的操作基本都是通过DgnFile类和DgnFileBase类完成。

下面介绍几个常用的DgnFile类的方法:

在当前文件内创建一个新的模型

CreateNewModel(创建新模型)
string cellModelName = “newmodel”;
DgnModelStatus modelStatus;
DgnModel model = Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnModel();
DgnPlatformNET.DgnModel newCellModel = cellfileOwner.DgnFile.CreateNewModel(out modelStatus, cellModelName, DgnPlatformNET.DgnModelType.Normal, componentModel.Is3d, model);

删除指定模型

DeleteModel(删除模型)
DgnModelRef modelRef = Session.Instance.GetActiveDgnModelRef();
StatusInt ret = Dgnfile.DeleteModel (modelRef.AsDgnModel ());
FillDictionaryModel(确保字典模型已填充)和FillSectionsInModel(确保已填充指定的模型)
读写读写外部DGN文件时,需要调用两个关键的函数FillDictionaryModel和FillSectionsInModel:
string strDgn = “c:\111\tu.dgn”;
DgnDocument dgnDoc = DgnDocument.CreateForLocalFile(strDgn);
DgnFileOwner dgnFileOwner = DgnFile.Create(dgnDoc, DgnFileOpenMode.ReadOnly);
DgnFile dgnFile = dgnFileOwner.DgnFile;
StatusInt errorStatus;
dgnFile.LoadDgnFile(out errorStatus);
dgnFile.FillDictionaryModel();

DgnModel dgnModel = dgnFile.LoadRootModelById(out errorStatus, dgnFile.DefaultModelId);
dgnFile.FillSectionsInModel(dgnModel, DgnModelSections.All);

通过模型ID找到指定模型

FindLoadedModelById(Bentley.DgnPlatformNET.ModelId)
ModelId ModelId = dgnFile.FindModelIdByName(“123”);
DgnModel dgnModel = dgnFile.LoadRootModelById(out errorStatus, ModelId);

通过模型名称找到对应模型ID

FindModelIdByName(string)
ModelId ModelId = dgnFile.FindModelIdByName(“123”);

获取颜色列表

GetColorMap
DgnPlatformNET.DgnColorMap colorTable = Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnFile ().GetColorMap ();

获取dgn文件字体表

GetDgnFontMap
DgnFontNumberMap fontmap = Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnFile ().GetDgnFontMap();

获取字典模型

GetDictionaryModel
DgnModel dictionaryModel = Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnFile ().GetDictionaryModel();

获取标注样式

GetDimensionStyles
foreach (DimensionStyle style in dgnFile.GetDimensionStyles ()
{}

获取DgnDocument

GetDocument
DgnDocument doc = Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnFile ().GetDocument()

获得dgn文件路径名称

GetFileName()
string fileName = Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnFile ().GetFileName();

获取图层缓存,通过图层缓存获取相关图层。

GetLevelCache
foreach (LevelHandle level in Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnFile ().GetLevelCache().GetHandles())
{
}

获取DGN版本号

GetVersion
DgnFileFormatType format;
int maj;
int min;
Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnFile ().GetVersion(out format, out maj, out min);

针对dgn文件进行修改操作后,调用该方法进行持久化操作。

ProcessChanges
dgnFile.ProcessChanges (DgnSaveReason.ApplicationInitiated);

加载dgn文件

LoadDgnFile
从磁盘加载文件头数据,相当于打开文件,它只加载文件头数据,而不加载任何其他数据。
sLoaded()在调用LoadDgnFile()后返回true,如果在写模式下打开,IsOpen()函数在调用LoadDgnFile()后返回true。
string strDgn = “c:\111\tu.dgn”;
DgnDocument dgnDoc = DgnDocument.CreateForLocalFile(strDgn);
DgnFileOwner dgnFileOwner = DgnFile.Create(dgnDoc, DgnFileOpenMode.ReadOnly);
DgnFile dgnFile = dgnFileOwner.DgnFile;
StatusInt errorStatus;
dgnFile.LoadDgnFile(out errorStatus);
dgnFile.FillDictionaryModel();

Release方法

关闭文件
dgnFile.Release()

获取dgn文件内所有模型集合

GetModelIndexCollection
ModelIndexCollection models = Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnFile().GetModelIndexCollection();

事件API

C#中事件是用户与应用程序交互的基础,它是回调机制的一种应用。举个例子,当用户点击按钮时,我们希望弹出一句“您好”;这里的“点击”就是一个事件。那么回调就是我们注册一个方法,当用户点击时,程序自动执行这个方法去响应这个操作,而不是我们时刻去监听用户有没有点击。而说到事件就肯定离不开委托这个关键字了,委托是.net用来实现回调机制的技术,而事件又是回调机制的一种应用,在学习事件前,应该先学习好委托的知识。有关委托和事件相关的内容,读者可以在C#语言教材中更进一步学习,我们这里主要介绍一下Mstn Addins SDK中为我们提供的事件。通过注册这些事件的回调函数,我们可以在插件中实现一些高级功能。
Mstn Addins SDK为我们提供的事件都在插件入口类Bentley.MstnPlatformNET.AddIn中定义,如下图所示:

基础平台API介绍 - 图24
基础平台API介绍 - 图25
这些事件大部分我们通过名字就可以大致猜测出来它是在用户做了什么操作时发生的,接下来我们简单介绍一下几个常用事件的用法。

1.ViewGroupChangeEventHandler ViewGroupChangeEvent

ViewGroupChangeEvent是在View Group发生变化时触发的一个事件。其对应的delegate类型如下所示:
public delegate void ViewGroupChangeEventHandler(AddIn sender, ViewGroupChangeEventArgs eventArgs);
第二个参数类型如下所示:
public class ViewGroupChangeEventArgs : EventArgs
{
public ViewGroup CurrentViewGroup;
public ViewGroup NewViewGroup;
public ChangeType m_change;
public ViewGroupChangeEventArgs(ViewGroup currentViewGroup, ViewGroup newViewGroup, VIEWGROUP_ChangeType changeType);
public ChangeType Change { get; }
public enum ChangeType
{
BeforeFileClose = 1,
BeforeApply = 2,
AfterApply = 3,
BeforeSaveAs = 4
}
}
通过这个参数的Change属性我们可以获取到View Group发生变化的类型,BeforeFileClose表示View Group变化因为关闭文件,在退出文件之前发生的。BeforeApply和AfterApply是我们在Mstn主界面中手动更改View Group时触发该事件了,这两个类型分别是在View Group变化之前和变化之后触发的。BeforeSaveAs表示是在文件另存时触发的。CurrentViewGroup和NewViewGroup可以获取到当前已经更改后的View Group。

2.MessageCenterWriteEventHandler MessageCenterWriteEvent

MessageCenterWriteEvent是在如下图所示的Mstn底部消息中心有新的内容写入时被触发的一个事件。
基础平台API介绍 - 图26
其对应的delegate类型如下所示:
public delegate void MessageCenterWriteEventHandler(AddIn sender, MessageCenterWriteEventArgs eventArgs);
第二个参数类型如下所示:
public class MessageCenterWriteEventArgs : EventArgs
{
public int MessageType;
public string Message;
public string Detail;
public int DetailMessageAttributes;
public MessageCenterWriteEventArgs(int messageType, char pMessage, char pDetail, int detailMessageAttributes);
}
我们可以通过成员变量Message和Detail获取到消息内容。

3.LevelChangeEventHandler LevelChangeEvent

LevelChangeEvent是在Level发生变化时被触发的一个事件,不仅仅Active Level变化会触发该事件,我们在Level Manager里边修改Level的一些设置时也会触发该事件。此事件对应的delegate类型如下所示:
public delegate void LevelChangeEventHandler(AddIn senderIn, LevelChangeEventArgs eventArgsIn);
第二个参数类型如下所示:
public class LevelChangeEventArgs : EventArgs
{
public LevelChangeEventArgs(LevelHandle levelIn, ChangeType changeIn);
public ChangeType Change { get; }
public LevelHandle Level { get; }
public enum ChangeType
{
TableRewrite = 1,
Create = 2,
Delete = 3,
ChangeName = 4,
ChangeCode = 5,
ChangeParent = 6,
ChangeDisplay = 7,
ChangeAttribute = 8,
ChangeActive = 9,
LibraryAttach = 10,
LibraryDetach = 11,
ChangeUsage = 12,
ChangeElementCount = 13,
TableUndo = 14,
TableRedo = 15,
TableImport = 16,
PreChangeActive = 17,
PreDelete = 18
}
}
我们通过Change属性可以获取到Level发生变化的原因,TableRewrite表示我们在Level Manager里边修改了某个Level的相关属性。Create 和ChangeName 则表示在我们创建或者删除Level时触发了该事件。ChangeName、ChangeCode、ChangeParent、ChangeDisplay、ChangeAttribute则表示Level的对应属性发生变化时被触发的。ChangeActive表示是当前Active Level发生变化触发了该事件,这里不仅仅是我们在Mstn中手动更改当前Active Level时会触发该事件,我们在程序中修改Active Level也会触发该事件。LibraryAttach和LibraryDetach是链接或者卸载Library的时候如果Library中有新的Level导入或者移除时触发了该事件。PreChangeActive表示在Active Level发生变化但是是在真正变化之前,类似的,PreDelete表示Level删除但是是在真正删除之前。我们还可以通过Level属性获取到当前发生变化的LevelHandle对象实例。通过这个对象实例我们可以进一步获取到Level相关的其他信息。

4.ModelChangedEventHandler ModelChangedEvent

ModelChangedEvent是在Model被修改时会被触发的一个事件。此事件对应的delegate类型如下所示:
public delegate void ModelChangedEventHandler(AddIn senderIn, ModelChangedEventArgs eventArgsIn);
其中第二个参数类型的定义如下所示:
public class ModelChangedEventArgs : EventArgs
{
public ModelChangedEventArgs(DgnModelRef* modelRefIn, ChangeType changeIn);
public ChangeType Change { get; }
public DgnPlatformNET.DgnModelRef DgnModelRef { get; }
public void ClearDgnModelRef();
public enum ChangeType
{
Create = 1,
Delete = 2,
Properties = 3,
Settings = 4,
Active = 5,
BeforeDelete = 6,
UnCreate = 7,
UnDelete = 8,
BeforeUnCreate = 9,
Name = 10,
BeforeActive = 11,
BeforeName = 12,
BeforeSettings = 13,
BeforeProperties = 14,
BeforeCreate = 15,
BeforeUnDelete = 16,
PropagateAnnotationScale = 17,
BeforeCopy = 18,
Copied = 19,
BeforeUndoProperties = 20,
UndoProperties = 21
}
}
通过此参数的Change成员属性可以知道触发此事件的原因,Create表示是创建新的Model触发了当前事件,Delete表示是删除Model触发了当前事件。UnCreate 、UnDelete则表示是撤销Model的创建或者删除操作时触发了当前事件。BeforeDelete 、BeforeCreate 表示在某个Model删除或者创建之前触发了此次事件。BeforeUnCreate 、BeforeUnDelete则表示在真正撤销Model创建或者删除之前触发了此次事件。Name 表示某个Model的名字发生变化时触发了此次事件,BeforeName 是Model的名字真正被修改之前触发了此次事件。Properties、BeforeProperties、UndoProperties、BeforeUndoProperties、Settings、BeforeSettings分别表示Model的属性、设置改变时触发了当前事件。其中Before表示是在属性或者设置真正修改之前触发了当前事件,而Undo则是撤销属性或者设置的修改触发了当前事件。Active表示激活了某个Model触发了当前事件。BeforeActive则是在某个Model真正激活之前触发了此次事件。PropagateAnnotationScale表示Model的注释比例发生变化触发了此次事件,Copied、BeforeCopy则是在Model被拷贝和拷贝之前触发了此次事件。
通过此参数的DgnModelRef成员属性可以获取到发生变化的Model的DgnPlatformNET.DgnModelRef对象实例,通过此实例可以完成对发生变化的Model的其他操作。

5.ReferenceModifiedEventHandler ReferenceModifiedEvent

ReferenceModifiedEvent是在参考文件被修改时触发的一个事件,此事件对应的delegate类型如下所示:
public delegate void ReferenceModifiedEventHandler(AddIn senderIn, ReferenceModifiedEventArgs eventArgsIn);
其中第二个参数类型的定义如下所示:
public class ReferenceModifiedEventArgs : EventArgs
{
public ReferenceModifiedEventArgs(DgnPlatform.DgnAttachment oldReferenceFileIn, DgnPlatform.DgnAttachment newReferenceFileIn, DgnModelRef modelRefIn, bool changesWrittenIn);
public bool ChangesWritten { get; }
public DgnPlatformNET.DgnAttachment DgnAttachment { get; }
public DgnPlatform.DgnAttachment
NewReferenceFile { get; }
public DgnPlatform.DgnAttachment* OldReferenceFile { get; }
}
通过此参数的DgnAttachment成员属性我们可以获取到发生修改的参考的DgnPlatformNET.DgnAttachment的对象实例,通过此实例我们可以获取到参考的其他信息。

6.ReferenceAttachedEventHandler ReferenceAttachedEvent

ReferenceAttachedEvent是在往当前Model连接新的参考文件时触发的一个事件,此事件对应的delegate类型如下所示:
public delegate void ReferenceAttachedEventHandler(AddIn senderIn, ReferenceAttachedEventArgs eventArgsIn);
其中第二个参数的类型定义如下所示:
public class ReferenceAttachedEventArgs : EventArgs
{
public ReferenceAttachedEventArgs(DgnModelRef* modelRefIn, AttachCause attachCauseIn);
public AttachCause Cause { get; }
public DgnPlatformNET.DgnAttachment DgnAttachment { get; }
public enum AttachCause
{
New = 0,
ReAttached = 1,
UndoneDetach = 2,
RedoneAttach = 3,
Reloaded = 4,
ReAttachUndoRedo = 5,
ReAttachChildrenReloaded = 6
}
}
通过此参数的Cause成员属性我们可以获取到当前参考是如何连接进来的。

7.ReferenceDetachedEventHandler ReferenceDetachedEvent

ReferenceDetachedEvent是在卸载参考文件时触发的一个事件。其对应的delegate类型如下所示:
public delegate void ReferenceDetachedEventHandler(AddIn senderIn, ReferenceDetachedEventArgs eventArgsIn);
其中第二个参数的类型定义如下所示:
public class ReferenceDetachedEventArgs : EventArgs
{
public ReferenceDetachedEventArgs(DgnModelRef* modelRefIn, string fileNameIn, DetachCause detachCauseIn);
public DetachCause Cause { get; }
public string FileName { get; }
public DgnPlatformNET.DgnAttachment DgnAttachment { get; }
public enum DetachCause
{
Detached = 0,
UndoAttach = 1,
RedoneDetach = 2,
ReAttached = 3,
ModelDeleted = 4,
Reloaded = 5
}
}
通过此参数的Cause成员属性我们可以获取到当前参考是如何卸载的。

8.XAttributeUndoRedoEventHandler XAttributeUndoRedoEvent

XAttributeUndoRedoEvent是在当前文件中的XAttribute撤销或者恢复的时候会被触发的一个事件,而在往文件中新添加或者删除时不会触发这个事件。其对应的delegate类型如下所示:
public delegate void XAttributeUndoRedoEventHandler(AddIn sender, XAttributeUndoRedoEventArgs eventArgs);
其中第二个参数类型的定义如下所示:
public class XAttributeUndoRedoEventArgs : EventArgs
{
public ChangeTrackKind Change;
public bool IsUndo;
public ChangeTrackSource Source;
public XAttributeUndoRedoEventArgs(XAttributeHandle xAttr, ChangeTrackKind changeKind, bool isUndo, ChangeTrackInfo info, ChangeTrackSource changeSource);
public ref ChangeTrackInfo Info { get; }
public XAttribute XAttribute { get; }
}
其中public ChangeTrackKind Change的定义如下所示:
public enum ChangeTrackKind
{
Delete = 1,
Add = 2,
Modify = 3,
ModifyFence = 5,
Mark = 7,
ModelAdd = 9,
ModelDelete = 10,
AddXAttribute = 11,
DeleteXAttribute = 12,
ModifyXAttribute = 13,
ReplaceXAttribute = 14
}
通过这个参数我们可以获取到撤销或者恢复的原因以及此动作的效果,例如是添加、修改或者是删除了XAttribute。

9.XAttributeChangedEventHandler XAttributeChangedEvent

XAttributeChangedEvent是当前文件中的XAttribute被修改时会触发的一个事件。其对应的delegate如下所示:
public delegate void XAttributeChangedEventHandler(AddIn sender, XAttributeChangedEventArgs eventArgs);
其中第二个参数类型定义如下所示:
public class XAttributeChangedEventArgs : EventArgs
{
public ChangeTrackKind Change;
public int ProcessNumber;
public short FunctionName;
public int GroupID;
public XAttributeChangedEventArgs(XAttributeHandle xattr, ChangeTrackKind changeKind, int processNumber, short functionName, int groupID, bool cannotBeUndoneFlagP);
public bool Undoable { get; set; }
public XAttribute XAttribute { get; }
}
通过这个参数我们可以获取到XAttribute的变化类型是添加、修改、删除、更新等。通过这个参数的XAttribute成员属性我们可以获取到发生变化的XAttribute的对象实例,XAttribute类型有一个ElemRefPtr的成员属性,通过这个属性我们调用Bentley.DgnPlatformNET.Elements.Element.GetFromElementRef函数可以构造出来XAttribute依附的元素的Bentley.DgnPlatformNET.Elements.Element对象实例。通过构造出来的Element对象实例。

10.ElementUndoRedoEventHandler ElementUndoRedoEvent

ElementUndoRedoEvent是在撤销或者恢复修改元素的操作时触发的一个事件。请注意这里不是对元素进行修改时触发,而是撤销或者恢复这个修改时触发的。其对应的delegate如下所示:
public delegate void ElementUndoRedoEventHandler(AddIn sender, ElementUndoRedoEventArgs eventArgs)
其中第二个参数类型定义如下所示:
public class ElementUndoRedoEventArgs : EventArgs
{
public IntPtr OldElementRef;
public IntPtr OldModelRef;
public ChangeTrackKind Change;
public bool IsUndo;
public ChangeTrackSource Source;
public ElementUndoRedoEventArgs(MSElementDescr newElemDescrP, MSElementDescr oldElemDescrP, IntPtr oldElemRef, IntPtr oldModelRef, ChangeTrackKind changeKind, bool isUndo, ChangeTrackInfo* info, ChangeTrackSource changeSource);
public IntPtr NewElemDescr { get; }
public IntPtr OldElemDescr { get; }
public ref ChangeTrackInfo Info { get; }
public IntPtr NewElementRef { get; }
public Element NewElement { get; }
}
通过这个参数我们可以获取当前撤销或者恢复是元素发生类什么类型的修改操作时引起的。通过OldElementRef、NewElementRef等成员变量我们可以获取到修改前后元素的Bentley.DgnPlatformNET.Elements.Element对象实例。

11.ElementChangedEventHandler ElementChangedEvent

ElementChangedEvent是在修改元素时会触发的一个事件。其对应的delegate如下所示:
public delegate void ElementChangedEventHandler(AddIn sender, ElementChangedEventArgs eventArgs);

其中第二个参数类型定义如下所示:
public class ElementChangedEventArgs : EventArgs
{
public IntPtr OldElementRef;
public IntPtr OldModelRef;
public ChangeTrackKind Change;
public ChangeTrackInfo Info;
public ElementChangedEventArgs(MSElementDescr newElemDescrP, MSElementDescr oldElemDescrP, IntPtr oldElemRef, IntPtr oldModelRef, ChangeTrackKind changeKind, int processNumber, short functionName, int groupID, bool* cannotBeUndoneFlagP);
public IntPtr NewElemDescr { get; }
public IntPtr OldElemDescr { get; }
public bool Undoable { get; set; }
public Element NewElement { get; }
}
通过这个参数的Change成员变量我们可以获取到是对元素做了什么类型的操作时触发了当前事件。通过OldElementRef、NewElementRef等成员变量我们可以获取到修改前后元素的Bentley.DgnPlatformNET.Elements.Element对象实例。

12.UndoRedoFinishedEventHandler UndoRedoFinishedEvent

UndoRedoFinishedEvent是我们在Mstn中做任何撤销或者恢复操作时触发的一个事件。其对应的delegate如下所示:
public event UndoRedoFinishedEventHandler UndoRedoFinishedEvent;
其中第二个参数类型定义如下所示:
public class UndoRedoFinishedEventArgs : EventArgs
{
public bool IsUndo;

  1. public UndoRedoFinishedEventArgs(bool isUndo);<br /> }<br />通过此参数的IsUndo成员变量我们可以获取触发当前事件的是撤销还是恢复操作。

13.FileSaveAsEventHandler FileSaveAsEvent

FileSaveAsEvent是我们在Mstn中执行另存文件时触发的一个事件。其对应的delegate如下所示:
public delegate void FileSaveAsEventHandler(AddIn sender, FileSaveAsEventArgs eventArgs);
其中第二个参数类型定义如下所示:
public class FileSaveAsEventArgs : EventArgs
{
public When WhenCode;
public string DestinationFileName;
public enum When
{
BeforeSaveAsFileCreated = 0,
AfterSaveAsFileCreated = 1
}
}
通过此参数的WhenCode成员变量我们可以获取当前事件是在完成文件另存操作之前还是以后触发的。通过DestinationFileName我们可以获取到另存文件的文件名。

14.FileSaveEventHandler FileSaveEvent

FileSaveEvent是在Mstn中保存文件时触发的一个事件。其对应的delegate如下所示:
public delegate void FileSaveEventHandler(AddIn sender, FileSaveEventArgs eventArgs);
其中第二个参数类型定义如下所示:
public class FileSaveEventArgs : EventArgs
{
public When WhenCode;
public Changes ChangesCode;
public Reason ReasonCode;
public double TimeStamp;
public string MasterFileName;
public enum When
{
BeforeProcessing = 0,
AfterProcessing = 1
}
public enum Changes
{
Abandon = 0,
Save = 1,
FullSave = 2
}
public enum Reason
{
UserInitiated = 1,
ApplInitiated = 2,
ReffileSave = 3,
FileClose = 4,
FileCompress = 5,
FileSaveAs = 6,
AutoTime = 7,
PreCommit = 8,
SaveSettings = 9,
Backup = 10,
Encrypt = 11,
Precompress = 12
}
}
通过此参数我们可以获取到当前事件的一些信息。例如通过其成员变量WhenCode我们可以判断当前事件是在完成保存操作之前还是以后触发的,通过成员变量ReasonCode我们可以获取是什么原因引发的文件保存。

15.DgnCacheUnloadingEventHandler DgnCacheUnloadingEvent

DgnCacheUnloadingEvent是在即将卸载DGN缓存时触发的一个事件,例如我们在卸载参考文件时,就会触发该事件。其对应的delegate如下所示:
public delegate void DgnCacheUnloadingEventHandler(AddIn sender, DgnCacheUnloadingEventArgs eventArgs);

16.NewDesignFileEventHandler NewDesignFileEvent

NewDesignFileEvent是在我们打开一个新的文件时会触发的一个事件。其对应的delegate如下所示:
public delegate void NewDesignFileEventHandler(AddIn sender, NewDesignFileEventArgs eventArgs);
其中第二个参数类型定义如下所示:
public class NewDesignFileEventArgs : EventArgs
{
public When WhenCode;
public string Name;
public NewDesignFileEventArgs(char* filenameP, int preOrPost);
public enum When
{
BeforeDesignFileClose = 0,
AfterDesignFileOpen = 1
}
}
通过此参数的成员变量WhenCode我们可以判断当前事件是在当前文件关闭之前还是在新的文件打开之后触发的。通过Name成员变量我们可以获取到文件名。

17.BeforeNewDesignFileEventHandler BeforeNewDesignFileEvent

BeforeNewDesignFileEvent是在我们打开新的文件,而在新的文件真正打开之前被调用的一个事件。这个事件跟NewDesignFileEvent事件当第二个参数的WhenCode为BeforeDesignFileClose时等同。其对应的delegate如下所示:
public delegate void BeforeNewDesignFileEventHandler(AddIn sender, BeforeNewDesignFileEventArgs eventArgs);
其中第二个参数类型定义如下所示:
public class BeforeNewDesignFileEventArgs : EventArgs
{
public string Name;
public BeforeNewDesignFileEventArgs(char* filenameP);
}

18.CompressDesignFileEventHandler CompressDesignFileEvent

CompressDesignFileEvent是我们在压缩文件时触发的一个事件。其对应的delegate如下所示:
public delegate void CompressDesignFileEventHandler(AddIn sender, CompressDesignFileEventArgs eventArgs);
其中第二个参数类型定义如下所示:
public class CompressDesignFileEventArgs : EventArgs
{
public When WhenCode;
public Response ResponseCode;
public string ReturnErrorMsg;
public enum When
{
BeforeDesignFileCompress = 1,
AfterDesignFileCompress = 2
}
public enum Response
{
CompressionProceed = 0,
CompressionAbort = 1
}
}
通过此参数我们可以获取当前事件是在压缩完成之前或者之后触发的。

19.EventHandler ExitDesignFileStateEvent

ExitDesignFileStateEvent是在退出当前文件时会触发的一个事件。其对应的delegate如下所示:
public delegate void EventHandler(AddIn sender, EventArgs eventArgs);

20.ChildTerminatedEventHandler ChildTerminatedEvent

ChildTerminatedEvent是在卸载子MDL应用程序时会触发的一个事件。如果MDL应用程序通过调用mdlSystem_loadMdlProgramExtended或mdlSystem_loadMdlProgram启动另外一个MDL应用程序,则此被启动的MDL应用程序被视为一个子MDL应用程序。其对应的delegate如下所示:
public delegate void ChildTerminatedEventHandler(AddIn sender, ChildTerminatedEventArgs eventArgs);
其中第二个参数的类型定义如下所示:
public class ChildTerminatedEventArgs : EventArgs
{
public UnloadReasons UnloadKind;
public int UnloadStatus;
public string MdlTaskId;
}
成员变量public UnloadReasons UnloadKind的定义如下所示:
public enum UnloadReasons
{
AppDomainUnloading = -6,
EnteringRestrictedRightsMode = -5,
UnloadUserInterfaceServers = -4,
LibraryUnload = -3,
Shutdown = -2,
Fatal = -1,
Command = 1,
ExitBySelf = 2,
ExitByOtherApp = 3,
Exception = 4
}
通过这个成员变量我们可以获取到子MDL应用程序下载的原因。

21.UnloadAnyAppEventHandler UnloadAnyAppEvent

UnloadAnyAppEvent是在Mstn中卸载某个MDL应用程序时会被触发的一个事件。其对应的delegate如下所示:
public delegate void UnloadAnyAppEventHandler(AddIn sender, UnloadAnyAppEventArgs eventArgs);
其中第二个参数的类型定义如下所示:
public class UnloadAnyAppEventArgs : EventArgs
{
public UnloadReasons UnloadKind;
public string MdlTaskId;
public UnloadAnyAppEventArgs(UnloadReasons reasonCode, string mdlTaskId);
}

22.UnloadingEventHandler UnloadingEvent

UnloadedEvent是在Mstn中卸载当前应用程序之后会触发的一个事件,其对应的delegate如下所示:
public delegate void UnloadedEventHandler(AddIn sender, UnloadedEventArgs eventArgs);
ReloadEventHandler ReloadEvent
ReloadEvent是在Mstn中重新加载当前应用程序时会触发的一个事件,其对用的delegate如下所示:
public delegate void ReloadEventHandler(AddIn sender, ReloadEventArgs eventArgs);

23.ViewGroupCacheChangeEventHandler ViewGroupCacheChangeEvent

ViewGroupCacheChangeEvent是在当前View Group缓存发生变化时会被触发的一个事件,例如当我们在Mstn中创建或者删除一个View Group时就会触发这个事件。此事件对应的delegate如下所示:
public delegate void ViewGroupCacheChangeEventHandler(AddIn sender, ViewGroupCacheChangeEventArgs eventArgs);
其中第二个参数的类型定义如下所示:
public class ViewGroupCacheChangeEventArgs : EventArgs
{
public string Name;
public string Description;
public int ChangeType;
public ViewGroupCacheChangeEventArgs(char nameP, char descriptionP, ViewGroupChangeType type);
}
通过这个参数我们可以获取到View Group的Name、Description等信息。

24.AcsOperationEventHandler AcsOperationEvent

AcsOperationEvent是我们在修改ACS坐标系时会触发的一个事件。其对应的delegate如下所示:
public delegate void AcsOperationEventHandler(AddIn sender, AcsOperationEventArgs eventArgs);

其中第二个参数的类型定义如下所示:
public class AcsOperationEventArgs : EventArgs
{
public string Name;
public string Description;
public ACSType Type;
public int OpType;
public IAuxCoordSys ACS;
public ACSEventType EventType;
public AcsOperationEventArgs(char
acsNameP, char acsDescP, ACSType acsType, AcsChangeType opType, IAuxCoordSys acs, ACSEventType eventType);
}
我们通过此参数的Name、Description、Type等成员变量可以获取到ACS坐标系的名字、描述、类型等信息。

25.SelectionChangedEventHandler SelectionChangedEvent

SelectionChangedEvent是在当前选择集发生变化时会被触发的一个事件,此处变化不仅仅是选择集变化,我们通过Mstn的修改元素的工具去修改选择集中的元素时也会触发此事件。其对应的delegate如下所示:
public delegate void SelectionChangedEventHandler(AddIn sender, SelectionChangedEventArgs eventArgs);
其中第二个参数的类型定义如下所示:
public class SelectionChangedEventArgs : EventArgs
{
public Response ResponseCode;
public ActionKind Action;
public uint FilePosition;
public SelectionChangedEventArgs(ActionKind actionKind, uint filePosition, DgnModelRef* modelRefP);

  1. public DgnPlatformNET.DgnModelRef DgnModelRef { get; }<br /> public enum Response<br /> {<br /> SelectProceed = 0,<br /> SelectAbort = 1<br /> }<br /> public enum ActionKind<br /> {<br /> Nothing = 0,<br /> Stretch = 1,<br /> Window = 2,<br /> Drag = 3,<br /> DragNew = 4,<br /> SetEmpty = 6,<br /> SetChanged = 8,<br /> DoubleClickHandle = 10,<br /> DoubleClickElement = 11<br /> }<br /> }<br />通过此参数我们可以影响选择集的一些行为,例如我们在事件处理函数中将此参数的ResponseCode成员变量设置为SelectionChangedEventArgs.Response.SelectAbort的话,用户将无法通过光标直接在视图中拖拽移动元素。我们通过此参数的Action成员变量可以获取当前选择集发生了什么变化。例如当用户在视图中直接通过按下左键来拖拽移动元素时,参数的Action成员变量的值将为SelectionChangedEventArgs.ActionKind.Drag

26.ActiveParamChangedEventHandler ActiveParamChangedEvent

ActiveParamChangedEvent是在Mstn中一些激活参数设置发生变化时被触发的一个事件。其对应的delegate如下所示:

public delegate void ActiveParamChangedEventHandler(AddIn sender, ActiveParamChangedEventArgs args);
其中第二个参数的类型定义如下所示:
public class ActiveParamChangedEventArgs : EventArgs
{
public ActiveParamChangedEventArgs(ActiveParamId id);

  1. public ActiveParamId Id { get; }<br /> }<br />其中成员变量Id的类型定义如下所示:<br />public enum ActiveParamId<br /> {<br /> COLOR = 1,<br /> COLOR_BY_NAME = 2,<br /> LINESTYLE = 3,<br /> LINEWEIGHT = 4,<br /> LEVEL = 5,<br /> ANGLE = 6,<br /> FONT = 7,<br /> GRIDUNITS = 8,<br /> GRIDREF = 9,<br /> TEXTHEIGHT = 10,<br /> TEXTWIDTH = 11,<br /> UNITROUNDOFF = 12,<br /> TEXTJUST = 13,<br /> NODEJUST = 14,<br /> CELLNAME = 15,<br /> LINELENGTH = 16,<br /> LINESPACING = 17,<br /> TERMINATOR = 18,<br /> TAGINCREMENT = 19,<br /> TAB = 20,<br /> STREAMDELTA = 21,<br /> STREAMTOLERANCE = 22,<br /> STREAMANGLE = 23,<br /> STREAMAREA = 24,<br /> POINT = 25,<br /> KEYPOINT = 26,<br /> PATTERNDELTA = 27,<br /> PATTERNANGLE = 28,<br /> PATTERNSCALE = 29,<br /> PATTERNCELL = 30,<br /> AREAMODE = 31,<br /> AXISANGLE = 32,<br /> CLASS = 33,<br /> CAPMODE = 34,<br /> GRIDMODE = 35,<br /> GRIDRATIO = 36,<br /> FILLMODE = 37,<br /> SCALE = 38,<br /> TERMINATORSCALE = 39,<br /> DIMCOMPAT = 40,<br /> MLINECOMPAT = 41,<br /> AXISORIGIN = 42,<br /> PATTERNTOLERANCE = 43,<br /> LINESTYLENAME = 44,<br /> LINESTYLEPARAMS = 45,<br /> FILLCOLOR = 46,<br /> SNAPOVERRIDE = 47,<br /> DESIGNFILE3D = 48,<br /> DESIGNFILEREADONLY = 49,<br /> DESIGNFILENAME = 50,<br /> MASTERUNITLABEL = 51,<br /> SUBUNITLABEL = 52,<br /> SUBPERMASTER = 53,<br /> GLOBALORIGIN = 54,<br /> NUMSCREENS = 55,<br /> FENCE = 56,<br /> FENCEVIEW = 57,<br /> UORPERSUB = 58,<br /> NEXTGGROUP = 59,<br /> NEXTTEXTNODE = 60,<br /> TEXTSLANT = 61,<br /> CELLLIBFILENAME = 66,<br /> AREAPATTERNDELTA = 67,<br /> AREAPATTERNANGLE = 68,<br /> UORPERMASTER = 69,<br /> GRIDORIENTATION = 70,<br /> GRIDANGLE = 71,<br /> UNITROUNDRATIO = 72,<br /> TEXTSTYLE = 73,<br /> LEVEL_FILTER = 74,<br /> DISPLAYPRIORITY = 75,<br /> TRANSPARENCY = 76,<br /> SCALEDIMVALUES = 77,<br /> SCALEANNOTATIONS = 78,<br /> SCALEMLINEOFFSETS = 79,<br /> FONTNAME = 80,<br /> GRADIENTFILL = 100,<br /> SNAPMODE = 501<br />}<br />可以看到这里包含了Mstn中的各种各样的参数设置类型。

27.ActiveLockChangedEventHandler ActiveLockChangedEvent

ActiveLockChangedEvent是在Mstn中修改各种Active Lock状态时触发的一个事件,我们可以通过Mstn界面底部如下图所示的位置修改Active Lock的状态。

基础平台API介绍 - 图27

其对应的delegate如下所示:
public delegate void ActiveLockChangedEventHandler(AddIn sender, ActiveLockChangedEventArgs args);
其中第二个参数args的类型定义如下所示:
public class ActiveLockChangedEventArgs : EventArgs
{
public ActiveLockChangedEventArgs(LockChangedId id);

  1. public LockChangedId Id { get; }<br /> }<br />我们通过这个参数的成员变量Id可以判断具体是那个Active Lock的状态发生了变化。LockChangeId的定义如下所示:<br />public enum LockChangedId<br /> {<br /> Snap = 1,<br /> Grid = 2,<br /> Unit = 3,<br /> Angle = 5,<br /> Textnode = 6,<br /> Axis = 7,<br /> Scale = 8,<br /> GraphicGroup = 9,<br /> Level = 10,<br /> CellStretch = 11,<br /> ConstructionPlane = 13,<br /> Isometric = 14,<br /> Association = 15,<br /> Depth = 16,<br /> ConstructionPlanePerp = 17,<br /> FenceMode = 18,<br /> IsometricPlane = 19,<br /> UseAnnotationScale = 20,<br /> ACSContext = 21,<br /> ElementTemplateAssociation = 22,<br /> SharedCells = 23<br />}<br />可以看到类型LockChangedId中的枚举值跟下图所示的Locks对话框中的各个开关是一一对应的。

基础平台API介绍 - 图28

28.LevelFilterChangedEventHandler LevelFilterChangedEvent

LevelFilterChangedEvent是在Level Filter发生变化时被触发的一个事件。其对应的delegate如下所示:
public delegate void LevelFilterChangedEventHandler(AddIn senderIn, LevelFilterChangedEventArgs eventArgsIn);
其中第二个参数的类型定义如下所示:
public class LevelFilterChangedEventArgs : EventArgs
{
public LevelFilterChangedEventArgs(string name, uint filterId, FilterChangeType changeType);
public uint FilterId { get; }
public FilterChangeType ChangeType { get; }
public string FilterName { get; }
public enum FilterChangeType
{
Change = 1,
Active = 2,
Create = 3,
Delete = 4,
ChangeName = 5,
ChangeDescription = 6,
ChangeType = 7,
ChangePersistent = 8,
ChangeFlag = 9,
ChangeParent = 10,
ChangeExpression = 11,
TableImport = 12,
TableUndo = 13,
TableRedo = 14
}
}
我们通过这个参数的ChangeType和FilterName成员属性可以获取到改变的类型以及Level Filter的名字。

29.LevelMaskPostChangeEventHandler LevelMaskPostChangeEvent

LevelMaskPostChangeEvent是在我们修改层掩码时会被触发的一个事件,我们可以在下图所示的对话框中修改层掩码。

基础平台API介绍 - 图29
此事件对应的delegate如下所示:
public delegate void LevelMaskPostChangeEventHandler(AddIn senderIn, LevelMaskPostChangeEventArgs eventArgsIn);
其中第二个参数类型定义如下所示:
public class LevelMaskPostChangeEventArgs : EventArgs
{
public LevelMaskPostChangeEventArgs(DgnModelRef* modelRefIn, int viewNumber);

  1. public int ViewNumber { get; }<br /> public DgnPlatformNET.DgnModelRef DgnModelRef { get; }<br /> }<br />我们通过其成员变量ViewNumber可以获取是哪个视图的层掩码发生了变化。

30.ColorMapChangedEventHandler ColorMapChangedEvent

ColorMapChangedEvent是在颜色表发生变化时触发的一个事件。其对应的delegate如下所示:
public delegate void ColorMapChangedEventHandler(AddIn senderIn, ColorMapChangedEventArgs eventArgsIn);

31.CellLibraryChangedEventHandler CellLibraryChangedEvent

CellLibraryChangedEvent是在连接到当前文件的单元库发生变化时会被触发的一个事件。此事件对应的delegate如下所示:
public delegate void CellLibraryChangedEventHandler(AddIn sender, CellLibraryChangedEventArgs e);
其中第二个参数的类型定义如下所示:
public class CellLibraryChangedEventArgs : EventArgs
{
public CellLibraryChangedEventArgs(string path, ChangeType type);
public ChangeType Type { get; set; }
public string LibraryPath { get; set; }
public enum ChangeType
{
Errpr = -1,
PreAttach = 0,
PostAttach = 1,
PreDetach = 2,
PostDetach = 3,
PreCreate = 4,
PostCreate = 5
}
}

我们通过这个参数的Type成员属性可以判断当前事件是在单元库发生什么变化时触发的。Attach表示是在连接单元库时触发了当前事件,Detach是在卸载单元库时触发了当前事件,Create表示是在创建新的单元库时触发了当前事件。而枚举值的前缀“Pre”和“Post”分别表示当前事件是在动作完成之前和之后触发的。

32.SelectedViewChangedEventHandler SelectedViewChangedEvent

SelectedViewChangedEvent是在当前激活视图发生变化时触发的一个事件。此事件对应的delegate如下所示:
public delegate void SelectedViewChangedEventHandler(AddIn sender, SelectedViewChangedEventArgs eventArgs);
其中第二个参数的类型定义如下所示:
public class SelectedViewChangedEventArgs : EventArgs
{
public int OldViewIndex;
public int NewViewIndex;
public bool FromButtonEvent;
public SelectedViewChangedEventArgs(int oldViewIndex, int newViewIndex, bool fromButtonEvent);
}
我们通过成员变量OldViewIndex和NewViewIndex可以获取变化之前激活视图的索引和新的激活视图的索引。成员变量FromButtonEvent表示Selected View变化是否是因为在视图中按下鼠标键引起的。

管理器API

Mstn SDK中有很多管理器(Manager)API,通过这些接口我们可以直接调用到Mstn中的一些功能。例如通过ACSManager我们可以操作ACS(Auxiliary Coordinate System),通过ConfigurationManager可以访问Mstn中的配置变量等等。利用这些工具我们通过这些管理器类我们可以是我们的应用程序与Mstn自身的功能结合的更加紧密。接下来我们就看一下Mstn SDK中都有哪些管理器接口。

ACSManager

在Mstn中我们可以通过下图所示的按钮打开ACS对话框,在这个对话框中列出了当前文件中所有的ACS坐标系,我们在这里还可以创建或者删除指定的ACS坐标系。

基础平台API介绍 - 图30

列表中分割线上部显示的是当前激活视图中使用的ACS坐标系的信息,例如上图中显示的是视图1中使用的是名字为“Top”的ACS坐标系。分割线以下列出的是当前文件中存在的ACS坐标系。
在C# Addins开发中我们可以通过ACSManager来操作访问Mstn中的ACS坐标系对象,ACSManager的类型定义如下所示:
#region Assembly Bentley.DgnPlatformNET, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4bf6c96a266e58d4
// C:\Program Files\Bentley\MicroStation CONNECT Edition\MicroStation\Bentley.DgnPlatformNET.dll
#endregion

namespace Bentley.DgnPlatformNET
{
public class ACSManager
{
public ACSManager();
public static AuxiliaryCoordinateSystem CreateACS();
public static StatusInt Delete(string name, DgnModelRef modelRef);
public static AuxiliaryCoordinateSystem GetActive(Viewport vp);
public static AuxiliaryCoordinateSystem GetByName(string name, DgnModelRef modelRef, uint options);
public static StatusInt Save(AuxiliaryCoordinateSystem auxCoordSys, DgnModelRef modelRef, ACSSaveOptions saveOption, ACSEventType eventType);
public static StatusInt SetActive(AuxiliaryCoordinateSystem auxCoordSys, Viewport vp);
public static bool Traverse(ACSTraversalHandler handler, DgnModelRef modelRef);
}
}
可以看到这个类型在Bentley.DgnPlatformNET.dll这个程序集中,我们可以通过静态成员函数Traverse可以遍历当前文件中保存的所有ACS坐标系。Traverse函数的第一个参数ACSTraversalHandler是一个abstract class,我们需要继承并重写这个class。如下所示:
class MyACSTraversalHandler : ACSTraversalHandler
{
public override int GetACSTraversalOptions()
{
return 0;
}

  1. public override bool HandleACSTraversal(string name, string description, ACSType acsType, ACSFlags flags)<br /> {<br /> MessageCenter.Instance.ShowInfoMessage(name + "___" + description + "___" + acsType.ToString() + "___" + flags.ToString(), "", false);<br /> return false;<br /> }<br /> }<br />其中重写的HandleACSTraversal成员函数是我们接受ACS坐标系的函数,当我们通过重写的MyACSTraversalHandler对象实例调用ACSManager.Traverse函数时,后台会迭代当前文件中的ACS坐标系,并将每个ACS坐标系的信息传递给HandleACSTraversal这个成员函数。这个函数是一个bool类型的值,当我们返回false的时候,后台会继续迭代下一个ACS坐标系,如果返回true的话,就会停止退出当前循环。<br />我们还可以通过ACSManager的静态成员函数Create创建一个新的ACS坐标系。这个函数返回的是一个AuxiliaryCoordinateSystem类型的对象实例,此类型的定义如下所示:<br />#region Assembly Bentley.DgnPlatformNET, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4bf6c96a266e58d4<br />// C:\Program Files\Bentley\MicroStation CONNECT Edition\MicroStation\Bentley.DgnPlatformNET.dll<br />#endregion<br />using System;<br />using System.Runtime.ExceptionServices;<br />using Bentley.GeometryNET;<br />namespace Bentley.DgnPlatformNET<br />{<br /> public class AuxiliaryCoordinateSystem : IDisposable<br /> {<br /> ~AuxiliaryCoordinateSystem();
  2. public ACSType Type { get; set; }<br /> public double Scale { get; set; }<br /> public bool IsReadOnly { get; }<br /> public string TypeName { get; }
  3. public AuxiliaryCoordinateSystem Clone();<br /> public StatusInt DeleteFromFile(DgnModelRef modelRef);<br /> public sealed override void Dispose();<br /> public bool Equals(AuxiliaryCoordinateSystem other);<br /> public string GetDescription();<br /> public ACSFlags GetFlags();<br /> public string GetName();<br /> public DPoint3d GetOrigin(out DPoint3d pOrigin);<br /> public DMatrix3d GetRotation(out DMatrix3d pRot);<br /> public PointFromStringResult PointFromString(string pattern, bool relative, DPoint3d lastPoint, DgnModelRef modelRef);<br /> public PointFromStringResult PointFromString(string pattern, bool relative, DgnModelRef modelRef);<br /> public StatusInt SaveToFile(DgnModelRef modelRef, ACSSaveOptions option);<br /> public StatusInt SetDescription(string descr);<br /> public StatusInt SetFlags(ACSFlags flags);<br /> public StatusInt SetName(string name);<br /> public StatusInt SetOrigin(DPoint3d pOrigin);<br /> public StatusInt SetRotation(DMatrix3d pRot);<br /> public StringFromPointResult StringFromPoint(DPoint3d inPoint, DPoint3d deltaOrigin, DgnModelRef modelRef, DistanceFormatter distanceFormatter, DirectionFormatter directionFormatter);<br /> public StringFromPointResult StringFromPoint(DPoint3d inPoint, DgnModelRef modelRef, DistanceFormatter distanceFormatter, DirectionFormatter directionFormatter);<br /> [HandleProcessCorruptedStateExceptions]<br /> protected virtual void Dispose(bool A_0);<br /> }<br />}<br />可以看到AuxiliaryCoordinateSystem类型有各种各样的获取或者设置ACS坐标系属性的成员函数,我们通过这些成员函数可以可以设置新创建的ACS坐标系的各种属性,例如原点(SetOrigin)、旋转矩阵(SetRotation)、名字(SetName)等。设置好了这些属性后,我们可以通过ACSManagerSave函数将新创建的ACS坐标系保存到当前文件中。通过ACSManager下的SetActive函数和GetActive函数可以分别将新创建的AuxiliaryCoordinateSystem对象实例设置为指定视图的激活ACS坐标系或者获取指定视图的AuxiliaryCoordinateSystem对象实例。GetByName成员函数则可以通过名字获取到当前文件中的ACS坐标系,Delete成员函数可以删除指定的ACS坐标系。

ConfigurationManager

ConfigurationManager提供的方法允许用户和应用程序在运行时自定义程序的行为。配置是特定于主机的,应用程序中可能有多个主机处于活动状态。例如,应用程序中的每个线程都可以有自己的主机。ConfigurationManager的方法提供对当前主机的配置数据库的访问。因此,在不同的线程中调用ConfigurationManager.GetVariable(“A”)可能会产生不同的值或返回状态。ConfigurationManager的类型定义如下所示:
#region Assembly Bentley.DgnPlatformNET, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4bf6c96a266e58d4
// C:\Program Files\Bentley\MicroStation CONNECT Edition\MicroStation\Bentley.DgnPlatformNET.dll
#endregion
namespace Bentley.DgnPlatformNET
{
public static class ConfigurationManager
{
public static BentleyStatus DefineVariable(string configurationVariableName, string value, ConfigurationVariableLevel level);
public static BentleyStatus DefineVariable(string configurationVariableName, string value);
public static string GetLocalTemporaryDirectory(string subDirectoryName);
public static string GetLocalTemporaryDirectoryBaseName();
public static string GetNameForTemporaryFile(string partialPathName, string prefix);
public static string GetVariable(string configurationVariableName);
public static string GetVariable(string configurationVariableName, ConfigurationVariableLevel level);
public static bool IsVariableDefined(string configurationVariableName);
public static bool IsVariableDefinedAndFalse(string configurationVariableName);
public static bool IsVariableDefinedAndTrue(string configurationVariableName);
public static void SetAdmin(MacroConfigurationAdmin Admin);
public static BentleyStatus UndefineVariable(string configurationVariableName);
public static BentleyStatus WriteActiveConfigurationSummary(string CfgFilePath);
}
}
可以看到这个类型也是在Bentley.DgnPlatformNET.dll中,ConfigurationManager. DefineVariable函数可以定义一个配置变量,这个函数有两个重载。两个重载函数的参数类型不同之处在于“ConfigurationVariableLevel level”参数。Mstn中配置变量分不同的级别,通过这个参数我们可以指定我们的配置变量属于哪一级别。如果我们定义的变量已经存在的话,那么变量就会重新定义成新的值。GetLocalTemporaryDirectoryBaseName函数返回可用于存储临时文件的本地目录的根目录。GetLocalTemporaryDirectory函数返回可用于存储临时文件的本地目录。此目录可以是GetLocalTemporaryDirectoryBaseName的子目录。如果参数subDirectoryName传递空字符串的话,其返回结果和GetLocalTemporaryDirectoryBaseName相同,如果非空的话,则此子目录会被创建。GetNameForTemporaryFile函数可以用于创建一个名字唯一的临时文件。GetVariable函数可以通过配置变量的名字获取配置变量的值,与DefineVariable函数类型,此函数有两个重载类型,通过“ConfigurationVariableLevel level”参数可以获取到指定级别的配置变量的值。IsVariableDefined、IsVariableDefinedAndFalse、IsVariableDefinedAndTrue用来判断某个变量是否定义以及其值是否是false或者true值。UndefineVariable函数用来删除某个配置变量的值。WriteActiveConfigurationSummary函数可以将当前所有的配置变量的级别以及值输入到指定文件中,需要注意的是这个文件必须具有写的权限。

FenceManager

FenceManager用来访问当前Mstn中Active Fence,FenceManager的类型定义如下所示:
#region Assembly Bentley.DgnDisplayNET, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9bfed12b64a9b7df
// C:\Program Files\Bentley\MicroStation CONNECT Edition\MicroStation\Bentley.DgnDisplayNet.dll
#endregion
using Bentley.DgnPlatformNET.Elements;
using Bentley.GeometryNET;
namespace Bentley.DgnPlatformNET
{
public class FenceManager
{
public FenceManager();
public static bool UseActiveFence { get; }
public static bool IsVoidMode { get; }
public static bool IsOverlapMode { get; }
public static bool IsClipMode { get; }
public static bool IsDefinedByElem { get; }
public static bool IsDefinedByPoints { get; }
public static FenceStretchFlags ActiveFenceStretchFlags { get; }
public static FenceClipFlags ActiveFenceClipFlags { get; }
public static bool IsFenceActive { get; }
public static StatusInt BuildAgenda(FenceParameters fenceParameters, ElementAgenda elementAgenda, DgnModelRef[] modelRefList, bool modifyOrig, bool allowLocked, bool callAsynch);
public static void ClearFence();
public static StatusInt ClipElement(FenceParameters unnamed000, ElementAgenda inside, ElementAgenda outside, Element element, FenceClipFlags clipFlags);
public static StatusInt DefineByElement(Element element, Viewport
unnamed001);
public static StatusInt DefineByPoints(DPoint3d[] points, Viewport __unnamed001);
public static void DisplayFence(Viewport viewport);
public static void DisplayFence(Viewport viewport, DTransform3d transform, int transparency);
public static Element GetFenceElement();
public static DPoint3d[] GetFencePoints();
public static Viewport GetFenceViewport();
public static StatusInt InitFromActiveFence(FenceParameters fenceParameters, bool overlap, bool doClip, FenceClipMode allowClipFlag);
public static void SetInhibitFenceDisplay(FenceDisplayMode inhibit);
public static StatusInt StretchElement(FenceParameters fenceParameters, Element element, DTransform3d transform, FenceStretchFlags stretchFlags);
public static StatusInt TransformFence(DTransform3d transform);
}
}
可以看到FenceManager在Bentley.DgnDisplayNet.dll这个程序集中,它除了有大部分的静态类型的成员函数以外,还有若干个静态类型的成员属性。用过Mstn中的Move、Copy等操作元素的交互式工具的话,一定对ToolSetting窗口中的“Use Fence”复选框有印象,如下图所示:

基础平台API介绍 - 图31
如果选中这个选项的话,工具操作的元素将不再是通过我们的工具去选择了,而是通过Fence获取要被操作的元素。而且当我们在“Move Element”工具的ToolSetting窗口中选中这个选项,同样其他有类似复选框的工具的ToolSetting窗口中此复选框的状态也会同步。FenceManager下的UseActiveFence静态成员属性就可以获取到此复选框的状态。同样的其他几个静态类型的成员属性也是获取类型的属性的。
利用FenceManager下的DefineByElement我们可以在指定视图中通过第一个参数传递的Element放置一个Fence。DefineByPoints可以通过指定的若干个点放置一个Fence。如果Active Fence是通过Element初始化的来的,我们可以通过GetFenceElement函数获取到这个Element。如果我们仅仅是在程序要想使用Fence的相关功能,不需要在视图中显示Active Fence,我们可以调用SetInhibitFenceDisplay函数。StretchElement函数则类似与下图所示的“Stretch Element”功能,而这个函数只是对第二个参数传递进来的元素进行“Stretch”。

基础平台API介绍 - 图32
StretchElement函数的第一个参数我们可以通过InitFromActiveFence函数去获取。ClipElement 函数可以用来对指定元素通过Active Fence进行剪切,剪切后的元素通过第二个和第三个参数返回给我们。BuildAgenda函数可以用来获取Active Fence中的元素。TransformFence函数可以变换Active Fence。最后通过ClearFence函数可以清除掉Active Fence.

SelectionSetManager

选择集工具是Mstn中非常特殊的一种工具,在Mstn中当我们退出除视图类工具以外的其他工具时都会激活选择集工具,通过选择集工具选中的元素也会被放入到选择集中。而我们在代码中可以通过SelectionSetManager这个类完成对选择集的操作。我们可以访问用户通过选择集工具选中的元素,可以往选择集中添加新的元素,或者移除选择集中指定的元素。SelectionSetManager的类型定义如下所示:
#region Assembly Bentley.DgnDisplayNET, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9bfed12b64a9b7df
// C:\Program Files\Bentley\MicroStation CONNECT Edition\MicroStation\Bentley.DgnDisplayNet.dll
#endregion
using Bentley.DgnPlatformNET.Elements;
namespace Bentley.DgnPlatformNET
{
public class SelectionSetManager
{
public SelectionSetManager();
public static void ActivatePrevious();
public static BentleyStatus AddElement(Element element, DgnModelRef modelRef);
public static BentleyStatus AddElementSet(IElementSet elementSet);
public static StatusInt BuildAgenda(ref ElementAgenda agenda);
public static void EmptyAll();
public static StatusInt GetElement(uint index, ref Element element, ref DgnModelRef modelRef);
public static BentleyStatus InvertElement(Element element, DgnModelRef modelRef);
public static BentleyStatus InvertElementSet(IElementSet elementSet);
public static bool IsActive();
public static BentleyStatus ModifyWithElementSets(IElementSet removeSet, IElementSet addSet);
public static uint NumSelected();
public static BentleyStatus RemoveElement(Element element, DgnModelRef modelRef);
public static BentleyStatus RemoveElementSet(IElementSet elementSet);
public static BentleyStatus ReplaceWithElement(Element element, DgnModelRef modelRef);
public static BentleyStatus ReplaceWithElementSet(IElementSet elementSet);
}
}
可以看到SelectionSetManager在Bentley.DgnDisplayNet.dll这个程序集中,SelectionSetManager下有各种各样的静态类型的成员函数实现了对选择集的操作。ActivatePrevious可以激活当前选择集之前的选中状态,例如我们选中了A、B两个元素之后,我们清空选择集中的元素,或者又通过选择集选中了其他元素,则调用此函数之后会恢复选中A、B两个元素的状态。AddElement函数可以往选择集中添加一个指定元素。AddElementSet函数则可以一次往选择集中添加多个元素,如果需要往选择集中添加多个元素时,一次调用AddElementSet比多次调用AddElement效率会更高一些。因为每次调用AddElement往选择集中添加一个元素时,视图中都话刷新选择集元素高亮显示状态,而AddElementSet则是在往选择集中添加完所有要添加的元素以后才会去刷新一下高亮显示状态。AddElementSet函数需要一个IElementSet的对象实例,IElementSet是一个接口类型,需要我们去实现这个接口。BuildAgenda函数可以获取到选择集中的所有元素。EmptyAll用来清空选择集中的元素。GetElement可以获取到选择集中指定索引处的元素。InvertElement和InvertElementSet可以反转元素在选择集中的状态,如果指定元素在选择集中,则这两个函数就会将元素从选择集中清除掉,如果指定元素不在选择集中,将会将此元素添加到选择集中。IsActive用来判断当前选择集中是否有元素。ModifyWithElementSets用来批量往选择集中添加以及移除指定元素。NumSelected用来获取选择集中有多少元素。RemoveElement和RemoveElementSet用来从选择集中移除指定元素。ReplaceWithElement和ReplaceWithElementSet的效果是清空选择集,然后将传递的元素添加到选择集中。

约束与参数化API

Mstn CE版本新增加了参数化建模的功能,通过参数化建模构造的模型不再像传统模型那样一成不变了,参数化模型能够根据输入的变化(例如调整参数的值)做出响应。SDK中也同样给我们提供了参数化建模的编程接口,通过这些编程接口,我们可以通过代码生成参数化模型。

参数化变量

我们在创建参数化模型时,通常会先规划一下我们的参数化模型需要哪些参数去控制,前期规划好的话,后期可以为我们省去很多修改模型带来的麻烦。SDK中参数化建模的编程接口也同样提供了创建参数的接口,下面的代码演示了如何在当前Model中创建参数化变量:
DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
EditParameterDefinitions defs = EditParameterDefinitions.GetForModel(dgnModel);
string varName = “var”;
double value = 15000.0;
ParameterDefinition v = defs.FindByLabel(varName);
if (null != v)
{
return;
}
defs.Add(varName, ParameterType.Distance, value, false);
上面的代码会在当前Model中创建一个名字为“var”,类型为“ParameterType.Distance”的参数化变量,如下图所示:

基础平台API介绍 - 图33
上边的代码首先通过EditParameterDefinitions下的FindByLabel成员函数在当前Model中查找是否已经存在名字为“var”的参数化变量,如果当前Model中已经存在就返回不在创建。否则的话就调用EditParameterDefinitions的Add成员函数去创建新的参数化变量。这个函数有好几个重载形式,但无论什么样的形式都需要一个变量名以及变量值作为参数的,而参数的类型的话,或者是通过ParameterType类型的参数来指定,后者就是通过变量值这个参数的类型来指定的。而对于Model中已经存在的变量我们想要修改的话,则需要调用前边提到的EditParameterDefinitions下的FindByLabel成员函数去获取到变量的ParameterDefinition对象实例,ParameterDefinition的类型定义如下所示:
#region Assembly Bentley.DgnPlatformNET, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4bf6c96a266e58d4
// C:\Program Files\Bentley\MicroStation CONNECT Edition\MicroStation\Bentley.DgnPlatformNET.dll
#endregion
namespace Bentley.DgnPlatformNET
{
public class ParameterDefinition
{
public ParameterDefinition();

  1. public ParameterType Type { get; set; }<br /> public bool IsCalculated { get; set; }<br /> public bool IsDomainParameter { get; }<br /> public bool IsDefinitionScope { get; set; }<br /> public bool IsHidden { get; set; }<br /> public string DisplayLabel { get; set; }<br /> public string AccessString { get; set; }<br /> public ParameterDefinition Clone();<br /> }<br />}<br />可以看到ParameterDefinition下有各种各样的成员属性,这些属性是可读写的,当我们修改了某些属性后,EditParameterDefinitions下的Replace成员函数就可一替换掉修改之前的参数化变量。如果要删除某个参数化变量的话需要调用EditParameterDefinitionsRemove成员函数,此函数需要的参数accessString可以通过ParameterDefinitionAccessString成员属性获取。<br />参数化变量的值除了可以设置为具体的某个常量值以外,还可以设置为某个表达式的值,则个表达式可以引用其他已经存在参数化变量,非常灵活。下面的代码就演示了如何创建这样的参数化变量:<br />void CreateVariable(EditParameterDefinitions defs, string varName, double value, ParameterType type)<br /> {<br /> ParameterDefinition v = defs.FindByLabel(varName);<br /> if (null != v)<br /> {<br /> return;<br /> }<br /> defs.Add(varName, type, value, false);<br /> return;<br /> }<br /> void SetExpressionForVariable(ParameterDefinition v, string expression, EditParameterDefinitions defs)<br /> {<br /> if (null == v)<br /> return;<br /> ParameterExpressionParser parser = new ParameterExpressionParser();<br /> ParseParameterExpressionResult result = parser.Parse(expression, v, defs);<br /> if (ParameterExpressionStatus.Success == result.Status)<br /> defs.SetExpressionForParameter(v.AccessString, result.ParsedExpression);<br /> return;<br /> }<br /> void ExampleAddExpressions()<br /> {<br /> DgnModel dgnModel = Session.Instance.GetActiveDgnModel();<br /> if (null == dgnModel)<br /> return;<br /> EditParameterDefinitions defs = EditParameterDefinitions.GetForModel(dgnModel);<br /> string labelR = "Radius1";<br /> string labelX = "X";<br /> string labelY = "Y";<br /> double r = 10.0;<br /> double x = 10000.0;<br /> double y = 15000.0;<br /> double z = 20000.0;<br /> string exp1 = "10 * sqrt (16)";<br /> string exp2 = "2 * X";<br /> ParameterDefinition paramDefR, paramDefX, paramDefY;<br /> if (null == (paramDefR = defs.FindByLabel(labelR)))<br /> {<br /> CreateVariable(defs, labelR, r, ParameterType.Distance);<br /> }
  2. if (null == (paramDefX = defs.FindByLabel(labelX)))<br /> {<br /> CreateVariable(defs, labelX, x, ParameterType.Scalar);<br /> }<br /> if (null == (paramDefY = defs.FindByLabel(labelY)))<br /> {<br /> CreateVariable(defs, labelY, y, ParameterType.Scalar);<br /> }<br /> SetExpressionForVariable(paramDefR, exp1, defs);<br /> SetExpressionForVariable(paramDefY, exp2, defs);<br /> }<br />这里我们创建了名字为“Radius1”、“X”、“Y”的三个变量,最后分别将“Radius1”的值设置为常量表达式“10*sqrt(16)”,将“Y”的值设置为表达式“2*X”,即变量“X”的2倍。这里我们需要注意的两点是,首先表达式中引用其他参数化变量时,一定先在对应的Model中创建这个变量,其次我们还要确保表达式的有效性,上面的代码中演示了如何检测表达式是否有效。通过调用ParameterExpressionParser下的Parse成员函数来检测。<br />我们在创建好了参数化变量之后通常会定义一套标准的参数,这套标准的参数可能对应于参数化模型代表的某个标准构件,在Mstn中我们将这套标准的参数称为“Variations”。下面的代码演示了如果通过编程创建Variations:<br />void ExampleAddVariations()<br /> {<br /> DgnModel dgnModel = Session.Instance.GetActiveDgnModel();<br /> var hdlr = DgnComponentDefinitionHandler.GetForModel(dgnModel).DefinitionModelHandler;<br /> if (null == hdlr)<br /> return;<br /> var variations = hdlr.ParameterSets;<br /> ParameterSet set1;<br /> if (null == (set1 = variations.FirstOrDefault(x => x.Name == "set1")))<br /> set1 = hdlr.CreateParameterSet("set1", "my set", null);<br /> EditParameterDefinitions defs = EditParameterDefinitions.GetForModel(dgnModel);<br /> ParameterDefinition v = defs.FindByLabel("X");<br /> if (null == v)<br /> return;<br /> IDgnECInstance props = set1.Properties as IDgnECInstance;<br /> IECPropertyValue pv = props.FindPropertyValue(v.AccessString, false, false, false, true/*includeAdhoc*/);<br /> pv.NativeValue = 30000.0;<br /> props.WriteChanges();<br /> return;<br /> }<br />上面的代码中我们创建了一个名字为“set1”的Variations,其参数化变量“X”的值我们定义为了30000.0。我们首先通过DgnComponentDefinitionModelHandler下的ParameterSets成员属性获取到了当前Model下的Variations集合,然后判断当前是否已经存在名字为“set1“的Variations,没有的话就调用DgnComponentDefinitionModelHandler的成员函数CreateParameterSet去创建。

DgnTool工具类

MicroStation中超过一半的功能都是以交互式工具的形式而存在的,可见在Mstn的二次开发中交互式工具的开发是多么的重要。我们的SDK封装了DgnTool、DgnPrimitiveTool、DgnElementSetTool等类(Class)供编程人员派生来实现自己的交互式工具。我们只要根据应用场景选择合适的类派生一个我们自己的工具类,根据交互式工具的不同功能,重写一些基类的成员函数很容易就能实现交互式工具的各种需求。
在这三个工具类中DgnTool是位于最顶端的一个类,DgnPrimitiveTool派生于DgnTool,而DgnElementSetTool派生于DgnPrimitiveTool。通过VS的对象浏览功能,我们可以看到DgnTool的定义如下所示:

namespace Bentley.DgnPlatformNET
{
public abstract class DgnTool : IDisposable
{
protected DgnTool();

    ~DgnTool();<br />     …<br />        public static DgnPrimitiveTool GetActivePrimitiveTool();<br />        …<br />     …<br />     …<br />        protected internal virtual void DecorateScreen(Viewport vp);<br />        protected internal abstract void ExitTool();<br />        protected internal virtual string GetToolName();<br />        protected internal virtual bool On3DInputEvent(Dgn3DInputEvent ev);<br />        protected internal virtual void OnCleanup();<br />        protected internal abstract bool OnDataButton(DgnButtonEvent ev);<br />        protected internal virtual bool OnDataButtonUp(DgnButtonEvent ev);<br />        protected internal virtual bool OnFlick(DgnFlickEvent ev);<br />        protected internal virtual bool OnGesture(DgnGestureEvent ev);<br />        protected internal virtual bool OnGestureNotify(IndexedViewport A_0, long A_1);<br />        protected internal virtual bool OnInstall();<br />        protected internal virtual bool OnModelEndDrag(DgnButtonEvent ev);<br />        protected internal virtual bool OnModelMotion(DgnButtonEvent ev);<br />        protected internal virtual bool OnModelMotionStopped(DgnButtonEvent ev);<br />        protected internal virtual bool OnModelNoMotion(DgnButtonEvent ev);<br />        protected internal virtual bool OnModelStartDrag(DgnButtonEvent ev);<br />        protected internal virtual bool OnModifierKeyTransition(bool wentDown, int key);<br />        protected internal virtual bool OnMouseWheel(DgnMouseWheelEvent ev);<br />        protected internal virtual void OnPostInstall();<br />        …<br />        protected internal virtual void OnReinitialize();<br />        protected internal abstract bool OnResetButton(DgnButtonEvent ev);<br />        protected internal virtual bool OnResetButtonUp(DgnButtonEvent ev);<br />        …<br />    }<br />}

我们可以看到它定义了交互式工具使用过程中大部分的鼠标和键盘相关的事件处理函数。这些事件成员函数都是virtual类型,这样我们从DgnTool直接或间接派生了我们自己的类,重写了某一事件对应的虚函数时,如果对应事件发生,系统后台会通过保存的DgnTool的实例引用调用我们重写的虚函数。例如如果我们重写了OnDataButton函数的话,当我们在视图中单击鼠标左键时,重写的这个OnDataButton函数就会被调用。除了单击鼠标左键事件以外,还有单击鼠标右键、Ctrl/Shift/Alt键按下等事件,甚至当我们的鼠标在视图中移动以及停止移动时都会触发一个事件,这些事件都对应有相关的事件处理函数。我们的交互式工具就是在这些事件处理函数中根据用户输入的信息,而完成各种复杂的交互功能。DgnTool中常用的事件相关的成员虚函数如下表所示:

OnDataButton 视图中单击鼠标左键触发
OnResetButton 视图中单击鼠标右键触发
OnModelMotion 鼠标在视图中移动时触发
OnModelNoMotion 鼠标在视图中停留一定时间后触发
OnModelMotionStopped 鼠标在视图中停止移动时触发
OnModelStartDrag 视图中开始拖拽时触发
OnModelEndDrag 视图中停止拖拽时触发
OnModifierKeyTransition 按下Control、Shift或Alt时触发

DgnPrimitiveTool

DgnPrimitiveTool提供了最基本的放置元素的逻辑。如果我们要实现的交互式工具在使用过程中,不需要用户选择某些元素来完成操作的话,最好是从这个类派生我们自己的类来实现我们的交互式工具,如下所示:

class MyDgnPrimitiveTool : DgnPrimitiveTool
{
public MyDgnPrimitiveTool():base(0,0)
{

    }<br />        protected override bool OnDataButton(DgnButtonEvent ev)<br />        {<br />            ...<br />            return false;<br />        }

    protected override bool OnResetButton(DgnButtonEvent ev)<br />        {<br />            ...<br />            return false;<br />        }

    protected override void OnRestartTool()<br />        {<br />            ...<br />        }<br />}

在MyDgnPrimitiveTool的中我们定义了四个必不可少的成员函数,利用VS的对象浏览功能我们转到DgnPrimitiveTool的定义可以看到,在其定义中没有无参构造函数,只有一个如下所示的构造函数:

public DgnPrimitiveTool(int toolName, int toolPrompt);

所以在我们的派生类中必须定义一个构造函数并调用DgnPrimitiveTool这个唯一的构造函数。MyDgnPrimitiveTool中的另外三个成员函数则是从基类DgnPrimitiveTool以及DgnPrimitiveTool的基类DgnTool中继承来的“abstract “类型函数,我们必须要重写这些函数才能实例化我们的工具类。接下来我们看一下要如何启动我们的工具类,使之成为Mstn的当前激活工具。我们需要通过new运算符构造一个工具类的对象实例,并通过此实例调用从基类DgnTool中继承来的InstallTool函数来启动,如下所示:

MyDgnPrimitiveTool myTool = new MyDgnPrimitiveTool();
myTool.InstallTool();

当我们调用InstallTool函数以后,后台会通过我们的工具类实例调用一系列的成员虚函数来完成初始化的工作。在我们的工具真正激活之前,后台会调用到原型如下所示的OnInstall函数:

protected internal virtual bool OnInstall();

此函数的返回类型为bool,只有当此函数返回true时,我们的工具才能激活成为当前的工具,后台才会继续往下执行调用后续我们工具类的其他成员虚函数。如果返回false,则我们的工具将不会激活,后续的其他成员虚函数当然也不会再被调用到。这就给了我们一个机会去判断只有当满足一定条件时我们的工具才能使用,例如如果我们要编写一个处理三维实体的工具,就可以在此函数中判断如果当前模型是二维的话就返回false,如下所示:

protected override bool OnInstall()
{
if (!Session.Instance.GetActiveDgnModelRef().Is3d)
return false;
return true;
}

OnInstall函数返回true以后,我们的工具就激活成为当前工具了,紧接着后台就会调用OnPostInstall函数。OnPostInstall函数被调用时,我们的工具已经是当前工具了,我们可以在此函数中做一些初始化的工作了。例如如果工具需要用户手动输入一些额外数据的话,我们就可以在此函数中将界面显示到ToolSettings窗口中。ToolSettings窗口给Mstn所有的交互式工具提供了一个公共的容器,交互式工具如果需要显示额外的界面时都会将界面显示到ToolSettings窗口容器中。而当工具退出时,又会将其从ToolSettings中移除。OnPostInstall函数返回后,后台陆续执行一些其他操作以后,控制权就返回到主界面了。此时我们的工具就做好了准备接受用户在视图中各种操作产生的消息了,当用户在视图中点击鼠标左键时,会立刻回调我们重写的OnDataButton函数。当用户在视图中点击鼠标右键时会立刻回调我们重写的OnResetButton函数。如果鼠标在视图中移动时想临时绘制出鼠标在当前位置按下左键后的效果,则需要另外重写OnDynamicFrame函数,这个函数是鼠标在视图中晃动时,会被后台不停且高频率地调用。不过需要注意的是,只有在调用了BeginDynamics函数以后,OnDynamicFrame函数才会被回调,而EndDynamics函数的调用则会停止OnDynamicFrame的回调。如下代码演示了如何在OnDynamicFrame函数中动态绘制一条从世界坐标系原点到鼠标当前位置的线段:

protected override void OnDynamicFrame(DgnButtonEvent ev)
{
DSegment3d segment = new DSegment3d(DPoint3d.Zero, ev.Point);
LineElement lineEle = new LineElement(Session.Instance.GetActiveDgnModel(), null, segment);
RedrawElems redraw = new RedrawElems(); redraw.SetDynamicsViewsFromActiveViewSet(Session.GetActiveViewport());
redraw.DrawMode = DgnDrawMode.TempDraw;
redraw.DrawPurpose = DrawPurpose.Dynamics;
redraw.DoRedraw(lineEle);
}

DgnPrimitiveTool中还有一个很有用的事件回调函数OnUndoPreviousStep函数,此函数是在用户按下“Ctrl+Z“键撤销时被回调的。类似与OnDynamicFrame函数,OnUndoPreviousStep函数的回调也需要在调用EnableUndoPreviousStep函数启动后才有效。这里还需要注意的一点时,EnableUndoPreviousStep函数只有在当前工具类真正激活后调用才会有效,如果你在OnInstall函数中调用的话是无效的。DgnPrimitiveTool的OnReinitialize函数是用来重新初始化当前工具的,DgnPrimitiveTool中OnReinitialize函数的实现是直接调用了OnRestartTool,所以也可以认为是用来重启当前工具的。而OnRestartTool函数是一个纯虚函数,如何初始化我们的工具就由我们自己来决定了。最简单的方式就是直接在OnRestartTool函数中重新生成一个工具类的实例,调用新实例的InstallTool启动当前工具的一个新实例即可。
最后如何退出我们的工具类呢?MicroStation中当前只能有一个激活工具,如果启动另外一个工具则会自动强制退出先前的工具,所以一种方式是我们启动新的工具来结束当前工具。如果我们想退出当前工具启动MicroStation的默认工具的话则可以直接调用DgnPrimitiveTool中的ExitTool函数。不管是哪种方式退出当前工具,工具退出前都会调用OnCleanup函数。在OnCleanup函数中我们可以清除一些工具类中动态申请的资源,而如果您在前文中介绍的OnPostInstall函数中往ToolSettings窗口容器中附加了用户界面的话,则需要在这里将其卸载掉。

DgnElementSetTool

DgnPrimitiveTool只能实现放置元素的功能,如果我们的交互式工具需要用户选中某些元素才能完成目标操作的话则需要借助于DgnElementSetTool来实现我们的工具类。DgnElementSetTool在DgnPrimitiveTool的基础上封装了拾取元素的功能,此外还封装了元素修改的逻辑。由于C#的接口都是在C/C++接口的基础之上通过C++/CLI封装而来的,所以本节我们详细介绍C/C++接口中DgnElementSetTool的工作原理,C#中DgnElementSetTool的用法与C/C++基本一致。
DgnElementSetTool的基类除了DgnPrimitiveTool以外还有IRedrawOperation和ModifyOp(C#中是IModifyElement接口,实际上ModifyOp也是从C/C++接口中的IModifyElement派生下来的)这两个基类,从DgnPrimitiveTool继承了视图及鼠标键盘等交互事件的响应功能,从IRedrawOperation继承实现了元素动态重绘的功能,从ModifyOp继承实现了元素修改逻辑的功能,而DgnElementSetTool自身又添加了元素选取(包括点选、划选框选、选择集以及围栅)的功能。我们首先从工具启动后DgnElementSetTool的成员函数调用顺序看一下DgnElementSetTool的各个成员函数的调用执行流程。
当我们实现了一个从DgnElementSetTool派生下来的类以后,与DgnPrimitiveTool一样,我们动态创建一个类的实例化对象,调用基类的成员函数InstallTool来启动我们的工具类。我们在介绍DgnPrimitiveTool的时候InstallTool后台调用的函数只提到了_OnInstall和_OnPostInstall函数,实际上InstallTool只是调用了_InstallToolImplementation,_InstallToolImplementation进而调用了_OnInstall和_OnPostInstall函数,这一点我们从Mstn SDK的C/C++头文件…、include\DgnView\DgnTool.h中就能看到。DgnElementSetTool重写了这三个函数,我们先看一下重写的_InstallToolImplementation函数。这个函数里边会调用_SetElemSource设置DgnElementSetTool:: m_elemSource的值,这个值是调用_GetPreferredElemSource获得的。_GetPreferredElemSource通过调用_AllowFence、_AllowSelection以及当前围栅、选择集的激活状态判断返回什么值。如果_AllowFence返回的是USES_FENCE_Required,表明必须通过围栅获取元素,则_GetPreferredElemSource返回SOURCE_Fence,如果_AllowFence返回的是USES_FENCE_Check,表明可以但不是必须要通过围栅选择元素,这个时候再查看当前是否有围栅激活。如果有的话也是返回SOURCE_Fence,否则就继续往后判断。接下来就是通过_AllowSelection的返回值判断是否支持选择集获取元素,流程跟围栅的判断流程类似。最后如果围栅和选择集都不支持的话就返回SOURCE_Pick。_GetPreferredElemSource的伪代码如下所示:

DgnElementSetTool::ElemSource DgnElementSetTool::_GetPreferredElemSource ()
{
switch (_AllowFence ())
{
case USES_FENCE_Required:
return SOURCE_Fence;

    case USES_FENCE_Check:<br />            if (_UseActiveFence () && FenceManager::GetManager().IsFenceActive ())<br />                return SOURCE_Fence;<br />            break;<br />        }

switch (_AllowSelection ())<br />        {<br />        case USES_SS_Required:<br />            return SOURCE_SelectionSet;

    case USES_SS_Check:<br />            if (SelectionSetManager::GetManager().IsActive ())<br />                return SOURCE_SelectionSet;<br />            break;

    default:<br />            SelectionSetManager::GetManager().EmptyAll ();<br />            break;<br />        }

return SOURCE_Pick;<br />}

设置好DgnElementSetTool:: m_elemSource的值后,会调用基类的_InstallToolImplementation函数,即DgnPrimitiveTool:: _InstallToolImplementation,这个函数最终调用了我们先前介绍的_OnInstall和_OnPostInstall函数。而DgnElementSetTool重写了这两个函数,所以实际上调用了DgnElementSetTool:: _OnInstall和DgnElementSetTool:: _OnPostInstall。我们先介绍一下DgnElementSetTool:: _OnInstall里边做了哪些操作。这个函数里边通过调用_GetElemSource获取DgnElementSetTool:: m_elemSource的值,判断这个值如果是SOURCE_Fence,但是当前没有围栅激活的话,就返回false,工具就无法激活。同样的如果是SOURCE_SelectionSet,而当前没有选择集激活的话也是返回false。如果通过这两步的话就返回true,工具就会被激活真正成为当前的工具,继而调用DgnElementSetTool:: _OnPostInstall。主要的调用顺序如下所示:

DgnTool ::InstallTool
DgnElementSetTool:: _InstallToolImplementation
DgnElementSetTool:: _SetElemSource
DgnElementSetTool:: _GetPreferredElemSource
DgnElementSetTool:: _AllowFence
DgnElementSetTool:: _AllowSelection
DgnPrimitiveTool:: _InstallToolImplementation
DgnElementSetTool:: _OnInstall
DgnElementSetTool:: _OnPostInstall

接下来我们看一下DgnElementSetTool:: _OnPostInstall函数。函数里边首先判断如果_GetElemSource返回的结果是SOURCE_Pick的话就调用_BeginPickElements函数。_BeginPickElements会设置点选元素时搜寻哪些Model,以及设置光标为点选元素状态。如果_GetElemSource返回的是SOURCE_SelectionSet的话,接下来会根据_NeedPointForSelection返回的结果判断是否需要用户输入额外的确认点才开始处理选择集元素。如果我们重写了_NeedPointForSelection并且返回false(DgnElementSetTool:: _NeedPointForSelection返回true),则相继调用_BuildAgenda、_ProcessAgenda、_OnModifyComplete对选择集中的元素进行处理。如果返回true的话,则继续往下执行,调用_NeedPointForDynamics判断是否需要用户输入额外的确认点来启动动态绘制。如果重写了_NeedPointForDynamics并且返回false(DgnElementSetTool:: _NeedPointForDynamics返回true),就会调用_BeginDynamics启动动态绘制。调用_BeginDynamics之前会调用_GetElemSource判断当前是否是通过选择集选择的元素(返回SOURCE_Pick),如果是会调用_BuildAgenda来获取选择集中的元素。_OnPostInstall的伪代码如下所示:

void DgnElementSetTool::_OnPostInstall ()
{

if (SOURCE_Pick == _GetElemSource ())
{
_BeginPickElements ();
}
else if (SOURCE_SelectionSet == _GetElemSource ())
{
if (!_NeedPointForSelection ())
{

_BuildAgenda (ev);

        _ProcessAgenda (ev)<br />                _OnModifyComplete (ev);

        return;<br />            }<br />        else<br />            {<br />…<br />        }<br />    if (!_NeedPointForDynamics ())<br />        {<br />        if (SOURCE_Pick != _GetElemSource ())<br />            {<br />    …<br />            _BuildAgenda (ev);<br />            }

    _BeginDynamics ();<br />        }<br />}

DgnElementSetTool:: OnPostInstall函数里边有两个函数我们需要更深入地研究一下, BuildAgenda和 ProcessAgenda, ProcessAgenda 我们放到后边介绍OnDataButton函数的时候再介绍,我们先看一下_BuildAgenda。DgnElementSetTool定义了一个ElementAgenda的私有成员变量m_agenda,无论是围栅、选择集还是点选的元素,使用DgnElementSetTool提供的拾取元素的接口最终获取到的元素都会放到这个变量里边,由于是私有成员变量,所以DgnElementSetTool的派生类里边只能通过GetElementAgenda函数访问这个成员变量。 BuildAgenda根据_GetElemSource返回的结果判断是通过围栅还是选择集来填充m_agenda,填充后会继续调用_ModifyAgendaEntries对m_agenda中的元素进行修改筛选。_ModifyAgendaEntries会调用_FilterAgendaEntries,如果重写了_FilterAgendaEntries并且返回true(DgnElementSetTool:: _FilterAgendaEntries返回false)的话,会将m_agenda中无效的元素(指调用了EditElementHandle:: Invalidate的元素)剔除掉,所以这就给了我们一个机会去筛选DgnElementSetTool为我们拾取的元素。最后调用_HiliteAgendaEntries高亮最终的ElementAgenda,如果是通过围栅获取的元素,_HiliteAgendaEntries 会调用_HiliteFenceElems判断是否高亮围栅选中的元素。
_OnInstall和_OnPostInstall执行之后,工具处与激活状态,等待用户的输入。这个时候我们的鼠标或者键盘在视图中发生的一些事件会触发DgnElementSetTool对应的成员函数,这些成员函数都是虚函数,我们可以在自己的类中重写这些虚函数从而响应这些事件,我们首先介绍一下_OnPostLocate函数。当光标在视图中移动并且定位到某个元素时,这个函数就会被调用。_OnPostLocate的函数原型如下所示:

virtual bool _OnPostLocate (HitPathCP path, WStringR cantAcceptReason);

通过path参数我们可以获取到当前光标定位到的元素,我们可以在重写的_OnPostLocate函数中获取元素的属性,然后判断我们的工具是否支持处理定位到的元素。如果不支持,就返回false,这样用户就没办法选中这个元素。我们还可以设置cantAcceptReason参数的值,从而提醒用户是什么原因不能选中这个元素,接下来我们看一下DgnElementSetTool ::_OnDataButton函数。
前面已经提到过单击鼠标左键时_OnDataButton函数会被调用,DgnElementSetTool中为我们实现了_OnDataButton函数,这个函数与_DecorateScreen、_OnModifierKeyTransition、_OnModelStartDrag、_OnModelEndDrag、_OnModelMotion等函数配合完成了支持点选、划选以及框选的功能。DgnElementSetTool::_OnDataButton函数中首先会根据m_agenda中元素个数是否为0或者_WantAdditionalLocate的返回结果是否为true,判断当前是否需要拾取元素。如果需要拾取元素的话会通过_GetElemSource的返回的结果判断是要点选元素还是要通过选择集或者围栅来拾取元素。如果是点选元素的话,会调用_LocateOneElement来定位拾取元素,否则会调用前面提到过的_BuildAgenda来拾取元素。如果没有拾取到新的元素的话,会根据_AllowDragSelect的返回结果判断是否要启用框选或者划选。如果启用框选或者划选的话,那么当光标停止拖拽在_OnModelEndDrag函数中,_BuildDragSelectAgenda会被调用。_BuildDragSelectAgenda会把框选或者划选的元素加入到m_agenda中,如果当前处于多选状态下的话,框选或者划选的元素已经在m_agenda中,这些元素会被反选掉。如果不是在多选状态下的话,m_agenda首先会被清空,然后再将框选或者划选的元素插入到m_agenda中,调用_BuildDragSelectAgenda之后会调用_ModifyAgendaEntries,前面我们提到过_ModifyAgendaEntries函数,给了我们一个过滤元素的机会。我们继续回到_OnDataButton函数中,如果拾取到新的元素的话,会调用_WantDynamics判断是否要启动动态绘制。然后会调用_NeedAcceptPoint判断是否需要用户再点击左键才开始处理元素,如果返回true的话,_OnDataButton会直接返回。如果_NeedAcceptPoint返回false的话,会直接调用_ProcessAgenda开始执行元素修改的流程。_ProcessAgenda调用以后,最后调用_OnModifyComplete。其中DgnElementSetTool::_NeedAcceptPoint的实现如下所示,可以看到如果_WantDynamics返回true,的话其直接返回true,否则会根据m_agenda中元素的来源判断返回true还是false。

bool DgnElementSetTool::_NeedAcceptPoint ()
{
if (_WantDynamics ())
return true;

return (SOURCE_Pick != _GetElemSource () || AccuSnap::GetInstance().UserWantsLocates() ? false : true);<br />}

_OnDataButton函数的流程图如下所示:

基础平台API介绍 - 图34
OnDataButton函数中调用的_LocateOneElement、_ProcessAgenda、_OnModifyComplete我们需要再深入探讨一下。_LocateOneElement中通过调用_WantAdditionalLocate判断是否支持多选,如果_WantAdditionalLocate返回false,则会清空m_agenda。如果返回true的话,会判断第二个参数newSearch的值。newSearch这个参数是用来控制定位元素时是否继续从上次定位到元素的位置往后查找,我们知道虽然在Mstn中我们看到的元素在空间下是杂乱无章的,但是Dgn文件在存储到磁盘上时,是按顺序一个挨着一个存储的。_LocateOneElement函数中是通过调用_DoLocate来定位元素的,_DoLocate在搜寻到元素时,会记录查找到元素的位置,_DoLocate有一个参数可以让我们从这个位置继续往后定位搜寻元素。在调用_DoLocate之前,如果newSearch的值为false的话,表明用户最近拾取的元素不是想要的,需要继续往后定位其他元素,所以这里会调用_RemoveAgendaElement从m_agenda中移除最近一次定位到的元素。之后就会调用_DoLocate来定位元素了,_DoLocate返回定位到的元素,_LocateOneElement中通过调用_BuildLocateAgenda把定位到的元素插入到m_agenda中。_BuildLocateAgenda也是先调用_WantAdditionalLocate判断是否支持多选,如果支持多选且当前Ctrl键处于按下的状态(通过参数ev->IsControlKey()判断)的话会先查看m_agenda中是否已经存在要插入的元素,如果存在会调用__RemoveAgendaElement将其移除然后马上返回,这样就实现了反选的功能。如果不存在的话,最后将定位到的元素插入到m_agenda中,这个时候会调用_IsModifyOriginal判断是插入元素本身还是元素的拷贝。其实我们前面介绍的_BuildAgenda以及框选划选的时候都会调用_IsModifyOriginal判断是插入元素本身还是元素的拷贝。另外在点选元素时还会调用_DoGroups判断是否与要插入元素同一组的元素也要插入到m_agenda中,在调用_RemoveAgendaElement时,也是会通过_DoGroups判断是否要移除同一组中的其他元素。 _LocateOneElement调用_BuildLocateAgenda之后也会调用_ModifyAgendaEntries,如前面所述,在这里同样给了我们一个机会去筛选m_agenda中的元素。
接下来我们看一下_ProcessAgenda函数,_ProcessAgenda中会依次调用_SetupForModify、_PreModifyAgenda、_ModifyAgendaGroup、_PostModifyAgenda。在_PreModifyAgenda中,会调用_IsFenceClip判断是否用围栅对元素进行剪切,如果需要的话,会调用_DoFenceClip来完成。在_ModifyAgendaGroup函数中,经过层层调用最终会调用到_DoOperationForModify、_OnPreElementModify、_OnElementModify。在_OnElementModify函数中如果我们对通过参数传递进来的元素进行修改,并且返回SUCCESS的话,在_DoOperationForModify中会用修改后的元素替换掉原来的元素,当然前提是_IsModifyOriginal返回true。否则的话会直接把修改后的元素重新添加到Dgn文件中。
_OnDataButton函数中调用_ProcessAgenda之后会调用_OnModifyComplete。_OnModifyComplete会先调用_CheckSingleShot,如果_CheckSingleShot返回true,则_OnModifyComplete直接返回。否则会根据_GetElemSource的返回结果做不同的操作,若果返回SOURCE_Pick,则会调用_NeedAcceptPoint和_AcceptIdentifiesNext,两者都返回ture的话会清空m_agenda,并调用_OnDataButton。如果_GetElemSource的返回结果是SOURCE_SelectionSet或者SOURCE_Fence则直接调用_ExitTool退出当前工具。
接下来我们看一下DgnElementSetTool封装的动态绘制功能是如何实现的。前面在介绍DgnPrimitiveTool的时候已经提到只要调用了_BeginDynamics之后,当我们的光标在视图中移动时,_OnDynamicFrame会被不停地调用,_OnPostInstall和_OnDataButton函数中在适当的时机都会调用到_BeginDynamics。DgnElementSetTool::_OnDynamicFrame中首先会判断m_agenda中是否有元素,如果没有就直接返回。否则继续调用_SetupForModify,这一点与_ProcessAgenda类似,区别是调用时第二个参数为true。接下来后台会调用一系列函数,经过层层调用后_OnRedrawInit、_OnRedrawOperation、_OnResymbolize、_OnRedrawFinish和_OnRedrawComplete会先后被调用到,其中_OnRedrawOperation又会调用到_OnElementModify。所以我们在_OnElementModify对元素所做的修改,同样的在动态绘制里边也会起作用。在这个过程中m_agenda中的元素会被复制拷贝一份出来传递给_OnElementModify,所以动态过程中并不会修改m_agenda中原有的元素。
目前为止,我们使用了大部分的鼠标相关的事件,其实键盘按键相关的事件处理函数主要有两个_OnModifierKeyTransition和_OnKeyTransition。_OnModifierKeyTransition在Ctrl、Alt或者Shift按下时触发,_OnKeyTransition是在VK_TAB, VK_RETURN, VK_END, VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN这些按键的其中一个按下时触发。并不是每个交互式工具都需要按键功能,根据情况而定。我们上边提到的框选和划选就是在_OnModifierKeyTransition函数中通过Alt键来切换的。
以上就是C/C++接口DgnElementSetTool的工作原理,C#接口中DgnElementSetTool的成员函数与C/C++中基本一致。主要区别就是在虚函数名称前少了“
“,只要我们理解了C/C++中的工作原理,在C#中使用DgnElementSetTool写起交互式工具也会得心应手。