第2章、在Addin中创建元素


Mstn中有很多种类型的元素,我们可以将其分成图形元素和非图形元素。本章主要讨论如何在Addin中利用Mstn对象模型创建图形元素。下图是CE版本Addins的整体架构。其中我们创建图形元素用到的对象主要在DgnPlatformNET下。

有关Mstn对象模型更详细的信息请参考位于…\ Bentley\MicroStationCONNECTSDK\doc文件夹下的帮助文档。另外,当你在VS中引用了Mstn对象模型后也能通过VS中的对象浏览器查看到整个对象模型,如下图所示。(VS中的对象浏览器是通过选VS菜单View > Object Browser打开的)

既然了解了图形元素的一些知识,就让我们通过一步步的操作在DGN模型中建立一些图形元素。

1.在解决方案浏览器中右击csAddins,选菜单Add > New Item…,在弹出的窗体中选Visual C# Items下的Class,文件名输入CreateElement.cs。点击Add按钮为当前项目添加一个新的CreateElement.cs文件。

2.修改并键入代码。最终的CreateElement.cs文件内容如下。其中绘制了九组元素,分别是LineAndLineString1、LineAndLineString2、LineAndLineString3、ShapeAndComplexShape、TextString、Cell、Dimension、BsplineCurve和Cone。

using Bentley.DgnPlatformNET;
using Bentley.DgnPlatformNET.Elements;
using Bentley.GeometryNET;
using Bentley.MstnPlatformNET;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BIM = Bentley.Interop.MicroStationDGN;

namespace csAddins
{
    //尺寸标注元素的构造函数会调用DimensionCreateData的各个成员函数去获取创建尺寸标注元素需要的各种参数
    class CreateDimensionCallbacks : DimensionCreateData
    {
        private DimensionStyle m_dimStyle;
        private DgnTextStyle m_textStyle;
        private Symbology m_symbology;
        private LevelId m_levelId;
        private DirectionFormatter m_directionFormatter;

        public CreateDimensionCallbacks(DimensionStyle dimStyle, DgnTextStyle textStyle, Symbology symb, LevelId levelId, DirectionFormatter formatter)
        {
            m_dimStyle = dimStyle;
            m_textStyle = textStyle;
            m_symbology = symb;
            m_levelId = levelId;
            m_directionFormatter = formatter;
        }

        public override DimensionStyle GetDimensionStyle()
        {
            return m_dimStyle;
        }

        public override DgnTextStyle GetTextStyle()
        {
            return m_textStyle;
        }

        public override Symbology GetSymbology()
        {
            return m_symbology;
        }

        public override LevelId GetLevelId()
        {
            return m_levelId;
        }

        public override int GetViewNumber()
        {
            return 0;
        }

        //此函数返回的旋转矩阵与GetViewRotation返回的旋转矩阵共同定义了尺寸标注元素的方向
        public override DMatrix3d GetDimensionRotation()
        {
            return DMatrix3d.Identity;
        }

        public override DMatrix3d GetViewRotation()
        {
            return DMatrix3d.Identity;
        }

        //用于从数字方向值构造字符串。
        public override DirectionFormatter GetDirectionFormatter()
        {
            return m_directionFormatter;
        }
    }
    class CreateElement
    {
        //函数后台坐标值使用的单位都是Uor单位,我们需要将传递给函数接口的值从主单位乘上此值变为Uor单位
        static double UorPerMas = Session.Instance.GetActiveDgnModel().GetModelInfo().UorPerMaster;
        
        //创建图形元素首先按框架分有两种创建方式,正如我们在第零章中开头部分介绍的那样,本函数简单演示了从v8i继承的COM接口创建图形元素的方式
        public static void LineAndLineString1()
        {
            //从v8i继承的编程框架创建元素的函数都在Bentley.Interop.MicroStationDGN.Application接口下
            BIM.Application app = Bentley.MstnPlatformNET.InteropServices.Utilities.ComApp;
            BIM.Point3d ptStart = app.Point3dZero();
            BIM.Point3d ptEnd = ptStart;
            //使用这套编程框架时,函数接受参数的单位都是主单位,这一点是跟新的编程框架最大的不同之处
            ptStart.X = 10;
            BIM.LineElement lineEle = app.CreateLineElement2(null, ref ptStart, ref ptEnd);
            lineEle.Color = 0; lineEle.LineWeight = 2;
            app.ActiveModelReference.AddElement(lineEle);
        }

        //新的编程框架下创建元素的方式又可以分为两大种,本函数演示了其中一种直接通过特定类型元素的构造函数去构造,直接将坐标值传递给
        //特定类型的构造函数去创建指定类型的元素
        public static void LineAndLineString2()
        {
            DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
            ModelInfo modelInfo = dgnModel.GetModelInfo();
            DSegment3d seg = new DSegment3d(0 * UorPerMas, 5 * UorPerMas, 0 * UorPerMas, 10 * UorPerMas, 10 * UorPerMas, 0 * UorPerMas);
            LineElement lineEle = new LineElement(dgnModel, null, seg);
            lineEle.AddToModel();
            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();
        }

        //本函数演示了新框架下另外一种创建图形元素的方法,即先构造图形元素的几何数据,最后调用统一的DraftingElementSchema.ToElement函数完成几何数据到特定类型元素的创建
        public static void LineAndLineString3()
        {
            DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
            ModelInfo modelInfo = dgnModel.GetModelInfo();
            DPoint3d[] ptArr = new DPoint3d[5];
            ptArr[0] = new DPoint3d(0 * UorPerMas, 10 * UorPerMas, 0 * UorPerMas);
            ptArr[1] = new DPoint3d(1 * UorPerMas, 12 * UorPerMas, 0 * UorPerMas);
            ptArr[2] = new DPoint3d(3 * UorPerMas, 8 * UorPerMas, 0 * UorPerMas);
            ptArr[3] = new DPoint3d(5 * UorPerMas, 12 * UorPerMas, 0 * UorPerMas);
            ptArr[4] = new DPoint3d(6 * UorPerMas, 10 * UorPerMas, 0 * UorPerMas);
            //CurvePrimitive仅仅保存基本曲线的几何数据,不包含Mstn元素的其他任何数据(例如元素的颜色,线型等属性)
            CurvePrimitive curPri = CurvePrimitive.CreateLineString(ptArr);
            //DraftingElementSchema.ToElement将几何数据转换成Mstn中对应类型的元素(ArcElement,LineElement等)
            Element ele = DraftingElementSchema.ToElement(dgnModel, curPri, null);
            ele.AddToModel();
        }

        public static void ShapeAndComplexShape()
        {
            DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
            DPoint3d[] ptArr = new DPoint3d[6];
            ptArr[0] = new DPoint3d(0 * UorPerMas, -6 * UorPerMas, 0 * UorPerMas);
            ptArr[1] = new DPoint3d(0 * UorPerMas, -2 * UorPerMas, 0 * UorPerMas);
            ptArr[2] = new DPoint3d(2 * UorPerMas, -2 * UorPerMas, 0 * UorPerMas);
            ptArr[3] = new DPoint3d(2 * UorPerMas, -4 * UorPerMas, 0 * UorPerMas);
            ptArr[4] = new DPoint3d(4 * UorPerMas, -4 * UorPerMas, 0 * UorPerMas);
            ptArr[5] = new DPoint3d(4 * UorPerMas, -6 * UorPerMas, 0 * UorPerMas);
            ShapeElement shapeEle = new ShapeElement(dgnModel, null, ptArr);
            //ElementPropertiesSetter用来设置元素Symbol属性(颜色,线型等属性)
            ElementPropertiesSetter elePropSet = new ElementPropertiesSetter();
            elePropSet.SetColor(0);
            elePropSet.SetWeight(2);
            elePropSet.Apply(shapeEle);
            shapeEle.AddToModel();
            for (int i = 0; i < 6; i++)
                ptArr[i].X += 5 * UorPerMas;
            CurvePrimitive curvePri = CurvePrimitive.CreateLineString(ptArr);
            //CurveVector是CurvePrimitive的集合,用来表示任意复杂的线型几何数据
            CurveVector curVec = CurveVector.Create(CurveVector.BoundaryType.Outer);
            curVec.Add(curvePri);
            ptArr[2].Y = -8;
            DEllipse3d ellipse = new DEllipse3d();
            if (DEllipse3d.TryCircularArcFromCenterStartEnd(ptArr[2], ptArr[5], ptArr[0], out ellipse))
            {
                curvePri = CurvePrimitive.CreateArc(ellipse);
                curVec.Add(curvePri);
                Element eleTemp = DraftingElementSchema.ToElement(dgnModel, curVec, null);
                eleTemp.AddToModel();
                elePropSet.SetColor(1);
                elePropSet.SetWeight(2);
                elePropSet.Apply(eleTemp);
                eleTemp.AddToModel();
            }
        }

        //文本元素需要的各种参数分了Block,Paragraph,Run等层级,每一层设置其包含的属性,有点类似于Word中的管理结构
        public static void TextString()
        {
            DgnFile dgnFile = Session.Instance.GetActiveDgnFile();
            DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
            TextBlockProperties txtBlockProp = new TextBlockProperties(dgnModel);
            txtBlockProp.IsViewIndependent = true;
            ParagraphProperties paraProp = new ParagraphProperties(dgnModel);
            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();
        }

        //单元是由若干个子元素加一个单元头元素构成的复杂元素,子元素也可是一个单元
        public static void Cell()
        {
            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<Element> listEle = new List<Element>();
            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();
        }

        public static void Dimension()
        {
            DgnFile dgnFile = Session.Instance.GetActiveDgnFile();
            DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
            double uorPerMast = dgnModel.GetModelInfo().UorPerMaster;
            
            //获取当前dgn文件中名字为"DimStyle"的标注样式,尺寸标注元素的外貌由上百个属性控制,而标注样式是一组预先设置好的属性
            //获取了预先订制好的标注样式之后,还可以调用DimensionStyle下的各种SetXXX成员函数修改设置的属性
            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();
            }
        }

        public static void BsplineCurve()
        {
            DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
            DPoint3d[] ptArr = new DPoint3d[5];
            ptArr[0] = new DPoint3d(0 * UorPerMas, 25 * UorPerMas, 0 * UorPerMas);
            ptArr[1] = new DPoint3d(5 * UorPerMas, 35 * UorPerMas, 0 * UorPerMas);
            ptArr[2] = new DPoint3d(10 * UorPerMas, 25 * UorPerMas, 0 * UorPerMas);
            ptArr[3] = new DPoint3d(15 * UorPerMas, 35 * UorPerMas, 0 * UorPerMas);
            ptArr[4] = new DPoint3d(20 * UorPerMas, 25 * 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();
        }

        public static void Cone()
        {
            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();
        }
    }
}

4.打开MyAddins.cs文件修改如下。

protected override int Run(string[] commandLine)
{
                CreateElement.LineAndLineString1();
                CreateElement.LineAndLineString2();
                CreateElement.LineAndLineString3();
                CreateElement.ShapeAndComplexShape();
                CreateElement.TextString();
                CreateElement.Cell();
                CreateElement.Dimension();
                CreateElement.BsplineCurve();
                CreateElement.Cone();
            return 0;
}

5.通过选菜单Build > Build Solution来重新生成目标文件。记住,在执行生成前要记住退出Mstn。

6.启动Mstn,装载csAddins程序,则能看到如下图所示的图形。请注意,你当前的DGN文件模型应该是一个三维模型,否则Cone方法将不能被正确执行。

在以上代码中我们用了三种方法画线元素。LineAndLineString1用的是CE版本之前Addins开放框架。LineAndLineString2用的是CEAddins开发框架,通过元素类型的构造函数创建元素。LineAndLineString3用的是CEAddins开发框架的一种全新的创建元素的方法,即先创建几何,最后通过DraftingElementSchema 下的静态成员函数ToElement把几何转换为元素。我们可以看到CE Addins框架为我们提供了丰富的创建元素的方法,具体使用哪一种我们可以根据实际情况选择。