This post was inspired by a comment on this previous post, where we looked at some code to select entities on a specific layer. The question was regarding how best to select entities from multiple layers: the selection filtering mechanism inside AutoCAD makes this very easy, and can cope with composition of conditions related to various entity properties.
The basic concept is to enclose sets of entity properties for which you wish to filter with tags indicating the composition of the conditions: for "or" you enclose the conditions with "<or" and "or>" and for "and" you use "<and" and "and>". Wow: I can safely say that that's probably the only sentence I've ever written that has 6 of the last 10 words being "and". :-)
Let's take a concrete example: let's say we want to select all lines on on layer 0 and all the circles with radii greater than 10.'s how we would compose the conditions, in pseudo-code:
- <or
- <and
- Layer == "0"
- Entity type == "LINE"
- and>
- <and
- Entity type == "CIRCLE"
- Radius >= 10.0
- and>
- <and
- or>
This translates into the following C# code - for clarity I've left the specific properties/values hard-coded, but clearly it would be straightforward to ask the user or pick them out of a database, as needed.
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
namespace EntitySelection
{
public class Commands
{
[CommandMethod("SEWP")]
static public void SelectEntitiesWithProperties()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
// Build a conditional filter list so that only
// entities with the specified properties are
// selected
TypedValue[] tvs =
new TypedValue[] {
new TypedValue(
(int)DxfCode.Operator,
"<or"
),
new TypedValue(
(int)DxfCode.Operator,
"<and"
),
new TypedValue(
(int)DxfCode.LayerName,
"0"
),
new TypedValue(
(int)DxfCode.Start,
"LINE"
),
new TypedValue(
(int)DxfCode.Operator,
"and>"
),
new TypedValue(
(int)DxfCode.Operator,
"<and"
),
new TypedValue(
(int)DxfCode.Start,
"CIRCLE"
),
new TypedValue(
(int)DxfCode.Operator,
">="
),
new TypedValue(
(int)DxfCode.Real, // Circle Radius
10.0
),
new TypedValue(
(int)DxfCode.Operator,
"and>"
),
new TypedValue(
(int)DxfCode.Operator,
"or>"
)
};
SelectionFilter sf =
new SelectionFilter(tvs);
PromptSelectionResult psr =
ed.SelectAll(sf);
ed.WriteMessage(
"\nFound {0} entit{1}.",
psr.Value.Count,
(psr.Value.Count == 1 ? "y" : "ies")
);
}
}
}
By the way - you can also choose to perform an "exclusive or" test by using "<xor" and "xor>".
To try out this code, draw a number of lines in a blank drawing, and run the SEWP command. This simply tells you how many entities met the selection criteria - it doesn't leave them selected for use by further commands. You can then see how drawing circles of varying radii changes the number of entities selected by the command.
On a final note... SelectionFilters can be used either non-interactively (as in this example, via the SelectAll() method) or interactively (via GetSelection(), SelectWindow(), SelectCrossingPolygon(), SelectFence(), etc.). I've shown simple uses of SelectionFilters in previous posts, but it's also possible to use quite complicated groupings of conditions - as we've scratched the surface of in this post.