(15)ObjectARX2015 + vs2012创建三维实体

1. 说明

        ObjectARX 中提供了三类创建三维实体的方法:
                (1)创建标准形状的实体
                (2)拉伸面域创建实体
                (3)旋转面域创建实体。
        本篇通过创建长方体、圆锥体、弹簧和一个皮带轮实体来介绍这三种方法。
        仅能用三类方法来创建实体,所能得到的实体的形状还是很有限的,布尔运算提供了实体的交、并、补运算,能够根据已有的实体“组合”出复杂形状的实体。本篇通过对两个长方体进行布尔运算来介绍其使用方法。
2. 思路
        在 ObjectARX 中, AcDb3dSolid 类用于代表 AutoCAD 中的三维实体,提供了创建和合并实体的一些方法,与使用 AutoCAD 命令来创建实体类似。
        但是,ACIS 实体才是实体真正的几何表示,AcDb3dSolid 类只是 ACIS 实体的容器和接口,该类中并没有提供直接操作 ACIS 实体边、顶点和面的方法。要遍历 ACIS 实体中隐含(无法直接访问子实体)的边、面和顶点,必须使用 ObjectARX 开发包中的 BREP 应用程序开发接口( API )。
(1)长方体
        AcDb3dSolid 类仅提供了一个不包含任何参数的构造函数,用于创建一个“空”实体,在构造 AcDb3dSolid 对象之后,必须使用其成员函数来完成实体的创建。
        createBox 函数用于创建长方体,其定义为:
//该函数将会创建一个中心位于世界坐标系原点的长方体
//并且其长、宽、高分别平行于世界坐标系的 X、Y 和 Z 轴。
virtual Acad::ErrorStatus createBox(
    double xLen,   //长方体的长
    double yLen,   //长方体的宽
    double zLen);  //长方体的高

(2)圆锥体

        ObjectARX 中并未直接提供创建圆锥体的方法,而是将其包含在创建平截头体(圆柱体
和圆锥体都是其中的一种)的函数 createFrustum 中,
        createFrustum 函数定义为:
//如果要创建一个圆锥体
//将 topXRadius 参数设置为 0,并且保证 xRadius 和 yRadius 的值相等
virtual Acad::ErrorStatus createFrustum( 
    double height,       //height 表示平截头体的高度
    double xRadius,      //xRadius 表示底面在 X 轴方向的半径
    double yRadius,      //            底面在 Y 轴方向的半径
    double topXRadius);  //topXRadius 表示顶面在 X 轴方向的半径

(3)拉伸面域创建实体

        AcDb3dSolid 类中的 extrudeAlongPath 函数用于拉伸面域创建一个实体,

        extrudeAlongPath 函数定义为:

//拉伸面域创建一个实体
//注意:在执行extrudeAlongPath函数时,region和 path 都必须是模型空间中的实体,否则会引发一个异常。
virtual Acad::ErrorStatus extrudeAlongPath( 
const AcDbRegion* region,   //region是一个指向作为拉伸截面的面域的指针
const AcDbCurve* path);     //path  是一个指向作为拉伸路径的曲线的指针

        AcDb3dSolid类的另一个函数extrude用于沿面域所在平面的法线方向拉伸面域创建新的实体,并且可以指定拉伸时的斜切角度。

(4)旋转面域创建实体

        AcDb3dSolid 类中的 revolve 函数用于绕给定的轴线旋转面域而生成实体,其定义为:
                revolve 函数定义为:

//绕给定的轴线旋转面域而生成实体
virtual Acad::ErrorStatus revolve(
    const AcDbRegion* region,       //region是一个指向作为旋转截面的面域的指针
    const AcGePoint3d& axisPoint,   //axisPoint 指定旋转轴线上的一点
    const AcGeVector3d& axisDir,    //axisDir指定了旋转轴的方向,和axisPoint共同确定旋转轴的具体位置
    double angleOfRevolution);      //angleOfRevolution 指定旋转面域的角度(弧度值来表示)

(5)布尔运算

        AcDb3dSolid 类中的 booleanOper 函数用于在两个实体之间执行布尔运算
        booleanOper 函数定义为:
//在两个实体之间执行布尔运算
virtual Acad::ErrorStatus booleanOper(
    AcDb::BoolOperType operation,   //operation指定了进行布尔运算的方式,包括
                                    //AcDb::kBoolUnite (并集)
                                    //AcDb::kBoolIntersect(交集)
                                    //AcDb::kBoolSubtract(差集)三种类型
    AcDb3dSolid* solid);            //solid是一个指向布尔运算的另一个实体的指针

3. 步骤

(1) 创建长方体

    //添加长方体
    static void AddBox();  //添加长方体
//添加长方体
void CCreateEnt::AddBox()
{
    AcDb3dSolid *pSolid = new AcDb3dSolid(); 
    Acad::ErrorStatus es = pSolid->createBox(40, 50, 30);

    if (es != Acad::eOk) 
    {
        acedAlert(_T("创建长方体失败!")); 
        delete pSolid; 
        return;
    }

    // 使用几何变换矩阵移动长方体
    AcGeMatrix3d xform;
    AcGeVector3d vec(100, 100, 100);
    xform.setToTranslation(vec);
    pSolid->transformBy(xform); 
    // 将长方体添加到模型空间
    PostToModelSpace(pSolid);//此为自定义函数,在本系列(1)(4)中有具体代码
}

(2) 创建圆锥

    //添加圆锥
    static void AddCylinder();  //添加圆锥
//添加圆锥
void CCreateEnt::AddCylinder()
{
    // 创建特定参数的圆柱体(实际上是一个圆锥体)
    AcDb3dSolid *pSolid = new AcDb3dSolid(); 
    pSolid->createFrustum(30, 10, 10, 0);

    // 将圆锥体添加到模型空间
    PostToModelSpace(pSolid);
}

(3) 创建弹簧

        首先创建一个三维螺旋线作为拉伸路径,使用小段的三维多段线来模拟三维螺旋线,segment 的一点是,需要计算的顶点个数实际上是 num 间隔数总是比节点数少 1

        atan( 用来代替π,其值为π/4,因此 4*atan(1)的值就是π。这种替代比直接用一个常量“const double PI = 3.1415926;”要精确得多。

        代码中使用了两个 ObjectARX 中的数组类型:AcGePoint3dArray AcDbObjectIdArray。这两个类均派生自 AcArray 类,AcArray 类的使用非常简单,length 函数用于获得数组对象的元素个数;at 函数用于获得指定索引的元素的值;append 函数用于向数组添加元素;[]运算符的作用与 at 函数相同。

        其中,CreateRegion 是一个自定义函数,用于根据给定的边界创建面域,该函数与 博客(9)
中的同名函数完全相同
    //添加三维弹簧模型
    static void AddSpire();//添加三维弹簧模型
//添加三维弹簧模型
void CCreateEnt::AddSpire()
{
    //指定创建螺旋线的参数
    double radius, deltaVertical; //半径和每一周在垂直方向的增量
    double number, segment; //螺旋线的旋转圈数和组成一圈

    radius = 30, deltaVertical = 12; 
    number = 5, segment = 30;

    //计算点的个数和角度间隔
    int n = number * segment; //点的个数实际上是n+1
    double angle = 8 * atan(1) / segment; //两点之间的旋转角度

    //计算控制点的坐标
    AcGePoint3dArray points; // 控制点坐标数组
    for (int i = 0; i < n+1; i++)
    {
        AcGePoint3d vertex;
        vertex[X] = radius * cos(8 * i * atan(1) / segment);
        vertex[Y] = radius * sin(8 * i * atan(1) / segment);
        vertex[Z] = i * deltaVertical / segment;
        points.append(vertex);
    }

    // 创建螺旋线路径
    AcDb3dPolyline *p3dPoly = new AcDb3dPolyline(AcDb::k3dSimplePoly, points); 

    //将路径添加到模型空间
    AcDbObjectId spireId = PostToModelSpace(p3dPoly);

    //创建一个圆作为拉伸的截面
    AcGeVector3d vec(0, 1, 0);  //圆所在平面的法矢量
    AcGePoint3d ptCenter(30, 0, 0);  //圆心位置与半径的大小有关
    AcDbCircle *pCircle = new AcDbCircle(ptCenter, vec, 3);
    AcDbObjectId circleId = PostToModelSpace(pCircle);

    //根据圆创建一个面域
    AcDbObjectIdArray boundaryIds, regionIds; 
    boundaryIds.append(circleId);
    regionIds = CreateRegion(boundaryIds);

    //打开拉伸截面和拉伸路径
    AcDbRegion *pRegion; 
    acdbOpenObject(pRegion, regionIds.at(0), AcDb::kForRead);
    AcDb3dPolyline *pPoly;
    acdbOpenObject(pPoly, spireId, AcDb::kForRead);

    //进行拉伸操作
    AcDb3dSolid *pSolid = new AcDb3dSolid();
    pSolid->extrudeAlongPath(pRegion, pPoly);
    PostToModelSpace(pSolid);

    pPoly->close(); 
    pRegion->close();
}

(4)     旋转面域成三维实体
 

    //旋转面域成三维实体
    static void RevolveEnt();  //旋转面域成三维实体
//旋转面域成三维实体
void CCreateEnt::RevolveEnt()
{
    // 设置顶点的坐标
    AcGePoint3d vertex[5];
    vertex[0] = AcGePoint3d(15,  0, 0);
    vertex[1] = AcGePoint3d(45,  0, 0);
    vertex[2] = AcGePoint3d(35,  9, 0);
    vertex[3] = AcGePoint3d(41, 18, 0);
    vertex[4] = AcGePoint3d(15, 18, 0);
    AcGePoint3dArray points;
    for (int i= 0; i <= 4; i++)
    {
        points.append(vertex[i]);
    }

    //创建作为旋转截面的多段线
    AcDb3dPolyline *p3dPoly = new AcDb3dPolyline(AcDb::k3dSimplePoly, points, true);
    AcDbObjectId polyId = PostToModelSpace(p3dPoly);

    //将闭合的多段线转化成面域
    AcDbObjectIdArray boundarylds, regionlds;
    boundarylds.append(polyId);
    regionlds = CreateRegion(boundarylds);

    //进行旋转操作
    AcDbRegion *pRegion;
    Acad:ErrorStatus es = acdbOpenObject(pRegion, regionlds.at(0), AcDb::kForRead);
    AcDb3dSolid *pSolid = new AcDb3dSolid();
    es = pSolid->revolve(pRegion,AcGePoint3d::kOrigin,AcGeVector3d(0, 1, 0),8 * atan(1));
    PostToModelSpace(pSolid);
    pRegion->close();
}

(5)  布尔运算组合三维实体

    //布尔运算组合三维实体
    static void BooleanEnt(); //布尔运算组合三维实体
//布尔运算组合三维实体
void CCreateEnt::BooleanEnt()
{
    //创建两个长方体
    AcDb3dSolid *pSolid1 = new AcDb3dSolid();
    pSolid1->createBox(40,50,30);
    AcDb3dSolid *pSolid2 = new AcDb3dSolid();
    pSolid2->createBox(40,50,30);
    
    //使用几何变换矩阵移动长方体
    AcGeMatrix3d xform;
    AcGeVector3d vec(20,25,15);
    xform.setToTranslation(vec);
    pSolid1->transformBy(xform);
    
    //将长方体添加到模型空间
    AcDbObjectId solidld1 = PostToModelSpace(pSolid1);
    AcDbObjectId solidld2 = PostToModelSpace(pSolid2);

    //进行布尔运算,生成新的实体
    acdbOpenObject(pSolid1 , solidld1, AcDb::kForWrite);
    acdbOpenObject(pSolid2, solidld2, AcDb::kForWrite);
    Acad:ErrorStatus es = pSolid1->booleanOper(AcDb::kBoolUnite, pSolid2);
    assert(pSolid2->isNull());pSolid2->erase();
    
    //将其删除
    pSolid2->close();
    
    //删除之后还是需要关闭该实体
    pSolid1->close();
}

         booleanOper函数不会自动删除 pSolid2,因此需要手工删除 pSolid2,删除之后仍然需要使用 close 函数将其关闭,也就是将该对象的控制权交给AutoCAD。为什么在删除实体之后仍需要关闭实体,并将对象控制权交给AutoCAD? 因为执行erase函数之后系统不会立即从图形中将指定的实体删除,而是将其“删除位”打开,在AutoCAD保存图形时该实体将不会再被保存,下一次重新打开图形时该实体就不再存在。

        提示: 为什么erase 函数执行时不是立即删除实体? 这是为了提供Undo(撤消)的操作,只要未关闭图形,一个被删除的实体就可以使用 erase(kfalse) 来撤消删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值