Kean Walmsley


  • About the Author
    Kean on Google+

July 2014

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    








« Linking Circles, Part 3: Automatic linking on circle creation | Main | Linking Circles, Part 5: Animating the snake »

December 04, 2006

Linking Circles, Part 4: Adding 3D

In the last three posts, we've looked at how to link circles using .NET events, how to store the link data in the drawing database, and how to create links automatically as objects are created.

In this post we'll extend the code to support 3D. Yes, that's right, we're going to add support for creating chains of spheres, and with surprisingly little additional effort.

Here's the source code for this post as a download.

Notes on the changes:

Lines 522, 526 and 536 are simply changes to prompts to refer to spheres as well as circles. To actually support the selection of spheres, we now make an additional call to add Solid3d as an allowed class (line 529).

On lines 621-622 we change the criteria for auto-linking, to support objects of type Solid3d. It would be nice to also filter specifically on the solid type, but unfortunately this information is currently not exposed through .NET (you can get it from C++, should you really need to... this is a technique we used in the Component Technologies demo we've been presenting at our annual regional conferences). And in any case, you can get some really fun results if you select different types of solids... :-)

And finally, we have the code to get the centre and radius of spheres (lines 772-787 and line 794). We simply use the centroid of the solid for the centre (which is a fair guess for solids, but may be slightly off for pyramids, for instance), and we retrieve the radius by working backwards from the surface area, which for sphere is 4 x PI x r^2. Again - this isn't quite going to right for non-spherical solids, so be prepared.

OK, that's it... here's 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 or sphere to link: "

  523         );

  524       opts.AllowNone = true;

  525       opts.SetRejectMessage(

  526         "\nOnly circles or 3D solids can be selected."

  527       );

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

  529       opts.AddAllowedClass(typeof(Solid3d), false);

  530

  531       PromptEntityResult res = ed.GetEntity(opts);

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

  533       {

  534         ObjectId from = res.ObjectId;

  535         opts.Message =

  536           "\nSelect second circle or sphere to link: ";

  537         res = ed.GetEntity(opts);

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

  539         {

  540           ObjectId to = res.ObjectId;

  541           m_linkManager.LinkObjects(from, to);

  542           m_lastEntity = to;

  543           m_entitiesToUpdate.Add(from);

  544         }

  545       }

  546     }

  547

  548     // Define "AUTOLINK" command

  549     [CommandMethod("AUTOLINK")]

  550     public void ToggleAutoLink()

  551     {

  552       Document doc =

  553         Application.DocumentManager.MdiActiveDocument;

  554       Editor ed = doc.Editor;

  555       m_autoLink = !m_autoLink;

  556       if (m_autoLink)

  557       {

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

  559       }

  560       else

  561       {

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

  563       }

  564     }

  565

  566     // Define "LOADLINKS" command

  567     [CommandMethod("LOADLINKS")]

  568     public void LoadLinkSettings()

  569     {

  570       Document doc =

  571         Application.DocumentManager.MdiActiveDocument;

  572       Database db = doc.Database;

  573       m_linkManager.LoadFromDatabase(db);

  574     }

  575

  576     // Define "SAVELINKS" command

  577     [CommandMethod("SAVELINKS")]

  578     public void SaveLinkSettings()

  579     {

  580       Document doc =

  581         Application.DocumentManager.MdiActiveDocument;

  582       Database db = doc.Database;

  583       m_linkManager.SaveToDatabase(db);

  584     }

  585

  586     // Define callback for Database.ObjectModified event

  587     private void OnObjectModified(

  588       object sender, ObjectEventArgs e)

  589     {

  590       ObjectId id = e.DBObject.ObjectId;

  591       if (m_linkManager.Contains(id) &&

  592           !m_entitiesToUpdate.Contains(id))

  593       {

  594         m_entitiesToUpdate.Add(id);

  595       }

  596     }

  597

  598     // Define callback for Database.ObjectErased event

  599     private void OnObjectErased(

  600       object sender, ObjectErasedEventArgs e)

  601     {

  602       if (e.Erased)

  603       {

  604         ObjectId id = e.DBObject.ObjectId;

  605         m_linkManager.RemoveLinks(id);

  606         if (m_lastEntity == id)

  607         {

  608           m_lastEntity = ObjectId.Null;

  609         }

  610       }

  611     }

  612

  613     // Define callback for Database.ObjectAppended event

  614     void OnObjectAppended(object sender, ObjectEventArgs e)

  615     {

  616       Database db = sender as Database;

  617       if (db != null)

  618       {

  619         if (m_autoLink)

  620         {

  621           if (e.DBObject.GetType() == typeof(Circle) ||

  622               e.DBObject.GetType() == typeof(Solid3d))

  623           {

  624             ObjectId from = e.DBObject.ObjectId;

  625             if (m_lastEntity == ObjectId.Null)

  626             {

  627               m_lastEntity = from;

  628             }

  629             else

  630             {

  631               m_linkManager.LinkObjects(from, m_lastEntity);

  632               m_lastEntity = from;

  633               m_entitiesToUpdate.Add(from);

  634             }

  635           }

  636         }

  637       }

  638     }

  639

  640     // Define callback for Database.BeginSave event

  641     void OnBeginSave(object sender, DatabaseIOEventArgs e)

  642     {

  643       Database db = sender as Database;

  644       if (db != null)

  645       {

  646         m_linkManager.SaveToDatabase(db);

  647       }

  648     }

  649

  650     // Define callback for Document.CommandEnded event

  651     private void OnCommandEnded(

  652       object sender, CommandEventArgs e)

  653     {

  654       foreach (ObjectId id in m_entitiesToUpdate)

  655       {

  656         UpdateLinkedEntities(id);

  657       }

  658       m_entitiesToUpdate.Clear();

  659     }

  660

  661     // Helper function for OnCommandEnded

  662     private void UpdateLinkedEntities(ObjectId from)

  663     {

  664       Document doc =

  665         Application.DocumentManager.MdiActiveDocument;

  666       Editor ed = doc.Editor;

  667       Database db = doc.Database;

  668

  669       ObjectIdCollection linked =

  670         m_linkManager.GetLinkedObjects(from);

  671

  672       Transaction tr =

  673         db.TransactionManager.StartTransaction();

  674       using (tr)

  675       {

  676         try

  677         {

  678           Point3d firstCenter;

  679           Point3d secondCenter;

  680           double firstRadius;

  681           double secondRadius;

  682

  683           Entity ent =

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

  685

  686           if (GetCenterAndRadius(

  687                 ent,

  688                 out firstCenter,

  689                 out firstRadius

  690               )

  691           )

  692           {

  693             foreach (ObjectId to in linked)

  694             {

  695               Entity ent2 =

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

  697               if (GetCenterAndRadius(

  698                     ent2,

  699                     out secondCenter,

  700                     out secondRadius

  701                   )

  702               )

  703               {

  704                 Vector3d vec = firstCenter - secondCenter;

  705                 if (!vec.IsZeroLength())

  706                 {

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

  708                   // already near enough               

  709                   double apart =

  710                   vec.Length - (firstRadius + secondRadius);

  711                   if (apart < 0.0)

  712                     apart = -apart;

  713

  714                   if (apart > 0.00001)

  715                   {

  716                     ent2.UpgradeOpen();

  717                     ent2.TransformBy(

  718                       Matrix3d.Displacement(

  719                         vec.GetNormal() * apart

  720                       )

  721                     );

  722                   }

  723                 }

  724               }

  725             }

  726           }

  727         }

  728         catch (System.Exception ex)

  729         {

  730           Autodesk.AutoCAD.Runtime.Exception ex2 =

  731             ex as Autodesk.AutoCAD.Runtime.Exception;

  732           if (ex2 != null &&

  733               ex2.ErrorStatus !=

  734                 ErrorStatus.WasOpenForUndo &&

  735               ex2.ErrorStatus !=

  736                 ErrorStatus.WasErased

  737           )

  738           {

  739             ed.WriteMessage(

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

  741             );

  742           }

  743           else if (ex2 == null)

  744           {

  745             ed.WriteMessage(

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

  747             );

  748           }

  749         }

  750         tr.Commit();

  751       }

  752     }

  753

  754     // Helper function to get the center and radius

  755     // for all supported circular objects

  756     private bool GetCenterAndRadius(

  757       Entity ent,

  758       out Point3d center,

  759       out double radius

  760     )

  761     {

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

  763       Circle circle = ent as Circle;

  764       if (circle != null)

  765       {

  766         center = circle.Center;

  767         radius = circle.Radius;

  768         return true;

  769       }

  770       else

  771       {

  772         // For solids (spheres) return the centroid

  773         // and the radius, derived from the area

  774         Solid3d solid = ent as Solid3d;

  775         if (solid != null)

  776         {

  777           center =

  778             solid.MassProperties.Centroid;

  779           // Surface area of a sphere is 4 * pi * r^2

  780           radius =

  781             System.Math.Sqrt(

  782             solid.Area / System.Math.PI

  783             ) / 2;

  784           return true;

  785         }

  786         else

  787         {

  788           // Throw in some empty values...

  789           // Returning false indicates the object

  790           // passed in was not useable

  791           center = Point3d.Origin;

  792           radius = 0.0;

  793           return false;

  794         }

  795       }

  796     }

  797   }

  798 }

Just to prove it all works, here are a couple of screenshots of some linked spheres with pretty materials attached. By the way, the links will also work when the movement is in full 3D - not just planar to the current UCS:

Linkedcircles_4_1

Linkedcircles_4_2

That's almost it for the "Linking Circles" series, unless someone makes some interesting suggestions in the comments. I have an old LISP file I used to demo the original sample: it simply moves the "head of the snake" through a sine wave a number of times across the screen (just using the MOVE command - nothing very fancy). I'll post the code next time, in case anyone's interested.

TrackBack

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

Listed below are links to weblogs that reference Linking Circles, Part 4: Adding 3D:

blog comments powered by Disqus

10 Random Posts