The Advance Steel API works with the AutoCAD API.
This tutorial will look at several examples. For more information on the AutoCAD API, see the online help for the AutoCAD Managed .NET API.
Create a new class called WorkingWithAutoCADAPI and add the following code:
|
Code Region: WorkingWithAutoCADAPI command class |
using Autodesk.AdvanceSteel.CADAccess;
using Autodesk.AdvanceSteel.DocumentManagement;
using Autodesk.AdvanceSteel.Modelling;
using Autodesk.AdvanceSteel.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using System.Windows.Forms;
namespace WorkingWithAutoCADandASAPI
{
class WorkingWithAutoCADAPI
{
[CommandMethodAttribute("TEST_GROUP", "WorkingWithAutoCADAPI", "WorkingWithAutoCADAPI",
CommandFlags.Modal | CommandFlags.UsePickSet | CommandFlags.Redraw)]
public void Create()
{
using (DocumentAccess da = new DocumentAccess(null, false))
{
da.Commit();
}
}
}
}
|
Note that this tutorial will require 4 using statements for AutoCAD API namespaces. The AutoCAD API has several class names in common with Advance Steel, such as ObjectId. This requires disambiguation in the code. Rather than including the namespace in front of the class name, we can use a 'using alias directive' at the top of the file to create a shorter name for one of the classes. For this tutorial, we will use three using alias directives as shown in the rewritten code below.
|
Code Region: Disambiguating class names |
using Autodesk.AdvanceSteel.CADAccess;
using Autodesk.AdvanceSteel.DocumentManagement;
using Autodesk.AdvanceSteel.Modelling;
using Autodesk.AdvanceSteel.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using System.Windows.Forms;
using ACTransaction = Autodesk.AutoCAD.DatabaseServices.Transaction;
using ASObjectId = Autodesk.AdvanceSteel.CADLink.Database.ObjectId;
using ACDocument = Autodesk.AutoCAD.ApplicationServices.Document;
using Autodesk.AutoCAD.Geometry;
namespace WorkingWithAutoCADandASAPI
{
class WorkingWithAutoCADAPI
{
[CommandMethodAttribute("TEST_GROUP", "WorkingWithAutoCADAPI", "WorkingWithAutoCADAPI",
CommandFlags.Modal | CommandFlags.UsePickSet | CommandFlags.Redraw)]
public void Create()
{
using (DocumentAccess da = new DocumentAccess(null, false))
{
da.Commit();
}
}
}
}
|
The using alias directives will be used later in the tutorial.
In the Walkthrough: Create beam and plate features tutorial, we looked a using the UserInteraction class to have the user select an object on which to act. In this tutorial, we will look at using an AutoCAD selection window to automatically select some objects based on location.
Add the method below to the WorkingWithAutoCADAPI class. This method uses a crossing window to find objects within a rectangular area. It then checks if any of them are straight beams and returns he first straight beam it finds.
|
Code Region: Selecting a beam |
private StraightBeam GetStraightBeam()
{
StraightBeam beam = null;
//Try to get a beam repr using AutoCad selection window
PromptSelectionResult acSSPrompt;
Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
acSSPrompt = ed.SelectCrossingWindow(new Point3d(0, 0, 0), new Point3d(1000, 0, 0));
if (acSSPrompt.Status == PromptStatus.OK)
{
SelectionSet acSSet = acSSPrompt.Value;
ObjectId[] ids = acSSet.GetObjectIds();
//Iterate through the selected objects, and check if we have a straight beam
foreach (ObjectId id in ids)
{
//Get the beam filer object
ASObjectId idDbObject =
DatabaseManager.GetFilerObjectId(new ASObjectId(id.OldIdPtr), false);
FilerObject obj = DatabaseManager.Open(idDbObject);
//If we have a straight beam
if (obj.Type() == FilerObject.eObjectType.kStraightBeam)
{
beam = obj as StraightBeam;
break;
}
}
}
return beam;
}
|
In the sample code above, note that after getting the Autodesk.AutoCAD.DatabaseServices.ObjectId, it is converted to a Autodesk.AdvanceSteel.CADLink.Database.ObjectId before checking to see if it is a StraightBeam. This is due to a duality of Advance Steel entities. Advance Steel objects are, in general, composed of two AutoCAD entities: the "internal" entity and the "representation" entity. Normally an Advance Steel user can only interface with the "representation" entity. That is, when a user selects a beam inside Advance Seel they select the representation of the beam.
In order to successfully work with Advance Steel and AutoCAD API it is necessary to understand which entity is required. Whenever you want AutoCAD to act on an object you need to use the "representation" id, while in the cases when you want the AdvanceSteel API to act on the same object the "internal" id must be used. Whenever object ids are obtained by calling methods, Advance Steel methods always return ids of the "internal" objects, while AutoCAD API calls always return ids of the "representation" objects. The Advance Steel API has methods to go from one type of id to the other.
Next, let's look at using the AutoCAD API to explode an Advance Steel entity. This works similarly to selecting an Advance Steel beam and calling the "explode" command on it. It will return the exploded lines, but does not affect the model. The resulting simpler entities can be exported or used for calculations or other uses.
|
Code Region: Exploding a beam |
private int ExplodeBeam(StraightBeam beam)
{
int nExplodedEnts = 0;
// get the "representation" id - the id that AutoCAD understands as being the object drawn on the screen
ASObjectId reprId = DatabaseManager.GetReprId(beam);
// convert this id from "AdvanceSteel" id to "Acad" id
ObjectId acadIdBeam = new ObjectId(reprId.AsOldId());
// start an AutoCAD transaction
DocumentCollection docs = Autodesk.AutoCAD.ApplicationServices.Core.Application.DocumentManager;
ACDocument currDoc = docs.CurrentDocument;
Autodesk.AutoCAD.DatabaseServices.Transaction trans = currDoc.TransactionManager.StartTransaction();
// use the transaction to gain access to the beam representation as an AutoCAD entity
DBObject objBeam = trans.GetObject(acadIdBeam, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForWrite);
if (objBeam is Autodesk.AutoCAD.DatabaseServices.Entity)
{
Entity ent = (Entity)objBeam;
// ask autoCAD to "explode" this beam - equivalent of selecting an advance steel beam from the screen and calling "explode" command
DBObjectCollection explodedEnts = new DBObjectCollection();
ent.Explode(explodedEnts);
nExplodedEnts = explodedEnts.Count;
trans.Commit();
}
return nExplodedEnts;
}
|
Note that the method above first converts the Advance Steel id to an AutoCAD id since we want the AutoCAD Explode method to act on the entity.
Now return to the original Create() method for the WorkingWithAutoCADAPI and call our two methods - one to get an Advance Steel straight beam and one to explode it.
|
Code Region: Putting it together |
public void Create()
{
using (DocumentAccess da = new DocumentAccess(null, true))
{
StraightBeam beam = GetStraightBeam();
if (beam != null)
{
ExplodeBeam(beam);
}
}
}
|
Advance Steel special parts are generic 3d objects that can be added to an Advance Steel model to complement standard construction elements. Special parts can be created just like block references from external dwg files containing any valid AutoCAD objects including other Advance Steel objects. A solid is created first and then assigned to the special part.
In this example, we will create the AutoCAD 3d solid with code, but it could also be created manually. Add the following method to the class file to create a wedge.
|
Code Region: Creating an AutoCAD 3d solid |
private ObjectId CreateAutoCADWedge()
{
ObjectId ret;
// Get the current document and database, and start an AutoCAD transaction
ACDocument acDoc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
Database acCurDb = acDoc.Database;
using (ACTransaction acTrans = acCurDb.TransactionManager.StartTransaction())
{
// Open the Block table record for read
BlockTable acBlkTbl;
acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForWrite) as BlockTable;
// Open the Block table record Model space for write
BlockTableRecord acBlkTblRec = new BlockTableRecord();
acBlkTblRec.Name = "wedge";
// Create a 3D solid wedge
Solid3d acSol3D = new Solid3d();
acSol3D.SetDatabaseDefaults();
acSol3D.CreateWedge(10, 15, 20);
// Position the center of the 3D solid at (5,5,0)
acSol3D.TransformBy(Matrix3d.Displacement(new Point3d(5, 5, 0) - Point3d.Origin));
// Add the new object to the block table record and the transaction
acBlkTblRec.AppendEntity(acSol3D);
acBlkTbl.Add(acBlkTblRec);
acTrans.AddNewlyCreatedDBObject(acBlkTblRec, true);
// Save the new objects to the database
acTrans.Commit();
ret = acBlkTblRec.Id;
}
return ret;
}
|
Note that the method returns an ObjectId for the BlockTableRecord. We will use this for our special part, after converting it to an Advance Steel ObjectId. Add the following method to create a new special part.
|
Code Region: Creating a special part |
private void CreateSpecialPart()
{
SpecialPart specialPart = new SpecialPart(new Autodesk.AdvanceSteel.Geometry.Matrix3d());
specialPart.WriteToDb();
ObjectId newBlock = CreateAutoCADWedge();
specialPart.SetBlock(new ASObjectId(newBlock.OldIdPtr), 1.0);
}
|
|
Code Region: Putting it together |
public void Create()
{
using (DocumentAccess da = new DocumentAccess(null, false))
{
StraightBeam beam = GetStraightBeam();
if (beam != null)
{
ExplodeBeam(beam);
}
CreateSpecialPart();
da.Commit();
}
}
|
Sometimes it is useful to respond to a command in AutoCAD. An Advance Steel plugin can subscribe to the CommandEnded event to be notified with a command has completed so some action can be taken. In this example, we will create a method that looks for when a new beam has been added to the Advance Steel model and checks to make sure all beams (which would include the new one) meet some minimum beam length (and issue a warning if one does not).
|
Code Region: CommandEnded reactor |
void CurrentDocument_CommandEnded(object sender, Autodesk.AutoCAD.ApplicationServices.CommandEventArgs e)
{
// If a beam has just been created
if (e.GlobalCommandName == "ASTM4CRBEAMBYCLASS")
{
using (DocumentAccess da = new DocumentAccess(null, true))
{
try
{
ASObjectId[] ids;
ClassTypeFilter filter = new ClassTypeFilter();
filter.AppendAcceptedClass(FilerObject.eObjectType.kStraightBeam);
//Get all the beams from the database
DatabaseManager.GetModelObjectIds(out ids, filter);
foreach (ASObjectId id in ids)
{
FilerObject obj = DatabaseManager.Open(id);
if (obj != null)
{
StraightBeam sb = obj as StraightBeam;
// check that beam meets minimum length for project
double length = sb.GetLength();
if (length < 305)
{
MessageBox.Show("Minimum beam length is 305 mm. Please adjust beam.");
}
}
}
}
catch(System.Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
|
Note that in this method, it checks the GlobalCommandName to see if it is ASTM4CRBEAMBYCLASS, the command indicating that a new Advance Steel beam has been created. The command name may be one created by another plugin, such as CREATEFEATURES, or any built in command from Advance Steel or AutoCAD. If you do not know the name of the command you want to create a reactor for, simply create a command reactor method similar to above and place a breakpoint in the method to check the value of e.GlobalCommandName when the command is triggered at the end of the desired command.
Since this method will be called when a command has ended and is not going to be within the scope of the transaction started in the Create() method, it is necessary for CurrentDocument_CommandEnded to have it's own transaction, as well as calls to lock and unlock the current document.
To have your command reactor called, it must be registered with the current document. Add the following code to the WorkingWithAutoCADAPI class to register the CurrentDocument_CommandEnded method.
|
Code Region: Registering a command reactor |
private void AddCommandEndedReactor()
{
DocumentCollection docs = Autodesk.AutoCAD.ApplicationServices.Core.Application.DocumentManager;
ACDocument currDoc = docs.CurrentDocument;
currDoc.CommandEnded += CurrentDocument_CommandEnded;
}
|
|
Code Region: Putting it together |
public void Create()
{
using (DocumentAccess da = new DocumentAccess(null, false))
{
StraightBeam beam = GetStraightBeam();
if (beam != null)
{
ExplodeBeam(beam);
}
CreateSpecialPart();
AddCommandEndedReactor();
}
}
|
After invoking the WorkingWithAutoCADAPI method in Avance Steel, the CurrentDocument_CommandEnded method will be called whenever a command ends in AutoCAD or Advance Steel.