├── LICENSE ├── README.md ├── scripts ├── 00-all-sample.sh ├── 01-download.sh ├── 02-unzip.sh ├── 03-rexz.sh ├── 03b-unxz.sh ├── 04-merge.sh ├── 05-contour-tiles.sh ├── 06-contour-level-pyramid.sql ├── 07-shaded-relief.sh └── 08-create-previews.sh └── stylesheets ├── color-ramps ├── generate_qgis_color_ramp.sh ├── slope-ramp.txt ├── srtm-Australia-color-ramp.gdaldem.txt └── srtm-Australia-color-ramp.qgis.txt ├── configure.py ├── contours.mss ├── contours.template.mml ├── srtm-hillshaded-color-relief.xml └── srtm.tilestache.cfg /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | 123 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About 2 | This package contains a set of shell scripts for working with NASA SRTM DEM 3 | data, gdaldem based stylesheets for creating shaded relief and/or hypsometric 4 | tinted maps, Mapnik stylesheets for making contours maps and a TileStache 5 | configuration for sandwiching or compositing the shaded relief and contour maps. 6 | 7 | ![SRTM3 Hillshaded, Color Relief Contour 8 | Map](http://tianjara.net/hosted/srtm3-stylesheet-git-preview.png) 9 | 10 | The aim of the project is to produce a free and open source repeatable workflow 11 | for visualising worldwide elevation data. 12 | 13 | This project should be useful if you want to, 14 | * automate the download of SRTM3 data 15 | * produce a void filled single large GeoTIFF DEM from SRTM3 HGT tiles 16 | * produce hill shaded, slope shaded, hypsometric and/or contour maps 17 | * have contours loaded into a PostgreSQL/PostGIS database for use in a GIS 18 | * have a simple general purpose elevation layer/map (default style included) 19 | 20 | All of the above use cases are accommodated for in these scripts. 21 | 22 | The SRTM data has been released at varying resolution. SRTM3 refers to the 23 | near global 3 arc-second product and SRTM1 the higher resolution 1 arc-second 24 | product. SRTM1 was only released to the public in late 2014 and is not listed 25 | on the public directory yet at dds.cr.usgs.gov/srtm. You can however download 26 | the files by navigating the website at http://earthexplorer.usgs.gov/. 27 | 28 | # License 29 | With the exception of stylesheets/configure.py which is 3-clause BSD 30 | licensed, all files within this repository are licensed by the author, 31 | Andrew Harvey as follows. 32 | 33 | To the extent possible under law, the person who associated CC0 34 | with this work has waived all copyright and related or neighboring 35 | rights to this work. 36 | http://creativecommons.org/publicdomain/zero/1.0/ 37 | 38 | The SRTM data which these scripts are designed to use is in the public 39 | domain because it was solely created by NASA. NASA copyright policy 40 | states that "NASA material is not protected by copyright unless noted". 41 | 42 | # Running through the scripts 43 | ## Dependencies 44 | To run through all the steps provided by these script you will need, 45 | 46 | wget unzip xz-utils gdal-bin postgresql-client postgis carto tilestache libmapnik|libmapnik2 fonts-sil-gentium-basic python-gdal 47 | 48 | ## Downloading SRTM3 data 49 | 50 | ./scripts/01-download.sh SRTM3_Region... 51 | 52 | To determine the SRTM3_Region see the [region map](http://dds.cr.usgs.gov/srtm/version2_1/Documentation/Continent_def.gif), 53 | in combination with the [actual directory names](http://dds.cr.usgs.gov/srtm/version2_1/SRTM3/) for these regions. 54 | 55 | You can list multiple regions as arguments or just one. 56 | 57 | The coordinates refer to the bottom left corner of the tile, or expressed 58 | differently the tile is in the top right quadrant referred to by the coordinate. 59 | 60 | ## Downloading SRTM1 data 61 | Presently you need to navigate and manually download scenes via http://earthexplorer.usgs.gov/ 62 | 63 | ## Unzipping downloads 64 | To unzip these downloads run, 65 | 66 | ./scripts/02-unzip.sh 67 | 68 | If you want to keep these files for later reference, you may wish to 69 | re-compress using xz to save space using, 70 | 71 | ./scripts/03-rexz.sh 72 | 73 | Which you can later uncompress again using, 74 | 75 | ./scripts/03b-unxz.sh 76 | 77 | ## Grunt work 78 | If you have made it this far then all the data is prepared and ready for 79 | the real grunt work. The are two bits of processing we do. Preparing the 80 | vector contours and preparing the raster DEM. To create the final 81 | sandwiched map you will need to perform both steps, if not then you can 82 | just perform one. 83 | 84 | ### Raster DEM processing 85 | 86 | #### Creating a mosaic DEM 87 | To avoid edge artefacts and to make the process simpler, we mosaic all 88 | those 1 x 1 degree tiles into a single continent mosaic using, 89 | 90 | ./scripts/04-merge.sh SRTM1|SRTM3 SRTM_Continent lon0 lon1 lat0 lat1 91 | 92 | The last four parameters are the bounds we will use for the mosaic. You 93 | can only use integer values as they are simply used to select which 94 | individual .hgt tiles to glue together. 95 | 96 | An additional processing step is also run as part of this script to fill the 97 | voids in the data. However you need to apply this patch 98 | http://trac.osgeo.org/gdal/ticket/4464 to your gdal_fillnodata.py script for 99 | this to work. 100 | 101 | #### Hill shading and color relief (hypsometric tints) 102 | 103 | ./scripts/07-shaded-relief.sh SRTM1|SRTM3 SRTM_Continent 104 | 105 | Keep in mind that the hypsometric tint values are defined in 106 | `stylesheets/color-ramps/srtm-Continent-color-ramp.gdaldem.txt`. In the first 107 | column you have the elevation value in meters. I've only created a color ramp 108 | specifically suited for the highest point in Australia. I'm not sure of the 109 | best approach for applying this on a global scale. 110 | 111 | ### Vector contour processing 112 | You will need a PostgreSQL database set up somewhere with the PostGIS 113 | extensions installed. 114 | 115 | Then make sure you set your [PG* environment variables](http://www.postgresql.org/docs/current/static/libpq-envars.html), for example, 116 | 117 | export PGDATABASE=srtm 118 | 119 | then run, 120 | 121 | ./scripts/05-contour-tiles.sh SRTM1|SRTM3 lon0 lon1 lat0 lat1 122 | 123 | This will convert the DEM into contours and load them into a PostgreSQL 124 | database. 125 | 126 | After this you will need to run, 127 | 128 | psql -f ./scripts/06-contour-level-pyramid.sql 129 | 130 | This creates materialised tables of higher level contours (ie. 50m from 131 | the base 10m ones) and some other plumbing work. 132 | 133 | # Previewing the Mapnik style 134 | If you have made it this far then you should be ready to start rending 135 | some maps! 136 | 137 | There are two styles within the stylesheets directory. One for contours 138 | and one for the hill shaded color relief. 139 | 140 | There is also a sample TileStache configuration for sandwiching these 141 | together into a single map layer. 142 | 143 | The hill shaded color relief style should be ready to go. 144 | 145 | The contour style needs to be configured with, 146 | 147 | ./stylesheets/configure.py 148 | 149 | You can pass it parameters --host, --port, --dbname, --user, --password. 150 | 151 | When you run it, it will copy the `contours.template.mml` into 152 | `contours.mml` and fill in the new file with your configuration. 153 | 154 | You can then further run, 155 | 156 | carto stylesheets/contours.mml > contours.xml 157 | 158 | To convert it into a Mapnik XML stylesheet. 159 | 160 | You could preview these independently with TileLite's `litserv`, or you 161 | could just run, 162 | 163 | tilestache-server -c stylesheets/srtm3.tilestache.cfg 164 | 165 | Alternatively you can generate some samples/previews of both the independent 166 | layers and the sandwiched layer using, 167 | 168 | ./scripts/08-create-previews.sh 169 | 170 | Be aware that for this you will need 171 | https://gist.github.com/andrewharvey/1290744 in your $PATH and the ImageMagick 172 | program convert. 173 | 174 | There is a [live preview of this sandwiched stylesheet](http://tianjara.net/map#srtm3/8/-34.003/151.125). 175 | 176 | # Cleaning up 177 | There are some files you can remove to save some space. 178 | 179 | # remove the original zipped hgt files we downloaded from USGS 180 | rm -rf dds.cr.usgs.gov 181 | 182 | # remove the unzipped hgt files (if you want you can keep a .tar.xz) 183 | rm -rf SRTM3 184 | 185 | # if you no longer need the single large DEM but are just using the layers/ 186 | rm -rf SRTM3*.tiff 187 | -------------------------------------------------------------------------------- /scripts/00-all-sample.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | continent=Australia 4 | 5 | ./scripts/01-download.sh $continent && \ 6 | ./scripts/02-unzip.sh && \ 7 | ./scripts/04-merge.sh $continent 140 153 25 37 && \ 8 | ./scripts/05-contour-tiles.sh 140 153 25 37 && \ 9 | psql -f scripts/06-contour-level-pyramid.sql && \ 10 | ./scripts/07-shaded-relief.sh $continent 11 | -------------------------------------------------------------------------------- /scripts/01-download.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script will only download SRTM3 data as SRTM1 data isn't yet available in the same way. 4 | 5 | if [ -z $1 ] ; then 6 | echo "Usage: $0 [SRTM3_Region]..." 7 | exit 1 8 | fi 9 | 10 | for ARG in $* ; do 11 | wget --mirror --no-parent http://dds.cr.usgs.gov/srtm/version2_1/SRTM3/$ARG/ 12 | done 13 | -------------------------------------------------------------------------------- /scripts/02-unzip.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | for f in dds.cr.usgs.gov/srtm/version2_1/SRTM3/*/*.zip ; do 4 | unzip -u -d SRTM3 "$f" 5 | done 6 | 7 | for f in SRTM1_ZIP/*.zip ; do 8 | unzip -u -d SRTM1 "$f" 9 | done 10 | -------------------------------------------------------------------------------- /scripts/03-rexz.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mkdir -p SRTM3-XZ 4 | for f in SRTM3/*.hgt ; do 5 | b=`basename $f` 6 | xz < "$f" > "SRTM3-XZ/$b.xz" 7 | done 8 | -------------------------------------------------------------------------------- /scripts/03b-unxz.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mkdir -p SRTM3 4 | for f in SRTM3-XZ/*.hgt.xz ; do 5 | b=`basename $f .xz` 6 | echo "$b" 7 | xz --keep --decompress --stdout "$f" > "SRTM3/$b" 8 | done 9 | -------------------------------------------------------------------------------- /scripts/04-merge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script is licensed CC0 by Andrew Harvey 4 | # 5 | # To the extent possible under law, the person who associated CC0 6 | # with this work has waived all copyright and related or neighboring 7 | # rights to this work. 8 | # http://creativecommons.org/publicdomain/zero/1.0/ 9 | 10 | 11 | # argument list of hgt files 12 | files="" 13 | 14 | # where the HGT files are at 15 | base=$1 16 | 17 | continent=$2 18 | 19 | if [ -z $continent ] ; then 20 | echo "Usage: $0 SRTM1|SRTM3 SRTM3_Region" 21 | exit 1 22 | fi 23 | 24 | 25 | # filename of output single merged file 26 | merged=${base}_${continent}.tiff 27 | filled=${base}_${continent}_filled.tiff 28 | 29 | if [ -z $6 ] ; then 30 | echo "Usage: $0 SRTM1|SRTM3 SRTM3_Continent lon0 lon1 lat0 lat1" 31 | exit 1 32 | else 33 | lon0=$3 34 | lon1=$4 35 | lat0=$5 36 | lat1=$6 37 | fi 38 | 39 | if [ $lat0 -gt $lat1 ] ; then 40 | echo "lat0 must be <= lat1" 41 | exit 1 42 | fi 43 | if [ $lon0 -gt $lon1 ] ; then 44 | echo "lon0 must be <= lon1" 45 | exit 1 46 | fi 47 | 48 | # count how mange files we are planning to merge 49 | counter=0 50 | for lon in `seq $lon0 $lon1` ; do 51 | if [ $lon -lt 0 ] ; then 52 | ew='W' 53 | lon=${lon#-} # remove sign 54 | else 55 | ew='E' 56 | fi 57 | for lat in `seq $lat0 $lat1` ; do 58 | if [ $lat -lt 0 ] ; then 59 | ns='S' 60 | lat=${lat#-} # remove sign 61 | else 62 | ns='N' 63 | fi 64 | if [ $base == "SRTM1" ] ; then 65 | file="${ns}${lat}_${ew}${lon}_1arc_v3.bil" 66 | file=`echo $file | tr 'A-Z' 'a-z'` 67 | file="${base}/${file}" 68 | elif [ $base == "SRTM3" ] ; then 69 | file="${base}/${ns}${lat}${ew}${lon}.hgt" 70 | else 71 | echo "Usage: $0 SRTM1|SRTM3 [SRTM3_Region]" 72 | echo "Argument 1 must be either SRTM1 or SRTM3" 73 | exit 1 74 | fi 75 | echo "$file" 76 | if [ -e "$file" ] ; then 77 | files="${files} $file" 78 | counter=$(($counter + 1)) 79 | fi 80 | done 81 | done 82 | 83 | echo "Merging $counter files..." 84 | 85 | rm -rf $merged 86 | nice gdal_merge.py -o $merged -co BIGTIFF=YES -co COMPRESS=LZW $files 87 | 88 | echo "Written $merged" 89 | 90 | 91 | # check we have the patched gdal_fillnodata.py script 92 | cat `which gdal_fillnodata.py` | grep "\-srcnodata value" > /dev/null 93 | if [ $? -eq 0 ] ; then 94 | echo "Removing voids..." 95 | nice gdal_fillnodata.py -srcnodata -32768 $merged -of GTiff -co COMPRESS=LZW -co BIGTIFF=YES $filled 96 | 97 | # just keep the one void filled variant 98 | rm -rf $merged 99 | mv $filled $merged 100 | else 101 | echo "It does not appear that you have the patch at 102 | http://trac.osgeo.org/gdal/ticket/4464 applied. Hence any voids in 103 | SRTM3 data weren't filled." 104 | fi 105 | -------------------------------------------------------------------------------- /scripts/05-contour-tiles.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script is licensed CC0 by Andrew Harvey 4 | # 5 | # To the extent possible under law, the person who associated CC0 6 | # with this work has waived all copyright and related or neighboring 7 | # rights to this work. 8 | # http://creativecommons.org/publicdomain/zero/1.0/ 9 | 10 | base=$1 11 | base_lower=`echo "$base" | tr 'A-Z' 'a-z'` 12 | 13 | mkdir -p ${base}_Contour_Tiles/ 14 | 15 | interval=10 16 | 17 | if [ -z $5 ] ; then 18 | echo "Usage: $0 SRTM1|SRTM3 lon0 lon1 lat0 lat1" 19 | exit 1 20 | else 21 | lon0=$2 22 | lon1=$3 23 | lat0=$4 24 | lat1=$5 25 | fi 26 | 27 | if [ $lat0 -gt $lat1 ] ; then 28 | echo "lat0 must be <= lat1" 29 | exit 1 30 | fi 31 | if [ $lon0 -gt $lon1 ] ; then 32 | echo "lon0 must be <= lon1" 33 | exit 1 34 | fi 35 | 36 | psql -c "DROP TABLE IF EXISTS ${base_lower};" 37 | 38 | counter=0 39 | for lon in `seq $lon0 $lon1` ; do 40 | for lat in `seq $lat0 $lat1` ; do 41 | if [ $lon -lt 0 ] ; then 42 | ew='W' 43 | lon=${lon#-} # remove sign 44 | else 45 | ew='E' 46 | fi 47 | if [ $lat -lt 0 ] ; then 48 | ns='S' 49 | lat=${lat#-} # remove sign 50 | else 51 | ns='N' 52 | fi 53 | if [ $base == "SRTM1" ] ; then 54 | f="${ns}${lat}_${ew}${lon}_1arc_v3.bil" 55 | f=`echo $f | tr 'A-Z' 'a-z'` 56 | f="${base}/${f}" 57 | elif [ $base == "SRTM3" ] ; then 58 | f="${base}/${ns}${lat}${ew}${lon}.hgt" 59 | else 60 | echo "Argument 1 must be either SRTM1 or SRTM3" 61 | exit 1 62 | fi 63 | echo $f 64 | if [ -e "$f" ] ; then 65 | counter=$(($counter + 1)) 66 | if [ $base == "SRTM1" ] ; then 67 | b=`basename $f .bil` 68 | elif [ $base == "SRTM3" ] ; then 69 | b=`basename $f .hgt` 70 | fi 71 | echo $b 72 | 73 | working_tile="$f" 74 | # check we have the patched gdal_fillnodata.py script 75 | cat `which gdal_fillnodata.py` | grep "\-srcnodata value" > /dev/null 76 | if [ $? -eq 0 ] ; then 77 | echo "Removing voids." 78 | filled_tile=`mktemp --suffix=.tiff` 79 | gdal_fillnodata.py -srcnodata -32768 "$f" -of GTiff "$filled_tile" 80 | working_tile="$filled_tile" 81 | fi 82 | 83 | # create contours for this hgt file then save it as a shape file 84 | nice ionice -c 3 \ 85 | gdal_contour \ 86 | -i $interval \ 87 | -a ele \ 88 | -snodata -32768 \ 89 | "$working_tile" \ 90 | ${base}_Contour_Tiles/$b.shp 91 | 92 | # remove the tile if it is a temporary one we just created 93 | if [ ! -z "${filled_tile+xxx}" -a -e "${filled_tile}" ]; then 94 | # VAR $filled_tile is SET AND file exists 95 | rm -f "$filled_tile" 96 | fi 97 | 98 | # then load that shape file into PostgreSQL 99 | nice ionice -c 3 \ 100 | ogr2ogr \ 101 | -f PostgreSQL \ 102 | -nln srtm \ 103 | -append \ 104 | -t_srs "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs" \ 105 | PG:dbname=$PGDATABASE \ 106 | "${base}_Contour_Tiles/$b.shp" 107 | 108 | # we don't need the shape file anymore 109 | rm -f ${base}_Contour_Tiles/$b.* 110 | fi 111 | done 112 | done 113 | 114 | if [ $counter -eq 0 ] ; then 115 | echo "No suitable ${base} tiles were found in ${base}/ for the bounds you specified." 116 | else 117 | echo "Imported contours for $counter ${base} tiles." 118 | fi 119 | 120 | rm -rf ${base}_Contour_Tiles 121 | 122 | psql -c "ALTER TABLE srtm DROP COLUMN id;" 123 | -------------------------------------------------------------------------------- /scripts/06-contour-level-pyramid.sql: -------------------------------------------------------------------------------- 1 | -- This file is licensed CC0 by Andrew Harvey 2 | -- 3 | -- To the extent possible under law, the person who associated CC0 4 | -- with this work has waived all copyright and related or neighboring 5 | -- rights to this work. 6 | -- http://creativecommons.org/publicdomain/zero/1.0/ 7 | 8 | -- create materialised tables for different elevation levels 9 | 10 | -- note that they will be overlapping. so for example the 10m contours 11 | -- will still contain the 100m contours; they are present in both. 12 | 13 | -- drop the id column from the table as we don't need it 14 | ALTER TABLE srtm DROP COLUMN id; 15 | 16 | -- drop any existing tables 17 | DROP TABLE IF EXISTS srtm_contours_10m; 18 | DROP TABLE IF EXISTS srtm_contours_50m; 19 | DROP TABLE IF EXISTS srtm_contours_250m; 20 | 21 | -- create the pyramid 22 | CREATE TABLE srtm_contours_10m AS ( 23 | SELECT * FROM srtm WHERE ((ele % 10) = 0) 24 | ); 25 | VACUUM ANALYZE srtm_contours_10m; 26 | 27 | CREATE TABLE srtm_contours_50m AS ( 28 | SELECT * FROM srtm_contours_10m WHERE ((ele % 50) = 0) 29 | ); 30 | VACUUM ANALYZE srtm_contours_50m; 31 | 32 | CREATE TABLE srtm_contours_250m AS ( 33 | SELECT * FROM srtm_contours_50m WHERE ((ele % 250) = 0) 34 | ); 35 | VACUUM ANALYZE srtm_contours_250m; 36 | 37 | -- this table isn't really needed anymore more 38 | -- if you are planning to use it for other things though you may want to 39 | -- keep it 40 | DROP TABLE srtm; 41 | 42 | -- create geometry indexes 43 | CREATE INDEX srtm_contours_10m_geom_idx 44 | ON srtm_contours_10m 45 | USING gist 46 | (wkb_geometry); 47 | 48 | CREATE INDEX srtm_contours_50m_geom_idx 49 | ON srtm_contours_50m 50 | USING gist 51 | (wkb_geometry); 52 | 53 | CREATE INDEX srtm_contours_250m_geom_idx 54 | ON srtm_contours_250m 55 | USING gist 56 | (wkb_geometry); 57 | 58 | 59 | -- ensure we have the proper PostGIS metadata for these tables 60 | INSERT INTO geometry_columns(f_table_catalog, f_table_schema, f_table_name, f_geometry_column, coord_dimension, srid, "type") VALUES ('', 'public', 'srtm_contours_10m', 'wkb_geometry', 2, 900914, 'LINESTRING'); 61 | INSERT INTO geometry_columns(f_table_catalog, f_table_schema, f_table_name, f_geometry_column, coord_dimension, srid, "type") VALUES ('', 'public', 'srtm_contours_50m', 'wkb_geometry', 2, 900914, 'LINESTRING'); 62 | INSERT INTO geometry_columns(f_table_catalog, f_table_schema, f_table_name, f_geometry_column, coord_dimension, srid, "type") VALUES ('', 'public', 'srtm_contours_250m', 'wkb_geometry', 2, 900914, 'LINESTRING'); 63 | 64 | -------------------------------------------------------------------------------- /scripts/07-shaded-relief.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script is licensed CC0 by Andrew Harvey 4 | # 5 | # To the extent possible under law, the person who associated CC0 6 | # with this work has waived all copyright and related or neighboring 7 | # rights to this work. 8 | # http://creativecommons.org/publicdomain/zero/1.0/ 9 | 10 | # This process follows http://mapbox.com/tilemill/docs/guides/terrain-data/ 11 | 12 | base=$1 13 | continent=$2 14 | 15 | if [ -z $continent ] ; then 16 | echo "Usage: $0 SRTM1|SRTM3 [SRTM3_Region]" 17 | exit 1 18 | fi 19 | 20 | base_lower=`echo "$base" | tr 'A-Z' 'a-z'` 21 | 22 | if [ ! -e stylesheets/color-ramps/srtm-${continent}-color-ramp.gdaldem.txt ] ; then 23 | echo "Could not find stylesheets/color-ramps/srtm-${continent}-color-ramp.gdaldem.txt" 24 | echo "" 25 | echo "This file defines the color ramp used for the relief image of the DEM." 26 | echo "" 27 | echo "This is not a global color ramp, if it were Mount Everest would look good" 28 | echo "but a flat country would not." 29 | echo "" 30 | echo "If you are just rendering a single country then you may want to rescale" 31 | echo "the ramp for a user defined maximum elevation." 32 | exit 1 33 | fi 34 | 35 | # reproject to slippy map projection 36 | gdalwarp -t_srs "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs" -r near -of VRT ${base}_$continent.tiff ${base}_$continent-WebMercator.vrt 37 | 38 | mkdir -p layers 39 | 40 | # make the color relief image 41 | nice gdaldem color-relief ${base}_$continent-WebMercator.vrt stylesheets/color-ramps/srtm-${continent}-color-ramp.gdaldem.txt layers/${base}_${continent}_color_relief.tiff -of GTiff -co COMPRESS=DEFLATE -co ZLEVEL=9 42 | 43 | # make the hillshaded greyscale image 44 | nice gdaldem hillshade ${base}_$continent-WebMercator.vrt layers/${base}_${continent}_hillshade.tiff -of GTiff -co COMPRESS=DEFLATE -co ZLEVEL=9 45 | 46 | # generate slope for the slopeshade 47 | nice gdaldem slope ${base}_$continent-WebMercator.vrt layers/${base}_${continent}_slope.tiff -of GTiff -co COMPRESS=DEFLATE -co ZLEVEL=9 48 | 49 | # generate the slopeshade 50 | nice gdaldem color-relief layers/${base}_${continent}_slope.tiff stylesheets/color-ramps/slope-ramp.txt layers/${base}_${continent}_slopeshade.tiff -of GTiff -co COMPRESS=DEFLATE -co ZLEVEL=9 51 | 52 | # we only needed this to generate the slopeshade, so remove it now 53 | rm -f layers/${base}_${continent}_slope.tiff 54 | 55 | # add a link to the layers within the stylesheets directory for the mapnik stylesheet 56 | ln -s -T ../layers stylesheets/layers 57 | -------------------------------------------------------------------------------- /scripts/08-create-previews.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script is licensed CC0 by Andrew Harvey 4 | # 5 | # To the extent possible under law, the person who associated CC0 6 | # with this work has waived all copyright and related or neighboring 7 | # rights to this work. 8 | # http://creativecommons.org/publicdomain/zero/1.0/ 9 | 10 | # This script will create some sample/preview images of the final stylesheet. 11 | 12 | # You must have the mapnik_render_static_map.py script from 13 | # https://gist.github.com/andrewharvey/1290744 in your $PATH 14 | 15 | preview=preview/ 16 | mkdir -p $preview 17 | 18 | preview_width=1400 19 | preview_height=800 20 | 21 | function render { 22 | x=$1 23 | y=$2 24 | z=$3 25 | w=$4 26 | h=$5 27 | output=$6 28 | 29 | echo -n "Rendering $output" 30 | mapnik_render_static_map.py \ 31 | --mapfile stylesheets/srtm3-hillshaded-color-relief.xml \ 32 | --centrex $x \ 33 | --centrey $y \ 34 | --zoom $z \ 35 | --width $w \ 36 | --height $h \ 37 | --output ${preview}${output}_base.png \ 38 | > /dev/null 39 | 40 | echo -n "." 41 | 42 | mapnik_render_static_map.py \ 43 | --mapfile stylesheets/contours.xml \ 44 | --centrex $x \ 45 | --centrey $y \ 46 | --zoom $z \ 47 | --width $w \ 48 | --height $h \ 49 | --output ${preview}${output}_contour.png \ 50 | > /dev/null 51 | 52 | echo -n "." 53 | 54 | convert ${preview}${output}_base.png ${preview}${output}_contour.png \ 55 | -composite -quality 90 ${preview}${output}.jpg 56 | 57 | echo " saved as ${preview}${output}.jpg" 58 | } 59 | 60 | # centrex centrey z width hight name 61 | render 149.41818 -35.66511 9 $preview_width $preview_height z9 62 | render 150.85859 -34.40224 12 $preview_width $preview_height z12 63 | render 150.77019 -34.05095 10 $preview_width $preview_height z10 64 | render 146.71692 -42.66931 9 $preview_width $preview_height z9_tas 65 | render 150.28988 -35.28192 12 $preview_width $preview_height z12_mnp 66 | render 151.01601 -33.26194 11 $preview_width $preview_height z11_nth 67 | -------------------------------------------------------------------------------- /stylesheets/color-ramps/generate_qgis_color_ramp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cat srtm3-Australia-color-ramp.gdaldem.txt | \ 4 | tr ' ' ',' | \ 5 | sed 's/$/,255/g' | \ 6 | sed -r 's/([^,]*)(.*)/\1\2,\1m/g' | \ 7 | sed '1i\INTERPOLATION:INTERPOLATED' \ 8 | > srtm3-Australia-color-ramp.qgis.txt 9 | -------------------------------------------------------------------------------- /stylesheets/color-ramps/slope-ramp.txt: -------------------------------------------------------------------------------- 1 | 0 255 255 255 2 | 90 0 0 0 3 | -------------------------------------------------------------------------------- /stylesheets/color-ramps/srtm-Australia-color-ramp.gdaldem.txt: -------------------------------------------------------------------------------- 1 | -8764 0 0 0 2 | -4000 3 45 85 3 | -100 0 101 199 4 | 0 192 224 255 5 | 1 108 220 108 6 | 55 50 180 50 7 | 390 240 250 150 8 | 835 190 185 135 9 | 1114 180 128 107 10 | 1392 235 220 175 11 | 2228 215 244 244 12 | 4000 255 255 255 13 | -------------------------------------------------------------------------------- /stylesheets/color-ramps/srtm-Australia-color-ramp.qgis.txt: -------------------------------------------------------------------------------- 1 | INTERPOLATION:INTERPOLATED 2 | -8764,0,0,0,255,-8764m 3 | -4000,3,45,85,255,-4000m 4 | -100,0,101,199,255,-100m 5 | 0,192,224,255,255,0m 6 | 1,108,220,108,255,1m 7 | 55,50,180,50,255,55m 8 | 390,240,250,150,255,390m 9 | 835,190,185,135,255,835m 10 | 1114,180,128,107,255,1114m 11 | 1392,235,220,175,255,1392m 12 | 2228,215,244,244,255,2228m 13 | 4000,255,255,255,255,4000m 14 | -------------------------------------------------------------------------------- /stylesheets/configure.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (c) 2011, Development Seed, Inc. 4 | # 2012, Andrew Harvey 5 | # All rights reserved. 6 | # 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions are 9 | # met: 10 | # 11 | # * Redistributions of source code must retain the above copyright 12 | # notice, this list of conditions and the following disclaimer. 13 | # * Redistributions in binary form must reproduce the above copyright 14 | # notice, this list of conditions and the following disclaimer in 15 | # the documentation and/or other materials provided with the 16 | # distribution. 17 | # * Neither the name of the Development Seed, Inc. nor the names of 18 | # its contributors may be used to endorse or promote products 19 | # derived from this software without specific prior written 20 | # permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 23 | # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 | # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 25 | # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 26 | # OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 | # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 29 | # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | 35 | import json 36 | from sys import path 37 | from os.path import join 38 | import argparse 39 | import shutil 40 | 41 | ################################# 42 | ## argparse 43 | 44 | parser = argparse.ArgumentParser(description='Configure an MML file with datasource settings') 45 | parser.add_argument('--host', default='localhost') 46 | parser.add_argument('--port', default='5432') 47 | parser.add_argument('--dbname', default='srtm') 48 | parser.add_argument('--user', default='') 49 | parser.add_argument('--password', default='') 50 | 51 | args = parser.parse_args() 52 | 53 | ################################# 54 | ## configure mml 55 | 56 | mml = join(path[0], 'contours.mml') 57 | 58 | shutil.copyfile( join(path[0], 'contours.template.mml'), mml) 59 | 60 | with open(mml, 'r') as f: 61 | newf = json.loads(f.read()) 62 | f.closed 63 | 64 | with open(mml, 'w') as f: 65 | for layer in newf["Layer"]: 66 | layer["Datasource"]["host"] = args.host 67 | layer["Datasource"]["port"] = args.port 68 | layer["Datasource"]["dbname"] = args.dbname 69 | layer["Datasource"]["user"] = args.user 70 | layer["Datasource"]["password"] = args.password 71 | f.write(json.dumps(newf, indent=2)) 72 | f.closed 73 | 74 | -------------------------------------------------------------------------------- /stylesheets/contours.mss: -------------------------------------------------------------------------------- 1 | /* 2 | * SRTM3 Contours Stylesheet 3 | * 4 | * Not usually used on its own. Best combined with a shaded relief of the DEM. 5 | * 6 | * Author: Andrew Harvey 7 | * License: CC0 http://creativecommons.org/publicdomain/zero/1.0/ 8 | * To the extent possible under law, the person who associated CC0 9 | * with this work has waived all copyright and related or neighboring 10 | * rights to this work. 11 | */ 12 | 13 | 14 | /* 15 | ===== Protips for generating cartographic contour maps ===== 16 | 17 | Protip #1 18 | Only use two levels of line thickness at once. So use normal 19 | thin lines for each contour line and then thicker ones every so 20 | often. But don't then do even thicker ones even more ofter than that. 21 | 22 | Protip #2 23 | Your thicker contour lines should either be 5 or 10 times the 24 | interval of the thin contour lines. So this would produce a thick 25 | contour line for every 5 or 10 thin contour lines. 26 | 27 | With these two rules in mind creating a contour map is easy. You have 28 | two paramaters. 29 | 30 | x - the vertical distance between the thin contour lines; x contours 31 | m - every mth contour line is a thick one; mx contours 32 | 33 | We shall call these x*m contour maps. 34 | */ 35 | 36 | /* Also keep in mind that with labels on you will need to use a small map 37 | buffer to avoid the labels being cut on tile boundaries. */ 38 | 39 | 40 | /* default variables */ 41 | @contour_line_color: black; 42 | 43 | @thin_line_width: 0.2; 44 | @thick_line_width: 0.4; 45 | 46 | 47 | /* high zooms - 10m*5 */ 48 | 49 | /* thin line */ 50 | #contour-10m[zoom >= 11] { 51 | line-color: @contour_line_color; 52 | line-width: @thin_line_width; 53 | } 54 | 55 | /* thick */ 56 | #contour-50m[zoom >= 11] { 57 | line-color: @contour_line_color; 58 | line-width: @thick_line_width; 59 | } 60 | 61 | /* elevation labels */ 62 | /* I'm not sure if these should be off by default though. 63 | Are they generally usefull, or just cause clutter? */ 64 | #contour-50m[zoom >= 13] { 65 | text-name: "[ele]"; 66 | text-face-name: "Gentium Regular"; 67 | text-fill: white; 68 | text-placement: line; 69 | text-halo-fill: black; 70 | text-halo-radius: 1.5; 71 | text-spacing: 400; 72 | text-min-path-length: 200; 73 | 74 | text-size: 12; 75 | } 76 | 77 | /* medium zooms - 50m*5 */ 78 | 79 | /* thin */ 80 | #contour-50m[zoom <= 10][zoom >= 9] { 81 | line-color: @contour_line_color; 82 | line-width: @thin_line_width; 83 | } 84 | 85 | /* thick */ 86 | #contour-250m[zoom <= 10][zoom >= 9] { 87 | line-color: @contour_line_color; 88 | line-width: @thick_line_width; 89 | } 90 | 91 | /* low zooms 250m */ 92 | /* thin */ 93 | #contour-250m[zoom <= 8][zoom >= 7] { 94 | line-color: @contour_line_color; 95 | line-width: @thin_line_width; 96 | } 97 | 98 | /* no contour lines for zoom 6 or less */ 99 | -------------------------------------------------------------------------------- /stylesheets/contours.template.mml: -------------------------------------------------------------------------------- 1 | { 2 | "srs": "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over", 3 | "Stylesheet": [ 4 | "contours.mss" 5 | ], 6 | "Layer": [ 7 | { 8 | "geometry": "linestring", 9 | "id": "contour-10m", 10 | "name": "contour-10m", 11 | "srs": "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over", 12 | "class": "contour", 13 | "Datasource": { 14 | "type": "postgis", 15 | "table": "(\n SELECT wkb_geometry, ele\n FROM srtm_contours_10m\n) AS contours_10m", 16 | "geometry_field": "wkb_geometry" 17 | } 18 | }, 19 | { 20 | "geometry": "linestring", 21 | "id": "contour-50m", 22 | "name": "contour-50m", 23 | "srs": "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over", 24 | "class": "contour", 25 | "Datasource": { 26 | "type": "postgis", 27 | "table": "(\n SELECT wkb_geometry, ele\n FROM srtm_contours_50m\n) AS contours_50m", 28 | "geometry_field": "wkb_geometry" 29 | } 30 | }, 31 | { 32 | "geometry": "linestring", 33 | "id": "contour-250m", 34 | "name": "contour-250m", 35 | "srs": "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over", 36 | "class": "contour", 37 | "Datasource": { 38 | "type": "postgis", 39 | "table": "(\n SELECT wkb_geometry, ele\n FROM srtm_contours_250m\n) AS contours_250m", 40 | "geometry_field": "wkb_geometry" 41 | } 42 | } 43 | ], 44 | "name": "srtm-contours", 45 | "description": "SRTM Contours Stylesheet" 46 | } 47 | -------------------------------------------------------------------------------- /stylesheets/srtm-hillshaded-color-relief.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 17 | 23 | 29 | 30 | 31 | srtm-color-relief 32 | 33 | layers/srtm_color_relief.tiff 34 | gdal 35 | 36 | 37 | 38 | srtm-hillshade 39 | 40 | layers/srtm_hillshade.tiff 41 | gdal 42 | 43 | 44 | 45 | srtm-slopeshade 46 | 47 | layers/srtm_slopeshade.tiff 48 | gdal 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /stylesheets/srtm.tilestache.cfg: -------------------------------------------------------------------------------- 1 | { 2 | "cache": 3 | { 4 | "name": "Test" 5 | }, 6 | "layers": 7 | { 8 | "srtm": 9 | { 10 | "provider": 11 | { 12 | "name": "Sandwich", 13 | "stack": 14 | [ 15 | {"src": "srtm-hillshade-relief"}, 16 | {"src": "srtm-contours"} 17 | ] 18 | }, 19 | "metatile": 20 | { 21 | "rows": 8, 22 | "columns": 8, 23 | "buffer": 0 24 | }, 25 | "bounds": 26 | { 27 | "north": -26.9995833, 28 | "west": 139.9995833, 29 | "south": -37.0004167, 30 | "east": 154.0004167, 31 | "high": 15, 32 | "low": 0 33 | }, 34 | "preview": 35 | { 36 | "lat": -34.003, 37 | "lon": 151.125, 38 | "zoom": 7 39 | }, 40 | "jpeg options": 41 | { 42 | "quality": 95 43 | }, 44 | "redirects": 45 | { 46 | "png": "jpg" 47 | } 48 | }, 49 | "srtm-contours": { 50 | "provider": 51 | { 52 | "name": "mapnik", 53 | "mapfile": "contours.xml" 54 | }, 55 | "metatile": 56 | { 57 | "rows": 8, 58 | "columns": 8, 59 | "buffer": 64 60 | }, 61 | "bounds": 62 | { 63 | "north": -26.9995833, 64 | "west": 139.9995833, 65 | "south": -37.0004167, 66 | "east": 154.0004167, 67 | "high": 15, 68 | "low": 0 69 | }, 70 | "preview": 71 | { 72 | "lat": -34.003, 73 | "lon": 151.125, 74 | "zoom": 7 75 | } 76 | }, 77 | "srtm-hillshade-relief": { 78 | "provider": 79 | { 80 | "name": "mapnik", 81 | "mapfile": "srtm-hillshaded-color-relief.xml" 82 | }, 83 | "metatile": 84 | { 85 | "rows": 8, 86 | "columns": 8, 87 | "buffer": 0 88 | }, 89 | "bounds": 90 | { 91 | "north": -26.9995833, 92 | "west": 139.9995833, 93 | "south": -37.0004167, 94 | "east": 154.0004167, 95 | "high": 15, 96 | "low": 0 97 | }, 98 | "preview": 99 | { 100 | "lat": -34.003, 101 | "lon": 151.125, 102 | "zoom": 7 103 | } 104 | } 105 | } 106 | } 107 | --------------------------------------------------------------------------------