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());
            }
        }
Exemple #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 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 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);