Author Topic: Extract Title Block Attributes  (Read 2790 times)

0 Members and 1 Guest are viewing this topic.

cadpro

  • Guest
Extract Title Block Attributes
« on: November 03, 2011, 10:47:18 AM »
Hi,

How do I extract one of the title block's attribute from a drawing with many layouts? That is, even if there are many layouts for a drawing, I only need info from any one of the title blocks, probably the first layout. Can this be achieved please?

Thanks

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Extract Title Block Attributes
« Reply #1 on: November 03, 2011, 11:07:27 AM »
Just go to straight to the definition(BlockTableRecord) and use BlockTableRecord.GetBlockReferenceIds() to grab a reference and get the attribute.

cadpro

  • Guest
Re: Extract Title Block Attributes
« Reply #2 on: November 03, 2011, 03:59:29 PM »
Thanks Jeff! That did the job.

Thanks

cadpro

  • Guest
Re: Extract Title Block Attributes
« Reply #3 on: November 03, 2011, 05:47:02 PM »
Sorry Jeff. I couldn't get it to work. I could only get the tags. The TextStrings return empty. This is my code.


Code: [Select]
public void GetTitleAtts()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt["A1"], OpenMode.ForRead);
 
                StringCollection colNames = new StringCollection();

                foreach (ObjectId adId in btr)
                {
                    DBObject adObj = tr.GetObject(adId, OpenMode.ForRead);

                    AttributeDefinition ad = adObj as AttributeDefinition;
 
                    if (ad != null)
                    {
                        colNames.Add(ad.Tag);
                    }
                }
                tr.Commit();
            }
        }

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Extract Title Block Attributes
« Reply #4 on: November 03, 2011, 05:53:54 PM »
This was not thought out well and thrown together quickly but,
 I mainly converted this to VB to see how indexer methods were done and if atts[""]; instead of atts.get_Item("");  from C# could be used.
Code: [Select]
        <CommandMethod("TitleBlock")> _
        Public Sub TitleBlock()
 
            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor
 
            Using trx As Transaction = db.TransactionManager.StartTransaction()
 
                Dim bt As BlockTable = trx.GetObject(db.BlockTableId, OpenMode.ForRead)
                Dim block As BlockTableRecord = trx.GetObject(bt("TitleBlock"), OpenMode.ForRead)
 
                Dim atts As New AttributedTextInfo(block.GetBlockReferenceIds(True, False).Item(0))
                Application.ShowAlertDialog(atts("TagValue"))
 
                trx.Commit()
            End Using
        End Sub

 

Had to use <DefaultMember("Item")>  attribute & Default Public ReadOnly Property

Code: [Select]
Imports System.Reflection
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Runtime
 
<DefaultMember("Item")> _
Public Class AttributedTextInfo
    Implements IEnumerable
 
    Private _objectId As ObjectId
    Private _attributes As Dictionary(Of String, String)
 
    Public Sub New(brefId As ObjectId)
        _objectId = brefId
        _attributes = New Dictionary(Of String, String)()
        getAttributes()
    End Sub
 
    Private Sub getAttributes()

        Using trx As Transaction = _objectId.Database.TransactionManager.StartTransaction()
            Dim blockRef As BlockReference = trx.GetObject(_objectId, OpenMode.ForRead)

            If blockRef IsNot Nothing Then

                For Each id As ObjectId In blockRef.AttributeCollection
                    If id.ObjectClass = RXClass.GetClass(GetType(AttributeReference)) Then
                        Dim attRef As AttributeReference = trx.GetObject(id, OpenMode.ForRead)
                        _attributes.Add(attRef.Tag, attRef.TextString)
                    End If
                Next
            End If
            trx.Commit()
        End Using
    End Sub
 
    Default Public ReadOnly Property Item(tag As String) As String
        Get
            Return _attributes(tag.ToUpper())
        End Get
    End Property
 
    Public Function GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
        Return _attributes.GetEnumerator()
    End Function

End Class

 
 
 

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Extract Title Block Attributes
« Reply #5 on: November 03, 2011, 06:05:24 PM »
Sorry Jeff. I couldn't get it to work. I could only get the tags. The TextStrings return empty. This is my code.
That is because you are looking in the definition and the textString is equal to what was entered for default(TextString = Default)
Just grab the first reference if is does not matter and use AttributeReference
 
Code: [Select]
         [CommandMethod("GetTitleAtts")]
        public void GetTitleAtts()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt["A1"], OpenMode.ForRead);
                StringCollection colNames = new StringCollection();
                BlockReference bref = (BlockReference)tr.GetObject(btr.GetBlockReferenceIds(true, false)[0], OpenMode.ForRead);
                foreach (ObjectId adId in bref.AttributeCollection)
                {
                    DBObject adObj = tr.GetObject(adId, OpenMode.ForRead);
                    AttributeReference ad = adObj as AttributeReference;
                    if (ad != null)
                    {
                        colNames.Add(ad.TextString);
                    }
                }
                tr.Commit();
                foreach (string s in colNames)
                {
                    Application.ShowAlertDialog(s);
                }
            }
        }


 

kaefer

  • Guest
Re: Extract Title Block Attributes
« Reply #6 on: November 04, 2011, 03:12:13 AM »
Code: [Select]
<DefaultMember("Item")> _
Public Class AttributedTextInfo
    Implements IEnumerable

Hi Jeff,

that's all very well what you're demonstrating there. Just let me remark that from a software design perspective it's a not so great idea to implement IEnumerable with an indexer, because IEnumerable is both lazy and potentially infinite. It makes sense only as far as it's a light-weight interface compared to ICollection or IDictionary, and since you're using a Dictionary under the hood, then why don't you go the whole way?

The standard approach when working with sequences would be using FirstOrDefault<TSource> (Seq.tryFind in F#) to return the first element that satisfies a given predicate, or default(TSource) when none is found.

Cheers, Thorsten

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Extract Title Block Attributes
« Reply #7 on: November 04, 2011, 04:26:49 AM »
Hi,

I had to build a similar class, here's the way I did it (I only add an Indexor and a Constructor from ObjectId I didn't needed when I wrote this).
I needed a class implementing IEqualityComparer too, so that the Linq GroupBy() extension method can be used with a 'BlockAttribute' collection.

Code: [Select]
    public class BlockAttribute
    {
        private string _name;
        private Dictionary<string, string> _atts;

        public string Name
        {
            get { return _name; }
        }

        public Dictionary<string, string> Attributes
        {
            get { return _atts; }
        }

        public string this[string key]
        {
            get { return _atts[key.ToUpper()]; }
        }

        public BlockAttribute(BlockReference br)
        {
            SetProperties(br);
        }

        public BlockAttribute(ObjectId id)
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            using (Transaction tr = doc.TransactionManager.StartTransaction())
            {
                SetProperties(tr.GetObject(id, OpenMode.ForRead) as BlockReference);
            }
        }

        new public string ToString()
        {
            if (_atts != null && _atts.Count > 0)
                return string.Format("{0}: {1}",
                    _name,
                    _atts.Select(a => string.Format("{0}={1}", a.Key, a.Value))
                        .Aggregate((a, b) => string.Format("{0}; {1}", a, b)));
            return _name;
        }

        private void SetProperties(BlockReference br)
        {
            if (br == null) return;
            _name = br.IsDynamicBlock ?
                ((BlockTableRecord)br.DynamicBlockTableRecord.GetObject(OpenMode.ForRead)).Name :
                br.Name;
            _atts = new Dictionary<string, string>();
            foreach (ObjectId id in br.AttributeCollection)
            {
                AttributeReference att = (AttributeReference)id.GetObject(OpenMode.ForRead);
                _atts.Add(att.Tag.ToUpper(), att.TextString);
            }
        }
    }

    public class BlockAttributeEqualityComparer : IEqualityComparer<BlockAttribute>
    {
        public bool Equals(BlockAttribute x, BlockAttribute y)
        {
            if (!x.Name.Equals(y.Name, StringComparison.CurrentCultureIgnoreCase)) return false;
            foreach (KeyValuePair<string, string> att in x.Attributes)
            {
                if (!y.Attributes.ContainsKey(att.Key)) return false;
                if (!y.Attributes[att.Key].Equals(att.Value)) return false;
            }
            return true;
        }

        public int GetHashCode(BlockAttribute obj)
        {
            return base.GetHashCode();
        }
    }
« Last Edit: November 04, 2011, 07:50:53 AM by gile »
Speaking English as a French Frog

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Extract Title Block Attributes
« Reply #8 on: November 04, 2011, 12:10:41 PM »
Code: [Select]
<DefaultMember("Item")> _
Public Class AttributedTextInfo
    Implements IEnumerable

Hi Jeff,

that's all very well what you're demonstrating there. Just let me remark that from a software design perspective it's a not so great idea to implement IEnumerable with an indexer, because IEnumerable is both lazy and potentially infinite. It makes sense only as far as it's a light-weight interface compared to ICollection or IDictionary, and since you're using a Dictionary under the hood, then why don't you go the whole way?

The standard approach when working with sequences would be using FirstOrDefault<TSource> (Seq.tryFind in F#) to return the first element that satisfies a given predicate, or default(TSource) when none is found.

Cheers, Thorsten
Thanks for pointing that out.