(7)ObjectARX2015 + vs2012创建多段线以及实体的旋转移动放缩

  提示:看之前的博客(1)和(4),那里已经分析了创建一个图形对象的基本过程,在之前的基础上本节开始就要将着眼点放在创建实体的参数上。

(1)ObjectARX2015 + vs2012创建直线_qq_42981953的博客-CSDN博客

(4)ObjectARX2015 + vs2012扩展绘制直线的功能为绘制实体_qq_42981953的博客-CSDN博客

1. 说明

        本节介绍若干个函数,分别用于创建轻量多段线、三维多段线、正多边形、矩形、圆(圆环)和圆弧。这里所说的圆形和博客(6)中创建的圆不一样,因为本节创建的圆实际上是一条闭合的多段线,可以设置线宽。

        (1) 创建轻量多段线(二维点, 连接点线宽)

        (2) 创建仅包含一条直线的多段线(二维起点, 二维结束点, 连接点线宽)

        (3) 创建三维多段线(三维点集)

        (4) ---实体操作:旋转/移动/放缩

        (5) 创建正多边形(中心、边数、外接圆半径、旋转角度(弧度值)和线宽)

        (6) 多线段矩形(两个角点、线宽)

        (7) 多线段圆(圆心、半径和线宽)

        (8) 多线段圆弧(圆心、半径、起始角度、终止角度和线宽)

2. 思路

        ObjectARX 中提供了三种多段线的相关类: AcDbPolyline AcDb2dPolyline
AcDb3dPolyline 。其中,利用 AutoCAD 的内部命令可以创建 AcDbPolyline AcDb3dPolyline
类的对象,用 PLINE 命令创建的对象是轻量多段线( AcDbPolyline ),用 3DPOLY 命令创建
的对象是三维多段线( AcDb3dPolyline )。鉴于 AcDb2dPolyline 目前并不常用,本节不准备详
细讨论它。
        创建轻量多段线和三维多段线的函数,直接封装 AcDbPolyline AcDb3dPolyline 类的构
造函数即可;创建正多边形、矩形、圆形和圆环,实际上都是创建了特殊形状的轻量多段线,
创建这些对象的关键都在于顶点和凸度的确定。
3. 步骤
(1) 在CCreateEnt类中:添加一个函数 CreatePolyline,用于向模型空间添加轻量多段线.
        创建 AcDbPolyline 对象可以分成两个步骤:创建类的实例和添加顶点。
        创建类的实例, 以多段线的顶点个数作为参数调用 AcDbPolyline::AcDbPolyline 函数;
        添加顶点时,则使用了 AcDbPolyline::addVertexAt 函数,将每一个顶点添加到多段线中。
//创建轻量多段线
static AcDbObjectId CreatePolyline(AcGePoint2dArray points, double width = 0);
//创建轻量多段线
//创建 AcDbPolyline 对象可以分成两个步骤:创建类的实例和添加顶点
AcDbObjectId CCreateEnt::CreatePolyline(AcGePoint2dArray points, double width)
{
    //创建类的实例, 以多段线的顶点个数作为参数调用 AcDbPolyline::AcDbPolyline 函数;
    int numVertices = points.length(); 
    AcDbPolyline *pPoly = new AcDbPolyline(numVertices);

    for (int i = 0; i < numVertices; i++) 
    {
        //添加顶点时,则使用了 AcDbPolyline::addVertexAt 函数,将每一个顶点添加到多段线中。
        pPoly->addVertexAt(i, points.at(i), 0, width, width); 
    }
/*
    //addVertexAt 函数定义为:
    Acad::ErrorStatus addVertexAt( 
        unsigned int index,         //index 用来指定插入顶点的索引号(从 0 开始);
        const AcGePoint2d& pt,      //pt 指定顶点的位置;
        double bulge = 0.,          //bulge 指出要创建的顶点的凸度;
        double startWidth = -1.,    //startWidth 和 endWidth 指定了从该顶点到下一顶点之间连线的起始和终止线宽,
        double endWidth = -1);      //利用该特性可以使用多段线创建一个实心箭头。
*/

    AcDbObjectId polyId;
    polyId = CCreateEnt::PostToModelSpace(pPoly); 

    return polyId;
}

        凸度是多段线中一个比较难理解的概念,用于指定当前顶点的平滑性,其被定义为:在
        多段线顶点显示中,选取顶点与下一个顶点形成的弧之间角度的四分之一的正切值。凸度可
        以用来设置多段线某一段的凸出参数,0 表示直线,1 表示半圆,介于 0~1 之间为劣弧,大
        于 1 为优弧。在创建圆的函数中,你会进一步学习。

(2) 创建仅包含一条直线的多段线

//创建仅包含一条直线的多段线
static AcDbObjectId CreatePolyline(AcGePoint2d ptStart, AcGePoint2d ptEnd, double width);
//创建仅包含一条直线的多段线
AcDbObjectId CCreateEnt::CreatePolyline(AcGePoint2d ptStart, AcGePoint2d ptEnd, double width)
{
    AcGePoint2dArray points; 
    points.append(ptStart); 
    points.append(ptEnd); 
    return CreatePolyline(points, width);
}

(3) 添加一个创建三维多段线的函数

//添加一个创建三维多段线的函数
static AcDbObjectId Create3dPolyline(AcGePoint3dArray points);
//添加一个创建三维多段线的函数
AcDbObjectId CCreateEnt::Create3dPolyline(AcGePoint3dArray points)
{
    AcDb3dPolyline *pPoly3d = new AcDb3dPolyline(AcDb::k3dSimplePoly, points); 
    return CCreateEnt::PostToModelSpace(pPoly3d);

/*
    AcDb3dPolyline 类的构造函数接受了三个参数:
    第一个参数值 AcDb::k3dSimplePoly 表示创建的多段线是一个未经拟合的标准多段线;
    第二个参数值指定了创建三维多段线的顶点数组;
    第三个参数指定是否闭合多段线,这里使用了默认参数值,不在创建多段线时将其闭合。
*/
}

(4) 在 CModifyEnt 类中,添加一个函数 Rotate,按照指定的角度(用弧度值表示)旋转指定的实体.

AcDbEntity::transformBy 函数对实体进行旋转,该函数能对实体进行比例变换、移动和旋转操作,其输入参数是一个几何变换矩阵(AcGeMatrix3d 类)
AcGeMatrix3d 类用于实体的几何变换非常简单,只要使用 setToScaling setToRotation setToTranslation
三个函数设置所要进行的变换,然后对所要变换的实体执行 transformBy 函数即可。
move和scale同理.

    Acad::ErrorStatus Rotate(AcDbObjectId entId, AcGePoint2d ptBase, double rotation); //旋转实体
    Acad::ErrorStatus Move(AcDbObjectId entId, AcGePoint3d ptBase, AcGePoint3d ptDest); //移动实体
    Acad::ErrorStatus Scale(AcDbObjectId entId, AcGePoint3d ptBase, double scaleFactor); //缩放实体
//旋转实体
Acad::ErrorStatus CModifyEnt::Rotate(AcDbObjectId entId, AcGePoint2d ptBase, double rotation)
{
    CGeometryOper m_geometryOper;
    AcGeMatrix3d xform;
    AcGeVector3d vec(0, 0, 1);
    xform.setToRotation(rotation, vec, m_geometryOper.Pt2dTo3d(ptBase));

    AcDbEntity *pEnt;
    Acad::ErrorStatus es = acdbOpenObject(pEnt, entId, AcDb::kForWrite, false);
    pEnt->transformBy(xform);
    pEnt->close();

    return es;
}


//移动实体
Acad::ErrorStatus CModifyEnt::Move(AcDbObjectId entId, AcGePoint3d ptBase, AcGePoint3d ptDest)
{
    // 设置变换矩阵的参数
    AcGeMatrix3d xform; 
    AcGeVector3d vec(ptDest.x - ptBase.x, ptDest.y - ptBase.y, ptDest.z - ptBase.z); 
    xform.setToTranslation(vec); 

    AcDbEntity *pEnt; 
    Acad::ErrorStatus es = acdbOpenObject(pEnt, entId, AcDb::kForWrite, false); 
    pEnt->transformBy(xform); 
    pEnt->close(); 

    return es;
}


//缩放实体
Acad::ErrorStatus CModifyEnt::Scale(AcDbObjectId entId, AcGePoint3d ptBase, double scaleFactor)
{
    // 设置变换矩阵的参数
    AcGeMatrix3d xform; 
    xform.setToScaling(scaleFactor, ptBase); 

    AcDbEntity *pEnt; 
    Acad::ErrorStatus es = acdbOpenObject(pEnt, entId, AcDb::kForWrite, false); 
    pEnt->transformBy(xform); 
    pEnt->close(); 

    return es;
}

(5) 添加创建正多边形的函数。创建正多边形的输入参数为中心、边数、外接圆半径、 旋转角度(弧度值)和线宽

        步骤 (a)计算顶点位置;

                (b)根据顶点位置创建多段线;

                (c)闭合多段线;

                (d)旋转多段线。

        步骤(c) 是新接触到的内容。前面已经介绍过,使用 acdbOpenAcDbEntity 函数能够得到一个指向 AcDbEntity 对象的指针,但是如何将其转化为指向 AcDbPolyline 的指针,从而利用AcDbPolylien 类的函数修改其特性呢?注意下面的语句:
                        AcDbPolyline *pPoly = AcDbPolyline::cast(pEnt);
        cast 是 ObjectARX 所有类的基类 AcRxObject 中实现的一个函数,该函数提供了一种
安全的类型转换机制,这里的作用就是从基类指针 pEnt 获得派生类的指针 pPoly

    如果你想为这条语句加上一个错误处理,还可以写成这样的形式:

if (pEnt->isKindOf(AcDbPolyline::desc()) == Adesk::kTrue) 
{ 
    AcDbPolyline *pPoly = AcDbPolyline::cast(pEnt); 
    if (pPoly != NULL) 
    {
        pPoly->setClosed(Adesk::kTrue); 
    } 
}
        isKindOf 和 desc 函数提供了 ObjectARX 中一种常用的动态类型检查机制,这种方法在
ObjectARX 编程中极为常见。

代码如下:

    //添加创建正多边形的函数(中心、边数、外接圆半径、旋转角度(弧度值)和线宽)
    static AcDbObjectId CreatePolygon(AcGePoint2d ptCenter, int number, double radius, double rotation, double width);
//添加创建正多边形的函数(中心、边数、外接圆半径、旋转角度(弧度值)和线宽)
//步骤(a)计算顶点位置;(b)根据顶点位置创建多段线;(c)闭合多段线;(d)旋转多段线。
AcDbObjectId CCreateEnt::CreatePolygon(AcGePoint2d ptCenter, int number, double radius, double rotation, double width)
{
    CGeometryOper m_geometryOper;
    AcGePoint2dArray points;
    double angle = 2 * m_geometryOper.PI() / (double)number;

    //1.计算顶点位置;
    for (int i = 0; i < number; i++)
    {
        AcGePoint2d pt;
        pt.x = ptCenter.x + radius * cos(i * angle);
        pt.y = ptCenter.y + radius * sin(i * angle);
        points.append(pt);
    }

    //2.根据顶点位置创建多段线;
    AcDbObjectId polyId= CCreateEnt::CreatePolyline(points, width);
    
    //3.闭合多段线;
    AcDbEntity *pEnt;
    acdbOpenAcDbEntity(pEnt, polyId, AcDb::kForWrite);
    AcDbPolyline *pPoly = AcDbPolyline::cast(pEnt);
    if (pPoly != NULL)
    {
        pPoly->setClosed(Adesk::kTrue);
    }
    pEnt->close();

    //4.旋转多段线。
    CModifyEnt m_modifyEnt;
    m_modifyEnt.Rotate(polyId, ptCenter, rotation);

    return polyId;
}

(6) 多线段矩形(两个角点、线宽)

先在CGeometryOper类中添加取最大最小值得函数

    double Max(double a, double b);
    double Min(double a, double b);
//求最大值
double CGeometryOper::Max(double a, double b) 
{ 
    if (a > b) 
    { 
        return a; 
    } 
    else 
    { 
        return b; 
    } 
} 


//求最小值
double CGeometryOper::Min(double a, double b) 
{ 
    if (a < b) 
    { 
        return a; 
    } 
    else 
    { 
        return b; 
    } 
}

再在CCreateEnt类中添加创建矩形函数

 //矩形(两个角点、线宽)
static AcDbObjectId CreateRectangle(AcGePoint2d pt1, AcGePoint2d pt2, double width);
//矩形(两个角点、线宽)
AcDbObjectId CCreateEnt::CreateRectangle(AcGePoint2d pt1, AcGePoint2d pt2, double width)
{
    // 提取两个角点的坐标值
    double x1 = pt1.x, x2 = pt2.x; 
    double y1 = pt1.y, y2 = pt2.y; 
    // 计算矩形的角点
    CGeometryOper m_geometryOper;
    AcGePoint2d ptLeftBottom(m_geometryOper.Min(x1, x2), 
        m_geometryOper.Min(y1, y2)); 
    AcGePoint2d ptRightBottom(m_geometryOper.Max(x1, x2), 
        m_geometryOper.Min(y1, y2)); 
    AcGePoint2d ptRightTop(m_geometryOper.Max(x1, x2), 
        m_geometryOper.Max(y1, y2)); 
    AcGePoint2d ptLeftTop(m_geometryOper.Min(x1, x2), 
        m_geometryOper.Max(y1, y2)); 
    // 创建对应的多段线
    AcDbPolyline *pPoly = new AcDbPolyline(4); 
    pPoly->addVertexAt(0, ptLeftBottom, 0, width, width); 
    pPoly->addVertexAt(1, ptRightBottom, 0, width, width); 
    pPoly->addVertexAt(2, ptRightTop, 0, width, width); 
    pPoly->addVertexAt(3, ptLeftTop, 0, width, width); 
    pPoly->setClosed(Adesk::kTrue); 
    // 将多段线添加到模型空间
    AcDbObjectId polyId; 
    polyId = CCreateEnt::PostToModelSpace(pPoly); 

    return polyId;
}

(7) 多线段圆(圆心、半径和线宽)

//多线段圆(圆心、半径和线宽)
static AcDbObjectId CreatePolyCircle(AcGePoint2d ptCenter, double radius, double width);
//多线段圆(圆心、半径和线宽)
AcDbObjectId CCreateEnt::CreatePolyCircle(AcGePoint2d ptCenter, double radius, double width) 
{ 
    // 计算顶点的位置
    AcGePoint2d pt1, pt2, pt3; 
    pt1.x = ptCenter.x + radius; 
    pt1.y = ptCenter.y; 
    pt2.x = ptCenter.x - radius; 
    pt2.y = ptCenter.y; 
    pt3.x = ptCenter.x + radius; 
    pt3.y = ptCenter.y; 
    // 创建多段线
    AcDbPolyline *pPoly = new AcDbPolyline(3);
    pPoly->addVertexAt(0, pt1, 1, width, width); 
    pPoly->addVertexAt(1, pt2, 1, width, width); 
    pPoly->addVertexAt(2, pt3, 1, width, width); 
    pPoly->setClosed(Adesk::kTrue); 
    // 将多段线添加到模型空间
    AcDbObjectId polyId; 
    polyId = CCreateEnt::PostToModelSpace(pPoly); 

    return polyId; 
}

(8) 多线段圆弧(圆心、半径、起始角度、终止角度和线宽)

//多线段圆弧(圆心、半径、起始角度、终止角度和线宽)
static AcDbObjectId CreatePolyArc(AcGePoint2d ptCenter, double radius, double angleStart, double angleEnd, double width);
//多线段圆弧(圆心、半径、起始角度、终止角度和线宽)
AcDbObjectId CCreateEnt::CreatePolyArc(AcGePoint2d ptCenter, double radius, 
                                       double angleStart, double angleEnd, double width) 
{ 
    // 计算顶点的位置
    AcGePoint2d pt1, pt2; 
    pt1.x = ptCenter.x + radius * cos(angleStart); 
    pt1.y = ptCenter.y + radius * sin(angleStart); 
    pt2.x = ptCenter.x + radius * cos(angleEnd); 
    pt2.y = ptCenter.y + radius * sin(angleEnd); 

    // 创建多段线
    AcDbPolyline *pPoly = new AcDbPolyline(3);
    pPoly->addVertexAt(0, pt1, tan((angleEnd - angleStart) / 4), width, width); 
    pPoly->addVertexAt(1, pt2, 0, width, width); 

    // 将多段线添加到模型空间
    AcDbObjectId polyId; 
    polyId = CCreateEnt::PostToModelSpace(pPoly); 

    return polyId; 
}

(9) 在acrxEntryPoint.cpp中添加

ACED_ARXCOMMAND_ENTRY_AUTO(CArxConfigApp, MidasMyGroup, MyDrawPolyline, MyDrawPolyline, ACRX_CMD_MODAL, NULL) //画多段线
//当前项目中注册一个命令 AddPolyline
     static void MidasMyGroupMyDrawPolyline() 
     {
         CGeometryOper m_geometryOper;
         // 创建三维多段线
         AcGePoint3d pt1(0, 0, 0), pt2(10, 0, 0), pt3(10, 10, 0), pt4(10, 10, 10); 
         AcGePoint3dArray points; 
         points.append(pt1); 
         points.append(pt2); 
         points.append(pt3);
         points.append(pt4);
         AcDbObjectId polyline3dId; 
         polyline3dId = CCreateEnt::Create3dPolyline(points);
         //创建正多边形(中心、边数、外接圆半径、旋转角度(弧度值)和线宽)
         AcDbObjectId polygonId; 
         polygonId = CCreateEnt::CreatePolygon(AcGePoint2d::kOrigin, 6, 15, 0, 1); 
         // 创建圆
         AcGePoint2d pt5(20, 20); 
         AcDbObjectId polyCircleId; 
         polyCircleId = CCreateEnt::CreatePolyCircle(pt5, 10, 1);
         // 创建圆弧
         AcGePoint2d pt6(10, 15);
         AcDbObjectId polyArcId; 
         polyArcId = CCreateEnt::CreatePolyArc(pt6, 15, m_geometryOper.GtoR(45), m_geometryOper.GtoR(225), 1);

         CModifyEnt m_modifyEnt;
         m_modifyEnt.ChangeColor(polyline3dId, 1);
         m_modifyEnt.ChangeColor(polygonId, 1);
         m_modifyEnt.ChangeColor(polyCircleId, 1);
         m_modifyEnt.ChangeColor(polyArcId, 1);
     }

 效果展示:

(7)ObjectARX2015 + vs2012创建多段线以及实体的旋转移动放缩_第1张图片

 

你可能感兴趣的:(cad,c++)