Softanza
DémarrerEnglish
Softanza
Visuel et spatial

Géographie et cartographie

Un moteur de cartes qui fait aussi la géodésie et les statistiques spatiales ; la plomberie SIG est la frontière.

5 Strong · 2 Solid · 4 Partial · 1 Emerging

Mesuré contre : D3-geo · GDAL · PostGIS · Cartopy · Dossiers : base/geo(s'ouvre dans un nouvel onglet) · Pour les programmeurs : la référence de ce domaine

où vit le Niger : une carte de densité à partir des frontières officielles et du recensement 2012
où vit le Niger : une carte de densité à partir des frontières officielles et du recensement 2012. re-rendue le 2026-09-30 à 23:09 en 5,9 secondes par le garde niger_density, identique à l'octet près à l'image commise · la source(s'ouvre dans un nouvel onglet)

Repensé depuis les premiers principes

Ce que Softanza a gardé de ce qui marche, et ce qu'elle a repensé, tel que la bibliothèque l'a écrit dans ses documents de conception et ses narrations.

La manière SoftanzaUne carte affirme des choses sur le monde : elle doit donc dire comment elle a été faite et ne rien affirmer qu'elle ne puisse vérifier.

Gardé des meilleures pratiques

  • Chaque carte passe par un même flux de traitement, repris de d3-geo (rotation, découpe sur la sphère, projection, rééchantillonnage, découpe au cadre) : aucune image ne peut sauter une étape. source(s'ouvre dans un nouvel onglet)
  • Les étiquettes suivent quatre règles de QGIS, Mapbox et ArcGIS : une étiquette est une boîte, les grandes régions d'abord, un nom qui ne tient pas va à l'extérieur, ou disparaît. source(s'ouvre dans un nouvel onglet)
  • Les dégradés sont les palettes ColorBrewer de Cynthia Brewer, écrites telles quelles plutôt que calculées : un dégradé calculé est un dégradé que personne n'a vérifié. source(s'ouvre dans un nouvel onglet)

Repensé

  • Aucune donnée de frontières n'est livrée. Un tel fichier prend parti sur les frontières disputées, vieillit en silence et impose une licence : chacun apporte ou télécharge la sienne. source(s'ouvre dans un nouvel onglet)
  • Une carte juge son propre raisonnement. Colorer des régions selon une valeur sur une projection qui gonfle les surfaces est signalé comme une erreur, car la couleur trahit la quantité. source(s'ouvre dans un nouvel onglet)
  • L'échelle graphique est tracée à une latitude indiquée, et refusée si l'échelle varie trop sur la feuille : une barre juste sur une seule ligne trompe partout ailleurs. source(s'ouvre dans un nouvel onglet)
  • Les noms de lieux sont rapprochés sans deviner. Une correspondance approximative est signalée, jamais coloriée, car colorier le Niger à la place du Nigeria est pire qu'un trou. source(s'ouvre dans un nouvel onglet)

A genuine standout: 44 self-inverting projections, full WGS84 geodesy, and a spatstat-class spatial-statistics engine ship together behind Haro faces, guarded by ~400 assertions and 72 negative controls. It is the rare library where the tool that draws the map also computes the statistics it shows and measures its own distortion — analysis-and-cartography strong, GIS-plumbing light.

Ce qu'un artisan en fait, et ce qui se distingue

  • 44 self-inverting projections with a solver that refuses a bad inverse
  • the tool that draws the map also computes the statistics and measures its own distortion
  • ordinary kriging with its variance surface
  • the Niger real-data map, vendor-free end to end

Ce qui est dû

  • vector geometry overlay algebra
  • source-CRS reprojection
  • a GeoJSON / TopoJSON writer
  • raster / DEM & GeoTIFF

La manière Softanza, exécutée

Ce que Softanza fait autrement dans ce domaine, montré par du code tiré de ses narrations et de ses gardes, et exécuté pour cette page.

Une carte colorée selon une valeur sur Mercator se signale elle-même en erreur, car la couleur parle alors pour des surfaces que la projection a gonflées.

Softanza
# the guard's fixture: two countries, in the caller's own file
oF = StzGeoFeaturesFromJson(read("../graphics/fixtures/two_countries.geojson"))
oBad = StzGeoMap(new stzGeoProjection(:Mercator), oF)
oBad.SetValuesQ([ 4200, 99999 ]).SetClasses([ 0, 5000, 20000, 30000 ])
aBad = oBad.Findings()
chk("A CHOROPLETH ON A PROJECTION THAT DISTORTS AREA IS AN ERROR -- it encodes " +
    "a quantity as the colour of an area, so the picture argues against its own legend",
    _HasRule(aBad, "choropleth_needs_an_equal_area_projection", "error"))
Sortie
  ok   A CHOROPLETH ON A PROJECTION THAT DISTORTS AREA IS AN ERROR -- it encodes a quantity as the colour of an area, so the picture argues against its own legend

exécuté le 2026-10-01 21:20 dans la bibliothèque au commit 0e72e2e2c ; tiré de base/test/graphics/geo_map_narrated.ring(s'ouvre dans un nouvel onglet)

Un tableau saisi à la main se rattache aux formes fournies par l'appelant ; un nom qui ne correspond à rien, ici Atlantis, est signalé et jamais deviné.

Softanza
# the guard's fixture: two countries, in the caller's own file
oF = StzGeoFeaturesFromJson(read("../graphics/fixtures/two_countries.geojson"))
oAt = StzGeoAtlas(oF)
aRows = [ [ "Arda", 10 ], [ "berea", 20 ], [ "Atlantis", 30 ] ]
aV = oAt.ValuesFor(aRows)
chk("A TABLE OF ROWS BECOMES ONE VALUE PER FEATURE, in the features' own order, " +
    "which is what the map takes",
    len(aV) = 2 and aV[1] = 10 and aV[2] = 20)
chk("...and what did not bind is ANSWERED rather than swallowed",
    len(oAt.Unresolved(aRows)) = 1 and oAt.Unresolved(aRows)[1] = "Atlantis")
Sortie
  ok   A TABLE OF ROWS BECOMES ONE VALUE PER FEATURE, in the features' own order, which is what the map takes
  ok   ...and what did not bind is ANSWERED rather than swallowed

exécuté le 2026-10-01 21:20 dans la bibliothèque au commit 0e72e2e2c ; tiré de base/test/graphics/geo_map_narrated.ring(s'ouvre dans un nouvel onglet)

Sollicitée pour une échelle graphique sur un planisphère Mercator, la carte refuse et répond 0, car aucune barre unique n'est juste sur toute la feuille.

Softanza
# the guard's fixture: one square, on a world Mercator map
oSq = StzGeoFeaturesFromJson(_FSquare())
oMe = StzGeoMap(new stzGeoProjection(:Mercator), oSq)
oMe.Projection().FitToSphere(900, 900, 4)
oC1 = new stzCanvas(600, 300)
oC1.SetBackground("#FFFFFF")
oFont = new stzFont("../gpu/fixtures/amiri_arabic_subset.ttf")   # a font the library commits
nDrew = oMe.DrawScaleBarOn(oC1, oFont, 12, 40, 200, 140, 0, "#333333")
? "   drawing a bar on a world Mercator returned " + nDrew
Sortie
   drawing a bar on a world Mercator returned 0

exécuté le 2026-10-01 21:20 dans la bibliothèque au commit 0e72e2e2c ; tiré de base/test/graphics/geo_furniture_narrated.ring(s'ouvre dans un nouvel onglet)

Les couloirs, un par un

Les couloirs et leurs notes sont cités tels qu'ils ont été lus à la source, le Read from the source on 2026-09-16, from a read-only main worktree (HEAD 04cff1c34).

Map projections
Strong
44 projections across five families, all with inverses; a shared 2D Newton solver refuses any inverse not round-tripping to 1e-6; rotate/clip/fit, UTMgeo_projection.zig; all-44 inverse round-trips
Geodesy
Strong
WGS84 + ellipsoid table, geodesic inverse/direct, rhumb lines, ECEF/ENU, DMS, meridian arc, polygon area on the ellipsoid with geodesic edgesgeo_geodesy.zig
Spatial statistics
Strong
Clark-Evans z-test, Ripley K/L/G/F with Monte-Carlo envelopes, IDW, variograms, ordinary kriging with variance surface, 7+ point-process null modelsgeo_stats.zig / geo_interp.zig / geo_process.zig; kriging-variance invariance guard
Thematic maps
Strong
Choropleth (equal-area default), proportional symbol, flow (great circles), hex-bin, bloc/membership, insets with a measured locator scalestzGeoMap
Map decorations & fields
Strong
Graticule, Tissot indicatrix on the same Jacobian, a scale bar that refuses to lie, north arrow, day-night terminator, even-spaced streamlinesgeo_furniture.zig
GeoJSON / TopoJSON I/O
Solid
stzGeoFeatures reads GeoJSON and TopoJSON with an engine-side filtered read (a 40 MB file yields only wanted features); read-only, no writerstzGeoFeatures
Atlas & real-data pipeline
Solid
stzGeoAtlas binds name->shape without vendoring data; the Niger real-data map (geoBoundaries ADM1 + RGPH-2012) is the cap; no fuzzy name matchingstzGeoAtlas; test/graphics/niger_density
Geometry & spatial ops
Partial
Haro area (planar/spherical/ellipsoidal), centroid, point-in-polygon, bounding boxes, spatial join; no buffer/intersection/union/convex hull
Source reprojection (CRS transforms)
Partial
Projections are a display transform (lon/lat in, pixels out); no source-CRS reprojection from UTM or a national grid
Raster & DEM
Partial
Scalar density fields, an ESRI ASCII grid reader, per-pixel resampled field image, marching-squares contours; no hillshade/slope/aspect, no GeoTIFFgeo_field.zig
Interactivity
Partial
Maps emit interactive SVG with per-region ids, classes and <title> hooks (SetInteractive, GE2c); no live pan/zoom, by plan the GUI plane's jobSetInteractive (GE2c)
Tiling & web maps
Emerging
None: no slippy-tile scheme, no tile server, no web-map basemap integration anywhere in the geo module