In the last post we looked at a jig that can be used to add block references to an AutoCAD drawing. This post extends that code to support annotative block definitions (available from AutoCAD 2008) and blocks with attributes. Thanks once again to Holger Steiner for the jig class and to Roland Feletic for posting the code to support annotative blocks.
A comment on the previous post asked about having attributes visible during the jig process: unfortunately that's not currently possible, as the existing managed AttributeCollection implementation wraps the version of the AcDbBlockReference::appendAttribute() ObjectARX function that requires the block reference to already have been added to the drawing. So for now you will need to live with the fact that the attributes don't display during the jig, but do display as soon as the block has been added to the drawing.
Below is the modified C# code, with line numbers. And here's the source file for download.
1 using Autodesk.AutoCAD.ApplicationServices;
2 using Autodesk.AutoCAD.DatabaseServices;
3 using Autodesk.AutoCAD.EditorInput;
4 using Autodesk.AutoCAD.Runtime;
5 using Autodesk.AutoCAD.Geometry;
6 using Autodesk.AutoCAD.Internal;
7
8 namespace BlockJigTest
9 {
10 class BlockJig : EntityJig
11 {
12 Point3d mCenterPt, mActualPoint;
13
14 public BlockJig(BlockReference br)
15 : base(br)
16 {
17 mCenterPt = br.Position;
18 }
19
20 protected override SamplerStatus Sampler(JigPrompts prompts)
21 {
22 JigPromptPointOptions jigOpts =
23 new JigPromptPointOptions();
24 jigOpts.UserInputControls =
25 (UserInputControls.Accept3dCoordinates
26 | UserInputControls.NoZeroResponseAccepted
27 | UserInputControls.NoNegativeResponseAccepted);
28
29 jigOpts.Message =
30 "\nEnter insert point: ";
31
32 PromptPointResult dres =
33 prompts.AcquirePoint(jigOpts);
34
35 if (mActualPoint == dres.Value)
36 {
37 return SamplerStatus.NoChange;
38 }
39 else
40 {
41 mActualPoint = dres.Value;
42 }
43 return SamplerStatus.OK;
44 }
45
46 protected override bool Update()
47 {
48 mCenterPt = mActualPoint;
49 try
50 {
51 ((BlockReference)Entity).Position = mCenterPt;
52 }
53 catch (System.Exception)
54 {
55 return false;
56 }
57 return true;
58 }
59
60 public Entity GetEntity()
61 {
62 return Entity;
63 }
64 }
65
66 public class Commands
67 {
68 [CommandMethod("BJIG")]
69 public void CreateBlockWithJig()
70 {
71 Document doc =
72 Application.DocumentManager.MdiActiveDocument;
73 Database db = doc.Database;
74 Editor ed = doc.Editor;
75
76 // First let's get the name of the block
77 PromptStringOptions opts =
78 new PromptStringOptions("\nEnter block name: ");
79 PromptResult pr = ed.GetString(opts);
80 if (pr.Status == PromptStatus.OK)
81 {
82 Transaction tr =
83 doc.TransactionManager.StartTransaction();
84 using (tr)
85 {
86 // Then open the block table and check the
87 // block definition exists
88 BlockTable bt =
89 (BlockTable)tr.GetObject(
90 db.BlockTableId,
91 OpenMode.ForRead
92 );
93 if (!bt.Has(pr.StringResult))
94 {
95 ed.WriteMessage("\nBlock not found.");
96 }
97 else
98 {
99 ObjectId bdId = bt[pr.StringResult];
100
101 // We loop until the jig is cancelled
102 while (pr.Status == PromptStatus.OK)
103 {
104 // Create the block reference and
105 // add it to the jig
106 Point3d pt = new Point3d(0, 0, 0);
107 BlockReference br =
108 new BlockReference(pt, bdId);
109
110 BlockJig entJig = new BlockJig(br);
111
112 // Perform the jig operation
113 pr = ed.Drag(entJig);
114 if (pr.Status == PromptStatus.OK)
115 {
116 // If all is OK, let's go and add the
117 // entity to the modelspace
118 BlockTableRecord ms =
119 (BlockTableRecord)tr.GetObject(
120 bt[BlockTableRecord.ModelSpace],
121 OpenMode.ForWrite
122 );
123 ms.AppendEntity(
124 entJig.GetEntity()
125 );
126 tr.AddNewlyCreatedDBObject(
127 entJig.GetEntity(),
128 true
129 );
130
131 // Start attrib/annot-scale support code
132 BlockTableRecord bd =
133 (BlockTableRecord)tr.GetObject(
134 bdId,
135 OpenMode.ForRead
136 );
137 if (bd.Annotative == AnnotativeStates.True)
138 {
139 ObjectContextManager ocm =
140 db.ObjectContextManager;
141 ObjectContextCollection occ =
142 ocm.GetContextCollection(
143 "ACDB_ANNOTATIONSCALES"
144 );
145 ObjectContexts.AddContext(
146 br,
147 occ.CurrentContext
148 );
149 }
150
151 // Add the attributes
152 foreach (ObjectId attId in bd)
153 {
154 Entity ent =
155 (Entity)tr.GetObject(
156 attId,
157 OpenMode.ForRead
158 );
159 if (ent is AttributeDefinition)
160 {
161 AttributeDefinition ad =
162 (AttributeDefinition)ent;
163 AttributeReference ar =
164 new AttributeReference();
165 ar.SetAttributeFromBlock(
166 ad,
167 br.BlockTransform
168 );
169 br.AttributeCollection.AppendAttribute(ar);
170 tr.AddNewlyCreatedDBObject(ar, true);
171 }
172 }
173 // End attrib/annot-scale support code
174
175 // Call a function to make the graphics display
176 // (otherwise it will only do so when we Commit)
177 doc.TransactionManager.QueueForGraphicsFlush();
178 }
179 }
180 }
181 tr.Commit();
182 }
183 }
184 }
185 }
186 }
You'll notice the lines in red, from lines 131 to 173, have been added to the previous version of the code. The lines from 137 to 149 will only work with versions since AutoCAD 2008, as they're related to annotation scaling. As mentioned previously, this section of code relies on AcMgdInternal.dll, an unsupported assembly which is liable to change in future releases.
Update:
Subsequent to the comment from Roland, I've modified the above code to attach the annotation scale earlier, before the jig starts. This allows the jig to properly represent the block being placed (as otherwise annotative blocks will not display during the jig operation):
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Internal;
namespace BlockJigTest
{
class BlockJig : EntityJig
{
Point3d mCenterPt, mActualPoint;
public BlockJig(BlockReference br)
: base(br)
{
mCenterPt = br.Position;
}
protected override SamplerStatus Sampler(JigPrompts prompts)
{
JigPromptPointOptions jigOpts =
new JigPromptPointOptions();
jigOpts.UserInputControls =
(UserInputControls.Accept3dCoordinates
| UserInputControls.NoZeroResponseAccepted
| UserInputControls.NoNegativeResponseAccepted);
jigOpts.Message =
"\nEnter insert point: ";
PromptPointResult dres =
prompts.AcquirePoint(jigOpts);
if (mActualPoint == dres.Value)
{
return SamplerStatus.NoChange;
}
else
{
mActualPoint = dres.Value;
}
return SamplerStatus.OK;
}
protected override bool Update()
{
mCenterPt = mActualPoint;
try
{
((BlockReference)Entity).Position = mCenterPt;
}
catch (System.Exception)
{
return false;
}
return true;
}
public Entity GetEntity()
{
return Entity;
}
}
public class Commands
{
[CommandMethod("BJIG")]
public void CreateBlockWithJig()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
// First let's get the name of the block
PromptStringOptions opts =
new PromptStringOptions("\nEnter block name: ");
PromptResult pr = ed.GetString(opts);
if (pr.Status == PromptStatus.OK)
{
Transaction tr =
doc.TransactionManager.StartTransaction();
using (tr)
{
// Then open the block table and check the
// block definition exists
BlockTable bt =
(BlockTable)tr.GetObject(
db.BlockTableId,
OpenMode.ForRead
);
if (!bt.Has(pr.StringResult))
{
ed.WriteMessage("\nBlock not found.");
}
else
{
ObjectId bdId = bt[pr.StringResult];
// We loop until the jig is cancelled
while (pr.Status == PromptStatus.OK)
{
// Create the block reference and
// add it to the jig
Point3d pt = new Point3d(0, 0, 0);
BlockReference br =
new BlockReference(pt, bdId);
// Start annot-scale support code
BlockTableRecord bd =
(BlockTableRecord)tr.GetObject(
bdId,
OpenMode.ForRead
);
// Using will dispose of the block definition
// when no longer needed
using (bd)
{
if (bd.Annotative == AnnotativeStates.True)
{
ObjectContextManager ocm =
db.ObjectContextManager;
ObjectContextCollection occ =
ocm.GetContextCollection(
"ACDB_ANNOTATIONSCALES"
);
ObjectContexts.AddContext(
br,
occ.CurrentContext
);
}
}
// End annot-scale support code
BlockJig entJig = new BlockJig(br);
// Perform the jig operation
pr = ed.Drag(entJig);
if (pr.Status == PromptStatus.OK)
{
// If all is OK, let's go and add the
// entity to the modelspace
BlockTableRecord ms =
(BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace],
OpenMode.ForWrite
);
ms.AppendEntity(
entJig.GetEntity()
);
tr.AddNewlyCreatedDBObject(
entJig.GetEntity(),
true
);
// Start attribute support code
bd =
(BlockTableRecord)tr.GetObject(
bdId,
OpenMode.ForRead
);
// Add the attributes
foreach (ObjectId attId in bd)
{
Entity ent =
(Entity)tr.GetObject(
attId,
OpenMode.ForRead
);
if (ent is AttributeDefinition)
{
AttributeDefinition ad =
(AttributeDefinition)ent;
AttributeReference ar =
new AttributeReference();
ar.SetAttributeFromBlock(
ad,
br.BlockTransform
);
br.AttributeCollection.AppendAttribute(ar);
tr.AddNewlyCreatedDBObject(ar, true);
}
}
// End attribute support code
// Call a function to make the graphics display
// (otherwise it will only do so when we Commit)
doc.TransactionManager.QueueForGraphicsFlush();
}
}
}
tr.Commit();
}
}
}
}
}
Update 2:
This more recent post shows how to jig blocks with attributes.
Leave a Reply to Tore Cancel reply