Advanced Selection Filtering with TeighaX

Vladimir Kalinin

June 13, 2017

When using the ActiveX interface to Teigha, traversing all the entities in a layout while looking for a specific subset has an inevitable overhead. For an entity to be accessible to a COM client, a wrapper should be created and attached to it.

For VB6 there is also an IDispatch call cost, and for .NET there is an arguments marshaling cost. In many cases selection performance can be improved by using selection filters. Selection filters allow filtering for entity types (DXF name), layer names, block names for blocks, etc. Essentially you can filter for any field in the DXF representation of an entity.

Selection filtering originated with the LISP interface where its syntax looks like:

(ssget "X" '((0 . "CIRCLE")))

This reads as “Get selection set of all the entities of type “CIRCLE” (DXF group code 0 is for the entity type). In ActiveX (C#) syntax, the analogous IAcadSelectionSet.Select call looks like this:

IAcadSelectionSet SelectionSet = oApp.ActiveDocument.SelectionSets.Add("Test");
SelectionSet.Select(AcSelect.acSelectionSetAll, Missing.Value, Missing.Value, new int[] { 0 }, 
new object[] { "CIRCLE" });

You can combine multiple conditions in a filter, e.g., to select all the text entities on an “Annotations” layer, you can do this:

SelectionSet.Select(AcSelect.acSelectionSetAll, Missing.Value, Missing.Value, new int[] { 0, 8 }, 
new object[] { "TEXT", "Annotations" });

If you need to select text and mtext on the layer “Annotations”, use logical operator brackets. In LISP syntax it looks like this:

(ssget "X" '((-4 . "<OR")(0 . "TEXT")(0 . "MTEXT")(-4, "OR>")(8 . "Annotations")))

By default all conditions not in operator brackets are considered to be in “and” brackets. That is, a second example may be rephrased like this:

SelectionSet.Select(AcSelect.acSelectionSetAll, Missing.Value, Missing.Value, new int[] { -4, 0, 8, -4 }, 
new object[] { "<AND", "TEXT", "Annotations", "AND>" });

Supported logical operators are “AND”, “OR”, “NOT”, and “XOR” with the usual meaning. In addition to checking the entity properties for equality to a value, you can compare them to values. For example, to look for circles with radius greater than 1.0:

SelectionSet.Select(AcSelect.acSelectionSetAll, Missing.Value, Missing.Value, new int[] { 0, -4, 40 }, 
new object[] { "CIRCLE", ">", 1.0  });

Valid relational operators are:

  • "=" — Default.
  • "*" — Anything goes (always true).
  • "!=", "<>",  "/=" — Not equal.
  • "<" — Less than.
  • "<=" — Less than or equal to.
  • ">" — Greater than.
  • ">=" — Greater than or equal to.
  • "&" — Bitwise and (applicable to integers only).
  • "&=" — Bitwise masked equal (applicable to integers only). Is true if ((value & filter) = filter), that is, check if the given bits are set.

You can also use wildcards when matching strings, e.g., to search all the entities on layers starting with an ‘A’:

SelectionSet.Select(AcSelect.acSelectionSetAll, Missing.Value, Missing.Value, new int[] { 8 }, 
new object[] {"A*" });

Supported wildcard syntax is rather extensive and only briefly summarized in this article.