public static byte[] ToFlatGeobuf(FeatureCollection fc, GeometryType?geometryType = null, byte dimensions = 2, IList <ColumnMeta> columns = null)
        {
            ulong count = (ulong)fc.Features.LongCount();

            if (count == 0)
            {
                return(new byte[0]);
            }

            var index = new PackedHilbertRTree(count);

            foreach (var f in fc.Features)
            {
                var b = f.Geometry.EnvelopeInternal;
                index.Add(b.MinX, b.MinY, b.MaxX, b.MaxY);
            }
            index.Finish();

            var featureFirst = fc.Features.First();

            if (geometryType == null)
            {
                geometryType = GeometryConversions.ToGeometryType(featureFirst.Geometry);
            }

            if (columns == null && featureFirst.Attributes != null)
            {
                columns = featureFirst.Attributes.GetNames()
                          .Select(n => new ColumnMeta()
                {
                    Name = n, Type = ToColumnType(featureFirst.Attributes.GetType(n))
                })
                          .ToList();
            }

            using (var memoryStream = new MemoryStream())
            {
                using (var featuresStream = new MemoryStream())
                    using (var offsetsStream = new MemoryStream())
                        using (var offetsWriter = new BinaryWriter(offsetsStream))
                        {
                            ulong offset = 0;
                            for (ulong i = 0; i < count; i++)
                            {
                                var feature = fc.Features[(int)index.Indices[i]];
                                var buffer  = FeatureConversions.ToByteBuffer(feature, geometryType.Value, dimensions, columns);
                                featuresStream.Write(buffer, 0, buffer.Length);
                                offetsWriter.Write(offset);
                                offset += (ulong)buffer.Length;
                            }
                            var header = BuildHeader(count, geometryType.Value, dimensions, columns, index);
                            memoryStream.Write(header, 0, header.Length);
                            var indexBytes = index.ToBytes();
                            memoryStream.Write(indexBytes, 0, indexBytes.Length);
                            offsetsStream.WriteTo(memoryStream);
                            featuresStream.WriteTo(memoryStream);
                        }
                return(memoryStream.ToArray());
            }
        }
Beispiel #2
0
        private static IList <LayerMeta> IntrospectLayers(FeatureCollection fc)
        {
            var featureFirst           = fc.Features.First();
            IList <ColumnMeta> columns = null;

            if (featureFirst.Attributes != null && featureFirst.Attributes.Count > 0)
            {
                columns = featureFirst.Attributes.GetNames()
                          .Select(n => new ColumnMeta()
                {
                    Name = n, Type = ToColumnType(featureFirst.Attributes.GetType(n))
                })
                          .ToList();
            }

            var geometryTypes = fc.Features
                                .Select(f => GeometryConversions.ToGeometryType(f.Geometry))
                                .Distinct();

            IList <LayerMeta> layers = geometryTypes
                                       .Select(geometryType => new LayerMeta()
            {
                GeometryType = geometryType, Columns = columns
            })
                                       .ToList();

            return(layers);
        }
        public static IFeature FromByteBuffer(ByteBuffer bb, GeometryType geometryType, byte dimensions, IList <ColumnMeta> columns = null)
        {
            var feature = Feature.GetRootAsFeature(bb);
            IAttributesTable attributesTable = null;
            var propertiesArray = feature.GetPropertiesArray();

            if (propertiesArray != null && propertiesArray.Length > 0)
            {
                var memoryStream = new MemoryStream(propertiesArray);
                var reader       = new BinaryReader(memoryStream);
                attributesTable = new AttributesTable();
                while (memoryStream.Position < memoryStream.Length)
                {
                    ushort i      = reader.ReadUInt16();
                    var    column = columns[i];
                    var    type   = column.Type;
                    var    name   = column.Name;
                    switch (type)
                    {
                    case ColumnType.Bool:
                        attributesTable.AddAttribute(name, reader.ReadBoolean());
                        break;

                    case ColumnType.Int:
                        attributesTable.AddAttribute(name, reader.ReadInt32());
                        break;

                    case ColumnType.Long:
                        attributesTable.AddAttribute(name, reader.ReadInt64());
                        break;

                    case ColumnType.Double:
                        attributesTable.AddAttribute(name, reader.ReadDouble());
                        break;

                    case ColumnType.String:
                        int len = reader.ReadInt32();
                        var str = Encoding.UTF8.GetString(memoryStream.ToArray(), (int)memoryStream.Position, len);
                        memoryStream.Position += len;
                        attributesTable.AddAttribute(name, str);
                        break;

                    default: throw new ApplicationException("Unknown type");
                    }
                }
            }

            IGeometry geometry = null;

            if (feature.Geometry.HasValue)
            {
                geometry = GeometryConversions.FromFlatbuf(feature.Geometry.Value, geometryType);
            }
            var f = new NetTopologySuite.Features.Feature(geometry, attributesTable);

            return(f);
        }
        public static void Serialize(Stream output, IEnumerable <IFeature> features, GeometryType geometryType, byte dimensions = 2, IList <ColumnMeta> columns = null)
        {
            output.Write(Constants.MagicBytes);
            var header = BuildHeader(0, geometryType, columns, null);

            output.Write(header);
            foreach (var feature in features)
            {
                var featureGeometryType = geometryType == GeometryType.Unknown ? GeometryConversions.ToGeometryType(feature.Geometry) : geometryType;
                var buffer = FeatureConversions.ToByteBuffer(feature, featureGeometryType, dimensions, columns);
                output.Write(buffer);
            }
        }
        public static byte[] ToByteBuffer(IFeature feature, IList <LayerMeta> layers)
        {
            // TODO: size might not be enough, need to be adaptive
            var builder = new FlatBufferBuilder(1024);

            // TODO: improve layer introspection
            var layer      = layers.First(l => l.GeometryType == GeometryConversions.ToGeometryType(feature.Geometry));
            var layerIndex = (uint)layers.IndexOf(layer);
            var columns    = layer.Columns;

            var geometryOffset = GeometryConversions.BuildGeometry(builder, feature.Geometry);

            VectorOffset?valuesOffset = null;

            if (feature.Attributes != null && feature.Attributes.Count > 0 && columns != null)
            {
                var valueOffsets = new List <Offset <Value> >();

                foreach (var column in columns)
                {
                    if (feature.Attributes.Exists(column.Name))
                    {
                        ushort columnIndex = (ushort)columns.IndexOf(column);
                        var    value       = feature.Attributes[column.Name];
                        switch (value)
                        {
                        case bool v:
                            valueOffsets.Add(Value.CreateValue(builder, columnIndex, bool_value: v));
                            break;

                        case int v:
                            valueOffsets.Add(Value.CreateValue(builder, columnIndex, int_value: v));
                            break;

                        case long v:
                            valueOffsets.Add(Value.CreateValue(builder, columnIndex, long_value: v));
                            break;

                        case double v:
                            valueOffsets.Add(Value.CreateValue(builder, columnIndex, double_value: v));
                            break;

                        case string v:
                            valueOffsets.Add(Value.CreateValue(builder, columnIndex, string_valueOffset: builder.CreateString(v)));
                            break;

                        case null:
                            break;

                        default: throw new ApplicationException("Unknown type");
                        }
                    }
                }
                valuesOffset = Feature.CreateValuesVector(builder, valueOffsets.ToArray());
            }

            Feature.StartFeature(builder);
            Feature.AddGeometry(builder, geometryOffset);
            Feature.AddLayer(builder, layerIndex);
            if (valuesOffset.HasValue)
            {
                Feature.AddValues(builder, valuesOffset.Value);
            }
            var offset = Feature.EndFeature(builder);

            builder.FinishSizePrefixed(offset.Value);

            var bytes = builder.DataBuffer.ToSizedArray();

            return(bytes);
        }
        public static IFeature FromByteBuffer(ByteBuffer bb, Header header)
        {
            // TODO: introspect which layer
            var            columnsLayer = header.Layers(0).Value;
            IList <Column> columns      = null;

            if (columnsLayer.ColumnsLength > 0)
            {
                columns = new List <Column>();
                for (int i = 0; i < columnsLayer.ColumnsLength; i++)
                {
                    var column = columnsLayer.Columns(i).Value;
                    columns.Add(column);
                }
            }

            var feature = Feature.GetRootAsFeature(bb);
            IAttributesTable attributesTable = null;

            if (feature.ValuesLength > 0)
            {
                attributesTable = new AttributesTable();
            }

            var layer = header.Layers((int)feature.Layer).Value;

            for (int i = 0; i < feature.ValuesLength; i++)
            {
                var value  = feature.Values(i).Value;
                var column = columns[value.ColumnIndex];
                switch (column.Type)
                {
                case ColumnType.Bool:
                    attributesTable.AddAttribute(column.Name, value.BoolValue);
                    break;

                case ColumnType.Int:
                    attributesTable.AddAttribute(column.Name, value.IntValue);
                    break;

                case ColumnType.Long:
                    attributesTable.AddAttribute(column.Name, value.LongValue);
                    break;

                case ColumnType.Double:
                    attributesTable.AddAttribute(column.Name, value.DoubleValue);
                    break;

                case ColumnType.String:
                    attributesTable.AddAttribute(column.Name, value.StringValue);
                    break;

                default: throw new ApplicationException("Unknown type");
                }
            }

            var geometry = GeometryConversions.FromFlatbuf(feature.Geometry.Value, layer.GeometryType, layer.Dimensions);
            var f        = new NetTopologySuite.Features.Feature(geometry, attributesTable);

            return(f);
        }
        public static ByteBuffer ToByteBuffer(IFeature feature, ref Header header)
        {
            var          builder = new FlatBufferBuilder(1024);
            GeometryType geometryType;

            if (header.GeometryType != GeometryType.Unknown)
            {
                geometryType = header.GeometryType;
            }
            else
            {
                geometryType = GeometryConversions.ToGeometryType(feature.Geometry);
            }
            var go           = GeometryConversions.BuildGeometry(builder, feature.Geometry, geometryType, ref header);
            var memoryStream = new MemoryStream();

            if (feature.Attributes != null && feature.Attributes.Count > 0 && header.ColumnsLength > 0)
            {
                var writer = new BinaryWriter(memoryStream, Encoding.UTF8);
                for (ushort i = 0; i < header.ColumnsLength; i++)
                {
                    var column = header.Columns(i).Value;
                    var type   = column.Type;
                    var name   = column.Name;
                    if (!feature.Attributes.Exists(name))
                    {
                        continue;
                    }
                    var value = feature.Attributes[name];
                    if (value is null)
                    {
                        continue;
                    }
                    writer.Write(i);
                    switch (type)
                    {
                    case ColumnType.Bool:
                        writer.Write((bool)value);
                        break;

                    case ColumnType.Int:
                        writer.Write((int)value);
                        break;

                    case ColumnType.Long:
                        writer.Write((long)value);
                        break;

                    case ColumnType.Double:
                        writer.Write((double)value);
                        break;

                    case ColumnType.String:
                        var bytes = Encoding.UTF8.GetBytes((string)value);
                        writer.Write(bytes.Length);
                        writer.Write(bytes);
                        break;

                    default:
                        throw new ApplicationException("Unknown type " + value.GetType().FullName);
                    }
                }
            }

            var propertiesOffset = default(VectorOffset);

            if (memoryStream.Position > 0)
            {
                propertiesOffset = Feature.CreatePropertiesVectorBlock(builder, memoryStream.ToArray());
            }

            Offset <Geometry> geometryOffset;

            if (go.gos != null && go.gos.Length > 0)
            {
                var partOffsets = new Offset <Geometry> [go.gos.Length];
                for (int i = 0; i < go.gos.Length; i++)
                {
                    var goPart     = go.gos[i];
                    var partOffset = Geometry.CreateGeometry(builder, goPart.endsOffset, goPart.xyOffset, goPart.zOffset, goPart.mOffset, default, default, go.Type, default);
        public static byte[] ToByteBuffer(IFeature feature, GeometryType geometryType, byte dimensions, IList <ColumnMeta> columns)
        {
            var builder      = new FlatBufferBuilder(4096);
            var go           = GeometryConversions.BuildGeometry(builder, feature.Geometry, geometryType, dimensions);
            var memoryStream = new MemoryStream();

            if (feature.Attributes != null && feature.Attributes.Count > 0 && columns != null)
            {
                var writer = new BinaryWriter(memoryStream, Encoding.UTF8);
                for (ushort i = 0; i < columns.Count(); i++)
                {
                    var column = columns[i];
                    var type   = column.Type;
                    var name   = column.Name;
                    if (!feature.Attributes.Exists(name))
                    {
                        continue;
                    }
                    var value = feature.Attributes[name];
                    if (value is null)
                    {
                        continue;
                    }
                    writer.Write(i);
                    switch (type)
                    {
                    case ColumnType.Bool:
                        writer.Write((bool)value);
                        break;

                    case ColumnType.Int:
                        writer.Write((int)value);
                        break;

                    case ColumnType.Long:
                        writer.Write((long)value);
                        break;

                    case ColumnType.Double:
                        writer.Write((double)value);
                        break;

                    case ColumnType.String:
                        var bytes = Encoding.UTF8.GetBytes((string)value);
                        writer.Write(bytes.Length);
                        writer.Write(bytes);
                        break;

                    default:
                        throw new ApplicationException("Unknown type " + value.GetType().FullName);
                    }
                }
            }

            var propertiesOffset = default(VectorOffset);

            if (memoryStream.Position > 0)
            {
                propertiesOffset = Feature.CreatePropertiesVector(builder, memoryStream.ToArray());
            }

            var geometryOffset = default(Offset <Geometry>);

            if (go.gos != null && go.gos.Length > 0)
            {
                var partOffsets = new Offset <Geometry> [go.gos.Length];
                for (int i = 0; i < go.gos.Length; i++)
                {
                    var goPart     = go.gos[i];
                    var partOffset = Geometry.CreateGeometry(builder, goPart.endsOffset, goPart.coordsOffset, default(VectorOffset), default(VectorOffset), default(VectorOffset), default(VectorOffset), go.type, default(VectorOffset));
                    partOffsets[i] = partOffset;
                }
                var partsOffset = Geometry.CreatePartsVector(builder, partOffsets);
                geometryOffset = Geometry.CreateGeometry(builder, default(VectorOffset), default(VectorOffset), default(VectorOffset), default(VectorOffset), default(VectorOffset), default(VectorOffset), go.type, partsOffset);
            }
            else
            {
                geometryOffset = Geometry.CreateGeometry(builder, go.endsOffset, go.coordsOffset, default(VectorOffset), default(VectorOffset), default(VectorOffset), default(VectorOffset), go.type, default(VectorOffset));
            }
            Feature.StartFeature(builder);

            Feature.AddGeometry(builder, geometryOffset);
            Feature.AddProperties(builder, propertiesOffset);
            var featureOffset = Feature.EndFeature(builder);

            builder.FinishSizePrefixed(featureOffset.Value);

            return(builder.DataBuffer.ToSizedArray());
        }