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

Explode all blocks of the drawing

12 REPLIES 12
SOLVED
Reply
Message 1 of 13
1127204185
988 Views, 12 Replies

Explode all blocks of the drawing

static void   MyGroupMyCommand()
{
	bool flag = true;
    AcDbObjectId idBTR;
   	AcDbEntity* pEnt = NULL;
	while (flag)
	{

		AcDbBlockTablePointer pBlkTbl(acdbCurDwg(), AcDb::kForWrite);
		if (Acad::eOk != pBlkTbl.openStatus()){	flag = false; break; }
		AcDbBlockTableIterator* pIt = NULL;
		Acad::ErrorStatus es = pBlkTbl->newIterator(pIt);
		if (Acad::eOk != es){	flag = false; break; }
		std::unique_ptr<AcDbBlockTableIterator> apIt(pIt);

		for (apIt->start(); !apIt->done(); apIt->step())
		{
			AcDbBlockTableRecord* pBTRecord = NULL;
			if (apIt->getRecord(pBTRecord, AcDb::kForWrite) == Acad::eOk)
			{

					AcDbObjectPointer<AcDbBlockReference> pEnt(pBTRecord->objectId(), AcDb::kForWrite);

						if (pEnt.openStatus() == Acad::eOk)		
						{
							AcDbVoidPtrArray entitySet;
                            pEnt->explode(entitySet);
						}
				pBTRecord->close();
			}
		}
	}
}
12 REPLIES 12
Message 2 of 13
2557003216
in reply to: 1127204185

after explode,U next post to modelspace

Message 3 of 13
tbrammer
in reply to: 1127204185

@2557003216 is right: You must either post the results in entitySet (casted to AcDbEntity*) to the database or delete them. 

 

But what exactly do you want to achive? You are iterating over all Blocks in the drawing. Do you really want to explode all blockreferences (BREFs) in all blocks? And if so: Where would you post their fragments to? It makes no sense to post them to the modelspace.

I assume you want to explode all BREFs in the modelspace, post their contents to the modelspace and erase the original BREF. This is what the EXPLODE command would do if you select all BREFs in the modelspace.

You can get the ID of the modelspace like this:

#include <dbsymutl.h>
AcDbDatabase *pDB = acdbCurDwg();
AcDbObjectId IdModelSpace = acdbSymUtil()->blockModelSpaceId(pDB);

 

How do you want to deal with nested blocks? What if block A contains BREFs to block B which contains BREFs to C and so on?


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

Message 4 of 13
1127204185
in reply to: tbrammer

Explode a block, including a block and a block inside
Then explode all the blocks in model space
Message 5 of 13
tbrammer
in reply to: 1127204185

It is important to distinguish exactly between a "block" (AcDbBlockTableRecord) and "block reference" (AcDbBlockReference, BREF). Let's say you have a block "X" and a BREF to it. If you make 99 copies from the BREF then there is only one block "X". If you explode or erase all 100 BREFs to "X" there is still this one block "X" - until you PURGE it.

 

You can't "explode" a block. You can explode a BREF, which will copy the block's entities to the BREF's owner block. Exploding a BREF will not modifiy the block it referenced!

 

A block can't have a "block inside". It can have BREFs inside. You can explode BREFs within a block with the BEDIT command.

 

If I understand you correctly, you want to explode BREFs (all? selected?) in the modelspace recursively so that there are no more BREFs in the modelspace.  So starting with the attached Explode.dwg you would like to get the result on the far right side. Correct?

 


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

Message 6 of 13
1127204185
in reply to: tbrammer

That's it, explode all the blocks in model space.

 

I don't know, why my writing wasn't successful

 

 

1x "housing"   Do not explode

Message 7 of 13
tbrammer
in reply to: 1127204185

This can't work:

 

AcDbBlockTableRecord* pBTRecord = NULL;
if (apIt->getRecord(pBTRecord, AcDb::kForWrite) == Acad::eOk) {
	// pBTRecord ist a block (AcDbBlockTableRecord),
	// NOT a BREF (AcDbBlockReference)
	AcDbObjectPointer<AcDbBlockReference> pEnt(pBTRecord->objectId(), AcDb::kForWrite);
	// ^- Here you tried to open a BREF with the Id of a block.
	if (pEnt.openStatus() == Acad::eOk)	// No way!

 

 

Try this:

 

 

#include <dbsymutl.h> // for acdbSymUtil()

static void MyGroupMyCommand()
{
	AcDbObjectIdArray explodedBrefs;
	AcDbVoidPtrArray  brefFragments;
	AcDbDatabase* pDB = acdbCurDwg();
	Acad::ErrorStatus es;

	// Get the modelspace
	AcDbObjectId IdModelSpace = acdbSymUtil()->blockModelSpaceId(pDB);
	AcDbObjectPointer<AcDbBlockTableRecord> modelspace(IdModelSpace, AcDb::kForRead);
	if (modelspace.openStatus() == Acad::eOk)	{
		// Now let's iterate over all entities in the modelspace
		AcDbBlockTableRecordIterator* it=nullptr;
		es = modelspace->newIterator(it);
		if (it && (es==Acad::eOk))		{
			AcDbObjectId entityId;
			for (it->start(); !it->done(); it->step())	{
				es = it->getEntityId(entityId);
				AcDbObjectPointer<AcDbBlockReference> bref(entityId, AcDb::kForRead);
				if (bref.openStatus() == Acad::eOk) 	{
					// We found a BREF!
					AcDbVoidPtrArray entitySet;
					es = bref->explode(entitySet);
					if (es == Acad::eOk) {
						brefFragments.append(entitySet);
						explodedBrefs.append(entityId);
					}
					// Don't append the fragments while iterating over the modelspace
				}
			}
			delete it;
		}

		// Now append the new explosion fragment entities
		es = modelspace->upgradeOpen(); // must be write enabled now.
		for (void *p : brefFragments)	{
			AcDbEntity *ent = (AcDbEntity*)p;
			es = modelspace->appendAcDbEntity(ent);
			if (es==Acad::eOk)
				ent->close();
			else
				delete ent; // avoid memory leak.
		}
	}

	// Now erase the exploded BREFs
	for (AcDbObjectId& brefId : explodedBrefs)	{
		AcDbObjectPointer<AcDbBlockReference> bref(brefId, AcDb::kForWrite);
		if (bref.openStatus() == Acad::eOk)
			bref->erase();
	}
}

 

 

 

 


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

Message 8 of 13
1127204185
in reply to: tbrammer

Thank you!

 

Automatically explode all at once

Message 9 of 13
tbrammer
in reply to: 1127204185

If you want to explode the BREFs recursively use this function instead of bref->explode(entitySet):

Acad::ErrorStatus ExplodeRecursive(AcDbBlockReference* bref, AcDbVoidPtrArray& entitySetTotal)
{
	Acad::ErrorStatus es, esSub;
	AcDbVoidPtrArray entitySet;
	es = bref->explode(entitySet);
	if (es == Acad::eOk) {
		AcDbBlockReference* subBref = nullptr;
		for (void* p : entitySet) {
			if (subBref = AcDbBlockReference::cast((AcDbEntity*)p)) 	{
				esSub = ExplodeRecursive(subBref, entitySetTotal);
				if (esSub == Acad::eOk)
					delete subBref;
				else
					entitySetTotal.append(subBref);
			}
			else
				entitySetTotal.append(p);
		}
	}
	return es;
}

  


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

Message 10 of 13
1127204185
in reply to: tbrammer

Thank you!
Message 11 of 13
racsoapres
in reply to: tbrammer

Great way to explode BlockRefs inside Blockrefs, thanks for sharing this stuff.

Message 12 of 13
463017170
in reply to: tbrammer

Excuse me, can you fry the block, keep the outermost block, and fry the block inside?

Message 13 of 13
tbrammer
in reply to: 463017170

What do you mean by "fry"? I assume that you mean "explode", right?

You can use both ExplodeRecursive(bref, entSet) or bref->explode(entSet) on any AcDbBlockReference *bref whether it resides in the modelspace or in any other "outer" block. There is no difference. In both cases you must erase the exploded BREF and append the resulting entSet to the AcDbBlockTableRecord that owns the BREF.


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

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

Post to forums  

AutoCAD Inside the Factory


Autodesk Design & Make Report