• ObjectARX完美实现一次拖动多个实体(上)


     ObjectARX完美实现一次拖动多个实体(上)

    我们知道,在ObjectARX中可以通过派生AcEdJig类来实现拖动过程。通常派生一个AcEdJig类必须重载以下三个成员函数:

        AcEdJig::sampler(),它获取几何值(角度、距离、点等)

        AcEdJig::update(),它分析几何值并且存储该值或更新实体

        AcEdJig::entity(),它返回要更新的实体的指针

      但在使用过程中发现有一个问题,就是AcEdJig::entity()只能返回单个实体的指针,也就是说使用AcEdJig类的派生类来实现拖动循环原则上只适用于单个实体,要使其适用于拖动多个实体,就不得不进行某些变通的处理。例如要对若干个新建的实体使用拖动,一种变通方法就是把新建的实体先加入CAD的数据库,在拖动过程中(即update()中)使用AcD::kForWrite模式打开并更新实体然后关闭。拖动结束后根据返回情况决定是保留还是删除实体。这样做显得很麻烦,一是要对新生成的实体作区别处理,entity()返回的实体和"其它"实体;二是先把实体加入数据库,然后再决定是否删除不应该是一种推荐的方式,总感觉有那么点不自在;拖动过程中频繁地用写方式打开实体也应该避免;而且这种方式并不适用数据库中已存在的实体,因为一旦取消拖动过程,实体可能已经不处在原来的位置了,当然可以通过复制临时实体的方式解决,但这就进一步使问题复杂化了。

      既然AcEdJig::entity()只能返回一个实体,最好的办法当然是从这个实体上入手了,我们使用一个自定义的临时实体,完美解决了这个问题,今天先来看新建实体的例子:

      先定义临时实体:

    //辅助实体类
    class CMultiCircleJigEntity : public AcDbEntity
    {
    public:
    CMultiCircleJigEntity(const AcGePoint3d & centerPoint, const unsigned int &iNum);
    ~CMultiCircleJigEntity();
    virtual Adesk::Boolean worldDraw (AcGiWorldDraw *mode);
    void setRadius(double dRadius);
    void appendToCurrentSpace();
    private:
    AcArray<AcDbCircle *> m_CircArr;
    };
    CMultiCircleJigEntity::CMultiCircleJigEntity(const AcGePoint3d & centerPoint, const unsigned int &iNum)
    {
    AcDbCircle *pCirc;
    for (int i = 0; i < iNum; i++)
    {
    pCirc = new AcDbCircle(centerPoint, AcGeVector3d::kZAxis, 1.0);
    m_CircArr.append(pCirc);
    }
    }
    CMultiCircleJigEntity::~CMultiCircleJigEntity()
    {
    for (int i = 0; i < m_CircArr.length(); i++)
    {
    delete m_CircArr[i];
    }
    }
    Adesk::Boolean CMultiCircleJigEntity::worldDraw(AcGiWorldDraw *mode)
    {
    for (int i = 0; i < m_CircArr.length(); i++)
    {
    mode ->geometry().draw(m_CircArr[i]);
    }
    return (AcDbEntity::worldDraw (mode)) ;
    }
    inline void CMultiCircleJigEntity::setRadius(double dRadius)
    {
    if (m_CircArr.length() <= 0)
    return;
    double dCurRadius = dRadius;
    double dRadiusStep = dRadius / m_CircArr.length();

    for (int i = 0; i < m_CircArr.length(); i++)
    {
    m_CircArr[i] ->setRadius(dCurRadius);
    dCurRadius -= dRadiusStep;
    }
    }
    void CMultiCircleJigEntity::appendToCurrentSpace()
    {
    AcDbDatabase * pDb = acdbCurDwg();
    AcDbBlockTable * pBlockTable;
    pDb ->getBlockTable(pBlockTable, AcDb::kForRead);
    AcDbBlockTableRecord *pBlkRec;
    if (pDb ->tilemode())
    {
    pBlockTable ->getAt(ACDB_MODEL_SPACE, pBlkRec, AcDb::kForWrite);
    }
    else
    {
    pBlockTable ->getAt(ACDB_PAPER_SPACE, pBlkRec, AcDb::kForWrite);
    }
    pBlockTable ->close();
    for (int i = 0; i < m_CircArr.length(); i++)
    {
    AcDbCircle *& pCirc = m_CircArr.at(i);
    if (Acad::eOk == pBlkRec ->appendAcDbEntity(pCirc))
    {
    pCirc ->setDatabaseDefaults();
    pCirc ->close();
    }
    else
    {
    delete pCirc;
    }
    }
    pBlkRec ->close();
    m_CircArr.removeAll();
    }

    再实现AcEdJig派生类:

    //jig类
    class CMultiCircJig : public AcEdJig
    {
    public:
    CMultiCircJig(const AcGePoint3d & centerPoint, const unsigned int &iNum);
    void doIt();
    virtual DragStatus sampler();
    virtual Adesk::Boolean update();
    virtual AcDbEntity* entity() const;
    private:
    CMultiCircleJigEntity *m_pEnt;
    AcGePoint3d m_CenterPoint;
    double m_dRadius;
    unsigned int m_NumCircles;
    };
    CMultiCircJig::CMultiCircJig(const AcGePoint3d ¢erPoint, const unsigned int & iNum) : m_CenterPoint(centerPoint), m_NumCircles(iNum)
    {
    }
    AcEdJig::DragStatus CMultiCircJig::sampler()
    {
    static double dTempRadius;
    DragStatus stat = acquireDist(m_dRadius, m_CenterPoint);
    if (dTempRadius != m_dRadius)
    {
    dTempRadius = m_dRadius;
    }
    else if (stat == AcEdJig::kNormal)
    {
    return AcEdJig::kNoChange;
    }
    return stat;
    }
    Adesk::Boolean CMultiCircJig::update()
    {
    m_pEnt ->setRadius(m_dRadius);
    return Adesk::kTrue;
    }
    AcDbEntity * CMultiCircJig::entity() const
    {
    return m_pEnt;
    }
    void CMultiCircJig::doIt()
    {
    m_pEnt = new CMultiCircleJigEntity(m_CenterPoint, m_NumCircles);
    setDispPrompt(_T("/n半径: "));
    if (drag() == AcEdJig::kNormal)
    {
    m_pEnt ->appendToCurrentSpace();
    }

    delete m_pEnt;
    }

    最后是测试命令:

    static void MyJig_njj(void)
    {
    int iNum = 5;
    acedInitGet( RSG_NOZERO | RSG_NONEG, NULL );
    int err = acedGetInt(_T("/n同心圆个数(1-100)<5>:"), &iNum);
    if (err == RTCAN || iNum < 1 || iNum > 100)
    {
    return;
    }
    AcGePoint3d centerPoint;
    if (RTNORM == acedGetPoint(NULL, _T("/n圆心"), asDblArray(centerPoint)))
    {
    CMultiCircJig * pJig = new CMultiCircJig(centerPoint, iNum);
    pJig ->doIt();
    delete pJig;
    }
    }

    ObjectARX完美实现一次拖动多个实体(下)

       这次我们来实现一次拖动多个数据库中已存在的实体,就象AuoCAD里的Move、Rotate、Mirror等命令一样。其中的临时实体类具有一定的通用性,只要给它传入不同的变换矩阵就能实现相应的功能。而Jig类的例子则是一个简单的移动示例,大约相当于Move命令的简化版。

        临时实体类:

    //辅助实体类
    //适用于拖动数据库中已经存在的实体,通常是一个选择集选择的实体集
    class CDatabaseJigEntity : public AcDbEntity
    {
    public:
    CDatabaseJigEntity(const AcDbObjectIdArray & ids) : m_Ids(ids){}
    ~CDatabaseJigEntity(){}
    virtual Adesk::Boolean worldDraw (AcGiWorldDraw *mode);
    void setXform(const AcGeMatrix3d & xform){ m_Xform = xform; }
    BOOL transform();
    BOOL transformedCopy();
    private:
    AcDbObjectIdArray m_Ids; //保存所有拖动对象的ID
    AcGeMatrix3d m_Xform;//变换矩阵
    };
    Adesk::Boolean CDatabaseJigEntity::worldDraw(AcGiWorldDraw *mode)
    {
    //这个地方是关键!
    mode->geometry().pushModelTransform(m_Xform);
    AcDbEntity* pEnt;
    for (int i = 0; i < m_Ids.length(); i++)
    {
    //绘制实体无需写打开
    if (Acad::eOk == acdbOpenObject(pEnt, m_Ids[i],AcDb::kForRead))
    {
    mode->geometry().draw(pEnt);
    pEnt->close();
    }
    }
    //这句不能少,恢复现场
    mode->geometry().popModelTransform();
    return (AcDbEntity::worldDraw (mode)) ;
    }
    //用于拖动结束后,将实体变换到新位置
    BOOL CDatabaseJigEntity::transform()
    {
    AcTransaction * pTrans = acTransactionManagerPtr() ->startTransaction();
    if (NULL == pTrans)
    return FALSE;
    AcDbEntity *pEnt;
    AcDbObject *pObj;
    for (int i= 0; i < m_Ids.length(); i++)
    {
    if (Acad::eOk != pTrans ->getObject(pObj, m_Ids[i], AcDb::kForWrite))
    {
    acTransactionManagerPtr() ->abortTransaction();
    return FALSE;
    }
    pEnt = AcDbEntity::cast(pObj);
    pEnt ->transformBy(m_Xform);
    }
    acTransactionManagerPtr() ->endTransaction();
    return TRUE;
    }
    //用于拖动结束后,将实体复制到新位置
    BOOL CDatabaseJigEntity::transformedCopy()
    {
    AcTransaction * pTrans = acTransactionManagerPtr() ->startTransaction();
    if (NULL == pTrans)
    return FALSE;
    AcDbEntity *pEnt;
    AcDbEntity *pNewEnt;
    AcDbObject *pObj;
    AcDbBlockTableRecord *pBlkRec;
    AcDbObjectId blkRecId;
    for (int i= 0; i < m_Ids.length(); i++)
    {
    if (Acad::eOk != pTrans ->getObject(pObj, m_Ids[i], AcDb::kForRead))
    {
    acTransactionManagerPtr() ->abortTransaction();
    return FALSE;
    }
    pEnt = AcDbEntity::cast(pObj);
    if (0 == i)
    {
    blkRecId = pEnt ->blockId();
    if (Acad::eOk != pTrans ->getObject(pObj, blkRecId, AcDb::kForWrite))
    {
    acTransactionManagerPtr() ->abortTransaction();
    return FALSE;
    }
    pBlkRec = AcDbBlockTableRecord::cast(pObj);
    }
    pEnt ->getTransformedCopy(m_Xform, pNewEnt);
    pBlkRec ->appendAcDbEntity(pNewEnt);
    acTransactionManagerPtr() ->addNewlyCreatedDBRObject(pNewEnt);
    }
    acTransactionManagerPtr() ->endTransaction();
    return TRUE;
    }

    用于移动的Jig类

    //移动实体的拖动类
    class CMoveJig : public AcEdJig
    {
    public:
    CMoveJig(const AcGePoint3d & fromPoint) : m_pEnt(NULL), m_FromPoint(fromPoint), m_ToPoint(fromPoint){}
    ~CMoveJig();
    void doIt(const AcDbObjectIdArray & ids, bool bCopy = false);
    virtual DragStatus sampler();
    virtual Adesk::Boolean update();
    virtual AcDbEntity* entity() const;
    private:
    CDatabaseJigEntity *m_pEnt;
    AcGePoint3d m_FromPoint;
    AcGePoint3d m_ToPoint;
    AcGeMatrix3d m_Xform;
    };
    CMoveJig::~CMoveJig()
    {
    if ( NULL != m_pEnt)
    {
    delete m_pEnt;
    m_pEnt = NULL;
    }
    }
    AcEdJig::DragStatus CMoveJig::sampler()
    {
    DragStatus stat;
    setUserInputControls((UserInputControls)
    (AcEdJig::kAccept3dCoordinates
    | AcEdJig::kNoNegativeResponseAccepted
    | AcEdJig::kNoZeroResponseAccepted
    | AcEdJig::kNullResponseAccepted ));
    static AcGePoint3d pointTemp;
    stat = acquirePoint(m_ToPoint, m_FromPoint);
    if (pointTemp != m_ToPoint)
    pointTemp = m_ToPoint;
    else if (stat == AcEdJig::kNormal)
    stat = AcEdJig::kNoChange;
    return stat;
    }
    Adesk::Boolean CMoveJig::update()
    {
    m_Xform.setToTranslation(m_ToPoint - m_FromPoint);
    m_pEnt ->setXform(m_Xform);
    return Adesk::kTrue;
    }
    AcDbEntity * CMoveJig::entity() const
    {
    return m_pEnt;
    }
    void CMoveJig::doIt(const AcDbObjectIdArray &ids, bool bCopy /*= false*/)
    {
    if ( 0 == ids.length() )
    {
    return;
    }
    if (NULL != m_pEnt)
    {
    delete m_pEnt;
    m_pEnt = NULL;
    }

    m_pEnt = new CDatabaseJigEntity(ids);
    setDispPrompt(_T("/n移动到: "));
    if ( AcEdJig::kNormal == drag() )
    {
    if (bCopy)
    {
    m_pEnt ->transformedCopy();
    }
    else
    {
    m_pEnt ->transform();
    }
    }
    delete m_pEnt;
    m_pEnt = NULL;
    }

    测试命令:

    static void ZDXMyJig_jigmove(void)
    {
    ads_name ename;
    ads_point pt;
    ads_name ss;
    int rt;

    if (rt = acedSSGet(NULL, NULL, NULL, NULL, ss) == RTCAN)
    return;
    long len;
    acedSSLength(ss, &len);
    if (0 == len) return;

    AcDbObjectId id;
    //acdbGetObjectId(id,ename);
    AcDbObjectIdArray ids;
    for (int i = 0; i < len; i++)
    {
    acedSSName(ss, i , ename);
    acdbGetObjectId(id, ename);
    ids.append(id);
    }
    acedSSFree(ss);
    acedGetPoint(NULL, L"/n起点:", pt);

    CMoveJig * pJig = new CMoveJig(asPnt3d(pt));
    pJig ->doIt(ids);
    }

  • 相关阅读:
    成长历程
    读书笔记javascript基本数据类型
    箭头函数
    sql server管理 这些你懂吗?
    索引的创建原则
    VisualStudio2012新特性[路边社通稿]
    第一节 MongoDB介绍及下载与安装
    sql server复灾 你懂了吗?
    错误处理:......标记为系统必备,必须对其进行强签名 收藏
    那么什么是好的代码呢?
  • 原文地址:https://www.cnblogs.com/mjgw/p/12392552.html
Copyright © 2020-2023  润新知