#!/usr/bin/env bash # OpenStreetMap no-hunting land in the US and Canada (parks, playgrounds, golf courses, cemeteries, schools, sports # grounds, campgrounds, built-up land) → geo.osm_exclusions → land-exclusions.pmtiles. "Can I hunt here?" never # answers "open" inside one: the government land layers miss municipal parks and park land on Crown parcels (e.g. # Shubie Park, Dartmouth NS). Run through the geotools image: # # tools/geodata/run land-status/osm-exclusions # Nova Scotia (dev default) # HG_OSM_EXTRACT=north-america/us/alabama HG_OSM_JURISDICTIONS=US-AL tools/geodata/run land-status/osm-exclusions # HG_OSM_PBF=/data/downloads/osm/north-america-latest.osm.pbf HG_OSM_JURISDICTIONS=ALL \ # tools/geodata/run land-status/osm-exclusions # production # # HG_OSM_JURISDICTIONS names the states/provinces the file fully covers: only they are replaced (an extract also # holds slivers of its neighbours, which must not wipe a full import of those). # ODbL: the rows live in their own table and tileset (land-exclusions.pmtiles, the "land-exclusions" overlay the app # draws with "Can I hunt here?"), never in geo.land_status (CLAUDE.md). set -euo pipefail HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$HERE/../lib/common.sh" EXTRACT="${HG_OSM_EXTRACT:-north-america/canada/nova-scotia}" PBF="${HG_OSM_PBF:-}" JURISDICTIONS="${HG_OSM_JURISDICTIONS:-$([[ -z "${HG_OSM_EXTRACT:-}${PBF}" ]] && echo CA-NS)}" [[ -n "$JURISDICTIONS" ]] || die "set HG_OSM_JURISDICTIONS to the states/provinces the file fully covers (or ALL)" jurisdictions_sql="null" if [[ "$JURISDICTIONS" != "ALL" ]]; then for j in $JURISDICTIONS; do [[ "$j" =~ ^(US|CA)-[A-Z]{2}$ ]] || die "bad jurisdiction code: $j"; done list="$(printf "'%s'," $JURISDICTIONS)" jurisdictions_sql="array[${list%,}]" fi if [[ -z "$PBF" ]]; then [[ "$EXTRACT" =~ ^[a-z0-9/-]+$ ]] || die "bad extract name: $EXTRACT" PBF="/data/downloads/osm/${EXTRACT//\//-}-latest.osm.pbf" SOURCE_URL="https://download.geofabrik.de/$EXTRACT-latest.osm.pbf" mkdir -p /data/downloads/osm # Geofabrik refreshes extracts daily; reuse a download from the last day. if [[ -z "$(find "$PBF" -mtime -1 2>/dev/null)" ]]; then log "Downloading $SOURCE_URL" curl -fsSL --retry 3 -A "HuntGrid geodata pipeline" -o "$PBF.part" "$SOURCE_URL" mv -f "$PBF.part" "$PBF" fi else SOURCE_URL="file://$PBF" fi [[ -f "$PBF" ]] || die "no OSM file at $PBF" VERSION="OpenStreetMap $(date -u -r "$PBF" +%Y-%m-%d)" psql_run -c "create schema if not exists staging" log "No-hunting land from $(basename "$PBF")" ogr2ogr -f PostgreSQL "PG:$HG_DB_URL" "$PBF" multipolygons -oo CONFIG_FILE="$HERE/osmconf-exclusions.ini" \ -where "leisure IN ('park','garden','dog_park','playground','golf_course','miniature_golf','pitch','sports_centre','stadium','track','recreation_ground') OR landuse IN ('cemetery','recreation_ground','residential','commercial','retail') OR amenity IN ('grave_yard','school','college','university','kindergarten','hospital') OR tourism IN ('camp_site','caravan_site','zoo','theme_park')" \ -nln staging.osm_exclusions_raw -overwrite -lco GEOMETRY_NAME=geom -lco SPATIAL_INDEX=NONE -nlt PROMOTE_TO_MULTI \ --config OSM_MAX_TMPFILE_SIZE 1024 --config OGR_TRUNCATE YES fetched="$(psql_run -tA -c "select count(*) from staging.osm_exclusions_raw")" log "Found $fetched areas" [[ "$fetched" -gt 0 ]] || die "no areas found; refusing to replace existing data" log "Normalising into geo.osm_exclusions" psql_run <