BRXNET - SelectionSets

Hello all,

I'm using code snippet below to get the id's of some entities by passing filterType and filterData.

In a drawing I have a block (say named 'Mickey') inserted in Modelspace. I use filters:

short[] filterType = new short[]{0,2};

object[] filterData = new object[] {"INSERT", "Mickey"};

and pass them to the GetSelectionIds method.

When the drawing is physically switched to Modelspace and I run the BrxNet.dll  the method works and finds the reference (in Modelspace).

But when the drawing is switched in Paperspace and I run the BrxNet.dll, the line:

_AcEd.PromptSelectionResult res = editor.SelectAll(selectionFilter) gives  res.Status = error... so no blokref is found.

Do I really have to be in modelspace to select modelspace entities?

Or is there an other way?

TIA,

Arno van Eeuwen

[code]

public static ObjectIdCollection GetSelectionIds (short[] filterType, object[] filterData)    {      _AcEd.Editor editor = _AcAp.Application.DocumentManager.MdiActiveDocument.Editor;       ObjectIdCollection ids = new ObjectIdCollection();       try      {        List<_AcDb.<SPAN style="COLOR: #2b91af">TypedValue> dxfCodes = new List<<SPAN style="COLOR: #2b91af">TypedValue>(filterType.Length);         for (int i = 0; i < filterType.Length; i++)          dxfCodes.Add(<SPAN style="COLOR: blue">new _AcDb.TypedValue(filterType[i], filterData[i]));         _AcEd.SelectionFilter selectionFilter = new SelectionFilter(dxfCodes.ToArray());         _AcEd.PromptSelectionResult res = editor.SelectAll(selectionFilter);         if (res.Status == _AcEd.PromptStatus.OK)        {          _AcEd.SelectionSet sset = res.Value;                   foreach (ObjectId objectId in sset.GetObjectIds()) 
            ids.Add(objectId);        }      }      catch (System.Exception ex)      {        _AcAp.Application.ShowAlertDialog(string.Format("\nError: {0}\nStackTrace: {1}", ex.Message, ex.StackTrace));           }      return ids;     }

[/code]

Comments

  • Hi Arno : )

    I'm pretty sure that the selection is confined to the current space.  However, if it's the goal of your method to find all the inserts in a drawing by name, there is a better way.  Have a look at BlockTableRecord.GetBlockReferenceIds ().   Also, a lot of times when I want to "search" the "whole" drawing, I just iterate through all the ids in the database.  here is a sample using BlockTableRecord.GetBlockReferenceIds ().   

    [code]

    public static class Commands   {       public static ObjectIdCollection       getBlockRefsIdsForName(string name, _AcDb.Database database)     {       _AcDb.ObjectIdCollection ids = new _AcDb.ObjectIdCollection();       _AcDb.TransactionManager tm = database.TransactionManager;       using (_AcDb.Transaction action = tm.StartTransaction())       {         BlockTable blockTable = action.GetObject             (database.BlockTableId, OpenMode.ForRead, false) as BlockTable;         if (blockTable.Has(name))         {           BlockTableRecord record = action.GetObject             (blockTable[name], OpenMode.ForWrite, false) as BlockTableRecord;           ids = record.GetBlockReferenceIds(true, true);         }       }       return ids;     }       [CommandMethod("doit")]     public static void doit()     {       _AcEd.Editor editor =         _AcAp.Application.DocumentManager.MdiActiveDocument.Editor;         _AcDb.Database database = editor.Document.Database;       _AcEd.PromptResult promptResult = editor.GetString("Enter Block Name");         if (promptResult.Status == _AcEd.PromptStatus.OK)       {         _AcDb.ObjectIdCollection refIds =           getBlockRefsIdsForName(promptResult.StringResult, database);           editor.WriteMessage("\nFound {0} References of Block {1}:",           refIds.Count, promptResult.StringResult);       }     }   }

    [/code]

    Cheers

  • That's exactly what I need.
    On with the .NET quest....

    Thank  you Daniel.
  • Next challenge:

    I also used to select entities by means of filters to clear a layer for example.(In the old COM days that is)

    Actually I don't want to switch Currentspace too frequently as this makes the screen looking 'nervous' and in heavy drawings it makes the performance sluggish. Ofcource I can cycle the Modelspace block and collect all entities from a specific layer (with a specific color etc), but the filter meganism is much stronger and faster than that.

    Is there any way (in the .NET API) to remain in Paperspace while I select entities (get their id's) in Modelspace by means of filters?

    TIA

  • having fun with linq... see if the attached spawns any ideas

    [code]

    var ObjectIds = from o in cache["Model"]                  where o.Layer == "0" &&                      o.Name.Equals("Line"StringComparison.CurrentCultureIgnoreCase)                  select o.ObjectId;

    [/code]

    BTY, something like this would work on closed drawings too

    DwgFilter.zip

  • Hi Daniel,

    interesting approach, although you also end up cycling a dictionary which first gets filled with the complete drawing.
    So programmatically there is not a real difference: do your own search (no filters)
    The query itself is mighty fast I must say.
    We tend to do a lot of modifications in our drawings so that would mean I'd have to keep the DrawingCache in sync (fillc) with the actual drawing before doing a query.
    I also did a 'Modelspace search' myself and found it quite fast enough.
    Some numbers: 
    A drawing with 180000 entities in MS:
    Fillc =677 ms
    q1 = 132000 entities in 0 ms (!!) (TEXT on layer 0)

    q2 (cycle MS) = 370 ms.

    At least I know which way to go, thanks for sharing your ideas.

    Arno

    [code] [CommandMethod("q2")]
        public static void q2()    {      Document doc = Application.DocumentManager.MdiActiveDocument;      try      {        using (Transaction trans = doc.TransactionManager.StartTransaction())        {          BlockTable blockTable = (BlockTable)trans.GetObject(doc.Database.BlockTableId, OpenMode.ForRead);           BlockTableRecord modelSpace = (BlockTableRecord)trans.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForRead);           ObjectIdCollection ids = new ObjectIdCollection();           Stopwatch sw = Stopwatch.StartNew();           foreach (ObjectId id in modelSpace)          {            Entity entity = (Entity)trans.GetObject(id, OpenMode.ForRead);             if (entity.Layer == "0" && entity is DBText)              ids.Add(id);          }           sw.Stop();           Application.DocumentManager.MdiActiveDocument.            Editor.WriteMessage("\nCount {0} in {1} ms", ids.Count, sw.ElapsedMilliseconds);        }      }      catch(System.Exception ex)      {        Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\nError q2 {0}", ex.Message);      }    
        }[/code]
  • Yeah, I wasn't sure if it would fit your model,  one this cool about the cache is it could be made thread safe, so you would be able to party with plinq and/or parallel foreach , but that would be premature optimization as its hard to beat 0MS : }

     

    FYI, you can cut the time down dramatically on the q2 model, by using ObjectId.ObjectClass to pre-filter  types. ObjectId.ObjectClass does not need to open the object, nor do a disk read to get the type. Example, I made a test drawing with 160,000 objects,  10,000 of which are typeof DBText on the zero layer, the rest are points.

     

    : q2   Count 10,000 in 414 ms

    : q3   Count 10,000 in 101 ms

    [code]

        [CommandMethod("q3")]    public static void q3()    {      Document doc = Application.DocumentManager.MdiActiveDocument;      try      {        using (Transaction trans = doc.TransactionManager.StartTransaction())        {          BlockTable blockTable =             (BlockTable)trans.GetObject(doc.Database.BlockTableIdOpenMode.ForRead);           BlockTableRecord modelSpace =             (BlockTableRecord)trans.GetObject(              blockTable[BlockTableRecord.ModelSpace], OpenMode.ForRead);           Stopwatch sw = Stopwatch.StartNew();           ObjectIdCollection ids = new ObjectIdCollection();          RXClass classtype = RXObject.GetClass(typeof(DBText)); //<<----          <SPAN style="COLOR: #0001fe">foreach (ObjectId id in modelSpace)          {            if (id.ObjectClass == classtype) //<------            {              <SPAN style="COLOR: #2b91af">Entity entity = (Entity)trans.GetObject(idOpenMode.ForRead);              if (entity.Layer == "0")                ids.Add(id);            }          }           sw.Stop();          Application.DocumentManager.MdiActiveDocument.            Editor.WriteMessage("\nCount {0} in {1} ms"ids.Countsw.ElapsedMilliseconds);        }      }      catch (System.Exception ex)      {        Application.DocumentManager.MdiActiveDocument.          Editor.WriteMessage("\nError q3 {0}"ex.Message);      }    }

    [/code]

    now thats fast : )

  • Just for grins, Count 10000 in 492 ms from your selection set

    still fast though : )

  •  Hmmm,

    I don't get the dramatic speed improvement:
    q2 = 132017 entities in 335 ms
    q3 = 131964 entities in 316 ms
    q1 = 131964 entities in 7 ms ;-)

    but most surprisingly: different number of entities in q2!
    Quite odd isn't is?


  • No worries mate!,

    this particular drawing  (showing a South American navigation channel with depth labels and buoys) has an unexpected feature:
    Naturally I did not make this drawing myself  ;-)
    The buoys are annotated by an AttributeDefinition, which is rather unusual I'd say.
    Since AttributeDefinition is derived from DBText it will pass the test 
    if (entity is BDText) and gets included.
    So that's why q2 has a different count.

    On with the .NET quest.


  • How about this:

    Erasing DBTEXTs from layer 0

    :-)

    [code]

    [CommandMethod("q4")]    public static void q4()    {      Document doc = Application.DocumentManager.MdiActiveDocument;      try      {        using (Transaction trans = doc.TransactionManager.StartTransaction())        {          BlockTable blockTable = (BlockTable)trans.GetObject(doc.Database.BlockTableId, OpenMode.ForRead);           BlockTableRecord modelSpace = (BlockTableRecord)trans.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForRead);           Stopwatch sw = Stopwatch.StartNew();           RXClass classtype = RXObject.GetClass(typeof(DBText));                    foreach(Entity entity in modelSpace.Cast<<SPAN style="COLOR: #2b91af">ObjectId>().Where(id => id.ObjectClass == classtype)                                  .Select(id => (Entity)trans.GetObject(id, OpenMode.ForWrite))                                  .Where(entity => entity.Layer == "0"))                         entity.Erase();           trans.Commit();             sw.Stop();           Application.DocumentManager.MdiActiveDocument.            Editor.WriteMessage("\nErase in {0} ms", sw.ElapsedMilliseconds);        }      }      catch (System.Exception ex)      {        Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\nError q4 {0}", ex.Message);      }    }

    [/code]

This discussion has been closed.