readBlockEntities (block within block)

readBlockEntities (block within block)

1127204185
Advocate Advocate
1,029 Views
4 Replies
Message 1 of 5

readBlockEntities (block within block)

1127204185
Advocate
Advocate
	static void readBlockEntities(const AcDbObjectId& blkid , AcDbObjectIdArray &ids)
	{
		AcDbBlockTableRecordIterator* iter;
		AcDbBlockReference* pBlkRef;
		AcDbBlockTableRecord* pRecord;
		Acad::ErrorStatus es = acdbOpenObject(pBlkRef, blkid, AcDb::kForRead);
		if (es != Acad::eOk)
			return;
		AcDbObjectId blockTableRecordId = pBlkRef->blockTableRecord();
		AcGeMatrix3d blkmat = pBlkRef->blockTransform();
		pBlkRef->close();
		es = acdbOpenObject(pRecord, blockTableRecordId, AcDb::kForWrite);
		if (es != Acad::eOk || pRecord == NULL)
			return;
		pRecord->newIterator(iter);
		for (iter->start(); !iter->done(); iter->step())
		{
			AcDbObjectId id;
			AcDbEntity* pEnt1 = NULL;
			es = iter->getEntityId(id);
			es = iter->getEntity(pEnt1, AcDb::kForRead);
			if (es != Acad::eOk || !id.isValid())continue;

			AcDbObjectPointer<AcDbBlockReference> pEnt(id, AcDb::kForRead);
			if (pEnt.openStatus() == Acad::eOk)
			{
				pEnt1->close();
				AcDbObjectIdArray nestedIds;
				readBlockEntities(id, nestedIds);
				ids.append(nestedIds);
			} 
			else
			{	
				pEnt1->transformBy(blkmat);
				ids.append(id);
				pEnt1->close();
			}
			
		}
		delete iter;
		pRecord->close();
	}
0 Likes
Accepted solutions (1)
1,030 Views
4 Replies
Replies (4)
Message 2 of 5

tbrammer
Advisor
Advisor

It seems that you try to "explode" a blockreference (BREF) with the ID blkid and collect the fragments in AcDbObjectIdArray &ids.

The idea to treat block references by recursion is basically right. But the way you implemented it has several issues.

 

  1. You are opening the entities twice in two different ways, which is neither elegant nor performant.
      iter->getEntity(pEnt1, AcDb::kForRead)
      AcDbObjectPointer<AcDbBlockReference> pEnt(id, AcDb::kForRead);
    Better use 
      AcDbBlockReference *pEnt = AcDbBlockReference::cast(pEnt1);
    pEnt will be NULL if  pEnt1 is not a block reference.

  2. You open pEnt1  for read only and try to modify it with pEnt1->transformBy(blkmat);
    1. This will crash AutoCAD. You must open the entity kForWrite.
    2. Even if you open the entity for write: Transforming it is probably not what you want, because it will modify the BREF's block itself and all it's nested blocks! The final array ids would contain ids of entities from different blocks which is pretty useless. At this point the question is: What do you expect as result?
      Usually you would create a transformed copy i.e. with 
         pEnt1->getTransformedCopy(blkmat, pEntCopy);
      and append it to a block record - maybe to modelspace.

  3. When you find an AcDbBlockReference you and you call readBlockEntities() recursive you must pass the current transformation matrix blkmat and multiply the transformation matrix with the "owner matrix".
    This would look like this:
    void readBlockEntities(const AcGeMatrix3d &matOwner, ..) 
    {
      AcGeMatrix3d blkmat = matOwner * pBlkRef->blockTransform();
      ...
      if (pBref)
        readBlockEntities(blkmat, id, nestedIds);
    }​

 


Thomas Brammer ● Software Developer ● imos AGLinkedIn
If an answer solves your problem please [ACCEPT SOLUTION]. Otherwise explain why not.

0 Likes
Message 3 of 5

1127204185
Advocate
Advocate
Thank you very much! I have studied your 'explain' code,The modification was not successful,I feel like this is more difficult。I have been unable to complete it。
0 Likes
Message 4 of 5

tbrammer
Advisor
Advisor
Accepted solution

Try this:

 

void readBlockEntities(const AcGeMatrix3d& matOwner, AcDbBlockReference *pBlkRef, AcDbBlockTableRecord *pTargetBlock, AcDbObjectIdArray& ids)
{
	if (!pBlkRef || !pTargetBlock)
		return;
	AcDbBlockTableRecordIterator* iter;
	AcDbBlockTableRecord* pRecord;
	Acad::ErrorStatus es;
	AcDbObjectId blockTableRecordId = pBlkRef->blockTableRecord();
	AcGeMatrix3d blkmat = matOwner * pBlkRef->blockTransform();
	pBlkRef->close();
	es = acdbOpenObject(pRecord, blockTableRecordId, AcDb::kForRead); //TB only for read. We don't want to modify the block.
	if (es != Acad::eOk || !pRecord)
		return;
	pRecord->newIterator(iter);
	for (iter->start(); !iter->done(); iter->step())
	{
		AcDbEntity* pEnt1 = NULL;		
		es = iter->getEntity(pEnt1, AcDb::kForRead);
		if (es != Acad::eOk)
			continue;
		AcDbBlockReference* pSubBref = AcDbBlockReference::cast(pEnt1);
		if (pSubBref)
		{
			AcDbObjectIdArray nestedIds;
			readBlockEntities(blkmat, pSubBref, pTargetBlock, nestedIds);
			ids.append(nestedIds);
		}
		else
		{
			AcDbEntity *pNewEnt=nullptr;
			es = pEnt1->getTransformedCopy(blkmat, pNewEnt);
			if (!es)
			{
				es = pTargetBlock->appendAcDbEntity(pNewEnt);
				if (es)
					delete pNewEnt;
				else
				{
					ids.append(pNewEnt->objectId());
					pNewEnt->close();
				}
			}
		}
		pEnt1->close();

	}
	delete iter;
	pRecord->close();
}

void readBlockEntities(const AcDbObjectId& blkid, AcDbObjectIdArray& ids)
{
	AcDbBlockReference* pBlkRef;
	Acad::ErrorStatus es = acdbOpenObject(pBlkRef, blkid, AcDb::kForRead);
	if (es)
	{
		acutPrintf(L"\nNot a BREF!");
		return;
	}

	// We want to append the enties to the modelspace...
	AcDbDatabase *db = pBlkRef->database();
	AcDbObjectId IdModelSpace = acdbSymUtil()->blockModelSpaceId(db);
	AcDbBlockTableRecord *pModelSpace;
	if ((es = acdbOpenObject(pModelSpace, IdModelSpace, AcDb::kForWrite)) == Acad::eOk)
	{
		AcGeMatrix3d mat; 
		mat.setToTranslation(AcGeVector3d(200.0, 0.0, 0.0)); // ... translated by 200 in X direction.
		readBlockEntities(mat, pBlkRef, pModelSpace, ids);
		pModelSpace->close();
	}

}

void cmdTestReadBlockEntities()
{
	ads_point    pt;
	ads_name     ent;
	AcDbObjectId blkid;

	if (acedEntSel(_T("\nPick a BREF: "), ent, pt) != RTNORM)
		return;

	if (acdbGetObjectId(blkid, ent) != Acad::eOk)
		return;

	AcDbObjectIdArray ids;
	readBlockEntities(blkid, ids);
}

Thomas Brammer ● Software Developer ● imos AGLinkedIn
If an answer solves your problem please [ACCEPT SOLUTION]. Otherwise explain why not.

0 Likes
Message 5 of 5

1127204185
Advocate
Advocate
Thank you very much!
0 Likes