@@ -3,10 +3,12 @@ set -o errexit -o nounset -o pipefail
33
44if [ $# -ge 1 ] && [ " $1 " = " -h" ] ; then
55 cat << -END
6- Usage: $0 INPUT.osh.pbf BEFORETIME AFTERTIME BBOX
7-
8- TIME1 & TIME2 are ISO timestamps
9- bboxes can be found via http://bboxfinder.com/
6+ Usage: $0 INPUT.osh.pbf BEFORETIME AFTERTIME BBOX [MIN_ZOOM] [MAX_ZOOM] [NUM_FRAMES]
7+
8+ BEFORETIME & AFTERTIME are ISO-8601 timestamps
9+ BBOX is a comma-separated long/lat bounding box (left,bottom,right,top) and can be found via http://bboxfinder.com/
10+ MIN_ZOOM and MAX_ZOOM are optional zoom levels (default: 6 and 12)
11+ NUM_FRAMES is the number of frames to generate for the GIF (default: 2)
1012 END
1113 exit 0
1214fi
@@ -15,159 +17,150 @@ INPUT_FILE=$(realpath "${1:?Arg 1 should be the path to the pbf file}")
1517TIME_BEFORE=${2:? Arg 2 should be the ISO timestamp for the before time}
1618TIME_AFTER=${3:? Arg 3 should be the ISO timestamp for the after time}
1719BBOX=${4:- " world" }
20+ BBOX_COMMA=" ${BBOX// / ,} "
21+ BBOX_SPACE=" ${BBOX// ,/ } "
22+ MIN_ZOOM=${5:- 6}
23+ MAX_ZOOM=${6:- 12}
24+ NUM_FRAMES=${7:- 2}
25+
1826# for planet-latest.osm.obf we calculate the "planet" part
1927PREFIX=$( basename " $INPUT_FILE " )
2028PREFIX=${PREFIX%% .osh.pbf}
2129PREFIX=${PREFIX%% -latest}
2230PREFIX=${PREFIX%% -internal}
2331PREFIX=${PREFIX// -/ _}
24- MIN_ZOOM=${5:- 6}
25- MAX_ZOOM=${6:- 12}
2632
2733ROOT=" $( realpath " $( dirname " $0 " ) " ) "
2834cd " $ROOT " || exit
2935
30- BBOX_COMMA=" ${BBOX// / ,} "
31- BBOX_SPACE=" ${BBOX// ,/ } "
32-
33- if [ ! -s " $INPUT_FILE " ] ; then
34- echo " Input file $INPUT_FILE not found" 1>&2
35- exit 1
36- fi
37-
38- if [ " $BBOX " = " world" ] ; then
39- PBF_FILE=" $INPUT_FILE "
40- else
41- PBF_FILE=" $( realpath " $PREFIX .$BBOX .osh.pbf" ) "
42- if [ " $INPUT_FILE " -nt " $PBF_FILE " ] ; then
43- echo " Extracting the OSM history for just this bounding box $BBOX "
44- NEWFILE=$( mktemp -p . " tmp.extract.${PREFIX} .XXXXXX.osm.pbf" )
45- osmium extract --with-history --overwrite -o " $NEWFILE " --bbox " $BBOX_COMMA " " $INPUT_FILE "
46- mv " $NEWFILE " " $PBF_FILE "
47- fi
48- fi
49-
50- BEFORE_FILENAME=" $( realpath " ${PREFIX} .$TIME_BEFORE .$BBOX_COMMA .osm.pbf" ) "
51- if [ " $PBF_FILE " -nt " $BEFORE_FILENAME " ] ; then
52- NEWFILE=$( mktemp -p . tmp.time1.XXXXXX.osm.pbf)
53- echo " Extracting 'before' data..."
54- osmium time-filter --overwrite -o " $NEWFILE " " $PBF_FILE " " $TIME_BEFORE "
55- mv " $NEWFILE " " $BEFORE_FILENAME "
56- fi
57-
58- AFTER_FILENAME=" $( realpath " ${PREFIX} .$TIME_AFTER .$BBOX_COMMA .osm.pbf" ) "
59- if [ " $PBF_FILE " -nt " $AFTER_FILENAME " ] ; then
60- NEWFILE=$( mktemp -p . tmp.time2.XXXXXX.osm.pbf)
61- echo " Extracting 'after' data..."
62- osmium time-filter --overwrite -o " $NEWFILE " " $PBF_FILE " " $TIME_AFTER "
63- mv " $NEWFILE " " $AFTER_FILENAME "
36+ PBF_FILE=" $( realpath " $PREFIX .$BBOX .osh.pbf" ) "
37+ if [ " $INPUT_FILE " -nt " $PBF_FILE " ] ; then
38+ echo " Extracting the OSM history for just this bounding box $BBOX "
39+ NEWFILE=$( mktemp -p . " tmp.extract.${PREFIX} .XXXXXX.osm.pbf" )
40+ osmium extract --with-history --overwrite -o " $NEWFILE " --bbox " $BBOX_COMMA " " $INPUT_FILE "
41+ mv " $NEWFILE " " $PBF_FILE "
6442fi
6543
66-
6744if [ ! -s " $ROOT /openstreetmap-carto/node_modules/.bin/carto" ] ; then
68- cd " $ROOT /openstreetmap-carto"
69- echo " Installing carto into $ROOT /openstreetmap-carto/node_modules with npm..."
70- npm init -y
71- npm install carto -q
45+ cd " $ROOT /openstreetmap-carto"
46+ echo " Installing carto into $ROOT /openstreetmap-carto/node_modules with npm..."
47+ npm init -y
48+ npm install carto -q
7249fi
73- if [ ! -s " $ROOT /openstreetmap-carto/project.xml" ] ; then
74- cd " $ROOT "
75- if [ ! -e " $ROOT /openstreetmap-carto" ] ; then
76- git submodule update
77- fi
78- cd " $ROOT /openstreetmap-carto"
79- if [ ! -s project.xml ] || [ project.mml -nt project.xml ] ; then
80- TMP=$( mktemp -p . tmp.project.XXXXXX.xml)
81- ./node_modules/.bin/carto -a 3.0.0 project.mml > " $TMP "
82- mv " $TMP " project.xml
83- fi
8450
51+ if [ ! -s " $ROOT /openstreetmap-carto/project.xml" ] ; then
52+ cd " $ROOT "
53+ if [ ! -e " $ROOT /openstreetmap-carto" ] ; then
54+ git submodule update
55+ fi
56+ cd " $ROOT /openstreetmap-carto"
57+ if [ ! -s project.xml ] || [ project.mml -nt project.xml ] ; then
58+ TMP=$( mktemp -p . tmp.project.XXXXXX.xml)
59+ ./node_modules/.bin/carto -a 3.0.0 project.mml > " $TMP "
60+ mv " $TMP " project.xml
61+ fi
8562fi
8663
8764if [ " $( psql -At -c " select count(*) from pg_database where datname = 'gis';" ) " = " 0" ] ; then
88- echo " Creating gis database..."
89- createdb gis
90- psql -d gis -c " create extension postgis;"
91- psql -d gis -c " create extension hstore;"
65+ echo " Creating gis database..."
66+ createdb gis
67+ psql -d gis -c " create extension postgis;"
68+ psql -d gis -c " create extension hstore;"
9269fi
9370
9471if [ ! -e " $ROOT /openstreetmap-carto/data/.external-data-done" ] ; then
95- cd " $ROOT /openstreetmap-carto/"
96- echo " Downloading external datasets..."
97- ./scripts/get-external-data.py
98- touch data/.external-data-done
99- cd " $ROOT "
100- fi
101-
102- if [ " $BEFORE_FILENAME " -nt " $ROOT /.$PREFIX .$TIME_BEFORE .$BBOX_COMMA .generated" ] ; then
103- cd " $ROOT /openstreetmap-carto"
104- osm2pgsql -G --hstore --style openstreetmap-carto.style --tag-transform-script openstreetmap-carto.lua -d gis " $BEFORE_FILENAME "
105- psql -d gis -f indexes.sql
106- touch " $ROOT /.$PREFIX .$TIME_BEFORE .$BBOX_COMMA .generated"
72+ cd " $ROOT /openstreetmap-carto/"
73+ echo " Downloading external datasets..."
74+ ./scripts/get-external-data.py
75+ touch data/.external-data-done
76+ cd " $ROOT "
10777fi
10878
109- cd " $ROOT "
110-
111- for ZOOM in $( seq " $MIN_ZOOM " " $MAX_ZOOM " ) ; do
112- if [ " $ROOT /.$PREFIX .$TIME_BEFORE .$BBOX_COMMA .generated" -nt " $PREFIX .$TIME_BEFORE .$BBOX_COMMA .z${ZOOM} .png" ] ; then
113- # eventually the image is too large, so then just break out of the loop
114- echo " Generating zoom ${ZOOM} level"
115- nik4.py openstreetmap-carto/project.xml " $PREFIX .$TIME_BEFORE .$BBOX_COMMA .z${ZOOM} .png" -b $BBOX_SPACE -z " $ZOOM " || break
116- NEW=" $( mktemp tmp.XXXXXX.png) "
117- # gm convert "$PREFIX.$TIME_BEFORE.$BBOX_COMMA.z${ZOOM}.png" -background white -label "${TIME_BEFORE}" -gravity center -append "$NEW"
118- # mv "$NEW" "$PREFIX.$TIME_BEFORE.$BBOX_COMMA.z${ZOOM}.png"
119- gm convert " $PREFIX .$TIME_BEFORE .$BBOX_COMMA .z${ZOOM} .png" -background white -label " ${TIME_BEFORE} , data © OpenStreetMap contributors, ODbL" -gravity center -append " $NEW "
120- mv " $NEW " " $PREFIX .$TIME_BEFORE .$BBOX_COMMA .z${ZOOM} .png"
121- fi
122- done
123-
124- if [ " $AFTER_FILENAME " -nt " $ROOT /.$PREFIX .$TIME_AFTER .$BBOX_COMMA .generated" ] ; then
125- cd " $ROOT /openstreetmap-carto"
126- osm2pgsql -G --hstore --style openstreetmap-carto.style --tag-transform-script openstreetmap-carto.lua -d gis " $AFTER_FILENAME "
127- psql -d gis -f indexes.sql
128- touch " $ROOT /.$PREFIX .$TIME_AFTER .$BBOX_COMMA .generated"
129- fi
130-
131- cd " $ROOT "
132- for ZOOM in $( seq " $MIN_ZOOM " " $MAX_ZOOM " ) ; do
133- if [ " $ROOT /.$PREFIX .$TIME_AFTER .$BBOX_COMMA .generated" -nt " $PREFIX .$TIME_AFTER .$BBOX_COMMA .z${ZOOM} .png" ] ; then
134- # eventually the image is too large, so then just break out of the loop
135- echo " Generating zoom ${ZOOM} level"
136- nik4.py openstreetmap-carto/project.xml " $PREFIX .$TIME_AFTER .$BBOX_COMMA .z${ZOOM} .png" -b $BBOX_SPACE -z " $ZOOM " || break
137- NEW=" $( mktemp tmp.XXXXXX.png) "
138- # gm convert "$PREFIX.$TIME_AFTER.$BBOX_COMMA.z${ZOOM}.png" -background white -label "$TIME_AFTER" -gravity center -append "$NEW"
139- # mv "$NEW" "$PREFIX.$TIME_AFTER.$BBOX_COMMA.z${ZOOM}.png"
140- gm convert " $PREFIX .$TIME_AFTER .$BBOX_COMMA .z${ZOOM} .png" -background white -label " ${TIME_AFTER} , data © OpenStreetMap contributors, ODbL" -gravity center -append " $NEW "
141- mv " $NEW " " $PREFIX .$TIME_AFTER .$BBOX_COMMA .z${ZOOM} .png"
142- fi
79+ # Function to generate ISO-8601 timestamps between two times
80+ generate_timestamps () {
81+ local start_time=$1
82+ local end_time=$2
83+ local num_stops=$3
84+ python3 - << END
85+ import datetime
86+ from dateutil import parser
87+ start_time = parser.isoparse("$start_time ")
88+ end_time = parser.isoparse("$end_time ")
89+ delta = (end_time - start_time) / ($num_stops - 1)
90+ timestamps = [start_time + i * delta for i in range($num_stops )]
91+ for ts in timestamps:
92+ ts = ts.replace(microsecond=0)
93+ print(ts.isoformat().replace("+00:00", "Z"))
94+ END
95+ }
96+
97+ # Generate timestamps
98+ TIMESTAMPS=$( generate_timestamps " $TIME_BEFORE " " $TIME_AFTER " " $NUM_FRAMES " )
99+
100+ # Process each timestamp
101+ for TIME in $TIMESTAMPS ; do
102+ FILENAME=" $( realpath " ${PREFIX} .$TIME .$BBOX_COMMA .osm.pbf" ) "
103+ if [ " $PBF_FILE " -nt " $FILENAME " ] ; then
104+ NEWFILE=$( mktemp -p . tmp.time.XXXXXX.osm.pbf)
105+ echo " Extracting data for $TIME ..."
106+ osmium time-filter --overwrite -o " $NEWFILE " " $PBF_FILE " " $TIME "
107+ mv " $NEWFILE " " $FILENAME "
108+ fi
109+
110+ if [ " $FILENAME " -nt " $ROOT /.$PREFIX .$TIME .$BBOX_COMMA .generated" ] ; then
111+ cd " $ROOT /openstreetmap-carto"
112+ echo " Importing data for $TIME ..."
113+ osm2pgsql -G --hstore --style openstreetmap-carto.style --tag-transform-script openstreetmap-carto.lua -d gis " $FILENAME "
114+ psql -d gis -f indexes.sql
115+ touch " $ROOT /.$PREFIX .$TIME .$BBOX_COMMA .generated"
116+ fi
117+
118+ cd " $ROOT "
119+ for ZOOM in $( seq " $MIN_ZOOM " " $MAX_ZOOM " ) ; do
120+ if [ " $ROOT /.$PREFIX .$TIME .$BBOX_COMMA .generated" -nt " $PREFIX .$TIME .$BBOX_COMMA .z${ZOOM} .png" ] ; then
121+ echo " Generating zoom ${ZOOM} at time ${TIME} "
122+ GENERATED=" $PREFIX .$TIME .$BBOX_COMMA .z${ZOOM} .png"
123+ nik4.py openstreetmap-carto/project.xml " $GENERATED " -b $BBOX_SPACE -z " $ZOOM " || break
124+ # Add padding to the bottom of the image to make space for the attribution
125+ NEW_PADDED=" $( mktemp tmp.XXXXXX.padded.png) "
126+ gm convert " $GENERATED " -background white -gravity south -extent -0-30 " $NEW_PADDED " || break
127+ # Add the attribution and timestamp
128+ NEW_ATTRIBUTION=" $( mktemp tmp.XXXXXX.attribution.png) "
129+ gm convert " $NEW_PADDED " -font Courier -pointsize 20 -fill black \
130+ -gravity southwest -draw " text 5,5 '${TIME} '" \
131+ -gravity southeast -draw " text 5,5 'Data © OpenStreetMap contributors, ODbL'" \
132+ " $NEW_ATTRIBUTION " || break
133+ mv " $NEW_ATTRIBUTION " " $GENERATED "
134+ rm " $NEW_PADDED "
135+ fi
136+ done
143137done
144138
145139cd " $ROOT "
146140for ZOOM in $( seq " $MIN_ZOOM " " $MAX_ZOOM " ) ; do
147- NEW_PNG=" progress.$PREFIX .$TIME_BEFORE .$TIME_AFTER .$BBOX_COMMA .z${ZOOM} .png"
148- BEFORE=" $PREFIX .$TIME_BEFORE .$BBOX_COMMA .z${ZOOM} .png"
149- AFTER=" $PREFIX .$TIME_AFTER .$BBOX_COMMA .z${ZOOM} .png"
150- if [ ! -s " $BEFORE " ] || [ ! -s " $AFTER " ] ; then
151- continue
152- fi
153- echo " Generating comparison image for zoom $ZOOM "
154-
155- if [ " $BEFORE " -nt " $NEW_PNG " ] || [ " $AFTER " -nt " $NEW_PNG " ] ; then
156- TMP=" $( mktemp tmp.XXXXXX.png) "
157- gm montage -geometry +0+0 " $BEFORE " " $AFTER " " $TMP "
158-
159- gm convert " $TMP " -background white -label " Data © OpenStreetMap contributors, ODbL" -gravity center -append " $NEW_PNG "
160- fi
161-
162- if [ " $BEFORE " -nt " $NEW_PNG " ] || [ " $AFTER " -nt " $NEW_PNG " ] ; then
163- gm montage -geometry +0+0 " $BEFORE " " $AFTER " " $NEW_PNG "
164- fi
165-
166- NEW_GIF=" progress.$PREFIX .$TIME_BEFORE .$TIME_AFTER .$BBOX_COMMA .z${ZOOM} .gif"
141+ # Generate comparison images of start and end times for each zoom level
142+ NEW_PNG=" progress.$PREFIX .$TIME_BEFORE .$TIME_AFTER .$BBOX_COMMA .z${ZOOM} .png"
143+ BEFORE=" $PREFIX .$TIME_BEFORE .$BBOX_COMMA .z${ZOOM} .png"
144+ AFTER=" $PREFIX .$TIME_AFTER .$BBOX_COMMA .z${ZOOM} .png"
145+ if [ ! -s " $BEFORE " ] || [ ! -s " $AFTER " ] ; then
146+ continue
147+ fi
148+ echo " Generating comparison image for zoom $ZOOM "
149+
150+ if [ " $BEFORE " -nt " $NEW_PNG " ] || [ " $AFTER " -nt " $NEW_PNG " ] ; then
151+ TMP=" $( mktemp tmp.XXXXXX.png) "
152+ gm montage -geometry +0+0 " $BEFORE " " $AFTER " " $TMP "
153+ gm convert " $TMP " -background white -label " Data © OpenStreetMap contributors, ODbL" -gravity center -append " $NEW_PNG "
154+ rm " $TMP "
155+ fi
156+
157+ if [ " $BEFORE " -nt " $NEW_PNG " ] || [ " $AFTER " -nt " $NEW_PNG " ] ; then
158+ gm montage -geometry +0+0 " $BEFORE " " $AFTER " " $NEW_PNG "
159+ fi
160+
161+ # Generate a GIF using the frames
162+ NEW_GIF=" progress.$PREFIX .$TIME_BEFORE .$TIME_AFTER .$BBOX_COMMA .z${ZOOM} .gif"
167163 if [ " $BEFORE " -nt " $NEW_GIF " ] || [ " $AFTER " -nt " $NEW_GIF " ] ; then
168- gm convert -delay 50 " $BEFORE " " $AFTER " " $NEW_GIF "
169- fi
170-
164+ gm convert -delay 50 " $PREFIX " .* ." $BBOX_COMMA " .z" $ZOOM " .png " $NEW_GIF "
165+ fi
171166done
172-
173-
0 commit comments