Finding all the AutoCAD entities on a particular layer using .NET
This question came in recently by email:
Is there a way to obtain the object IDs of all the object on a layer? I found the GetAllObjects() method of the Transaction object but it doesn't work.
That's right: GetAllObjects() will return the objects accessed via (or added to) the transaction - it has nothing to do with retrieving objects based on any particular property.
What you need to do is Editor.SelectAll(), the equivalent of acedSSGet("X") in ObjectARX and (ssget "X") in AutoLISP. You need the version where you pass in a SelectionFilter specifying the layer for which to search.
Here's some C# code doing just this, with the hard work encapsulated in a function (GetEntitiesOnLayer()) to make it easier to integrate into your code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
namespace EntitySelection
{
public class Commands
{
[CommandMethod("EOL")]
static public void EntitiesOnLayer()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
PromptResult pr =
ed.GetString("\nEnter name of layer: ");
if (pr.Status == PromptStatus.OK)
{
ObjectIdCollection ents =
GetEntitiesOnLayer(pr.StringResult);
ed.WriteMessage(
"\nFound {0} entit{1} on layer {2}",
ents.Count,
(ents.Count == 1 ? "y" : "ies"),
pr.StringResult
);
}
}
private static ObjectIdCollection
GetEntitiesOnLayer(string layerName)
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
// Build a filter list so that only entities
// on the specified layer are selected
TypedValue[] tvs =
new TypedValue[1] {
new TypedValue(
(int)DxfCode.LayerName,
layerName
)
};
SelectionFilter sf =
new SelectionFilter(tvs);
PromptSelectionResult psr =
ed.SelectAll(sf);
if (psr.Status == PromptStatus.OK)
return
new ObjectIdCollection(
psr.Value.GetObjectIds()
);
else
return new ObjectIdCollection();
}
}
}
Running EOL simply counts the entities on a particular layer (the following is from running in the 3D House.dwg sample drawing):
Command: EOL
Enter name of layer: A-Beam
Found 1 entity on layer A-Beam
Command: EOL
Enter name of layer: A-Concrete
Found 1 entity on layer A-Concrete
Command: EOL
Enter name of layer: Furniture
Found 14 entities on layer Furniture
Command: EOL
Enter name of layer: Legs
Found 16 entities on layer Legs
It would be straightforward to do something more than just count the results of the GetEntitiesOnLayer() function, of course, or even to adapt the function to filter on other properties.
May 2, 2008 in AutoCAD, AutoCAD .NET, Drawing structure, Selection | Permalink | Comments (2) | TrackBack
Understanding the properties of textual linetype segments in AutoCAD
In the last post we looked at using .NET to define complex linetypes containing text segments. In the post I admitted to not knowing specifics about the properties used to create the text segment in the linetype, and, in the meantime, an old friend took pity on me and came to the rescue. :-)
Mike Kehoe, who I've known for many years since we worked together in the Guildford office of Autodesk UK, sent me some information that I've reproduced below. Mike now works for Micro Concepts Ltd., an Autodesk reseller, developer and training centre. He originally wrote the below description in the R12/12 timeframe, but apparently most of it remains valid; and while it refers to the text string used to define a linetype in a .lin file, these are also mostly properties that are exposed via the .NET interface.
Example: Using Text within a Linetype.
A,.5,-.2,["MK",STANDARD,S=.2,R=0.0,X=-0.1,Y=-.1],-.2The key elements for defining the TEXT are as follows:
"MK" - These are the letters that will be printed along the line.
STANDARD -This tells AutoCAD what text style to apply to the text. NB: This is optional. When no style is defined AutoCAD will use the current text style – TextStyle holds the setting for the current text style.
[Note from Kean: I found the text style to be mandatory when using the .NET interface.]
S=.2 - This is the text scaling factor. However, there are 2 options: (1) when the text style's height is 0, then S defines the height; in this case, 0.2 units; or (2) when the text style's height parameter is non-zero, the height is found by multiplying the text style's height by this number; in this case, the linetype would place the text at 20% of the height defined in the text style.
R=0.0 - This rotates the text relative to the direction of the line; e.g.: 0.0 means there is no rotation. NB: This is optional. When no rotation is defined AutoCAD will assume zero degrees. The default measurement is degrees; NB: you can use r to specify radians, g for grads, or d for degrees, such as R=150g.
[Note from Kean: just like ObjectARX, the .NET interface accepts radians for this value, in SetShapeRotationAt(). A quick reminder: 360 degrees = 2 x PI radians. So you can pass 90 degrees using "System.Math.PI / 2".]
A=0.0 - This rotates the text relative to the x-axis ("A" is short for Absolute); this ensures the text is always oriented in the same direction, no matter the direction of the line. The rotation is always performed within the text baseline and capital height. That's so that you don't get text rotated way off near the orbit of Pluto.
[Note from Kean: to use this style of rotation using .NET, you need to use SetShapeIsUcsOrientedAt() to make sure the rotation is calculated relative to the current UCS rather than the direction of the line.]
X=-0.1 - This setting moves the text just in the x-direction from the linetype definition vertex.
Y=-0.1 – This setting moves the text in the y-direction from the linetype definition vertex.
These 2 settings can be used to center the text in the line. The units are defined from the linetype scale factor, which is stored in system variable LtScale.
Thanks for the information, Mike!
January 11, 2008 in AutoCAD, AutoCAD .NET, Drawing structure, Object properties | Permalink | Comments (0) | TrackBack
Creating a complex AutoCAD linetype containing text using .NET
In my last post we saw some code to create a simple linetype using .NET. As a comment on that post, Mark said:
Kean, i tried you code and it works great and it also got me thinking... is it possible to programmitically add text in as well? I've tried using ltr.SetTextAt(1, "TEST") but so far i've had no luck, any suggestions???
It turned out to be quite a bit more complicated to make a linetype containing text than merely calling SetTextAt() on one of the segments. In order to understand what properties needed setting, I first loaded the HOT_WATER_SUPPLY linetype from acad.lin (using the LINETYPE command):
I then looked at the contents of the linetype table using ArxDbg (the ObjectARX SDK sample that is very helpful for understanding drawing structure). Here's what the SNOOPDB command - defined by the ArxDbg application - showed for the loaded linetype:
From there it was fairly straightforward to determine the code needed to create our own complex linetype containing text segments. I decided to call the new linetype "COLD_WATER_SUPPLY", and have it resemble the original in every way but placing "CW" in the middle segment, rather than "HW" (with the descriptions updated to match, of course). As I've simply copied the properties of an existing linetype, please don't ask me to explain what they all mean. :-)
Here's the C# code:
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
namespace Linetype
{
public class Commands
{
[CommandMethod("CCL")]
public void CreateComplexLinetype()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
Transaction tr =
db.TransactionManager.StartTransaction();
using (tr)
{
// We'll use the textstyle table to access
// the "Standard" textstyle for our text
// segment
TextStyleTable tt =
(TextStyleTable)tr.GetObject(
db.TextStyleTableId,
OpenMode.ForRead
);
// Get the linetype table from the drawing
LinetypeTable lt =
(LinetypeTable)tr.GetObject(
db.LinetypeTableId,
OpenMode.ForWrite
);
// Create our new linetype table record...
LinetypeTableRecord ltr =
new LinetypeTableRecord();
// ... and set its properties
ltr.Name = "COLD_WATER_SUPPLY";
ltr.AsciiDescription =
"Cold water supply ---- CW ---- CW ---- CW ----";
ltr.PatternLength = 0.9;
ltr.NumDashes = 3;
// Dash #1
ltr.SetDashLengthAt(0, 0.5);
// Dash #2
ltr.SetDashLengthAt(1, -0.2);
ltr.SetShapeStyleAt(1, tt["Standard"]);
ltr.SetShapeNumberAt(1, 0);
ltr.SetShapeOffsetAt(1, new Vector2d(-0.1,-0.05));
ltr.SetShapeScaleAt(1, 0.1);
ltr.SetShapeIsUcsOrientedAt(1, false);
ltr.SetShapeRotationAt(1, 0);
ltr.SetTextAt(1, "CW");
// Dash #3
ltr.SetDashLengthAt(2, -0.2);
// Add the new linetype to the linetype table
ObjectId ltId = lt.Add(ltr);
tr.AddNewlyCreatedDBObject(ltr, true);
// Create a test line with this linetype
BlockTable bt =
(BlockTable)tr.GetObject(
db.BlockTableId,
OpenMode.ForRead
);
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace],
OpenMode.ForWrite
);
Line ln =
new Line(
new Point3d(0, 0, 0),
new Point3d(10, 10, 0)
);
ln.SetDatabaseDefaults(db);
ln.LinetypeId = ltId;
btr.AppendEntity(ln);
tr.AddNewlyCreatedDBObject(ln, true);
tr.Commit();
}
}
}
}
And here's the result of calling the CCL command and zooming in on the created line:
January 9, 2008 in AutoCAD, AutoCAD .NET, Drawing structure, Object properties | Permalink | Comments (6) | TrackBack
Creating an AutoCAD linetype programmatically using .NET
Happy New Year, everyone!
I had a very relaxing break over the holiday period: during the better part of two weeks I managed to stay away from my PC and even my BlackBerry, which I admit I'm generally not very good at ignoring. So now I'm easing back into the swing of things, remembering how to type and open modelspaces, among other things. :-)
To save my brain from unnecessary stress during the first few weeks of 2008, I've decided to take inspiration from the ADN website. Today's post is based on this DevNote, which shows how to create a custom linetype using ObjectARX.
Here's some equivalent code in C#:
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
namespace Linetype
{
public class Commands
{
[CommandMethod("CL")]
public void CreateLinetype()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
Transaction tr =
db.TransactionManager.StartTransaction();
using (tr)
{
// Get the linetype table from the drawing
LinetypeTable lt =
(LinetypeTable)tr.GetObject(
db.LinetypeTableId,
OpenMode.ForWrite
);
// Create our new linetype table record...
LinetypeTableRecord ltr =
new LinetypeTableRecord();
// ... and set its properties
ltr.AsciiDescription = "T E S T -";
ltr.PatternLength = 0.75;
ltr.NumDashes = 2;
ltr.SetDashLengthAt(0, 0.5);
ltr.SetDashLengthAt(1,-0.25);
ltr.Name = "TESTLINTEYPE";
// Add the new linetype to the linetype table
ObjectId ltId = lt.Add(ltr);
tr.AddNewlyCreatedDBObject(ltr,true);
// Create a test line with this linetype
BlockTable bt =
(BlockTable)tr.GetObject(
db.BlockTableId,
OpenMode.ForRead
);
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace],
OpenMode.ForWrite
);
Line ln =
new Line(
new Point3d(0, 0, 0),
new Point3d(10, 10, 0)
);
ln.SetDatabaseDefaults(db);
ln.LinetypeId = ltId;
btr.AppendEntity(ln);
tr.AddNewlyCreatedDBObject(ln, true);
tr.Commit();
}
}
}
}
Once you've run the CL command, Zoom Extents to see a line that has been created with our new custom linetype.
January 7, 2008 in AutoCAD, AutoCAD .NET, Drawing structure, Object properties | Permalink | Comments (4) | TrackBack
Accessing the active space or layout in an AutoCAD drawing using .NET
This question was asked as comment to a previous post by har!s:
Thanks a lot for the code. I have yet to see 2008 and MultiLeader. But I presume that it works on both Model and paper spaces. In that case, what is the best method to make the operation space independent? i.e., it should work on active space irrespective of whether it's model or paper. I think this will be generally applicable to almost all the entity creations.
The question is very valid and does indeed apply to a lot of entity creation - and other - activities. Most of the time I simply show how to open the modelspace in my code, for example:
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
Transaction tr =
db.TransactionManager.StartTransaction();
using (tr)
{
BlockTable bt =
(BlockTable)tr.GetObject(
db.BlockTableId,
OpenMode.ForRead
);
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace],
OpenMode.ForWrite
);
// ...
}
The key statement here is at the end, where we use GetObject() to open the BlockTableRecord to which we want to (for example) append an entity. The form we use is:
bt[BlockTableRecord.ModelSpace]
Breaking this down: we're actually looking up the ObjectId of the BlockTableRecord with the name of "*MODEL_SPACE", which is the string stored in the static ModelSpace property of the BlockTableRecord class.
Here are a few different options for what we might do here:
- Use either BlockTableRecord.ModelSpace or BlockTableRecord.PaperSpace, if we know that we want to access either of these containers (the current approach).
- Use foreach() on the BlockTable to iterate through the various BlockTableRecords: you can open each one using GetObject() and check the IsLayout property to find those that are either modelspace or paperspace layouts.
- Use db.CurrentSpaceId to open the currently active space in that particular database.
Option 3 is really the answer to this question, which makes the code like this:
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
Transaction tr =
db.TransactionManager.StartTransaction();
using (tr)
{
BlockTable bt =
(BlockTable)tr.GetObject(
db.BlockTableId,
OpenMode.ForRead
);
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(
db.CurrentSpaceId,
OpenMode.ForWrite
);
// ...
}
September 10, 2007 in AutoCAD, AutoCAD .NET, Drawing structure | Permalink | Comments (2) | TrackBack
Purging registered application names from a folder of AutoCAD drawings using .NET
In the last post we looked at some code to programmatically purge Registered Application names from the drawing currently active in AutoCAD. In this post we take the "batching" code first used in this previous post and apply it to this problem.
What we end up with is an additional command called PF which asks the user to specify a folder and then purges the RegApps from the DWGs in that folder, saving those files that end up being modified with the "_purged" suffix.
One point to note is the use of the Database.RetainOriginalThumbnailBitmap property: as we're not making any graphical changes it's fairly safe to set this to true, which retains the pervious thumbnail bitmap, rather than it being blank in the new drawing. If you were to set it to true after graphical changes nothing especially serious would happen, but it could be confusing for users if the preview differed substantially from the DWG contents.
Here's the C# code with the additional lines in red:
1 using Autodesk.AutoCAD.ApplicationServices;
2 using Autodesk.AutoCAD.DatabaseServices;
3 using Autodesk.AutoCAD.EditorInput;
4 using Autodesk.AutoCAD.Runtime;
5 using System.IO;
6 using System;
7
8 namespace Purger
9 {
10 public class Commands
11 {
12 [CommandMethod("PF")]
13 public void PurgeFiles()
14 {
15 Document doc =
16 Application.DocumentManager.MdiActiveDocument;
17 Editor ed = doc.Editor;
18
19 PromptResult pr =
20 ed.GetString(
21 "\nEnter folder containing DWGs to process: "
22 );
23 if (pr.Status != PromptStatus.OK)
24 return;
25 string pathName = pr.StringResult;
26
27 string[] fileNames =
28 Directory.GetFiles(pathName, "*.dwg");
29
30 // We'll use some counters to keep track
31 // of how the processing is going
32
33 int processed = 0, saved = 0, problem = 0;
34
35 foreach (string fileName in fileNames)
36 {
37 if (fileName.EndsWith(
38 ".dwg",
39 StringComparison.CurrentCultureIgnoreCase
40 )
41 )
42 {
43 string outputName =
44 fileName.Substring(
45 0,
46 fileName.Length - 4) +
47 "_purged.dwg";
48 Database db = new Database(false, true);
49 using (db)
50 {
51 try
52 {
53 ed.WriteMessage(
54 "\n\nProcessing file: " + fileName
55 );
56
57 db.ReadDwgFile(
58 fileName,
59 FileShare.ReadWrite,
60 false,
61 ""
62 );
63
64 db.RetainOriginalThumbnailBitmap = true;
65
66 int objectsPurged =
67 PurgeDatabase(db);
68
69 // Display the results
70
71 ed.WriteMessage(
72 "\nPurged {0} object{1}",
73 objectsPurged,
74 objectsPurged == 1 ? "" : "s"
75 );
76
77 // Only save if we changed something
78
79 if (objectsPurged > 0)
80 {
81 ed.WriteMessage(
82 "\nSaving to file: {0}", outputName
83 );
84
85 db.SaveAs(
86 outputName,
87 DwgVersion.Current
88 );
89 saved++;
90 }
91 processed++;
92 }
93 catch (System.Exception ex)
94 {
95 ed.WriteMessage(
96 "\nProblem processing file: {0} - \"{1}\"",
97 fileName,
98 ex.Message
99 );
100 problem++;
101 }
102 }
103 }
104 }
105 ed.WriteMessage(
106 "\n\nSuccessfully processed {0} files," +
107 " of which {1} had objects to purge" +
108 " and an additional {2} had errors " +
109 "during reading/processing.",
110 processed,
111 saved,
112 problem
113 );
114 }
115
116 [CommandMethod("PC")]
117 public void PurgeCurrentDocument()
118 {
119 Document doc =
120 Application.DocumentManager.MdiActiveDocument;
121 Database db = doc.Database;
122 Editor ed = doc.Editor;
123
124 int count =
125 PurgeDatabase(db);
126
127 ed.WriteMessage(
128 "\nPurged {0} object{1} from " +
129 "the current database.",
130 count,
131 count == 1 ? "" : "s"
132 );
133 }
134
135 private static int PurgeDatabase(Database db)
136 {
137 int idCount = 0;
138
139 Transaction tr =
140 db.TransactionManager.StartTransaction();
141 using (tr)
142 {
143 // Create the list of objects to "purge"
144
145 ObjectIdCollection idsToPurge =
146 new ObjectIdCollection();
147
148 // Add all the Registered Application names
149
150 RegAppTable rat =
151 (RegAppTable)tr.GetObject(
152 db.RegAppTableId,
153 OpenMode.ForRead
154 );
155
156 foreach (ObjectId raId in rat)
157 {
158 if (raId.IsValid)
159 {
160 idsToPurge.Add(raId);
161 }
162 }
163
164 // Call the Purge function to filter the list
165
166 db.Purge(idsToPurge);
167
168 Document doc =
169 Application.DocumentManager.MdiActiveDocument;
170 Editor ed = doc.Editor;
171
172 ed.WriteMessage(
173 "\nRegistered applications being purged: "
174 );
175
176 // Erase each of the objects we've been
177 // allowed to
178
179 foreach (ObjectId id in idsToPurge)
180 {
181 DBObject obj =
182 tr.GetObject(id, OpenMode.ForWrite);
183
184 // Let's just add to me "debug" code
185 // to list the registered applications
186 // we're erasing
187
188 RegAppTableRecord ratr =
189 obj as RegAppTableRecord;
190 if (ratr != null)
191 {
192 ed.WriteMessage(
193 "\"{0}\" ",
194 ratr.Name
195 );
196 }
197
198 obj.Erase();
199 }
200
201 // Return the number of objects erased
202 // (i.e. purged)
203
204 idCount = idsToPurge.Count;
205 tr.Commit();
206 }
207 return idCount;
208 }
209 }
210 }
You can download the source file from here.
August 15, 2007 in AutoCAD, AutoCAD .NET, Batch processing, Drawing structure, Purge | Permalink | Comments (10) | TrackBack
Purging registered application names in the current AutoCAD drawing using .NET
Purging can seriously reduce the size of AutoCAD drawings by removing unnecessary symbol table and dictionary entries. The PURGE command in AutoCAD allows you to safely purge these non-graphical objects (layers, linetypes, block definitions, etc.).
Since AutoCAD 2005 (if I recall correctly), PURGE also supports the removal of Registered Application names. Applications that make use of Extended Entity Data (XData) must register unique application names in drawings. A few applications have, in the past, created many more names than they required, and as these RegApp names get copied from drawing to drawing (when they get XRefed, for instance), they ended spreading from DWG file to DWG file (one comparison I remember hearing was to a virus, although that was perhaps a little extreme). To the best of my knowledge the applications that mistakenly caused this problem have now been fixed (and shall remain nameless), but there are still drawings out there with a lot of these records, which is ultimately why we extended PURGE to address the problem from within AutoCAD.
Anyway, I've chosen to implement a command to purge these RegApp names - even though it's now there in the product - really just an example of how to code this type of functionality. It could very easily be extended to handle the specific data you feel needs purging in your company's (or customers') DWG files.
The Database.Purge() function available in .NET wraps AcDbDatabase::purge(). These functions are both misleadingly named, as neither of them actually performs a purge on the database. What they do - and this is actually more useful, as it gives you more control - is filter a list of object IDs you pass in, removing any that cannot safely be purged by your application. So they would more accurately be named TellMeWhatCanSafelyBePurged(), or something like that. Typically objects get removed from the list because a reference exists somewhere in the drawing to that object - such as from an entity to a layer (making the layer dangerous to purge). The code calling the Purge function will usually then erase the objects that have been returned. And that's how the PURGE command is implemented.
Here's some C# code that purges the Registered Application names in the current document:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System.IO;
using System;
namespace Purger
{
public class Commands
{
[CommandMethod("PC")]
public void PurgeCurrentDocument()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
int count =
PurgeDatabase(db);
ed.WriteMessage(
"\nPurged {0} object{1} from " +
"the current database.",
count,
count == 1 ? "" : "s"
);
}
private static int PurgeDatabase(Database db)
{
int idCount = 0;
Transaction tr =
db.TransactionManager.StartTransaction();
using (tr)
{
// Create the list of objects to "purge"
ObjectIdCollection idsToPurge =
new ObjectIdCollection();
// Add all the Registered Application names
RegAppTable rat =
(RegAppTable)tr.GetObject(
db.RegAppTableId,
OpenMode.ForRead
);
foreach (ObjectId raId in rat)
{
if (raId.IsValid)
{
idsToPurge.Add(raId);
}
}
// Call the Purge function to filter the list
db.Purge(idsToPurge);
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
ed.WriteMessage(
"\nRegistered applications being purged: "
);
// Erase each of the objects we've been
// allowed to
foreach (ObjectId id in idsToPurge)
{
DBObject obj =
tr.GetObject(id, OpenMode.ForWrite);
// Let's just add to me "debug" code
// to list the registered applications
// we're erasing
RegAppTableRecord ratr =
obj as RegAppTableRecord;
if (ratr != null)
{
ed.WriteMessage(
"\"{0}\" ",
ratr.Name
);
}
obj.Erase();
}
// Return the number of objects erased
// (i.e. purged)
idCount = idsToPurge.Count;
tr.Commit();
}
return idCount;
}
}
}
Here's what happens when you run the PC command:
Command: PC
Registered applications being purged: "AcadAnnoPO" "PE_URL" "AcadAnnoAV"
"ACAD_EXEMPT_FROM_CAD_STANDARDS"
Purged 4 objects from the current database.
In the next post we'll look at extending this to - once again - work on a folder of drawings.
August 13, 2007 in AutoCAD, AutoCAD .NET, Drawing structure, Purge | Permalink | Comments (4) | TrackBack
Moving entities from one AutoCAD layer to another using .NET
Firstly I should apologise to those readers using RSS to access this site: I've been playing around with the configuration, to integrate FeedBurner but also to switch from publishing entire articles via RSS to publishing introductions - my posts are just too long, which seems to cause a problem for some RSS readers. So you may have received multiple versions of the same articles for the last few weeks - sorry about that.
For those of you who have not yet subscribed via RSS - please see the new options in the side-bar on the left: it should now be simpler for you to use your favourite RSS reader to pull down excerpts of the content I publish, rather than checking the site itself.
OK, now onto the real content. I had this question come in from António Rodrigues, an engineering student from Portugal:
I'm doing a project at school about hydraulics calculations, where i have get some data from AutoCAD. [...] I need to get all the objects from a single layer in the drawing, so i can use them to perform the calculations needed.
I put together some code for Antonio which uses Editor.SelectAll() with an appropriate SelectionFilter to get the list of entities on a particular layer. Just for fun I then extended the code to allow the user to enter a new layer name for these entities to be moved to.
Here's the C# code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
namespace LayerTools
{
public class Commands
{

Atom


