ObjectARX
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Problem with copyclip pastclip of custom entity that store hardpointerId

24 REPLIES 24
Reply
Message 1 of 25
MichalSzkocja
1850 Views, 24 Replies

Problem with copyclip pastclip of custom entity that store hardpointerId

In my ObjectArx app I have an object A that is derived from AcDbObject and an object B derived from AcDbEntity  that store the hardpointerId of the object A.  Obejct A stores some properties for the object B such us colour. The application works in the way that if property of object A is changed  all the objects that store its id reflect the change (Similar way to layher – all objects that belong to particular Layher change colour). Application works fine when I use copy but problem is when copyclip and pastclip is used. For some reason after pasteclip the hardpointerId does not point to object A. I know that copyclip/pasteclip function use combination of wblokclone, deepclone and dwgfillin and dwgfillout. However I don’t know how to implement them in the way copy and copyclip/pastclip will work. It would be great to see an example.

Thaks

24 REPLIES 24
Message 2 of 25
artc2
in reply to: MichalSzkocja

When you copyclip, object B is wblocked so a copy of it is created in a new database, and since it has a hard pointer to object A, object A will also be wblocked so a copy of it will be created in that same new database and the copy of object B will be set to have a hard pointer to the copy of object A.  Now, when you pasteclip, the copies of the two objects are cloned into the database being pasted into, so you end up with a copy of a copy of object B pointing to a copy of a copy of object A.

Message 3 of 25
MichalSzkocja
in reply to: artc2

Why a pasted object B is pointing to a null object A?

 

What will happen if I pasteclip object B to the same database (that already contain object A)? 

Can I stop wblockclone to make new object A if a destination for object B is same database?

 

Is there any other way to solve my problem?

How forexample AcDbTextStyle is implemented?

Message 4 of 25
artc2
in reply to: MichalSzkocja

I'd have to see your code to see what's going on.  Also, what is the owner of your object A?

 

There are several ways to control what gets cloned and how things get hooked up.  For each database, does each object B have a hard pointer to the same object A, or does each object B have a hard poitner to a different object A?

 

Message 5 of 25
MichalSzkocja
in reply to: artc2

Thaks for your quick replay

 

The owner of object A is Named Objects Dictionary.

 

I would like each object B had a hard pointer to the same object A. The reason of that is all object B must have completly same properties that are stored in object A and if any property of object A is changed all objects B would be modified to reflect the change, so there is no need to store completly same objects in the database for each object B. Is this possible?

 

Message 6 of 25
MichalSzkocja
in reply to: artc2

Have you got any idea to solve the problem?

 

Regards,

Michal

Message 7 of 25
owenwengerd
in reply to: MichalSzkocja

Did you miss the first sentence in Art's reply? It would be best if you can create a new standalone custom object project that reproduces the problem with minimal code.

--
Owen Wengerd
ManuSoft
Message 8 of 25
michalpawelak
in reply to: owenwengerd

#if defined(_DEBUG) && !defined(AC_FULL_DEBUG)
#error _DEBUG should not be defined except in internal Adesk debug builds
#endif

#include <adslib.h>
#include <dbelipse.h>
#include <gemat3d.h>
#include <dbsymtb.h>
#include <dbapserv.h>
#include <aced.h>
#include <actrans.h>
#include <dbidmap.h>
#include <acestext.h>
#include "tchar.h"
#include <atlstr.h>
#include "dbobjptr.h"
#include "dbobjptr2.h"
#include "acutmem.h"
#include "dbxutil.h"
#include "dbcfilrs.h"
#define acdbCurDwg acdbHostApplicationServices()->workingDatabase
#define ASCL_LIB							ACRX_T("Libraries") 
#define ASCL_LIB_PROP						ACRX_T("Libraries>>Properties") 
#define ASCL_LIB_PROP_PROP1					ACRX_T("Libraries>>Properties>>Prop_1") 


class AsclPropComponentII : public AcDbObject {
public:
	ACRX_DECLARE_MEMBERS(AsclPropComponentII) ;
protected:
	static Adesk::UInt32 kCurrentVersionNumber ;

public:
	AsclPropComponentII () ;
	virtual ~AsclPropComponentII () ;
	virtual Acad::ErrorStatus dwgOutFields (AcDbDwgFiler *pFiler) const ;
	virtual Acad::ErrorStatus dwgInFields (AcDbDwgFiler *pFiler) ;
	double radius() const;
	Acad::ErrorStatus setRadius(double radius);
private:
	double m_radius;
} ;

class MyEntity : public AcDbEntity{
public:
    ACRX_DECLARE_MEMBERS(MyEntity);
    MyEntity() {};
    MyEntity(AcGePoint3d stPos, AcGePoint3d enPos, const AcDbObjectId propertyId): m_propertyId(propertyId), m_start(stPos), m_end(enPos) {};
	virtual ~MyEntity () {};

	AcDbObjectId componentPropertyId() const;
	void setComponentPropertyId(const AcDbObjectId& newPropId);

    virtual Acad::ErrorStatus dwgInFields(AcDbDwgFiler* filer);
    virtual Acad::ErrorStatus dwgOutFields(AcDbDwgFiler* filer) const;

	virtual void modified (const AcDbObject *pDbObj) ;

protected:
	virtual void subViewportDraw (AcGiViewportDraw *mode) ;
	virtual Adesk::Boolean subWorldDraw (AcGiWorldDraw *mode) ;

	virtual Acad::ErrorStatus subTransformBy(const AcGeMatrix3d& xform);

protected:
	virtual Acad::ErrorStatus subDeepClone  (AcDbObject* pOwnerObject, AcDbObject*& pClonedObject, AcDbIdMapping &idMap, Adesk::Boolean isPrimary = true) const ;
    virtual Acad::ErrorStatus subWblockClone(AcRxObject* pOwnerObject, AcDbObject*& pClonedObject, AcDbIdMapping &idMap, Adesk::Boolean isPrimary = Adesk::kTrue) const;
    
private:
	AcDbObjectId m_propertyId;
	AcGePoint3d m_start, m_end;
    AcDbObjectIdArray mEllipseIds;
};

ACRX_DXF_DEFINE_MEMBERS(MyEntity, AcDbEllipse,
AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent,
0,\
MyEntity, REFERENC)

void MyEntity::modified (const AcDbObject *pDbObj) 
{
	assertReadEnabled();
	if(pDbObj->isKindOf(AsclPropComponentII::desc())){
		AcDbSmartObjectPointer<MyEntity> thisPtr(objectId(), AcDb::kForWrite);
		if(thisPtr.openStatus() == Acad::eOk){
			assertWriteEnabled();
		}
	} 
	AcDbEntity::modified (pDbObj) ;
}

//-----------------------------------------------------------------------------
//----- AcDbEntity protocols
Adesk::Boolean MyEntity::subWorldDraw (AcGiWorldDraw *mode) {
	assertReadEnabled();
	
	double radius = 10;
	AcDbSmartObjectPointer<AsclPropComponentII> prop(componentPropertyId(), AcDb::kForRead); 
	Acad::ErrorStatus es = prop.openStatus(); 
	if(es == Acad::eOk){
		radius = prop->radius();
	}
	mode->geometry().circle(m_start,radius,AcGeVector3d(0,0,1)); 
	return (Adesk::kTrue) ;
}

void MyEntity::subViewportDraw (AcGiViewportDraw *mode) {
	assertReadEnabled();
	AcDbEntity::subViewportDraw (mode) ;
}

Acad::ErrorStatus MyEntity::subTransformBy(const AcGeMatrix3d& xform){
	assertWriteEnabled();
	m_start.transformBy(xform); 
	return Acad::eOk;
}

Acad::ErrorStatus MyEntity::dwgInFields(AcDbDwgFiler* filer){
    assertWriteEnabled();
    AcDbEntity::dwgInFields(filer);

	filer->readPoint3d (&m_start) ;

	AcDbHardPointerId hardPointerId;
    filer->readHardPointerId(&hardPointerId);
    m_propertyId = hardPointerId;

    return filer->filerStatus();
}

Acad::ErrorStatus MyEntity::dwgOutFields(AcDbDwgFiler* filer) const{
    assertReadEnabled();
    AcDbEntity::dwgOutFields(filer);

	filer->writePoint3d (m_start);
	filer->writeHardPointerId(m_propertyId);

    return filer->filerStatus();
}

Acad::ErrorStatus MyEntity::subDeepClone(AcDbObject*    pOwner, AcDbObject*&   pClonedObject,AcDbIdMapping& idMap,Adesk::Boolean isPrimary) const{
    pClonedObject = NULL;

    bool isPrim = false;
    if (isPrimary)
        isPrim = true;
    AcDbIdPair idPair(objectId(), (AcDbObjectId)NULL,
                      false, isPrim);
    if (idMap.compute(idPair) && (idPair.value() != NULL))
        return Acad::eOk;    

    MyEntity *pClone = (MyEntity*)isA()->create();
    if (pClone != NULL)
        pClonedObject = pClone;    // set the return value
    else
        return Acad::eOutOfMemory;

    AcDbDeepCloneFiler filer;
    dwgOut(&filer);

    filer.seek(0L, AcDb::kSeekFromStart);
    pClone->dwgIn(&filer);
    bool bOwnerXlated = false;
    if (isPrimary)
    {
        AcDbBlockTableRecord *pBTR =
            AcDbBlockTableRecord::cast(pOwner);
        if (pBTR != NULL)
        {
            pBTR->appendAcDbEntity(pClone);
            bOwnerXlated = true;
        }
        else
        {
            pOwner->database()->addAcDbObject(pClone);
        }
    } else {
        pOwner->database()->addAcDbObject(pClone);
        pClone->setOwnerId(pOwner->objectId());
        bOwnerXlated = true;
    }

    pClone->setAcDbObjectIdsInFlux();
    pClone->disableUndoRecording(true);

    idPair.setValue(pClonedObject->objectId());
    idPair.setIsCloned(Adesk::kTrue);
    idPair.setIsOwnerXlated(bOwnerXlated);
    idMap.assign(idPair);

    AcDbObjectId id;
    while (filer.getNextOwnedObject(id)) {

        AcDbObject *pSubObject;
        AcDbObject *pClonedSubObject;

        if (id == NULL)
            continue;

        acdbOpenAcDbObject(pSubObject, id, AcDb::kForRead);
        pClonedSubObject = NULL;
        pSubObject->deepClone(pClonedObject,
                              pClonedSubObject,
                              idMap, Adesk::kFalse);

        if (pSubObject != pClonedSubObject)
            pSubObject->close();
        
        if (pClonedSubObject != NULL)
            pClonedSubObject->close();
    }

    return Acad::eOk;
}

Acad::ErrorStatus MyEntity::subWblockClone(AcRxObject* pOwner,AcDbObject*& pClonedObject,AcDbIdMapping& idMap, Adesk::Boolean isPrimary) const{
    assertReadEnabled();

    pClonedObject = NULL;

    AcDbDatabase *pDest, *pOrig;
    idMap.destDb(pDest);
    idMap.origDb(pOrig);
    if (pDest == pOrig)
        return AcDbEntity::subWblockClone(pOwner, pClonedObject,
            idMap, isPrimary);

    AcDbObjectId pspace;
    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;
    
    bool isPrim = false;
    if (isPrimary)
        isPrim = true;

    AcDbIdPair idPair(objectId(), (AcDbObjectId)NULL,
                      false, isPrim);
    if (idMap.compute(idPair) && (idPair.value() != NULL))
        return Acad::eOk;    

    AcDbObject   *pOwn = AcDbObject::cast(pOwner);
    AcDbDatabase *pDb = AcDbDatabase::cast(pOwner);
    if (pDb == NULL) 
        pDb = pOwn->database();

    // STEP 1:
    // Create the clone
    //
    MyEntity *pClone = (MyEntity*)isA()->create();
    if (pClone != NULL)
        pClonedObject = pClone;    // set the return value
    else
        return Acad::eOutOfMemory;

    AcDbBlockTableRecord *pBTR = NULL;
    if (pOwn != NULL)
        pBTR = AcDbBlockTableRecord::cast(pOwn);
    if (pBTR != NULL && isPrimary) {
        pBTR->appendAcDbEntity(pClone);
    } else {
        pDb->addAcDbObject(pClonedObject);
    }

    AcDbWblockCloneFiler filer;
    dwgOut(&filer);

    filer.seek(0L, AcDb::kSeekFromStart);
    pClone->dwgIn(&filer);

    idMap.assign(AcDbIdPair(objectId(), pClonedObject->objectId(), Adesk::kTrue,
        isPrim, (Adesk::Boolean)(pOwn != NULL) ));

   pClonedObject->setOwnerId((pOwn != NULL) ?
        pOwn->objectId() : ownerId());

    pClone->setAcDbObjectIdsInFlux();

    AcDbObjectId id;
    while (filer.getNextHardObject(id)) {

        AcDbObject *pSubObject;
        AcDbObject *pClonedSubObject;

        if (id == NULL)
            continue;

        acdbOpenAcDbObject(pSubObject, id, AcDb::kForRead);
        if (pSubObject->database() != database()) {
            pSubObject->close();
            continue;
        }

        pClonedSubObject = NULL;
        if (pSubObject->ownerId() == objectId()) {
            pSubObject->wblockClone(pClone,pClonedSubObject,idMap, Adesk::kFalse);                        
        } else {
            pSubObject->wblockClone(pClone->database(),pClonedSubObject,idMap, Adesk::kFalse);                       
        }
        pSubObject->close();
        
        if (pClonedSubObject != NULL)
            pClonedSubObject->close();
    }

    return Acad::eOk;
}

AcDbObjectId MyEntity::componentPropertyId() const{
	assertReadEnabled();
	return m_propertyId; 
}

void MyEntity::setComponentPropertyId(const AcDbObjectId& newPropId){
	assertWriteEnabled();
	m_propertyId = newPropId; 
}


ACRX_DXF_DEFINE_MEMBERS(AsclPropComponentII, AcDbObject,
AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent,
0,\
ASCLPROPCOMPONENTII, REFERENC)


//-----------------------------------------------------------------------------
AsclPropComponentII::AsclPropComponentII () : AcDbObject () {
}

AsclPropComponentII::~AsclPropComponentII () {
}

//-----------------------------------------------------------------------------
//----- AcDbObject protocols
Acad::ErrorStatus AsclPropComponentII::dwgInFields(AcDbDwgFiler* filer){
    assertWriteEnabled();
    Acad::ErrorStatus es =AcDbObject::dwgInFields (filer) ;
	if ( es != Acad::eOk )
		return (es) ;

	filer->readItem (&m_radius) ;
    return filer->filerStatus();
}

Acad::ErrorStatus AsclPropComponentII::dwgOutFields(AcDbDwgFiler* filer) const{
    assertReadEnabled();
   	Acad::ErrorStatus es =AcDbObject::dwgOutFields (filer) ;
	if ( es != Acad::eOk )
		return (es) ;
	
	filer->writeItem (m_radius) ;
    return filer->filerStatus();
}

double AsclPropComponentII::radius(void) const{
	assertReadEnabled();
	return (m_radius) ;
}

Acad::ErrorStatus AsclPropComponentII::setRadius(double newVal){
	assertWriteEnabled();
	m_radius = newVal ;
	return (Acad::eOk) ;
}

//Helper functions//////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
AcDbObjectId entryAtPath(const CString& path){
	CString resToken;
	int curPos = 0;
	AcArray<CString> dictNamesTree; 

	resToken = path.Tokenize(L">>", curPos);
	while (resToken != L"")
	{
		dictNamesTree.append(resToken); 	   
		resToken = path.Tokenize(L">>", curPos); 
	};
	
	if(dictNamesTree.length() == 0)
		return AcDbObjectId::kNull; 

	//The first parent will always be the name objects dictionary
	//this value will change as we iterate through the items 
	AcDbObjectId currParentDictId = acdbCurDwg()->namedObjectsDictionaryId(); 
	
	const int numItems = dictNamesTree.length(); 
	const int lastItem = numItems - 1; 
	//Iterate through the tree names 
	for(int i=0; i< dictNamesTree.length(); i++)
	{		
		AcDbDictionaryPointer currParent(currParentDictId, AcDb::kForRead); 
		Acad::ErrorStatus es = currParent.openStatus(); 
		if(es != Acad::eOk)
			return AcDbObjectId::kNull; 
		
		AcDbObjectId subObjId; 

		es = currParent->getAt(dictNamesTree[i].AllocSysString(), subObjId); 
		if((es == Acad::eKeyNotFound) && (i != lastItem))
		{
			return AcDbObjectId::kNull; 
		}
		if((es == Acad::eKeyNotFound) && (i == lastItem))
		{
			return AcDbObjectId::kNull; 
		}
		else if ((es == Acad::eOk) && (i == lastItem))
		{
			//This is the object we are looking for open to verify
			AcDbSmartObjectPointer<AcDbObject> subObject(subObjId, AcDb::kForRead); 
			es = subObject.openStatus(); 
			if(es != Acad::eOk){
				return AcDbObjectId::kNull; 
			}
			else return subObjId; 
		}
		else if(es != Acad::eOk){
			return AcDbObjectId::kNull; 
		}

		currParentDictId = subObjId; 
	}

	return AcDbObjectId(); 
}

AcDbObjectId setAtPath(const CString& path, AcDbObject* ptr, bool createIfNotFound)
{
	if(!ptr)
		return AcDbObjectId(); 	
	
	CString resToken;
	int curPos = 0;
	AcArray<CString> dictNamesTree; 

	resToken = path.Tokenize(L">>", curPos);
	while (resToken != L"")
	{
		dictNamesTree.append(resToken); 	   
		resToken = path.Tokenize(L">>", curPos); 
	};
	
	if(dictNamesTree.length() == 0)
		return AcDbObjectId::kNull; 

	//The first parent will always be the name objects dictionary
	//this value will change as we iterate through the items 
	AcDbObjectId currParentDictId = acdbCurDwg()->namedObjectsDictionaryId(); 
	
	const int numItems = dictNamesTree.length(); 
	const int lastItem = numItems - 1; 
	//Iterate through the tree names 
	for(int i=0; i< dictNamesTree.length(); i++)
	{		
		AcDbDictionaryPointer currParent(currParentDictId, AcDb::kForRead); 
		Acad::ErrorStatus es = currParent.openStatus(); 
		if(es != Acad::eOk)
			return AcDbObjectId::kNull; 
		
		AcDbObjectId subObjId; 

		es = currParent->getAt(dictNamesTree[i].AllocSysString(), subObjId); 
		if((es == Acad::eKeyNotFound) && (i != lastItem) && createIfNotFound)
		{
			if(!createIfNotFound)
				return AcDbObjectId::kNull; 
			
			//Our dictionary does not exist! So create it
			AcDbSmartObjectPointer<AcDbDictionary> subDictionary; 
			subDictionary.create();
			currParent.open(currParentDictId, AcDb::kForWrite); 
			es = currParent.openStatus(); 
			if(es != Acad::eOk)
				return AcDbObjectId::kNull; 

			es = currParent->setAt(dictNamesTree[i].AllocSysString(), (AcDbObject*)subDictionary, subObjId); 
		}
		if((es == Acad::eKeyNotFound) && (i == lastItem))
		{
			//Open parent for write			
			currParent.open(currParentDictId, AcDb::kForWrite); 
			es = currParent.openStatus(); 
			if(es != Acad::eOk)
				return AcDbObjectId::kNull; 
			
			//Add the object to path !!!!!!!!!!!!!!!!!!!
			//Should check for existing???????
			es = currParent->setAt(dictNamesTree[i].AllocSysString(), (AcDbObject*)ptr, subObjId); 
			if(es != Acad::eOk){
				delete ptr; 
				ptr = NULL; 
				return AcDbObjectId::kNull; 
			}
			else return subObjId; 
		}
		else if ((es == Acad::eOk) && (i == lastItem))
		{
			//This is the object we are looking for open to verify
			AcDbSmartObjectPointer<AcDbObject> subObject(subObjId, AcDb::kForRead); 
			es = subObject.openStatus(); 
			if(es != Acad::eOk){
				return AcDbObjectId::kNull; 
			}
			else return subObjId; 
		}
		else if(es != Acad::eOk){
			return AcDbObjectId::kNull; 
		}

		currParentDictId = subObjId; 
	}

	return AcDbObjectId(); 
}

AcDbBlockTableRecord* openCurrentSpaceBlock(AcDb::OpenMode mode, AcDbDatabase* db){
    AcDbBlockTableRecord* blkRec;

    Acad::ErrorStatus es = acdbOpenObject(blkRec, db->currentSpaceId(), mode);
    if (es == Acad::eOk)
        return blkRec;
    else
        return NULL;
}

Acad::ErrorStatus addToCurrentSpace(AcDbEntity* newEnt, AcDbDatabase* db){
    AcDbBlockTableRecord* blkRec = openCurrentSpaceBlock(AcDb::kForWrite, db);
    if (blkRec == NULL)
        return Acad::eInvalidInput;

    Acad::ErrorStatus es = blkRec->appendAcDbEntity(newEnt);

    blkRec->close();
    return es;
}

Acad::ErrorStatus dictionaryEntryId(const AcDbObjectId &dictId, int at, AcDbObjectId& entryId) {
	Acad::ErrorStatus es = Acad::eInvalidInput;

	AcDbSmartObjectPointer<AcDbDictionary> dict(dictId, AcDb::kForRead); 
	es = dict.openStatus(); 
	if(es != Acad::eOk)
		return es; 

	AcDbDictionaryIterator* itr = NULL; 
	itr = dict->newIterator(); 

	if( itr == NULL )
		return Acad::eNullIterator; 

	AcDbObjectIdArray list; 

	for(; !itr->done(); itr->next())
	{
		list.append(itr->objectId()); 
	}
	delete itr;

	if(at > -1 && at < list.length())
		entryId = list.at(at); 

	return Acad::eOk;
}

//Commands//////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void AddEntity(){
	//create property
	AsclPropComponentII *entity = new AsclPropComponentII();
	entity->setRadius(54);
	setAtPath(ASCL_LIB_PROP_PROP1, entity, true);
	entity->close();
	
	//Get Property Id from NOD
	AcDbObjectId propertyId; 
	dictionaryEntryId(entryAtPath(ASCL_LIB_PROP), 0, propertyId);
	
	//Create custom entity
	AcGePoint3d stPos = AcGePoint3d(0,0,0),enPos = AcGePoint3d(100,0,0);
	MyEntity *theEntity = new MyEntity(stPos, enPos, propertyId); 
	addToCurrentSpace(theEntity, acdbHostApplicationServices()->workingDatabase());
	theEntity->close();
}
void ChangeProp(){
	Acad::ErrorStatus es = Acad::eInvalidInput;
	
	AcDbObjectId propertyId; 
	dictionaryEntryId(entryAtPath(ASCL_LIB_PROP), 0, propertyId);
	
	AcDbSmartObjectPointer<AsclPropComponentII> prop(propertyId, AcDb::kForWrite); 
	es = prop.openStatus(); 
	if(es != Acad::eOk)
		return; 

	prop->setRadius(prop->radius()+10);

}

void initApp(){
    acedRegCmds->addCommand(_T("ASDK_MYCOMMANDS"), _T("ASDK_MYENTITY"), _T("MYENTITY"),ACRX_CMD_MODAL, AddEntity);
	acedRegCmds->addCommand(_T("ASDK_MYCOMMANDS"), _T("ASDK_MYPROP"), _T("MYPROP"),ACRX_CMD_MODAL, ChangeProp);
	MyEntity::rxInit(); 
	acrxBuildClassHierarchy();
}

void unloadApp()
{
    acedRegCmds->removeGroup(_T("ASDK_MYCOMMANDS"));
    deleteAcRxClass(MyEntity::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;
}

 The above code reproduce the problem.

I created 2 command:

MYENTITY to create custom entity (circle) with property object. Property objec stores radius of the circle.

MYPROP to change radius of the circle by 10. Please Regenrate the drawing after MYPROP to see change of the custom entities.

The code works fine when copy function of autocad is used but not working for copy/paste for both same file and new file. Can someone help to resolve te problem. 

 

Thanks

Michal
Message 9 of 25
artc2
in reply to: michalpawelak

I haven't looked at your sample code in detail, but I think you may be approaching this the wrong way.  Based on what you said in the message thread, it sounds like you want only one of your AsclPropComponentII objects per database and all of your MyEntity entities in that database will reference that one AsclPropComponentII object.  If that's correct, then I think you can leave your MyEntity class using the inherited subDeepClone() and subWblockClone() methods and override them in your AsclPropComponentII class instead and then implement them to check to see if the target database already has an AsclPropComponentII object.  If it does, then create an AcDbIdPair with the source AsclPropComponentII object as the key and the target database's AsclPropComponentII object as the value, set isCloned and isOwnerXlated to true, then add the idpair to the idmap.  If the target database doesn't have an AsclPropComponentII object, then can either call the AsclPropComponentII class's base class's subDeepClone or subwblockClone method to do the necessary cloning and AcDbIdPair creation or you can do it all yourself.  That way you only get one AsclPropComponentII object per database and the deepClone or wblockClone mechanism will get all of your MyEntity object clones setup to reference the correct AsclPropComponentII object in the target database.

Message 10 of 25
michalpawelak
in reply to: artc2

Thanks artc2 for your quick response. You are right, I have apporach it wrongly. 

 

Is it possible to see an example of the wblockcone and deepclone function that will do the above you mentioned? 

 

Thanks

Michal
Message 11 of 25
artc2
in reply to: michalpawelak

Sorry, I don't have any sample code for this.

You can get the destination db from the idmap, then from that you can check to see if it already has your AsclPropComponentII object.  If there is one of your objects in the target DB, then just create an AcDbIdPair like so:

             AcDbIdPair idPair(objectId(), objId_Of_Target_DB_AsclPropComponentII_Object, true, isPrim);

and add it to the idmap

             isMap.assign(idPair);

set the pClonedObject pointer passed into the method to NULL and return eOk.

If the target DB doesn't have your AsclPropComponentII object, then just call the base class's subDeepClone or subWblockClone method and return whatever it returns:

    return AcDbEntity::subDeepClone(pOwner, pClonedObject, idMap, isPrimary);

 

I may be missing something, but I think that should mostly cover it.

 

 

Message 12 of 25
michalpawelak
in reply to: artc2

Hi artc2

 

I have created the folowing function:

 

Acad::ErrorStatus AsclPropComponentII::subDeepClone(AcDbObject* pOwner, AcDbObject*&   pClonedObject,AcDbIdMapping& idMap,Adesk::Boolean isPrimary) const{
	pClonedObject = NULL;
    AcDbDatabase *pDest;
    idMap.destDb(pDest);

	AcDbDictionary *pNamedObjDict;
    pDest->getNamedObjectsDictionary(pNamedObjDict,AcDb::kForRead);

	if(pNamedObjDict->has(objectId())) {
		AcDbIdPair idPair(objectId(), objectId(),true, false);
		idMap.assign(idPair);
		return Acad::eOk;
	}
	return AcDbObject::subDeepClone(pOwner, pClonedObject, idMap, false);
}

Acad::ErrorStatus AsclPropComponentII::subWblockClone(AcRxObject* pOwner,AcDbObject*& pClonedObject,AcDbIdMapping& idMap, Adesk::Boolean isPrimary) const{
	pClonedObject = NULL;
    AcDbDatabase *pDest;
    idMap.destDb(pDest);

	AcDbDictionary *pNamedObjDict;
    pDest->getNamedObjectsDictionary(pNamedObjDict,AcDb::kForRead);

	if(pNamedObjDict->has(objectId())) {
		AcDbIdPair idPair(objectId(), objectId(),true, false);
		idMap.assign(idPair);
		return Acad::eOk;
	}
	return AcDbObject::subWblockClone(pOwner, pClonedObject, idMap, false);
}

 For some reason they do not work. I am geting eror mesage when I press ctrl+c "Copy to clipboard Failed". Do you know what it could cause it? I have also noticed that the function subWblockClone is not called on ctrl+p so how the desitnation database is recognised? Please let me know if you have any solutions to the above.

 

Thanks

Michal
Message 13 of 25
artc2
in reply to: michalpawelak

Your code doesn't appear to be closing the NamedObjects dictionary that it has opened.  Also, the calls to AcDbObject::subDeepClone() and AcDbObject::subWblockClone() should pass in the isPrimary argument that was passed into your functions rather than explicitly passing in a value such as false.  In this case the isPrimary argument passed into your subXXX functions should always be false anyway, but it's best to be safe and simply pass the argument on.

 

And, why are you using the objectId of the source object (which is in the source database) to search for an object in the target database's NamedObjects dictionary?  You should be searching based on the key string for your object - assuming that is the same in all databases.  And, when you are creating the AcDbIdPair, you should be using the objectId of the target database's instance of your object as the value (second argument) not the objectId of the source database's object.  So, instead of using the has() method to findout if there is an instance of your object in the target database, you should use getAt() so that you get the objectId of the object in the target database in order to use that when creating the AcDbIdPair.  getAt() will return eKeyNotFound if there is no object in the dictionary with the key string you pass into it.

 

Paste uses insert which uses a special deepclone mechanism, but it should still call subDeepClone() on any objects that it needs to clone.

Message 14 of 25
MichalSzkocja
in reply to: artc2

I have modified the code according to your sugestions as follows:

 

Acad::ErrorStatus AsclPropComponentII::subDeepClone(AcDbObject* pOwner, AcDbObject*&   pClonedObject,AcDbIdMapping& idMap,Adesk::Boolean isPrimary) const{
	pClonedObject = NULL;
    AcDbDatabase *pDest;
    idMap.destDb(pDest);

	AcDbDictionary *pNamedObjDict;
    pDest->getNamedObjectsDictionary(pNamedObjDict,AcDb::kForRead);

    AcDbObjectId dictObjId;
	Acad::ErrorStatus es = pNamedObjDict->getAt(ASCL_LIB_PROP_PROP1, dictObjId);
    pNamedObjDict->close();

    if (es == Acad::eKeyNotFound) 
		return AcDbObject::subWblockClone(pOwner, pClonedObject, idMap, false);

	bool isPrim = false;
	if (isPrimary)
		isPrim = true;
	AcDbIdPair idPair(objectId(), dictObjId,true, isPrim);
	idMap.assign(idPair);

	return Acad::eOk;
}

Acad::ErrorStatus AsclPropComponentII::subWblockClone(AcRxObject* pOwner,AcDbObject*& pClonedObject,AcDbIdMapping& idMap, Adesk::Boolean isPrimary) const{
	pClonedObject = NULL;
    AcDbDatabase *pDest;
    idMap.destDb(pDest);

	AcDbDictionary *pNamedObjDict;
    pDest->getNamedObjectsDictionary(pNamedObjDict,AcDb::kForRead);

    AcDbObjectId dictObjId;
    Acad::ErrorStatus es = pNamedObjDict->getAt(ASCL_LIB_PROP_PROP1, dictObjId);
    pNamedObjDict->close();

    if (es == Acad::eKeyNotFound) 
		return AcDbObject::subWblockClone(pOwner, pClonedObject, idMap, false);

	bool isPrim = false;
	if (isPrimary)
		isPrim = true;
	AcDbIdPair idPair(objectId(), dictObjId,true, isPrim);
	idMap.assign(idPair);

	return Acad::eOk;
}

 

The only problem I have now is that the above functions are not called during copy, copyclip and paste clip. The only subWblockClone is called during copyclip. Should I modify dwgfillIn and dwgFillOut functions in My Entity class? Please see my dwgfillIn and dwgFillOut functions below.

 

Acad::ErrorStatus MyEntity::dwgInFields(AcDbDwgFiler* filer){
assertWriteEnabled();
AcDbEntity::dwgInFields(filer);

AcDbHardPointerId hardPointerId;
filer->readHardPointerId(&hardPointerId);
m_propertyId = hardPointerId;

filer->readPoint3d (&m_start) ;

return filer->filerStatus();
}

Acad::ErrorStatus MyEntity::dwgOutFields(AcDbDwgFiler* filer) const{
assertReadEnabled();
AcDbEntity::dwgOutFields(filer);

if (filer->filerType() == AcDb::kWblockCloneFiler)
filer->writeHardPointerId((AcDbHardPointerId)ownerId());

filer->writeHardPointerId(m_propertyId);
filer->writePoint3d (m_start);


return filer->filerStatus();
}

 

Message 15 of 25
owenwengerd
in reply to: MichalSzkocja

Unless I've missed something, Art has previously provided answers to the questions in both of your latest posts. I'm sure Art doesn't mind helping, but perhaps instead of waiting for Art to respond again you could re-read his previous answers to see if you can solve the problem on your own.

--
Owen Wengerd
ManuSoft
Message 16 of 25
michalpawelak
in reply to: owenwengerd

owenwengerd,

 

Yes 

Michal
Message 17 of 25
artc2
in reply to: MichalSzkocja

I think you misunderstood some of what I was saying.

 

This:

 

    AcDbObject::subWblockClone(pOwner, pClonedObject, idMap, false);

 

should be

 

    AcDbObject::subWblockClone(pOwner, pClonedObject, idMap, isPrim);

 

and this:

 

    AcDbIdPair idPair(objectId(), dictObjId,true, isPrim);

 

should always be

 

    AcDbIdPair idPair(objectId(), dictObjId,true, false);

 

The same changes are needed in subDeepClone().

 

If by "copy" you mean the copy command, that uses the clone() method instead of deepClone or wblockClone.  But, that should be ok in your case since copy is within the same drawing so a shallow clone will maintain the reference to your single custom object in the NamedObjects dictionary.

 

Message 18 of 25
MichalSzkocja
in reply to: artc2

Artc2,

 

I have tried to solve the problem with copyclip and pasteclip without any success. I tried I implemented all your sugestions but it does not work for me.

When I use copyclip and pasteclip function MyEntity is pasted without MyEntProp assigned. Could you please try the code I have attahced below to see if it works fine on your machine?

 

#if defined(_DEBUG) && !defined(AC_FULL_DEBUG)
#error _DEBUG should not be defined except in internal Adesk debug builds
#endif

#include <adslib.h>
#include <dbelipse.h>
#include <gemat3d.h>
#include <dbsymtb.h>
#include <dbapserv.h>
#include <aced.h>
#include <actrans.h>
#include <dbidmap.h>
#include <acestext.h>
#include "tchar.h"
#include <atlstr.h>
#include "dbobjptr.h"
#include "dbobjptr2.h"
#include "acutmem.h"
#include "dbxutil.h"
#include "dbcfilrs.h"

#define PROPS	ACRX_T("Properties") 
#define PROP_1		ACRX_T("Prop_1")

class MyEntProp : public AcDbObject {
public:	
	ACRX_DECLARE_MEMBERS(MyEntProp);
	MyEntProp () : AcDbObject () {}
	virtual ~MyEntProp () {}

	virtual Acad::ErrorStatus dwgOutFields (AcDbDwgFiler *pFiler) const ;
	virtual Acad::ErrorStatus dwgInFields (AcDbDwgFiler *pFiler) ;

protected:
	virtual Acad::ErrorStatus subDeepClone  (AcDbObject* pOwnerObject, AcDbObject*& pClonedObject, AcDbIdMapping &idMap, Adesk::Boolean isPrimary = Adesk::kTrue) const;
    virtual Acad::ErrorStatus subWblockClone(AcRxObject* pOwnerObject, AcDbObject*& pClonedObject, AcDbIdMapping &idMap, Adesk::Boolean isPrimary = Adesk::kTrue) const;

public:
	double radius() const;
	Acad::ErrorStatus setRadius(double radius);

private:
	double m_radius;
} ;

ACRX_DXF_DEFINE_MEMBERS(MyEntProp, AcDbObject, AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent, 0, MYENTPROP, REFERENC)

Acad::ErrorStatus MyEntProp::dwgInFields(AcDbDwgFiler* filer){
	assertWriteEnabled();
	Acad::ErrorStatus es =AcDbObject::dwgInFields (filer) ;
	if ( es != Acad::eOk )
		return (es) ;

	filer->readItem (&m_radius) ;
    return filer->filerStatus();
}

Acad::ErrorStatus MyEntProp::dwgOutFields(AcDbDwgFiler* filer) const{
    assertReadEnabled();
   	Acad::ErrorStatus es =AcDbObject::dwgOutFields (filer) ;
	if ( es != Acad::eOk )
		return (es) ;

	filer->writeItem (m_radius) ;
    return filer->filerStatus();
}

Acad::ErrorStatus MyEntProp::subDeepClone(AcDbObject* pOwner, AcDbObject*&   pClonedObject,AcDbIdMapping& idMap,Adesk::Boolean isPrimary) const{
	assertReadEnabled();
	pClonedObject = NULL;

	AcDbDatabase *pDest;
    idMap.destDb(pDest);
  
	AcDbDictionary *pNamedObjDict;
    Acad::ErrorStatus es = pDest->getNamedObjectsDictionary(pNamedObjDict,AcDb::kForRead);
	if(es == Acad::eOk){

		AcDbObjectId dictObjId1;
		Acad::ErrorStatus es = pNamedObjDict->getAt(PROPS, dictObjId1);
		pNamedObjDict->close();
		if(es == Acad::eOk){
			AcDbDictionaryPointer dictObj(dictObjId1, AcDb::kForRead); 
			es = dictObj.openStatus(); 
			if(es == Acad::eOk){
				AcDbObjectId myPropId;
				es = dictObj->getAt(PROP_1, myPropId);
				AcDbIdPair idPair(objectId(), myPropId,true, false);
				idMap.assign(idPair);
				return Acad::eOk;
			}
		}
	}

	bool isPrim = false;
	if (isPrimary)
		isPrim = true;
	return AcDbObject::subDeepClone(pOwner, pClonedObject, idMap, isPrim);
}

Acad::ErrorStatus MyEntProp::subWblockClone(AcRxObject* pOwner,AcDbObject*& pClonedObject,AcDbIdMapping& idMap, Adesk::Boolean isPrimary) const{
	assertReadEnabled();
	pClonedObject = NULL;

	AcDbDatabase *pDest;
    idMap.destDb(pDest);
  
	AcDbDictionary *pNamedObjDict;
    Acad::ErrorStatus es = pDest->getNamedObjectsDictionary(pNamedObjDict,AcDb::kForRead);
	if(es == Acad::eOk){

		AcDbObjectId dictObjId;
		Acad::ErrorStatus es = pNamedObjDict->getAt(PROPS, dictObjId);
		pNamedObjDict->close();
		if(es == Acad::eOk){
			AcDbDictionaryPointer dictObj(dictObjId, AcDb::kForRead); 
			es = dictObj.openStatus(); 
			if(es == Acad::eOk){
				AcDbObjectId myPropId;
				es = dictObj->getAt(PROP_1, myPropId);
				AcDbIdPair idPair(objectId(), myPropId,true, false);
				idMap.assign(idPair);
				return Acad::eOk;
			}
		}
	}

	bool isPrim = false;
	if (isPrimary)
		isPrim = true;
	return AcDbObject::subWblockClone(pOwner, pClonedObject, idMap, isPrim);
}

double MyEntProp::radius(void) const{
	assertReadEnabled();
	return (m_radius) ;
}

Acad::ErrorStatus MyEntProp::setRadius(double newVal){
	assertWriteEnabled();
	m_radius = newVal ;
	return (Acad::eOk) ;
}


class MyEntity : public AcDbEntity{
public:
    ACRX_DECLARE_MEMBERS(MyEntity);
    MyEntity() : AcDbEntity () {}
    MyEntity(AcGePoint3d stPos, AcGePoint3d enPos, const AcDbObjectId propertyId): m_propertyId(propertyId), m_start(stPos), m_end(enPos) {}
	virtual ~MyEntity () {}

	AcDbObjectId componentPropertyId() const;
	void setComponentPropertyId(const AcDbObjectId& newPropId);

    virtual Acad::ErrorStatus dwgInFields(AcDbDwgFiler* filer);
    virtual Acad::ErrorStatus dwgOutFields(AcDbDwgFiler* filer) const;

	virtual void modified (const AcDbObject *pDbObj) ;

protected:
	virtual void subViewportDraw (AcGiViewportDraw *mode) ;
	virtual Adesk::Boolean subWorldDraw (AcGiWorldDraw *mode) ;
	virtual Acad::ErrorStatus subTransformBy(const AcGeMatrix3d& xform);
    
private:
	AcDbObjectId  m_propertyId;
	AcGePoint3d m_start, m_end;

};

ACRX_DXF_DEFINE_MEMBERS(MyEntity, AcDbEntity, AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent, 0, MYENTITY, REFERENC)

void MyEntity::modified (const AcDbObject *pDbObj) 
{
	assertReadEnabled();
	if(pDbObj->isKindOf(MyEntProp::desc())){
		AcDbSmartObjectPointer<MyEntity> thisPtr(objectId(), AcDb::kForWrite);
		if(thisPtr.openStatus() == Acad::eOk){
			assertWriteEnabled();
		}
	} 
	AcDbEntity::modified (pDbObj) ;
}

Adesk::Boolean MyEntity::subWorldDraw (AcGiWorldDraw *mode) {
	assertReadEnabled();
	
	double radius = 10;
	AcDbSmartObjectPointer<MyEntProp> prop(componentPropertyId(), AcDb::kForRead); 
	Acad::ErrorStatus es = prop.openStatus(); 
	if(es == Acad::eOk){
		radius = prop->radius();
	}
	mode->geometry().circle(m_start,radius,AcGeVector3d(0,0,1)); 
	return (Adesk::kTrue) ;
}

void MyEntity::subViewportDraw (AcGiViewportDraw *mode) {
	assertReadEnabled();
	AcDbEntity::subViewportDraw (mode) ;
}

Acad::ErrorStatus MyEntity::subTransformBy(const AcGeMatrix3d& xform){
	assertWriteEnabled();
	m_start.transformBy(xform); 
	return Acad::eOk;
}

Acad::ErrorStatus MyEntity::dwgInFields(AcDbDwgFiler* filer){
	assertWriteEnabled();
	AcDbEntity::dwgInFields(filer);

	AcDbHardPointerId hardPointerId;
	filer->readHardPointerId(&hardPointerId);
	m_propertyId = hardPointerId;

	filer->readPoint3d (&m_start) ;

	return filer->filerStatus();
}

Acad::ErrorStatus MyEntity::dwgOutFields(AcDbDwgFiler* filer) const{
	assertReadEnabled();
	AcDbEntity::dwgOutFields(filer);

	filer->writeHardPointerId((AcDbHardPointerId)m_propertyId);
	filer->writePoint3d (m_start);

	return filer->filerStatus();
}

AcDbObjectId MyEntity::componentPropertyId() const{
	assertReadEnabled();
	return m_propertyId; 
}

void MyEntity::setComponentPropertyId(const AcDbObjectId& newPropId){
	assertWriteEnabled();
	m_propertyId = newPropId; 
}

//Commands
void AddEntity(){
	AcDbDictionary *pNamedobj;
	acdbHostApplicationServices()->workingDatabase()->getNamedObjectsDictionary(pNamedobj,AcDb::kForRead);

	AcDbDictionary *pDict;
	if (!pNamedobj->has(PROPS)){
		 if (pNamedobj->upgradeOpen() == Acad::eOk) {
            pDict = new AcDbDictionary;
            AcDbObjectId DictId;
            pNamedobj->setAt(PROPS, pDict, DictId);
            pNamedobj->close();

			AcDbObjectId rId1;
			MyEntProp *pObj1 = new MyEntProp();
			pObj1->setRadius(54);
			Acad::ErrorStatus es = pDict->setAt(PROP_1, pObj1, rId1);
            pObj1->close();
            pDict->close();
        } else
            pNamedobj->close();
	}

	AcDbDictionary *pNamedobj1;
    acdbHostApplicationServices()->workingDatabase()->getNamedObjectsDictionary(pNamedobj1,AcDb::kForRead);

    AcDbObjectId dictObjId1;
    Acad::ErrorStatus es = pNamedobj1->getAt(PROPS, dictObjId1);
    pNamedobj1->close();

	AcDbDictionaryPointer dictObj(dictObjId1, AcDb::kForRead); 
	es = dictObj.openStatus(); 
	if(es != Acad::eOk)
		return; 
	
	AcDbObjectId propertyId;
	es = dictObj->getAt(PROP_1, propertyId);

	AcGePoint3d stPos = AcGePoint3d(0,0,0),enPos = AcGePoint3d(100,0,0);
	MyEntity *theEntity = new MyEntity(stPos, enPos, propertyId);

	AcDbBlockTableRecord* blkRec;
	acdbOpenObject(blkRec, acdbHostApplicationServices()->workingDatabase()->currentSpaceId(), AcDb::kForWrite);
    blkRec->appendAcDbEntity(theEntity);
    blkRec->close();

	theEntity->close();
}
void ChangeProp(){
	AcDbDictionary *pNamedobj1;
    acdbHostApplicationServices()->workingDatabase()->getNamedObjectsDictionary(pNamedobj1,AcDb::kForRead);

    AcDbObjectId dictObjId1;
    Acad::ErrorStatus es = pNamedobj1->getAt(PROPS, dictObjId1);
    pNamedobj1->close();

	AcDbDictionaryPointer dictObj(dictObjId1, AcDb::kForRead); 
	es = dictObj.openStatus(); 
	if(es != Acad::eOk)
		return; 
	
	AcDbObjectId propertyId;
	es = dictObj->getAt(PROP_1, propertyId);
	
	AcDbSmartObjectPointer<MyEntProp> prop(propertyId, AcDb::kForWrite); 
	es = prop.openStatus(); 
	if(es != Acad::eOk)
		return; 

	prop->setRadius(prop->radius()+10);
}

void initApp(){
    acedRegCmds->addCommand(_T("ASDK_MYCOMMANDS"), _T("ASDK_MYENTITY"), _T("MYENTITY"),ACRX_CMD_MODAL, AddEntity);
	acedRegCmds->addCommand(_T("ASDK_MYCOMMANDS"), _T("ASDK_MYPROP"), _T("MYPROP"),ACRX_CMD_MODAL, ChangeProp);
	MyEntProp::rxInit(); 	
	MyEntity::rxInit();
	acrxBuildClassHierarchy();
}

void unloadApp(){
    acedRegCmds->removeGroup(_T("ASDK_MYCOMMANDS"));
    deleteAcRxClass(MyEntity::desc());
	deleteAcRxClass(MyEntProp::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;
}

 

 

Message 19 of 25

Can anyone help with the above? 

Message 20 of 25

Can someone help to solve above problem?

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost