Thursday, August 23, 2007

Auto Increment Numbering Macro for AutoCAD LT

Have you ever tried automating tasks in AutoCAD LT? If so, you will find it really difficult due to lack of programming support inside it. Often this leads you to experiment with DIESEL to achieve the results you normally achieve in full version of AutoCAD. Here is a tricky macro to automate the process of increment numbering in AutoCAD LT.

*^c^c_text;\;;$M=$(+,$(getvar,USERR1),$(getvar,USERR2));setvar;USERR1;$M=$(+,$(getvar,USERR1),$(getvar,USERR2));

Configure the macro in a button (or wherever you are comfortable). Click on the button once and click on the required locations continuously to keep the incremented numbers. use USERR1 system variable to set the starting number and USERR2 for the increment. For example, suppose you need to start numbering from 1.001 and continue like 1.002,1.003,1.004........, set USERR1 to 1 and USERR2 to .001. This will enable you to do the numbering as stated before.

The above macro is restricted to work only when the text height in the current text style is 0. If you have the habit of assigning specific text height to a text style, then you should better use the following macro.
Quote:

*^c^c_text;\;$M=$(+,$(getvar,USERR1),$(getvar,USERR2));setvar;USERR1;$M=$(+,$(getvar,USERR1),$(getvar,USERR2));

I just removed only one semicolumn from the second macro after the 'Text' command. It's becuase the 'Text' command skips one step (Text height) if the current text style has already got text height assigned. Hope AutoCAD LT people find this tip very useful. Needless to say, it will give you the same result in AutoCAD full version.

*EDIT*

Thanks to a very good suggestion from Russ for adding a prefix, I ended up adding both prefix and suffix to the numbers.

*^c^c_text;\;;$M=$(getvar,USERS1)$M=$(+,$(getvar,USERR1),$(getvar,USERR2))$M=$(getvar,USERS2);setvar;USERR1;$M=$(+,$(getvar,USERR1),$(getvar,USERR2));

The macro uses USERS1 system variable to hold the prefix and USERS2 for the suffix. Thanks to comments from an anonymous visitor, I realised that USERSx system variables are not supported in AutoCAD LT. So I replaced the macro with a new one using (getenv,variable) function in place of (getvar,USERSx).


*^c^c_text;\;;$M=$(getenv,StrPrefix)$M=$(+,$(getvar,USERR1),$(getvar,USERR2))$M=$(getenv,StrSuffix);setvar;USERR1;$M=$(+,$(getvar,USERR1),$(getvar,USERR2));

You need to set two environment variables (I used StrPreifx for prefix and StrSuffix for suffix) using SETENV command which, I beleive, is available in AutoCAD LT. Don't forget to respect the text height of the current text style as mentioned eariler. Again, I don't have AutoCAD LT to test this macro. I would be really thankful if somebody could test it on LT and post a feedback on it.

*EDIT*

Sunday, August 19, 2007

Putting Everything Together - An Enhanced Line Command

I have experienced in the past that the best way to learn something new is to apply it in our own way. So it's time to apply whatever we have learned so far, in a practical way. The result is an enhanced line command which allows the user to change current layer and linetype on the fly. I have also tried to have logical seperations inside the code using reusable methods(See SetCurrentLayer, SetCurrentLType and CreateLine methods).

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
namespace AcadNetSamples
{
public class Commands
{
/// <summary>
/// Enhanced Line Command.
/// Allows user to change current layer and
/// linetype from within the command.
/// </summary>
[CommandMethod("ELINE")]
public static void DrawEnhancedLine()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptPointOptions prPO = new PromptPointOptions("\nPick start point of line : ");
prPO.AllowNone = true;
prPO.UseBasePoint = false;
PromptPointResult ppr;
ppr = ed.GetPoint(prPO);
//Get start point
Point3d SPoint = ppr.Value;
//Remeber it for the CLOSE option
Point3d CPoint = SPoint;
prPO.Keywords.Add("LAyer");
prPO.Keywords.Add("LType");
prPO.Keywords.Add("Close");
// Continue line command until the user interrupts
while (ppr.Status == PromptStatus.OK ppr.Status ==
PromptStatus.Keyword)
{
prPO.UseBasePoint = true;
//Use the previously picked point as the base point for new line
prPO.BasePoint = SPoint;
prPO.Message = "\nPick next point or ";
ppr = ed.GetPoint(prPO);
Point3d NPoint = ppr.Value;
if (ppr.Status == PromptStatus.OK ppr.Status ==
PromptStatus.Keyword)
{
//Exit command on enter key
if (ppr.Status == PromptStatus.None) break;
//Declare ObjectId variable for common use
ObjectId objID;
// Check to see whether any keyword is choosen
if (ppr.Status == PromptStatus.Keyword)
{
PromptResult prs;
switch (ppr.StringResult)
{
case "LAyer":
prs = ed.GetString("\nEnter a layer name to make it current: ");
if (prs.Status == PromptStatus.OK)
{
//Loop back on Enter
if (prs.StringResult == "")
continue ;
try
{
objID =
SetCurrentLayer(prs.StringResult);
//Check whether the operation was successful
if (objID != ObjectId.Null)
ed.WriteMessage("\nCurrent layer is '"
+ prs.StringResult+"'");
else
ed.WriteMessage("\nThe layer '" +
prs.StringResult + "' was not found.");
continue;
}
catch
{
ed.WriteMessage("\nUnable to change current
layer. An error occured...!!"
);
continue;
}
}
return ;
case "LType":
prs = ed.GetString("\nEnter a linetype name to make it current: ");
if (prs.Status == PromptStatus.OK)
{
//Loop back on Enter
if (prs.StringResult == "")
continue;
try
{
objID =
SetCurrentLType(prs.StringResult);
//Check whether the operation was successful
if (objID != ObjectId.Null)
ed.WriteMessage("\nCurrent linetype is "
+ prs.StringResult +"'");
else
ed.WriteMessage("\nThe linetype '"
+ prs.StringResult + "' was not found.");
continue;
}
catch
{
ed.WriteMessage("\nUnable to change current linetype. An error occured...!!");
continue;
}
}
return ;
case "Close":
try
{
objID =
CreateLine(SPoint, CPoint);
if (objID != ObjectId.Null)
return;
break;
}
catch {}
return;
}
}
try
{
objID = CreateLine(SPoint, NPoint);
//The last end point will serve as the next base point
if (objID != ObjectId.Null) SPoint = NPoint;
}
catch { return; }
}
}
}
private static ObjectId SetCurrentLayer(string LayerName)
{
ObjectId layerId=ObjectId.Null ;
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = db.TransactionManager;
using (Transaction tr = tm.StartTransaction())
{
LayerTable lt = (LayerTable)tm.GetObject(db.LayerTableId, OpenMode.ForRead, false);
if (lt.Has(LayerName))
{
layerId = lt[LayerName];
db.Clayer = layerId;
}
tr.Commit();
}
return layerId;
}
private static ObjectId SetCurrentLType(string LineTypeName)
{
ObjectId ltypeId = ObjectId.Null;
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = db.TransactionManager;
using (Transaction tr = tm.StartTransaction())
{
LinetypeTable ltt = (LinetypeTable)tm.GetObject(db.LinetypeTableId, OpenMode.ForRead, false);
if (ltt.Has(LineTypeName))
{
ltypeId = ltt[LineTypeName];
db.Celtype = ltypeId;
}
tr.Commit();
}
return ltypeId;
}
private static ObjectId CreateLine(Point3d SPoint,Point3d EPoint)
{
ObjectId lineId = ObjectId.Null;
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
Line oLine = new Line(SPoint, EPoint);
Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = db.TransactionManager;
using (Transaction tr = tm.StartTransaction())
{
BlockTable bt = (BlockTable)tm.GetObject(db.BlockTableId, OpenMode.ForRead, false);
BlockTableRecord btr = (BlockTableRecord)tm.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite, false);
using (oLine)
{
lineId = btr.AppendEntity(oLine);
tm.AddNewlyCreatedDBObject(oLine, true);
}
tr.Commit();
}
return lineId;
}
}
}

Compile the code and type ELINE to activate the command. If you come across and syntax / logical erros, please feel free to post it here.

Tuesday, August 14, 2007

Creating AutoCAD Geometry

I think it's time to get into AutoCAD geometry. So, in this session, we are going to create a line command . We will also see using prompt options in this sample code. The command name used here is DRAWLINE.

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
namespace AcadNetSamples
{
public class Commands
{
[CommandMethod("DrawLine")]
public static void DrawLine()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptPointOptions prPO = new PromptPointOptions("\nPick start point of line: ");
prPO.AllowNone = false;
prPO.UseBasePoint = false;
PromptPointResult ppr1 = ed.GetPoint(prPO);
if (ppr1.Status == PromptStatus.OK)
{
prPO.UseBasePoint = true;
prPO.BasePoint = ppr1.Value;
prPO.Message = "\nPick end point: ";
PromptPointResult ppr2 = ed.GetPoint(prPO);
if (ppr2.Status == PromptStatus.OK)
{
Point3d SPoint = ppr1.Value;
Point3d EPoint = ppr2.Value;
Line oLine = new Line(SPoint, EPoint);
Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = db.TransactionManager;
Autodesk.AutoCAD.DatabaseServices.Transaction tr = tm.StartTransaction();
using
(tr)
{
BlockTable bt = (BlockTable)tm.GetObject(db.BlockTableId, OpenMode.ForRead, false);
BlockTableRecord btr = (BlockTableRecord)tm.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite, false);
using
(oLine)
{
btr.AppendEntity(oLine);
tm.AddNewlyCreatedDBObject(oLine, true);
}
tr.Commit();
}
}
}
}
}
}

I don't want to confine this blog to learning AutoCAD.Net only. I have got some Tips & Tricks to share with you. You may encounter these in between the dotnet posts (If you see one, just understand that I didn't get enough time to learn next dotnet topic :-).

Saturday, August 11, 2007

AutoCAD Prompts & Error Handling

In this post, we are going to start with basic prompt operations and error handling. You will see samples on common AutoCAD prompts like string prompt, point prompt, distance prompt etc. The first sample in this session also covers very basic form of error handling. There are three commands (OPENDWG, DISPOINT & GETDIST) in the following code. The OPENDWG accepts a drawing path string input from the user and opens that drawing if exists. The DISPOINT prompts the user to pick a point and show the point value in the command prompt. The GETDIST prompts the user to pick two points and returns the distance between them. We will have a look at advanced prompt operations and creating AutoCAD geometry in the forthcoming sessions.

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;

namespace AcadNetSamples
{
public class Commands
{
[CommandMethod("OPENDWG")]
public static void OpenDrawing()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
PromptResult res = ed.GetString("\nEnter a drawing path: ");

if (res.Status == PromptStatus.OK)
{
try
{
Application.DocumentManager.Open(res.StringResult,false);
}
catch
{
ed.WriteMessage("\nUnable to open drawing file.");
return;
}
finally
{
ed.WriteMessage("\nThis is an AutoCAD.Net sample command.");
}
}
}
[CommandMethod("DISPOINT")]
public void DisplayPoint()
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
PromptPointOptions prPO = new PromptPointOptions("Select a point: ");
PromptPointResult prPR = ed.GetPoint(prPO);
if (prPR.Status != PromptStatus.OK)
{
ed.WriteMessage("An error occured...!");
}
else
{
ed.WriteMessage("The point is " + prPR.Value.ToString());
}
}

[CommandMethod("GETDIST")]
public void GetDistance()
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
PromptDistanceOptions prDO = new PromptDistanceOptions("Select first point: ");

PromptDoubleResult prDR = ed.GetDistance(prDO);

if (prDR.Status != PromptStatus.OK)
{
ed.WriteMessage("An error occured...!");
}
else
{
ed.WriteMessage("Distance: " + prDR.Value.ToString());
}
}
}
}

Sunday, August 5, 2007

Iterations in C#

As I mentioned in the last post, in this session, we are going to cover the loop structures in C#. Our primary aim is to concentrate more on the syntax of loops. Here is a sample which shows iteration results in AutoCAD prompt using different looping methods.

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
namespace AcadNetSamples
{
public class Commands
{
[CommandMethod("LOOPS")]
public static void LoopOperations()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
string[] strs = new string[10];
int i;
for (i = 0; i < 10; i++)
{
strs[i] = "String No. " + (i + 1).ToString();
}
ed.WriteMessage("\n\nUsing 'foreach' Loop\n");
foreach (string str in strs)
{
ed.WriteMessage("\n\t\t" + str);
}
ed.WriteMessage("\n\nUsing 'While' Loop\n");
i = 0;
while (i < 10)
{
ed.WriteMessage("\n\t\tString No. " + (i + 1).ToString());
i++;
}
ed.WriteMessage("\n\nUsing 'Do While' Loop\n");
i = 0;
do
{
ed.WriteMessage("\n\t\tString No. "+ (i + 1).ToString());
i++;
} while (i < 10);
}
}
}

Next session, I am planning to start with AutoCAD prompt operations. Like an online streaming buffer, I have to keep a little ahead of my posts :-). So the blog post interval will depend on how quickly I learn new things. I highly appreciate any valuable contributions from the readers.

Wednesday, August 1, 2007

Conditions forever

Before starting AutoCAD data specific programs, I would like to put my hands on C# language specific statements like If, Switch etc. Here is a sample program covering very basic condition checking and some output formatting. Next post, I shall try to cover looping in C#.

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
namespace AcadNetSamples
{
public class
Commands
{
[CommandMethod("CONDITIONS")]
public static void ConditionalOperations()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
int x = 1; int y = 2; int z = 3;
if ((x + y) == z) ed.WriteMessage("\n{0}+{1} is equal to {2}",x,y,z);
if ((z - y) != x)
{
ed.WriteMessage("\n{0}+{1} is not equal to {2}", z, y, x);
}
else
{
ed.WriteMessage("\n{0}-{1} is equal to {2}", z, y, x);
}
switch (x + y + z)
{
case 3:
ed.WriteMessage("\n{0}+{1}+{2}=3", x, y, z);
break;
case 4:
ed.WriteMessage("\n{0}+{1}+{2}=4", x, y, z);
break;
case 5:
ed.WriteMessage("\n{0}+{1}+{2}=5", x, y, z);
break;
default:
ed.WriteMessage("\n{0}+{1}+{2}={3}", x, y, z, (x + y + z));
break;
}
}
}
}

Try to experiment with the above code using different conditions. Also try to work with common logical operators like AND, OR etc. in your code.