Add the Dynamic Block Callout Bubble and others using C#

Add the Dynamic Block Callout Bubble and others using C#

kmkxperia
Advocate Advocate
635 Views
4 Replies
Message 1 of 5

Add the Dynamic Block Callout Bubble and others using C#

kmkxperia
Advocate
Advocate

 

Hi I am trying to add the below dynamic bubble annotation using annotation. I am able to goto the dynamic block but not able to figure out how to get these annotations and put them on the drawing

[CommandMethod("CreateOrdinateDimension")]
public static void CreateOrdinateDimension()
{
// Get the current database
Document acDoc = Application.DocumentManager.MdiActiveDocument;
Database acCurDb = acDoc.Database;

// Start a transaction
using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
{
// Open the Block table for read
BlockTable acBlkTbl;
acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId,
OpenMode.ForRead) as BlockTable;

// Open the Block table record Model space for write
BlockTableRecord acBlkTblRec;
acBlkTblRec = acTrans.GetObject(acBlkTbl[BlockTableRecord.ModelSpace],
OpenMode.ForWrite) as BlockTableRecord;

 

How to add below annotation and get other annotations names

 

}}

 

kmkxperia_0-1684166890330.png

 

 

 

0 Likes
636 Views
4 Replies
Replies (4)
Message 2 of 5

norman.yuan
Mentor
Mentor

these dynamic blocks showed on Tool PaletteSet are just regular dynamic blocks stored somewhere in the computer by AutoCAD installation. You can find them in "C:\Program Files\Autodesk\AutoCAD 202x\Sample\en-us\Dynamic Blocks" folder. However, these blocks are not saved as individual block drawing. Rather they stored in drawing files (with the name shown as Toll PaletteSet's tab text) as block definitions (BlockTableRecord). 

 

So, in order to insert block references of these blocks, you need to do:

 

1. Open one of the drawing that contains your target block definition as side database, find the block definition and call WBlockCloneObjects() to import the BlockTableRecord into the current drawing's BlockTable;

2. Create a new BlockReference based in the imported blocktablerecord;

3. If the block is annotative, you need to associtate approperiate ObjectContext (AnnotationScale) to this block reference;

4. If the block definition has attribute defined, you add corresponding AttributeReferences to the block reference and set attribute values accordingly;

5. Since there blocks are dynamic, you need to set dynamic property values as required.

 

If you have done dynamic block insertion coding, all aforementioned steps are straightforward to do. Or, you can search this forum for WBlockCloneObject(), and for dynamic block insertion code samples.

 

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 3 of 5

kmkxperia
Advocate
Advocate

I tried below code I but it is only placing the numbers but not the bubble so in Image here Actual is what I am getting.

kmkxperia_0-1684239339590.png

 

 

 

[CommandMethod("AddCalloutBubble")]
        public static void AddCalloutBubble()

        {

            string blockPath = @"C:\\Program Files\\Autodesk2021\\AutoCAD 2021\\Sample\\en-us\\Dynamic Blocks\\Annotation - Imperial.dwg";
            string blockName = "Callout Bubble - Imperial";
            InsertBlock(blockPath, blockName);
        }

        private static void InsertBlock(string blockPath, string blockName)
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;
            using (var tr = db.TransactionManager.StartTransaction())
            {
                var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                ObjectId btrId = bt.Has(blockName) ?
                    bt[blockName] :
                    ImportBlock(db, blockName, blockPath);
                if (btrId.IsNull)
                {
                    ed.WriteMessage($"\nBlock '{blockName}' not found.");
                    return;
                }

                var cSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                var br = new BlockReference(Point3d.Origin, btrId);
                cSpace.AppendEntity(br);
                tr.AddNewlyCreatedDBObject(br, true);

                // add attribute references to the block reference
                var btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForRead);
                var attInfos = new Dictionary<string, TextInfo>();
                if (btr.HasAttributeDefinitions)
                {
                    foreach (ObjectId id in btr)
                    {
                        if (id.ObjectClass.DxfName == "ATTDEF")
                        {
                            var attDef = (AttributeDefinition)tr.GetObject(id, OpenMode.ForRead);
                            attInfos[attDef.Tag] = new TextInfo(
                                attDef.Position,
                                attDef.AlignmentPoint,
                                attDef.Justify != AttachmentPoint.BaseLeft,
                                attDef.Rotation);
                            var attRef = new AttributeReference();
                            attRef.SetAttributeFromBlock(attDef, br.BlockTransform);
                            attRef.TextString = attDef.TextString;
                            br.AttributeCollection.AppendAttribute(attRef);
                            tr.AddNewlyCreatedDBObject(attRef, true);
                        }
                    }
                }
                var jig = new InsertBlockJig(br, attInfos);
                var pr = ed.Drag(jig);
                if (pr.Status != PromptStatus.OK)
                {
                    br.Erase();
                }
                tr.Commit();
            }
        }

        private static ObjectId ImportBlock(Database destDb, string blockName, string sourceFileName)
        {
            if (System.IO.File.Exists(sourceFileName))
            {
                using (var sourceDb = new Database(false, true))
                {
                    try
                    {
                        // Read the DWG into a side database
                        sourceDb.ReadDwgFile(sourceFileName, FileOpenMode.OpenForReadAndAllShare, true, "");

                        // Create a variable to store the block identifier
                        var id = ObjectId.Null;
                        using (var tr = new OpenCloseTransaction())
                        {
                            // Open the block table
                            var bt = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead, false);

                            // if the block table contains 'blockName', store it into the variable
                            if (bt.Has(blockName))
                                id = bt[blockName];
                            MessageBox.Show(blockName);

                        }
                        // if the variable is not null (i.e. the block was found)
                        if (!id.IsNull)
                        {
                            // Copy the block deinition from source to destination database
                            var blockIds = new ObjectIdCollection();
                            blockIds.Add(id);
                            var mapping = new IdMapping();
                            sourceDb.WblockCloneObjects(blockIds, destDb.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);
                            // if the copy succeeded, return the ObjectId of the clone
                            if (mapping[id].IsCloned)
                                return mapping[id].Value;
                        }
                    }
                    catch (Autodesk.AutoCAD.Runtime.Exception ex)
                    {
                        var ed = Application.DocumentManager.MdiActiveDocument.Editor;
                        ed.WriteMessage("\nError during copy: " + ex.Message + "\n" + ex.StackTrace);
                    }
                }
            }
            return ObjectId.Null;
        }

        struct TextInfo
        {
            public Point3d Position { get; private set; }
            public Point3d Alignment { get; private set; }
            public bool IsAligned { get; private set; }
            public double Rotation { get; private set; }
            public TextInfo(Point3d position, Point3d alignment, bool aligned, double rotation)
            {
                Position = position;
                Alignment = alignment;
                IsAligned = aligned;
                Rotation = rotation;
            }
        }

        class InsertBlockJig : EntityJig
        {
            BlockReference br;
            Point3d pt;
            Dictionary<string, TextInfo> attInfos;

            public InsertBlockJig(BlockReference br, Dictionary<string, TextInfo> attInfos) : base(br)
            {
                this.br = br;
                this.attInfos = attInfos;
            }

            protected override SamplerStatus Sampler(JigPrompts prompts)
            {
                var options = new JigPromptPointOptions("\nSpecify insertion point: ");
                options.UserInputControls = UserInputControls.Accept3dCoordinates;
                var result = prompts.AcquirePoint(options);
                if (result.Value.IsEqualTo(pt))
                    return SamplerStatus.NoChange;
                pt = result.Value;
                return SamplerStatus.OK;
            }

            protected override bool Update()
            {
                br.Position = pt;
                if (br.AttributeCollection.Count > 0)
                {
                    var tr = br.Database.TransactionManager.TopTransaction;
                    foreach (ObjectId id in br.AttributeCollection)
                    {
                        var attRef = (AttributeReference)tr.GetObject(id, OpenMode.ForRead);
                        string tag = attRef.Tag.ToUpper();
                        if (attInfos.ContainsKey(tag))
                        {
                            TextInfo ti = attInfos[tag];
                            attRef.Position = ti.Position.TransformBy(br.BlockTransform);
                            if (ti.IsAligned)
                            {
                                attRef.AlignmentPoint =
                                    ti.Alignment.TransformBy(br.BlockTransform);
                                attRef.AdjustAlignment(br.Database);
                            }
                            if (attRef.IsMTextAttribute)
                            {
                                attRef.UpdateMTextAttribute();
                            }
                        }
                    }
                }
                return true;
            }
        }
    }

 

0 Likes
Message 4 of 5

norman.yuan
Mentor
Mentor

Not sure what/when the code went wrong. Can you open the block definition in Block Editor (command "BEDIT") to verify whether the block definition is imported correctly? You could try to only run the method "ImportBlock()". I just copied your code with very minor changes, as following, and ran it. The block was imported correctly:

 

		[CommandMethod("ImportBlk")]
		public static void ImportBlk()
		{
			var file = @"C:\Program Files\Autodesk\AutoCAD 2021\Sample\en-us\Dynamic Blocks\Annotation - Imperial.dwg";
			var blkName = "Callout Bubble - Imperial";
			var blkId = ObjectId.Null;
			var curDb = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database;
			using (var db = new Database(false, true))
			{
				db.ReadDwgFile(file, FileOpenMode.OpenForReadAndAllShare, false, null);
				using (var tran=db.TransactionManager.StartTransaction())
				{
					var bt = (BlockTable)tran.GetObject(db.BlockTableId, OpenMode.ForRead);
					if (bt.Has(blkName))
					{
						blkId = bt[blkName];
					}

					tran.Commit();
				}

				if (!blkId.IsNull)
				{
					var ids = new ObjectIdCollection();
					ids.Add(blkId);
					var mapping = new IdMapping();
					db.WblockCloneObjects(ids, curDb.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);
				}
			}
		}

 

BTW, in your JIG's Update() method, you do not have to change BlockRefernece's Position and then each AttributeReference's position with some many lines of code. You simply create a Displacement Matrix3d and use it to transform the BlockReference, this would move the block and its attributes together:

 

var mt=Matrix3d.Displacement([prevPoint].GetVectorTo([currentPoint]);

br.TrnsformeBy(mt);

 

 

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 5 of 5

kmkxperia
Advocate
Advocate

Checked Bedit and the block is shown,
but error still persists, You mentioned in point #3  If the block is annotative, you need to associtate approperiate ObjectContext (AnnotationScale) to this block reference; do I need to do those?

0 Likes