Lesson 3.2
FlatGeobuf
GEO5019.2025
Hugo Ledoux & Hidemichi Baba
FlatGeobuf
What is it?
Hugo Ledoux & Hidemichi Baba
oh wow!
FlatGeobuf
Hugo Ledoux & Hidemichi Baba
FlatGeobuf
especially interesting:
FlatBuffers + Geo + some bonus = FlatGeobuf
Hugo Ledoux & Hidemichi Baba
Recap serde
serializing and deserializing
similar meaning
Hugo Ledoux & Hidemichi Baba
Magic bytes
A file signature
Magic numbers, file signature, or magic bytes
Let’s read and write magic bytes in Python! (demo is here)
Go to ASCII table and see https://www.ascii-code.com/
Hugo Ledoux & Hidemichi Baba
Endianness (or "byte-order")
Little endian and big endian
Examples with the number 0x12345678 (i.e., 305 419 896 in decimal):
Little endian resembles the European data format (27 November 2025)
While big endian is like ISO format (2025-11-27)
Hugo Ledoux & Hidemichi Baba
FlatBuffers?
Hugo Ledoux & Hidemichi Baba
What is FlatBuffers?
One of the serialisation frameworks made by Google
“JSON not only has the obvious drawback of runtime inefficiency, but also forces you to write more code to access data (counterintuitively) due to its dynamic-typing serialization system.”
Why not JSON?
Hugo Ledoux & Hidemichi Baba
What is FlatBuffers?
How good is FlatBuffers?
Hugo Ledoux & Hidemichi Baba
FlatBuffers: Schema based serialisation
Steps to serialise
Example schema
namespace MyGame.Sample;
enum Color:byte { Red = 0, Green, Blue = 2 }
// Optionally add more tables.
union Equipment { Weapon }
struct Vec3 {
x:float;
y:float;
z:float;
}
table Monster {
pos:Vec3;
mana:short = 150;
hp:short = 100;
name:string;
friendly:bool = false (deprecated);
inventory:[ubyte];
color:Color = Blue;
weapons:[Weapon];
equipped:Equipment;
path:[Vec3];
}
table Weapon {
name:string;
damage:short;
}
root_type Monster;
Hugo Ledoux & Hidemichi Baba
FlatBuffers: data types
Supported data types
Tables: the main way of defining objects in FlatBuffers
Structs: consist of fields are required (so no defaults either), and fields may not be added or be deprecated
Other types
Scalars: fixed sized scalars
Hugo Ledoux & Hidemichi Baba
FlatBuffers: how do you encode variable length data?
Length prefix
Tables: the main way of defining objects in FlatBuffers
Hugo Ledoux & Hidemichi Baba
FlatBuffers + Geo + some bonus
= FlatGeobuf
Hugo Ledoux & Hidemichi Baba
What is FlatGeobuf?
How good is FlatGeobuf?
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: Convention of binary encodings
Two conventions for binary encoding of FlatGeobuf:
Q: What is the maximum size of a buffer?
(show example of bit shifting in Python)
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: File structure
How the file looks?
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: Magic bytes
Magic bytes
“ASCII F , G, B, followed by the spec major version (currently 03), then F,G,B again, then the spec patch version (currently 01).”
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: Header
Header
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: Header
For more detailed header schema, see their GitHub https://github.com/flatgeobuf/flatgeobuf/blob/master/src/fbs/header.fbs
Header content
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: Header
Feature
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: Features
Feature schema
table Feature {
geometry: Geometry; // Geometry
properties: [ubyte]; // Custom buffer, variable length collection of key/value pairs (key=ushort)
columns: [Column]; // Attribute columns schema (optional)
}
Feature
table Geometry {
ends: [uint]; // Array of end index in flat coordinates per geometry part
xy: [double]; // Flat x and y coordinate array (flat pairs)
z: [double]; // Flat z height array
m: [double]; // Flat m measurement array
t: [double]; // Flat t geodetic decimal year time array
tm: [ulong]; // Flat tm time nanosecond measurement array
type: GeometryType; // Type of geometry (only relevant for elements in heterogeneous collection types)
parts: [Geometry]; // Array of parts (for heterogeneous collection types)
}
Geometry
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: limitations: only single-dimensional array
How do you encode geometry?
“Nesting vectors is not supported, instead you can wrap the inner vector with a table.” (FlatBuffers, 2025)
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: limitations: only single-dimensional array
Point
Vertices are flattened
Geometry {
xy: [1,2],
z: [3],
type: 1
}
{"type":"Point","coordinates":[1,2,3]}
LineString
Geometry {
xy: [1,2,4,5]
z: [3,6],
type: 2
}
{"type":"LineString","coordinates":[[1,2,3],[4,5,6]]}
Polygon
Geometry {
// All coordinates from the ring flattened
// First coordinate is still repeated to close the ring as in WKT/GeoJSON/etc
xy: [-118.4765625,33.92578125,-118.125,33.92578125,-118.125,34.1015625,-118.4765625,34.1015625,-118.4765625,33.92578125]
type: 3
}
{
"type": "Polygon",
"coordinates": [
[
[-118.4765625,33.92578125],
[-118.125, 33.92578125],
[-118.125, 34.1015625],
[-118.4765625, 34.1015625],
[-118.4765625, 33.92578125]
]
]
}
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: limitations: only single-dimensional array
How about polygon with inner rings?
Polygon (1 outer, 1 inner ring)
Geometry {
// all coordinates from BOTH rings flattened
xy: [-118.4765625,33.92578125,-118.125,33.92578125,-118.125,34.1015625,-118.4765625,34.1015625,-118.4765625,33.92578125,-118.24447631835938,34.0521240234375,-118.24310302734375,34.0521240234375,-118.24310302734375,34.053497314453125,-118.24447631835938,34.053497314453125,-118.24447631835938,34.0521240234375]
// 1-indexed coordinate number for last point per ring
ends: [5,10],
type: 3
}
{
"type": "Polygon",
"coordinates": [
[
[-118.4765625,33.92578125],
[-118.125, 33.92578125],
[-118.125, 34.1015625],
[-118.4765625, 34.1015625],
[-118.4765625, 33.92578125]
],
[
[-118.24447631835938, 34.0521240234375],
[-118.24310302734375, 34.0521240234375],
[-118.24310302734375, 34.053497314453125],
[-118.24447631835938, 34.053497314453125],
[-118.24447631835938, 34.0521240234375]
]
]
}
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: limitations: only single-dimensional array
What about these?
CircularString = 8,
CompoundCurve = 9,
CurvePolygon = 10,
MultiCurve = 11,
MultiSurface = 12,
Curve = 13,
Surface = 14,
PolyhedralSurface = 15,
TIN = 16,
Triangle = 17
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: property encoding
enum ColumnType: ubyte {
Byte, // Signed 8-bit integer
UByte, // Unsigned 8-bit integer
...
DateTime, // ISO 8601 date time
Binary // General binary type intended to be application specific
}
We encode metadata of properties as `Column` table
table Column {
name: string (required); // Column name
type: ColumnType; // Column type
title: string; // Column title
description: string; // Column description (intended for free form long text)
…
}
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: property encoding
How do we encode a data structure that we can’t anticipate?
// Custom buffer, variable length collection of key/value pairs (key=ushort)
properties: [ubyte];
Just an array of bytes meaning we can embed anything we want
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: Spatial index
Spatial index
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: Binary search
Binary search
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: Feature sorting and spatial index
“Packed” R-Tree
Q:
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: Feature sorting and spatial index
Example of not “Packed” R-Tree
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: Feature sorting and spatial index
Hilbert ordering
Hilbert ordering
File layout
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: Feature sorting and spatial index
Steps to sort features and construct R-Tree
Hugo Ledoux & Hidemichi Baba
Why sorting feature matters?
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: CPU cache
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: Batching I/O
“features are hilbert-sorted before being indexed and written to allow for more efficient I/O batching when looking data up via the index” (Horace Williams, 2025)
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: HTTP access
Packed R-Tree + Hilbert ordering
Hugo Ledoux & Hidemichi Baba
What affects read performance over HTTP?
Hugo Ledoux & Hidemichi Baba
FlatGeobuf: limitations
Downsides
Hugo Ledoux & Hidemichi Baba
Great references
Hugo Ledoux & Hidemichi Baba
Examples
https://github.com/HideBa/geo5019-flatgeobuf-sample
Hugo Ledoux & Hidemichi Baba