Author Topic: Relative speed of SelectionSets and Iterating a DB.  (Read 3032 times)

0 Members and 1 Guest are viewing this topic.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 10732
  • class keyThumper<T>:ILazy<T>
Relative speed of SelectionSets and Iterating a DB.
« on: March 15, 2008, 05:06:08 am »
I may have learnt something today ... again :-).

I was perusing http://discussion.autodesk.com/thread.jspa?threadID=650451 and saw a recent discussion which provided VB code to collect all attributes from modelspace and write the values to a file.
The solution iterated the DB and tested each entity to see if it was a block, with attributes ; if so write the tag and value to a file.
[rinse and repeat]
From: caddie75
Date: Mar/15/08 - 06:42 (EST)
with [Attachment: Test_attReads.vb.txt]


I thought that Iterating the DB would be uber slow so I've put together a quick test to see how using a selection set compared.

I built a drawing which has 12103 entities mixed as simple ents, blocks without atts and attributed blocks.

this is the resulting output :

Command: Test_01
End eval...Process time: 0.34375 Seconds for 1980 records of 12103
Command: Test_02
End eval...Process time: 0.4375 Seconds for 1980 records of 12103

not much of a difference !

and the code :
note .. you may want to change the .txt file address or names.
The code could probable be optimised a little :-)

Code - C#: [Select]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6.  
  7. using Autodesk.AutoCAD.ApplicationServices;
  8. using Autodesk.AutoCAD.DatabaseServices;
  9. using Autodesk.AutoCAD.EditorInput;
  10. using Autodesk.AutoCAD.Geometry;
  11. using Autodesk.AutoCAD.Runtime;
  12.  
  13. using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
  14. using AcAp = Autodesk.AutoCAD.ApplicationServices;
  15. using AcDb = Autodesk.AutoCAD.DatabaseServices;
  16. using AcEd = Autodesk.AutoCAD.EditorInput;
  17. using AcGe = Autodesk.AutoCAD.Geometry;
  18. using AcRx = Autodesk.AutoCAD.Runtime;
  19. //
  20. using AcUi = Autodesk.AutoCAD.Windows;
  21.  
  22.  
  23. namespace kdubTestingCommands
  24. {
  25.    public partial class TestCommands
  26.    {
  27.        //
  28.        // // CodeHimBelongaKwb ©  Mar 2008
  29.        //
  30.        [CommandMethod("Test_01")]
  31.        public void getBlocksTest()
  32.        {
  33.            DateTime TimeStart = DateTime.Now;
  34.            string FileNamePath = @"D:\EvalReport_01.txt";
  35.            Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
  36.  
  37.            ObjectId[] selectedIDs = SelectBlockRefs03();
  38.            if (selectedIDs == null) return;
  39.  
  40.            StreamWriter LogFile_Obj = new StreamWriter(FileNamePath, true, System.Text.Encoding.ASCII);
  41.            LogFile_Obj.AutoFlush = true;
  42.            LogFile_Obj.WriteLine("Starting eval...");
  43.            int countAtts = 0;
  44.            Database db = AcDb.HostApplicationServices.WorkingDatabase;
  45.            AcDb.TransactionManager tm = AcadApp.DocumentManager.MdiActiveDocument.TransactionManager;
  46.  
  47.            using (Transaction tr = tm.StartTransaction())
  48.            {
  49.                try
  50.                {
  51.                    foreach (ObjectId entID in selectedIDs)
  52.                    {
  53.                        BlockReference blkRef = tr.GetObject(entID, OpenMode.ForRead, false)
  54.                            as BlockReference;
  55.                        foreach (ObjectId attId in blkRef.AttributeCollection)
  56.                        {
  57.                            AttributeReference attRef = tr.GetObject(attId, OpenMode.ForRead)
  58.                                as AttributeReference;
  59.                            if (!(attRef == null))
  60.                            {
  61.                                countAtts = countAtts + 1;
  62.                                LogFile_Obj.WriteLine(countAtts.ToString() + '\t' +
  63.                                                 attRef.Tag + '\t' + attRef.TextString);
  64.                            }
  65.                        }
  66.                    }
  67.                    TimeSpan TimeDuration = (DateTime.Now - TimeStart);
  68.                    ed.WriteMessage("End eval...Process time: "
  69.                            + (TimeDuration.TotalSeconds + " Seconds for "
  70.                            + countAtts.ToString() + " records of "
  71.                            + db.ApproxNumObjects.ToString()));                    
  72.                    LogFile_Obj.WriteLine(("End eval...Process time: "
  73.                            + (TimeDuration.TotalSeconds + " Seconds.")));
  74.                }
  75.                catch
  76.                {
  77.                    ed.WriteMessage("Ooops");
  78.                }
  79.                finally
  80.                {
  81.                    LogFile_Obj.Close();
  82.                }
  83.            }
  84.        }
  85.        //
  86.        // // CodeHimBelongaKwb ©  Mar 2008
  87.        //
  88.        static public ObjectId[] SelectBlockRefs03()
  89.        {
  90.            Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
  91.            TypedValue[] tValues =
  92.                { new TypedValue((int)DxfCode.Start, "INSERT"),
  93.                  new TypedValue((int)DxfCode.LayerName, "BLOCKS"),
  94.                  new TypedValue(410, "Model"),                  
  95.                  new TypedValue(66, 1) // hasAttributes ?
  96.                };
  97.  
  98.            SelectionFilter sFilter = new SelectionFilter(tValues);
  99.  
  100.            PromptSelectionResult res = ed.SelectAll(sFilter);
  101.  
  102.            if (res.Status != PromptStatus.OK) return null;
  103.            return res.Value.GetObjectIds();
  104.        }
  105.  
  106.        //
  107.        // Translated from VB code AT http://discussion.autodesk.com/thread.jspa?threadID=650451
  108.        //
  109.        [CommandMethod("Test_02")]
  110.        public void Test_ReadWriteAttData()
  111.        {
  112.            DateTime TimeStart = DateTime.Now;
  113.            string FileNamePath = @"D:\EvalReport_02.txt";
  114.            Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
  115.  
  116.            StreamWriter LogFile_Obj = new StreamWriter(FileNamePath, true, System.Text.Encoding.ASCII);
  117.            LogFile_Obj.AutoFlush = true;
  118.  
  119.            LogFile_Obj.WriteLine("Starting eval...");
  120.  
  121.            int countAtts = 0;
  122.  
  123.            Database db = AcDb.HostApplicationServices.WorkingDatabase;
  124.            AcDb.TransactionManager tm = AcadApp.DocumentManager.MdiActiveDocument.TransactionManager;
  125.  
  126.            using (Transaction tr = tm.StartTransaction())
  127.            {
  128.                try
  129.                {
  130.                    BlockTable table = tm.GetObject
  131.                          (db.BlockTableId, OpenMode.ForRead, false) as BlockTable;
  132.                    BlockTableRecord modelSpace = tm.GetObject(table[BlockTableRecord.ModelSpace],
  133.                        OpenMode.ForWrite, false) as BlockTableRecord;
  134.  
  135.                    foreach (ObjectId objId in modelSpace)
  136.                    {
  137.                        Entity ent = tr.GetObject(objId, OpenMode.ForRead, false) as Entity;
  138.                        if (ent.GetType().FullName.Equals("Autodesk.AutoCAD.DatabaseServices.BlockReference"))
  139.                        {
  140.                            BlockReference blkRef = ent as BlockReference;
  141.                            if (blkRef.Layer == "BLOCKS")
  142.                            {
  143.                                foreach (ObjectId attId in blkRef.AttributeCollection)
  144.                                {
  145.                                    AttributeReference attRef = tr.GetObject(attId, OpenMode.ForRead)
  146.                                        as AttributeReference;
  147.                                    if (!(attRef == null))
  148.                                    {
  149.                                        countAtts = countAtts + 1;
  150.                                        LogFile_Obj.WriteLine(countAtts.ToString() + '\t' +
  151.                                                         attRef.Tag + '\t' + attRef.TextString);
  152.                                    }
  153.                                }
  154.                            }
  155.                        }
  156.                    }
  157.                    TimeSpan TimeDuration = (DateTime.Now - TimeStart); ;
  158.                    ed.WriteMessage("End eval...Process time: "
  159.                            + (TimeDuration.TotalSeconds + " Seconds for "
  160.                            + countAtts.ToString() + " records of "
  161.                            + db.ApproxNumObjects.ToString()));
  162.                    LogFile_Obj.WriteLine(("End eval...Process time: "
  163.                            + (TimeDuration.TotalSeconds + " Seconds.")));
  164.                }
  165.                catch
  166.                {
  167.                    ed.WriteMessage("Ooops");
  168.                }
  169.                finally
  170.                {
  171.                    LogFile_Obj.Close();
  172.                }
  173.            }
  174.        }
  175.    }
  176. }


edit:kdub code=csharp
« Last Edit: August 16, 2012, 10:18:05 pm by Kerry »
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

--> Donate<--

nullptr

  • Bricscad
  • Needs a day job
  • Posts: 6584
  • AKA Daniel
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #1 on: March 15, 2008, 07:26:37 am »
Code: [Select]
Command: Test_01
End eval...Process time: 0.1802592 Seconds for 923 records of 109993
Command: Test_02
End eval...Process time: 0.4306192 Seconds for 923 records of 109993

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 10732
  • class keyThumper<T>:ILazy<T>
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #2 on: March 15, 2008, 07:51:11 am »

Those relationships sound about right Daniel ..

The less blocks in the drawing the better the advantage of the SelectionSet methodology.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

--> Donate<--

nullptr

  • Bricscad
  • Needs a day job
  • Posts: 6584
  • AKA Daniel
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #3 on: March 15, 2008, 09:16:17 am »

Those relationships sound about right Daniel ..

The less blocks in the drawing the better the advantage of the SelectionSet methodology.

I suspect that the selection set method will always be faster since itís native code.

Glenn R

  • Water Moccasin
  • Posts: 1932
  • What idiot child of married cousins wrote this?!
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #4 on: March 15, 2008, 04:20:14 pm »
Kerry,

For the benefit of the VB (cough) people who probably don't read C# code that well (if at all) ;), could you also state which test is which? ie. is Test_01 the selection set and Test_02 the database iteration or vice versa.

Also, I can't remember whether the filtered selectionset method will get a blockreference with attributes that is nested inside a blockreference that doesn't contain attributes, if you know what I mean.

Also (hate to repeat that word for another sentence), but the quickest way in my mind to accomplish the stated goal, would be to roll over the BlockTable (excluding layouts of course) and check the HasAttributeDefinitions property of each BlockTableRecord (BTR). If this is true, then use the GetBlockReferenceIds method to get the actual inserts and process from there...does that make sense?

I think you would find that this would out perform the selectionset approach...but I maybe wrong of course  :-)

Cheers,
Glenn.
Me

nullptr

  • Bricscad
  • Needs a day job
  • Posts: 6584
  • AKA Daniel
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #5 on: March 15, 2008, 09:33:36 pm »
Just so we can compare apples and other types of fruit,
native code will iterate though the DB using the same dwg at a smashing 0.030 seconds  :-o

Code: [Select]
static void GetAttributesBench_doit(void)
  {
    clock_t start, end;
    double diff;
    start = clock();
   
    Acad::ErrorStatus es;
    int counter = 0;

    wofstream out("D:\\EvalReport_03.txt");

    AcDbBlockTableRecord *pTableRecord;

    AcDbDatabase *pDatabase =
      acdbHostApplicationServices()->workingDatabase();

    AcDbBlockTablePointer
      pBlockTable(pDatabase,AcDb::kForRead);

    AcDbBlockTableIterator *pBlockTableIterator;
    pBlockTable->newIterator(pBlockTableIterator);

    for (pBlockTableIterator->start();
        !pBlockTableIterator->done();
        pBlockTableIterator->step())
    {
      es = pBlockTableIterator->getRecord(pTableRecord, AcDb::kForRead,Adesk::kFalse);
      if (es == Acad::eOk &&  pTableRecord->hasAttributeDefinitions() == Adesk::kTrue)
      {
        AcDbObjectIdArray blockReferenceIds;
        pTableRecord->getBlockReferenceIds(blockReferenceIds);

        for(int i = 0 ; i < blockReferenceIds.length() ; i++)
        {

          AcDbObjectPointer<AcDbBlockReference> pBlockReference
            (blockReferenceIds[i] , AcDb::kForRead,Adesk::kFalse);

          AcDbObjectIterator* pAttributeIterator;
          pAttributeIterator = pBlockReference->attributeIterator();

          for (pAttributeIterator->start();
              !pAttributeIterator->done();
               pAttributeIterator->step())
          {
            if ( wcscmp(pBlockReference->layer(), _T("1_8_TEXT")) == 0)
            {
              AcDbObjectPointer<AcDbAttribute> pAttribute
                (pAttributeIterator->objectId(),AcDb::kForRead,Adesk::kFalse);

              counter += 1;
              out << "\n" << counter << " " << pAttribute->tag() << " " << pAttribute->textString();
            }
          }
        }
        pTableRecord->close();
      }
    }
    delete pBlockTableIterator;
    out.close();
    end = clock();
    diff = ((double)(end - start)) / CLOCKS_PER_SEC;
    acutPrintf( _T("\n%2.3f seconds\n"), diff);
  }

Glenn R

  • Water Moccasin
  • Posts: 1932
  • What idiot child of married cousins wrote this?!
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #6 on: March 16, 2008, 05:58:12 am »
Dan, can you either post your dwg or try the same method in C# so we actually can compare :)
Me

nullptr

  • Bricscad
  • Needs a day job
  • Posts: 6584
  • AKA Daniel
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #7 on: March 16, 2008, 06:27:07 am »
this was the result of testing Kerrys code on the Same DWG
http://www.theswamp.org/index.php?topic=21930.msg264792#msg264792

nullptr

  • Bricscad
  • Needs a day job
  • Posts: 6584
  • AKA Daniel
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #8 on: March 16, 2008, 06:29:15 am »
How about we make a test DWG to play with as this one is for a customer   :-D

nullptr

  • Bricscad
  • Needs a day job
  • Posts: 6584
  • AKA Daniel
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #9 on: March 16, 2008, 06:31:00 am »
Out of curiosity, I ported this over to DRX, just to see how Bricscad would perform. I honestly thought AutoCAD would give this little clone a spanking, but to my amazement, the performance was identical at 0.030 seconds. Wow!

Code: [Select]
int doit()
{
  clock_t start, end;
  double diff;
  start = clock();
  int counter = 0;
  wofstream out("D:\\EvalReport_04.txt");

  OdApDocManager *pDocMan = odapDocManager();
  OdApDocument* pDoc = pDocMan->curDocument();
  OdDbDatabasePtr pDb = pDoc->database();
  OdDbObjectId blockTableId = pDb->getBlockTableId();
  OdDbBlockTablePtr pBlockTable = blockTableId.openObject(OdDb::kForRead);
  OdDbBlockTableIteratorPtr pBlockTableIterator = pBlockTable->newIterator();

  for (pBlockTableIterator->start();
      !pBlockTableIterator->done();
       pBlockTableIterator->step())
  {
    OdDbBlockTableRecordPtr pTableRecord = pBlockTableIterator->getRecord(OdDb::kForRead);
    if(pTableRecord->hasAttributeDefinitions() == true)
    {
      OdDbObjectIdArray blockReferenceIds;
      pTableRecord->getBlockReferenceIds(blockReferenceIds);

      for(int i = 0 ; i < blockReferenceIds.length() ; i++)
      {
        OdDbBlockReferencePtr pBlockReference = blockReferenceIds[i].openObject(OdDb::kForRead);
        OdDbObjectIteratorPtr pAttributeIterator = pBlockReference->attributeIterator();

        for (pAttributeIterator->start();
             !pAttributeIterator->done();
             pAttributeIterator->step())
        {
          if ( wcscmp(pBlockReference->layer(), _T("1_8_TEXT")) == 0)
          {
            OdDbAttributePtr pAttribute =
              pAttributeIterator->objectId().openObject(OdDb::kForRead);
            counter += 1;
            out << "\n" << counter << " " << pAttribute->tag() << " " << pAttribute->textString();
          }
        }
      }
    }
  }
  out.close();
  end = clock();
  diff = ((double)(end - start)) / CLOCKS_PER_SEC;
  sds_printf( _T("\n%2.3f seconds\n"), diff);
  return (RTNORM);
}



Sorry to hijack your thread Kerry

Glenn R

  • Water Moccasin
  • Posts: 1932
  • What idiot child of married cousins wrote this?!
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #10 on: March 16, 2008, 07:12:00 am »
this was the result of testing Kerrys code on the Same DWG
http://www.theswamp.org/index.php?topic=21930.msg264792#msg264792


That's not what I meant. Kerry's code uses the selset method and iterate modelspace methods to get the work done.
What I would like to see, is your last example in C++ (which did it the way I mentioned) ported to a C# equivalent and that tested against your dwg file.

I would do the code myself, but my wife is nagging at me to do the shopping, so I will be out for a bit. Also, it makes sense for you to test it on your dwg as you've been posting a few different time tests against the same sample set of data...if that makes sense.

I will have a ply when I return from the shopping throngs :)

Cheers,
Glenn.
Me

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 10732
  • class keyThumper<T>:ILazy<T>
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #11 on: March 16, 2008, 08:56:15 am »
<snip>

Sorry to hijack your thread Kerry


not a problem ...  just wish I could make the time to participate more.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

--> Donate<--

nullptr

  • Bricscad
  • Needs a day job
  • Posts: 6584
  • AKA Daniel
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #12 on: March 16, 2008, 08:59:50 am »
Ah ok, yes much much faster at
End eval...Process time: 0.0701008 Seconds for 923 records of 109993

Good call Glenn  :kewl:

Code - C#: [Select]
  1.   [CommandMethod("Test_05")]
  2.    public void Test_ReadWriteAttData()
  3.    {
  4.      DateTime TimeStart = DateTime.Now;
  5.      string FileNamePath = @"D:\EvalReport_05.txt";
  6.      Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
  7.  
  8.      StreamWriter LogFile_Obj =
  9.        new StreamWriter(FileNamePath, true, System.Text.Encoding.ASCII);
  10.  
  11.      LogFile_Obj.AutoFlush = true;
  12.      LogFile_Obj.WriteLine("Starting eval...");
  13.  
  14.      int countAtts = 0;
  15.  
  16.      Database db = AcDb.HostApplicationServices.WorkingDatabase;
  17.  
  18.      AcDb.TransactionManager tm =
  19.        AcadApp.DocumentManager.MdiActiveDocument.TransactionManager;
  20.  
  21.      using (Transaction tr = tm.StartTransaction())
  22.      {
  23.        try
  24.        {
  25.          BlockTable blockTable = tr.GetObject
  26.            (db.BlockTableId, OpenMode.ForRead, false) as BlockTable;
  27.  
  28.          foreach (ObjectId blockTableRecordId in blockTable)
  29.          {
  30.            BlockTableRecord blockTableRecord = tr.GetObject
  31.              (blockTableRecordId, OpenMode.ForRead, false) as BlockTableRecord;
  32.  
  33.            if (blockTableRecord.HasAttributeDefinitions == true)
  34.            {
  35.              ObjectIdCollection blockReferenceIds =
  36.                  blockTableRecord.GetBlockReferenceIds(false, false);
  37.  
  38.              foreach (ObjectId blockReferenceId in blockReferenceIds)
  39.              {
  40.                BlockReference blockReference = tr.GetObject
  41.                  (blockReferenceId, OpenMode.ForRead, false) as BlockReference;
  42.  
  43.                if (blockReference.Layer == "1_8_TEXT")
  44.                {
  45.                  foreach (ObjectId attributeReferenceId in blockReference.AttributeCollection)
  46.                  {
  47.                    AttributeReference attributeReference = tr.GetObject
  48.                      (attributeReferenceId, OpenMode.ForRead) as AttributeReference;
  49.  
  50.                    countAtts = countAtts + 1;
  51.                    LogFile_Obj.WriteLine(countAtts.ToString() + '\t' +
  52.                          attributeReference.Tag + '\t' + attributeReference.TextString);
  53.                  }
  54.                }
  55.              }
  56.            }
  57.          }
  58.          TimeSpan TimeDuration = (DateTime.Now - TimeStart); ;
  59.          ed.WriteMessage("End eval...Process time: "
  60.                  + (TimeDuration.TotalSeconds + " Seconds for "
  61.                  + countAtts.ToString() + " records of "
  62.                  + db.ApproxNumObjects.ToString()));
  63.          LogFile_Obj.WriteLine(("End eval...Process time: "
  64.                  + (TimeDuration.TotalSeconds + " Seconds.")));
  65.        }
  66.        catch(System.Exception ex)
  67.        {
  68.          ed.WriteMessage(ex.Message);
  69.          ed.WriteMessage(ex.StackTrace);
  70.        }
  71.        finally
  72.        {
  73.          LogFile_Obj.Close();
  74.        }
  75.      }
  76.    }
  77.  

edit:kdub code=csharp
« Last Edit: August 16, 2012, 10:20:20 pm by Kerry »

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 10732
  • class keyThumper<T>:ILazy<T>
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #13 on: March 16, 2008, 09:15:27 am »

just a side issue.
the translation from the vb sample is not a pure translation ...I used a bit of artistic license :-)

It may be interesting to compile the VB code and test it too ... it will need a filter for layer added to be functionally comparative.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

--> Donate<--

Glenn R

  • Water Moccasin
  • Posts: 1932
  • What idiot child of married cousins wrote this?!
Re: Relative speed of SelectionSets and Iterating a DB.
« Reply #14 on: March 16, 2008, 09:28:12 am »
Ah ok, yes much much faster at
End eval...Process time: 0.0701008 Seconds for 923 records of 109993

Good call Glenn  :kewl:

Code: [Select]
   [CommandMethod("Test_05")]
    public void Test_ReadWriteAttData()
    {
      DateTime TimeStart = DateTime.Now;
      string FileNamePath = @"D:\EvalReport_05.txt";
      Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;

      StreamWriter LogFile_Obj =
        new StreamWriter(FileNamePath, true, System.Text.Encoding.ASCII);

      LogFile_Obj.AutoFlush = true;
      LogFile_Obj.WriteLine("Starting eval...");

      int countAtts = 0;

      Database db = AcDb.HostApplicationServices.WorkingDatabase;

      AcDb.TransactionManager tm =
        AcadApp.DocumentManager.MdiActiveDocument.TransactionManager;

      using (Transaction tr = tm.StartTransaction())
      {
        try
        {
          BlockTable blockTable = tr.GetObject
            (db.BlockTableId, OpenMode.ForRead, false) as BlockTable;

          foreach (ObjectId blockTableRecordId in blockTable)
          {
            BlockTableRecord blockTableRecord = tr.GetObject
              (blockTableRecordId, OpenMode.ForRead, false) as BlockTableRecord;

            if (blockTableRecord.HasAttributeDefinitions == true)
            {
              ObjectIdCollection blockReferenceIds =
                  blockTableRecord.GetBlockReferenceIds(false, false);

              foreach (ObjectId blockReferenceId in blockReferenceIds)
              {
                BlockReference blockReference = tr.GetObject
                  (blockReferenceId, OpenMode.ForRead, false) as BlockReference;

                if (blockReference.Layer == "1_8_TEXT")
                {
                  foreach (ObjectId attributeReferenceId in blockReference.AttributeCollection)
                  {
                    AttributeReference attributeReference = tr.GetObject
                      (attributeReferenceId, OpenMode.ForRead) as AttributeReference;

                    countAtts = countAtts + 1;
                    LogFile_Obj.WriteLine(countAtts.ToString() + '\t' +
                          attributeReference.Tag + '\t' + attributeReference.TextString);
                  }
                }
              }
            }
          }
          TimeSpan TimeDuration = (DateTime.Now - TimeStart); ;
          ed.WriteMessage("End eval...Process time: "
                  + (TimeDuration.TotalSeconds + " Seconds for "
                  + countAtts.ToString() + " records of "
                  + db.ApproxNumObjects.ToString()));
          LogFile_Obj.WriteLine(("End eval...Process time: "
                  + (TimeDuration.TotalSeconds + " Seconds.")));
        }
        catch(System.Exception ex)
        {
          ed.WriteMessage(ex.Message);
          ed.WriteMessage(ex.StackTrace);
        }
        finally
        {
          LogFile_Obj.Close();
        }
      }
    }


Dan,

Here is my take on it for the sake of completeness. If you can, can you run against your dataset and post the results. I haven't tested this at all btw.
Gimme another half hour or so and I might have another way that will beat even that C# one you posted recently.

Code - C#: [Select]
  1. [CommandMethod("Test_03")]
  2. public static void test03Command()
  3. {        
  4. Document doc = acadApp.DocumentManager.MdiActiveDocument;
  5. Database db = doc.Database;
  6. Editor ed = doc.Editor;
  7.  
  8. DateTime TimeStart = DateTime.Now;
  9.  
  10.    string outputFileName = @"C:\Temp\EvalReport_03.txt";
  11.  
  12.    int attributeCount = 0;
  13.  
  14. Transaction tr = null;
  15. StreamWriter logFileWriter = null;
  16.  
  17. try
  18. {
  19. logFileWriter = new StreamWriter(outputFileName, true, System.Text.Encoding.ASCII);
  20. logFileWriter.AutoFlush = true;
  21. logFileWriter.WriteLine("Starting eval...");
  22.  
  23. tr = db.TransactionManager.StartTransaction();
  24.  
  25. BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead, false) as BlockTable;
  26. if (bt == null)
  27. {
  28. ed.WriteMessage("{0}Catastrophic error: Failed to open the BlockTable!", Environment.NewLine);
  29. return;
  30. }
  31.  
  32. // roll over the block table
  33. foreach (ObjectId btrId in bt)
  34. {
  35. BlockTableRecord btr = tr.GetObject(btrId, OpenMode.ForRead, false) as BlockTableRecord;
  36. if (btr == null)
  37. {
  38. ed.WriteMessage("{0}Serious error: Failed to open a BlockTableRecord! Continuing...", Environment.NewLine);
  39. continue;
  40. }
  41.  
  42. if (!btr.HasAttributeDefinitions)
  43. continue;
  44.  
  45. ObjectIdCollection blkRefIds = btr.GetBlockReferenceIds(false, false);
  46. if (blkRefIds == null || blkRefIds.Count == 0)
  47. continue;
  48.  
  49. foreach (ObjectId blkRefId in blkRefIds)
  50. {
  51. BlockReference blkRef = tr.GetObject(blkRefId, OpenMode.ForRead, false) as BlockReference;
  52. if (blkRef == null)
  53. {
  54. ed.WriteMessage("{0}Serious error: Failed to open a BlockReference! Continuing...", Environment.NewLine);
  55. continue;
  56. }
  57.  
  58. if (blkRef.Layer != "BLOCKS")
  59. continue;
  60.  
  61. AttributeCollection attRefIds = blkRef.AttributeCollection;
  62. if (attRefIds == null || attRefIds.Count == 0)
  63. continue;
  64.  
  65. foreach (ObjectId attRefId in attRefIds)
  66. {
  67. AttributeReference attRef = tr.GetObject(attRefId, OpenMode.ForRead, false) as AttributeReference;
  68. if (attRef == null)
  69. {
  70. ed.WriteMessage("{0}Serious error: Failed to open an AttributeReference! Continuing...", Environment.NewLine);
  71. continue;
  72. }
  73.  
  74. attributeCount++;
  75.  
  76. logFileWriter.WriteLine(attributeCount.ToString() + '\t' + attRef.Tag + '\t' + attRef.TextString);
  77. }
  78. }
  79. }
  80.  
  81. tr.Commit();
  82.  
  83. TimeSpan TimeDuration = (DateTime.Now - TimeStart); ;
  84.  
  85. ed.WriteMessage("End eval...Process time: "
  86. + (TimeDuration.TotalSeconds + " Seconds for "
  87. + attributeCount.ToString() + " records of "
  88. + db.ApproxNumObjects.ToString()));
  89.  
  90. logFileWriter.WriteLine(("End eval...Process time: " + (TimeDuration.TotalSeconds + " Seconds.")));
  91. }
  92. catch (Autodesk.AutoCAD.Runtime.Exception arex)
  93. {
  94. ed.WriteMessage("{0}AutoCAD Runtime Exception: {1}", Environment.NewLine, arex.Message);
  95. return;
  96. }
  97. catch (System.Exception ex)
  98. {
  99. ed.WriteMessage("{0}System Runtime Exception: {1}", Environment.NewLine, ex.Message);
  100. return;
  101. }
  102. finally
  103. {
  104. if (tr != null)
  105. tr.Dispose();
  106.  
  107. if (logFileWriter != null)
  108. logFileWriter.Close();
  109. }
  110.  
  111. }
  112.  

Cheers,
Glenn.

edit:kdub code=csharp
« Last Edit: August 16, 2012, 10:25:49 pm by Kerry »
Me