In the last post we looked at how to add a new annotative scale to an AutoCAD drawing.
In this post we'll look at what's needed to make an object annotative - providing it's of a type that supports annotation scaling, of course. Once again, this post is based on functionality introduced in AutoCAD 2008.
I hit my head against the problem for a while, having tried my best to convert the technique shown in the AnnotationScaling ObjectARX sample (which uses a protocol extension to access objects stored in an annotative entity's extension dictionary) to .NET. I finally ended up asking our Engineering team: Ravi Pothineni came back with some code that uses an internal assembly (but one that ships with AutoCAD) to do this. Apparently this will become standard functionality in a future release of AutoCAD - it'll just be available directly from DBObject, rather than being in a separate "helper" - but in the meantime you will have to use slightly more cumbersome code, such as that shown below, and add a reference to AcMgdInternal.dll for it to work. As indicated by the name, this functionality is unsupported and to be used at your own risk.
Here's the C# code - the "ADS" command is basically the one shown previously (renamed from "AS") and the "ATS" function is the new command that makes an object annotative, attaching annotation scales to it:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Internal;
namespace AnnotationScaling
{
public class Commands
{
[CommandMethod("ADS")]
static public void addScale()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
try
{
ObjectContextManager ocm =
db.ObjectContextManager;
if (ocm != null)
{
// Now get the Annotation Scaling context collection
// (named ACDB_ANNOTATIONSCALES_COLLECTION)
ObjectContextCollection occ =
ocm.GetContextCollection("ACDB_ANNOTATIONSCALES");
if (occ != null)
{
// Create a brand new scale context
AnnotationScale asc = new AnnotationScale();
asc.Name = "MyScale 1:28";
asc.PaperUnits = 1;
asc.DrawingUnits = 28;
// Add it to the drawing's context collection
occ.AddContext(asc);
}
}
}
catch (System.Exception ex)
{
ed.WriteMessage(ex.ToString());
}
}
[CommandMethod("ATS")]
static public void attachScale()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
ObjectContextManager ocm =
db.ObjectContextManager;
ObjectContextCollection occ =
ocm.GetContextCollection("ACDB_ANNOTATIONSCALES");
Transaction tr =
doc.TransactionManager.StartTransaction();
using (tr)
{
PromptEntityOptions opts =
new PromptEntityOptions("\nSelect entity: ");
opts.SetRejectMessage(
"\nEntity must support annotation scaling."
);
opts.AddAllowedClass(typeof(DBText), false);
opts.AddAllowedClass(typeof(MText), false);
opts.AddAllowedClass(typeof(Dimension), false);
opts.AddAllowedClass(typeof(Leader), false);
opts.AddAllowedClass(typeof(Hatch), false);
PromptEntityResult per = ed.GetEntity(opts);
if (per.ObjectId != ObjectId.Null)
{
DBObject obj =
tr.GetObject(per.ObjectId, OpenMode.ForRead);
if (obj != null)
{
obj.UpgradeOpen();
obj.Annotative = AnnotativeStates.True;
ObjectContexts.AddContext(obj, occ.GetContext("1:1"));
ObjectContexts.AddContext(obj, occ.GetContext("1:2"));
ObjectContexts.AddContext(obj, occ.GetContext("1:10"));
ObjectContext oc = occ.GetContext("MyScale 1:28");
if (oc != null)
{
ObjectContexts.AddContext(obj, oc);
}
}
}
tr.Commit();
}
}
}
}
You'll notice that if you run the ADS command before ATS, you'll also get the newly-added annotation scale in the selected object's list:
Update:
From AutoCAD 2009 onwards, it's now possible to modify annotation scales on an object directly without relying on unsupported funcitonality in acmgdinternal.dll.
Here's the modified C# code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
namespace AnnotationScaling
{
public class Commands
{
[CommandMethod("ADS")]
static public void addScale()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
try
{
ObjectContextManager ocm =
db.ObjectContextManager;
if (ocm != null)
{
// Now get the Annotation Scaling context collection
// (named ACDB_ANNOTATIONSCALES_COLLECTION)
ObjectContextCollection occ =
ocm.GetContextCollection("ACDB_ANNOTATIONSCALES");
if (occ != null)
{
// Create a brand new scale context
AnnotationScale asc = new AnnotationScale();
asc.Name = "MyScale 1:28";
asc.PaperUnits = 1;
asc.DrawingUnits = 28;
// Add it to the drawing's context collection
occ.AddContext(asc);
}
}
}
catch (System.Exception ex)
{
ed.WriteMessage(ex.ToString());
}
}
[CommandMethod("ATS")]
static public void attachScale()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
ObjectContextManager ocm =
db.ObjectContextManager;
ObjectContextCollection occ =
ocm.GetContextCollection("ACDB_ANNOTATIONSCALES");
Transaction tr =
doc.TransactionManager.StartTransaction();
using (tr)
{
PromptEntityOptions opts =
new PromptEntityOptions("\nSelect entity: ");
opts.SetRejectMessage(
"\nEntity must support annotation scaling."
);
opts.AddAllowedClass(typeof(DBText), false);
opts.AddAllowedClass(typeof(MText), false);
opts.AddAllowedClass(typeof(Dimension), false);
opts.AddAllowedClass(typeof(Leader), false);
opts.AddAllowedClass(typeof(Table), false);
opts.AddAllowedClass(typeof(Hatch), false);
PromptEntityResult per = ed.GetEntity(opts);
if (per.ObjectId != ObjectId.Null)
{
DBObject obj =
tr.GetObject(per.ObjectId, OpenMode.ForRead);
if (obj != null)
{
obj.UpgradeOpen();
obj.Annotative = AnnotativeStates.True;
obj.AddContext(occ.GetContext("1:1"));
obj.AddContext(occ.GetContext("1:2"));
obj.AddContext(occ.GetContext("1:10"));
ObjectContext oc = occ.GetContext("MyScale 1:28");
if (oc != null)
{
obj.AddContext(oc);
}
}
}
tr.Commit();
}
}
}
}