Skip to content

Releases: ObjectVision/GeoDMS

GeoDms 20.20.0

Choose a tag to compare

@MaartenHilferink MaartenHilferink released this 10 Sep 22:09
Immutable release. Only release title and notes can be modified.

GeoDms 20.20.0 covers everything since 20.17.0; the 20.18 and 20.19.x builds in between were interim pre-releases and their notes are folded in here. Headlines: a stored item is now read by an operator like any calculated item (#587), which is what lets a check refer to it and a fence hold it; a fifth polygon family of GeoDMS's own, dms_*, with exact arithmetic and no validity requirement (#1214); .mmd stores that read back where they used to promise data they did not hold (#1247, #1264, #1267, #1245); an attribute declared without a domain finds its unit through a grouping container (#1244); deadlocks that used to park a computation at 0% CPU now report themselves (#1233); a refused memory commit is an error on the item instead of an access violation per thread (#1269); the XML configuration notation reads back what the writer emits (#1261); and the teardown, allocation and connect work of the 20.19 line. The .g (GLOBIO) flavour ships alongside .m, .c and .l.

Flavour Asset
.m — Windows, MSBuild GeoDms20.20.0.m-Setup-x64.exe
.c — Windows, CMake GeoDms20.20.0.c-Setup-x64.exe
.g — Windows, GLOBIO compatibility GeoDms20.20.0.g-Setup-x64.exe
.l — Linux, Ubuntu 24.04 GeoDms20.20.0.l-linux-x64.deb, .tar.gz (+ .sha256, .sha256.p7s)

Test report

Things a modeller must act on

  • A ring's role is read relative to the first ring, not to the compass (#1212). The GEOS and CGAL readers judged each ring absolutely — shell iff clockwise — so a feature whose rings are uniformly counter-clockwise, which is what a source listing coordinates in latitude/longitude order gives you, lost its shell and promoted the lake behind it. Nothing was rejected and nothing was empty: ordinary-looking geometry with the wrong area. A configuration's areas may change on upgrade; the older numbers were the wrong ones. Measured on a real model in #1230: in the RSopen regression, 105,051 BAG building footprints stored counter-clockwise were read as empty and are now read correctly, while 232 CBS land-use polygons whose rings are only partly flipped were read 2,298 ha too large and now match their stored area. Both directions occur; a feature that is only partly flipped still needs fix_winding_order.
  • The two remaining composition deprecations become errors in GeoDms 21 (#1038), and say so: a declared ValueComposition that differs from the calculated one, and a geometry argument whose composition is not what the operator means. A (polygon) declared on a points2sequence result — which computes an arc — now writes a polyline layer through gdalwrite.vect, as it always silently did; the message tells you which item to fix.
  • A .mmd store written below a DisableStorage case parameter is refused at write time (#1245) rather than producing a store that fails in the reader with "Domain mismatch between the specified Domain (/store) and the domain of the results". TreeItem::Copy returned early for a case parameter before carrying the configured properties over, so the DisableStorage never reached the instantiated parameter, and the writer accepted the shape.

Storages

  • A stored item is read by an operator (#587). A table unit read from a storage gets the calculator storage_read_table(…) right after its storage manager's UpdateTree, its stored attributes subitem(<that key>, attr), and a stored parameter storage_read_value(…); every storage manager reads through these — shp, dbf, odbc, xyz, FSS, cfs, strfiles, tif, bmp/pal, gdal.grid and gdal.vect. A stored item thus has a raw key like a calculated one. Two things that were impossible before follow from that: an IntegrityCheck on a stored item may refer to that item (a self-referring check is not a supplier of the item it checks), and a PhaseContainer may fence a container holding stored members — it asks the item that carries the data whether a member is ready. The gdal.vect attributes of a table are read in one pass over its features; a stored member that its table's read does not name reads on its own.
  • A shapefile is written with closed rings. Both writers stored a polygon's rings exactly as the value held them, but a GeoDMS polygon need not repeat a ring's first point at the end and the ESRI specification requires it. gdal.vect — the engine's own default reader for the file it just wrote — refused such a file with "Non closed ring detected".
  • gdalwrite.vect recognises a geometry by its composition, not by the name geometry (#1232). A geometry column called anything else was measured against the driver's creation field types, so the write was refused with "driver ESRI Shapefile does not support writing of values" and the layer was created without a geometry field.
  • A layer's companion columns come into play at write time (#1229).
  • Missing VAT when exporting to dbf or gpkg (#973) — four separate defects, among them a native shapefile branch that compared against the wrong driver name and had been dead since 2023, with the resulting storage failure reported as "Export ready". A unit carrying an attribute of another domain exports as a table again (#1145).
  • Storage readers validate their input. Bytes from a shapefile, a GDAL layer, a TIFF, a DBF, a BMP or an xyz file were trusted through assertions that are optimiser assumptions in a Release build; a malformed file could read past a vector or overflow a buffer through a mismatching column type. Each such condition is now a check that names the file. The TIFF reader takes a missing SampleFormat from the configured type's category instead of reporting an unknown pixel type, and reads the ModelTransformation tag with the right width.

.mmd dictionaries

  • A store materialises every attribute it declares (#1247). Two items of one store can resolve to the same thing — an aliased table, an attribute repeating another's source, two items with one expression — and the store held such content once while the dictionary declared every claimant, so it promised data it did not have. The write exited 0; the failure surfaced on first use, possibly on another machine months later, as "Data not found in .MMD storage folder". An attribute whose rule names anything outside the store is now written.
  • A store-local rule is recorded as a rule, not as bytes (#1264). Where an attribute's rule names only identifiers inside the store, the dictionary carries the rule and the store holds no bytes for it; the reader re-applies it.
  • A tiled domain reads back (#1267). The dictionary recorded a domain by its Range alone, so a reader tiled it the default way — 65,536 per tile — and the per-tile .dat and .seq files no longer matched; a store over a TiledUnit could not be read at all. The tiling is now recorded as a rule.
  • A zero-length attribute file reads (#1246), and the dictionary's unit-range guard no longer takes an interest it then has to satisfy by starting a computation while it writes (#1266).

Polygons

  • The dms_* polygon family (#1214) — GeoDMS's own backend next to bp_, bg_, cgal_ and geos_: dms_intersect, dms_union, dms_xor, dms_difference for all six point types, plus dms_polygon, dms_union_polygon, dms_overlay_polygon, dms_polygon_connectivity and the two Minkowski operators. It does not require valid input: each sequence is read as one closed walk under the even-odd rule, so self-intersecting, self-touching, overlapping and unclosed rings all have a defined meaning. The dissolve nodes every element once on one lattice and finds crossings by an exact plane sweep, in the shape boost::polygon uses; on the 124,662 Amsterdam buildings it agrees with geos_ to 3·10⁻¹⁰ in area and runs in a fifth of the time.
  • Nesting-based winding-order operators (#302) on GEOS: fix_winding_order, fix_polygon, has_correct_winding, geos_polygons_by_nesting. #1219points2polygon no longer requires a closed ring the readers close themselves. #917 — Minkowski sums take the kernel as an argument, deprecating 48 bp_* names.

Allocation

  • A land use type that is no option no longer fails the allocation. Measuring the distance from optimum — which only builds the DiscrAlloc completed … status line — added the shadow price to an undefined suitability, where the bidding loop itself skips such a type. On a model with null suitabilities that ended the whole run with numeric overflow in the shadow price arithmetic. The same addition used to wrap silently, so a type that was never an option compared as a better bid: the "at most N from optimum due to M better options" figures have been wrong for such models for as long as they have existed, and are now right.
  • The Simulation-of-Simplicity perturbation range is checked once per run, before the solve starts rather than partway through an allocation.
  • discrete_alloc arithmetic audited (#1196). The claim aggregates were summed in UInt32: two land use types at the "no limit" maximum claim sum to exactly 2^32, read back as zero, and the run was rejected as infeasible — four cells are enough. Shadow prices go through checked arithmetic naming the component that overflowed, and six discrete_alloc_*_pi64 names offer a 64-bit perturbation.

Robustness

  • Deadlocks report themselves instead of parking (#1233). Each showed the same thing: a computation at 0% CPU, no error, no log line. The one that bit hardest is in deterministic tile accumulation, where a tile that unwinds — a read error, a cancellation, a failed allocation — advanced nothing and every later tile waited for it forever. Every function that acquires a lock now declares the outermost acquire it makes and is checked on entry against what the cal...
Read more

GeoDms 20.19.3

GeoDms 20.19.3 Pre-release
Pre-release

Choose a tag to compare

@MaartenHilferink MaartenHilferink released this 04 Sep 21:51
Immutable release. Only release title and notes can be modified.

Pre-release. GeoDms 20.19.3 covers everything since 20.16.0 — 20.17.0 was published, 20.18.0 through 20.19.2 followed. New in this release: a Release-build fault now leaves a minidump instead of a vanished window, a map view of an irregularly tiled grid no longer terminates the GUI when the cursor leaves the tiles, iif and its family keep the geometry composition of their arguments, and an .mmd store written below a DisableStorage case parameter is refused at write time rather than failing in the reader. Carried over from the 20.19.x line: three deadlocks that used to park a computation at 0% CPU now report themselves, connect accepts its two geometries the other way round and gains matrix variants, and the teardown and allocation fixes. The .g (GLOBIO) flavour ships alongside .m, .c and .l.

Flavour Asset
.m — Windows, MSBuild GeoDms20.19.3.m-Setup-x64.exe
.c — Windows, CMake GeoDms20.19.3.c-Setup-x64.exe
.g — Windows, GLOBIO compatibility GeoDms20.19.3.g-Setup-x64.exe
.l — Linux, Ubuntu 24.04 GeoDms20.19.3.l-linux-x64.deb, .tar.gz (+ .sha256, .sha256.p7s)

Allocation

  • A land use type that is no option no longer fails the allocation. Measuring the distance from optimum — which only builds the DiscrAlloc completed … status line — added the shadow price to an undefined suitability, where the bidding loop itself skips such a type before doing any arithmetic. On a model with null suitabilities that ended the whole run with numeric overflow in the shadow price arithmetic. The same addition used to wrap silently, so a type that was never an option compared as a better bid: the "at most N from optimum due to M better options" figures have been wrong for such models for as long as they have existed, and are now right.
  • The Simulation-of-Simplicity perturbation range is checked once per run instead of at every use, and reported before the solve starts rather than partway through an allocation.
  • discrete_alloc arithmetic audited (#1196). The claim aggregates were summed in UInt32: two land use types at the "no limit" maximum claim sum to exactly 2^32, read back as zero, and the run was rejected as infeasible — four cells are enough, no grid needed. Shadow prices now go through checked arithmetic naming the component that overflowed, and six discrete_alloc_*_pi64 names offer a 64-bit perturbation.

Robustness

  • Three deadlocks no longer park silently (#1233). Each showed the same thing to the user: a computation at 0% CPU, no error, no log line. The one that bit hardest is in deterministic tile accumulation, where every data tile waits for the result tile counter to reach its own number — so a tile that unwinds (a read error, a cancellation, a failed allocation) advances nothing and every later tile waits for it forever, taking the parallel_tileloop and its Join with it. Failure is now published and the waiters are woken. The lock inventory and the ceilings that make such orderings checkable are documented alongside (#1227, #1233), and every function that acquires a lock now declares the outermost acquire it makes — 207 declarations across the engine, checked on entry against what the caller holds. That made the remaining orderings checkable rather than argued, and turned up and fixed four more silent parks on the way (P5, P11, P13, P14).
  • A Release-build fault leaves a minidump (#1241). A structured exception used to leave nothing to debug: the handler ran only after Windows had unwound every frame between the fault and the __try, so there was no stack to capture, and the feedback child it spawned aborted before showing its message. The net effect was a window that vanished with no dump and no text. The dump is now written in the exception filter, while the faulting frames are still on the stack, by a parked writer thread on a stack of its own — which is what makes a stack overflow dumpable at all. One filter covers the GUI main thread, GeoDmsRun and the GDAL callbacks alike.
  • A map view of an irregularly tiled grid no longer terminates the GUI (#1242). Moving the mouse over a part of the viewport that no tile covers ended GeoDmsGuiQt with no message and no dump: the tooltip handed an out-of-range location to an index routine whose precondition the caller was meant to shield, and the tile lookup then walked off the end of the tile vector. Such a location now answers an undefined row, which a tiling that need not cover its own range makes a normal outcome.
  • GDALAllRegister is serialized (#1234). GeoDmsRun died with 0xC0000374 (heap corruption) or 0xC0000005, with no [E] line and part of the tif set already written, when ten gdalwrite.grid items with an aggregating IntegrityCheck were pulled by one ExplicitSuppliers trigger. The fallback registration for an extension with no known driver was the one path not taken under the GDAL section lock, and GDALAllRegister is not thread-safe.
  • A derived values unit stays alive (#1237). The single-argument area / arc_length / mls_length derives its result unit from the geometry's coordinate unit, but a data item holds its values unit only weakly, so that parentless unit was freed while still referenced.
  • A process no longer aborts at exit with a corrupted heap. Reporting the final allocator summary allocates, and allocating can post to the main-thread operation queue — which, by the time a static destructor of the same library runs, has itself been destroyed, so the post freed an already-freed buffer. The damage surfaced much later as an abort during process exit, with a stack naming an unrelated allocation. It cost roughly one run in ten on a loaded machine and nothing at all on an idle one; on Linux it aborted the GUI, on Windows the heap may absorb it silently. The summary now comes from an explicit terminate step while the process is still whole.
  • #1191 — what aborts the process is named, and the cancellation paths no longer abort it. #1206 — GDAL cleanup ordering at process shutdown. #1225 — a GUI closed with work abandoned no longer ends in uncaught DmsException: Cannot find Domain unit ..
  • #1226 / #1227 — the export dialog no longer hangs on a cold item: GetName() hands out a lock on the token registry, and holding it across a walk that parses an expression made the main thread wait for itself. That self-deadlock is now reported rather than parked on.

Polygons

  • A ring's role is read relative to the first ring, not to the compass (#1212). The GEOS and CGAL readers judged each ring absolutely — shell iff clockwise — so a feature whose rings are uniformly counter-clockwise, which is what a source listing coordinates in latitude/longitude order gives you, lost its shell and promoted the lake behind it. Nothing was rejected and nothing was empty: ordinary-looking geometry with the wrong area. A configuration's areas may change on upgrade; the older numbers were the wrong ones. What that means in practice is measured on a real model in #1230: in the RSopen regression, 105,051 BAG building footprints stored counter-clockwise — none of which has a hole, so nothing was left to promote — were read as empty and are now read correctly, while 232 CBS land-use polygons whose rings are only partly flipped were read 2,298 ha too large and now match their stored area. Both directions occur, so an area can grow or shrink; a feature that is only partly flipped still needs fix_winding_order.
  • Nesting-based winding-order operators (#302) on GEOS: fix_winding_order, fix_polygon, has_correct_winding, geos_polygons_by_nesting. #1219points2polygon no longer requires a closed ring the readers close themselves. #917 — Minkowski sums take the kernel as an argument, deprecating 48 bp_* names.

Storages and export

  • A shapefile is written with closed rings. Both writers stored a polygon's rings exactly as the value held them, but a GeoDMS polygon need not repeat a ring's first point at the end and the ESRI specification requires that it does. The result violated the format, and gdal.vect — which a .shp StorageName selects since 17.0.0, so the engine's own default reader for the file it just wrote — refuses such a file with "Non closed ring detected".
  • gdalwrite.vect recognises a geometry by its composition, not by the name geometry (#1232). A geometry column called anything else was measured against the driver's creation field types — and no OGR field type corresponds to fpoint, dpoint or spoint — so the write was refused with "driver ESRI Shapefile does not support writing of values", and the layer was created without a geometry field.
  • A layer's companion columns come into play at write time (#1229).
  • Writing vector layers (#711). gdalwrite.vect created a field for every storable attribute and left the rest <null> when only one column was of interest. A column of interest now pulls in the other columns of its layer for exactly as long as the outside interest lasts. A unit that both declares a SpatialReference and has a calculation rule no longer loses that CRS, so a shapefile gets its .prj again.
  • Missing VAT when exporting to dbf or gpkg (#973) — four separate defects, among them a native shapefile branch that compared against the wrong driver name and had been dead since 2023, with the resulting storage failure reported to the user as "Export ready".
  • A unit carrying an attribute of another domain exports as a table again (#1145).

.mmd dictionaries

  • DisableStorage below the holder is refused at write time (#1245). A template's case parameter declared DisableStorage = "True" and instantiated below an .mmd storage holder was written into the dictionary as a stored domain of its own, with the attributes beside it declared against that unit instea...
Read more

GeoDms 20.19.2

GeoDms 20.19.2 Pre-release
Pre-release

Choose a tag to compare

@MaartenHilferink MaartenHilferink released this 03 Sep 22:59
Immutable release. Only release title and notes can be modified.

Pre-release. GeoDms 20.19.2 covers everything since 20.16.0 — 20.17.0 was published, 20.18.0 through 20.19.1 followed. Headlines of this release: three deadlocks that used to park a computation at 0% CPU with no error now report themselves, connect accepts its two geometries the other way round and gains matrix variants, a shapefile is written with closed rings, and the teardown and allocation fixes of 20.19.1. The .g (GLOBIO) flavour ships alongside .m, .c and .l.

Flavour Asset
.m — Windows, MSBuild GeoDms20.19.2.m-Setup-x64.exe
.c — Windows, CMake GeoDms20.19.2.c-Setup-x64.exe
.g — Windows, GLOBIO compatibility GeoDms20.19.2.g-Setup-x64.exe
.l — Linux, Ubuntu 24.04 GeoDms20.19.2.l-linux-x64.deb, .tar.gz (+ .sha256, .sha256.p7s)

Allocation

  • A land use type that is no option no longer fails the allocation. Measuring the distance from optimum — which only builds the DiscrAlloc completed … status line — added the shadow price to an undefined suitability, where the bidding loop itself skips such a type before doing any arithmetic. On a model with null suitabilities that ended the whole run with numeric overflow in the shadow price arithmetic. The same addition used to wrap silently, so a type that was never an option compared as a better bid: the "at most N from optimum due to M better options" figures have been wrong for such models for as long as they have existed, and are now right.
  • The Simulation-of-Simplicity perturbation range is checked once per run instead of at every use, and reported before the solve starts rather than partway through an allocation.
  • discrete_alloc arithmetic audited (#1196). The claim aggregates were summed in UInt32: two land use types at the "no limit" maximum claim sum to exactly 2^32, read back as zero, and the run was rejected as infeasible — four cells are enough, no grid needed. Shadow prices now go through checked arithmetic naming the component that overflowed, and six discrete_alloc_*_pi64 names offer a 64-bit perturbation.

Robustness

  • Three deadlocks no longer park silently (#1233). Each showed the same thing to the user: a computation at 0% CPU, no error, no log line. The one that bit hardest is in deterministic tile accumulation, where every data tile waits for the result tile counter to reach its own number — so a tile that unwinds (a read error, a cancellation, a failed allocation) advances nothing and every later tile waits for it forever, taking the parallel_tileloop and its Join with it. Failure is now published and the waiters are woken. The lock inventory and the ceilings that make such orderings checkable are documented alongside (#1227, #1233).
  • GDALAllRegister is serialized (#1234). GeoDmsRun died with 0xC0000374 (heap corruption) or 0xC0000005, with no [E] line and part of the tif set already written, when ten gdalwrite.grid items with an aggregating IntegrityCheck were pulled by one ExplicitSuppliers trigger. The fallback registration for an extension with no known driver was the one path not taken under the GDAL section lock, and GDALAllRegister is not thread-safe.
  • A derived values unit stays alive (#1237). The single-argument area / arc_length / mls_length derives its result unit from the geometry's coordinate unit, but a data item holds its values unit only weakly, so that parentless unit was freed while still referenced.
  • A process no longer aborts at exit with a corrupted heap. Reporting the final allocator summary allocates, and allocating can post to the main-thread operation queue — which, by the time a static destructor of the same library runs, has itself been destroyed, so the post freed an already-freed buffer. The damage surfaced much later as an abort during process exit, with a stack naming an unrelated allocation. It cost roughly one run in ten on a loaded machine and nothing at all on an idle one; on Linux it aborted the GUI, on Windows the heap may absorb it silently. The summary now comes from an explicit terminate step while the process is still whole.
  • #1191 — what aborts the process is named, and the cancellation paths no longer abort it. #1206 — GDAL cleanup ordering at process shutdown. #1225 — a GUI closed with work abandoned no longer ends in uncaught DmsException: Cannot find Domain unit ..
  • #1226 / #1227 — the export dialog no longer hangs on a cold item: GetName() hands out a lock on the token registry, and holding it across a walk that parses an expression made the main thread wait for itself. That self-deadlock is now reported rather than parked on.

Polygons

  • A ring's role is read relative to the first ring, not to the compass (#1212). The GEOS and CGAL readers judged each ring absolutely — shell iff clockwise — so a feature whose rings are uniformly counter-clockwise, which is what a source listing coordinates in latitude/longitude order gives you, lost its shell and promoted the lake behind it. Nothing was rejected and nothing was empty: ordinary-looking geometry with the wrong area. A configuration's areas may change on upgrade; the older numbers were the wrong ones. What that means in practice is measured on a real model in #1230: in the RSopen regression, 105,051 BAG building footprints stored counter-clockwise — none of which has a hole, so nothing was left to promote — were read as empty and are now read correctly, while 232 CBS land-use polygons whose rings are only partly flipped were read 2,298 ha too large and now match their stored area. Both directions occur, so an area can grow or shrink; a feature that is only partly flipped still needs fix_winding_order.
  • Nesting-based winding-order operators (#302) on GEOS: fix_winding_order, fix_polygon, has_correct_winding, geos_polygons_by_nesting. #1219points2polygon no longer requires a closed ring the readers close themselves. #917 — Minkowski sums take the kernel as an argument, deprecating 48 bp_* names.

Storages and export

  • A shapefile is written with closed rings. Both writers stored a polygon's rings exactly as the value held them, but a GeoDMS polygon need not repeat a ring's first point at the end and the ESRI specification requires that it does. The result violated the format, and gdal.vect — which a .shp StorageName selects since 17.0.0, so the engine's own default reader for the file it just wrote — refuses such a file with "Non closed ring detected".
  • gdalwrite.vect recognises a geometry by its composition, not by the name geometry (#1232). A geometry column called anything else was measured against the driver's creation field types — and no OGR field type corresponds to fpoint, dpoint or spoint — so the write was refused with "driver ESRI Shapefile does not support writing of values", and the layer was created without a geometry field.
  • A layer's companion columns come into play at write time (#1229).
  • Writing vector layers (#711). gdalwrite.vect created a field for every storable attribute and left the rest <null> when only one column was of interest. A column of interest now pulls in the other columns of its layer for exactly as long as the outside interest lasts. A unit that both declares a SpatialReference and has a calculation rule no longer loses that CRS, so a shapefile gets its .prj again.
  • Missing VAT when exporting to dbf or gpkg (#973) — four separate defects, among them a native shapefile branch that compared against the wrong driver name and had been dead since 2023, with the resulting storage failure reported to the user as "Export ready".
  • A unit carrying an attribute of another domain exports as a table again (#1145).

.mmd dictionaries

  • Unit paths are absolute, in declarations and checks alike (#1195). A domain configured as ../RegioUnit went into the dictionary verbatim, so a reader merging that store elsewhere resolved the dots against its structure: Unknown identifier '../RegioUnit'. The store could then not be read at all.
  • A differing dictionary root name is provenance, not a warning (#1194), and a check that cannot be built now names itself (#1197).

IntegrityChecks and fences

  • A check now guards an item read from a storage (#1209) — such an item has no calculation rule, so consumers were handed an unguarded source reference and the check ran only after data preparation.
  • A check on an ExplicitSuppliers item guards the item that declares it (#1218). Selecting either item in the TreeView previously ran no check at all.
  • A phase runs when a member is reached (#1167), collecting a phase member is re-entrant (#1201), indirect expressions behind a fence are rejected (#1199), and the phase scan honours the static argument policy (#1224).

Charts and views

  • A new chart no longer waits for its own classification (#1221), position axes fit their data instead of forcing zero into view (#1222), row-number axes are labelled from the domain's Label attribute (#1207) and tick labels take the thousand separator (#1223).
  • Each chart kind has its own icon (#1211), the View and Window menus and window titles are drawn from the TreeView's icon set (#1220), and tree icons say what an item is (#319) rather than which views can be opened on it.
  • The active TreeView item is visible again (#1235). Selecting an item changed nothing on screen — no colour, no focus caret, not even the 2px border the delegate believed it was drawing, because the base style re-ran initStyleOption on its own copy and painted the background back over it.
  • Every DataView caption leads with the kind of view, and a missing SpatialReference is named (#1238). A map view whose world coordinate unit declares neither a SpatialReference nor a Label produced a caption starting with a bare ...
Read more

GeoDms 20.19.1

GeoDms 20.19.1 Pre-release
Pre-release

Choose a tag to compare

@MaartenHilferink MaartenHilferink released this 31 Aug 15:55
Immutable release. Only release title and notes can be modified.

Pre-release. GeoDms 20.19.1 covers everything since 20.16.0 — 20.17.0 was published, 20.18.0 and 20.19.0 followed, and this release adds a teardown fix that made a process abort at exit and an allocation fix that stopped discrete_alloc from failing on a land use type that is no option. The .g (GLOBIO) flavour ships alongside .m, .c and .l.

Flavour Asset
.m — Windows, MSBuild GeoDms20.19.1.m-Setup-x64.exe
.c — Windows, CMake GeoDms20.19.1.c-Setup-x64.exe
.g — Windows, GLOBIO compatibility GeoDms20.19.1.g-Setup-x64.exe
.l — Linux, Ubuntu 24.04 GeoDms20.19.1.l-linux-x64.deb, .tar.gz (+ .sha256, .sha256.p7s)

Allocation

  • A land use type that is no option no longer fails the allocation. Measuring the distance from optimum — which only builds the DiscrAlloc completed … status line — added the shadow price to an undefined suitability, where the bidding loop itself skips such a type before doing any arithmetic. On a model with null suitabilities that ended the whole run with numeric overflow in the shadow price arithmetic. The same addition used to wrap silently, so a type that was never an option compared as a better bid: the "at most N from optimum due to M better options" figures have been wrong for such models for as long as they have existed, and are now right.
  • The Simulation-of-Simplicity perturbation range is checked once per run instead of at every use, and reported before the solve starts rather than partway through an allocation.
  • discrete_alloc arithmetic audited (#1196). The claim aggregates were summed in UInt32: two land use types at the "no limit" maximum claim sum to exactly 2^32, read back as zero, and the run was rejected as infeasible — four cells are enough, no grid needed. Shadow prices now go through checked arithmetic naming the component that overflowed, and six discrete_alloc_*_pi64 names offer a 64-bit perturbation.

Robustness

  • A process no longer aborts at exit with a corrupted heap. Reporting the final allocator summary allocates, and allocating can post to the main-thread operation queue — which, by the time a static destructor of the same library runs, has itself been destroyed, so the post freed an already-freed buffer. The damage surfaced much later as an abort during process exit, with a stack naming an unrelated allocation. It cost roughly one run in ten on a loaded machine and nothing at all on an idle one; on Linux it aborted the GUI, on Windows the heap may absorb it silently. The summary now comes from an explicit terminate step while the process is still whole.
  • #1191 — what aborts the process is named, and the cancellation paths no longer abort it. #1206 — GDAL cleanup ordering at process shutdown. #1225 — a GUI closed with work abandoned no longer ends in uncaught DmsException: Cannot find Domain unit ..
  • #1226 / #1227 — the export dialog no longer hangs on a cold item: GetName() hands out a lock on the token registry, and holding it across a walk that parses an expression made the main thread wait for itself. That self-deadlock is now reported rather than parked on.

Polygons

  • A ring's role is read relative to the first ring, not to the compass (#1212). The GEOS and CGAL readers judged each ring absolutely — shell iff clockwise — so a feature whose rings are uniformly counter-clockwise, which is what a source listing coordinates in latitude/longitude order gives you, lost its shell and promoted the lake behind it. Nothing was rejected and nothing was empty: ordinary-looking geometry with the wrong area. A configuration's areas may change on upgrade; the older numbers were the wrong ones. What that means in practice is measured on a real model in #1230: in the RSopen regression, 105,051 BAG building footprints stored counter-clockwise — none of which has a hole, so nothing was left to promote — were read as empty and are now read correctly, while 232 CBS land-use polygons whose rings are only partly flipped were read 2,298 ha too large and now match their stored area. Both directions occur, so an area can grow or shrink; a feature that is only partly flipped still needs fix_winding_order.
  • Nesting-based winding-order operators (#302) on GEOS: fix_winding_order, fix_polygon, has_correct_winding, geos_polygons_by_nesting. #1219points2polygon no longer requires a closed ring the readers close themselves. #917 — Minkowski sums take the kernel as an argument, deprecating 48 bp_* names.

Storages and export

  • A layer's companion columns come into play at write time (#1229).
  • Writing vector layers (#711). gdalwrite.vect created a field for every storable attribute and left the rest <null> when only one column was of interest. A column of interest now pulls in the other columns of its layer for exactly as long as the outside interest lasts. A unit that both declares a SpatialReference and has a calculation rule no longer loses that CRS, so a shapefile gets its .prj again.
  • Missing VAT when exporting to dbf or gpkg (#973) — four separate defects, among them a native shapefile branch that compared against the wrong driver name and had been dead since 2023, with the resulting storage failure reported to the user as "Export ready".
  • A unit carrying an attribute of another domain exports as a table again (#1145).

.mmd dictionaries

  • Unit paths are absolute, in declarations and checks alike (#1195). A domain configured as ../RegioUnit went into the dictionary verbatim, so a reader merging that store elsewhere resolved the dots against its structure: Unknown identifier '../RegioUnit'. The store could then not be read at all.
  • A differing dictionary root name is provenance, not a warning (#1194), and a check that cannot be built now names itself (#1197).

IntegrityChecks and fences

  • A check now guards an item read from a storage (#1209) — such an item has no calculation rule, so consumers were handed an unguarded source reference and the check ran only after data preparation.
  • A check on an ExplicitSuppliers item guards the item that declares it (#1218). Selecting either item in the TreeView previously ran no check at all.
  • A phase runs when a member is reached (#1167), collecting a phase member is re-entrant (#1201), indirect expressions behind a fence are rejected (#1199), and the phase scan honours the static argument policy (#1224).

Charts and views

  • A new chart no longer waits for its own classification (#1221), position axes fit their data instead of forcing zero into view (#1222), row-number axes are labelled from the domain's Label attribute (#1207) and tick labels take the thousand separator (#1223).
  • Each chart kind has its own icon (#1211), the View and Window menus and window titles are drawn from the TreeView's icon set (#1220), and tree icons say what an item is (#319) rather than which views can be opened on it.
  • Editing a calculated class break, colour or label copies the values first (#634); a classification can be copied from one map view and applied in another (#734); the EventLog filter panel is no longer squeezed (#1213); the legend-width menu items name the keys that actually work (#1217). The main window's placement is recorded while it is up, so a session ending in a crash no longer restores a placement from days ago.

Networks

  • Bi-criteria (pareto) impedance_matrix (#856) — a second Dijkstra engine keeping the pareto-optimal set over two impedances instead of collapsing them into one weighted cost.
  • od:StartPoint_rel is written (#1210) — the member was created, allocated and committed but never filled, so requesting it yielded uninitialised memory. NYI since 2022.

Configuration language and diagnostics

  • The engine no longer reports case mix-ups about its own names (#1161). The regression battery emitted 2747 case warnings over 233 configurations with not one clean; ten of every eleven were the engine disagreeing with itself. unit, value, item, param, attr and nrofrows are now canonically lower case, chosen by census over 1146 .dms files. Battery: 2747 → 40 lines.
  • union_data warns when its arguments do not match the parts of its result domain (#990), the legacy brace range spelling is caught on either bound (#1165), and select_spec / collect_spec (#337) take their four choices as a ;-separated word list.
  • table_spec and stable sort_index helpers (#421); editor navigation into a template instantiation (#471); a worker thread's internal error names the item it was working on (#1202); a configuration can decide whether its hidden items are shown (#694).
  • Source Description covers what a storage feeds (#975), and the CalcCache machinery is retired (#1189) — a configuration still spelling %calcCacheDir% now gets an unknown-placeholder error.

Packaging and build

  • The .g (GLOBIO) flavour, built from the same solution with a committed GeoDmsGlobio switch against the older GDAL/GEOS stack, with its own output tree and vcpkg manifest. Install it only where that stack is required; .m remains the ordinary Windows build.
  • The VS Code extension ships with the setup, and the editor language definitions are generated from the operator registry: 23 names that no longer resolved to anything registered were removed.
  • Multi-version Python bindings (#1105), and #1186 — the .c setup now ships the MSVC runtime instead of borrowing whatever redistributable happened to be in System32.
  • Every text blob in the repository is stored with LF. Source only; nothing about the shipped binaries changes.

GeoDms 20.17.0

Choose a tag to compare

@MaartenHilferink MaartenHilferink released this 23 Aug 01:46
Immutable release. Only release title and notes can be modified.

Pre-release. GeoDms 20.17.0 follows 20.16.0 with a round of .mmd storage fixes — a dictionary written by one configuration and read by another now actually reads — plus fence, teardown and provenance work.

Flavour Asset
.m — Windows, MSBuild GeoDms20.17.0.m-Setup-x64.exe
.c — Windows, CMake GeoDms20.17.0.c-Setup-x64.exe
.l — Linux, Ubuntu 24.04 GeoDms20.17.0.l-linux-x64.deb, .tar.gz (+ .sha256, .sha256.p7s)

.mmd dictionaries

The restrictions that a dictionary carries were introduced one release ago. Reading such a store back into a different configuration — the whole point of the decoupling pattern — turned out to fail in three separate ways.

  • Unit paths are now absolute, in declarations and checks alike (#1195). The restriction spelled each unit with the raw configured token, and so did the declaration beside it, so a domain configured as ../RegioUnit or (...) went into the dictionary verbatim. A reader merges that dictionary somewhere else in its own tree, where the dots resolve against its structure and land on whatever sits there: Unknown identifier '../RegioUnit', or Cannot find operator for these arguments: arg1 of type TreeItem. The store could then not be read at all — not even where the declaration itself resolved fine. A bare name had the same defect more subtly, binding by up-scope search to whatever the reader declares under that name. Both check and declaration now come from one source and are written as the full path for every unit declared outside the dictionary. Where typed bound literals are emitted, the redundant PropValue(u, 'ValueType') term is dropped: a changed value type already fails the bounds term.
  • A differing dictionary root name is provenance, not a warning (#1194). The root name in 0Dictionary.dms is the name of the container that wrote the store, and a reader names its own container after the read step, so in the decoupling pattern the two differ by construction — and the writing project need not even be the same project. Silencing it by adopting the writer's name is impossible as soon as one file is read into more than one place. One ordinary session produced six such warnings before anything was calculated, which is how people learn to skim past warnings. It is now a trace line that says which name is the writer's and which the reader's.
  • A check that cannot be built now names itself (#1197). An IntegrityCheck whose operator or identifier does not resolve failed with the operator's own message and nothing else — eq Error: Cannot find operator for these arguments — with no word that a check was involved, let alone which one. That matters most for the restriction a dictionary carries, since it appears nowhere in the configuration. A check that merely evaluates to false already reported itself.

Writing vector layers (#711)

gdalwrite.vect writes a layer as a whole, but when only one column was of interest it created a field for every storable attribute and left the rest <null>. A column of interest now pulls in the other columns of its layer for exactly as long as the outside interest lasts, and field creation follows what is actually written: no field for a column without data, and an explicit error for drivers such as CSV that fix their fields at the first feature.

A unit that both declares a SpatialReference and has a calculation rule lost that CRS once its referred item was resolved, so a shapefile got no .prj and a GeoPackage got srs_id "Undefined". The declared CRS is now part of the unit's key expression.

Fences and scheduling

  • A phase runs when a member is reached (#1167). A PhaseContainer was executed only when its container was reached, so a configuration that reaches members at update level — the Ready + ExplicitSuppliers driver idiom, which is all GeoDmsRun ever produces — walked straight past the fence: the work ran unfenced and the phase reported nothing while still paying for its mirror tree.
  • Collecting a phase member is re-entrant (#1201). With the whole result sub-tree no longer supplied, a completed phase re-emplaced its resource on the next demand and re-collected members that already carried a result — which recalculates the source. That is the shape a for_each produces when its generated items each consume one member of the same phase.
  • An indirect expression keeps what it refers to. It is calculated in place and then dropped, and everything it read is dropped with it, so the next evaluation recalculates all of it. Where a PhaseContainer is among those suppliers that means re-running the whole fence: every phase in one test configuration ran and reported four times over.
  • Teardown drain is bounded (#1191). An item still of interest when the tree is torn down held the session usage count above zero with every worker already idle, so the process parked in an untimed wait. The drain now gives up and reports what is still holding it.

Elsewhere

  • Source Description covers what a storage feeds (#975). A storage was listed only for the item literally carrying StorageName; its sub-items and everything computed from them showed an empty page. The storage relation is not a supplier relation, so it is now resolved per item — itself when it holds the manager, else the nearest storage parent it reads from or writes to.
  • Tree icons say what an item is (#319), instead of which views can be opened on it. That mismatch is why a unit with sub-items drew as a container, an empty container drew as a base unit, and class-break attributes drew as plain attributes.
  • select_spec / collect_spec (#337) take the four choices that select_with_attr_by_xxx encodes in its name as a ;-separated word list in their first argument, including the new ref reach that follows a template case parameter's binding. Adding the reach as names would have cost 51 of them. The named operators are unchanged and now share one code path.
  • The CalcCache machinery is retired (#1189). The automatic disk cache of the GeoDMS 7 series was retired with 8.0, but its name survived in a form that reads as current mechanism — most damagingly the versioned %calcCacheDir% default, which cost real investigation time on a report of cold/warm run differences that were the filesystem cache. A configuration still spelling %calcCacheDir% now gets an unknown-placeholder error.
  • The Terminate button no longer clips its own label (#1192).

Test report

GeoDms 20.16.0

Choose a tag to compare

@MaartenHilferink MaartenHilferink released this 21 Aug 18:37
Immutable release. Only release title and notes can be modified.

Pre-release. GeoDms 20.16.0 is the first release since 20.12.0, and it is a large one. An external model — an R or python script — can now be driven from a configuration as an ordinary supplier, with its output in the event log and its place in the calculation order guaranteed (#659). An IntegrityCheck on a container or unit finally guards the items underneath it (#1180), which is the change most likely to be noticed in an existing configuration. MMD storages now record and verify what they hand back, so a store read into the wrong domain fails instead of returning a plausible wrong answer (#1154, #1187). The GUI no longer goes "(Not Responding)" during a long computation (#1156), starts with an empty project, and got a round of long-standing usability fixes. Grid mapping / mapping_count gained a separable fast path (#298), and a sweep over the registered operator list turned up several names that silently produced wrong or empty results.

Flavour Asset
.m — Windows, MSBuild GeoDms20.16.0.m-Setup-x64.exe
.c — Windows, CMake GeoDms20.16.0.c-Setup-x64.exe
.l — Linux, Ubuntu 24.04 GeoDms20.16.0.l-linux-x64.deb, .tar.gz (+ .sha256, .sha256.p7s)

Read this first: what can start failing after the upgrade

Several changes turn silence into a message. That is the point of them, but it means a configuration that ran clean on 20.12.0 can stop on this build:

  • An IntegrityCheck on an ancestor is now evaluated when an item below it is read. A check that was never actually enforced — because nobody requested the item carrying it — starts firing, and it fails the read.
  • An MMD store whose length does not match the domain it is read into is now refused, as is a store whose dictionary restrictions no longer hold.
  • An IntegrityCheck configured on an item below a storage holder is refused at write time, with a message pointing at the holder.
  • A point range spelled {row, col} still parses, but now emits a depreciation warning naming its xy(x; y) replacement.
  • CalcRule = "" (or the deprecated Expr = "") warns where it used to be accepted in silence.

Driving an external model from a configuration (#659)

Running Rscript or python from a configuration over exec_ec plus files already worked, but two things made it unusable in practice, and both are fixed.

The child process inherited our standard handles. Under GeoDmsGuiQt, which has no console, a failing script therefore left nothing behind but an exit code — no message, no traceback. The child now gets one inheritable pipe carrying both stdout and stderr, and whatever arrives is reassembled into lines and reported as exec: <line> under the commands message category. Reporting is capped at 1 MB, after which the pipe is still drained — not draining it would block the child once the buffer fills — with a single warning saying so. A redirection inside the command itself still wins, so an existing dir *.shp > dirinfo.str behaves as before. Implemented on both platforms: CreatePipe with PeekNamedPipe-gated reads on Windows, pipe() plus posix_spawn file actions with a poll()-driven non-blocking read on Linux.

The wait was a single infinite WaitForSingleObject, which left no room to drain that pipe and made a multi-minute child indistinguishable from a hang. It is now a 500 ms tick that drains the pipe and reports exec: still waiting for <program> after <n> seconds every ten seconds.

The ordering half. A stored item with no calculation rule collected only its calculation suppliers and its domain/values-unit futures as prerequisites of its read. Its configured ExplicitSuppliers were honoured by actor-level visitation but never entered that future list, so a read could race ahead of the supplier still producing the very file to read — measured at two seconds ahead, with a gdal.vect read of a parquet file starting before the exec_ec that runs the python writing it. PrepareDataRead now makes each ExplicitSupplier's future a prerequisite of the read.

That makes a full write → exec_ec → read round trip orderable as ordinary suppliers within one run, with the whole chain under interest up front. On a 13-step model coupling, per-step time went flat at 13–16 s instead of growing from 79 s to 188 s, total 6 minutes instead of 33, and peak commit 27.6 GB instead of 67.6 GB. At full scale the same chain runs at a constant ~120 s per step where the meta-scripted equivalent needed hours and 327 GB.

IntegrityChecks now guard the items below them

An ancestor's check applies to its descendants (#1180). Using a nested item did not validate its ancestors, so an IntegrityCheck on a container or unit only ever fired when that item was itself requested. Reading anything underneath it succeeded and delivered exactly the data the check was written to gate — silently, which is the worst of the three possible behaviours. Visiting a check and enforcing it are separate concerns, so this took two halves: VisitSuppliers now walks self and ancestors, making an ancestor's checker part of the item's dependency graph — scheduled, and with cycles detected rather than hidden — and the validate phase evaluates the item's own check while the ancestors' verdicts arrive through the tree structure, the parent being validated first.

A check that reaches into its own subtree closes a cycle and is reported as a circular dependency. It always was one whenever the item carrying it was requested, so such a check could never be relied upon.

Making that affordable (#1182). Folding every ancestor check into the items below it means a single check on a root container multiplies over the whole configuration: one test configuration applied the integrity_check operator 3393 times. The set of conditions an expression is certain to evaluate is now memoized per DataController and derived once per node, as an explicit-stack post-order walk that stops at nodes already carrying a set — exact at any depth, where the first attempt was depth-bounded and lost sight of the guard exactly where configurations are deepest. A 25-link reference chain under one ancestor check now yields one integrity_check DataController instead of 25. Conditions are compared per conjunct rather than as whole expressions, so a && b normalises the same way however it is nested.

Debug builds run these configurations again (#1181). Four sites in the lookahead estimation and reporting instrumentation called accessors whose Debug preconditions — meta thread, being the range item, holding interest — an estimator or reporter cannot guarantee, so every Debug run whose operator produced a data item died on an assert. Each now uses an accessor whose contract it can honour. Two of them were also wrong in Release: the tiling was read from a delegating unit's own empty slot, so the estimator missed the actual tiling.

MMD storages: say what is stored, and verify it

The dictionary records restrictions on external units (#1154). An .mmd dictionary references a unit declared outside the storage by name only, which re-resolves against whatever the reading configuration declares under that name. When that declaration changed since the write — an fpoint that became a dpoint — the reader silently bound the new element type to the old bytes. The dictionary root now carries a synthesized IntegrityCheck restricting every unit that is referenced by a stored attribute but declared outside the dictionary: its ValueType always, and for an external domain its extent as well when the range is known at emission. Merged onto the read holder, those restrictions guard every sub-item read through it via the ancestor fold above.

A stored array must match its domain (#1187). An MMD attribute is a keyless positional array; its element count comes from the domain the reader binds to, never from the file. The mapping call only noticed a file that was too short, and then as an access-denied error naming neither the domain nor the sizes. A file that was too long was accepted silently: the requested capacity was clamped down to the file, the surplus dropped, and the first N elements handed out as if they belonged to this domain — values attached to the wrong elements while every total stayed plausible. That is how a production run produced a wrong but credible answer, reading 11,008,492 cached elements into a domain of 11,007,909. The read path now compares the file length against the very function the write path sizes the file with, and throws an error naming the storage, both sizes, the element count and the tile count. It applies to stores whose dictionary carries no restriction at all, i.e. to everything written by earlier versions.

Restrictions on MMD content belong on the common ancestor (#1179). An IntegrityCheck on a stored sub-item derailed the write session: the data file was produced, but the dictionary was never written and the whole storage read back empty — silently, with exit code 0. The rule is now explicit and enforced on both sides. On write, a check on any item below the storage holder is refused loudly before any file is produced, with a message directing to the holder; a check on the holder itself works and writes the dictionary normally. On read, a read-only holder that declares sub-items or carries a reader-declared check is refused, because the sub-items and restrictions of a read holder come from the dictionary — previously a dictionary-supplied property silently replaced the reader's.

Points state their coordinate order (#1155, #1165)

A textual point was rendered as a bare pair whose order the reader had to guess, and the two halves of the product guessed differently: the range property and the Range entry of a dictionary wrote {row, col}, while the Range row of the detail pages applied a shuffle and wrote {col, row}. The sam...

Read more

GeoDms 20.12.0

Choose a tag to compare

@MaartenHilferink MaartenHilferink released this 09 Aug 11:19
Immutable release. Only release title and notes can be modified.

GeoDms 20.12.0 rolls up everything since 20.8.0 and supersedes the 20.9–20.11 pre-releases.

Headlines:

  • user-defined functions in the DMS language,
  • free-store drainage (memory pressure now returns freed memory to the OS),
  • a CRS/metric decoupling of the unit system, and
  • a batch of new and repaired operators including voronoi.
Flavour Asset
.m — Windows, MSBuild GeoDms20.12.0.m-Setup-x64.exe
.c — Windows, CMake GeoDms20.12.0.c-Setup-x64.exe
.l — Linux, Ubuntu 24.04 GeoDms20.12.0.l-linux-x64.deb, .tar.gz (+ .sha256, .sha256.p7s)

Language: user-defined functions

The DMS language now has typed, user-defined functions — from plain helpers to higher-order composition:

  • function definitions with typed signatures, applied inline or via instantiate/apply; anonymous function literals as arguments.
  • Generic type variables with constraints, type aliases and refinements, type-dependent overloading (variants), partial application, map(F, src) over containers — including map(F(k, _), src).
  • Container/record types as parameters: structured unit<...> { ... } parameters with typed members, checked at definition time.
  • Definition-time type checking of function bodies, so mistakes surface when the function is defined, not when a run finally reaches it. GeoDmsRun @checkfunctions audits every definition in a config; @dumpconfig round-trips the parsed config to DMS text.
  • The old RewriteExpr.lsp rule base is largely retired in favour of a typed prelude written in the language itself, auto-imported as the outermost namespace.

Design and status: typed-hof-language-design, type-declaration-forms, operator-signature-interface, typed-hof-remaining-work. A ~260-config regression battery ships with the installers under examples/testcases.

Memory: free-store drainage (on by default)

Freed object stores used to stay on the allocator's free stacks for the rest of the run — measured at 112 GB of retained-but-dead pool on a large allocation workload. Under memory pressure they are now decommitted back to the OS: array-wide, budgeted, largest classes first, with a keep-hot reuse band so steady-state performance does not pay for it. On the RSopen benchmark this cut peak commit charge from 193.5 GB to ~180 GB, leaving the peak bounded by genuinely live data.

Control: MemoryDrainage setting (default on), /SF / /CF switches; the trigger is MemoryFlushThreshold (default 80% of allowed RAM — note MemoryMaxRAM_GB defaults to 64, raise it on bigger machines). Full measurement trail: schedule-with-lookahead §8.1.

Scheduling: resource-aware admission (available, off by default)

The engine can now estimate each operation's memory impact, keep a ledger, and defer memory-adding work when a budget would be exceeded — with drainage coupled in, so a task waiting for memory actively frees it. Measured honestly: on the workloads tried it does not lower live-bound peaks (§8.1.29–8.1.32 document why), so it stays off by default. ResourceAwareScheduling = 1 (/Sq) logs what it would do; 2 (/SQ) enforces. The estimation work also produced always-on allocation accounting and per-operator working-memory estimates (GEOS buffers, connectivity, matrices).

Units: CRS decoupled from the metric

A projection/CRS is now a first-class value on a unit, decoupled from the linear metric — stages 0–7 of crs-metric-decoupling: CrsUnit operator, derivation rules, unification with a projection fallback, background-layer registry keyed by CRS, and retirement of the old 0xFF-packed side table. Fixes the class of "area(geom, m2) rejects a CRS-tagged metric" problems at the root.

Operators: new and repaired

  • voronoi(points, extentUnit) — new: the Thiessen cell polygon per point, clipped to the extent unit's range. wiki/voronoi
  • triangualize(points) — was registered but unimplemented (silently empty); now returns the Delaunay edge network as a unit<uint32> with F1/F2. wiki/triangualize, #1172
  • bp_buffer_multi_point, cgal_buffer_linestring, cgal_buffer_point — all three silently returned empty results (winding mismatch, wrong algorithm, mis-registration); fixed. #1172
  • greedy_alloc / needy_alloc — greedy aborted after solving; both are now real allocation regimes with aggregate (_np) variants. #1171
  • frequency_table_with_null — nulls now counted in the total and preserved across tiles; plus new as_unique_list_with_null. #1170
  • perimeter — accumulated into uninitialised memory. #1169
  • min_ifdefined / min_alldefined (and max variants) — new aggregations. #597
  • discrete_alloc and the Dijkstra/connect families got name-directed, typed result members.

Fixes

  • Linux: every startup segfaulted before main (static-init order); two GCC-only compile errors. Both from 20.11.0, fixed in 20.11.1.
  • GUI: +/- and mouse-wheel zoom in the map view (#1129), TableView follows TreeView text colors (#1159), storage of .mmd-backed units in the detail page (#1143), crashes on template-internal generic items, a glyph-cache corruption from a dangling font-name pointer.
  • Language/engine: value types print lowercase (#1161), nested function bodies reach enclosing parameters (#1166), generic domain-point constraints (#1163), boost::format fully replaced by std::format (#1164), unknown string escape codes now warn (#292), rate-limited EmptyWorkingSet storm on large-RAM machines.

Build

One version source of truth (GeoDmsVersion.cmd) for C++, batch and CMake; ISO 8601 buildstamps. One vcpkg world for MSBuild, CMake and IDE builds (shared binary cache, downloads root and pinned tools), with pre-build drift tripwires so an ABI change announces its rebuild cost up front instead of an hour in. prelude.dms is packaged in all three setups (the root cause of the 20.9.0.m unit-test failures).

Test report

GeoDms 20.8.0

Choose a tag to compare

@MaartenHilferink MaartenHilferink released this 15 Jul 13:27
Immutable release. Only release title and notes can be modified.

GeoDms 20.8.0 is a large engineering release. The headline is an object-ownership refactor — the TreeItem / data-item family moved from intrusive reference-counting onto standard std::shared_ptr / std::weak_ptr, closing a class of teardown hangs, exit leaks and use-after-frees. Alongside it are a broad build & compile-time modernization (precompiled headers, std::format, a large boost reduction down to a handful of header-only libraries, a three-DLL merge), a Qt 6.11 upgrade, a big Linux/GCC warning cleanup, expanded Python bindings, and a set of view, operator and storage fixes.

The sections below cover everything since 20.3.0 — the 20.4 / 20.5 / 20.6 / 20.7 builds were internal and not published as GitHub releases.

Builds are provided at the same source revision in three flavors:

Flavor Platform Asset
.m Windows x64 (MSBuild) GeoDms20.8.0.m-Setup-x64.exe
.c Windows x64 (CMake) GeoDms20.8.0.c-Setup-x64.exe
.l Linux x64 (WSL / Ubuntu 24.04) GeoDms20.8.0.l-linux-x64.deb (+ .tar.gz)

🧬 Object-ownership refactor (internals)

  • The TreeItem / data-item family was migrated from intrusive SharedPtr / WeakPtr onto standard std::shared_ptr / std::weak_ptr, with an explicit parent-owns-child model and non-owning std::weak_ptr back-references.
  • Fixed a class of ownership bugs surfaced by the migration: several teardown drain hangs, memory leaks reported at exit, cache-unit liveness use-after-frees, move-assignment lock leaks (ItemWriteLock / DataWriteLock / DataReadLockAtom), and interest-at-destruction leaks that hung GUI close.
  • Fixed a GUI exit deadlock: open map views and value-info windows are now destroyed before the shutdown drain waits on the item interest they hold (previously their deletion was deferred past the drain, hanging test-script and app-exit teardown — reproducibly so on Linux).
  • Debug unit tests now exit cleanly; headless Debug runs surface asserts and leak dumps without modal abort() dialog stalls.

🏗️ Build & compile-time modernization

  • Precompiled headers enabled for the 8 DLL projects.
  • boost::formatstd::format; broad boost reduction (random / locale / tuple / mpl / core / preprocessor → std / native); boost_thread eliminated (Spirit parsing serialized behind a single mutex); boost::signals2 replaced by a ~100-line synchronous Signal<> (drops ~1100 transitive headers from 29 view-DLL translation units).
  • The boost dependency narrowed to 11 header-only libraries actually used; GeoDMS links zero compiled boost, and the installed boost runtime DLLs went from 37 to 15 (the remainder are CGAL / asio package dependencies).
  • rtc + sym + tic merged into a single DLL (DmRtc / Rtc.dll); source tree flattened accordingly.
  • clc: the four largest translation units split per value-type for faster, more parallel builds.
  • On-demand MSVC /analyze (PREfast) pass (analyze.bat); fixed the intermittent vcpkg runtime-DLL deploy gap for good (both a stray machine-wide vcpkg integration and an IncrementalClean bookkeeping asymmetry that reaped the GDAL/GEOS/PROJ runtime DLLs on certain build sequences).

🐧 Linux / GCC

  • Warning cleanup from ~67k down to a few hundred, fixing a handful of latent bugs along the way (a delete[] of void*, a pointer-vs-literal comparison, a 16-bit truncation, a 1 << 63 shift overflow, an always-false IsInTrans()).
  • Self-contained Linux package — the .l setup bundles the Qt6 runtime with an $ORIGIN rpath, so the GUI runs without a system Qt6 install.
  • Fixed an exit-time SIGABRT after GDAL write sessions (the GDAL cleanup atexit hook is now Windows-only; on Linux it ran after GDAL's own teardown).
  • Missing-#include and link fixes that GCC surfaces but MSVC hides.

🖥️ Qt & Python

  • Qt upgraded to 6.11.1.
  • Python bindings: primary-data accessors, InMemoryConfig functions, an example and binding test scripts; the CMake build now ships Python 3.13.

🗺️ View & interaction

  • #515: overview zoom-out limited to the background / world extent.
  • #1151: drag sliders widened to 8 px (was 5 px).
  • #1150: table resize works after Toggle Rows/Cols; honest, non-sticky resize cursors; added untoggled row-height resize.
  • #1149: statistics copy-to-clipboard now starts with an Item name <path> row (and fixes a ReplaceChar infinite loop).

🔧 Operators, storage & fixes

  • #1152: items whose storage turns out to hold no primary data now fail with a clear error instead of lingering non-ready and non-failed.
  • #411: the table-view export button opens the Export Primary Data dialog (adds XML format) and reports export failures.
  • #367: internal file:// UNC encoding is converted to native paths at the GDAL / cfs boundaries.
  • #1146 / #1148: actionable errors on export-meta self-reference instead of recursing; force a 0 class-break when signed data straddles zero.
  • #1124: MetaInfo sidecar diverted to <stem>.meta.<ext> when it would collide with the dataset; GML classified as non-updatable.
  • Removed long-obsolete operators (format / unprefixed boost::polygon / non-DPoint GEOS).

https://geodms.nl/tests/reports/20_8_0_c___16_0_5.html

GeoDms 20.3.0

Choose a tag to compare

@MaartenHilferink MaartenHilferink released this 21 Jun 23:33
Immutable release. Only release title and notes can be modified.

GeoDms 20.3.0's headline is interactive view rotation and tilt in the MapView — the map can now be yawed and tilted into an oblique / perspective view, with horizon-aware rendering across raster, WMS background, polygon, arc and graticule layers, plus OGR Parquet/Arrow/Feather support.

This release also a new interactive Chart view (#75), template-driven editor presets, a routing/connectivity fix, operator improvements, a self-contained Linux package, and a large Linux/GCC warning cleanup. The sections below cover everything since 20.1.0.

Builds are provided at the same source revision in three flavors:

Flavor Platform Asset
.m Windows x64 (MSBuild) GeoDms20.3.0.m-Setup-x64.exe
.c Windows x64 (CMake) GeoDms20.3.0.c-Setup-x64.exe
.l Linux x64 (WSL / Ubuntu 24.04) GeoDms20.3.0.l-linux-x64.deb (+ .tar.gz)

🗺️ Map view: rotation & tilt (new)

  • View rotation (yaw) and tilt end-to-end: the MapView can be rotated and tilted into an oblique / perspective projection (yaw direction matches the Google-Maps feel; tilt clamped to 0–75°, no negative tilt or upside-down flip).
  • Rotated rasters: rotated raster georeferences are parsed into a projective coordinate transformation, and a new DrawImageTransformed primitive blits rotated/tilted raster tiles.
  • Horizon-aware rendering under tilt so nothing above the horizon renders as an artifact: polygon fills and borders, arcs, feature layers, the graticule and WMS background tiles are all horizon-clipped — fixing "UFOs" in the sky, the foreground being cut off, fills ballooning into slabs, and stray outline lines.
  • WMS background under rotation/tilt: counter-rotation, white-seam, tile-enumeration and pan-follow fixes so the background stays aligned with the foreground.

📊 Chart view (#75, new)

  • New Chart data view with a histogram mode and a series mode.
  • Series layers: scatter and line rendering via a dedicated ChartLayer, with thematic colouring and menu synchronisation.
  • Bar mode: bar draw mode with an X-axis picker, a categorical X axis, and side-by-side grouped bars for multiple bar layers.

🖱️ View & interaction

  • Reactivating a layer in the Layer Control now redraws immediately.
  • Fixed MapView keyboard-focus drift after app re-activation / view switch.
  • Fixed pan corrupting tilted views (full repaint when the scroll is not a pure translation).

➗ Operators, storage & calculation

  • GDAL (#1142): .parquet / .arrow / .feather extensions now map to the OGR Parquet / Arrow drivers.
  • connect / routing (#1138, #1136, #793): fixed a cut sort-key regression from the #793 parallelization that silently disconnected split road segments (severing origins and destinations from the routed network and diverging the land-use output); connectivity now matches the pre-#793 results.
  • area / arc_length (#1119) now convert the result to the requested unit and gain a unary auto-derive form.

Value Composition: arc, polygon, multi_point

  • points2arc, points2polygon, and points2multi_point variants of points2sequence.
  • depreciation warnings when value composition is different than expected in various functions.
  • geos_buffer (#1038) dispatches on argument ValueComposition;
  • recollect_by_cond now warns when its 2nd/3rd arguments have a mismatched ValueComposition.

⚡ Stability

  • WmsLayer::Draw is now suspendible/resumable (ResumableCounter port) making MapView navigation faster
  • #1126: dropped a false-positive DeadLock detection in lock_shared.

🐧 Linux & build

  • Self-contained Linux package (#1137) — the .l setup now bundles the Qt6 runtime (with rpath $ORIGIN), so the GUI runs on machines without a system Qt6 install (e.g. headless servers).
  • GCC/Linux warning cleanup — the Linux/CMake build's warning surface was cut ~67k → ~450 with no behavior change. A handful of latent bugs were fixed along the way: a delete[] of a void* (UB), a pointer-vs-string-literal comparison, a 16-bit truncation when printing a ULONG, a 1 << 63 shift-count overflow, and an always-false IsInTrans().
  • #1133: the /L log now carries explicit severity + category tags; the profiler parses both the tagged and the legacy log formats.
  • The executable now self-determines its exe-root directory, and Help/About reports the running executable.
  • Build housekeeping: project-local vcpkg MSBuild integration, CONFIGURE_DEPENDS on CMake source/header globs, de-hardcoded repo-root paths in build/test scripts, LOC tooling, version/buildstamp headers generated once per build session, restored vcpkg runtime DLLs on a no-relink incremental MSBuild, and a CLAUDE.md build/run policy.

Verifying the Linux download

sha256sum -c GeoDms20.3.0.l-linux-x64.tar.gz.sha256

The accompanying .p7s is a detached SHA-256 signature of the checksum file (GlobalSign EV).

Full Changelog: v20.1.0...v20.3.0

https://geodms.nl/tests/reports/20_3_0_m___16_0_5.html

GeoDms 20.1.0

Choose a tag to compare

@MaartenHilferink MaartenHilferink released this 11 Jun 18:00
Immutable release. Only release title and notes can be modified.

GeoDms 20.1.0's headline is first-class Linux support: the GeoDMS engine and the Qt GUI now build and run natively on Linux, distributed as a .deb package and a portable tarball alongside the Windows installers. This release also brings a UTF-8 overhaul across all modules, several map/table-view improvements, a first-class pow operator, and a refreshed dependency baseline.

Builds are provided at the same source revision in three flavors:

Flavor Platform Asset
.m Windows x64 (MSBuild) GeoDms20.1.0.m-Setup-x64.exe
.c Windows x64 (CMake) GeoDms20.1.0.c-Setup-x64.exe
.l Linux x64 (WSL / Ubuntu 24.04) GeoDms20.1.0.l-linux-x64.deb (+ .tar.gz)

🐧 Linux support (new)

  • GeoDmsRun and the GeoDmsGuiQt GUI now run on Linux (built under WSL/Ubuntu, Qt 6), shipped as a .deb and a portable tarball.
  • Completed the narrow → wide (UTF-8) migration: shv and every module now build as Unicode, and the Windows executables embed a UTF-8 active-code-page manifest, so paths and text behave consistently across platforms.
  • Fixed a Linux GUI exit segfault during window teardown (OnStatusText dereferencing an already-cleared main window).
  • Known issue: some Qt libraries are missing in the Linux install; they will be included in a next version. This might only affect the workings of GeoDmsGuiQt, not GeoDmsRun. Workaround: Install Qt version 6.4. See #1137

🗺️ Map & table views

  • WMS/WMTS legends (#405): the map-view layer control can now fetch and display a remote legend image.
  • Name disambiguation (#418, #620): view captions and value-info panels qualify non-distinct item names so duplicates are distinguishable.
  • Focus highlight (#1039): the focused MapView/TableView is marked with a clear magenta highlight.
  • Single-point zoom (#374): opening a single point no longer over-zooms.
  • Multi-column resize (#1121): pooled column-width resizing across a multi-column selection.
  • Fixed a duplicated column when activating a container (#1122).
  • Window position and size are now persisted between sessions.

➗ Operators & calculation

  • pow / ^ is now a first-class operator (#839) instead of being rewritten as exp(b·log(a)) — correct results for integer, negative, and zero bases, with less precision loss.
  • Fixed a conversion regression (#1098).
  • Fixed grid-range upper-bound clamping on large grids (unsigned rounding past 32767).
  • StorageTileSizeXPropDef = 0 on non-storage-holders is no longer treated as an error.
  • Clearer NetCDF diagnostic when a raster band is missing.

⚡ Performance & stability

  • #933: storage reads no longer block worker threads on a storage manager's critical section, improving throughput on storage-heavy models.

🔧 Build & dependencies

  • Upgraded the vcpkg baseline to 2026.05.25 — boost 1.91, GDAL 3.12, CGAL 6.1, PROJ 9.8 — via an in-repo vcpkg submodule that auto-bootstraps on a fresh checkout (both MSBuild and CMake).
  • Pinned the toolchain to MSVC 14.50.35717 to avoid a GEOS miscompile in 14.51 that caused buffer-operation crashes.
  • Corrected PROJ/GDAL data deployment so PROJ 9.8 ships a current proj.db.
  • Packaging fixes (ship tinyxml2.dll; drop stale uriparser/vcpkg DLL references) and a large build-warning cleanup.

Verifying the Linux download

sha256sum -c GeoDms20.1.0.l-linux-x64.tar.gz.sha256

The accompanying .p7s is a detached SHA-256 signature of the checksum file (GlobalSign EV).

Full Changelog: v20.0.4...v20.1.0

Known regresssion in the connect operator that is now multi-treaded but has a sorting issue in this version. Has been resolved for the next release: see #1138

Test results

https://geodms.nl/tests/reports/20_1_0_c___17_9_2.html
https://geodms.nl/tests/reports/20_1_0_m___17_9_2.html
See https://github.com/ObjectVision/GeoDMS/wiki/Full-test for context