hypar-io / Elements

The smallest useful BIM.
https://www.hypar.io
MIT License
349 stars 74 forks source link

Cannot Deserialise Grid2d #985

Closed Gytaco closed 1 year ago

Gytaco commented 1 year ago

Describe the bug I have a Grid2d item in a Dictionary as follows. I am running this in a Unit Test.

AvailableFace is a simple enum (Top, Bottom, Left, Right) public Dictionary<AvailableFace, Grid2d> AvailableGrids { get; set; }

I have also tested just as public Grid2d TestGrid { get; set; } and I get the same result.

It appears to serialise correctly. Here is my Json output using the default serialiser.

Here is my deserialisation code for reference. It works for all other hypar objects. Here is my code to construct my Grid.

Grid2d g2d = new Grid2d(item.Value.Perimeter)
                {
                    Type = "Area"
                };
                floor.Test = g2d;

Here is my deserialiser.

public T Deserialize<T>(string serialValue, Type outputType)
        {
            var settings = new JsonSerializerSettings();
            settings.TypeNameHandling = TypeNameHandling.Auto;

            return (T)JsonConvert.DeserializeObject(serialValue, outputType, settings);
        }

Here is the raw Json output

   "AvailableGrids": {
        "Top": {
            "discriminator": "Elements.Spatial.Grid2d",
            "BoundariesInGridSpace": {
                "$type": "Elements.Geometry.Polygon[], Hypar.Elements",
                "$values": [{
                        "discriminator": "Elements.Geometry.Polygon",
                        "Vertices": [{
                                "X": 0.0,
                                "Y": 0.0,
                                "Z": 0.0
                            }, {
                                "X": 3000.0,
                                "Y": 0.0,
                                "Z": 0.0
                            }, {
                                "X": 3000.0,
                                "Y": -1670.0,
                                "Z": 0.0
                            }, {
                                "X": 0.0,
                                "Y": -1670.0,
                                "Z": 0.0
                            }
                        ]
                    }
                ]
            },
            "FromGrid": {
                "Matrix": {
                    "Components": [1.0, 0.0, 0.0, 6840.0, 0.0, 1.0, 0.0, 430.0, 0.0, 0.0, 1.0, 0.0]
                }
            },
            "ToGrid": {
                "Matrix": {
                    "Components": [1.0, 0.0, 0.0, -6840.0, 0.0, 1.0, 0.0, -430.0, 0.0, 0.0, 1.0, -0.0]
                }
            },
            "Type": "Available",
            "U": {
                "discriminator": "Elements.Spatial.Grid1d",
                "CurveDomain": {
                    "Max": 3000.0,
                    "Min": 0.0
                },
                "Domain": {
                    "Max": 3000.0,
                    "Min": 0.0
                },
                "IsSingleCell": true,
                "TopLevelParentCurve": {
                    "discriminator": "Elements.Geometry.Line",
                    "End": {
                        "X": 3000.0,
                        "Y": 0.0,
                        "Z": 0.0
                    },
                    "Start": {
                        "X": 0.0,
                        "Y": 0.0,
                        "Z": 0.0
                    }
                }
            },
            "UDomainInternal": {
                "Max": 3000.0,
                "Min": 0.0
            },
            "V": {
                "discriminator": "Elements.Spatial.Grid1d",
                "CurveDomain": {
                    "Max": 1670.0,
                    "Min": 0.0
                },
                "Domain": {
                    "Max": 1670.0,
                    "Min": 0.0
                },
                "IsSingleCell": true,
                "TopLevelParentCurve": {
                    "discriminator": "Elements.Geometry.Line",
                    "End": {
                        "X": 0.0,
                        "Y": 0.0,
                        "Z": 0.0
                    },
                    "Start": {
                        "X": 0.0,
                        "Y": -1670.0,
                        "Z": 0.0
                    }
                }
            },
            "VDomainInternal": {
                "Max": 0.0,
                "Min": -1670.0
            }
        }
    }

To Reproduce Steps to reproduce the behavior:

  1. Create a Grid2d with a profile/perimeter
  2. Set the Type string
  3. Serialise
  4. Try to deserialise
  5. See Error below

System.Exception: 'An object with the discriminator, Elements.Spatial.Grid2d, could not be deserialized. This may happen if the type is not recognized in the system. See the inner exception for more details.'

JsonSerializationException: Type specified in JSON 'Elements.Geometry.Polygon[], Hypar.Elements, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not compatible with 'System.Collections.Generic.List`1[[Elements.Geometry.Polygon, Hypar.Elements, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e'. Path 'BoundariesInGridSpace.$type'.

Expected behavior I would expect it to deserialise back into a valid Grid2d object. Its not happy about the Polygon[] but it would be good to have a reference before I go building a custom deserialiser if possible.

Additional context I'm open to any tips to fix this before I go deep into the weeds.

andrewheumann commented 1 year ago

The problem seems to have to do with your custom deserializer / your serialization settings. If you serialize a Grid2d normally, you do not get the $type and $values properties in the json. This is what a properly serialized grid2d should look like:

{
    "discriminator": "Elements.Spatial.Grid2d",
    "FromGrid": {
        "Matrix": {
            "Components": [
                1.0,
                0.0,
                0.0,
                -5.0,
                0.0,
                1.0,
                0.0,
                -5.0,
                0.0,
                0.0,
                1.0,
                0.0
            ]
        }
    },
    "ToGrid": {
        "Matrix": {
            "Components": [
                1.0,
                0.0,
                0.0,
                5.0,
                0.0,
                1.0,
                0.0,
                5.0,
                0.0,
                0.0,
                1.0,
                0.0
            ]
        }
    },
    "UDomainInternal": {
        "Min": 0.0,
        "Max": 10.0
    },
    "VDomainInternal": {
        "Min": 0.0,
        "Max": 10.0
    },
    "BoundariesInGridSpace": [
        {
            "discriminator": "Elements.Geometry.Polygon",
            "Vertices": [
                {
                    "X": 0.0,
                    "Y": 0.0,
                    "Z": 0.0
                },
                {
                    "X": 10.0,
                    "Y": 0.0,
                    "Z": 0.0
                },
                {
                    "X": 10.0,
                    "Y": 10.0,
                    "Z": 0.0
                },
                {
                    "X": 0.0,
                    "Y": 10.0,
                    "Z": 0.0
                }
            ]
        }
    ],
    "U": {
        "discriminator": "Elements.Spatial.Grid1d",
        "CurveDomain": {
            "Min": 0.0,
            "Max": 10.0
        },
        "Type": null,
        "Domain": {
            "Min": 0.0,
            "Max": 10.0
        },
        "IsSingleCell": true,
        "TopLevelParentCurve": {
            "discriminator": "Elements.Geometry.Line",
            "Start": {
                "X": 0.0,
                "Y": 0.0,
                "Z": 0.0
            },
            "End": {
                "X": 10.0,
                "Y": 0.0,
                "Z": 0.0
            }
        }
    },
    "V": {
        "discriminator": "Elements.Spatial.Grid1d",
        "CurveDomain": {
            "Min": 0.0,
            "Max": 10.0
        },
        "Type": null,
        "Domain": {
            "Min": 0.0,
            "Max": 10.0
        },
        "IsSingleCell": true,
        "TopLevelParentCurve": {
            "discriminator": "Elements.Geometry.Line",
            "Start": {
                "X": 0.0,
                "Y": 0.0,
                "Z": 0.0
            },
            "End": {
                "X": 0.0,
                "Y": 10.0,
                "Z": 0.0
            }
        }
    },
    "Type": "Area"
}

This code works to serialize / deserialize a grid2d, without any custom settings:

using Elements.Spatial;
var grid = new Grid2d(Polygon.Rectangle(10,10)) {
    Type = "Area"
};
var gridAsJson = JsonConvert.SerializeObject(grid);
var gridFromJson = JsonConvert.DeserializeObject<Grid2d>(gridAsJson);