Kean Walmsley

July 2009

Sun Mon Tue Wed Thu Fri Sat
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Twitter Updates

    follow me on Twitter



    « COM vs. .NET in AutoCAD | Main | Using the pickfirst selection from an AutoCAD .NET application »

    September 15, 2006

    Getting AutoCAD block attributes from a .NET application

    It's been a hectic week, between one thing and another, and I don’t expect it to get better anytime soon: apart from anything else, my wife is due to give birth any day to our second child. We're both excited - and admittedly a little anxious - about it, and our 2 year-old seems to be feeding of that, which means none of us have ended getting much sleep of late. All good preparation, I suppose. :-)

    So I decided the path of least resistance for getting a blog entry out today was to look through some of the responses DevTech have sent out to ADN members recently, to find something that might be of interest to a wider audience. A lot of what we do ends up being very specific to individual situations, but we also get requests for code samples that prove to be of general interest (these latter topics are generally turned into DevNotes (technical solutions) and get posted to the ADN website). Over the busy months ahead I'm sure I'll end up feeding many of these through this blog.

    One response that caught my eye was this helpful little code sample, written by Varadan (a.k.a. Krishnan Varadarajan), a member of the DevTech team in India.

    It asks the user to select block references, and then goes through them, looking for any contained attributes, which it then dumps to the AutoCAD console:

    using Autodesk.AutoCAD;

    using Autodesk.AutoCAD.Runtime;

    using Autodesk.AutoCAD.ApplicationServices;

    using Autodesk.AutoCAD.DatabaseServices;

    using Autodesk.AutoCAD.EditorInput;


    namespace MyApplication

    {

      public class DumpAttributes

      {

        [CommandMethod("LISTATT")]

        public void ListAttributes()

        {

          Editor ed =

            Application.DocumentManager.MdiActiveDocument.Editor;

          Database db =

            HostApplicationServices.WorkingDatabase;

          Transaction tr =

            db.TransactionManager.StartTransaction();


          // Start the transaction

          try

          {

            // Build a filter list so that only

            // block references are selected

            TypedValue[] filList = new TypedValue[1] {

              new TypedValue((int)DxfCode.Start, "INSERT")

            };

            SelectionFilter filter =

              new SelectionFilter(filList);

            PromptSelectionOptions opts =

              new PromptSelectionOptions();

            opts.MessageForAdding = "Select block references: ";

            PromptSelectionResult res =

              ed.GetSelection(opts, filter);


            // Do nothing if selection is unsuccessful

            if (res.Status != PromptStatus.OK)

              return;


            SelectionSet selSet = res.Value;

            ObjectId[] idArray = selSet.GetObjectIds();

            foreach (ObjectId blkId in idArray)

            {

              BlockReference blkRef =

                (BlockReference)tr.GetObject(blkId,

                  OpenMode.ForRead);

              BlockTableRecord btr =

                (BlockTableRecord)tr.GetObject(

                  blkRef.BlockTableRecord,

                  OpenMode.ForRead

                );

              ed.WriteMessage(

                "\nBlock: " + btr.Name

              );

              btr.Dispose();


              AttributeCollection attCol =

                blkRef.AttributeCollection;

              foreach (ObjectId attId in attCol)

              {

                AttributeReference attRef =

                  (AttributeReference)tr.GetObject(attId,

                    OpenMode.ForRead);


                string str =

                  ("\n  Attribute Tag: "

                    + attRef.Tag

                    + "\n    Attribute String: "

                    + attRef.TextString

                  );

                ed.WriteMessage(str);

              }

            }

            tr.Commit();

          }

          catch (Autodesk.AutoCAD.Runtime.Exception ex)

          {

            ed.WriteMessage(("Exception: " + ex.Message));

          }

          finally

          {

            tr.Dispose();

          }

        }

      }

    }

    Here's what happened when I ran it against the "Blocks and Tables - Imperial.dwg" sample drawing that ships with AutoCAD. On running the LISTATT command and selecting the title block on the right of the page, here's what was dumped out:

    Command: LISTATT


    Select block references: 1 found


    Select block references:


    Block: ARCHBDR-D

      Attribute Tag: NAME

        Attribute String: CORY B.

      Attribute Tag: NAME

        Attribute String: BOB M.

      Attribute Tag: DATE

        Attribute String:

      Attribute Tag: X"=X'-X"

        Attribute String: 1/4" =1'

      Attribute Tag: 0

        Attribute String: 1

      Attribute Tag: 0

        Attribute String: 1

      Attribute Tag: PROJECT

        Attribute String: ADDA

      Attribute Tag: TITLE

        Attribute String: FLOOR PLANS

      Attribute Tag: X

        Attribute String:

      Attribute Tag: X

        Attribute String:

      Attribute Tag: X

        Attribute String:

      Attribute Tag: X/XX/XX

        Attribute String:

      Attribute Tag: X/XX/XX

        Attribute String:

      Attribute Tag: X/XX/XX

        Attribute String:

      Attribute Tag: COMMENT

        Attribute String:

      Attribute Tag: COMMENT

        Attribute String:

      Attribute Tag: COMMENT

        Attribute String:

    Command:

    TrackBack

    TrackBack URL for this entry:
    http://www.typepad.com/services/trackback/6a00d83452464869e200d834b2ddc553ef

    Listed below are links to weblogs that reference Getting AutoCAD block attributes from a .NET application:

    Comments

    The try/finally in this example could be replaced with using (Transaction tr = db.TransactionManager.StartTransaction()). No difference in the generated IL code but more elegant and readable code.

    Hi Kean
    Thanks for your code, do you have a vbnet simmilar example?. Does it list raster block references attribuites?
    Thanks again

    Hi Raul,

    Sorry, no (and have my hands full on paternity leave right now).

    I generally use an automatic conversion tool such as the one mentioned in this previous entry:

    http://through-the-interface.typepad.com/through_the_interface/2006/08/some_cool_copyp.html

    This tool simply uses a website convertor, such as at:

    http://carlosag.net/Tools/CodeTranslator/Default.aspx

    This automatic conversion should get you a good deal of the way there...

    Regards,

    Kean

    BTW - I don't know what you mean by "raster block references"...

    Regards,

    Kean

    Thanks Kean for your tip and congrats for your newborn, I am a 2 little girls father (1 and 4 year old), so no hurry about technical stuff answers.
    I meant by "raster block references" the external references of the *.jpg or *.tif type. I was able to get the block id of files (.dwg ones) attached as external references, and then its attribuites like the file path.

    Well, hope you get some decent sleep and thanks again for your usefull blog, I have found some good code and history.

    Regards

    Thanks for the code. Can you help me on the code for doing the oposite ie edit block attributes given a known objectid for the block. I have seach for the code seem to be struggling especially with the open.mode.write. Also can with resources can i learn autocad vb.net.

    For Raul:

    Thanks! :-)

    Although conceptually similar to blocks, rasters are actually separate objects. You would need to change the above code to handle raster image and raster image definition objects:

    Autodesk.AutoCAD.DatabaseServices.RasterImage
    Autodesk.AutoCAD.DatabaseServices.RasterImageDef

    For Ed:

    Check out the resources listed on the AutoCAD Developer Center (http://www.autodesk.com/developautocad). I'd suggest posting your problematic code to the AutoCAD .NET Discussion Group (http://discussion.autodesk.com/forum.jspa?forumID=152).

    Regards,

    Kean

    Hi Kean;
    Thanks for the hint, I found a sample to get raster image attributes, but unfortunately I have not found any sample to set raster image attributes like the filename.
    Well, I hope you find the time, maybe one of those sleepless nights ;-) to show us the way in this blog.
    Thanks again

    Raul

    Hi Raul,

    Oh, you need to repath images? I haven't tried it, but you might try getting the RasterImageDef and setting the ActiveFilePath property.

    Regards,

    Kean

    Hi Kean,
    Thanks for your fast reply. I coud not find the RasterImageDef.ActiveFilePath property although I tried to set rasterImageDef.SourceFileName and rasterImageDef.ActiveFileName, both throw an exception.

    Thanks

    Raul

    Hi Raul,

    You probably don't have the object open for write... I'd suggest posting the code to the .NET Customization Discussion Group (http://discussion.autodesk.com/forum.jspa?forumID=152).

    Regards,

    Kean

    Hi Kean;
    I posted my code on the group you mentioned some days ago, see http://discussion.autodesk.com/thread.jspa?threadID=513346
    no answer yet, I changed all the read occurences of the object for OpenMode.ForWrite and still I do not see the ActiveFilePath property.

    Any help I will appreciate.

    Thanks

    Raul

    Hi Kean
    I replied to you at http://discussion.autodesk.com/thread.jspa?messageID=5368660

    I will appreciate if you review it.

    Thanks

    Raul

    Reply posted...

    Kean

    Hi Kean
    I did not have the opportunity to thanks for your last reply on http://discussion.autodesk.com/thread.jspa?threadID=513346
    It works fine now. I had to add a line imageAttributeDef.load since it did not load the raster reference by default. Also this repath operation works for the database of files that are not opened, I will investigate how to do it on open files.
    I noticed that AutoCAD 2007 adds a DWF external reference feature, I will also investigate how to repath those files.

    Again, thanks for your altruistic effort.

    Best wishes

    Raul

    Hi Raul,

    Great - I'm glad you got it working.

    Regards,

    Kean

    Hi Kean, hows parenthood suiting you?
    I have a question regarding 3rd party supplied blocks.
    Is there a way to modify the layers on an 3rd party issued block so it "works" in my drawings.
    I have hundreds to go through from dozens of suppliers and it just seems too much to open each and every block and send each part to the relevant layers in my drawings.
    Do you have any clues or ideas?
    Any help would be great.
    Thanks

    Hi Adie,

    Parenthood's treating me well, thanks (having 2 boys under 3 years old is a challenge, but luckily the youngest is still fairly easy to handle).

    I'd suggest checking out the CAD Standards implementation... aside from the STANDARDS command, take a look at LAYTRANS and also the Batch Standards Checker (a separate executable that can check across sets of files).

    You could always implement some custom code to go in and do this, but it's always worth seeing what standard functionality already exists.

    Regards,

    Kean

    Hi Kean,
    Sorry about the delay getting back to you,
    Thanks for the info, i will be trawling through looking at these tips.
    Thanks
    Adie

    Hi Kean

    I´m using Autocad 2006 and .Net and I want to know how can i get the Id of one document (dwg) throw .net, and if i make a copy of the dwg file (document) when i open the copy it has the same Id of the original....?

    Hi Cynthia,

    Which ID are you referring to? Do you mean the FingerprintGuid, or something else? A new FingerprintGuid does get assigned when you SaveAs, WBlock a new DWG, etc., but there's no way to control someone copying the file through Explorer etc.

    But then it sounds as though you want to maintain the same ID as the original (which FingerprintGuid mostly will not), so you may need to find another way to do this. Bear in mind that with this logic, nearly every DWG would end up referring to the template it was created from...

    Regards,

    Kean

    Hi Kean, sorry, in my las comment i wasn´t clear.
    I´m going to explain what i want to do.

    I start Autocad 2006, and creat a new document or dwg. I set a name like Test.dwg and save it. Then i draw some lines, I know each line has an unique identifier assigned (id) in the draw or document, so i get throw .net each id of each line and save it in a external database with name and others properties i add.
    I close Autocad, i start again and open Test.dwg, y choose each line i draw before, and the unique identifier assigned (id) of the lines maintance the same value, but i can get the unique identifier assigned (id) of the document. I belive that autocad must assign an id for each document ( when i said document i mean dwg file), so i need to get unique identifier assigned (id) to the document and then relate it with the lines drawed. This way I could save and relate a document wich all objets drawed in it throw each id´s and save it in an external database like Acces.

    I want to know too if i make a file copy of the Test.dwg, what happend with the unique identifier assigned (id) of the document or dwg. And if there's no way to control someone copying the file through Explorer etc. What happend with the Id´s of the lines and other objects drawed in it.

    Thanks so much, and i´m happy to have the oportunity to ask you.

    You can use the FingerprintGuid property the Database object, but this will remain the same across DWGs file copied via Explorer (for instance). AutoCAD is simply not involved in the copying of files at the OS-level.

    Most developers working on this type of problem would rely on the uniqueness of the file location on the system (using its path/URL/etc.).

    I assume you're using handles for object identifiers: these are maintained (and kept unique) for the drawing's lifetime, but are not guaranteed to be unique across DWGs.

    Hi Kean,
    I am back again, hopping you are doing fine with your kids.
    After working doing programmatic .net repath work with different external references objects using AutoCAD 2008 I got few comments you may find useful.

    DWG external reference object:
    It accepts any kind of path convention, local i.e. c:\myxdwgref.dwg and network \\myserver\myxdwgref.dwg, relative local and url i.e. .\..\ and ./../ types, absolute url i.e. http://myserver/myxdwgref.dwg

    Raster image external reference (jpg, bmp, etc):
    It behaves as above but it changes any relative url path reference by its local counterpart i.e.
    RasterImageDef.SourceFileName = "./myxdwgref.dwg"
    It accepts the value but it changes to ".\myxdwgref.dwg"

    DWF and DGN underlay references:
    Works as DWG references, but it do not process absolute url references, i.e. when using the following,
    DwfDefinition.SourFileName = "http://myserver/myDwfXref.dwf" it takes the value but it does not load the myDwfXref.dwf as rasters and dwg objects do. It seems that dwg and raster external references are downloaded automatically.

    Well I just wanted to expose what I think there are some inconsistencies on several external references objects. I hope Autodesk will come with some fix in future releases.

    I will appreciate any comments you may have

    Best wishes

    Raul

    Hi Raul,

    Thanks - we're all doing very well. :-)

    Some of the differences you've found are probably historical (the objects having been implemented at different times) and some are probably logical (the objects do behave differently).

    If there are product changes you would like to see happen, then I suggest submitting through ADN (if you're a member), or otherwise you can submit them via this form on the Autodesk website:

    http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=1109794

    Regards,

    Kean

    Verify your Comment

    Previewing your Comment

    This is only a preview. Your comment has not yet been posted.

    Working...
    Your comment could not be posted. Error type:
    Your comment has been posted. Post another comment

    The letters and numbers you entered did not match the image. Please try again.

    As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

    Having trouble reading this image? View an alternate.

    Working...

    Post a comment

    Feed & Share

    Search