Skip to content

Releases: gsueur/geopq-workbench

v0.5.3

Choose a tag to compare

@github-actions github-actions released this 28 Jul 18:51

GeoPQ Workbench 0.5.3 makes the basemap a layer, and stops fetching
tiles for views you have already left.

The basemap is a layer now

It is the bottom layer of the map, so it belongs at the bottom of the
layers panel rather than in a menu. Its own row there: a visibility
checkbox, a list of every source, and an opacity slider.

Opacity is what a menu could never offer and what the basemap most
needs. It sits under your data, and fading it back is how you keep the
context without it competing with what you are actually looking at. It
persists with the rest of the layer context, and switching the basemap
off and on comes back to the source you had.

Tiles follow the view you are in

Zooming across several levels kept the earlier levels loading. The fetch
queue was a FIFO: every frame pushed its tiles onto the end, and the four
workers ground through the lot, so a zoom from z8 to z14 spent requests
on five views you had already left before it reached the one you were
looking at.

The queue is now replaced rather than appended to. Each pass writes
exactly what the current view wants, so anything queued for a view you
have left is dropped before a request is spent on it. Requests already in
flight cannot be taken back — a blocking read is not interruptible — but
there are at most four of those, and the tail is gone.

STAC collections grow as you pan

Parts were chosen once, at open, from whatever the viewport happened to
be, and the layer stayed frozen at that choice: pan somewhere else and it
showed nothing. Past sixteen intersecting parts the load refused outright
and told you to zoom in, so Overture's 512-part buildings collection could
not be opened from any view wide enough to want it.

A camera settle now looks for parts the viewport wants and the layer
lacks, opens up to eight of them — most-overlapping first, because a pan
should fetch what it is heading into before what it is only clipping —
and streams their geometry through the same path row refinement uses.

Fragments are numbered in global order, so appending them at the end
leaves every existing row-group index meaning exactly what it meant
before. That is what makes it cheap: the layer keeps the geometry and
decode state it already built, and the new parts simply extend the space.
No rebuild, no flicker.

Opening now takes the sixteen parts covering most of the view instead of
refusing. Measured against Overture: 512 parts, opens 16 with 80.4M rows,
and panning finds more to add.

Fixes

  • A failed tile marked for retry lost its attempt count, so the backoff
    restarted every time and a dead tile was re-requested every two seconds
    for the whole session, never reaching its attempt limit.
  • The basemap row sits at the foot of the layers panel instead of
    scrolling away with the list.

Install

Prebuilt binaries for macOS (Apple Silicon and Intel), Linux x86_64 and
Windows x86_64 are attached, each with a SHA-256 checksum. macOS builds
are signed and notarized.

v0.5.2

Choose a tag to compare

@github-actions github-actions released this 28 Jul 16:13

GeoPQ Workbench 0.5.2 draws the basemap in the projection your data
asked for, in the colours it was published in.

Tiles outside Web Mercator

The first layer picks an equal-area projection by default, and that was
exactly when the basemap disappeared: tiles were gated on the display
being Web Mercator, so a Lambert-93 view of a French city got no basemap
at all.

Tiles are square in Mercator and curved anywhere else, so each one is
now drawn as a subdivided mesh with its vertices projected exactly. The
error falls as O(h²) in the sub-cell size, adjacent tiles share the
vertices along their common edge so no seams open, and 128 triangles a
tile is nothing next to a vector layer.

What reprojection cannot fix is text. Place names are pixels in the
raster, so they shear with it and no amount of subdivision helps. So the
view is measured rather than assumed: sample the Jacobian of Mercator to
display across the viewport, and when the worst rotation passes 5° or
the worst anisotropy passes 1.2, fall back to the same style without
labels.

rotation drawn
Toulouse, Lambert-93, z12 1.2° labels kept
Europe, LAEA, z5 25.4° label-free

At world scale there is no honest answer, so tiles are refused and say
why: Mercator stops at ±85°, and a warped world map would leave a blank
cap over each pole, which is the one place an equal-area projection is
supposed to be truthful. The projected coastline overlay already covers
that view.

Tiles also carry a mip chain now, box-reduced in linear light, and the
sampler does 16x anisotropic filtering. Reprojection minifies a tile
several times over along one axis, roughly 1/cos²φ against a cylindrical
equal-area, so 4:1 at 60°N.

The dark basemap was black

Not a reprojection bug, and older than this release. The tile texture
was declared sRGB while the surface is Bgra8Unorm, so the sampler
decoded to linear and nothing ever re-encoded. Mid-grey 128 reached the
screen as 55. On a light basemap that reads as slightly flat; on the
dark one it is a black rectangle.

This affected every basemap in every release so far.

More basemaps

OpenTopoMap, Esri World Topo and Esri World Imagery, plus label-free
variants of all three Carto styles. Imagery carries no rendered text at
all, so it reprojects with none of the label caveats.

The Basemap menu also stops hiding sources. It used to drop a labelled
style whenever its label-free twin existed, which left no way to pick it
again; every source is listed, and when the one drawn differs from the
one picked the menu says so instead of substituting silently.

The basemap loads with the data, not after it

Tiles were never serialised behind the parquet read. The camera simply
sat on the whole world until the built layer arrived, and at world scale
there is nothing to fetch, so nothing was requested for the entire load
and then everything at once.

The extent is known from the row-group covering boxes the moment the
footer is read. The map is framed there before a byte of geometry is
decoded, so the basemap downloads alongside the data. The exact bounds
still refine the fit when the layer lands, and a file with no covering
stats behaves as before. The win scales with load time: seconds on a
local file, the whole download on a remote one.

Fixes

  • The cursor readout no longer prints the CRS name. Names like
    Auto: Albers equal-area (36.2°/45.8°) pushed the zoom, tile count
    and network readout off the right of the status bar; the projection
    selector in the corner already names it.

Install

Prebuilt binaries for macOS (Apple Silicon and Intel), Linux x86_64 and
Windows x86_64 are attached, each with a SHA-256 checksum. macOS builds
are signed and notarized.

v0.5.1

Choose a tag to compare

@github-actions github-actions released this 27 Jul 21:24

GeoPQ Workbench 0.5.1 stops remote reads paying for bytes nobody wanted.

Reading a remote file

Parquet reads a page header through a streaming read and takes the page
body through a bounded one. Every streaming read began with a fixed
256 kB window, so each column chunk cost 256 kB to consume about twenty
bytes of header. A 2 MB file cost 31 MB to read, and no amount of
row-group pruning could hide it.

The first window is now sized to what the caller actually asked for,
with a 4 kB floor, and doubles from there as before, so a consumer that
really does stream still reaches the ceiling in a handful of requests.
The last window fetched is also kept, so the bounded read that follows a
header is served from bytes already paid for instead of asking twice.

Measured on a viewport export of a sorted fixture, as a fraction of the
file read:

read
0.5.0 1458%
adaptive window 161%
plus the window cache 45%

This applies to every remote read, not only exports.

Exporting the current viewport

"Viewport only" read the whole file and filtered afterwards. On a remote
source that is the entire download for a handful of features. It now
prunes row groups from the same metadata boxes the viewer prunes with,
before reading a byte.

Panning a remote layer

Refinement resolves each intersecting row group against its bbox column,
one round trip apiece, and those ran one after another: twenty row
groups put several seconds between the camera settling and the first
byte of geometry being requested. They now resolve in parallel. The
budget still walks them in order, so which groups make the cut does not
depend on who answered first.

Install

Prebuilt binaries for macOS (Apple Silicon and Intel), Linux x86_64 and
Windows x86_64 are attached, each with a SHA-256 checksum. macOS builds
are signed and notarized.

Sample datasets

Sample datasets Pre-release
Pre-release

Choose a tag to compare

@gsueur gsueur released this 22 Jul 11:46

Synthetic sample GeoParquet files for trying the workbench (generated by testdata/regenerate.sh, no real-world data). Used by the in-app File > Open sample dataset menu; also fine to download directly. The points file is deliberately a raw unoptimized export so the quality scorecard and Optimize flow have something to show.

Runtime assets

Runtime assets Pre-release
Pre-release

Choose a tag to compare

@gsueur gsueur released this 22 Jul 12:33

Data fetched by the app on demand. ne_10m_coastline.bin: Natural Earth 1:10m coastline (public domain), packed in the app's NEC1 format by assets/make_coastline_bin.py, downloaded and cached the first time you zoom in far enough for the embedded 1:50m coastline to look coarse.