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);
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM