第二章、在MDL应用中创建元素

MicroStation有很多种类型的元素,我们可以将其分成图形元素和非图形元素。本章将讨论如何在MDL程序中创建图形元素。

下表列出了MicroStation中支持的大多数图形元素:

在写代码前还需要介绍三个重要的结构体:MSElement、MSElementDescr和EditElemHandle。前两个是C结构,最后一个是C++结构(C++的结构和类很相似)。当我们创建一个简单元素时,可以将其保存到MSElement结构中,这是一个具有固定大小(最大为128K字节)的结构。对于复杂元素,由于其大小无法事先确定,所以需要采用一个指针(即MSElementDescr *)来表达。这两个结构体在MDL C API中大量使用。EditElemHandle是MDL C++ API中引入的一个新的类,它是表达一个被修改元素的最理想方式。有关EditElemHandle的详细描述,请阅读MicroStationAPI.chm中的EditElemHandle Struct Reference一节。这三个结构的相互转换关系如下图所示:

从本文、帮助文档或例子代码中您可能已经注意到MSElement和MSElementDescr有多种变形写法,其实际定义如下表所示:

变形写法

实际定义

MSElementP

MSElement *

MSElementCP

MSElement const *

MSElementDescrP

MSElementDescr *

MSElementDescrCP

MSElementDescr const*

MSElementDescrH

MSElementDescr **

了解了以上一些基本知识后我们就开始动手来编写生成元素的代码。为了简化起见,所有代码都没有错误检查。

1、编辑HelloWorld.cpp文件,最终结果如下:

/*-------------------------------------------------------------+

|   HelloWorld.cpp                                             |

+-------------------------------------------------------------*/

#include <MicroStationAPI.h>

#include <msdialog.fdf>

#include <mselmdsc.fdf>

#include <msbsplin.fdf>

USING_NAMESPACE_BENTLEY_USTN_ELEMENT

double g_1mu;

void createALine (DPoint3d *basePtP)

{   

MSElement myLine;   

DPoint3d  pts[2];   

pts[0] = pts[1] = *basePtP;   

pts[1].x += g_1mu*2;    pts[1].y += g_1mu;   

mdlLine_create (&myLine, NULL, pts);   

EditElemHandle eeh (&myLine, ACTIVEMODEL);   

eeh.AddToModel (ACTIVEMODEL);

}

void createAComplexShape (DPoint3d *basePtP)

{   

MSElement        el;   

MSElementDescrP  edP = NULL;   

DPoint3d         pts[3], tmpPt;   

mdlComplexChain_createHeader (&el, 1, 0);   

mdlElmdscr_new (&edP, NULL, &el);   

pts[0] = pts[1] = pts[2] = *basePtP;   

pts[1].x += g_1mu*0.3;    pts[1].y += g_1mu*0.7;   

pts[2].x += g_1mu;        pts[2].y += g_1mu;   

mdlArc_createByPoints (&el, NULL, pts);   

mdlElmdscr_appendElement (edP, &el);   

tmpPt = pts[0];         pts[0] = pts[2];     pts[2] = tmpPt;   

pts[1].x = pts[0].x;    pts[1].y = pts[2].y;   

mdlLineString_create (&el, NULL, pts, 3);   

mdlElmdscr_appendElement (edP, &el);   

EditElemHandle eeh (edP, true, false);   

eeh.AddToModel (ACTIVEMODEL);

}

void createAProjectedSolid (DPoint3d *basePtP)

{   

MSElement        el;   

MSElementDescrP  sectionEdP = NULL, solidEdP = NULL;   

DPoint3d         pts[6], pt1, pt2;      

pts[0] = *basePtP;    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;   

pt1 = pt2 = pts[0];    pt2.z += g_1mu;   

mdlShape_create (&el, NULL, pts, 6, 0);   

mdlElmdscr_new (&sectionEdP, NULL, &el);   

mdlSurface_project (&solidEdP, sectionEdP, &pt1, &pt2, NULL);   

mdlElmdscr_freeAll (&sectionEdP);   

solidEdP->el.ehdr.type = SOLID_ELM;   

EditElemHandle eeh (solidEdP, true, false);   

eeh.AddToModel (ACTIVEMODEL);

}

void createABsplineSurface (DPoint3d *basePtP)

{   

   MSElement        el;   

   MSElementDescrP  edP = NULL;   

   MSBsplineSurface bsSurface;   

   MSBsplineCurve   bsCurves[4];   

   DPoint3d         arcPts[4][3];     

   arcPts[0][0] = arcPts[0][1] = arcPts[0][2] = *basePtP;   

   arcPts[0][1].x += g_1mu/2;  arcPts[0][1].z += g_1mu/2;   

   arcPts[0][2].x += g_1mu;    arcPts[1][0] = arcPts[1][1] = arcPts[1][2] = arcPts[0][2];   

   arcPts[1][1].y += g_1mu/2;    arcPts[1][1].z += g_1mu/2;   

   arcPts[1][2].y += g_1mu;    arcPts[2][0] = arcPts[2][1] = arcPts[2][2] = arcPts[1][2];   

   arcPts[2][1].x -= g_1mu/2;  arcPts[2][1].z += g_1mu/2;   

   arcPts[2][2].x -= g_1mu;    arcPts[3][0] = arcPts[3][1] = arcPts[3][2] = arcPts[2][2];   

   arcPts[3][1].y -= g_1mu/2;  arcPts[3][1].z += g_1mu/2;    arcPts[3][2] = *basePtP;     

   for (int i=0; i<4; i++)   

     {      

        mdlArc_createByPoints (&el, NULL, arcPts[i]);     

        mdlElmdscr_new (&edP, NULL, &el);     

        mdlBspline_convertToCurve (&bsCurves[i], edP);     

        mdlElmdscr_freeAll (&edP);   

     }   

   if (SUCCESS == mdlBspline_coonsPatch (&bsSurface, bsCurves))   

    {      

       mdlBspline_createSurface (&edP, NULL, &bsSurface);      

       EditElemHandle eeh (edP, true, false);      

       eeh.AddToModel (ACTIVEMODEL);      

       mdlBspline_freeSurface (&bsSurface);   

    }   

   for (int i=0; i<4; i++)      

    mdlBspline_freeCurve (&bsCurves[i]);

}

extern "C" DLLEXPORT int MdlMain (int argc, char *argv[])

{    

   g_1mu = mdlModelRef_getUorPerMaster(ACTIVEMODEL);   

   DPoint3d basePt = {0,0,0};    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);   

   return 0;

}

1.1、这段代码主要由四个函数组成,分别演示了如何创建一条线、一个复杂形、一个实体和一个B样条曲面。

1.2、在代码的开头包含了两个新的函数定义文件mselmdsc.fdf和msbsplin.fdf,它们分别包含了mdlElmdscr_xxx和mdlBspline_xxx函数的原型。

1.3、由于EditElemHandle类位于命名空间Bentley::Ustn::Element下,所以使用了宏定义USING_NAMESPACE_BENTLEY_USTN_ELEMENT。注意,这一行不需要用分号结束,因为宏定义中已经含有分号了。

1.4、由于MDL中默认的单位是UOR(Unit Of Resolution)而不是MicroStation中的主单位,所以我们定义了一个全程变量g_1mu来代表一个主单位。在MdlMain函数中将其赋值为mdlModelRef_getUorPerMaster(ACTIVEMODEL)。有关主单位、子单位和分辨率单位的关系,请参考下图(选菜单Settings > Design File可打开这个对话框):

1.5、createALine函数建立一条线。mdlLine_create函数根据两个点在MSElement结构体中生成这条线,然后据此建立一个EditElemHandle的实例,最后调用AddToModel方法加入到当前模型中。

1.6、createAComplexShape函数建立一个由弧和线串组成的复杂形。首先建立一个复杂链头元素(mdlComplexChain_createHeader的第二个参数1表示建立一个封闭形的头元素),紧接着将其转换为一个元素描述符,又分别建立弧元素和线串元素且将它们附加到这个元素描述符中。然后据此元素描述符建立一个EditElemHandle的实例,调用AddToModel方法将复杂形加入到当前模型中。注意,EditElemHandle eeh(edP, true,false)中的第二个参数true表示该元素句柄接管元素描述符edP。当eeh失效时会自动释放edP的,从而不再需要显式调用mdlElmdscr_freeAll来释放edP了。

1.7、createAProjectedSolid函数利用mdlSurface_project函数根据一个断面来生成一个拉伸体。默认生成的是一个拉伸面,通过设置solidEdP->el.ehdr.type = SOLID_ELM将拉伸面变成拉伸体。

2、编辑HelloWorld.mke文件,修改DLM_LIBRARY_FILES定义如下:

DLM_LIBRARY_FILES = $(mdlLibs)BentleyDgn.lib \                    

                    $(mdlLibs)toolsubs.lib \                    

                    $(mdlLibs)ditemlib.lib \                    

                    $(mdlLibs)mdllib.lib \                    

                    $(mdlLibs)msbspline.lib

之所以要增加一个msbspline.lib是因为我们在代码中调用了mdlBspline类函数,而这些函数的内容位于msbspline.dll中。如果不增加这个库,执行bmake后会出现下图所示的链接错误:

从mdlBspline类函数的文档中可以知道要在.cpp中包含哪个头文件,在.mke中要指定哪个库。如下图所示:

3、在MicroStation Developer Shell中键入bmake –a来生成最终的HelloWorld.ma和HelloWorld.dll。

4、启动MicroStation,打开或新建一个三维的模型,在键入命令域键入MDL LOAD HelloWorld并回车就能生成如下所示的图形。该图形是在ISO视图下看到的效果。

【技巧】:a. 在MicroStation Developer Shell黑窗口中可以通过键盘的上箭头键翻出前一个命令;                    b. 在MicroStation的Keyin对话框中也可以通过键盘的上箭头键翻出前一个命令或直接双击以前键入的命令来执行;

5、有关建立网格曲面和智能实体的例子请见Learning MicroStation Addins Step by Step[9]中的相关代码。将这些代码稍作修改即可生成如下所示的图形。不要犹豫,快自己动手吧!