SpatiaLite/Examples/Mapping SurveySheets to FederalState names
< SpatiaLite | Examples
Jump to navigation
Jump to search
Intro
This script builds a SpatiaLite database from scratch containing two tables:
- states with columns name, source, g
- mtbmbr with columnr name (just a placeholder), nr, g
It was build with the goal in mind to determine which federal state territory is covered by which survey map sheet(s) of the TK 25 or resp. Messtischblätter map series. The map sheets in the series are numbered uniquely by a grid scheme which is leveraged by the script to calculate, rather than import, the bounding boxes of these map sheets. It's currently useful to
- determine all map sheets covering a certain federal state completely, and, vice versa:
- determine the federal state(s) a map sheet has information about
- retrieve all map sheet numbers covering the border region of a federal state (grenzmtb view)
- get map sheets that cover the border region along two (or more) certain adjacent federal states
- calculate the difference between the polygon areas and the boundary as entered in OSM
- ...
states is filled twice, using
- rough geometry contained in Geofabrik's polygon files (source=poly)
- precise boundary geometry pulled from Overpass API (source=osm)
mtbmbr is filled with minimum bounding rectangles of Messtischblatt / TK25 map rectangles
- bbox'es are synthesized / computed by the script
- the table totals 89x59 entries, some cover ocean or territory a paper map never was published for
The code
- was written and tested on Kubuntu 14.04 LTS Live/Install ISO booted off an USB key, corei3 CPU, 3G RAM
- pulls needed deps using "sudo apt-get", among them spatialite
- needs write access within /tmp and the directory the script is put in
- needs a recent osmjs, if it is uninstalled the script makes an attempt to build it from source
- the deb distributed with trusty was not stable and ran out of memory too quick, even with -l sparsetable.
- since the live system resides in memory, -l vector is used to constrain osmjs to a lower memory footprint.
- the result of a potential build is cached, consecutive runs of the script will not rebuild osmjs
Some exemplary queries are found near the end of the script. Feel free to reuse this code or the db it produces for your own purposes.
Produced files
- the sqlite database to work with later on, containing
- the tables with geometry column and spatial index
- saved views that make use of the spatial index
- an mtb to state map which is a dump of the view mtb2state
See also
- Transforming geocoords between WGS84 (SRID 4326) and Bessel1841 / DHDN (SRID 4314) (german) - Note: SpatiaLite returns
POINT(6.799386 50.000062)
when queriedSELECT AsText(Transform(GeomFromText('POINT(6.79867 49.99891)', 4326), 4314));
Listing
#!/bin/bash
# urls
NADURL="http://crs.bkg.bund.de/crseu/crs/descrtrans/BeTA/BETA2007.gsb"
POLYURLS="http://download.geofabrik.de/europe/germany/"
OVERPASS="http://overpass-api.de/api/interpreter"
# permanent files
MTBMAP="${0%.sh}.mtbmap"
NAD="${0%.sh}.beta2007"
DB="${0%.sh}.sqlite"
# temporary files
QF="$(mktemp --dry-run --suffix=.sql)"
OF="${QF//./-}.osm" # else osmjs deducts pbf from filename
which spatialite &> /dev/null \
|| sudo apt-get install spatialite-{bin,gui} proj-bin \
|| exit 1
# ----------------------------------------------------------------
# do not recreate the db, if it exists
# ----------------------------------------------------------------
[[ -f "$DB" ]] || { # START DB creation
cat <<EOF > "$QF"
CREATE TABLE IF NOT EXISTS states(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name TEXT,
source TEXT
);
SELECT AddGeometryColumn(
'states', 'g', 4326, 'MULTIPOLYGON', 'XY'
);
SELECT CreateSpatialIndex(
'states', 'g'
);
DELETE FROM states;
EOF
wget -qO - "$POLYURLS" |\
sed -e 's/href=./\n/g' |\
sed -e 's/".*//' |\
grep ".poly$" |\
while read p
do
echo "INSERT INTO states VALUES(NULL, \"${p%.poly}\", \"poly\", " >> "$QF"
echo -n " GeomFromText('MULTIPOLYGON(((" >> "$QF"
wget -qO - "$POLYURLS/$p" |\
while read l k
do
[[ -z "$k" && "$l" -gt 1 ]] && echo -en ")),(("
[[ -n "$k" ]] && LANG=C printf "%f %f," "$l" "$k"
done |\
sed -e 's/$/))/' -e 's/,)/)/g' >> "$QF"
echo -e ")', 4326)\n);" >> "$QF"
done
OSMJS="$(which osmjs)"
[[ -x "$OSMJS" ]] || {
OSMJS="${0%.sh}-osmjs"
sudo apt-get install g++ git \
lib{boost,expat1,gdal1,geos++,icu,osmpbf,protobuf,shp,sparsehash,v8,z}-dev \
|| exit 1
}
[[ -x "$OSMJS" ]] || {
CO="$(mktemp --directory --dry-run --suffix=.git)"
git clone -b master https://github.com/joto/osmium.git "$CO"
make -C "$CO/osmjs" \
&& cp -a "$CO/osmjs/osmjs" "$OSMJS" \
&& rm -rf "$CO"
}
[[ -x "$OSMJS" ]] && {
wget -O "$OF" "$OVERPASS" --post-data '
relation
["type"="boundary"]
["boundary"="administrative"]
["admin_level"="4"]
["ISO3166-2"~"^DE-"]
(47.5,6.0,55.0,15.0);
(
._;
way(r);
node(w);
);
out;'
"$OSMJS" -m -l vector -j <(echo '
Osmium.Callbacks.area = function() {
print( "INSERT INTO states VALUES(NULL, \"" +
this.tags.name +
"\", \"osm\", GeomFromText(\"" +
this.geom.toWKT() +
"\", 4326));"
);
}'
) "$OF" >> "$QF"
}
cat <<EOF >> "$QF"
CREATE TABLE IF NOT EXISTS mtbmbr(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
nr TEXT,
name TEXT
);
SELECT AddGeometryColumn(
'mtbmbr', 'g', 4326, 'POLYGON', 'XY'
);
SELECT CreateSpatialIndex(
'mtbmbr', 'g'
);
DELETE FROM mtbmbr;
EOF
[[ -f "$NAD" ]] || wget -O "$NAD" "$NADURL"
latd=56 latm=0 latdb=55 latmb=54
for r in {01..89}
do
if [[ "$latm" -eq 0 ]]
then
latd="$((latd-1))"
latm=54
else
latm="$((latm-6))"
fi
if [[ "$latm" -eq 0 ]]
then
latdb="$((latd-1))"
latmb=54
else
latmb="$((latm-6))"
fi
lond=5 lonm=40 londr=5 lonmr=50
for c in {01..59}
do
if [[ "$lonm" -eq 50 ]]
then
lond="$((lond+1))"
lonm=0
else
lonm="$((lonm+10))"
fi
if [[ "$lonm" -eq 50 ]]
then
londr="$((lond+1))"
lonmr=0
else
lonmr="$((lonm+10))"
fi
ul="${lond}d${lonm}'E ${latd}d${latm}'N"
ur="${londr}d${lonmr}'E ${latd}d${latm}'N"
lr="${londr}d${lonmr}'E ${latdb}d${latmb}'N"
ll="${lond}d${lonm}'E ${latdb}d${latmb}'N"
mbr=$(
# nadgrids only support translation up to column 59
echo -e "$ul \n$ur \n$lr \n$ll \n$ul" |\
cs2cs -f "%.12f" +proj=lonlat +ellps=bessel +nadgrids="$NAD" \
+to +init=epsg:4326 |\
while read lon lat h
do echo -n "$lon $lat, "
done
)
cat <<EOF >> "$QF"
INSERT INTO mtbmbr VALUES(NULL, "$r$c", "",
GeomFromText("POLYGON(( ${mbr%,*} ))", 4326)
);
EOF
done
done
for view in grenzmtb=Overlaps mtb2state=Intersects
do
cat <<EOF >> "$QF"
CREATE VIEW IF NOT EXISTS ${view%=*} AS
SELECT s.name Bundesland, m.nr MTB_Nr, m.g MTB_WGS84_Geom,
Area(Intersection(s.g, m.g))*100/Area(m.g) AS Prozentanteil
FROM states s, mtbmbr m
WHERE s.name NOT LIKE "undef%"
AND s.source="osm"
AND ${view#*=}(s.g, m.g)
AND s.ROWID IN (
SELECT ROWID
FROM SpatialIndex
WHERE f_table_name = "states"
AND search_frame = m.g
)
;
EOF
done
spatialite "$DB" <<EOF
.echo ON
.stats ON
.read "$QF" UTF-8
.quit
EOF
# cleanup
#echo "Keep temporary files ${QF} and ${OF}? [y/N]"
#read ans
#[[ "${ans,}" != "y" ]] && rm -rf "$QF" "$OF"
rm -rf "$QF" "$OF"
} # END DB creation
# ----------------------------------------------------------------
# do a test query if nothing more specific was passed as arguments
GEOMTOUSE="${1:-GeomFromText('POINT(12 51)', 4326)}"
MATCHMODE="${2:-Contains}"
echo "Running some examplary queries.."
echo "This may take some time, safely abort this process with Ctrl+C."
spatialite "$DB" <<EOF |& cat
.headers ON
.stats ON
.echo ON
SELECT AsText($GEOMTOUSE) AS coord, name AS lies_within, source AS says_source
FROM states
WHERE $MATCHMODE(g, $GEOMTOUSE)
AND id IN (
SELECT ROWID FROM SpatialIndex
WHERE f_table_name = 'states'
AND search_frame = $GEOMTOUSE
)
;
SELECT *
FROM mtb2state
WHERE Bundesland="Berlin"
AND Prozentanteil < 30
;
SELECT *
FROM (
SELECT * FROM grenzmtb WHERE Bundesland="Saarland"
) a
LEFT JOIN (
SELECT * FROM grenzmtb WHERE Bundesland LIKE "Rheinl%"
) b
ON (
a.MTB_Nr=b.MTB_Nr
)
;
.quit
EOF
echo "Dumping mtb2state mapping to $MTBMAP."
echo "This may take some time, safely abort this process with Ctrl+C."
spatialite "$DB" <<EOF > "$MTBMAP"
SELECT MTB_Nr, Bundesland FROM mtb2state;
.quit
EOF
echo "Bye."