├── README.md ├── make_all.sh ├── pgsql ├── functions.sql ├── make_grids.sql ├── postgis-vt-util.sql ├── pre_process.sql └── process.sql ├── polarmap-source.tm2source ├── .thumb.png ├── data.xml └── data.yml ├── settings.sh └── ubuntu └── ubuntu_setup.sh /README.md: -------------------------------------------------------------------------------- 1 | # Polar Map 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /make_all.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eu -o pipefail 3 | 4 | source "$(dirname $0)/settings.sh" 5 | 6 | pushd "$(pwd)" 7 | mkdir -p "$DATADIR" 8 | cd "$DATADIR" 9 | 10 | if [ ! -e planet.osm.pbf ]; then 11 | wget -O planet.osm.pbf "$PBF_URL" 12 | fi 13 | 14 | if [ ! -e arctic_latest.osm.pbf ]; then 15 | osmconvert planet.osm.pbf -b="$BBOX" --complex-ways -o=arctic_latest.osm.pbf 16 | fi 17 | 18 | if [ $(($(date +%s)-$(stat -c '%Y' arctic_latest.osm.pbf))) -gt $((12*60*60)) ] 19 | then 20 | # Updating the arctic extract to the latest OSM data with osmupdate. 21 | # This should take only a few minutes for each day's worth of changes. 22 | osmupdate arctic_latest.osm.pbf arctic_new.osm.pbf -b=$BBOX 23 | mv -f arctic_latest.osm.pbf arctic_old.osm.pbf 24 | mv -f arctic_new.osm.pbf arctic_latest.osm.pbf 25 | fi 26 | 27 | if [ ! -e arctic_land.shp ]; then 28 | wget -N http://data.openstreetmapdata.com/land-polygons-complete-4326.zip 29 | unzip -ju land-polygons-complete-4326.zip 30 | ogr2ogr -t_srs EPSG:$EPSG -clipsrc $BBOX_OGR \ 31 | arctic_land.shp land_polygons.shp 32 | fi 33 | 34 | if [ ! -e natural_earth_vector.sqlite ]; then 35 | nezip=natural_earth_vector.sqlite.zip 36 | wget -O "$nezip" "http://naciscdn.org/naturalearth/packages/$nezip" 37 | unzip -ju $nezip -x CHANGELOG README.md VERSION 38 | fi 39 | 40 | if [ ! -e natural_earth_arctic.sqlite ]; then 41 | ogr2ogr \ 42 | -clipsrc $BBOX_OGR \ 43 | -f SQLite \ 44 | natural_earth_arctic.sqlite \ 45 | natural_earth_vector.sqlite \ 46 | ne_10m_admin_0_boundary_lines_land \ 47 | ne_10m_admin_0_boundary_lines_maritime_indicator \ 48 | ne_10m_admin_0_countries \ 49 | ne_10m_admin_1_states_provinces_lines_shp \ 50 | ne_10m_admin_1_states_provinces_shp \ 51 | ne_10m_airports \ 52 | ne_10m_geographic_lines \ 53 | ne_10m_geography_marine_polys \ 54 | ne_10m_geography_regions_elevation_points \ 55 | ne_10m_geography_regions_polys \ 56 | ne_10m_glaciated_areas \ 57 | ne_10m_land \ 58 | ne_10m_land_ocean_label_points \ 59 | ne_10m_ocean \ 60 | ne_10m_parks_and_protected_lands_area \ 61 | ne_10m_populated_places_simple \ 62 | ne_10m_ports \ 63 | ne_10m_roads \ 64 | ne_10m_time_zones \ 65 | ne_10m_urban_areas \ 66 | ne_50m_land \ 67 | ne_110m_land 68 | fi 69 | 70 | popd 71 | 72 | ## IMPORT 73 | 74 | $PSQL -c "drop database $PG_DBNAME;" || true 75 | $PSQL -c "create database $PG_DBNAME;" 76 | $PSQLD -c "create extension if not exists postgis;" 77 | $PSQLD -c "create extension if not exists hstore;" 78 | $PSQLD -f ./pgsql/postgis-vt-util.sql 79 | $PSQLD -f ./pgsql/functions.sql 80 | 81 | # Generate Mask Layer 82 | $PSQLD -c "create table mask as (select ST_Buffer(ST_Difference( 83 | ST_SetSRID(TileBBox(0, 0, 0), $EPSG), 84 | ST_Transform(ST_Segmentize(ST_MakeEnvelope($BBOX, 4326), 0.25), $EPSG)), 85 | -0.1) as geom);" 86 | 87 | # Generate grids 88 | printf "\\set epsg $EPSG\n" | cat - pgsql/make_grids.sql | $PSQLD 89 | 90 | 91 | export PG_USE_COPY=TRUE 92 | export OGR_ENABLE_PARTIAL_REPROJECTION=TRUE 93 | export PGCLIENTENCODING=UTF8 94 | ogr2ogr \ 95 | -s_srs EPSG:4326 \ 96 | -t_srs EPSG:$EPSG \ 97 | -segmentize 0.25 \ 98 | -f PostgreSQL \ 99 | "PG:user=$PG_USER dbname=$PG_DBNAME host=$PG_HOST port=$PG_PORT" \ 100 | "$DATADIR/natural_earth_arctic.sqlite" \ 101 | -lco GEOMETRY_NAME=geom \ 102 | -nlt GEOMETRY 103 | 104 | export PGCLIENTENCODING=UTF8 105 | osm2pgsql \ 106 | --num-processes=$PROCS \ 107 | --create \ 108 | --proj=$EPSG \ 109 | --database="$PG_DBNAME" \ 110 | --username="$PG_USER" \ 111 | --hstore \ 112 | "$DATADIR/arctic_latest.osm.pbf" 113 | 114 | 115 | ## PROCESS 116 | 117 | $PSQLD -f ./pgsql/pre_process.sql 118 | parallel "set -eu -o pipefail; \ 119 | printf '\\set procs $PROCS\n\\set proc {}\n' \ 120 | | cat - ./pgsql/process.sql | $PSQLD" ::: $(seq 0 $((PROCS-1))) 121 | -------------------------------------------------------------------------------- /pgsql/functions.sql: -------------------------------------------------------------------------------- 1 | create or replace function point_label_arc ( 2 | _name text, 3 | _geom geometry(point) 4 | ) 5 | returns geometry 6 | language plpgsql immutable as 7 | $function$ 8 | declare 9 | _srid integer := ST_SRID(_geom); 10 | _angle float := ST_Y(ST_Transform(_geom, 4326)); 11 | begin 12 | return MakeArc( 13 | ST_Transform(ST_Translate(ST_Transform(_geom, 4326), _angle * -1, 0), _srid), 14 | _geom, 15 | ST_Transform(ST_Translate(ST_Transform(_geom, 4326), _angle, 0), _srid) 16 | ); 17 | end; 18 | $function$; 19 | -------------------------------------------------------------------------------- /pgsql/make_grids.sql: -------------------------------------------------------------------------------- 1 | -- IMPORTANT: in order for this file to run you must first set an appropriate 2 | -- 'epsg' variable. For example, in bash: 3 | -- printf "\\set epsg 3995" | cat - make_grids.sql | psql 4 | 5 | drop table if exists grid; 6 | 7 | create table grid ( 8 | geom geometry(linestring), 9 | class text, 10 | val integer, 11 | zmin integer, 12 | zmax integer 13 | ); 14 | -- lines of latitude 15 | 16 | insert into grid ( 17 | select 18 | ST_Transform(ST_Segmentize(ST_SetSRID(ST_MakeLine( 19 | ST_MakePoint(-180, lat), ST_MakePoint(180, lat)), 20 | 4326), 0.25), :epsg) as geom, 21 | 'lat'::text as class, 22 | lat as val, 23 | case 24 | when lat % 20 = 0 then 0 25 | when lat % 10 = 0 then 2 26 | when lat % 5 = 0 then 3 27 | when lat % 2 = 0 then 4 28 | else 5 end as zmin, 29 | 99 as zmax 30 | from (select generate_series(89, 0, -1) as lat) as sub 31 | ); 32 | 33 | -- lines of longitude 34 | 35 | create or replace function mklon (_lon float, _latmax float, _epsg integer) 36 | returns geometry 37 | language plpgsql immutable as 38 | $func$ 39 | begin 40 | return ST_Transform(ST_SetSRID(ST_MakeLine( 41 | ST_MakePoint(_lon, _latmax), 42 | ST_MakePoint(_lon, 0)), 43 | 4326), 44 | _epsg 45 | ); 46 | end; 47 | $func$; 48 | 49 | -- z1 50 | insert into grid ( 51 | select 52 | mklon(lon, 80, :epsg) as geom, 53 | 'lon' as class, 54 | lon as val, 55 | 0 as zmin, 56 | 1 as zmax 57 | from (select generate_series(-180, 160, 20) as lon) as sub 58 | ); 59 | 60 | -- z2 61 | insert into grid ( 62 | select 63 | case when lon % 20 = 0 then mklon(lon, 80, :epsg) 64 | else mklon(lon, 70, :epsg) end as geom, 65 | 'lon' as class, 66 | lon as val, 67 | 2 as zmin, 68 | 2 as zmax 69 | from (select generate_series(-180, 170, 10) as lon) as sub 70 | ); 71 | 72 | -- z3 73 | insert into grid ( 74 | select 75 | case when lon % 20 = 0 then mklon(lon, 85, :epsg) 76 | when lon % 10 = 0 then mklon(lon, 75, :epsg) 77 | else mklon(lon, 65, :epsg) end as geom, 78 | 'lon' as class, 79 | lon as val, 80 | 3 as zmin, 81 | 3 as zmax 82 | from (select generate_series(-180, 175, 5) as lon) as sub 83 | ); 84 | 85 | -- z4 86 | insert into grid ( 87 | select 88 | case when lon % 20 = 0 then mklon(lon, 88, :epsg) 89 | when lon % 10 = 0 then mklon(lon, 80, :epsg) 90 | else mklon(lon, 72, :epsg) end as geom, 91 | 'lon' as class, 92 | lon as val, 93 | 4 as zmin, 94 | 4 as zmax 95 | from (select generate_series(-180, 178, 2) as lon) as sub 96 | ); 97 | 98 | -- z5 99 | insert into grid ( 100 | select 101 | case when lon % 20 = 0 then mklon(lon, 89, :epsg) 102 | when lon % 10 = 0 then mklon(lon, 85, :epsg) 103 | when lon % 2 = 0 then mklon(lon, 80, :epsg) 104 | else mklon(lon, 75, :epsg) end as geom, 105 | 'lon' as class, 106 | lon as val, 107 | 5 as zmin, 108 | 99 as zmax 109 | from (select generate_series(-180, 179, 1) as lon) as sub 110 | ); 111 | -------------------------------------------------------------------------------- /pgsql/postgis-vt-util.sql: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | ### Bounds ### 3 | 4 | Returns an array of the bounding coordinates of the input geometry - 5 | `{xmin, ymin, xmax, ymax}`. Useful for interfacing with software outside of 6 | PostGIS, among other things. 7 | 8 | If an SRID is specified the output will be the bounds of the reprojected 9 | geometry, not a reprojected bounding box. 10 | 11 | __Parameters:__ 12 | 13 | - `geometry` g - Any geometry 14 | - `integer` srid (optional) - The desired output SRID of the bounds, if 15 | different from the input. 16 | 17 | __Returns:__ `float[]` - an array of 4 floats, `{xmin, ymin, xmax, ymax}` 18 | ******************************************************************************/ 19 | create or replace function Bounds (g geometry, srid integer = null) 20 | returns float[] 21 | language plpgsql immutable as 22 | $func$ 23 | begin 24 | if srid is not null then 25 | g := ST_Transform(g, srid); 26 | end if; 27 | 28 | return array[ 29 | ST_XMin(g), 30 | ST_YMin(g), 31 | ST_XMax(g), 32 | ST_YMax(g) 33 | ]; 34 | end; 35 | $func$; 36 | 37 | 38 | /****************************************************************************** 39 | ### CleanInt ### 40 | 41 | Returns the input text as an integer if possible, otherwise null. 42 | 43 | __Parameters:__ 44 | 45 | - `text` i - Text that you would like as an integer. 46 | 47 | __Returns:__ `integer` 48 | ******************************************************************************/ 49 | create or replace function CleanInt (i text) 50 | returns integer 51 | language plpgsql immutable as 52 | $func$ 53 | begin 54 | return cast(cast(i as float) as integer); 55 | exception 56 | when invalid_text_representation then 57 | return null; 58 | when numeric_value_out_of_range then 59 | return null; 60 | end; 61 | $func$; 62 | 63 | 64 | /****************************************************************************** 65 | ### CleanNumeric ### 66 | 67 | Returns the input text as an numeric if possible, otherwise null. 68 | 69 | __Parameters:__ 70 | 71 | - `text` i - Text that you would like as an numeric. 72 | 73 | __Returns:__ `numeric` 74 | ******************************************************************************/ 75 | create or replace function CleanNumeric (i text) 76 | returns numeric 77 | language plpgsql immutable as 78 | $$ 79 | begin 80 | return cast(cast(i as float) as numeric); 81 | exception 82 | when invalid_text_representation then 83 | return null; 84 | when numeric_value_out_of_range then 85 | return null; 86 | end; 87 | $$; 88 | 89 | 90 | /****************************************************************************** 91 | ### LabelGrid ### 92 | 93 | Returns a "hash" of a geometry's position on a specified grid to use in a GROUP 94 | BY clause. Useful for limiting the density of points or calculating a localized 95 | importance ranking. 96 | 97 | This function is most useful on point geometries intended for label placement 98 | (eg points of interest) but will accept any geometry type. It is usually used 99 | as part of either a `DISTINCT ON` expression or a `rank()` window function. 100 | 101 | __Parameters:__ 102 | 103 | - `geometry` g - A geometry. 104 | - `numeric` grid_size - The cell size of the desired grouping grid. 105 | 106 | __Returns:__ `text` - A text representation of the labelgrid cell 107 | 108 | __Example Mapbox Studio query:__ 109 | 110 | ```sql 111 | ( SELECT * FROM ( 112 | SELECT DISTINCT ON (LabelGrid(geom, 64*!pixel_width!)) * FROM ( 113 | SELECT id, name, class, population, geom FROM city_points 114 | WHERE geom && !bbox! 115 | ) AS raw 116 | ORDER BY LabelGrid(geom, 64*!pixel_width!), population DESC, id 117 | ) AS filtered 118 | ORDER BY population DESC, id 119 | ) AS final 120 | ``` 121 | ******************************************************************************/ 122 | create or replace function LabelGrid ( 123 | g geometry, 124 | grid_size numeric 125 | ) 126 | returns text 127 | language plpgsql immutable as 128 | $func$ 129 | begin 130 | if grid_size <= 0 then 131 | return 'null'; 132 | end if; 133 | if GeometryType(g) <> 'POINT' then 134 | g := (select (ST_DumpPoints(g)).geom limit 1); 135 | end if; 136 | return ST_AsText(ST_SnapToGrid( 137 | g, 138 | grid_size/2, -- x origin 139 | grid_size/2, -- y origin 140 | grid_size, -- x size 141 | grid_size -- y size 142 | )); 143 | end; 144 | $func$; 145 | 146 | 147 | /****************************************************************************** 148 | ### LargestPart ### 149 | 150 | Returns the largest single part of a multigeometry. 151 | 152 | - Given a multipolygon or a geometrycollection containing at least one polygon, 153 | this function will return the single polygon with the largest area. 154 | - Given a multilinestring or a geometrycollection containing at least one 155 | linestring and no polygons, this function will return the single linestring 156 | with the longest length. 157 | - Given a single point, line, or polygon, the original geometry will be 158 | returned. 159 | - Given any other geometry type the result of ST_GeometryN(, 1) will be 160 | returned. (See the documentation for that function.) 161 | 162 | __Parameters:__ 163 | 164 | - `geometry` g - A geometry. 165 | 166 | __Returns:__ `geometry` - The largest single part of the input geometry. 167 | ******************************************************************************/ 168 | create or replace function LargestPart (g geometry) 169 | returns geometry 170 | language plpgsql immutable as 171 | $func$ 172 | begin 173 | -- Non-multi geometries can just pass through 174 | if GeometryType(g) in ('POINT', 'LINESTRING', 'POLYGON') then 175 | return g; 176 | -- MultiPolygons and GeometryCollections that contain Polygons 177 | elsif not ST_IsEmpty(ST_CollectionExtract(g, 3)) then 178 | return ( 179 | select geom 180 | from ( 181 | select (ST_Dump(ST_CollectionExtract(g,3))).geom 182 | ) as dump 183 | order by ST_Area(geom) desc 184 | limit 1 185 | ); 186 | -- MultiLinestrings and GeometryCollections that contain Linestrings 187 | elsif not ST_IsEmpty(ST_CollectionExtract(g, 2)) then 188 | return ( 189 | select geom 190 | from ( 191 | select (ST_Dump(ST_CollectionExtract(g,2))).geom 192 | ) as dump 193 | order by ST_Length(geom) desc 194 | limit 1 195 | ); 196 | -- Other geometry types are not really handled but we at least try to 197 | -- not return a MultiGeometry. 198 | else 199 | return ST_GeometryN(g, 1); 200 | end if; 201 | end; 202 | $func$; 203 | 204 | 205 | /****************************************************************************** 206 | ### LineLabel ### 207 | 208 | This function tries to estimate whether a line geometry would be long enough to 209 | have the given text placed along it at the specified scale. 210 | 211 | It is useful in vector tile queries to filter short lines from zoom levels 212 | where they would be unlikely to have text places on them anyway. 213 | 214 | __Parameters:__ 215 | 216 | - `numeric` zoom - The Web Mercator zoom level you are considering. 217 | - `text` label - The label text that you will be placing along the line. 218 | - `geometry(linestring)` g - A line geometry. 219 | 220 | __Returns:__ `boolean` 221 | ******************************************************************************/ 222 | create or replace function LineLabel ( 223 | zoom numeric, 224 | label text, 225 | g geometry 226 | ) 227 | returns boolean 228 | language plpgsql immutable as 229 | $func$ 230 | begin 231 | if zoom > 20 or ST_Length(g) = 0 then 232 | -- if length is 0 geom is (probably) a point; keep it 233 | return true; 234 | else 235 | return length(label) between 1 and ST_Length(g)/(2^(20-zoom)); 236 | end if; 237 | end; 238 | $func$; 239 | 240 | 241 | /****************************************************************************** 242 | ### MakeArc ### 243 | 244 | Creates a CircularString arc based on 3 input points. 245 | 246 | __Parameters:__ 247 | 248 | - `geometry(point)` p0 - The starting point of the arc. 249 | - `geometry(point)` p1 - A point along the path of th arc. 250 | - `geometry(point)` p2 - The end point of the arc. 251 | - `integer` srid (optional) - Sets the SRID of the output geometry. Useful 252 | when input points have no SRID. If not specified the SRID of the first 253 | input geometry will be assigned to the output. 254 | 255 | __Returns:__ `geometry(linestring)` 256 | 257 | __Examples:__ 258 | 259 | 260 | ```sql 261 | SELECT MakeArc( 262 | ST_MakePoint(-100, 0), 263 | ST_MakePoint(0, 100), 264 | ST_MakePoint(100, 0), 265 | 3857 266 | ); 267 | ``` 268 | ******************************************************************************/ 269 | create or replace function MakeArc ( 270 | p0 geometry(point), 271 | p1 geometry(point), 272 | p2 geometry(point), 273 | srid integer default null 274 | ) 275 | returns geometry 276 | language plpgsql immutable as 277 | $func$ 278 | begin 279 | return ST_CurveToLine(ST_GeomFromText( 280 | 'CIRCULARSTRING(' 281 | || ST_X(p0) || ' ' || ST_Y(p0) || ', ' 282 | || ST_X(p1) || ' ' || ST_Y(p1) || ', ' 283 | || ST_X(p2) || ' ' || ST_Y(p2) || ')', 284 | coalesce(srid, ST_SRID(p0)) 285 | )); 286 | end; 287 | $func$; 288 | 289 | 290 | /****************************************************************************** 291 | ### MercBuffer ### 292 | 293 | Wraps ST_Buffer to adjust the buffer distance by latitude in order to 294 | approximate real-world measurements. Assumes input geometries are Web Mercator 295 | and input distances are real-world meters. Accuracy decreases for larger buffer 296 | distances and at extreme latitudes. 297 | 298 | __Parameters:__ 299 | 300 | - `geometry` g - A geometry to buffer. 301 | - `numeric` distance - The distance you would like to buffer, in real-world 302 | meters. 303 | 304 | __Returns:__ `geometry` 305 | ******************************************************************************/ 306 | create or replace function MercBuffer (g geometry, distance numeric) 307 | returns geometry 308 | language plpgsql immutable as 309 | $func$ 310 | begin 311 | return ST_Buffer( 312 | g, 313 | distance / cos(radians(ST_Y(ST_Transform(ST_Centroid(g),4326)))) 314 | ); 315 | end; 316 | $func$; 317 | 318 | 319 | /****************************************************************************** 320 | ### MercDWithin ### 321 | 322 | Wrapper for ST_DWithin that adjusts distance by latitude to approximate real- 323 | world measurements. Assumes input geometries are Web Mercator and input 324 | distances are real-world meters. Accuracy decreases for larger distances and at 325 | extreme latitudes. 326 | 327 | __Parameters:__ 328 | 329 | - `geometry` g1 - The first geometry. 330 | - `geometry` g2 - The second geometry. 331 | - `numeric` distance - The maximum distance to check against 332 | 333 | __Returns:__ `boolean` 334 | ******************************************************************************/ 335 | create or replace function MercDWithin ( 336 | g1 geometry, 337 | g2 geometry, 338 | distance numeric 339 | ) 340 | returns boolean 341 | language plpgsql immutable as 342 | $func$ 343 | begin 344 | return ST_Dwithin( 345 | g1, 346 | g2, 347 | distance / cos(radians(ST_Y(ST_Transform(ST_Centroid(g1),4326)))) 348 | ); 349 | end; 350 | $func$; 351 | 352 | 353 | /****************************************************************************** 354 | ### MercLength ### 355 | 356 | Wrapper for ST_Length that adjusts distance by latitude to approximate real- 357 | world measurements. Assumes input geometries are Web Mercator. Accuracy 358 | decreases for larger y-axis ranges of the input. 359 | 360 | __Parameters:__ 361 | 362 | - `geometry` g - A (multi)linestring geometry. 363 | 364 | __Returns:__ `numeric` 365 | ******************************************************************************/ 366 | create or replace function MercLength (g geometry) 367 | returns numeric 368 | language plpgsql immutable as 369 | $func$ 370 | begin 371 | return ST_Length(g) * cos(radians(ST_Y(ST_Transform(ST_Centroid(g),4326)))); 372 | end; 373 | $func$; 374 | 375 | 376 | /****************************************************************************** 377 | ### OrientedEnvelope ### 378 | 379 | Returns the oriented minimum-bounding rectangle of a geometry. 380 | 381 | __Parameters:__ 382 | 383 | - `geometry` g - A geometry. 384 | 385 | __Returns:__ `geometry(polygon)` 386 | ******************************************************************************/ 387 | create or replace function OrientedEnvelope (g geometry) 388 | returns geometry(polygon) 389 | language plpgsql immutable as 390 | $func$ 391 | declare 392 | p record; 393 | p0 geometry(point); 394 | p1 geometry(point); 395 | ctr geometry(point); 396 | angle_min float; 397 | angle_cur float; 398 | area_min float; 399 | area_cur float; 400 | begin 401 | -- Approach is based on the rotating calipers method: 402 | -- 403 | g := ST_ConvexHull(g); 404 | ctr := ST_Centroid(g); 405 | for p in (select (ST_DumpPoints(g)).geom) loop 406 | p0 := p1; 407 | p1 := p.geom; 408 | if p0 is null then 409 | continue; 410 | end if; 411 | angle_cur := ST_Azimuth(p0, p1) - pi()/2; 412 | area_cur := ST_Area(ST_Envelope(ST_Rotate(g, angle_cur, ctr))); 413 | if area_cur < area_min or area_min is null then 414 | area_min := area_cur; 415 | angle_min := angle_cur; 416 | end if; 417 | end loop; 418 | return ST_Rotate(ST_Envelope(ST_Rotate(g, angle_min, ctr)), -angle_min, ctr); 419 | end; 420 | $func$; 421 | 422 | 423 | /****************************************************************************** 424 | ### SmartShrink ### 425 | 426 | Buffers a polygon progressively (on an exponential scale) until the 427 | area of the result hits a certain threshold ratio to the original area. 428 | The result is also simplified with a tolerance matching the inset 429 | distance. 430 | 431 | __Parameters:__ 432 | 433 | - `geometry` g - A (multi)polygon. 434 | - `float` ratio - The threshold for how much smaller (by area) you want 435 | the shrunk polygon to be compared to the original. Eg a value of 0.6 436 | would result in a polygon that is at least 60% as large as the input. 437 | - `boolean` simplify - Defaults to false. Whether or not you would 438 | like the shrunk geometry simplified. 439 | 440 | __Returns:__ `geometry` 441 | ******************************************************************************/ 442 | create or replace function SmartShrink( 443 | geom geometry, 444 | ratio float, 445 | simplify boolean = false 446 | ) 447 | returns geometry 448 | language plpgsql immutable as 449 | $func$ 450 | declare 451 | full_area float := ST_Area(geom); 452 | buf0 geometry; 453 | buf1 geometry := geom; 454 | d0 float := 0; 455 | d1 float := 2; 456 | begin 457 | while ST_Area(buf1) > (full_area * ratio) loop 458 | d0 := d1; 459 | d1 := d1 * 2; 460 | buf0 := buf1; 461 | buf1 := ST_Buffer(geom, -d1, 'quad_segs=0'); 462 | end loop; 463 | if simplify = true then 464 | return ST_SimplifyPreserveTopology(buf0, d0); 465 | else 466 | return buf0; 467 | end if; 468 | end; 469 | $func$; 470 | 471 | 472 | /****************************************************************************** 473 | ### TileBBox ### 474 | 475 | Given a Web Mercator tile ID as (z, x, y), returns a bounding-box 476 | geometry of the area covered by that tile. 477 | 478 | __Parameters:__ 479 | 480 | - `integer` z - A tile zoom level. 481 | - `integer` x - A tile x-position. 482 | - `integer` y - A tile y-position. 483 | - `integer` srid - SRID of the desired target projection of the bounding 484 | box. Defaults to 3857 (Web Mercator). 485 | 486 | __Returns:__ `geometry(polygon)` 487 | ******************************************************************************/ 488 | create or replace function TileBBox (z int, x int, y int, srid int = 3857) 489 | returns geometry 490 | language plpgsql immutable as 491 | $func$ 492 | declare 493 | max numeric := 20037508.34; 494 | res numeric := (max*2)/(2^z); 495 | bbox geometry; 496 | begin 497 | bbox := ST_MakeEnvelope( 498 | -max + (x * res), 499 | max - (y * res), 500 | -max + (x * res) + res, 501 | max - (y * res) - res, 502 | 3857 503 | ); 504 | if srid = 3857 then 505 | return bbox; 506 | else 507 | return ST_Transform(bbox, srid); 508 | end if; 509 | end; 510 | $func$; 511 | 512 | 513 | /****************************************************************************** 514 | ### ToPoint ### 515 | 516 | Helper to wrap ST_PointOnSurface, ST_MakeValid. This is needed because 517 | of a ST_PointOnSurface bug in geos < 3.3.8 where POLYGON EMPTY can pass 518 | through as a polygon geometry. 519 | 520 | __Parameters:__ 521 | 522 | - `geometry` g - A geometry. 523 | 524 | __Returns:__ `geometry(point)` 525 | 526 | __Example:__ 527 | 528 | ```sql 529 | -- Create an additional point geometry colums for labeling 530 | ALTER TABLE city_park ADD COLUMN geom_label geometry(point); 531 | UPDATE city_park SET geom_label = ToPoint(geom); 532 | ``` 533 | ******************************************************************************/ 534 | create or replace function ToPoint (g geometry) 535 | returns geometry(point) 536 | language plpgsql immutable as 537 | $func$ 538 | begin 539 | g := ST_MakeValid(g); 540 | if GeometryType(g) = 'POINT' then 541 | return g; 542 | elsif ST_IsEmpty(g) then 543 | -- This should not be necessary with Geos >= 3.3.7, but we're getting 544 | -- mystery MultiPoint objects from ST_MakeValid (or somewhere) when 545 | -- empty objects are input. 546 | return null; 547 | else 548 | return ST_PointOnSurface(g); 549 | end if; 550 | end; 551 | $func$; 552 | 553 | 554 | /****************************************************************************** 555 | ### ZRES ### 556 | 557 | Takes a web mercator zoom level and returns the pixel resolution for that 558 | scale, assuming 256x256 pixel tiles. Non-integer zoom levels are accepted. 559 | 560 | __Parameters:__ 561 | 562 | - `float` z - A Web Mercator zoom level. 563 | 564 | __Returns:__ `float` 565 | 566 | __Examples:__ 567 | 568 | ```sql 569 | -- Delete all polygons smaller than 1px square at zoom level 10 570 | DELETE FROM water_polygons WHERE sqrt(ST_Area(geom)) < ZRes(10); 571 | 572 | -- Simplify geometries to a resolution appropriate for zoom level 10 573 | UPDATE water_polygons SET geom = ST_Simplify(geom, ZRes(10)); 574 | ``` 575 | ******************************************************************************/ 576 | create or replace function ZRes (z float) 577 | returns float 578 | language plpgsql immutable as 579 | $func$ 580 | begin 581 | return (40075016.6855785/(256*2^z)); 582 | end; 583 | $func$; 584 | 585 | 586 | /****************************************************************************** 587 | ### Z ### 588 | 589 | Returns a Web Mercator integer zoom level given a scale denominator. 590 | 591 | Useful with Mapnik's !scale_denominator! token in vector tile source 592 | queries. 593 | 594 | __Parameters:__ 595 | 596 | - `numeric` scale_denominator - The denominator of the scale, eg `250000` 597 | for a 1:250,000 scale. 598 | 599 | __Returns:__ `integer` 600 | 601 | __Example Mapbox Studio query:__ 602 | 603 | ```sql 604 | ( SELECT * FROM roads 605 | WHERE Z(!scale_denominator!) >= 12 606 | ) AS data 607 | ``` 608 | ******************************************************************************/ 609 | create or replace function z (numeric) 610 | returns integer 611 | language plpgsql immutable as 612 | $func$ 613 | begin 614 | -- Don't bother if the scale is larger than ~zoom level 0 615 | if $1 > 600000000 then 616 | return null; 617 | end if; 618 | return round(log(2,559082264.028/$1)); 619 | end; 620 | $func$; 621 | 622 | 623 | -------------------------------------------------------------------------------- /pgsql/pre_process.sql: -------------------------------------------------------------------------------- 1 | --alter table planet_osm_point add column label_line geometry; 2 | 3 | alter table ne_10m_admin_0_countries add column geom_pt geometry(point); 4 | create index ne_10m_admin_0_countries_geom_pt on ne_10m_admin_0_countries using gist (geom_pt); 5 | 6 | alter table ne_10m_admin_1_states_provinces_shp add column geom_pt geometry(point); 7 | create index ne_10m_admin_1_states_provinces_shp_geom_pt on ne_10m_admin_1_states_provinces_shp using gist (geom_pt); 8 | 9 | alter table ne_10m_populated_places_simple add column label_line geometry; 10 | 11 | create index grid_geom on grid using gist (geom); 12 | create index mask_geom on mask using gist (geom); 13 | -------------------------------------------------------------------------------- /pgsql/process.sql: -------------------------------------------------------------------------------- 1 | -- IMPORTANT: this file is not meant to be run directly. 2 | 3 | -- This file is multi-processed in parallel and requires that statements 4 | -- are written to work well being run multiple times at once. At run-time 5 | -- the variables :cores and :mod are available to allow you to split up 6 | -- your statements by id based on the number of processes being run. In 7 | -- most cases you can use them by adding a condition like this: 8 | -- [...] WHERE (gid % :procs) = :proc [...] 9 | 10 | update ne_10m_admin_0_countries 11 | set geom_pt = ST_PointOnSurface(LargestPart(geom)) 12 | where (ogc_fid % :procs) = :proc; 13 | 14 | update ne_10m_admin_1_states_provinces_shp 15 | set geom_pt = ST_PointOnSurface(LargestPart(geom)) 16 | where (ogc_fid % :procs) = :proc; 17 | 18 | update ne_10m_populated_places_simple 19 | set label_line = point_label_arc(name, geom) 20 | where (ogc_fid % :procs) = :proc; 21 | -------------------------------------------------------------------------------- /polarmap-source.tm2source/.thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajashton/polarmap/64070005d342704859d8494e76a83122c5677b22/polarmap-source.tm2source/.thumb.png -------------------------------------------------------------------------------- /polarmap-source.tm2source/data.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -1.3184,-9.1021,4 7 | pbf 8 | 9 | 8 10 | 0 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | = 6 43 | AND geom && !bbox! 44 | ) AS data]]> 45 | 46 | 47 | 48 | 49 | 50 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 69 | 70 | 71 | 72 | 73 | 74 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | = scalerank 102 | ) AS data]]> 103 | 104 | 105 | 106 | 107 | 108 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 136 | 137 | 138 | 139 | 140 | 141 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | = scalerank 159 | ) AS data]]> 160 | 161 | 162 | 163 | 164 | 165 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 184 | 185 | 186 | 187 | 188 | 189 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | = 5 THEN TRUE 216 | WHEN z(!scale_denominator!) = 4 AND val % 2 = 0 THEN TRUE 217 | WHEN z(!scale_denominator!) = 3 AND val % 5 = 0 THEN TRUE 218 | WHEN z(!scale_denominator!) = 2 AND val % 10 = 0 THEN TRUE 219 | WHEN z(!scale_denominator!) = 1 AND val % 20 = 0 THEN TRUE 220 | ELSE FALSE END 221 | ) AS data]]> 222 | 223 | 224 | 225 | 226 | 227 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | = scalerank 245 | ORDER BY scalerank ASC, pop_est DESC 246 | ) AS data]]> 247 | 248 | 249 | 250 | 251 | 252 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | = scalerank 270 | ORDER BY scalerank ASC, area_sqkm DESC 271 | ) AS data]]> 272 | 273 | 274 | 275 | 276 | 277 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 302 | 303 | 304 | 305 | 306 | 307 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 331 | 332 | 333 | 334 | 335 | 336 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | = scalerank 354 | ) AS data]]> 355 | 356 | 357 | 358 | 359 | 360 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | -------------------------------------------------------------------------------- /polarmap-source.tm2source/data.yml: -------------------------------------------------------------------------------- 1 | _prefs: 2 | disabled: 3 | - place_label 4 | - place_label_lines 5 | - state_label 6 | - country_label 7 | inspector: false 8 | mapid: aj.caaa01d5 9 | rev: s-8fa35ea5 10 | saveCenter: true 11 | attribution: '' 12 | center: 13 | - -1.3184 14 | - -9.1021 15 | - 4 16 | description: '' 17 | Layer: 18 | - id: land 19 | Datasource: 20 | dbname: polarmap 21 | extent: -20037508.34,-20037508.34,20037508.34,20037508.34 22 | geometry_field: '' 23 | geometry_table: '' 24 | host: localhost 25 | key_field: '' 26 | max_size: 512 27 | password: '' 28 | port: 5432 29 | srid: '' 30 | table: |- 31 | ( SELECT geom 32 | FROM ne_110m_land 33 | WHERE z(!scale_denominator!) <= 2 34 | AND geom && !bbox! 35 | UNION ALL 36 | SELECT geom 37 | FROM ne_50m_land 38 | WHERE z(!scale_denominator!) BETWEEN 3 AND 5 39 | AND geom && !bbox! 40 | UNION ALL 41 | SELECT geom 42 | FROM ne_10m_land 43 | WHERE z(!scale_denominator!) >= 6 44 | AND geom && !bbox! 45 | ) AS data 46 | type: postgis 47 | user: postgres 48 | description: '' 49 | fields: {} 50 | properties: 51 | "buffer-size": 8 52 | 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 53 | - id: urban 54 | Datasource: 55 | dbname: polarmap 56 | extent: -20037508.34,-20037508.34,20037508.34,20037508.34 57 | geometry_field: '' 58 | geometry_table: '' 59 | host: localhost 60 | key_field: '' 61 | max_size: 512 62 | password: '' 63 | port: 5432 64 | srid: '' 65 | table: |- 66 | ( SELECT geom 67 | FROM ne_10m_urban_areas 68 | WHERE geom && !bbox! 69 | ) AS data 70 | type: postgis 71 | user: postgres 72 | description: '' 73 | fields: {} 74 | properties: 75 | "buffer-size": 2 76 | 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 77 | - id: state_boundaries 78 | Datasource: 79 | dbname: polarmap 80 | extent: -20037508.34,-20037508.34,20037508.34,20037508.34 81 | geometry_field: '' 82 | geometry_table: '' 83 | host: localhost 84 | key_field: '' 85 | max_size: 512 86 | password: '' 87 | port: 5432 88 | srid: '' 89 | table: |- 90 | ( SELECT 91 | geom, 92 | scalerank, 93 | featurecla AS class, 94 | name, 95 | adm0_a3, 96 | adm0_name, 97 | name_l, 98 | name_r, 99 | sov_a3 100 | FROM ne_10m_admin_1_states_provinces_lines_shp 101 | WHERE geom && !bbox! 102 | AND z(!scale_denominator!)+2 >= scalerank 103 | ) AS data 104 | type: postgis 105 | user: postgres 106 | description: '' 107 | fields: 108 | adm0_a3: String 109 | adm0_name: String 110 | class: String 111 | name: String 112 | name_l: String 113 | name_r: String 114 | scalerank: Number 115 | sov_a3: String 116 | properties: 117 | "buffer-size": 8 118 | 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 119 | - id: country_boundaries 120 | Datasource: 121 | dbname: polarmap 122 | extent: -20037508.34,-20037508.34,20037508.34,20037508.34 123 | geometry_field: '' 124 | geometry_table: '' 125 | host: localhost 126 | key_field: '' 127 | max_size: 512 128 | password: '' 129 | port: 5432 130 | srid: '' 131 | table: |- 132 | ( SELECT 133 | geom, 134 | scalerank, 135 | featurecla AS class, 136 | name, 137 | adm0_left, 138 | adm0_right, 139 | adm0_a3_l, 140 | adm0_a3_r, 141 | type 142 | FROM ne_10m_admin_0_boundary_lines_land 143 | WHERE geom && !bbox! 144 | ) AS data 145 | type: postgis 146 | user: postgres 147 | description: '' 148 | fields: 149 | adm0_a3_l: String 150 | adm0_a3_r: String 151 | adm0_left: String 152 | adm0_right: String 153 | class: String 154 | name: String 155 | scalerank: Number 156 | type: String 157 | properties: 158 | "buffer-size": 8 159 | 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 160 | - id: roads 161 | Datasource: 162 | dbname: polarmap 163 | extent: -20037508.34,-20037508.34,20037508.34,20037508.34 164 | geometry_field: '' 165 | geometry_table: '' 166 | host: localhost 167 | key_field: '' 168 | max_size: 512 169 | password: '' 170 | port: 5432 171 | srid: '' 172 | table: |- 173 | ( SELECT * FROM ne_10m_roads 174 | WHERE geom && !bbox! 175 | AND z(!scale_denominator!)+3 >= scalerank 176 | ) AS data 177 | type: postgis 178 | user: postgres 179 | description: '' 180 | fields: 181 | add: Number 182 | continent: String 183 | edited: String 184 | expressway: Number 185 | featurecla: String 186 | ignore: Number 187 | label: String 188 | label2: String 189 | labelrank: Number 190 | length_km: Number 191 | level: String 192 | local: String 193 | localalt: String 194 | localtype: String 195 | name: String 196 | namealt: String 197 | namealtt: String 198 | ne_part: String 199 | note: String 200 | ogc_fid: Number 201 | orig_fid: Number 202 | prefix: String 203 | question: Number 204 | routeraw: String 205 | rwdb_rd_id: Number 206 | scalerank: Number 207 | sov_a3: String 208 | toll: Number 209 | type: String 210 | uident: Number 211 | properties: 212 | "buffer-size": 8 213 | 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 214 | - id: geographic_lines 215 | Datasource: 216 | dbname: polarmap 217 | extent: -20037508.34,-20037508.34,20037508.34,20037508.34 218 | geometry_field: '' 219 | geometry_table: '' 220 | host: localhost 221 | key_field: '' 222 | max_size: 512 223 | password: '' 224 | port: 5432 225 | srid: '' 226 | table: |- 227 | ( SELECT geom, name, name_long, abbrev, featurecla AS class 228 | FROM ne_10m_geographic_lines 229 | WHERE geom && !bbox! 230 | ) AS data 231 | type: postgis 232 | user: postgres 233 | description: '' 234 | fields: 235 | abbrev: String 236 | class: String 237 | name: String 238 | name_long: String 239 | properties: 240 | "buffer-size": 2 241 | 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 242 | - id: grid 243 | Datasource: 244 | dbname: polarmap 245 | extent: -20037508.34,-20037508.34,20037508.34,20037508.34 246 | geometry_field: '' 247 | geometry_table: '' 248 | host: localhost 249 | key_field: '' 250 | max_size: 512 251 | password: '' 252 | port: 5432 253 | srid: '' 254 | table: |- 255 | ( SELECT geom, class, val 256 | FROM grid 257 | WHERE ST_Intersects(geom, !bbox!) 258 | AND class = 'lon' 259 | AND z(!scale_denominator!) BETWEEN zmin AND zmax 260 | UNION ALL 261 | SELECT geom, class, val 262 | FROM grid 263 | WHERE ST_Intersects(geom, !bbox!) 264 | AND class = 'lat' 265 | AND CASE 266 | WHEN z(!scale_denominator!) >= 5 THEN TRUE 267 | WHEN z(!scale_denominator!) = 4 AND val % 2 = 0 THEN TRUE 268 | WHEN z(!scale_denominator!) = 3 AND val % 5 = 0 THEN TRUE 269 | WHEN z(!scale_denominator!) = 2 AND val % 10 = 0 THEN TRUE 270 | WHEN z(!scale_denominator!) = 1 AND val % 20 = 0 THEN TRUE 271 | ELSE FALSE END 272 | ) AS data 273 | type: postgis 274 | user: postgres 275 | description: '' 276 | fields: 277 | class: String 278 | val: Number 279 | properties: 280 | "buffer-size": 8 281 | 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 282 | - id: country_label 283 | Datasource: 284 | dbname: polarmap 285 | extent: -20037508.34,-20037508.34,20037508.34,20037508.34 286 | geometry_field: '' 287 | geometry_table: '' 288 | host: localhost 289 | key_field: '' 290 | max_size: 512 291 | password: '' 292 | port: 5432 293 | srid: '' 294 | table: |- 295 | ( SELECT geom_pt AS geom, scalerank, name, abbrev 296 | FROM ne_10m_admin_0_countries 297 | WHERE z(!scale_denominator!)+2 >= scalerank 298 | ORDER BY scalerank ASC, pop_est DESC 299 | ) AS data 300 | type: postgis 301 | user: postgres 302 | description: '' 303 | fields: 304 | abbrev: String 305 | name: String 306 | scalerank: Number 307 | properties: 308 | "buffer-size": 64 309 | 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 310 | - id: state_label 311 | Datasource: 312 | dbname: polarmap 313 | extent: -20037508.34,-20037508.34,20037508.34,20037508.34 314 | geometry_field: '' 315 | geometry_table: '' 316 | host: localhost 317 | key_field: '' 318 | max_size: 512 319 | password: '' 320 | port: 5432 321 | srid: '' 322 | table: |- 323 | ( SELECT geom_pt AS geom, scalerank, name, abbrev, iso_a2 324 | FROM ne_10m_admin_1_states_provinces_shp 325 | WHERE z(!scale_denominator!)+2 >= scalerank 326 | ORDER BY scalerank ASC, area_sqkm DESC 327 | ) AS data 328 | type: postgis 329 | user: postgres 330 | description: '' 331 | fields: 332 | abbrev: String 333 | iso_a2: String 334 | name: String 335 | scalerank: Number 336 | properties: 337 | "buffer-size": 64 338 | 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 339 | - id: place_label_lines 340 | Datasource: 341 | dbname: polarmap 342 | extent: -20037508.34,-20037508.34,20037508.34,20037508.34 343 | geometry_field: '' 344 | geometry_table: '' 345 | host: localhost 346 | key_field: '' 347 | max_size: 512 348 | password: '' 349 | port: 5432 350 | srid: '' 351 | table: |- 352 | ( SELECT 353 | ST_Intersection(label_line, ST_Buffer( 354 | geom, !pixel_width! * char_length(name) * 2)) AS geom, 355 | name, 356 | scalerank 357 | FROM ne_10m_populated_places_simple 358 | WHERE geom && !bbox! 359 | AND scalerank <= z(!scale_denominator!)+2 360 | ORDER BY scalerank ASC, pop_max DESC NULLS LAST 361 | ) AS data 362 | type: postgis 363 | user: postgres 364 | description: '' 365 | fields: 366 | name: String 367 | scalerank: Number 368 | properties: 369 | "buffer-size": 64 370 | 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 371 | - id: place_label 372 | Datasource: 373 | dbname: polarmap 374 | extent: -20037508.34,-20037508.34,20037508.34,20037508.34 375 | geometry_field: '' 376 | geometry_table: '' 377 | host: localhost 378 | key_field: '' 379 | max_size: 512 380 | password: '' 381 | port: 5432 382 | srid: '' 383 | table: |- 384 | ( SELECT 385 | geom, 386 | name, 387 | scalerank 388 | FROM ne_10m_populated_places_simple 389 | WHERE geom && !bbox! 390 | AND scalerank <= z(!scale_denominator!)+2 391 | ORDER BY scalerank ASC, pop_max DESC NULLS LAST 392 | ) AS data 393 | type: postgis 394 | user: postgres 395 | description: '' 396 | fields: 397 | name: String 398 | scalerank: Number 399 | properties: 400 | "buffer-size": 64 401 | 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 402 | - id: airports 403 | Datasource: 404 | dbname: polarmap 405 | extent: -20037508.34,-20037508.34,20037508.34,20037508.34 406 | geometry_field: '' 407 | geometry_table: '' 408 | host: localhost 409 | key_field: '' 410 | max_size: 512 411 | password: '' 412 | port: 5432 413 | srid: '' 414 | table: |- 415 | ( SELECT * FROM ne_10m_airports 416 | WHERE geom && !bbox! 417 | AND z(!scale_denominator!) >= scalerank 418 | ) AS data 419 | type: postgis 420 | user: postgres 421 | description: '' 422 | fields: 423 | abbrev: String 424 | featurecla: String 425 | gps_code: String 426 | iata_code: String 427 | location: String 428 | name: String 429 | natlscale: Number 430 | ogc_fid: Number 431 | scalerank: Number 432 | type: String 433 | wikipedia: String 434 | properties: 435 | "buffer-size": 64 436 | 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 437 | - id: mask 438 | Datasource: 439 | dbname: polarmap 440 | extent: -20037508.34,-20037508.34,20037508.34,20037508.34 441 | geometry_field: '' 442 | geometry_table: '' 443 | host: localhost 444 | key_field: '' 445 | max_size: 512 446 | password: '' 447 | port: 5432 448 | srid: '' 449 | table: mask 450 | type: postgis 451 | user: postgres 452 | description: '' 453 | fields: {} 454 | properties: 455 | "buffer-size": 2 456 | 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 457 | maxzoom: 8 458 | minzoom: 0 459 | name: Polar Map Source 460 | -------------------------------------------------------------------------------- /settings.sh: -------------------------------------------------------------------------------- 1 | PBF_URL="${PBF_URL:-http://planet.openstreetmap.org/pbf/planet-latest.osm.pbf}" 2 | DATADIR="${DATA_DIR:-/tmp/polarmap}" 3 | EPSG=3995 # should be both a valid EPSG code and valid PostGIS SRID 4 | BBOX="-180,30,180,90" # latlon xmin,ymin,xmax,ymax 5 | BBOX_OGR="${BBOX//,/ }" # like $BBOX, but no commas 6 | 7 | PG_DBNAME="${PG_DBNAME:-polarmap}" 8 | PG_USER="${PG_USER:-postgres}" 9 | PG_HOST="${PG_HOST:-localhost}" 10 | PG_PORT=${PG_PORT:-5432} 11 | PSQL="psql -U $PG_USER -h $PG_HOST -p $PG_PORT" 12 | PSQLD="$PSQL -d $PG_DBNAME" 13 | 14 | PROCS=${PROCS:-$(parallel --number-of-cores)} 15 | -------------------------------------------------------------------------------- /ubuntu/ubuntu_setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eu -o pipefail 3 | 4 | SRCDIR=${TEMP:-/tmp}/src 5 | 6 | apt_packages=( 7 | postgresql-9.3-postgis-2.1 8 | # for building osm2pgsql: 9 | autoconf 10 | automake 11 | libtool 12 | make 13 | g++ 14 | pkg-config 15 | libboost-dev 16 | libboost-system-dev 17 | libboost-filesystem-dev 18 | libboost-thread-dev 19 | libexpat1-dev 20 | libgeos-dev 21 | libgeos++-dev 22 | libpq-dev 23 | libbz2-dev 24 | libproj-dev 25 | zlib1g-dev # also needed to build osmconvert 26 | protobuf-compiler 27 | libprotobuf-dev 28 | lua5.2 29 | liblua5.2-dev 30 | ) 31 | 32 | install_packages() { 33 | sudo apt-get update 34 | sudo apt-get install -y "${apt_packages[@]}" 35 | } 36 | 37 | build_osmconvert() { 38 | wget -O - http://m.m.i24.cc/osmconvert.c | cc -x c - -lz -O3 -o osmconvert 39 | sudo mv osmconvert /usr/local/bin/ 40 | } 41 | 42 | build_osmupdate() { 43 | wget -O - http://m.m.i24.cc/osmupdate.c | cc -x c - -o osmupdate 44 | sudo mv osmupdate /usr/local/bin/ 45 | } 46 | 47 | build_osm2pgsql() { 48 | pushd "$(pwd)" 49 | git clone https://github.com/openstreetmap/osm2pgsql.git osm2pgsql 50 | cd osm2pgsql 51 | ./autogen.sh 52 | ./configure 53 | make -j8 54 | sudo make install 55 | popd 56 | } 57 | 58 | # Do it 59 | install_packages 60 | mkdir -p "$SRCDIR" 61 | cd "$SRCDIR" 62 | 63 | if [ -z "$(which osmconvert)" ]; then 64 | build_osmconvert 65 | fi 66 | 67 | if [ -z "$(which osmupdate)" ]; then 68 | build_osmupdate 69 | fi 70 | 71 | if [ -z "$(which osm2pgsql)" ]; then 72 | build_osm2pgsql 73 | fi 74 | 75 | --------------------------------------------------------------------------------