The first link suggests explicitly providing the type to JsonConvert.DeserializeObject(x); but this doesn’t work if I don’t know the type in the first place.
The other links/examples seem to be using the Rhino3dmIO toolkit - is this appropriate though for a plugin running inside an active instance of Rhino? I think I want something like CommonObject.Decode but I can’t seem to find it in RhinoCommon. Do I need to add a reference to Rhino3dmIO as well (this seems strange and also results in a bunch of namespace conflicts so I assume this is not the way!) I could do as @Dani_Abalde suggests in the third link, but I think this is slightly different than the opennurbs way (although perhaps the “data” property there is just a string encoding of the same byte array?)
Ideally I’d like to simply configure JSON.Net to automatically deserialize to Rhino geometry wherever it finds it - but I’m willing to do something a bit more “special case” if necessary.
Thanks for the quick reply @dale. I’ve looked through RhinoCompute.cs a bit but I confess I’m still at a loss… not sure how to apply what I am seeing. I saw a few examples of DeserializeObject in use but they all already have a type argument specified. There’s also some business with custom JsonConverters in the python code but I’m not sure what I’m looking at there either. Can you give me a little more direction?
To clarify, I was hoping there was some pre-existing method to pop out a GeometryBase from its serialized representation without knowing the geometry type in advance. Perhaps I’m mistaken in thinking this is possible?
I see the problem you are dealing with. GeometryBase and CommonObject are abstract which is causing problems with Json.net deserializer. When you know the exact geometry type you are deserializing to (which compute does know), it is easy enough to just directly use the JsonConvert class
var c = new Rhino.Geometry.Circle(12);
var extrusion = Rhino.Geometry.Extrusion.Create(c.ToNurbsCurve(), 12, true);
var json = Newtonsoft.Json.JsonConvert.SerializeObject(extrusion);
var geometry = Newtonsoft.Json.JsonConvert.DeserializeObject<Rhino.Geometry.Extrusion>(json);
I’ll try to figure out a generic solution for this tomorrow (this time I really mean tomorrow )
Exactly. I can write a thing that repeatedly tries to deserialize it to a bunch of diff geometry (is it a curve? is it a brep? is it a mesh? etc) but it seems like there must be a more elegant way.
Coming up blank on a generic solution. I can give you a unsafe and hack technique to do this involving pInvokes and reflection if you really want to try going that route.
I think I’ll need to add some functionality to RhinoCommon itself to improve the situation. Some sort of static function on Rhino.Runtime.CommonObject that creates an instance given a json string.
I’m in the process of adding a couple functions to Rhino.Runtime.CommonObject that would look like
public static CommonObject FromBase64String(int archive3dm, int opennurbs, string data);
public static CommonObject FromJSON(Dictionary<string,string> json);
Do you think those would work for you? You should be able to just use JsonConvert.DeserializeObject<Dictionary<string,string>> and pass that to the FromJSON function.
that would be awesome! in the meantime I’m wrapping the objects with type information when I serialize them, and extracting the type info to deserialize accordingly, which works, but this seems cleaner.
I’m trying to do some dynamic To/From JSON serializing with Rhino and I don’t quite understand what data the FromJSON method requires (Why a dictionary when the ToJSON just gives a json string? Are there some handy dandy bits of data you can add in to help?). I also couldn’t find a sample anywhere, would you be able to knock one together if there isn’t one, possibly something that might assist me or @andheum with our dynamic serializing needs?
I’m not at my computer today, so I can’t give a great answer.
Try running ToJson on some geometry. This is what FromJson is expecting. It is probably the dictionary that you would get if Json.net converted the string to a dictionary.
Thanks @Steve for the tip,
I tried it out in Grasshopper, and formalised it a bit better here. But for anyone reading this topic, the below code works magically on a random set of Curves/Breps.
using System.Collections.Generic;
using System;
using Newtonsoft.Json;
namespace RhinoSerialization
{
public static class ToAndFrom
{
public bool CastTo(GeometryBase inthing, out string json)
{
Rhino.FileIO.SerializationOptions so = new Rhino.FileIO.SerializationOptions();
json = inthing.ToJSON(so);
}
public bool CastFrom(string json, out GeometryBase outthing)
{
Dictionary<string, string> jsonDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
outthing = Rhino.Runtime.CommonObject.FromJSON(jsonDict);
}
}
}