SubErase, subOpen, subClose, and subCancel
Ф-ции erase(), open(), close(), и cancel() все имеют соответствующие виртуальные функции, начинающиеся с префиксной замены. Вы можете отменять эти вспомогательные функции, чтобы обеспечить дополнительные функциональные возможности для полученных классов. Вспомогательная функция вызвана невиртуальной “главной” функцией. Например, erase() - subErase(). Сигнатура для subErase() следующие:
virtual Acad::ErrorStatus
subErase(Adesk::Boolean pErasing);
Перегрузите вспомогательную функцию
1 Проверяют правильность вашей окрестности. Например, если ваш объект имеет жесткую ссылку указателя к другому объекту, и ваш объект не стирается, Вы можете проверять, чтобы объект, к которому Вы относите все еще, существовал. Если имеются проблемы, немедленно возвращают соответствующее состояние ошибки и не упускают сообщение, потому что ваше плохое состояние ошибки эффективно уничтожит операцию.
2, если все - OK, затем вызывает Ваше Родительское подстирание:: () функция. Исследуйте его результат. Если это не возвращает eOK, то возвращается.
3, если все - OK, затем исполняет ваши действия.
Лучше не изменить{*заменить*} любое государство{*состояние*} во вспомогательной функции. Если Вы изменили{*заменили*} государство{*состояние*}, затем пробовать изменить{*заменить*} это после вызова родительского выполнения класса той же самой функции (в случае, если код ошибки возвращен). Если Вы изменили{*заменить*} государство{*состояние*} перед вызовом родительской функции класса, то подготовлены, чтобы полностью изменить это, если родительский класс возвращает плохое состояние.
Следующий пример показывает выполнению subErase() функция, которая называется, когда объект стерт. subErase() проверяет жесткие ссылки указателя к другим объектам и стирает их также.
class AsdkEllipse : public AcDbEllipse
// Этот класс расширяет AcDbEllipse, добавляясь в функциональных возможностях
// Сохранять динамический массив жесткого объекта IDs указателя.
//
// subErase () функция элемента отменяет и
// Осуществленный, так, когда объект этого класса
// Стертый, объекты, указанные жестким указателем IDs
// Сохраненный в пределах объекта будет также стерт.
//
{
public:
ACRX_DECLARE_MEMBERS(AsdkEllipse);
AsdkEllipse() {};
AsdkEllipse(const AsdkEllipse&);
AsdkEllipse(const AcDbObjectIdArray& ellipses)
: mEllipseIds(ellipses) {};
AsdkEllipse(const AcGePoint3d& center,
const AcGeVector3d& unitNormal,
const AcGeVector3d& majorAxis,
double radiusRatio,
double startAngle = 0.0,
double endAngle = 6.28318530717958647692);
AsdkEllipse(const AcDbObjectIdArray& ellipses,
const AcGePoint3d& center,
const AcGeVector3d& unitNormal,
const AcGeVector3d& majorAxis,
double radiusRatio,
double startAngle = 0.0,
double endAngle = 6.28318530717958647692);
AcDbObjectId ellipseId(unsigned short which);
Acad::ErrorStatus setEllipseId(
const AcDbObjectId& objId, unsigned short which);
Acad::ErrorStatus setEllipseIds(
const AcDbObjectIdArray& Ids);
Acad::ErrorStatus appendId(const AcDbObjectId& objId);
Acad::ErrorStatus appendIds(
const AcDbObjectIdArray& objIds);
inline Adesk::Boolean removeId(
const AcDbObjectId& objId);
// AcDbObject overrides.
//
virtual Acad::ErrorStatus subErase(
Adesk::Boolean pErasing);
virtual Acad::ErrorStatus dwgInFields(
AcDbDwgFiler* filer);
virtual Acad::ErrorStatus dwgOutFields(
AcDbDwgFiler* filer) const;
virtual Acad::ErrorStatus dxfInFields(
AcDbDxfFiler* filer);
virtual Acad::ErrorStatus dxfOutFields(
AcDbDxfFiler* filer) const;
virtual Acad::ErrorStatus wblockClone(
AcRxObject* pOwnerObject,
AcDbObject*& pClonedObject,
AcDbIdMapping& idMap,
Adesk::Boolean isPrimary = Adesk::kTrue) const;
// AcDbEntity overrides.
//
virtual void list() const;
// AcRxObject overrides.
//
virtual AcRxObject* clone() const;
private:
AcDbObjectIdArray mEllipseIds;
static int mInFlux; // == 1 when first object’s
// subErase is active.
};
ACRX_DXF_DEFINE_MEMBERS(AsdkEllipse, AcDbEllipse,
AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent, 0, ASDKELLIPSE,
REFERENC);
// Static class data member definition.
//
int AsdkEllipse::mInFlux = Adesk::kFalse;
AsdkEllipse::AsdkEllipse(const AsdkEllipse& master)
{
set(master.center(), master.normal(),
master.majorAxis(), master.radiusRatio(),
master.startAngle(), master.endAngle());
mEllipseIds = master.mEllipseIds;
}
AsdkEllipse::AsdkEllipse(const AcGePoint3d& center,
const AcGeVector3d& unitNormal,
const AcGeVector3d& majorAxis,
double radiusRatio,
double startAngle,
double endAngle) :
AcDbEllipse(center, unitNormal, majorAxis, radiusRatio,
startAngle, endAngle)
{ }
AsdkEllipse::AsdkEllipse(const AcDbObjectIdArray& ellipses,
const AcGePoint3d& center,
const AcGeVector3d& unitNormal,
const AcGeVector3d& majorAxis,
double radiusRatio,
double startAngle,
double endAngle) :
AcDbEllipse(center, unitNormal, majorAxis, radiusRatio,
startAngle, endAngle), mEllipseIds(ellipses)
{ }
AcDbObjectId
AsdkEllipse::ellipseId(unsigned short which)
{
assertReadEnabled();
if (which > mEllipseIds.length())
return AcDbObjectId::kNull;
return mEllipseIds[which];
}
Acad::ErrorStatus
AsdkEllipse::setEllipseId(const AcDbObjectId& objId,
unsigned short which)
{
assertWriteEnabled();
if (which > mEllipseIds.length())
return Acad::eInvalidIndex;
mEllipseIds[which] = objId;
return Acad::eOk;
}
Acad::ErrorStatus
AsdkEllipse::setEllipseIds(const AcDbObjectIdArray& objIds)
{
assertWriteEnabled();
if (objIds.length() == 0)
return Acad::eNullObjectId;
mEllipseIds = objIds;
return Acad::eOk;
}
Acad::ErrorStatus
AsdkEllipse::appendId(const AcDbObjectId& objId)
{
assertWriteEnabled();
if (objId == AcDbObjectId::kNull)
return Acad::eNullObjectId;
mEllipseIds.append(objId);
return Acad::eOk;
}
Acad::ErrorStatus
AsdkEllipse::appendIds(const AcDbObjectIdArray& objIds)
{
assertWriteEnabled();
if (objIds.length() == 0)
return Acad::eNullObjectId;
mEllipseIds.append(objIds);
return Acad::eOk;
}
inline Adesk::Boolean
AsdkEllipse::removeId(const AcDbObjectId& objId)
{
assertWriteEnabled();
return mEllipseIds.remove(objId);
}
// This implementation of subErase opens and erases all
// objects that this entity has hard pointer references
// to. The effect is that when one AsdkEllipse is erased,
// all the others it has hard pointers to also erase as
// a "group".
//
Acad::ErrorStatus
AsdkEllipse::subErase(Adesk::Boolean pErasing)
{
Acad::ErrorStatus es = AcDbEllipse::subErase(pErasing);
if (es != Acad::eOk)
return es;
if (mInFlux == Adesk::kFalse) {
mInFlux = Adesk::kTrue;
AsdkEllipse *pEllipse;
int es;
for (int i = 0; i < mEllipseIds.length(); i++) {
es = acdbOpenObject(pEllipse, mEllipseIds[i],
AcDb::kForWrite, Adesk::kTrue);
if (es != Acad::eOk)
continue;
pEllipse->erase(pErasing);
pEllipse->close();
}
mInFlux = Adesk::kFalse;
}
return Acad::eOk;
}
Acad::ErrorStatus
AsdkEllipse::dwgInFields(AcDbDwgFiler* filer)
{
assertWriteEnabled();
AcDbEllipse::dwgInFields(filer);
mEllipseIds.setLogicalLength(0);
int idCount;
filer->readInt32((long*)&idCount);
AcDbHardPointerId objId;
for (int i = 0; i < idCount; i++) {
filer->readItem(&objId);
mEllipseIds.append(objId);
}
return filer->filerStatus();
}
Acad::ErrorStatus
AsdkEllipse::dwgOutFields(AcDbDwgFiler* filer) const
{
assertReadEnabled();
AcDbEllipse::dwgOutFields(filer);
filer->writeInt32(mEllipseIds.length());
for (int i = 0; i < mEllipseIds.length(); i++) {
filer->writeHardPointerId(mEllipseIds[i]);
}
return filer->filerStatus();
}
Acad::ErrorStatus
AsdkEllipse::dxfInFields(AcDbDxfFiler* filer)
{
assertWriteEnabled();
Acad::ErrorStatus es = AcDbEllipse::dxfInFields(filer);
if (es != Acad::eOk) {
return es;
}
// Check to see if we’re at the right subclass data
// marker.
//
if (!filer->atSubclassData("AsdkEllipse")) {
return Acad::eBadDxfSequence;
}
struct resbuf inbuf;
AcDbObjectId objId;
int idCount;
filer->readItem(&inbuf);
if (inbuf.restype == AcDb::kDxfInt32) {
idCount = inbuf.resval.rint;
} else {
filer->pushBackItem();
filer->setError(Acad::eInvalidDxfCode,
"\nError: expected group code %d",
AcDb::kDxfInt32);
return filer->filerStatus();
}
for (int i = 0; i < idCount; i++) {
es = filer->readItem(&inbuf);
if (es != Acad::eOk) {
filer->setError(Acad::eMissingDxfField,
"\nError: expected more group code %d’s",
AcDb::kDxfHardPointerId);
return filer->filerStatus();
}
if (inbuf.restype == AcDb::kDxfHardPointerId) {
acdbGetObjectId(objId, inbuf.resval.rlname);
mEllipseIds.append(objId);
} else {
filer->pushBackItem();
filer->setError(Acad::eInvalidDxfCode,
"\nError: expected group code %d",
AcDb::kDxfHardPointerId);
return filer->filerStatus();
}
}
return filer->filerStatus();
}
Acad::ErrorStatus
AsdkEllipse::dxfOutFields(AcDbDxfFiler* filer) const
{
assertReadEnabled();
AcDbEllipse::dxfOutFields(filer);
filer->writeItem(AcDb::kDxfSubclass, "AsdkEllipse");
filer->writeInt32(AcDb::kDxfInt32,
mEllipseIds.length());
for (int i = 0; i < mEllipseIds.length(); i++) {
filer->writeObjectId(AcDb::kDxfHardPointerId,
mEllipseIds[i]);
}
return filer->filerStatus();
}
void
AsdkEllipse::list() const
{
assertReadEnabled();
AcDbEllipse::list();
acutPrintf("\nClass:\t%s", isA()->name());
for (int i = 0; i < mEllipseIds.length(); i++) {
acutPrintf("\nReferenceId[%d]:\t%ld", i,
(mEllipseIds[i]).asOldId());
}
}
// Called whenever an object of this class is dragged,
// moved, stretched, rotated, etc. so be careful what
// this function is made to do.
//
AcRxObject*
AsdkEllipse::clone() const
{
assertReadEnabled();
return new AsdkEllipse(*this);
}
Acad::ErrorStatus
AsdkEllipse::wblockClone(
AcRxObject* pOwnerObject,
AcDbObject*& pClonedObject,
AcDbIdMapping& idMap,
Adesk::Boolean isPrimary) const
{
assertReadEnabled();
static AcDbObjectId btr, pspace = AcDbObjectId::kNull;
AcTransaction *pTrans = NULL;
pClonedObject = NULL;
if (pspace == AcDbObjectId::kNull) {
AcDbBlockTable *pTable;
database()->getSymbolTable(pTable, AcDb::kForRead);
pTable->getAt(ACDB_PAPER_SPACE, pspace);
pTable->close();
}
if ( idMap.deepCloneContext() == AcDb::kDcXrefBind && ownerId() == pspace)
return Acad::eOk;
// Have we already done this entity ?
//
AcDbIdPair idPair(objectId(), (AcDbObjectId)NULL, Adesk::kTrue);
if (idMap.compute(idPair) == TRUE && idPair.value() != NULL)
{
pClonedObject = NULL;
return Acad::eOk;
}
AcDbBlockTableRecord *pBTR = AcDbBlockTableRecord::cast(pOwnerObject);
if (pBTR != NULL) {
if (isPrimary == Adesk::kTrue)
btr = pBTR->objectId();
else
btr = AcDbObjectId::kNull;
} else if (btr != AcDbObjectId::kNull) {
pTrans = actrTransactionManager->startTransaction();
pTrans->getObject((AcDbObject*&)pBTR, btr,
AcDb::kForWrite);
pOwnerObject = pBTR;
}
Acad::ErrorStatus es = AcDbEllipse::wblockClone(pOwnerObject,
pClonedObject, idMap, btr != AcDbObjectId::kNull);
if (pTrans)
actrTransactionManager->endTransaction();
acutPrintf("\nWblockClone error status: %s",
acadErrorStatusText(es));
return Acad::eOk;
}
void
createEllipses()
{
const ellipseCount = 10;
AsdkEllipse *pEllipse;
pEllipse = new AsdkEllipse(AcGePoint3d(4.0, 4.0, 0.0),
AcGeVector3d(0.0, 0.0, 1.0),
AcGeVector3d(2.0, 0.0, 0.0),
0.5);
AcDbVoidPtrArray ellipses;
ellipses.append(pEllipse);
// Now use the getTransformedCopy() function with a
// scaling matrix (in X & Y only) to create new
// AsdkEllipses, each 0.5 units larger than the last in
// the X & Y direction, but identical in the Z
// direction. This would be similar to the
// getOffsetCurves() function, but that function
// returns AcDbSpline entities instead of AcDbEllipses.
//
double j = 1.1;
AcGeMatrix3d scale;
for (int i = 0; i < ellipseCount; i++, j += 0.1) {
scale.setToScaling(j, pEllipse->center());
scale.entry[2][2] = 1.0; // Z scaling == 1
// getTransformed copy uses this->clone() to create
// a new object, which the ent pointer is assigned
// to point to. Therefore, ent should NOT point to an
// existing entity or there will be a memory leak!
//
// Since this->clone() is used, the AsdkEllipse class
// must override this member function to
// be sure that an AsdkEllipse is created instead
// of just an AcDbEllipse.
//
AsdkEllipse *pNextEllipse;
((AsdkEllipse*)ellipses[0])->getTransformedCopy(
scale, (AcDbEntity*&)pNextEllipse);
ellipses.append(pNextEllipse);
}
AcDbBlockTable *pBlockTable;
acdbHostApplicationServices()->workingDatabase()
->getSymbolTable(pBlockTable, AcDb::kForRead);
AcDbBlockTableRecord *pBlockTableRecord;
pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord,
AcDb::kForWrite);
pBlockTable->close();
AcDbObjectIdArray ellipseIds;
AcDbObjectId tempId;
for (i = 0; i < ellipses.length(); i++) {
pBlockTableRecord->appendAcDbEntity(tempId,
(AsdkEllipse*)ellipses[i]);
ellipseIds.append(tempId);
}
pBlockTableRecord->close();
// Set up the hard pointers and close the ellipses.
//
for (i = 0; i < ellipses.length(); i++) {
// Add in all the IDs.
//
((AsdkEllipse*)ellipses[i])
->setEllipseIds(ellipseIds);
// Now remove the object ID of the "*this" ellipse
// so it doesn’t reference itself.
//
((AsdkEllipse*)ellipses[i])->removeId(
((AsdkEllipse*)ellipses[i])->objectId());
((AsdkEllipse*)ellipses[i])->close();
}
}
void
initApp()
{
acedRegCmds->addCommand("ASDK_ELLIPSES",
"ASDK_ELLIPSES", "ELLIPSES",
ACRX_CMD_MODAL, createEllipses);
AsdkEllipse::rxInit();
acrxBuildClassHierarchy();
}
void
unloadApp()
{
acedRegCmds->removeGroup("ASDK_ELLIPSES");
// Remove the AsdkEllipse class from the ACRX runtime
// class hierarchy. If this is done while the database is
// still active, it should cause all objects of class
// AsdkEllipse to be turned into proxies.
//
deleteAcRxClass(AsdkEllipse::desc());
}
extern "C" AcRx::AppRetCode
acrxEntryPoint(AcRx::AppMsgCode msg, void* appId)
{
switch (msg) {
case AcRx::kInitAppMsg:
acrxDynamicLinker->unlockApplication(appId);
acrxDynamicLinker->registerAppMDIAware(appId);
initApp();
break;
case AcRx::kUnloadAppMsg:
unloadApp();
}
return AcRx::kRetOK;
}