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



    « Linking Circles, Part 2: Getting persistent | Main | Linking Circles, Part 4: Adding 3D »

    December 01, 2006

    Linking Circles, Part 3: Automatic linking on circle creation

    In the previous posts we looked at some code to link AutoCAD entities via .NET events, and how to persist the link data in the drawing file.

    This post extends the previous code to automatically link circles into the head of the chain, as circles are drawn by the user. The changes to the project are relatively modest compared to last time. Once again, the source is both available for download and listed below with changed line-numbers in red.

    Some notes on the changes:

    First we declare some new variables in our command class: a boolean (m_autolink - line 463) which tells us whether automatic linking is "on" or "off", and an ObjectId (m_lastEntity - line 464), which we will use to find the most recently created, linked object. We could have made this a setting in our LinkedObjectManager class, should we have wanted to make this a persistent setting, for instance, but for simplicity's sake we'll leave it in the command class for now.

    We have to register (lines 475-476) and unregister (lines 497-498) a handler for another event - OnObjectAppended(). It's via this callback that we're informed that a new object has been added to the drawing.

    Next we define our AUTOLINK command (lines 547-563). This simply toggles the m_autolink setting between true and false (or on and off). We might have chosen to display the current setting and ask whether the user wanted to change it to on or off, but frankly that seemed like overkill. If you don't like what you've set it to, you can just call the command again. :-)

    A minor change was needed to OnObjectErased(), to set the value of m_lastEntity to Null, should the entity be erased. This also gets caught by a change in the code right at the end, but it's cleaner coding to make the behaviour right here, also.

    Next we have the guts of our implementation (such that it is), which is the OnObjectAppended() callback definition (lines 612-636). Here we check whether the object added is a circle, and if so, we either link it to the last one added (stored in m_lastEntity), or - if the value of m_lastEntity is Null, for whatever reason - then we simply make it the next object to be linked in, and leave it at that.

    And finally there's a minor change I added to more elegantly support UNDO (which also applies to the code in the first two posts, although I won't go and update them now). Because we're not persisting the state of our links synchronously in the drawing database, they don't automatically participate in the undo mechanism (e.g. if the user uses the UNDO command, we would have to do a little extra work to recreate the correct "last object to link to" settings). Rather than implement the equivalent of our own undo mechanism, I decided not to bother, and simply made sure that when a link is to an erased object, we simply give up (without any error message). This shouldn't happen very often - as we have our OnObjectErased() callback, but you never know. It does mean that the "bad" links might continue to exist in our LinkedObjectManager, they just won't work. The next time the data is saved and reloaded, though, these links effectively get purged. To really make this a production-ready app, I feel a little more attention is needed in this area... that said, the foundation is certainly there for you to work from (just please test thoroughly for your specific situation, of course).

    Now for the C# code:

        1 using System;

        2 using System.Collections;

        3 using System.Collections.Generic;

        4 using Autodesk.AutoCAD.Runtime;

        5 using Autodesk.AutoCAD.ApplicationServices;

        6 using Autodesk.AutoCAD.DatabaseServices;

        7 using Autodesk.AutoCAD.EditorInput;

        8 using Autodesk.AutoCAD.Geometry;

        9

       10 [assembly:

       11   CommandClass(

       12     typeof(

       13       AsdkLinkingLibrary.LinkingCommands

       14     )

       15   )

       16 ]

       17

       18 namespace AsdkLinkingLibrary

       19 {

       20   /// <summary>

       21   /// Utility class to manage and save links

       22   /// between objects

       23   /// </summary>

       24   public class LinkedObjectManager

       25   {

       26     const string kCompanyDict =

       27       "AsdkLinks";

       28     const string kApplicationDict =

       29       "AsdkLinkedObjects";

       30     const string kXrecPrefix =

       31       "LINKXREC";

       32

       33     Dictionary<ObjectId, ObjectIdCollection> m_dict;

       34

       35     // Constructor

       36     public LinkedObjectManager()

       37     {

       38       m_dict =

       39         new Dictionary<ObjectId,ObjectIdCollection>();

       40     }

       41

       42     // Create a bi-directional link between two objects

       43     public void LinkObjects(ObjectId from, ObjectId to)

       44     {

       45       CreateLink(from, to);

       46       CreateLink(to, from);

       47     }

       48

       49     // Helper function to create a one-way

       50     // link between objects

       51     private void CreateLink(ObjectId from, ObjectId to)

       52     {

       53       ObjectIdCollection existingList;

       54       if (m_dict.TryGetValue(from, out existingList))

       55       {

       56         if (!existingList.Contains(to))

       57         {

       58           existingList.Add(to);

       59           m_dict.Remove(from);

       60           m_dict.Add(from, existingList);

       61         }

       62       }

       63       else

       64       {

       65         ObjectIdCollection newList =

       66           new ObjectIdCollection();

       67         newList.Add(to);

       68         m_dict.Add(from, newList);

       69       }

       70     }

       71

       72     // Remove bi-directional links from an object

       73     public void RemoveLinks(ObjectId from)

       74     {

       75       ObjectIdCollection existingList;

       76       if (m_dict.TryGetValue(from, out existingList))

       77       {

       78         m_dict.Remove(from);

       79         foreach (ObjectId id in existingList)

       80         {

       81           RemoveFromList(id, from);

       82         }

       83       }

       84     }

       85

       86     // Helper function to remove an object reference

       87     // from a list (assumes the overall list should

       88     // remain)

       89     private void RemoveFromList(

       90       ObjectId key,

       91       ObjectId toremove

       92     )

       93     {

       94       ObjectIdCollection existingList;

       95       if (m_dict.TryGetValue(key, out existingList))

       96       {

       97         if (existingList.Contains(toremove))

       98         {

       99           existingList.Remove(toremove);

      100           m_dict.Remove(key);

      101           m_dict.Add(key, existingList);

      102         }

      103       }

      104     }

      105

      106     // Return the list of objects linked to

      107     // the one passed in

      108     public ObjectIdCollection GetLinkedObjects(

      109       ObjectId from

      110     )

      111     {

      112       ObjectIdCollection existingList;

      113       m_dict.TryGetValue(from, out existingList);

      114       return existingList;

      115     }

      116

      117     // Check whether the dictionary contains

      118     // a particular key

      119     public bool Contains(ObjectId key)

      120     {

      121       return m_dict.ContainsKey(key);

      122     }

      123

      124     // Save the link information to a special

      125     // dictionary in the database

      126     public void SaveToDatabase(Database db)

      127     {

      128       Transaction tr =

      129         db.TransactionManager.StartTransaction();

      130       using (tr)

      131       {

      132         ObjectId dictId =

      133           GetLinkDictionaryId(db, true);

      134         DBDictionary dict =

      135           (DBDictionary)tr.GetObject(

      136             dictId,

      137             OpenMode.ForWrite

      138           );

      139         int xrecCount = 0;

      140

      141         foreach (

      142           KeyValuePair<ObjectId, ObjectIdCollection> kv

      143           in m_dict

      144         )

      145         {

      146           // Prepare the result buffer with our data

      147           ResultBuffer rb =

      148             new ResultBuffer(

      149               new TypedValue(

      150                 (int)DxfCode.SoftPointerId,

      151                 kv.Key

      152               )

      153             );

      154           int i = 1;

      155           foreach (ObjectId id in kv.Value)

      156           {

      157             rb.Add(

      158               new TypedValue(

      159                 (int)DxfCode.SoftPointerId + i,

      160                 id

      161               )

      162             );

      163             i++;

      164           }

      165

      166           // Update or create an xrecord to store the data

      167           Xrecord xrec;

      168           bool newXrec = false;

      169           if (dict.Contains(

      170                 kXrecPrefix + xrecCount.ToString()

      171               )

      172           )

      173           {

      174             // Open the existing object

      175             DBObject obj =

      176               tr.GetObject(

      177                 dict.GetAt(

      178                   kXrecPrefix + xrecCount.ToString()

      179                 ),

      180                 OpenMode.ForWrite

      181               );

      182             // Check whether it's an xrecord

      183             xrec = obj as Xrecord;

      184             if (xrec == null)

      185             {

      186               // Should never happen

      187               // We only store xrecords in this dict

      188               obj.Erase();

      189               xrec = new Xrecord();

      190               newXrec = true;

      191             }

      192           }

      193           // No object existed - create a new one

      194           else

      195           {

      196             xrec = new Xrecord();

      197             newXrec = true;

      198           }

      199           xrec.XlateReferences = true;

      200           xrec.Data = (ResultBuffer)rb;

      201           if (newXrec)

      202           {

      203             dict.SetAt(

      204               kXrecPrefix + xrecCount.ToString(),

      205               xrec

      206             );

      207             tr.AddNewlyCreatedDBObject(xrec, true);

      208           }

      209           xrecCount++;

      210         }

      211

      212         // Now erase the left-over xrecords

      213         bool finished = false;

      214         do

      215         {

      216           if (dict.Contains(

      217                 kXrecPrefix + xrecCount.ToString()

      218               )

      219           )

      220           {

      221             DBObject obj =

      222               tr.GetObject(

      223                 dict.GetAt(

      224                   kXrecPrefix + xrecCount.ToString()

      225                 ),

      226                 OpenMode.ForWrite

      227               );

      228             obj.Erase();

      229           }

      230           else

      231           {

      232             finished = true;

      233           }

      234           xrecCount++;

      235         } while (!finished);

      236         tr.Commit();

      237       }

      238     }

      239

      240     // Load the link information from a special

      241     // dictionary in the database

      242     public void LoadFromDatabase(Database db)

      243     {

      244       Document doc =

      245         Application.DocumentManager.MdiActiveDocument;

      246       Editor ed = doc.Editor;

      247       Transaction tr =

      248         db.TransactionManager.StartTransaction();

      249       using (tr)

      250       {

      251         // Try to find the link dictionary, but

      252         // do not create it if one isn't there

      253         ObjectId dictId =

      254           GetLinkDictionaryId(db, false);

      255         if (dictId.IsNull)

      256         {

      257           ed.WriteMessage(

      258             "\nCould not find link dictionary."

      259           );

      260           return;

      261         }

      262

      263         // By this stage we can assume the dictionary exists

      264         DBDictionary dict =

      265           (DBDictionary)tr.GetObject(

      266             dictId, OpenMode.ForRead

      267           );

      268         int xrecCount = 0;

      269         bool done = false;

      270

      271         // Loop, reading the xrecords one-by-one

      272         while (!done)

      273         {

      274           if (dict.Contains(

      275                 kXrecPrefix + xrecCount.ToString()

      276             )

      277           )

      278           {

      279             ObjectId recId =

      280               dict.GetAt(

      281                 kXrecPrefix + xrecCount.ToString()

      282               );

      283             DBObject obj =

      284               tr.GetObject(recId, OpenMode.ForRead);

      285             Xrecord xrec = obj as Xrecord;

      286             if (xrec == null)

      287             {

      288               ed.WriteMessage(

      289                 "\nDictionary contains non-xrecords."

      290               );

      291               return;

      292             }

      293             int i = 0;

      294             ObjectId from = new ObjectId();

      295             ObjectIdCollection to =

      296               new ObjectIdCollection();

      297             foreach (TypedValue val in xrec.Data)

      298             {

      299               if (i == 0)

      300                 from = (ObjectId)val.Value;

      301               else

      302               {

      303                 to.Add((ObjectId)val.Value);

      304               }

      305               i++;

      306             }

      307             // Validate the link info and add it to our

      308             // internal data structure

      309             AddValidatedLinks(db, from, to);

      310             xrecCount++;

      311           }

      312           else

      313           {

      314             done = true;

      315           }

      316         }

      317         tr.Commit();

      318       }

      319     }

      320

      321     // Helper function to validate links before adding

      322     // them to the internal data structure

      323     private void AddValidatedLinks(

      324       Database db,

      325       ObjectId from,

      326       ObjectIdCollection to

      327     )

      328     {

      329       Document doc =

      330         Application.DocumentManager.MdiActiveDocument;

      331       Editor ed = doc.Editor;

      332       Transaction tr =

      333         db.TransactionManager.StartTransaction();

      334       using (tr)

      335       {

      336         try

      337         {

      338           ObjectIdCollection newList =

      339             new ObjectIdCollection();

      340

      341           // Open the "from" object

      342           DBObject obj =

      343             tr.GetObject(from, OpenMode.ForRead, false);

      344           if (obj != null)

      345           {

      346             // Open each of the "to" objects

      347             foreach (ObjectId id in to)

      348             {

      349               DBObject obj2;

      350               try

      351               {

      352                 obj2 =

      353                   tr.GetObject(id, OpenMode.ForRead, false);

      354                 // Filter out the erased "to" objects

      355                 if (obj2 != null)

      356                 {

      357                   newList.Add(id);

      358                 }

      359               }

      360               catch (System.Exception)

      361               {

      362                 ed.WriteMessage(

      363                   "\nFiltered out link to an erased object."

      364                 );

      365               }

      366             }

      367             // Only if the "from" object and at least

      368             // one "to" object exist (and are unerased)

      369             // do we add an entry for them

      370             if (newList.Count > 0)

      371             {

      372               m_dict.Add(from, newList);

      373             }

      374           }

      375         }

      376         catch (System.Exception)

      377         {

      378           ed.WriteMessage(

      379             "\nFiltered out link from an erased object."

      380           );

      381         }

      382         tr.Commit();

      383       }

      384     }

      385

      386     // Helper function to get (optionally create)

      387     // the nested dictionary for our xrecord objects

      388     private ObjectId GetLinkDictionaryId(

      389       Database db,

      390       bool createIfNotExisting

      391     )

      392     {

      393       ObjectId appDictId = ObjectId.Null;

      394

      395       Transaction tr =

      396         db.TransactionManager.StartTransaction();

      397       using (tr)

      398       {

      399         DBDictionary nod =

      400           (DBDictionary)tr.GetObject(

      401             db.NamedObjectsDictionaryId,

      402             OpenMode.ForRead

      403           );

      404         // Our outer level ("company") dictionary

      405         // does not exist

      406         if (!nod.Contains(kCompanyDict))

      407         {

      408           if (!createIfNotExisting)

      409             return ObjectId.Null;

      410

      411           // Create both the "company" dictionary...

      412           DBDictionary compDict = new DBDictionary();

      413           nod.UpgradeOpen();

      414           nod.SetAt(kCompanyDict, compDict);

      415           tr.AddNewlyCreatedDBObject(compDict, true);

      416

      417           // ... and the inner "application" dictionary.

      418           DBDictionary appDict = new DBDictionary();

      419           appDictId =

      420             compDict.SetAt(kApplicationDict, appDict);

      421           tr.AddNewlyCreatedDBObject(appDict, true);

      422         }

      423         else

      424         {

      425           // Our "company" dictionary exists...

      426           DBDictionary compDict =

      427             (DBDictionary)tr.GetObject(

      428               nod.GetAt(kCompanyDict),

      429               OpenMode.ForRead

      430             );

      431           /// So check for our "application" dictionary

      432           if (!compDict.Contains(kApplicationDict))

      433           {

      434             if (!createIfNotExisting)

      435               return ObjectId.Null;

      436

      437             // Create the "application" dictionary

      438             DBDictionary appDict = new DBDictionary();

      439             compDict.UpgradeOpen();

      440             appDictId =

      441               compDict.SetAt(kApplicationDict, appDict);

      442             tr.AddNewlyCreatedDBObject(appDict, true);

      443           }

      444           else

      445           {

      446             // Both dictionaries already exist...

      447             appDictId = compDict.GetAt(kApplicationDict);

      448           }

      449         }

      450         tr.Commit();

      451       }

      452       return appDictId;

      453     }

      454   }

      455

      456   /// <summary>

      457   /// This class defines our commands and event callbacks.

      458   /// </summary>

      459   public class LinkingCommands

      460   {

      461     LinkedObjectManager m_linkManager;

      462     ObjectIdCollection m_entitiesToUpdate;

      463     bool m_autoLink = false;

      464     ObjectId m_lastEntity = ObjectId.Null;

      465

      466     public LinkingCommands()

      467     {

      468       Document doc =

      469         Application.DocumentManager.MdiActiveDocument;

      470       Database db = doc.Database;

      471       db.ObjectModified +=

      472         new ObjectEventHandler(OnObjectModified);

      473       db.ObjectErased +=

      474         new ObjectErasedEventHandler(OnObjectErased);

      475       db.ObjectAppended +=

      476         new ObjectEventHandler(OnObjectAppended);

      477       db.BeginSave +=

      478         new DatabaseIOEventHandler(OnBeginSave);

      479       doc.CommandEnded +=

      480         new CommandEventHandler(OnCommandEnded);

      481

      482       m_linkManager = new LinkedObjectManager();

      483       m_entitiesToUpdate = new ObjectIdCollection();

      484     }

      485

      486     ~LinkingCommands()

      487     {

      488       try

      489       {

      490         Document doc =

      491           Application.DocumentManager.MdiActiveDocument;

      492         Database db = doc.Database;

      493         db.ObjectModified -=

      494           new ObjectEventHandler(OnObjectModified);

      495         db.ObjectErased -=

      496           new ObjectErasedEventHandler(OnObjectErased);

      497         db.ObjectAppended -=

      498           new ObjectEventHandler(OnObjectAppended);

      499         db.BeginSave -=

      500           new DatabaseIOEventHandler(OnBeginSave);

      501         doc.CommandEnded +=

      502           new CommandEventHandler(OnCommandEnded);

      503       }

      504       catch(System.Exception)

      505       {

      506         // The document or database may no longer

      507         // be available on unload

      508       }

      509     }

      510

      511     // Define "LINK" command

      512     [CommandMethod("LINK")]

      513     public void LinkEntities()

      514     {

      515       Document doc =

      516         Application.DocumentManager.MdiActiveDocument;

      517       Database db = doc.Database;

      518       Editor ed = doc.Editor;

      519

      520       PromptEntityOptions opts =

      521         new PromptEntityOptions(

      522           "\nSelect first circle to link: "

      523         );

      524       opts.AllowNone = true;

      525       opts.SetRejectMessage(

      526         "\nOnly circles can be selected."

      527       );

      528       opts.AddAllowedClass(typeof(Circle), false);

      529

      530       PromptEntityResult res = ed.GetEntity(opts);

      531       if (res.Status == PromptStatus.OK)

      532       {

      533         ObjectId from = res.ObjectId;

      534         opts.Message =

      535           "\nSelect second circle to link: ";

      536         res = ed.GetEntity(opts);

      537         if (res.Status == PromptStatus.OK)

      538         {

      539           ObjectId to = res.ObjectId;

      540           m_linkManager.LinkObjects(from, to);

      541           m_lastEntity = to;

      542           m_entitiesToUpdate.Add(from);

      543         }

      544       }

      545     }

      546

      547     // Define "AUTOLINK" command

      548     [CommandMethod("AUTOLINK")]

      549     public void ToggleAutoLink()

      550     {

      551       Document doc =

      552         Application.DocumentManager.MdiActiveDocument;

      553       Editor ed = doc.Editor;

      554       m_autoLink = !m_autoLink;

      555       if (m_autoLink)

      556       {

      557         ed.WriteMessage("\nAutomatic linking turned on.");

      558       }

      559       else

      560       {

      561         ed.WriteMessage("\nAutomatic linking turned off.");

      562       }

      563     }

      564

      565     // Define "LOADLINKS" command

      566     [CommandMethod("LOADLINKS")]

      567     public void LoadLinkSettings()

      568     {

      569       Document doc =

      570         Application.DocumentManager.MdiActiveDocument;

      571       Database db = doc.Database;

      572       m_linkManager.LoadFromDatabase(db);

      573     }

      574

      575     // Define "SAVELINKS" command

      576     [CommandMethod("SAVELINKS")]

      577     public void SaveLinkSettings()

      578     {

      579       Document doc =

      580         Application.DocumentManager.MdiActiveDocument;

      581       Database db = doc.Database;

      582       m_linkManager.SaveToDatabase(db);

      583     }

      584

      585     // Define callback for Database.ObjectModified event

      586     private void OnObjectModified(

      587       object sender, ObjectEventArgs e)

      588     {

      589       ObjectId id = e.DBObject.ObjectId;

      590       if (m_linkManager.Contains(id) &&

      591           !m_entitiesToUpdate.Contains(id))

      592       {

      593         m_entitiesToUpdate.Add(id);

      594       }

      595     }

      596

      597     // Define callback for Database.ObjectErased event

      598     private void OnObjectErased(

      599       object sender, ObjectErasedEventArgs e)

      600     {

      601       if (e.Erased)

      602       {

      603         ObjectId id = e.DBObject.ObjectId;

      604         m_linkManager.RemoveLinks(id);

      605         if (m_lastEntity == id)

      606         {

      607           m_lastEntity = ObjectId.Null;

      608         }

      609       }

      610     }

      611

      612     // Define callback for Database.ObjectAppended event

      613     void OnObjectAppended(object sender, ObjectEventArgs e)

      614     {

      615       Database db = sender as Database;

      616       if (db != null)

      617       {

      618         if (m_autoLink)

      619         {

      620           if (e.DBObject.GetType() == typeof(Circle))

      621           {

      622             ObjectId from = e.DBObject.ObjectId;

      623             if (m_lastEntity == ObjectId.Null)

      624             {

      625               m_lastEntity = from;

      626             }

      627             else

      628             {

      629               m_linkManager.LinkObjects(from, m_lastEntity);

      630               m_lastEntity = from;

      631               m_entitiesToUpdate.Add(from);

      632             }

      633           }

      634         }

      635       }

      636     }

      637

      638     // Define callback for Database.BeginSave event

      639     void OnBeginSave(object sender, DatabaseIOEventArgs e)

      640     {

      641       Database db = sender as Database;

      642       if (db != null)

      643       {

      644         m_linkManager.SaveToDatabase(db);

      645       }

      646     }

      647

      648     // Define callback for Document.CommandEnded event

      649     private void OnCommandEnded(

      650       object sender, CommandEventArgs e)

      651     {

      652       foreach (ObjectId id in m_entitiesToUpdate)

      653       {

      654         UpdateLinkedEntities(id);

      655       }

      656       m_entitiesToUpdate.Clear();

      657     }

      658

      659     // Helper function for OnCommandEnded

      660     private void UpdateLinkedEntities(ObjectId from)

      661     {

      662       Document doc =

      663         Application.DocumentManager.MdiActiveDocument;

      664       Editor ed = doc.Editor;

      665       Database db = doc.Database;

      666

      667       ObjectIdCollection linked =

      668         m_linkManager.GetLinkedObjects(from);

      669

      670       Transaction tr =

      671         db.TransactionManager.StartTransaction();

      672       using (tr)

      673       {

      674         try

      675         {

      676           Point3d firstCenter;

      677           Point3d secondCenter;

      678           double firstRadius;

      679           double secondRadius;

      680

      681           Entity ent =

      682             (Entity)tr.GetObject(from, OpenMode.ForRead);

      683

      684           if (GetCenterAndRadius(

      685                 ent,

      686                 out firstCenter,

      687                 out firstRadius

      688               )

      689           )

      690           {

      691             foreach (ObjectId to in linked)

      692             {

      693               Entity ent2 =

      694                 (Entity)tr.GetObject(to, OpenMode.ForRead);

      695               if (GetCenterAndRadius(

      696                     ent2,

      697                     out secondCenter,

      698                     out secondRadius

      699                   )

      700               )

      701               {

      702                 Vector3d vec = firstCenter - secondCenter;

      703                 if (!vec.IsZeroLength())

      704                 {

      705                   // Only move the linked circle if it's not

      706                   // already near enough               

      707                   double apart =

      708                   vec.Length - (firstRadius + secondRadius);

      709                   if (apart < 0.0)

      710                     apart = -apart;

      711

      712                   if (apart > 0.00001)

      713                   {

      714                     ent2.UpgradeOpen();

      715                     ent2.TransformBy(

      716                       Matrix3d.Displacement(

      717                         vec.GetNormal() * apart

      718                       )

      719                     );

      720                   }

      721                 }

      722               }

      723             }

      724           }

      725         }

      726         catch (System.Exception ex)

      727         {

      728           Autodesk.AutoCAD.Runtime.Exception ex2 =

      729             ex as Autodesk.AutoCAD.Runtime.Exception;

      730           if (ex2 != null &&

      731               ex2.ErrorStatus !=

      732                 ErrorStatus.WasOpenForUndo &&

      733               ex2.ErrorStatus !=

      734                 ErrorStatus.WasErased

      735           )

      736           {

      737             ed.WriteMessage(

      738               "\nAutoCAD exception: {0}", ex2

      739             );

      740           }

      741           else if (ex2 == null)

      742           {

      743             ed.WriteMessage(

      744               "\nSystem exception: {0}", ex

      745             );

      746           }

      747         }

      748         tr.Commit();

      749       }

      750     }

      751

      752     // Helper function to get the center and radius

      753     // for all supported circular objects

      754     private bool GetCenterAndRadius(

      755       Entity ent,

      756       out Point3d center,

      757       out double radius

      758     )

      759     {

      760       // For circles it's easy...

      761       Circle circle = ent as Circle;

      762       if (circle != null)

      763       {

      764         center = circle.Center;

      765         radius = circle.Radius;

      766         return true;

      767       }

      768       else

      769       {

      770         // Throw in some empty values...

      771         // Returning false indicates the object

      772         // passed in was not useable

      773         center = Point3d.Origin;

      774         radius = 0.0;

      775         return false;

      776       }

      777     }

      778   }

      779 }

    Let's take a quick look at this code running. Here's an existing chain that we've created using LINK. We then use AUTOLINK to toggle the automatic linking to on, and start creating circles:

    Linkedcircles_3_1

    Linkedcircles_3_2

    Linkedcircles_3_3

    Linkedcircles_3_4

    And that's it for this post. Next time we'll look at adding support for other object types, including 3D (woohoo!).

    TrackBack

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

    Listed below are links to weblogs that reference Linking Circles, Part 3: Automatic linking on circle creation:

    Comments

    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