<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: readBlockEntities (block within block) in ObjectARX Forum</title>
    <link>https://forums.autodesk.com/t5/objectarx-forum/readblockentities-block-within-block/m-p/13069599#M406</link>
    <description>&lt;P&gt;It seems that you try to "explode" a blockreference (BREF) with the ID&amp;nbsp;&lt;FONT face="courier new,courier"&gt;blkid&lt;/FONT&gt; and collect the fragments in&amp;nbsp;&lt;FONT face="courier new,courier"&gt;AcDbObjectIdArray &amp;amp;ids&lt;/FONT&gt;.&lt;/P&gt;
&lt;P&gt;The idea to treat block references by recursion is basically right. But the way you implemented it has several issues.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;You are opening the entities twice in two different ways, which is neither elegant nor performant.&lt;BR /&gt;&lt;FONT face="courier new,courier"&gt;&amp;nbsp; iter-&amp;gt;getEntity(pEnt1, AcDb::kForRead)&lt;/FONT&gt;&lt;BR /&gt;&lt;FONT face="courier new,courier"&gt;&amp;nbsp; AcDbObjectPointer&amp;lt;AcDbBlockReference&amp;gt; pEnt(id, AcDb::kForRead);&lt;/FONT&gt;&lt;BR /&gt;Better use&amp;nbsp;&lt;BR /&gt;&lt;FONT face="courier new,courier"&gt;&amp;nbsp; AcDbBlockReference *pEnt = AcDbBlockReference::cast(pEnt1);&lt;/FONT&gt;&lt;BR /&gt;&lt;FONT face="courier new,courier"&gt;pEnt&lt;/FONT&gt; will be NULL if&amp;nbsp; &lt;FONT face="courier new,courier"&gt;pEnt1&amp;nbsp;&lt;/FONT&gt;is not a block reference.&lt;BR /&gt;&lt;BR /&gt;&lt;/LI&gt;
&lt;LI&gt;You open &lt;FONT face="courier new,courier"&gt;pEnt1&lt;/FONT&gt;&amp;nbsp; for &lt;U&gt;read only&lt;/U&gt; and try to modify it with&amp;nbsp;&lt;FONT face="courier new,courier"&gt;pEnt1-&amp;gt;transformBy(blkmat);&lt;/FONT&gt;
&lt;OL&gt;
&lt;LI&gt;This will crash AutoCAD. You must open the entity &lt;FONT face="courier new,courier"&gt;kForWrite&lt;/FONT&gt;.&lt;/LI&gt;
&lt;LI&gt;Even if you open the entity for write: Transforming it is probably &lt;STRONG&gt;not&lt;/STRONG&gt; what you want, because it will modify the BREF's block itself and all it's nested blocks! The final array &lt;FONT face="courier new,courier"&gt;ids&lt;/FONT&gt;&amp;nbsp;would contain ids of entities from different blocks which is pretty useless. At this point the question is: What do you expect as result?&lt;BR /&gt;Usually you would create a transformed copy i.e. with&amp;nbsp; &lt;BR /&gt;&lt;FONT face="courier new,courier"&gt;&amp;nbsp; &amp;nbsp;pEnt1-&amp;gt;getTransformedCopy(blkmat, pEntCopy);&lt;/FONT&gt;&lt;BR /&gt;and append it to a block record - maybe to modelspace.&lt;BR /&gt;&lt;BR /&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;/LI&gt;
&lt;LI&gt;When you find an&amp;nbsp;&lt;FONT face="courier new,courier"&gt;AcDbBlockReference &lt;/FONT&gt;you and you call&amp;nbsp;&lt;FONT face="courier new,courier"&gt;readBlockEntities()&lt;/FONT&gt; recursive you must pass the current transformation matrix&amp;nbsp;&lt;FONT face="courier new,courier"&gt;blkmat&lt;/FONT&gt; and multiply the transformation matrix with the "owner matrix".&lt;BR /&gt;This would look like this:&lt;BR /&gt;&lt;LI-CODE lang="cpp"&gt;void readBlockEntities(const AcGeMatrix3d &amp;amp;matOwner, ..) 
{
  AcGeMatrix3d blkmat = matOwner * pBlkRef-&amp;gt;blockTransform();
  ...
  if (pBref)
    readBlockEntities(blkmat, id, nestedIds);
}​&lt;/LI-CODE&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Tue, 08 Oct 2024 07:04:01 GMT</pubDate>
    <dc:creator>tbrammer</dc:creator>
    <dc:date>2024-10-08T07:04:01Z</dc:date>
    <item>
      <title>readBlockEntities (block within block)</title>
      <link>https://forums.autodesk.com/t5/objectarx-forum/readblockentities-block-within-block/m-p/13068955#M405</link>
      <description>&lt;LI-CODE lang="cpp"&gt;	static void readBlockEntities(const AcDbObjectId&amp;amp; blkid , AcDbObjectIdArray &amp;amp;ids)
	{
		AcDbBlockTableRecordIterator* iter;
		AcDbBlockReference* pBlkRef;
		AcDbBlockTableRecord* pRecord;
		Acad::ErrorStatus es = acdbOpenObject(pBlkRef, blkid, AcDb::kForRead);
		if (es != Acad::eOk)
			return;
		AcDbObjectId blockTableRecordId = pBlkRef-&amp;gt;blockTableRecord();
		AcGeMatrix3d blkmat = pBlkRef-&amp;gt;blockTransform();
		pBlkRef-&amp;gt;close();
		es = acdbOpenObject(pRecord, blockTableRecordId, AcDb::kForWrite);
		if (es != Acad::eOk || pRecord == NULL)
			return;
		pRecord-&amp;gt;newIterator(iter);
		for (iter-&amp;gt;start(); !iter-&amp;gt;done(); iter-&amp;gt;step())
		{
			AcDbObjectId id;
			AcDbEntity* pEnt1 = NULL;
			es = iter-&amp;gt;getEntityId(id);
			es = iter-&amp;gt;getEntity(pEnt1, AcDb::kForRead);
			if (es != Acad::eOk || !id.isValid())continue;

			AcDbObjectPointer&amp;lt;AcDbBlockReference&amp;gt; pEnt(id, AcDb::kForRead);
			if (pEnt.openStatus() == Acad::eOk)
			{
				pEnt1-&amp;gt;close();
				AcDbObjectIdArray nestedIds;
				readBlockEntities(id, nestedIds);
				ids.append(nestedIds);
			} 
			else
			{	
				pEnt1-&amp;gt;transformBy(blkmat);
				ids.append(id);
				pEnt1-&amp;gt;close();
			}
			
		}
		delete iter;
		pRecord-&amp;gt;close();
	}&lt;/LI-CODE&gt;</description>
      <pubDate>Mon, 07 Oct 2024 11:39:35 GMT</pubDate>
      <guid>https://forums.autodesk.com/t5/objectarx-forum/readblockentities-block-within-block/m-p/13068955#M405</guid>
      <dc:creator>1127204185</dc:creator>
      <dc:date>2024-10-07T11:39:35Z</dc:date>
    </item>
    <item>
      <title>Re: readBlockEntities (block within block)</title>
      <link>https://forums.autodesk.com/t5/objectarx-forum/readblockentities-block-within-block/m-p/13069599#M406</link>
      <description>&lt;P&gt;It seems that you try to "explode" a blockreference (BREF) with the ID&amp;nbsp;&lt;FONT face="courier new,courier"&gt;blkid&lt;/FONT&gt; and collect the fragments in&amp;nbsp;&lt;FONT face="courier new,courier"&gt;AcDbObjectIdArray &amp;amp;ids&lt;/FONT&gt;.&lt;/P&gt;
&lt;P&gt;The idea to treat block references by recursion is basically right. But the way you implemented it has several issues.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;You are opening the entities twice in two different ways, which is neither elegant nor performant.&lt;BR /&gt;&lt;FONT face="courier new,courier"&gt;&amp;nbsp; iter-&amp;gt;getEntity(pEnt1, AcDb::kForRead)&lt;/FONT&gt;&lt;BR /&gt;&lt;FONT face="courier new,courier"&gt;&amp;nbsp; AcDbObjectPointer&amp;lt;AcDbBlockReference&amp;gt; pEnt(id, AcDb::kForRead);&lt;/FONT&gt;&lt;BR /&gt;Better use&amp;nbsp;&lt;BR /&gt;&lt;FONT face="courier new,courier"&gt;&amp;nbsp; AcDbBlockReference *pEnt = AcDbBlockReference::cast(pEnt1);&lt;/FONT&gt;&lt;BR /&gt;&lt;FONT face="courier new,courier"&gt;pEnt&lt;/FONT&gt; will be NULL if&amp;nbsp; &lt;FONT face="courier new,courier"&gt;pEnt1&amp;nbsp;&lt;/FONT&gt;is not a block reference.&lt;BR /&gt;&lt;BR /&gt;&lt;/LI&gt;
&lt;LI&gt;You open &lt;FONT face="courier new,courier"&gt;pEnt1&lt;/FONT&gt;&amp;nbsp; for &lt;U&gt;read only&lt;/U&gt; and try to modify it with&amp;nbsp;&lt;FONT face="courier new,courier"&gt;pEnt1-&amp;gt;transformBy(blkmat);&lt;/FONT&gt;
&lt;OL&gt;
&lt;LI&gt;This will crash AutoCAD. You must open the entity &lt;FONT face="courier new,courier"&gt;kForWrite&lt;/FONT&gt;.&lt;/LI&gt;
&lt;LI&gt;Even if you open the entity for write: Transforming it is probably &lt;STRONG&gt;not&lt;/STRONG&gt; what you want, because it will modify the BREF's block itself and all it's nested blocks! The final array &lt;FONT face="courier new,courier"&gt;ids&lt;/FONT&gt;&amp;nbsp;would contain ids of entities from different blocks which is pretty useless. At this point the question is: What do you expect as result?&lt;BR /&gt;Usually you would create a transformed copy i.e. with&amp;nbsp; &lt;BR /&gt;&lt;FONT face="courier new,courier"&gt;&amp;nbsp; &amp;nbsp;pEnt1-&amp;gt;getTransformedCopy(blkmat, pEntCopy);&lt;/FONT&gt;&lt;BR /&gt;and append it to a block record - maybe to modelspace.&lt;BR /&gt;&lt;BR /&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;/LI&gt;
&lt;LI&gt;When you find an&amp;nbsp;&lt;FONT face="courier new,courier"&gt;AcDbBlockReference &lt;/FONT&gt;you and you call&amp;nbsp;&lt;FONT face="courier new,courier"&gt;readBlockEntities()&lt;/FONT&gt; recursive you must pass the current transformation matrix&amp;nbsp;&lt;FONT face="courier new,courier"&gt;blkmat&lt;/FONT&gt; and multiply the transformation matrix with the "owner matrix".&lt;BR /&gt;This would look like this:&lt;BR /&gt;&lt;LI-CODE lang="cpp"&gt;void readBlockEntities(const AcGeMatrix3d &amp;amp;matOwner, ..) 
{
  AcGeMatrix3d blkmat = matOwner * pBlkRef-&amp;gt;blockTransform();
  ...
  if (pBref)
    readBlockEntities(blkmat, id, nestedIds);
}​&lt;/LI-CODE&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 08 Oct 2024 07:04:01 GMT</pubDate>
      <guid>https://forums.autodesk.com/t5/objectarx-forum/readblockentities-block-within-block/m-p/13069599#M406</guid>
      <dc:creator>tbrammer</dc:creator>
      <dc:date>2024-10-08T07:04:01Z</dc:date>
    </item>
    <item>
      <title>Re: readBlockEntities (block within block)</title>
      <link>https://forums.autodesk.com/t5/objectarx-forum/readblockentities-block-within-block/m-p/13070245#M407</link>
      <description>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。</description>
      <pubDate>Mon, 07 Oct 2024 22:41:56 GMT</pubDate>
      <guid>https://forums.autodesk.com/t5/objectarx-forum/readblockentities-block-within-block/m-p/13070245#M407</guid>
      <dc:creator>1127204185</dc:creator>
      <dc:date>2024-10-07T22:41:56Z</dc:date>
    </item>
    <item>
      <title>Re: readBlockEntities (block within block)</title>
      <link>https://forums.autodesk.com/t5/objectarx-forum/readblockentities-block-within-block/m-p/13070932#M408</link>
      <description>&lt;P&gt;Try this:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;LI-CODE lang="cpp"&gt;void readBlockEntities(const AcGeMatrix3d&amp;amp; matOwner, AcDbBlockReference *pBlkRef, AcDbBlockTableRecord *pTargetBlock, AcDbObjectIdArray&amp;amp; ids)
{
	if (!pBlkRef || !pTargetBlock)
		return;
	AcDbBlockTableRecordIterator* iter;
	AcDbBlockTableRecord* pRecord;
	Acad::ErrorStatus es;
	AcDbObjectId blockTableRecordId = pBlkRef-&amp;gt;blockTableRecord();
	AcGeMatrix3d blkmat = matOwner * pBlkRef-&amp;gt;blockTransform();
	pBlkRef-&amp;gt;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-&amp;gt;newIterator(iter);
	for (iter-&amp;gt;start(); !iter-&amp;gt;done(); iter-&amp;gt;step())
	{
		AcDbEntity* pEnt1 = NULL;		
		es = iter-&amp;gt;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-&amp;gt;getTransformedCopy(blkmat, pNewEnt);
			if (!es)
			{
				es = pTargetBlock-&amp;gt;appendAcDbEntity(pNewEnt);
				if (es)
					delete pNewEnt;
				else
				{
					ids.append(pNewEnt-&amp;gt;objectId());
					pNewEnt-&amp;gt;close();
				}
			}
		}
		pEnt1-&amp;gt;close();

	}
	delete iter;
	pRecord-&amp;gt;close();
}

void readBlockEntities(const AcDbObjectId&amp;amp; blkid, AcDbObjectIdArray&amp;amp; 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-&amp;gt;database();
	AcDbObjectId IdModelSpace = acdbSymUtil()-&amp;gt;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-&amp;gt;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);
}
&lt;/LI-CODE&gt;</description>
      <pubDate>Tue, 08 Oct 2024 07:34:47 GMT</pubDate>
      <guid>https://forums.autodesk.com/t5/objectarx-forum/readblockentities-block-within-block/m-p/13070932#M408</guid>
      <dc:creator>tbrammer</dc:creator>
      <dc:date>2024-10-08T07:34:47Z</dc:date>
    </item>
    <item>
      <title>Re: readBlockEntities (block within block)</title>
      <link>https://forums.autodesk.com/t5/objectarx-forum/readblockentities-block-within-block/m-p/13071634#M409</link>
      <description>Thank you very much!</description>
      <pubDate>Tue, 08 Oct 2024 13:35:58 GMT</pubDate>
      <guid>https://forums.autodesk.com/t5/objectarx-forum/readblockentities-block-within-block/m-p/13071634#M409</guid>
      <dc:creator>1127204185</dc:creator>
      <dc:date>2024-10-08T13:35:58Z</dc:date>
    </item>
  </channel>
</rss>

