(41)ObjectARX2015 + vs2012 JIG-基本的拖动

1. 说明

        拖动效果在AutoCAD中被广泛应用, 他在创建/修改实体时具有所见即所得的特点.本节介绍AutoCAD提供的最基本的Jig实现, 采用的例子是用拖动的方式来创建一个正方形.

2. 思路

        实现Jig效果的核心是创建AcedJig类的一个子类,重写其中的几个虚函数sampler、update 和 entity,以及实现自己需要的效果,他们的作用如下:

(1) sampler(取样器): 将被AcEd::drag() 函数调用以获得用户输入(用户输入点、角度等).

(2) update: 更新实体,以反映在用户输入变换的过程中,图形中的实体需要发生怎样的变化.

(3) entity: 返回一个实体的指针,告诉AutoCAD哪个实体在被改变.

        除此之外,一般会在子类中添加一个成员函数doIt(函数名称和变量都根据你的需求来确定),这个函数将被命令实现的函数所调用,对Jig对象进行初始化.

3. 步骤

(1) 创建一个新类 CDrawSquierJig ,父类设置为 ACEdJig

class CDrawSquareJig : public AcEdJig
{
public:
    CDrawSquareJig(void);
    virtual ~CDrawSquareJig(void);

public:
    // 外部调用的函数,一般用于 Jig 的初始化
    bool doIt();

    // 此函数将被 drag 函数调用以获得用户输入
    virtual AcEdJig::DragStatus sampler();

    // 对需要在拖动过程中发生变化的实体进行修改
    virtual Adesk::Boolean update();

    // 指定了Jig 所操作的对象
    virtual AcDbEntity* entity() const;


};

(2) 分析Jig的行为, 添加需要的成员变量. 先添加两个必须的成员变量, m_pPoly, m_curPoint, 考虑到在拖动过程中需要连续变化的是正方形的大小, 但是他的中心点是固定不变的, 因此还需要一个成员变量m_centerPoint, 并且他的值需要通过 doIt 函数传递进来,由此, 在类的头文件中需要添加三个私有成员变量, 并且完善了 doIt函数的声明部分.

class CDrawSquareJig : public AcEdJig
{
public:
    CDrawSquareJig(void);
    virtual ~CDrawSquareJig(void);

public:
    // 外部调用的函数,一般用于 Jig 的初始化
    bool doIt(const AcGePoint3d &centerPoint, AcDbObjectId &polyId));

    // 此函数将被 drag 函数调用以获得用户输入
    virtual AcEdJig::DragStatus sampler();

    // 对需要在拖动过程中发生变化的实体进行修改
    virtual Adesk::Boolean update();

    // 指定了Jig 所操作的对象
    virtual AcDbEntity* entity() const;

private:
    AcDbPolyline* m_pPoly;      // 拖动过程中动态变化的实体
    AcGePoint3d m_curPoint;     // 存储用户光标移动时点的临时位置
    AcGePoint3d m_centerPoint;  // 正方形的中心点
};

(3) 在 CDrawSquierJig 类的构造函数中,需要对指针类型的成员变量进行初始化;

CDrawSquareJig::CDrawSquareJig(void)
{
    m_pPoly = NULL; //初始化
}

(4) 添加 doIt 函数的实现代码

        doIt 体现了拖动操作的三个步骤:

                A. 拖动开始之前,创建拖动需要的实体和成员变量

                B. 显示命令行提示,执行那个drag函数进行拖动流程

                C. 拖动完成,函数在退出之前进行特定的操作

// 外部调用的函数,一般用于 Jig 的初始化
bool CDrawSquareJig::doIt(const AcGePoint3d &centerPoint, AcDbObjectId &polyId)
{
    m_centerPoint = centerPoint;

    // 拖动之前: 将多段线创建出来
    m_pPoly = new AcDbPolyline();
    for (int i = 0; i < 4; i++) // 将四个顶点连接,形成一个矩形
    {
        m_pPoly->addVertexAt(i, ToPoint2d(m_centerPoint));
    }
    m_pPoly->setClosed(Adesk::kTrue); // 闭合顶点

    // 进入拖动流程
    CString prompt = _T("\n指定标注插入点: ");
    setDispPrompt(prompt); //使用一种dispPrompt 的拷贝作为后续的拖拽操作的新提示字符串。
    AcEdJig::DragStatus stat = drag();

    // 拖动结束: 函数返回部分
    CCreateEnt m_createEnt;
    if (stat == kNormal)
    {
        polyId = m_createEnt.PostToModelSpace(m_pPoly);
        return true;
    }
    else
    {
        delete m_pPoly;
        return false;
    }
}

// 转换为二维点
AcGePoint2d CDrawSquareJig::ToPoint2d(const AcGePoint3d &point3d)
{
    return AcGePoint2d(point3d.x, point3d.y);
}

(5) sampler()函数: 他在拖动过程中收集用户输入信息并更新到成员变量

在用户移动光标的过程中,sampler函数会不断被调用

// 此函数将被 drag 函数调用以获得用户输入
AcEdJig::DragStatus CDrawSquareJig::sampler()
{
    setUserInputControls((UserInputControls)( AcEdJig::kAccept3dCoordinates
                                            | AcEdJig::kNoNegativeResponseAccepted
                                            | AcEdJig::kNullResponseAccepted ));

    // 一定要判断一下点是否发生了变化,否则update函数不停地被调用,实体反而不能被绘制出来
    static AcGePoint3d pointTemp;
    DragStatus stat = acquirePoint(m_curPoint);
    if (pointTemp != m_curPoint)
    {
        pointTemp = m_curPoint;
    }
    else if (stat == AcEdJig::kNormal)
    {
        return AcEdJig::kNoChange;
    }
    return stat;
}
//关于setUserInputControls函数:
//设置用户输入控制属性。
void setUserInputControls(
    AcEdJig::UserInputControls
    );
AcEdJig::kAccept3dCoordinates	// 设置“接受Z坐标”模式。默认情况下,输入被限制为2d输入。
AcEdJig::kNoNegativeResponseAccepted	// 设置“不接受负值”模式。默认值接受负值。这适用于获取函数()和获取角()
AcEdJig::kNullResponseAccepted	//设置用户输入请求包的“接受空输入”位。默认情况下btit是已知的,不接收null输入

(6) update()函数

// 在sampler函数后被调用,他才是真正的更新实体的地方
Adesk::Boolean CDrawSquareJig::update()
{
    //实现你的更新操作,在这里更新的是m_pPoly
    double dist = ToPoint2d(m_centerPoint).distanceTo(ToPoint2d(m_curPoint));
    for (int i = 0; i < 4; i++)
    {
        double angle = i * CGeometryOper::PI() * 0.5 + CGeometryOper::PI() *0.25;
        AcGePoint2d pt = CGeometryOper::PolarPoint(ToPoint2d(m_centerPoint), angle, dist);
        m_pPoly->setPointAt(i, pt);
    }

    return Adesk::kTrue;
}

重载极坐标函数

    static AcGePoint2d PolarPoint(const AcGePoint2d& basePoint, double angle, double length); //重载极坐标
//根据相对极坐标来确定一个点的位置
AcGePoint2d CGeometryOper::PolarPoint(const AcGePoint2d& basePoint, double angle, double length)
{
    double x = basePoint.x + length * cos(angle);
    double y = basePoint.y + length * sin(angle);

    return AcGePoint2d(x, y);
}

(7) entity() 函数

// 告诉AutoCAD哪个实体发生了变化,这里发生变化的是m_pPoly对象
AcDbEntity* CDrawSquareJig::entity() const
{
    return m_pPoly;
}

(8)  实现绘制

    // 实现绘制
    static void DrawSequareJig();
void CDrawSquareJig::DrawSequareJig()
{
    //提示用户输入中心点
    AcGePoint3d centerPoint;
    if (CDrawSquareJig::GetPoint(_T("\n指定正方形的中心点:"), centerPoint))
    {
        //进入拖动状态
        CDrawSquareJig jig;
        AcDbObjectId polyId;
        if (jig.doIt(centerPoint, polyId))
        {
            //成功创建之后,可以进行其他的修改
            CDrawSquareJig::SetColor(polyId, 1);
        }
        else
        {
            //用户取消,删除已经创建的实体
            CDrawSquareJig::Erase(polyId);
        }
    }

用到的函数

    static bool GetPoint(const TCHAR* prompt, AcGePoint3d &point);
    static int GetPointReturnCode(const TCHAR* prompt, AcGePoint3d &point);
    static AcGePoint3d UcsToWcsPoint(const AcGePoint3d &point);
    static void CDrawSquareJig::SetColor(AcDbObjectId entId, int colorIndex);
    
    //删除已经被创建出来的实体
    static void Erase(AcDbObjectId entId);
// 如果Jig中用户取消了操作,就要删除已经被创建出来的实体
void CDrawSquareJig::Erase(AcDbObjectId entId)
{
    AcDbEntity *pEnt = NULL;
    if (acdbOpenObject(pEnt, entId, AcDb::kForWrite) == Acad::eOk)
    {
        pEnt->erase();
        pEnt->close();
    }
}

bool CDrawSquareJig::GetPoint(const TCHAR* prompt, AcGePoint3d &point)
{
    return (GetPointReturnCode(prompt, point) == RTNORM);
}

int CDrawSquareJig::GetPointReturnCode(const TCHAR* prompt, AcGePoint3d &point)
{
    int nReturn = acedGetPoint(NULL, prompt, asDblArray(point));
    if (nReturn == RTNORM)
    {
        point = CDrawSquareJig::UcsToWcsPoint(point);
    }

    return nReturn;
}


AcGePoint3d CDrawSquareJig::UcsToWcsPoint(const AcGePoint3d &point)
{
    // 转换成世界坐标	
    AcGePoint3d pt;
    struct resbuf rbFrom, rbTo;
    rbFrom.restype = RTSHORT;
    rbFrom.resval.rint = 1; // from UCS
    rbTo.restype = RTSHORT;
    rbTo.resval.rint = 0; // to WCS

    acedTrans(asDblArray(point), &rbFrom, &rbTo, Adesk::kFalse, asDblArray(pt));

    return pt;
}

void CDrawSquareJig::SetColor(AcDbObjectId entId, int colorIndex)
{
    // 检测参数的有效性
    assert(colorIndex >= 0 && colorIndex <= 256);

    AcDbEntity *pEnt = NULL;
    if (acdbOpenObject(pEnt, entId, AcDb::kForWrite) == Acad::eOk)
    {
        pEnt->setColorIndex(colorIndex);
        pEnt->close();
    }
}

(9) 在acrxEntryPoint.cpp中

ACED_ARXCOMMAND_ENTRY_AUTO(CArxConfigApp, MidasMyGroup, MyDrawSequareJig, MyDrawSequareJig, ACRX_CMD_MODAL, NULL) //选择实体
    //当前项目中注册命令 DrawSequareJig(添加多个实体)
    static void MidasMyGroupMyDrawSequareJig()
    {
        CDrawSquareJig::DrawSequareJig();
    }

效果展示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值