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



    « Adding a new annotation scale in AutoCAD using .NET | Main | Adding a context menu to AutoCAD objects using .NET »

    April 27, 2007

    TrackBack

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

    Listed below are links to weblogs that reference Making AutoCAD objects annotative using .NET:

    Comments

    Kean, interesting!
    I see a new type of context: object context. Can you describe it?

    Hi Nikolay,

    All I have is what's in the ObjectARX Reference, describing the AcDbObjectContext class:

    >>>
    Abstract base class for representing a particular context which may affect the properties and/or behavior of one or more types of objects.Classes that are derived from this base class are used to represent a particular type of context such as annotation scale.
    <<<

    Regards,

    Kean

    Hi Kean, thank you for this code.
    Now I tried your code but it didn't work for BlockReferences, you get an "eIvalidInput" error when you try it. It would be nice if you could tell us how to do it for BlockReferences.
    Also if you want to see the result for dimensions you have to do something more. I don't know if it is the right way, but I inserted the line "obj.UpgradeOpen()" after adding the context.

    Hi Roland,

    OK - my mistake. I should not allow selection of BlockReferences in the above code (I'll remove it). Here's what's said in the online help:

    >>>
    Annotative block definitions create annotative block references. Annotative block references and attributes initially support the current annotation scale at the time they are inserted. You should insert annotative block references with a unit factor of 1.

    You cannot change the Annotative property of individual block references.
    <<<

    Regards,

    Kean

    I removed the lines allowing selection of BlockReference and AttributeReference objects from the above code.

    About the dimension issue - it seems to work fine for me (I just used DIM VERT to create a dimension, used ATS to make it annotative, and I see the glyph when I hover over it and I get the appropriate annotation properties in the properties palette).

    Any hints on what do I need to do to reproduce the problem?

    Regards,

    Kean

    Kean, I think that table object does not support annotative scale too.

    Hi Kean,
    thank you again. If I want to use a block with different scales, what do I have to do then?
    I will have a look at the dimension problem on monday when i'm back to work.

    Hi Roland,

    You need to create annotative block definitions. This is from the online help:

    >>>
    To create an annotative block definition

    1. Click Draw menu -> Block -> Make.... or At the command prompt, enter block.
    2. In the Block Definition dialog box, enter a block name in the Name box.
    3. Under Objects, select Convert to Block.
    4. Click Select Objects.
    5. Under Behavior, select Annotative.
    6. Use your pointing device to select objects to be included in block definition. Press ENTER to complete object selection.
    7. In the Block Definition dialog box, under Base Point, specify the block insertion point.
    8. Click OK.
    <<<

    Then when you insert the block, it will pivk up the current annotation scale:

    >>>
    Annotative block definitions create annotative block references. Annotative block references and attributes initially support the current annotation scale at the time they are inserted. You should insert annotative block references with a unit factor of 1.
    <<<

    Regards,

    Kean

    Hi Nikolay,

    I think you're right... it was listed as annotative in a version of the docs I looked at, but I don't see it as being annotative. I'll remove the option to select a table from the code.

    Thanks,

    Kean

    Hi Kean,
    I know how to make an annotative block ;-) I'm testing spago since the alpha release.
    The problem i have is to insert an external drawing as a block with .NET (and VBA, also in VBA it inserts an annotative DWG as non annotative).
    1. How do I now if the drawing is annotative or not?
    2. How do I insert the drawing as a block and make it annotative?
    3. And if i insert the annotative block, is it possible to insert it for more annotative scales (eg. inserting the block for annotation scale "1:100" and "1:50")?

    Now the problem with the dimensions. It doesn' matter how I do it, I have to do it like this to see the annotation-scales for a dimension.

    if (oc != null)
    {
    ObjectContexts.AddContext(obj, oc);
    }
    obj.UpgradeOpen();

    Regards
    Roland

    Hi Roland,

    I'm afraid I'm no mind reader - your previous descriptions were missing a lot of information. Even now I have no idea how you are inserting the external DWG programmatically.

    Also, this is going off-topic, in that it's only tangentially related to the blog post. I'd suggest submitting the question - with code and a DWG - to my team via the ADN website or posting it on the Discussion Groups.

    As for the dimension problem - on my system I don't need to make that change to my code - the object is already open for write, and it works just fine. Have you modified other parts of the code?

    Regards,

    Kean

    Hi Kean,
    thank you for your response, I will post my annotative block problems in the discussion group.

    As for the dimension problem I didn't change your code (just deleted the lines for adding 1:2 and 1:10), but it is no problem, it works when I add the line like in my previous post.

    Regards
    Roland

    Hi Kean,
    I tested a little bit with inserting an annotative block into the drawing and it didn't work as the help said. It didn't insert the block at the current annotative scale, just the attributes where inserted at the current annotation-scale.
    Therefore i tried to add the context and it did work.
    Here is the code for inserting an annotative block which is working for me if someone want to know.


    using Autodesk.AutoCAD.ApplicationServices;
    using Autodesk.AutoCAD.DatabaseServices;
    using Autodesk.AutoCAD.EditorInput;
    using Autodesk.AutoCAD.Runtime;
    using Autodesk.AutoCAD.Geometry;
    using Autodesk.AutoCAD.Internal;

    [assembly: CommandClass(typeof(RSNNAcadApp.Test.InsertBlock))]
    namespace RSNNAcadApp.Test
    {
    public class InsertBlock
    {
    //Inserts a blockreference at Point 0,0,0
    [CommandMethod("InsertTest")]
    static public void InsertBlockTest()
    {
    ObjectId tmpBlockId;

    Document doc = Application.DocumentManager.MdiActiveDocument;
    Database db = doc.Database;
    Editor ed = doc.Editor;
    Transaction tr = doc.TransactionManager.StartTransaction();
    try
    {
    using (tr)
    {
    //Get Blockname and Id
    PromptStringOptions BlockNameOption = new PromptStringOptions("Blockname:");
    BlockNameOption.AllowSpaces = false;
    PromptResult BlockNameResult = ed.GetString(BlockNameOption);
    BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead, false);

    if (BlockNameResult.Status == PromptStatus.Cancel)
    return;

    else if (BlockNameResult.Status == PromptStatus.OK)
    {
    string tmpBlockName = BlockNameResult.StringResult;

    tmpBlockId = bt[tmpBlockName];

    BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);

    Point3d ObjPunkt = Point3d.Origin;
    BlockReference BlockRef = new BlockReference(ObjPunkt, tmpBlockId);
    ObjectId BlObj = btr.AppendEntity(BlockRef);
    tr.AddNewlyCreatedDBObject(BlockRef, true);

    BlockTableRecord btAttRec = (BlockTableRecord)tr.GetObject(tmpBlockId, OpenMode.ForRead);

    ed.WriteMessage(string.Format("Block {0} annotative!", btAttRec.Annotative == AnnotativeStates.True ? "is" : "is not"));

    //Attach Current Annotation-Scale.
    //If you don't add the content the block and the following attribute will not inserted correct.
    ObjectContextManager ocm = db.ObjectContextManager;
    ObjectContextCollection occ = ocm.GetContextCollection("ACDB_ANNOTATIONSCALES");

    DBObject obj = tr.GetObject(BlObj, OpenMode.ForRead);
    if (obj != null)
    {
    //ObjectContexts.AddContext(obj, occ.GetContext("1:1"));
    ObjectContexts.AddContext(obj, occ.CurrentContext);
    }


    //Add the attributes
    foreach (ObjectId idAtt in btAttRec)
    {
    Entity ent = (Entity)tr.GetObject(idAtt, OpenMode.ForRead);
    if (ent is AttributeDefinition)
    {
    AttributeDefinition attDef = (AttributeDefinition)ent;
    AttributeReference attRef = new AttributeReference();
    attRef.SetAttributeFromBlock(attDef, BlockRef.BlockTransform);
    ObjectId AttObj = BlockRef.AttributeCollection.AppendAttribute(attRef);
    tr.AddNewlyCreatedDBObject(attRef, true);
    /* //You do not need to insert the CurrentContext to AttributeReference because it is inserted with it.
    DBObject aobj = tr.GetObject(AttObj, OpenMode.ForRead);
    if (aobj != null)
    {
    //ObjectContexts.AddContext(aobj, occ.GetContext("1:1"));
    ObjectContexts.AddContext(aobj, occ.CurrentContext);
    }
    */
    }
    }
    }


    tr.Commit();
    }
    }
    catch (System.Exception ex)
    {
    ed.WriteMessage(ex.ToString());
    }
    finally
    {
    tr.Dispose();
    }

    }

    }
    }


    Regards
    Roland

    Hi Roland,

    OK, *now* I see what you wanted to do... :-)

    The help refers to the INSERT command, whereas you wanted to programmatically insert an annotative block. Yes - I can see why you'd have to do what you've done.

    Thanks for sharing the code!

    Kean

    I know it is an old post, but I want to delete all annotation-scales which are not used. Is it possible to see if an AnnotationScale is used or not by any objects? The following code deletes all scales, it doesn't matter if they are used or not except the current annoscale and 1:1.

    [CommandMethod("ASDELETE")]
    public void DeleteAll()
    {
    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)
    {
    foreach (ObjectContext oc in occ)
    {

    if (oc is AnnotationScale)
    {
    try
    {
    AnnotationScale scale = (AnnotationScale)oc;
    if (scale.Name != "1:1")
    if (oc.Name != occ.CurrentContext.Name)
    {
    ed.WriteMessage(string.Format("\n{0} wird gelöscht", scale.Name));
    occ.RemoveContext(scale.Name);
    }
    }
    catch (System.Exception e)
    {
    ed.WriteMessage(e.ToString());
    }
    }

    }

    }
    }
    }
    catch (System.Exception ex)
    {
    ed.WriteMessage(ex.ToString());
    }
    }

    Hi Roland,

    I don't know how you'd do this: for something like a style you'd get the object ID and use the "purge" function on the database to check the references to it, but I don't know whether this would work for Annotation Scales (assuming you could get the object ID of the dictionary entry).

    Regards,

    Kean

    Thank you, Kean,
    I will have a look at it. But I also hope that in the next release it is possible to purge all the unused annotation-scales with AutoCAD.

    Regards
    Roland

    Hi Kean
    I try to add annotations to MTEXT objects with the COM interface and have no luck so far. I know they get stored somewhere inside AcadDictionary. If I parse an entity object with added annotation scales I get the same amount of entries of ObjectName "AcDbMTextObjectContextData" things. But there are no interfaces to read them out or to create such things. Any ideas?

    The code I used to get the dictionary items looks as below:

    AcadEntity entity = ...

    if ( entity.HasExtensionDictionary )
    {
    AcadDictionary dict = entity.GetExtensionDictionary( );
    DumpAcadDictionary( dict, "" );
    }

    private void DumpAcadDictionary( AcadDictionary dict, string offset )
    {
    for ( int i = 0; i < dict.Count; i++ )
    {
    AcadObject obj = dict.Item( i );

    Console.WriteLine( "{0}Item: {1} {2}", offset, i, obj.ObjectName );

    if ( obj.ObjectName == "AcDbDictionary" )
    {
    DumpAcadDictionary( ( AcadDictionary ) obj, offset + " " );
    }
    if ( obj.HasExtensionDictionary )
    {
    AcadDictionary subDict = obj.GetExtensionDictionary( );
    DumpAcadDictionary( subDict, offset + " " );
    }
    }
    if ( dict.HasExtensionDictionary )
    {
    AcadDictionary subDict = dict.GetExtensionDictionary( );
    DumpAcadDictionary( subDict, offset + " " );
    }
    }

    Hi Armin,

    I don't think you can rely on adding Annotation Scales manually into the extension dictionary: I'd suggest using the technique I've shown with the managed interface, instead. You mention COM, but seem to be coding in C#, so that shouldn't be a big issue (unless I'm missing something).

    Regards,

    Kean

    Newbie question: How do you compile the above code for use in AutoCAD?

    Hi David,

    I'd suggest checking out this introductory post.

    Regards,

    Kean

    Hi Kean,

    i was asked to search for 5 examples of elevation, 3D animation and step by step procedure of gear making.. All of this were made using autocad.. do you have any of these? this is my project and i have seen already 3 samples of elevation and 3D animation but i still need 2 more each and the step by step gear making using autocad.. it's hard to find one and my time is limited only in searching.. can you help me?

    Hi Zyra,

    Are you looking for code samples or content samples? If content, you might try the Content Search tool on the Autodesk Labs website.

    If content then I'd suggest posting something to the appropriate discussion group, depending on the technology you're interested in.

    Regards,

    Kean

    Hi there Kean,
    I got Visual Studio .NET 2008 that has a C# compiler.
    I loaded your above code (for "Making AutoCAD objects annotative using .NET"), I referenced the ACDBMGD.DLL and ACMGD.DLL from AutoCAD 2008, and the .Internal in "using Autodesk.AutoCAD.Internal;" statement is missing. As such I was not able to compile the code. Can you please tell me what to do in order to compile your code?
    Thanks in advance for any help.
    Have a nice day and happy 4th of July.
    Regards,
    Stefan

    There should also be an assembly in the AutoCAD folder called acmgdinternal.dll. Be warned: the APIs exposed by this assembly are not officially supported.

    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