Using Selection Filters
31 Dec, 2001 By: Bill KramerAn important aspect of most AutoCAD-based programming projects is the building of one or more selection sets. A selection set is a collection of entity-name references. A selection set can contain any type of entity reference. This becomes a potential problem when writing a program to manipulate specific objects, such as text or dimensions, in a drawing. Either your program must distinguish and identify the desired entity objects in a given selection set or the selection set must be filtered to contain only the objects to be processed. A filter can be applied at two different stages--the first as the selection set is created; the second after creation but before your program processes it. AutoCAD provides a tool for the first case. For the second case, you need to write the code to create a new selection set containing just the objects desired from the objects in the original selection set.
AutoCAD allows you to define a set of criteria to be matched in the drawing. Criteria may be something as open as everything on layer "0" to something as specific as all circle objects on layer "0" with a radius greater than three units. This mechanism is commonly called a selection-set-get filter because it is applied when "getting" a selection set.
How a selection set is represented will depend on the language you're using to customize AutoCAD. This month we are going to look at filters. We will then look at how both Visual LISP and VBA implement selection-set-get filters since the strategies are essentially the same; they just differ in tactical implementation. Filters seem intimidating at first because you need some background material before they can be properly understood and employed for your benefit.
Filter ConceptsFilters are defined using the same concepts in both Visual LISP and VBA. In both cases, a list of values are used as criteria. The specific mechanisms used to supply the lists of values, however, will be explained shortly, as they do differ. Right now you need to understand the data being supplied as a filter.
Table 1. Key Number Values and Meanings | |
Value | Meaning |
<0 to 9 | String data |
10 to 59 | Real numbers |
60 to 79 | Integers |
Filter data is supplied in pairs. An integer code number is paired with some data. The data can be an integer, a string, or a real number. The integer code number is the key number and communicates the intent of the associated data. Autodesk devised these key numbers a long time ago for use in the DXF (drawing exchange format) file (see Table 1 for a summary of these data types). A more detailed listing of these numbers and their uses can be found in the AutoCAD online help, DXF Reference.
When building filters there are several code numbers you will use more frequently (see Table 2 for a summary of these code values). Code values 0 and 8 allow you to describe which entity objects and layers you want to use. These are most commonly employed when working with well-defined layering standards. You can easily identify objects based on the layers they exist on--for instance, the LINE objects existing on the WALL-CENTERLINE layer.
A combination of codes and values constructs a filter. If you want to accept more than one object type--such as LINE, ARC, and POLYLINE--then they can all be written together. The string would appear as "LINE, ARC, LWPOLYLINE." The result is an object that will be selected if it is any one of those object types. The same type of combination will work with layer names as well. This is a logical-OR combination of the values you are looking to match in the data field indicated by the group code.
For layer names, you can also employ wildcard characters to aid in searching. Suppose you have a layer standard where each floor in a building plan follows a standard naming scheme. You could request a selection set containing elements of just that floor. For example, if the names of all the floor layers start with FL, followed by a number and some additional characters identifying the type of data represented (walls, doors, HVAC), then the layer name search string could be "FL-1-*" for all objects on floor one.
Table 2. Frequently Used Key Numbers | |
Value | Purpose |
-4 | Grouping code |
0 | Entity type |
2 | Name of block |
8 | Layer name |
40 | Radius of arc or circle |
66 | Block has attributes |
Simple combinations and wildcards can be used when working with string values. However, these approaches will not work with number comparisons. Instead of requesting a value exactly matching something, you may want to get objects with values that fall in a range between two numbers. In those cases you can use -4 codes to designate a test, as shown in the list in Table 3. When used as part of a filter, the test is supplied as a string with a -4 code number.
Table 3. Tests available with -4 code | |
Code | Test Type |
< | Less than |
<= | Less than or equal to |
> | Greater than |
>= | Greater than or equal to |
!= or /= or <> | Not |
Suppose we want to locate all CIRCLE objects on a layer named "DRILL" that have a radius of 0.5 drawing units or greater. The filter would contain four elements. The first two elements are codes 0 and 8 associated with the values "CIRCLE" and "DRILL" for the entity type and layer. To specify that we want radius values of 0.5 or greater requires two entries into the filter. The first is a -4 code with the string value ">=." The second entry is 40 with the real number value 0.5. Code 40 signifies the radius of the circle. Thus our filter data pairs would be as follows.
0, "CIRCLE"
8, "DRILL"
-4, ">="
40, 0.5
Now let's make the example a bit more complex. Suppose we want all the circles on the same layer as before but this time with a radius value greater or equal to 0.5 and less than or equal to 0.75. Just add another -4 code with the test "<=" and a 40 code with the value 0.75. Since each item in a filter is combined as a logical AND, this will cause the filter to accept all circle objects on layer "DRILL" and have a radius between 0.5 and 0.75. Each match is combined together using a logical-AND filter, so that the computer reads it as a request to find all entity objects matching the combined tests. In this example the computer sees the request as follows.
Find entity objects where Object is circle AND object is on layer "DRILL" AND object radius is greater or equal to 0.5 AND the object radius is less or equal to 0.75.
The code numbers for this filter would be 0, 8, -4, 40, -4, and 40. The values would be "CIRCLE," "DRILL," ">=," 0.5, "<=," and 0.75. Even though LISP and VBA present these values to the filter mechanism in slightly different formats, the data remains the same.
We can expand this filter to look for ARC objects in addition to circles. The first value is changed to "CIRCLE, ARC," so that the search now selects either object. This is an OR combination because we are now saying we want circles or arcs that are on layer "DRILL" with a radius between 0.5 and 0.75. Additional layers to accept can be added in the same manner by appending more names to the "DRILL" entry.
But what if you want to find circles not in that range? Reversing the less and greater tests will not work since no circle or arc can have a radius both less than 0.5 and greater than 0.75. For this kind of testing, we need to incorporate an OR test instead of an AND test for the radius values.
When a logical OR or NOT is required in a filter, it can be added with a -4 code. The string that accompanies the -4 code for a logical-OR, -NOT, or -AND combination will have a "<" or ">" at the front or end of it to signify the end of a test group. For example, if we wanted to test for circles and arcs on layer "DRILL" and have a radius outside of the range 0.5 to 0.75, the codes and values should be written as follows:
0, "CIRCLE,ARC"
8, "DRILL"
-4, " -4, "<" 40, 0.5 -4, ">" 40, 0.75 -4, "OR>" The -4 codes with the pair of "OR" strings indicate the extent of the logical OR test. " Filter tests are powerful and can be used for a variety of applications. Suppose we want to find all the circles that are not on layer "DRILL" so that we could move them to that layer. The codes and values should be written as follows: 0, "CIRCLE" -4, " 8, "DRILL" -4, "NOT>" Filters are easy to build if you just think in terms of AND, NOT, and OR to construct the rule to find the entity objects your application seeks. And the power of filters provides a compelling argument when trying to enforce layering standards in an organization. The more exceptions or complexities a user wants to introduce in a drawing standard, the more difficult it will be to produce a filter to extract the information for downstream integration into other tasks or processes. Now let's look at how one creates a filter in Visual LISP and VBA. The mechanisms are the same internally; it is just a matter of how the data is presented. Filter lists are created using the same mechanisms we use to create an entity list. We can explicitly define the list following a single quote, in which case the filter is always the same. Or we can construct the filter list using CONS and LIST, allowing for the integration of variable values into the filters. The example we have been considering in the previous paragraphs, to find circles with a radius between 0.5 and 0.75 on layer "DRILL," is coded in Visual LISP as follows (this expression saves the filter list using the symbol "myFilter"): (setq myFilter '((0 . "CIRCLE") (8 . "DRILL") (-4 . ">=") (40 . 0.5) (-4 . "<=") (40 . 0.75) )) Once defined, a filter list is applied with the SSGET subr and will create a selection set offering a wide range of parameter options. Using SSGET with just the filter will activate manual input with the "Select object" prompt. When the filter is supplied, SSGET will only select those objects allowed by the filter. Supplying a character string as the first argument indicating what kind of automatic selection to be used, activates automatic selection using SSGET. A value of "X" will search the entire drawing based on the filter contents. A value of "W" will expect to find two points defining a window area following the string. A filter argument follows the points as an option. If present, only those objects called for in the filter and inside the window will be selected. The expression (setq SS1 (ssget myFilter)) will allow the user to select the objects allowed by the filter. In this case, the filter only allows selection of circles on layer "DRILL" with the radius between 0.5 and 0.75. Another way of using SSGET would be in the expression (setq SS1 (ssget "X" myFilter)). In this example the same filter is applied to the entire drawing and the user selects nothing. If objects are found matching the criteria spelled out in the filter, then the symbol SS1 is bound to a selection set. Otherwise, SS1 will have a binding of nil. Filters are pretty easy to program since they look so much like the entity data lists most Visual LISP programmers manipulate. The entity list structure is somewhat odd when first learned but is easy to master with a little practice.
Visual LISP uses lists, as expected, for filter storage. In fact, filter lists look identical to entity data lists. They are nested lists where each member is a list. The member lists are normally dotted pairs with the first value being the code number of the data. The second value can be a string or a number. Thus, when the filter calls for a radius value with a code number of 40, the second value is a real number. When the filter uses the -4 code, the associated value will be a string.
Defining a filter in VBA requires creating two arrays of the same size, but of different types. The first array to be defined is an integer array. The second is of the type Variant since it will contain the variable data associated with the integer code numbers. The array must be of the exact size to hold the filter when defined in the DIM statement (REDIM will be required if you are planning to use the same array to hold numerous filters of different sizes). Do note that the index into the arrays starts at an offset value of zero, meaning the declared number of members in the array will appear to be missing at first glance. In other words, if there are three members in the filter, the array is dimensioned to a value of 2.
Using our example problem of the circle entity (objects on layer "DRILL" with a radius between 0.5 and 0.75), the arrays would be dimensioned to hold six elements each.
Dim cN(0 to 5) As Integer
Dim dV(0 to 5) As Variant
After we declare the array, we must fill it in with the values making up the filter, using normal assignment statements for code numbers and data. The index into the arrays is the common factor. The first element of the integer array corresponds to the first element of the variant data array and so on. The following is a convenient way of writing this in code:
cN(0) = 0: dV(0) = "CIRCLE"
cN(1) = 8: dV(0) = "DRILL"
cN(2) = -4: dV(2) = ">="
cN(3) = 40: dV(3) = 0.5
cN(4) = -4: dV(4) = "<="
cN(5) = 40: dV(5) = 0.75
In order to use the filter in VBA, we need to assign the values in the arrays to variant pointers, which will actually be supplied to the methods of the AutoCAD VBA SelectionSet object. For example, the following lines of VBA code will create a selection set named SS1 and search the drawing for the objects matching the filter. For the purpose of this example, first create the selection set reference, SS1.
Dim VcN As Variant
Dim VdV as Variant
VcN = cN
VdV = dV
SS1.Select "X", , , VcN, VdV
When using filters in VBA, it is important to use variant pointers to the arrays. Don't use the arrays themselves because the method expects to find a reference only. Although the function could be programmed to accept the arrays directly, it is not as efficient as just passing the pointer. There is no need to send a copy; the Select method only wants to read the data.
The SelectOnScreen method can be used with a filter as well. This method allows users to select objects for inclusion in the selection set. When the filter pointers are provided, the user will only be given access to those objects allowed by the filter.
SS1.SelectOnScreen VcN, VdV
Using VBA-filter requires a couple of steps but is a powerful tool for object selection. Entity data sed by the object methods was derived from previously accepted standards. That is why alternative data storage strategies based on nested variant arrays or objects were not considered. The filter mechanism works in all programming language interfaces for AutoCAD in the same general way.
SummaryFilters are a power tool for advanced programmers. There are basically two types of applications for AutoCAD with most advanced applications being a mixture of the two types. The first consists of applications that create graphics from parameters and/or input from the user; the second reads the graphic data and processes it in some way. Filters are employed in the second type of application to obtain selection sets containing the graphic information of interest. By using layering and other standards for the creation of graphics, filters can be meaningfully applied to the data in order to interface with downstream applications such as NC post processing, finite element analysis, bill of materials, quality control, and so on. The applications are only limited by your imagination. So until next time, keep on programmin'!
For Mold Designers! Cadalyst has an area of our site focused on technologies and resources specific to the mold design professional. Sponsored by Siemens NX. Visit the Equipped Mold Designer here!
For Architects! Cadalyst has an area of our site focused on technologies and resources specific to the building design professional. Sponsored by HP. Visit the Equipped Architect here!