Site Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

developer:rhinocommonsamples:userdata [2015/09/14]
developer:rhinocommonsamples:userdata [2020/08/14] (current)
Line 1: Line 1:
 +====== Info: RhinoCommon object plug-in user data ======
 +
 +=====Overview=====
 +There are two basic ways plug-ins can store information in Rhino .3dm files, **document user data** and **object user data**.
 +
 +For example, a rendering plug-in might save a scene descriptions as **document user data** and use **object user data** to attach rendering material information to individual surfaces.
 +
 +=====Document User Data=====
 +To save document user data your plug-in must override three PlugIn base class functions:
 +
 +<code c#>
 +PlugIn::ShouldWriteDocument
 +PlugIn::WriteDocument
 +PlugIn::ReadDocument
 +</code>
 +
 +SDK references for these functions can be found [[http://www.rhino3d.com/5/rhinocommon/html/Methods_T_Rhino_PlugIns_PlugIn.htm|here]]
 +
 +When Rhino writes a .3dm file, it goes through all the plug-ins that are currently loaded.  First Rhino calls ShouldWriteDocument() to see if the plug-in wants to save document user data.  If ShouldWriteDocument() returns true, Rhino saves information that identifies the plug-in and then calls WriteDocument() when it is time for the plug-in to save its "document" user data.
 +
 +When Rhino reads a .3dm file and it encounters document user data, it uses the plug-in identification information to load the plug-in and then calls the plug-in's ReadDocument() to read the plug-in's "document" user data.
 +
 +
 +=====Object User Data=====
 +
 +Object user data can be attached to things like layers, materials, geometry objects, and object attributes.  In fact object user data can be attached to any class derived from CommonObject.  This user data is stored in a linked list on CommonObject and can be copied, transformed and saved along with the parent object.  For example, you could attach object user data to a mesh.  When the mesh is copied the object user data would be copied and attached to the copy.  When the mesh is transformed, the transformation would be recored by the object user data.  When the mesh is saved in a .3dm file, the object user data will be saved too.
 +
 +There are three forms of object user data
 +  - User strings
 +  - UserDictionary
 +  - Custom UserData
 +
 +**It is recommended to typically use the User Strings or the UserDictionary on an object since the data is automatically serialized for you and it is easily shared between plug-ins and scripts.**
 +
 +In the case that you want to write your own private custom user data, you would derive a class from Rhino.DocObjects.Custom.UserData.  Here's a sample
 +
 +===== C# =====
 +<code c# userdata.cs>
 +using System;
 +using Rhino;
 +using System.Runtime.InteropServices;
 +
 +namespace examples_cs
 +{
 +  // You must define a Guid attribute for your user data derived class
 +  // in order to support serialization. Every custom user data class
 +  // needs a custom Guid
 +  [Guid("DAAA9791-01DB-4F5F-B89B-4AE46767C783")]
 +  public class PhysicalData : Rhino.DocObjects.Custom.UserData
 +  {
 +    public int Weight{ get; set; }
 +    public double Density {get; set;}
 +
 +
 +    // Your UserData class must have a public parameterless constructor
 +    public PhysicalData(){}
 +
 +    public PhysicalData(int weight, double density)
 +    {
 +      Weight = weight;
 +      Density = density;
 +    }
 +
 +    public override string Description
 +    {
 +      get { return "Physical Properties"; }
 +    }
 +
 +    public override string ToString()
 +    {
 +      return String.Format("weight={0}, density={1}", Weight, Density);
 +    }
 +
 +    protected override void OnDuplicate(Rhino.DocObjects.Custom.UserData source)
 +    {
 +      PhysicalData src = source as PhysicalData;
 +      if (src != null)
 +      {
 +        Weight = src.Weight;
 +        Density = src.Density;
 +      }
 +    }
 +
 +    // return true if you have information to save
 +    public override bool ShouldWrite
 +    {
 +      get
 +      {
 +        if (Weight > 0 && Density > 0)
 +          return true;
 +        return false;
 +      }
 +    }
 +
 +    protected override bool Read(Rhino.FileIO.BinaryArchiveReader archive)
 +    {
 +      Rhino.Collections.ArchivableDictionary dict = archive.ReadDictionary();
 +      if (dict.ContainsKey("Weight") && dict.ContainsKey("Density"))
 +      {
 +        Weight = (int)dict["Weight"];
 +        Density = (double)dict["Density"];
 +      }
 +      return true;
 +    }
 +    protected override bool Write(Rhino.FileIO.BinaryArchiveWriter archive)
 +    {
 +      // you can implement File IO however you want... but the dictionary class makes
 +      // issues like versioning in the 3dm file a bit easier.  If you didn't want to use
 +      // the dictionary for writing, your code would look something like.
 +      //
 +      //  archive.Write3dmChunkVersion(1, 0);
 +      //  archive.WriteInt(Weight);
 +      //  archive.WriteDouble(Density);
 +      var dict = new Rhino.Collections.ArchivableDictionary(1, "Physical");
 +      dict.Set("Weight", Weight);
 +      dict.Set("Density", Density);
 +      archive.WriteDictionary(dict);
 +      return true;
 +    }
 +  }
 +
 +
 +  [Guid("ca9a110e-3969-49ec-9d59-a7c2ee0b85bd")]
 +  public class ex_userdataCommand : Rhino.Commands.Command
 +  {
 +    public override string EnglishName { get { return "cs_userdataCommand"; } }
 +
 +    protected override Rhino.Commands.Result RunCommand(RhinoDoc doc, Rhino.Commands.RunMode mode)
 +    {
 +      Rhino.DocObjects.ObjRef objref;
 +      var rc = Rhino.Input.RhinoGet.GetOneObject("Select Object", false, Rhino.DocObjects.ObjectType.AnyObject, out objref);
 +      if (rc != Rhino.Commands.Result.Success)
 +        return rc;
 +
 +      // See if user data of my custom type is attached to the geomtry
 +      var ud = objref.Geometry().UserData.Find(typeof(PhysicalData)) as PhysicalData;
 +      if (ud == null)
 +      {
 +        // No user data found; create one and add it
 +        int weight = 0;
 +        rc = Rhino.Input.RhinoGet.GetInteger("Weight", false, ref weight);
 +        if (rc != Rhino.Commands.Result.Success)
 +          return rc;
 +
 +        ud = new PhysicalData(weight, 12.34);
 +        objref.Geometry().UserData.Add(ud);
 +      }
 +      else
 +      {
 +        RhinoApp.WriteLine("{0} = {1}", ud.Description, ud);
 +      }
 +      return Rhino.Commands.Result.Success;
 +    }
 +  }
 +}
 +
 +</code>
 +
 +{{tag>Developer rhinocommon}}