Exploding AEC entities using RealDWG

<?xml encoding=”UTF-8″>By Balaji Ramamoorthy

Exploding an AEC entity such as a Wall in AutoCAD results in a block reference and the block table record that it refers to contains faces. But when exploding the Wall entity in a RealDWG application results in a block reference and the block table record that it refers to contains lines. 

In this blog post we will look into the reason for this difference and a way to workaround it. The workaround was provided by my colleagues Mikako Harada and Tony Zou. Many thanks to them.

While RealDWG can read a drawing created by any of the AutoCAD verticals, the object enablers specific to the verticals will still be needed for the host application to recognize the entities in that drawing. The object enabler defines the resulting entity set when the entity is exploded. As object enabler provides the explode functionality for its custom entities, they may also have other considerations.

For example, when an AEC drawing has its viewing direction set as Top View, a wall appears as a rectangle. When the viewing direction is any other view, the wall appears as a collection of faces. 

Also, AEC drawings do not fully load into a side database when using the readDwgFile. This is a known behavior in AutoCAD Architecture and here is a blog post by my colleague Adam Nagy. For the database to get fully loaded in a side database it is required to call AecAppDbx::drawingPromoterAndIniter method.

Considering the above reasons, here are the C++ and .Net sample codes to explode a wall entity in a RealDWg application. The methods to have the database initialized and to set its viewing direction are invoked by accessing the exported methods from AecBase.dbx using their ordinal numbers. Please note that the ordinal numbers can change and are version specific. In the below code, the ordinal numbers for 2015 and 2016 releases are provided. For any other version, you may need to find them out using dumpbin on AecBase.lib from the Lib-x64 folder.

Here is the C# code snippet :

 <span>using</span><span>  System.Runtime.InteropServices;</span>
 <span>using</span><span>  Autodesk.AutoCAD.Runtime;</span>
 
 <span>internal</span><span>  <span>static</span><span>  <span>class</span><span>  <span>Workaround</span><span> </span></span></span></span>
 <span>{</span>
     [<span>StructLayout</span><span> (<span>LayoutKind</span><span> .Sequential)]</span></span>
     <span>private</span><span>  <span>struct</span><span>  <span>AcGeVector3d</span><span> </span></span></span>
     <span>{</span>
         <span>public</span><span>  <span>double</span><span>  x;</span></span>
         <span>public</span><span>  <span>double</span><span>  y;</span></span>
         <span>public</span><span>  <span>double</span><span>  z;</span></span>
     <span>}</span>
 
     <span>// for 2016</span><span> </span>
     <span>//[DllImport(@"C:\Program Files\Autodesk\RealDWG 2015\AecBase.dbx", </span><span> </span>
     <span>//        CallingConvention = CallingConvention.Cdecl, </span><span> </span>
     <span>//        EntryPoint = "#1202")]</span><span> </span>
    
     <span>// for 2015</span><span> </span>
     [<span>DllImport</span><span> (<span>@"C:\Program Files\Autodesk\RealDWG 2015\AecBase.dbx"</span><span> , </span></span>
         CallingConvention = <span>CallingConvention</span><span> .Cdecl, </span>
         EntryPoint = <span>"#1204"</span><span> )]   </span>
 
     <span>private</span><span>  <span>extern</span><span>  <span>static</span><span>  <span>void</span><span>  setLastViewDir(<span>ref</span><span>  <span>AcGeVector3d</span><span>  vDir);</span></span></span></span></span></span>
 
     <span>public</span><span>  <span>static</span><span>  <span>void</span><span>  SetLastViewDirection(Vector3d direction)</span></span></span>
     <span>{</span>
         <span>if</span><span>  (! SystemObjects.ServiceDictionary.Contains(</span>
             <span>"AecBaseServices"</span><span> ))</span>
             <span>return</span><span> ;</span>
         <span>AcGeVector3d</span><span>  vec;</span>
         vec.x = direction.X;
         vec.y = direction.Y;
         vec.z = direction.Z;
         setLastViewDir(<span>ref</span><span>  vec);</span>
     <span>}</span>
 <span>}</span>
 
 <span>// No change in ordinals</span><span> </span>
 <span>// For 2015 and 2016</span><span> </span>
 [<span>DllImport</span><span> (<span>@"C:\Program Files\Autodesk\RealDWG 2015\AecBase.dbx"</span><span> , </span></span>
     CallingConvention = <span>CallingConvention</span><span> .Cdecl, </span>
     CharSet = <span>CharSet</span><span> .Unicode, EntryPoint = <span>"#897"</span><span> )] </span></span>
 <span>public</span><span>  <span>extern</span><span>  <span>static</span><span>  <span>void</span><span>  drawingPromoterAndIniter</span></span></span></span>
 (IntPtr db, <span>bool</span><span>  sideDb);</span>
 
 
 Database db = <span>new</span><span>  Database(<span>false</span><span> , <span>true</span><span> );</span></span></span>
 
 db.ReadDwgFile(
     <span>@"D:\Temp\wall.dwg"</span><span> , </span>
     System.IO.FileShare.None, 
     <span>false</span><span> , </span>
     <span>""</span><span> );</span>
 
 HostApplicationServices.WorkingDatabase = db;
 
 drawingPromoterAndIniter(db.UnmanagedObject, <span>true</span><span> );</span>
 Workaround.SetLastViewDirection(Vector3d.XAxis);
 
 <span>//... Usual Explode of the entity</span>
 

Here is the C++ code snippet :

 typedef <span>void</span><span>  (*drawingPromoterAndIniter)</span>
     (AcDbDatabase* pDb, <span>bool</span><span>  bUseCurrentViewInfo);</span>
 typedef <span>void</span><span>  (*setLastViewDir)(AcGeVector3d direction);</span>
 
 
 acdbSetHostApplicationServices(&gDumpDwgHostApp);
 	
 CString testFilePath = <span>"D:\\Temp\\wall.dwg"</span><span> ;</span>
 
 <span>long</span><span>  lcid = 0x00000409;  <span>// English</span><span> </span></span>
 acdbValidateSetup(lcid);
 
 <span>bool</span><span>  isLoaded = acrxLoadModule(</span>
     _T(<span>"C:\\Program Files\\Autodesk\\RealDWG 2016\\AecBase.dbx"</span><span> ), 0);</span>
 
 HMODULE hModule=GetModuleHandle(_T(<span>"AecBase.dbx"</span><span> ));</span>
 <span>int</span><span>  ordinal = 897;</span>
 auto drawingPromoterFunc = 
     (drawingPromoterAndIniter)GetProcAddress(hModule, (LPCSTR) ordinal);
 <span>if</span><span>  (drawingPromoterFunc == nullptr) </span>
 <span>{</span>
 	AfxMessageBox(_T(<span>"Error ! function not in AecBase.dbx !!"</span><span> ));</span>
 	<span>return</span><span>  1;</span>
 <span>}</span>
 
 ordinal = 1202; <span>// 2016</span><span> </span>
 <span>//ordinal = 1204; //2015</span><span> </span>
 auto setLastViewDirFunc = 
     (setLastViewDir)GetProcAddress(hModule, (LPCSTR) ordinal);
 <span>if</span><span>  (setLastViewDirFunc == nullptr) </span>
 <span>{</span>
 	AfxMessageBox(_T(<span>"Error ! function not in AecBase.dbx !!"</span><span> ));</span>
 	<span>return</span><span>  1;</span>
 <span>}</span>
 	
 AcDbDatabase *pDb = <span>new</span><span>  AcDbDatabase(Adesk::kFalse);</span>
 <span>if</span><span>  (pDb == NULL)</span>
     <span>return</span><span>  1;</span>
 
 Acad::ErrorStatus es = Acad::eOk;
 es = pDb->readDwgFile(testFilePath);
 
 acdbHostApplicationServices()->setWorkingDatabase(pDb);
 acdbResolveCurrentXRefs(pDb);
 drawingPromoterFunc(pDb, <span>false</span><span> );</span>
 
 setLastViewDirFunc(AcGeVector3d::kXAxis);
 
 <span>//... Usual Explode of the entity</span>
 


Comments

3 responses to “Exploding AEC entities using RealDWG”

  1. Hi, thanx for this example, but i am fairly new to this and i am having trouble using your example to extract values from a propertyset wich is attached to a solid3D.
    When i try to Pinvoke the loading of side databases, my application crashes. Is the correct ordinal used in the example? When i generate a list of exports using dumpbin the only readable function name that resembles the function you are using is:
    106 7 00177990 drawingPromoterAndInitialize
    When i run my code from whitin ACA, it run’s fine and values are extracted; but using RealDWG i keep getting a ProxyObject instead of a PropertySet.
    Any hint’s a to what i a doing wrong?

  2. Sorry for the delay. I hadn’t noticed your comment to this post.
    I have posted a reply to your discussion forum post on the same topic
    http://forums.autodesk.com/t5/net/use-objectdbx-realdwg-to-read-propertysetdef-from-solid3d/m-p/5955500#M46959
    Thanks
    Balaji

  3. What are ordinal numbers for RealDWG 2017?

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading