MSCE C++官网一步步学习搬运3 第三章、在MDL应用中创建元素
MicroStation有很多种类型的元素,我们可以将其分成图形元素和非图形元素。本章将讨论如何在MDL程序中创建图形元素。由于CE SDK对原来的C函数都做了类的封装,所以,提供了一套全新的创建元素的方法。下表列出了MicroStation中支持的大多数图形元素,同时也列出了新旧创建元素的方法。
在CE SDK中,大多数旧的C函数仍然被保留,但其函数原型(prototype)发生了变化。主要原因是CE版完全采用了Unicode字符编码。本章将仅介绍新的C++编程方法,如果对C函数编程感兴趣,可读《一步步学习MDL-V8i》系列文章。
CE SDK中最重要的一个类就是ElementHandle了,该类的对象代表内存中的一个元素。MDL为同一个类定义了多种变形写法,其目的是为了简化C++本身的写法。如下表所示:
变形写法 |
实际定义 |
ElementHandleP |
ElementHandle * |
ElementHandleCP |
ElementHandle const * |
ElementHandleR |
ElementHandle & |
ElementHandleCR |
ElementHandle const & |
了解了以上一些基本知识后我们就开始动手来编写生成元素的代码。为了简化起见,所有代码都没有错误检查。
1、编辑HelloWorld.cpp文件,最终结果如下:
/*-------------------------------------------------------------+ | HelloWorld.cpp | +-------------------------------------------------------------*/ #include <MstnMdlApiMdlApi.h> #include <DgnPlatformDgnPlatformApi.h> USING_NAMESPACE_BENTLEY_DGNPLATFORM USING_NAMESPACE_BENTLEY_MSTNPLATFORM USING_NAMESPACE_BENTLEY_MSTNPLATFORM_ELEMENT double g_1mu; void createALine(DPoint3dCR basePt) { EditElementHandle eeh; DSegment3d seg; seg.Init(basePt, DPoint3d::From(basePt.x + g_1mu * 2, basePt.y + g_1mu)); ICurvePrimitivePtr pCurve = ICurvePrimitive::CreateLine(seg); DraftingElementSchema::ToElement(eeh, *pCurve, nullptr, ACTIVEMODEL->Is3d(), *ACTIVEMODEL); eeh.AddToModel(); } void createAComplexShape(DPoint3dCR basePt) { EditElementHandle eeh; DPoint3d pts[3]; pts[0] = pts[1] = pts[2] = basePt; pts[1].x += g_1mu*0.3; pts[1].y += g_1mu*0.7; pts[0].x += g_1mu; pts[0].y += g_1mu; DEllipse3d arcPts = DEllipse3d::FromPointsOnArc(pts[2], pts[1], pts[0]); CurveVectorPtr pCurveVec = CurveVector::Create(CurveVector::BOUNDARY_TYPE_Outer); pCurveVec->Add(ICurvePrimitive::CreateArc(arcPts)); pts[1].x = pts[0].x; pts[1].y = pts[2].y; pCurveVec->Add(ICurvePrimitive::CreateLineString(pts, 3)); DraftingElementSchema::ToElement(eeh, *pCurveVec, nullptr, ACTIVEMODEL->Is3d(), *ACTIVEMODEL); eeh.AddToModel(); } void createAProjectedSolid(DPoint3dCR basePt) { DPoint3d pts[6]; pts[0] = basePt; pts[1].x = pts[0].x; pts[1].y = pts[0].y - g_1mu / 2; pts[1].z = pts[0].z; pts[2].x = pts[1].x + g_1mu / 2; pts[2].y = pts[1].y; pts[2].z = pts[0].z; pts[3].x = pts[2].x; pts[3].y = pts[2].y - g_1mu / 2; pts[3].z = pts[0].z; pts[4].x = pts[3].x + g_1mu / 2; pts[4].y = pts[3].y; pts[4].z = pts[0].z; pts[5].x = pts[4].x; pts[5].y = pts[0].y; pts[5].z = pts[0].z; CurveVectorPtr pCurveVec = CurveVector::CreateLinear(pts, 6, CurveVector::BOUNDARY_TYPE_Outer); DVec3d extrusionVec = DVec3d::From(0, 0, g_1mu); DgnExtrusionDetail data(pCurveVec, extrusionVec, true); ISolidPrimitivePtr pSolid = ISolidPrimitive::CreateDgnExtrusion(data); EditElementHandle eeh; DraftingElementSchema::ToElement(eeh, *pSolid, nullptr, *ACTIVEMODEL); eeh.AddToModel(); } void createABsplineSurface(DPoint3dCR basePt) { MSBsplineSurface bsSurface; MSBsplineCurve bsCurves[4]; DPoint3d center[4]; RotMatrix rMatrix[4]; double radius = g_1mu / 2; center[0] = center[1] = center[2] = center[3] = basePt; center[0].x += radius; center[1].x += g_1mu; center[1].y += radius; center[2].x += radius; center[2].y += g_1mu; center[3].y += radius; DVec3d xVec = DVec3d::From(1, 0, 0), negativeXVec = DVec3d::From(-1, 0, 0); DVec3d yVec = DVec3d::From(0, 1, 0), negativeYVec = DVec3d::From(0, -1, 0); DVec3d zVec = DVec3d::From(0, 0, 1); rMatrix[0].InitFrom2Vectors(xVec, zVec); //Front View rMatrix[1].InitFrom2Vectors(yVec, zVec); //Right View rMatrix[2].InitFrom2Vectors(negativeXVec, zVec); //Back View rMatrix[3].InitFrom2Vectors(negativeYVec, zVec); //Left View EditElementHandle eeh; for (int i = 0; i<4; i++) { bsCurves[i].InitEllipticArc(center[i], radius, radius, 0, PI, &rMatrix[i]); } if (SUCCESS == mdlBspline_coonsPatch(&bsSurface, bsCurves)) { DraftingElementSchema::ToElement(eeh, bsSurface, nullptr, *ACTIVEMODEL); eeh.AddToModel(); mdlBspline_freeSurface(&bsSurface); } for (int i = 0; i<4; i++) mdlBspline_freeCurve(&bsCurves[i]); } extern "C" DLLEXPORT void MdlMain(int argc, WCharCP argv[]) { ModelInfoCP pInfo = ACTIVEMODEL->GetModelInfoCP(); g_1mu = pInfo->GetUorPerStorage(); DPoint3d basePt = DPoint3d::FromZero(); createALine(basePt); basePt.x += g_1mu*1.7; basePt.y -= g_1mu*0.3; basePt.z -= g_1mu*0.6; createAComplexShape(basePt); basePt.x += g_1mu*1.5; basePt.y -= g_1mu*0.3; basePt.z -= g_1mu*0.6; createAProjectedSolid(basePt); basePt.x += g_1mu*2.2; basePt.y -= g_1mu*1.7; basePt.z -= g_1mu*0.6; createABsplineSurface(basePt); }
- 这段代码主要由四个函数组成,分别演示了如何创建一条线、一个复杂形、一个实体和一个B样条曲面。
- 在代码的开头包含了两个头文件MdlApi.h和DgnPlatformApi.h,这两个头文件中包含了大多数我们能所用到的类定义和函数原型。
- 引入了三个命名空间Bentley::DgnPlatform、Bentley::MstnPlatform和Bentley::MstnPlatform::Element。这里没有使用C++标准的using namepspace语法而是直接使用了三个MDL中预定义好的宏。注意,这三行都不需要用分号结束,因为宏定义中已经含有分号了。
- 由于MDL中默认的单位是UOR(Unit Of Resolution)而不是MicroStation中的主单位,所以我们定义了一个全程变量g_1mu来代表一个主单位。在MdlMain函数中将其赋值为ModelInfo下的UorPerStorage。有关主单位、子单位和分辨率单位的关系,请参考下图(选菜单File > Settings > File > Design File Settings可打开这个对话框):
- createALine函数建立一条线。首先构造DSegment3d对象seg,表示一条单段线段的两个端点,接着调用ICurvePrimitive接口下的CreateLine创建线段的几何,然后又调用DraftingElementSchema下的ToElement函数将几何转换为EditElementHandle对象eeh,最后调用AddToModel函数将eeh添加到模型中。这种思路是MicroStation CE SDK的一大变化,都是先几何后元素。可以将几何理解为与MicroStation无关的通用的几何表达,只有转换为EditElementHandle后才成为MicroStation中的元素。
- createAComplexShape函数建立一个由弧和线串组成的复杂形。首先建立一个类型为BOUNDARY_TYPE_Outer的CurveVector,CurveVector是由ICurvePrimitive组成的动态数组(STL中的Vector),可用来表达诸如Complex Chain(复杂链)或Complex Shape(复杂形)这样的复杂元素。然后分别调用ICurvePrimitive::CreateArc和ICurvePrimitive::CreateLineString创建一个弧和一个线串添加到CurveVector中,最后还是类似于createALine中那样调用DraftingElementSchema::ToElement生成EditElementHandle进而添加到模型中。
- createAProjectedSolid函数根据一个断面来生成一个拉伸体。首先创建表达断面的CurveVector,然后根据这个断面和拉伸矢量创建一个DgnExtrusionDetail几何数据,进而调用ISolidPrimitive::CreateDgnExtrusio创建一个拉伸体。ISolidPrimitive用来表示Bentley定义的基本几何实体,而ISolidKernelEntity用来表示利用ParaSolid内核表达的任意复杂实体。
- createABsplineSurface函数根据四个弧生成一个孔斯曲面。由于在MSBsplineSurface类中没有找到合适的成员函数,我们继续调用MDL C函数mdlBspline_coonsPatch。由于MSBsplineSurface和MSBsplineCurve都没有使用智能指针(以Ptr结尾的都是MDL中定义的智能指针),所以需要显式调用mdlBspline_freeSurface和mdlBspline_freeCurve释放内存,否则将会造成内存泄露。
2、在MicroStation Developer Shell中键入bmake –a来生成最终的HelloWorld.ma和HelloWorld.dll。
3、启动MicroStation,打开或新建一个三维的模型,在键入命令域键入MDL LOAD HelloWorld并回车就能生成如下所示的图形。该图形是在ISO视图下看到的效果。
【技巧】:a. 在MicroStation Developer Shell黑窗口中可以通过键盘的上箭头键翻出前一个命令;
b. 在MicroStation的Keyin对话框中也可以通过键盘的上箭头键翻出前一个命令或直接双击以前键入的命令来执行;