LINQ and the AutoCAD .NET API (Part 5)
ModelSpace | PaperSpace | CurrentSpace
This is the fifth in a series of posts on LINQ an the AutoCAD .NET API. Here's a complete list of posts in this series.
Introduction
In today's post we want to have a look at some further objects that easily can be made queryable. The model space is probably the first of such objects that comes to mind. So what's the standard way to access the model space? Something like this:
ModelSpace to the front row
The model space is a frequently used object, so it is quite unintuitive that is burried as a special BlockTableRecord
in the BlockTable
. And again, we have to write a lot of boilerplate code to get to the actual model space entities. For our GeneralHelper
it would be nice to have the model space in the front row, making querying for entities easy and the code to do that short. Something like this would be nice:
Once we have an instance of the GeneralHelper
, we only need to write a single line of code to get the number of lines in the model space.
So how do we implement this functionality? Well, the code needed is actually already in listing 1, so for starters we take that code and put it into a property called ModelSpace
:
And that's it. The type of the property is IEnumerable<Entity>
and we use yield return
to return the single entities. So when we add this property to the GeneralHelper
, we're able to run the line count example in listing 2.
Paper space and current space
And what about the paper space? Layouts have a geometric representation as well, how can we access it? Similar to the ModelSpace
property we used in line 6 of the code above, the BlockTableRecord
class has another static property named PaperSpace
, which points to the last active paper space layout. Furthermore, there's another interesting property for us: the database object has a property named CurrentSpaceId
, which represents the ID of the currently selected layout (so this is either the model space or one of the paper space layouts).
Having that information, we can now refactor the ModelSpace
property from listing 3: let's make the code more general and put it into a method, so that we can get the entities of the block by providing the name or the ObjectId
of the according BlockTableRecord
:
The GetEntities
method takes a function as a parameter, which takes the BlockTable
as an argument and returns the ObjectId
of the BlockTableRecord
we want to query. Using the function as an argument we can return the BlockTableRecord
from either the name or the ObjectId
.
Now we have a modified ModelSpace
property and two new properties, one pointing to the last active paper space layout, and the other one to the currently active layout:
Looks good! But, as always, there's room for improvement: There is always exactly one model space layout in a drawing, but we can have several paper space layouts. With the current implementation, we can access only the last active paper space layout. Since paper space layouts come with a name and have a certain position in the tab control at the bottom of the viewport, it would be nice to get a paper space layout by providing either the name or the tab index.
To implement that, our GetEntities
method is sufficient and we just have to use it correctly. To get a layout by tab index we can do the following:
First we have to consider that an element of type Layout
(accessible in the GeneralHelper
via the Layouts
property in line 5) stores characteristics of a paper space layout, like the tab index we are interested in. Each Layout
object has a corresponding object of type BlockTableRecord
, that holds the geometry of that layout. In other words, the BlockTableRecord
is the object we get our entities from. Now the trick in the above implementation is, that we first look for the Layout
that has the desired tab index, and use the Layout
's BlockTableRecordId
property to get get to the BlockTableRecord.
Getting a paper space layout by name is not different from getting the model space layout, so it's actually the same code as in listing 5. But it's better to add an overload of GetEntities
to check the layout name and throw an exception if it is unknown:
Put together we now have the following new code for our GeneralHelper
:
So the public interface of the GeneralHelper
class has two new properties and three new methods:
- A property to query the space that is currently active
- A property to query the model space
- Three methods to query the paper space layouts:
- The last one that was active
- One with a specific name
- One with a specific tab index
What's next?
We now have a neat way to query most of the containers of the drawing database. But at the moment all objects are opened "for read". The next step is to incorporate write access, so we can make changes to the objects. We’ll look at that in the next post.