[openstreetmap-carto] 01/04: Imported Upstream version 2.41.0

Bas Couwenberg sebastic at debian.org
Wed Jul 13 10:27:43 UTC 2016


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository openstreetmap-carto.

commit 9b514a5762ac1e6fce70899b79b009fd27917abd
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Wed Jul 13 12:18:51 2016 +0200

    Imported Upstream version 2.41.0
---
 .gitignore                       |   4 +
 INSTALL.md                       |  30 ++---
 amenity-points.mss               | 171 +++++++++++++++------------
 landcover.mss                    |  36 ++++--
 placenames.mss                   |   8 --
 preview.png                      | Bin 85552 -> 85803 bytes
 project.mml                      |  13 ++-
 project.yaml                     |  41 ++++---
 road-colors-generated.mss        |  26 +++++
 road-colors.yaml                 |  43 +++++++
 roads.mss                        |  43 ++-----
 scripts/generate_road_colours.py | 223 +++++++++++++++++------------------
 scripts/generate_shields.py      | 247 +++++++++++++++++++--------------------
 scripts/yaml2mml.py              |   2 +-
 style.mss                        |  16 +--
 symbols/dog_park.16.svg          |  59 ++++++++++
 symbols/dog_park.png             | Bin 0 -> 843 bytes
 17 files changed, 552 insertions(+), 410 deletions(-)

diff --git a/.gitignore b/.gitignore
index a5319ed..4da5ad5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,7 @@ data/
 *.xml
 node_modules/
 localconfig.json
+
+# Generated at runtime by Python.
+*.pyc
+**/*.pyc
diff --git a/INSTALL.md b/INSTALL.md
index 51da6bf..75f39c0 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -42,34 +42,38 @@ The repeated www.naturalearthdata.com in the Natural Earth shapefiles is correct
 Put these shapefiles at `path/to/openstreetmap-carto/data`.
 
 ## Fonts
-The stylesheet depends on a number of openly licensed fonts for support of all the languages found on the map. The package which supplies these fonts on Ubuntu is indicated.
+The stylesheet depends on a number of openly licensed fonts for support of all the languages found on the map. The package which supplies these fonts on Ubuntu 16.04 or Debian Testing is indicated.
 
-If a font is missing, it will skip to the next available font which contains those characters. If you are not concerned with a particular language, you do not need its fonts. DejaVu Sans and Unifont are the two required fonts, and included on most systems.
+If a font is missing, it will skip to the next available font which contains those characters. If you are not concerned with a particular script, you do not need its fonts. DejaVu Sans and Unifont are the two required fonts, and included on most systems.
+
+Mapnik 3 is required for acceptable rendering of most non-Latin scripts, particularly those with complicated diacritics and tone marks.
 
 ### Global
-* DejaVu Sans, for most languages (`ttf-dejavu`)
-* Droid Sans Fallback, as a reasonable fallback (`fonts-droid`)
+* DejaVu Sans, for most languages (`fonts-dejavu-core`)
+* Droid Sans Fallback, as a reasonable fallback (`fonts-droid-fallback`)
 * Unifont, as a last resort fallback (`ttf-unifont`)
 
 ### Southeast Asia
-* Arundina Sans, for Thai (`fonts-sipa-arundina`)
+* Arundina, for Thai (`fonts-sipa-arundina`)
 * Padauk, for Burmese (`fonts-sil-padauk`)
 * Khmer OS Metal Chrieng Regular, for Khmer (`fonts-khmeros`)
 
 ### South Asia
 
-* Mukti Narrow, for Bangali (`ttf-indic-fonts-core`)
-* Gargi Medium, for Devanagari (`ttf-indic-fonts-core`)
-* TSCu_Paranar, for Tamil (`ttf-tamil-fonts` or ``fonts-taml-tscu``, depending on your Ubuntu version)
-* Mallige, for Kannada (`ttf-indic-fonts-core` for normal and bold and `ttf-kannada-fonts` for oblique) *The filename uses "Malige" but the font name uses "Mallige"*
+* Mukti Narrow, for Bangali (`fonts-beng-extra`)
+* Gargi Medium, for Devanagari (`fonts-gargi`)
+* TSCu_Paranar, for Tamil (`fonts-taml-tscu`)
+* Tibetan Machine Uni, for Tibetian (`fonts-tibetan-machine`)
 
-On Ubuntu you can install all the fonts with
+On Ubuntu 16.04 or Debian Testing you can install all the fonts with
 
 ```
-sudo apt-get install ttf-dejavu fonts-droid ttf-unifont fonts-sipa-arundina fonts-sil-padauk fonts-khmeros \
-ttf-indic-fonts-core fonts-taml-tscu ttf-kannada-fonts
+sudo apt-get install fonts-dejavu-core fonts-droid-fallback ttf-unifont \
+  fonts-sipa-arundina fonts-sil-padauk fonts-khmeros \
+  fonts-beng-extra fonts-gargi fonts-taml-tscu fonts-tibetan-machine
 ```
-In Ubuntu 13.10 (Saucy) and lower, replace fonts-taml-tscu with ttf-tamil-fonts.
+
+On Ubuntu 14.04, replace `fonts-droid-fallback` with `fonts-droid`.
 
 ## Dependencies
 
diff --git a/amenity-points.mss b/amenity-points.mss
index a25aa1a..c3e519d 100644
--- a/amenity-points.mss
+++ b/amenity-points.mss
@@ -20,6 +20,8 @@
 
 @standard-wrap-width: 30;
 @standard-text-size: 10;
+ at standard-font: @book-fonts;
+ at standard-halo-radius: 1;
 
 /* Note that .points is also used in water-features.mss */
 .points {
@@ -524,6 +526,7 @@
     marker-clip: false;
   }
 
+  [feature = 'man_made_obelisk'][zoom >= 16],
   [feature = 'historic_monument'][zoom >= 16] {
     marker-file: url('symbols/monument.16.svg');
     marker-fill: @amenity-brown;
@@ -912,6 +915,13 @@
     marker-clip: false;
   }
 
+  [feature = 'leisure_dog_park'][zoom >= 17] {
+    marker-file: url('symbols/dog_park.16.svg');
+    marker-placement: interior;
+    marker-fill: darken(@park, 60%);
+    marker-clip: false;
+  }
+
   [feature = 'leisure_playground'][zoom >= 17] {
     marker-file: url('symbols/playground.16.svg');
     marker-fill: @amenity-brown;
@@ -1129,7 +1139,7 @@
     [way_pixels > 12000] { text-size: 12; }
     [way_pixels > 48000] { text-size: 15; }
     text-face-name: @oblique-fonts;
-    text-halo-radius: 1;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1149,8 +1159,8 @@
       text-fill: @amenity-brown;
       text-size: @standard-text-size;
       text-dy: 11;
-      text-face-name: @bold-fonts;
-      text-halo-radius: 1;
+      text-face-name: @standard-font;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-wrap-width: @standard-wrap-width;
       text-placement: interior;
@@ -1174,9 +1184,9 @@
       text-size: @standard-text-size;
       text-fill: @amenity-brown;
       text-dy: 13;
-      text-face-name: @bold-fonts;
-      [feature = 'tourism_museum'] { text-face-name: @book-fonts; }
-      text-halo-radius: 1;
+      text-face-name: @standard-font;
+      [feature = 'tourism_museum'] { text-face-name: @standard-font; }
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-wrap-width: @standard-wrap-width;
       text-placement: interior;
@@ -1198,8 +1208,8 @@
     [feature = 'amenity_car_rental']     { text-dy: 10; }
     [feature = 'amenity_bicycle_rental'] { text-dy: 10; }
     [feature = 'leisure_slipway']        { text-dy: 13; }
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1212,8 +1222,8 @@
     text-size: @standard-text-size;
     text-fill: @transportation-text;
     text-dy: 9;
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1243,8 +1253,8 @@
     [feature = 'amenity_police'] { text-dy: 11; }
     [feature = 'amenity_fire_station'] { text-dy: 11; }
     [feature = 'amenity_post_office'] { text-dy: 11; }
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1255,8 +1265,8 @@
     text-size: @standard-text-size;
     text-fill: #000033;
     text-dy: 12;
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1272,8 +1282,8 @@
     [feature = 'natural_volcano'] { text-fill: #d40000; }
     text-dy: 7;
     [feature = 'tourism_viewpoint'] { text-dy: 11; }
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1296,22 +1306,23 @@
       text-dy: 6;
     }
     [feature = 'man_made_mast'] { text-dy: 10; }
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
   }
 
   [feature = 'historic_memorial'][zoom >= 17],
+  [feature = 'man_made_obelisk'][zoom >= 16],
   [feature = 'historic_monument'][zoom >= 16],
   [feature = 'historic_archaeological_site'][zoom >= 17] {
     text-name: "[name]";
     text-size: @standard-text-size;
     text-fill: @amenity-brown;
     text-dy: 11;
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1322,8 +1333,8 @@
     text-name: "[name]";
     text-size: @standard-text-size;
     text-fill: darken(@park, 60%);
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-placement: interior;
     text-dy: 13;
@@ -1339,8 +1350,8 @@
       text-size: @standard-text-size;
       text-fill: darken(@park, 60%);
       text-dy: 11;
-      text-face-name: @book-fonts;
-      text-halo-radius: 1;
+      text-face-name: @standard-font;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-wrap-width: @standard-wrap-width;
       text-placement: interior;
@@ -1363,7 +1374,7 @@
       }
       text-fill: @marina-text;
       text-face-name: @landcover-face-name;
-      text-halo-radius: 1;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-placement: interior;
     }
@@ -1378,8 +1389,8 @@
       text-size: @standard-text-size;
       text-dy: 13;
       text-fill: darken(@park, 60%);
-      text-face-name: @book-fonts;
-      text-halo-radius: 1;
+      text-face-name: @standard-font;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-wrap-width: @standard-wrap-width;
       text-placement: interior;
@@ -1408,7 +1419,7 @@
         text-wrap-width: @landcover-wrap-width-size-bigger;
       }
       text-face-name: @landcover-face-name;
-      text-halo-radius: 1;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-placement: interior;
       [feature = 'landuse_military'] {
@@ -1441,7 +1452,7 @@
       }
       text-fill: darken(@danger_area, 40%);
       text-face-name: @bold-fonts;
-      text-halo-radius: 1;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-placement: interior;
     }
@@ -1463,7 +1474,7 @@
       }
       text-fill: darken(@garages, 50%);
       text-face-name: @landcover-face-name;
-      text-halo-radius: 1;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-placement: interior;
     }
@@ -1516,6 +1527,7 @@
   [feature = 'leisure_sports_centre'],
   [feature = 'leisure_stadium'],
   [feature = 'leisure_track'],
+  [feature = 'leisure_dog_park'],
   [feature = 'leisure_pitch'] {
     [zoom >= 10][way_pixels > 3000][is_building = 'no'],
     [zoom >= 17][is_building = 'no'],
@@ -1533,7 +1545,7 @@
         text-wrap-width: @landcover-wrap-width-size-bigger;
       }
       text-face-name: @landcover-face-name;
-      text-halo-radius: 1;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-placement: interior;
       [feature = 'natural_reef'],
@@ -1608,13 +1620,13 @@
       }
       [feature = 'tourism_attraction'] {
         text-fill: #660033;
-        text-face-name: @book-fonts;
+        text-face-name: @standard-font;
       }
       [feature = 'amenity_kindergarten'],
       [feature = 'amenity_school'],
       [feature = 'amenity_college'],
       [feature = 'amenity_university'] {
-        text-fill: darken(@educational_areas_and_hospital, 70%);
+        text-fill: darken(@societal_amenities, 70%);
       }
       [feature = 'natural_heath'] {
         text-fill: darken(@heath, 40%);
@@ -1628,7 +1640,12 @@
       }
       [feature = 'leisure_sports_centre'],
       [feature = 'leisure_stadium'] {
-        text-fill: darken(@stadium, 30%);
+        text-fill: darken(@stadium, 70%);
+      }
+      [feature = 'leisure_dog_park'] {
+        text-fill: darken(@park, 60%);
+        text-halo-radius: 1.5; /* Extra halo needed to stand out from paw pattern. */
+        text-halo-fill: rgba(255,255,255,0.6);
       }
       [feature = 'leisure_track'] {
         text-fill: darken(@track, 40%);
@@ -1644,8 +1661,8 @@
     text-name: "[name]";
     text-size: 10;
     text-fill: @water-text;
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1664,11 +1681,11 @@
     [feature = 'amenity_bank'] { text-dy: 9; }
     [feature = 'amenity_atm']  { text-dy: 10; }
     text-fill: @amenity-brown;
-    text-halo-radius: 1;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
-    text-face-name: @book-fonts;
+    text-face-name: @standard-font;
   }
 
   [feature = 'tourism_alpine_hut'][zoom >= 15],
@@ -1683,8 +1700,8 @@
     text-size: @standard-text-size;
     text-fill: #0066ff;
     text-dy: 11;
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1701,8 +1718,8 @@
     text-size: @standard-text-size;
     text-fill: #0066ff;
     text-dy: 10;
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1713,8 +1730,8 @@
     text-size: @standard-text-size;
     text-fill: #0066ff;
     text-dy: 11;
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1728,8 +1745,8 @@
       text-size: @standard-text-size;
       text-fill: @transportation-text;
       text-dy: 11;
-      text-face-name: @book-fonts;
-      text-halo-radius: 1;
+      text-face-name: @standard-font;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-wrap-width: @standard-wrap-width;
       text-placement: interior;
@@ -1755,7 +1772,7 @@
       }
       text-fill: @marina-text;
       text-face-name: @landcover-face-name;
-      text-halo-radius: 1;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-placement: interior;
     }
@@ -1766,8 +1783,8 @@
     text-size: @standard-text-size;
     text-fill: @marina-text;
     text-dy: 4;
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1782,8 +1799,8 @@
     text-size: @standard-text-size;
     text-fill: @amenity-brown;
     text-dy: 12;
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1795,8 +1812,8 @@
     text-size: @standard-text-size;
     text-fill: @transportation-text;
     text-dy: 16;
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1809,8 +1826,8 @@
     text-fill: @amenity-brown;
     text-dy: 12;
     [feature = 'amenity_recycling'] { text-dy: 10; }
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1821,8 +1838,8 @@
     text-fill: @health-color;
     text-size: @standard-text-size;
     text-dy: 10;
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1839,8 +1856,8 @@
       text-size: @standard-text-size;
       text-dy: 12;
       text-fill: @health-color;
-      text-face-name: @book-fonts;
-      text-halo-radius: 1;
+      text-face-name: @standard-font;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-wrap-width: @standard-wrap-width;
       text-placement: interior;
@@ -1909,8 +1926,8 @@
       text-size: @standard-text-size;
       text-dy: 12;
       text-fill: @shop-text;
-      text-face-name: @book-fonts;
-      text-halo-radius: 1;
+      text-face-name: @standard-font;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255, 255, 255, 0.6);
       text-wrap-width: @standard-wrap-width;
       text-placement: interior;
@@ -1927,8 +1944,8 @@
       text-size: @standard-text-size;
       text-dy: 12;
       text-fill: @shop-text;
-      text-face-name: @book-fonts;
-      text-halo-radius: 1;
+      text-face-name: @standard-font;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255, 255, 255, 0.6);
       text-wrap-width: @standard-wrap-width;
       text-placement: interior;
@@ -1939,8 +1956,8 @@
     text-name: "[ref]";
     text-size: @standard-text-size;
     text-fill: #aa66cc;
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: @standard-wrap-width;
     text-placement: interior;
@@ -1966,7 +1983,7 @@
       }
       text-fill: darken(@power, 40%);
       text-face-name: @landcover-face-name;
-      text-halo-radius: 1;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-placement: interior;
     }
@@ -1990,7 +2007,7 @@
         text-wrap-width: @landcover-wrap-width-size-bigger;
       }
       text-face-name: @landcover-face-name;
-      text-halo-radius: 1;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-placement: interior;
       [feature = 'natural_scree'],
@@ -2020,7 +2037,7 @@
       }
       text-fill: darken(@apron, 60%);
       text-face-name: @landcover-face-name;
-      text-halo-radius: 1;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-placement: interior;
     }
@@ -2043,7 +2060,7 @@
       }
       text-fill: darken(@rest_area, 40%);
       text-face-name: @landcover-face-name;
-      text-halo-radius: 1;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-placement: interior;
     }
@@ -2066,7 +2083,7 @@
       }
       text-fill: mix(darken(@glacier, 40%), darken(@glacier-line, 30%), 50%);
       text-face-name: @landcover-face-name;
-      text-halo-radius: 1;
+      text-halo-radius: @standard-halo-radius;
       text-halo-fill: rgba(255,255,255,0.6);
       text-placement: interior;
     }
@@ -2077,8 +2094,8 @@
     text-size: @standard-text-size;
     text-fill: @airtransport;
     text-dy: -10;
-    text-face-name: @bold-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-placement: interior;
     text-wrap-width: @standard-wrap-width;
@@ -2090,7 +2107,7 @@
     text-fill: darken(@airtransport, 15%);
     text-dy: -10;
     text-face-name: @oblique-fonts;
-    text-halo-radius: 1;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-placement: interior;
     text-wrap-width: @standard-wrap-width;
@@ -2101,8 +2118,8 @@
     text-size: @standard-text-size;
     text-dy: 11;
     text-fill: @man-made-icon;
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-placement: interior;
     text-wrap-width: @standard-wrap-width;
@@ -2116,8 +2133,8 @@
     [zoom >= 18] { text-dy: 8; }
     [zoom >= 19] { text-dy: 11; }
     [zoom >= 20] { text-dy: 18; }
-    text-face-name: @book-fonts;
-    text-halo-radius: 1;
+    text-face-name: @standard-font;
+    text-halo-radius: @standard-halo-radius;
     text-halo-fill: rgba(255,255,255,0.6);
     text-placement: interior;
     text-wrap-width: @standard-wrap-width;
diff --git a/landcover.mss b/landcover.mss
index 132b135..c2d00d8 100644
--- a/landcover.mss
+++ b/landcover.mss
@@ -1,19 +1,12 @@
 // --- Parks, woods, other green things ---
 
 @grass: #cdebb0; // also meadow, common, garden, village_green
- at golf_course: #b5e3b5;
 @scrub: #b5e3b5;
 @forest: #add19e;       // Lch(80,30,135)
 @forest-text: #46673b;  // Lch(40,30,135)
 @park: #c8facc;         // Lch(94,30,145) also recreation_ground
 @orchard: #aedfa3;
 
-// --- sports ---
-
- at stadium: #3c9; // also sports_centre
- at track: #74dcba;
- at pitch: #8ad3af;
-
 // --- "base" landuses ---
 
 @residential: #e0dfdf;      // Lch(89,0,0)
@@ -53,13 +46,20 @@
 @power-line: darken(@industrial-line, 5%);
 @rest_area: #efc8c8; // also services
 @sand: #f5e9c6;
- at educational_areas_and_hospital: #f0f0d8;
+ at societal_amenities: #f0f0d8;
 @station: #d4aaaa;
 @tourism: #734a08;
 @quarry: #c5c3c3;
 @military: #f55;
 @beach: #fff1ba;
 
+// --- sports ---
+
+ at pitch: #80d7b5;
+ at track: @pitch;
+ at stadium: @societal_amenities; // also sports_centre
+ at golf_course: #b5e3b5;
+
 #landcover-low-zoom[zoom < 10],
 #landcover[zoom >= 10] {
 
@@ -219,6 +219,20 @@
     }
   }
 
+  [feature = 'leisure_dog_park'] {
+    [zoom >= 10] {
+      polygon-fill: darken(@park, 5%);
+      [way_pixels >= 4]  { polygon-gamma: 0.75; }
+      [way_pixels >= 64] { polygon-gamma: 0.3;  }
+    }
+    [zoom >= 16] {
+      polygon-pattern-file: url('symbols/dog_park.png');
+      polygon-pattern-alignment: global;
+      [way_pixels >= 4]  { polygon-pattern-gamma: 0.75; }
+      [way_pixels >= 64] { polygon-pattern-gamma: 0.3;  }
+    }
+  }
+
   [feature = 'leisure_golf_course'][zoom >= 10],
   [feature = 'leisure_miniature_golf'][zoom >= 15] {
     polygon-fill: @golf_course;
@@ -450,7 +464,7 @@
     [zoom >= 10] {
       polygon-fill: @residential;
       [zoom >= 12] {
-        polygon-fill: @educational_areas_and_hospital;
+        polygon-fill: @societal_amenities;
         [zoom >= 13] {
           line-width: 0.3;
           line-color: brown;
@@ -520,7 +534,7 @@
     polygon-fill: @track;
     [zoom >= 15] {
       line-width: 0.5;
-      line-color: saturate(darken(@track, 40%), 20%);
+      line-color: saturate(darken(@track, 30%), 20%);
     }
     [way_pixels >= 4]  { polygon-gamma: 0.75; }
     [way_pixels >= 64] { polygon-gamma: 0.3;  }
@@ -530,7 +544,7 @@
     polygon-fill: @pitch;
     [zoom >= 15] {
       line-width: 0.5;
-      line-color: saturate(darken(@pitch, 40%), 20%);
+      line-color: saturate(darken(@pitch, 30%), 20%);
     }
     [way_pixels >= 4]  { polygon-gamma: 0.75; }
     [way_pixels >= 64] { polygon-gamma: 0.3;  }
diff --git a/placenames.mss b/placenames.mss
index 7c89860..dc02af3 100644
--- a/placenames.mss
+++ b/placenames.mss
@@ -31,7 +31,6 @@
     text-wrap-width: 35;
     text-placement: interior;
     text-character-spacing: 0.5;
-    text-min-distance: 3;
     text-line-spacing: 1;
   }
 }
@@ -48,7 +47,6 @@
       text-halo-radius: 1.5;
       text-wrap-width: 0;
       text-placement: interior;
-      text-min-distance: 3;
       [zoom >= 5] {
         text-name: "[name]";
         text-wrap-width: 30;
@@ -72,7 +70,6 @@
       text-halo-radius: 1.5;
       text-halo-fill: rgba(255,255,255,0.6);
       text-wrap-width: 30;
-      text-min-distance: 10;
       [zoom >= 5] {
         text-size: 11;
         text-wrap-width: 45;
@@ -108,7 +105,6 @@
       text-halo-radius: 1.5;
       text-halo-fill: rgba(255,255,255,0.6);
       text-wrap-width: 30;
-      text-min-distance: 10;
       [zoom >= 9] {
         text-size: 12;
         text-wrap-width: 60;
@@ -135,7 +131,6 @@
       text-halo-radius: 1.5;
       text-halo-fill: rgba(255,255,255,0.6);
       text-wrap-width: 45;
-      text-min-distance: 10;
       [zoom >= 11] {
         text-size: 11;
         text-wrap-width: 55;
@@ -161,7 +156,6 @@
     text-halo-radius: 1.5;
     text-halo-fill: rgba(255,255,255,0.6);
     text-wrap-width: 55;
-    text-min-distance: 10;
     [zoom >= 14] {
       text-size: 14;
       text-wrap-width: 70;
@@ -185,7 +179,6 @@
       text-halo-radius: 1.5;
       text-halo-fill: rgba(255,255,255,0.6);
       text-wrap-width: 50;
-      text-min-distance: 10;
       [zoom >= 14] {
         text-fill: @placenames-light;
         text-halo-fill: white;
@@ -214,7 +207,6 @@
       text-halo-radius: 1.5;
       text-halo-fill: rgba(255,255,255,0.6);
       text-wrap-width: 45;
-      text-min-distance: 10;
     }
     [zoom >= 16] {
       text-size: 12;
diff --git a/preview.png b/preview.png
index 5d6e08b..d9b2fd1 100644
Binary files a/preview.png and b/preview.png differ
diff --git a/project.mml b/project.mml
index 8c182dc..5033b9f 100644
--- a/project.mml
+++ b/project.mml
@@ -126,7 +126,7 @@
       "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",
       "Datasource": {
         "extent": "-20037508,-20037508,20037508,20037508",
-        "table": "(SELECT\n    way, name, religion, way_pixels,\n    COALESCE(aeroway, amenity, wetland, power, landuse, leisure, military, \"natural\", tourism, highway, railway) AS feature\n  FROM (SELECT\n      way, COALESCE(name, '') AS name,\n      ('aeroway_' || (CASE WHEN aeroway IN ('apron', 'aerodrome') THEN aeroway ELSE NULL END)) AS aeroway,\n      ('amenity_' || (CASE WHEN amenity IN ('parking', 'bicycle_parking', 'motorcycle_parking', 'university', 'college', 'school', \n    [...]
+        "table": "(SELECT\n    way, name, religion, way_pixels,\n    COALESCE(aeroway, amenity, wetland, power, landuse, leisure, military, \"natural\", tourism, highway, railway) AS feature\n  FROM (SELECT\n      way, COALESCE(name, '') AS name,\n      ('aeroway_' || (CASE WHEN aeroway IN ('apron', 'aerodrome') THEN aeroway ELSE NULL END)) AS aeroway,\n      ('amenity_' || (CASE WHEN amenity IN ('parking', 'bicycle_parking', 'motorcycle_parking', 'university', 'college', 'school', \n    [...]
         "geometry_field": "way",
         "type": "postgis",
         "key_field": "",
@@ -1397,7 +1397,7 @@
       "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",
       "Datasource": {
         "extent": "-20037508,-20037508,20037508,20037508",
-        "table": "(SELECT\n    way,\n    COALESCE(\n      'aeroway_' || CASE WHEN aeroway IN ('helipad', 'aerodrome') THEN aeroway ELSE NULL END,\n      'tourism_' || CASE WHEN tourism IN ('alpine_hut', 'camp_site', 'caravan_site', 'chalet', 'guest_house', \n                                          'hostel', 'hotel', 'motel', 'information', 'museum', 'picnic_site') THEN tourism ELSE NULL END,\n      'amenity_' || CASE WHEN amenity IN ('shelter', 'atm', 'bank', 'bar', 'bicycle_rental', ' [...]
+        "table": "(SELECT\n    way,\n    COALESCE(\n      'aeroway_' || CASE WHEN aeroway IN ('helipad', 'aerodrome') THEN aeroway ELSE NULL END,\n      'tourism_' || CASE WHEN tourism IN ('alpine_hut', 'camp_site', 'caravan_site', 'chalet', 'guest_house', \n                                          'hostel', 'hotel', 'motel', 'information', 'museum', 'picnic_site') THEN tourism ELSE NULL END,\n      'amenity_' || CASE WHEN amenity IN ('shelter', 'atm', 'bank', 'bar', 'bicycle_rental', ' [...]
         "geometry_field": "way",
         "type": "postgis",
         "key_field": "",
@@ -1423,7 +1423,7 @@
       "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",
       "Datasource": {
         "extent": "-20037508,-20037508,20037508,20037508",
-        "table": "(SELECT\n    way,\n    COALESCE(\n      'aeroway_' || CASE WHEN aeroway IN ('helipad', 'aerodrome') THEN aeroway ELSE NULL END,\n      'tourism_' || CASE WHEN tourism IN ('alpine_hut', 'camp_site', 'caravan_site', 'chalet', 'guest_house', 'hostel', \n                                          'hotel', 'motel', 'information', 'museum', 'picnic_site') THEN tourism ELSE NULL END,\n      'amenity_' || CASE WHEN amenity IN ('shelter', 'atm', 'bank', 'bar', 'bicycle_rental', ' [...]
+        "table": "(SELECT\n    way,\n    COALESCE(\n      'aeroway_' || CASE WHEN aeroway IN ('helipad', 'aerodrome') THEN aeroway ELSE NULL END,\n      'tourism_' || CASE WHEN tourism IN ('alpine_hut', 'camp_site', 'caravan_site', 'chalet', 'guest_house', 'hostel', \n                                          'hotel', 'motel', 'information', 'museum', 'picnic_site') THEN tourism ELSE NULL END,\n      'amenity_' || CASE WHEN amenity IN ('shelter', 'atm', 'bank', 'bar', 'bicycle_rental', ' [...]
         "geometry_field": "way",
         "type": "postgis",
         "key_field": "",
@@ -1711,7 +1711,7 @@
       "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",
       "Datasource": {
         "extent": "-20037508,-20037508,20037508,20037508",
-        "table": "(SELECT\n    way,\n    way_area/NULLIF(!pixel_width!::real*!pixel_height!::real,0) AS way_pixels,\n    COALESCE(\n      'aeroway_' || CASE WHEN aeroway IN ('gate', 'apron', 'helipad', 'aerodrome') THEN aeroway ELSE NULL END,\n      'tourism_' || CASE WHEN tourism IN ('alpine_hut', 'hotel', 'motel', 'hostel', 'chalet', 'guest_house', 'camp_site', 'caravan_site', \n                                          'theme_park', 'museum', 'zoo', 'information', 'picnic_site') THEN  [...]
+        "table": "(SELECT\n    way,\n    way_area/NULLIF(!pixel_width!::real*!pixel_height!::real,0) AS way_pixels,\n    COALESCE(\n      'aeroway_' || CASE WHEN aeroway IN ('gate', 'apron', 'helipad', 'aerodrome') THEN aeroway ELSE NULL END,\n      'tourism_' || CASE WHEN tourism IN ('alpine_hut', 'hotel', 'motel', 'hostel', 'chalet', 'guest_house', 'camp_site', 'caravan_site', \n                                          'theme_park', 'museum', 'zoo', 'information', 'picnic_site') THEN  [...]
         "geometry_field": "way",
         "type": "postgis",
         "key_field": "",
@@ -1763,7 +1763,7 @@
       "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",
       "Datasource": {
         "extent": "-20037508,-20037508,20037508,20037508",
-        "table": "(SELECT\n    way,\n    way_pixels,\n    feature,\n    access,\n    CONCAT(\n        name,\n        CASE WHEN name IS NOT NULL AND elevation IS NOT NULL THEN E'\\n' ELSE NULL END,\n        CASE WHEN elevation IS NOT NULL THEN CONCAT(REPLACE(ROUND(elevation)::TEXT, '-', U&'\\2212'), U&'\\00A0', 'm') ELSE NULL END\n    ) AS name,\n    CASE\n      WHEN \"natural\" IN ('peak', 'volcano', 'saddle') THEN elevation\n      ELSE NULL\n    END AS score,\n    operator,\n    ref,\n  [...]
+        "table": "(SELECT\n    way,\n    way_pixels,\n    feature,\n    access,\n    CONCAT(\n        name,\n        CASE WHEN name IS NOT NULL AND elevation IS NOT NULL THEN E'\\n' ELSE NULL END,\n        CASE WHEN elevation IS NOT NULL THEN CONCAT(REPLACE(ROUND(elevation)::TEXT, '-', U&'\\2212'), U&'\\00A0', 'm') ELSE NULL END\n    ) AS name,\n    CASE\n      WHEN \"natural\" IN ('peak', 'volcano', 'saddle') THEN elevation\n      ELSE NULL\n    END AS score,\n    operator,\n    ref,\n  [...]
         "geometry_field": "way",
         "type": "postgis",
         "key_field": "",
@@ -1945,7 +1945,7 @@
       "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",
       "Datasource": {
         "extent": "-20037508,-20037508,20037508,20037508",
-        "table": "(SELECT\n    way,\n    name,\n    admin_level\n  FROM planet_osm_polygon\n  WHERE boundary = 'administrative'\n    AND admin_level IN ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10')\n    AND name IS NOT NULL\n  ORDER BY admin_level::integer ASC, way_area DESC\n) AS admin_text",
+        "table": "(SELECT\n    way,\n    name,\n    admin_level\n  FROM planet_osm_roads\n  WHERE boundary = 'administrative'\n    AND admin_level IN ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10')\n    AND name IS NOT NULL\n    AND osm_id < 0\n  ORDER BY admin_level::integer ASC, way_area DESC\n) AS admin_text",
         "geometry_field": "way",
         "type": "postgis",
         "key_field": "",
@@ -2092,6 +2092,7 @@
     "landcover.mss",
     "water.mss",
     "water-features.mss",
+    "road-colors-generated.mss",
     "roads.mss",
     "power.mss",
     "citywalls.mss",
diff --git a/project.yaml b/project.yaml
index efbcaea..9f2a3ef 100644
--- a/project.yaml
+++ b/project.yaml
@@ -41,6 +41,7 @@ Stylesheet:
   - "landcover.mss"
   - "water.mss"
   - "water-features.mss"
+  - "road-colors-generated.mss"
   - "roads.mss"
   - "power.mss"
   - "citywalls.mss"
@@ -152,7 +153,7 @@ Layer:
                                                     'brownfield', 'landfill', 'construction') THEN landuse ELSE NULL END)) AS landuse,
               ('leisure_' || (CASE WHEN leisure IN ('swimming_pool', 'playground', 'park', 'recreation_ground', 'common', 'garden', 
                                                     'golf_course', 'miniature_golf', 'picnic_table', 'sports_centre', 'stadium', 'pitch', 
-                                                    'track') THEN leisure ELSE NULL END)) AS leisure,
+                                                    'track', 'dog_park') THEN leisure ELSE NULL END)) AS leisure,
               ('military_' || (CASE WHEN military IN ('danger_area') THEN military ELSE NULL END)) AS military,
               ('natural_' || (CASE WHEN "natural" IN ('beach', 'shoal', 'heath', 'grassland', 'wood', 'sand', 'scree', 'shingle', 'bare_rock', 'scrub') THEN "natural" ELSE NULL END)) AS "natural",
               ('wetland_' || (CASE WHEN "natural" IN ('wetland', 'marsh', 'mud') THEN (CASE WHEN "natural" IN ('marsh', 'mud') THEN "natural" ELSE wetland END) ELSE NULL END)) AS wetland,
@@ -1677,7 +1678,7 @@ Layer:
                                             'tailor', 'tanning', 'tattoo', 'tea', 'ticket', 'tiles', 'tobacco', 'trade', 'tyres', 'vacuum_cleaner', 'video', 
                                             'video_games', 'watches', 'wholesale', 'yes') THEN 'other' ELSE NULL END,
               'leisure_' || CASE WHEN leisure IN ('water_park', 'playground', 'miniature_golf', 'golf_course', 'picnic_table') THEN leisure ELSE NULL END,
-              'man_made_' || CASE WHEN man_made IN ('mast', 'water_tower', 'lighthouse', 'windmill') THEN man_made ELSE NULL END,
+              'man_made_' || CASE WHEN man_made IN ('mast', 'water_tower', 'lighthouse', 'windmill', 'obelisk') THEN man_made ELSE NULL END,
               'natural_' || CASE WHEN "natural" IN ('spring') THEN "natural" ELSE NULL END,
               'historic_' || CASE WHEN historic IN ('memorial', 'monument', 'archaeological_site') THEN historic ELSE NULL END,
               'highway_'|| CASE WHEN highway IN ('bus_stop', 'elevator', 'traffic_signals') THEN highway ELSE NULL END,
@@ -1705,7 +1706,7 @@ Layer:
                            'social_facility')
             OR shop IS NOT NULL -- skip checking a huge list and use a null check
             OR leisure IN ('water_park', 'playground', 'miniature_golf', 'golf_course', 'picnic_table')
-            OR man_made IN ('mast', 'water_tower', 'lighthouse', 'windmill')
+            OR man_made IN ('mast', 'water_tower', 'lighthouse', 'windmill', 'obelisk')
             OR "natural" IN ('spring')
             OR historic IN ('memorial', 'monument', 'archaeological_site')
             OR highway IN ('bus_stop', 'elevator', 'traffic_signals')
@@ -1755,8 +1756,9 @@ Layer:
                                             'real_estate', 'religion', 'rental', 'salon', 'scuba_diving', 'second_hand', 'sewing', 'shoe_repair', 'shopping_centre', 
                                             'solarium', 'souvenir', 'tailor', 'tanning', 'tattoo', 'tea', 'ticket', 'tiles', 'tobacco', 'trade', 'tyres', 
                                             'vacuum_cleaner', 'video', 'video_games', 'watches', 'wholesale', 'yes') THEN 'other' ELSE NULL END,
-              'leisure_' || CASE WHEN leisure IN ('water_park', 'playground', 'miniature_golf', 'golf_course', 'picnic_table', 'slipway') THEN leisure ELSE NULL END,
-              'man_made_' || CASE WHEN man_made IN ('mast', 'water_tower', 'lighthouse', 'windmill') THEN man_made ELSE NULL END,
+              'leisure_' || CASE WHEN leisure IN ('water_park', 'playground', 'miniature_golf', 'golf_course', 'picnic_table', 'slipway',
+                                                  'dog_park') THEN leisure ELSE NULL END,
+              'man_made_' || CASE WHEN man_made IN ('mast', 'water_tower', 'lighthouse', 'windmill', 'obelisk') THEN man_made ELSE NULL END,
               'natural_' || CASE WHEN "natural" IN ('peak', 'volcano', 'saddle', 'spring', 'cave_entrance') THEN "natural" ELSE NULL END,
               'historic_' || CASE WHEN historic IN ('memorial', 'monument', 'archaeological_site') THEN historic ELSE NULL END,
               'highway_'|| CASE WHEN highway IN ('bus_stop', 'elevator', 'traffic_signals', 'ford') THEN highway ELSE NULL END,
@@ -1793,8 +1795,9 @@ Layer:
                            'taxi', 'theatre', 'toilets', 'drinking_water', 'prison', 'hunting_stand', 'nightclub', 
                            'veterinary', 'social_facility')
             OR shop IS NOT NULL -- skip checking a huge list and use a null check
-            OR leisure IN ('water_park', 'playground', 'miniature_golf', 'golf_course', 'picnic_table', 'slipway')
-            OR man_made IN ('mast', 'water_tower', 'lighthouse', 'windmill', 'cross')
+            OR leisure IN ('water_park', 'playground', 'miniature_golf', 'golf_course', 'picnic_table', 'slipway',
+                           'dog_park')
+            OR man_made IN ('mast', 'water_tower', 'lighthouse', 'windmill', 'cross', 'obelisk')
             OR "natural" IN ('peak', 'volcano', 'saddle', 'spring', 'cave_entrance')
             OR historic IN ('memorial', 'monument', 'archaeological_site', 'wayside_cross')
             OR highway IN ('bus_stop', 'elevator', 'traffic_signals', 'ford')
@@ -2075,13 +2078,13 @@ Layer:
                                             'yes') THEN 'other' ELSE NULL END,
               'leisure_' || CASE WHEN leisure IN ('swimming_pool', 'water_park', 'miniature_golf', 'golf_course', 'sports_centre', 'stadium', 'track', 
                                                   'pitch', 'playground', 'park', 'recreation_ground', 'common', 'garden', 'nature_reserve', 'marina', 
-                                                  'picnic_table') THEN leisure ELSE NULL END,
+                                                  'picnic_table', 'dog_park') THEN leisure ELSE NULL END,
               'power_' || CASE WHEN power IN ('plant', 'station', 'generator', 'sub_station', 'substation') THEN power ELSE NULL END,
               'landuse_' || CASE WHEN landuse IN ('reservoir', 'basin', 'recreation_ground', 'village_green', 'quarry', 'vineyard', 'orchard', 'cemetery', 
                                                   'residential', 'garages', 'meadow', 'grass', 'allotments', 'forest', 'farmyard', 'farm', 'farmland', 
                                                   'greenhouse_horticulture', 'retail', 'industrial', 'railway', 'commercial', 'brownfield', 'landfill', 
                                                   'construction', 'military') THEN landuse ELSE NULL END,
-              'man_made_' || CASE WHEN man_made IN ('lighthouse', 'windmill', 'mast', 'water_tower', 'pier', 'breakwater', 'groyne') THEN man_made ELSE NULL END,
+              'man_made_' || CASE WHEN man_made IN ('lighthouse', 'windmill', 'mast', 'water_tower', 'pier', 'breakwater', 'groyne', 'obelisk') THEN man_made ELSE NULL END,
               'natural_' || CASE WHEN "natural" IN ('wood', 'water', 'mud', 'wetland', 'marsh', 'bay', 'spring', 'scree', 'shingle', 'bare_rock', 'sand', 'heath', 
                                                     'grassland', 'scrub', 'beach', 'shoal', 'reef', 'glacier') THEN "natural" ELSE NULL END,
               'place_' || CASE WHEN place IN ('island', 'islet') THEN place ELSE NULL END,
@@ -2107,7 +2110,7 @@ Layer:
               OR shop IS NOT NULL
               OR leisure IS NOT NULL
               OR landuse IS NOT NULL
-              OR man_made IN ('lighthouse', 'windmill', 'mast', 'water_tower', 'pier', 'breakwater', 'groyne')
+              OR man_made IN ('lighthouse', 'windmill', 'mast', 'water_tower', 'pier', 'breakwater', 'groyne', 'obelisk')
               OR "natural" IS NOT NULL
               OR place IN ('island', 'islet')
               OR military IN ('danger_area')
@@ -2116,7 +2119,9 @@ Layer:
               OR power IN ('plant', 'station', 'generator', 'sub_station', 'substation')
               OR boundary IN ('national_park')
               OR waterway = 'dam')
-            AND name IS NOT NULL
+            AND (name IS NOT NULL
+                 OR (ref IS NOT NULL AND aeroway IN ('gate'))
+                )
           ORDER BY way_area DESC
         ) AS text_poly
     properties:
@@ -2215,13 +2220,13 @@ Layer:
                                                 'wholesale', 'yes') THEN 'other' ELSE NULL END,
                   'leisure_' || CASE WHEN leisure IN ('swimming_pool', 'water_park', 'miniature_golf', 'golf_course', 'sports_centre', 'stadium', 'track',  
                                                       'pitch','playground', 'park', 'recreation_ground', 'common', 'garden', 'nature_reserve', 'marina',  
-                                                      'slipway', 'picnic_table') THEN leisure ELSE NULL END,
+                                                      'slipway', 'picnic_table', 'dog_park') THEN leisure ELSE NULL END,
                   'power_' || CASE WHEN power IN ('plant', 'station', 'generator', 'sub_station', 'substation') THEN power ELSE NULL END,
                   'landuse_' || CASE WHEN landuse IN ('reservoir', 'basin', 'recreation_ground', 'village_green', 'quarry', 'vineyard', 'orchard', 'cemetery', 
                                                       'residential', 'garages', 'meadow', 'grass', 'allotments', 'forest', 'farmyard', 'farm', 'farmland', 
                                                       'greenhouse_horticulture', 'retail', 'industrial', 'railway', 'commercial', 'brownfield', 'landfill', 
                                                       'construction', 'military') THEN landuse ELSE NULL END,
-                  'man_made_' || CASE WHEN man_made IN ('lighthouse', 'windmill', 'mast', 'water_tower') THEN man_made ELSE NULL END,
+                  'man_made_' || CASE WHEN man_made IN ('lighthouse', 'windmill', 'mast', 'water_tower', 'obelisk') THEN man_made ELSE NULL END,
                   'natural_' || CASE WHEN "natural" IN ('wood', 'peak', 'volcano', 'saddle', 'cave_entrance', 'water', 'mud', 'wetland', 'marsh', 'bay', 'spring', 
                                                         'scree', 'shingle', 'bare_rock', 'sand', 'heath', 'grassland', 'scrub', 'beach', 'glacier', 'tree') 
                                                         THEN "natural" ELSE NULL END,
@@ -2261,7 +2266,7 @@ Layer:
                   OR landuse IN ('reservoir', 'basin', 'recreation_ground', 'village_green', 'quarry', 'vineyard', 'orchard', 'cemetery', 'residential', 
                                  'garages', 'meadow', 'grass', 'allotments', 'forest', 'farmyard', 'farm', 'farmland', 'greenhouse_horticulture', 
                                  'retail', 'industrial', 'railway', 'commercial', 'brownfield', 'landfill', 'construction', 'military')
-                  OR man_made IN ('lighthouse', 'windmill', 'mast', 'water_tower', 'cross')
+                  OR man_made IN ('lighthouse', 'windmill', 'mast', 'water_tower', 'cross', 'obelisk')
                   OR "natural" IS NOT NULL
                   OR place IN ('island', 'islet')
                   OR military IN ('danger_area')
@@ -2270,7 +2275,10 @@ Layer:
                   OR power IN ('plant', 'station', 'generator', 'sub_station', 'substation')
                   OR boundary IN ('national_park')
                   OR waterway IN ('dam', 'weir'))
-                AND name IS NOT NULL
+                AND (name IS NOT NULL
+                     OR (ele IS NOT NULL AND ("natural" IN ('peak', 'volcano', 'saddle') OR tourism = 'alpine_hut' OR amenity = 'shelter'))
+                     OR (ref IS NOT NULL AND aeroway IN ('gate'))
+                    )
               ) AS p
           ORDER BY score DESC NULLS LAST
           ) AS text
@@ -2421,10 +2429,11 @@ Layer:
             way,
             name,
             admin_level
-          FROM planet_osm_polygon
+          FROM planet_osm_roads
           WHERE boundary = 'administrative'
             AND admin_level IN ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10')
             AND name IS NOT NULL
+            AND osm_id < 0
           ORDER BY admin_level::integer ASC, way_area DESC
         ) AS admin_text
     properties:
diff --git a/road-colors-generated.mss b/road-colors-generated.mss
new file mode 100644
index 0000000..eb87f8b
--- /dev/null
+++ b/road-colors-generated.mss
@@ -0,0 +1,26 @@
+/* This is generated code, do not change this file manually.         */
+/*                                                                   */
+/* To change these definitions, alter road-colors.yaml and run:      */
+/*                                                                   */
+/*   ./scripts/generate_road_colours.py > road-colors-generated.mss  */
+/*                                                                   */
+ at motorway-low-zoom-casing: #c24e6b;
+ at trunk-low-zoom-casing: #cf6649;
+ at primary-low-zoom-casing: #c38a27;
+ at secondary-low-zoom-casing: #9eae23;
+ at motorway-casing: #dc2a67;
+ at trunk-casing: #c84e2f;
+ at primary-casing: #a06b00;
+ at secondary-casing: #707d05;
+ at motorway-shield: #620728;
+ at trunk-shield: #5d1b0b;
+ at primary-shield: #4c2e00;
+ at secondary-shield: #323b00;
+ at motorway-low-zoom: #e66e89;
+ at trunk-low-zoom: #f5977a;
+ at primary-low-zoom: #f3c380;
+ at secondary-low-zoom: #e8eda0;
+ at motorway-fill: #e892a2;
+ at trunk-fill: #f9b29c;
+ at primary-fill: #fcd6a4;
+ at secondary-fill: #f7fabf;
diff --git a/road-colors.yaml b/road-colors.yaml
new file mode 100644
index 0000000..78d3188
--- /dev/null
+++ b/road-colors.yaml
@@ -0,0 +1,43 @@
+# This is the input for scripts/generate_road_colours.py
+
+# All road classes colours will be generated for, in order of importance
+# (biggest first).
+roads:
+  - motorway
+  - trunk
+  - primary
+  - secondary
+
+# The starting and ending hue. The range goes from 0 to 360, with 0 and 360
+# representing red.
+hue: [10, 106]
+
+# The lightness and chroma (also known as saturation) for each type of colour.
+# Lightness ranges from 0 to 100; dark to bright.
+# Chroma ranges from 0 to 100 too; unsaturated to fully saturated.
+classes:
+  # Colours for output into the MSS file
+  mss:
+    fill:
+      lightness: [70, 97]
+      chroma: [35, 29]
+    casing:
+      lightness: [50, 50]
+      chroma: [70, 55]
+    low-zoom:
+      lightness: [62, 92]
+      chroma: [50, 40]
+    low-zoom-casing:
+      lightness: [50, 70]
+      chroma: [50, 65]
+    shield:
+      lightness: [20, 25]
+      chroma: [40, 42]
+  # Colours used by the road shields script
+  shield:
+    fill:
+      lightness: [85, 95]
+      chroma: [12, 14]
+    stroke_fill:
+      lightness: [70, 80]
+      chroma: [22, 24]
diff --git a/roads.mss b/roads.mss
index 96af10e..a87336a 100644
--- a/roads.mss
+++ b/roads.mss
@@ -1,10 +1,5 @@
 /* For the main linear features, such as roads and railways. */
 
-//road colors for major roads were generated with scripts/generate_road_colors.py
- at motorway-fill: #e892a2; // Lch(70,35,10), error 0.5
- at trunk-fill: #f9b29c; // Lch(79,33,42), error 0.7
- at primary-fill: #fcd6a4; // Lch(88,31,74), error 1.7
- at secondary-fill: #f7fabf; // Lch(97,29,106), error 1.7
 @tertiary-fill: #ffffff;
 @residential-fill: #ffffff;
 @service-fill: @residential-fill;
@@ -22,16 +17,7 @@
 @taxiway-fill: @aeroway-fill;
 @helipad-fill: @aeroway-fill;
 
- at motorway-low-zoom: #e66e89; // Lch(62,50,10), error 0.7
- at trunk-low-zoom: #fa9476; // Lch(72,50,42), error 0.8
- at primary-low-zoom: #f8c171; // Lch(82,50,74), error 2.1
- at secondary-low-zoom: #e6ef89; // Lch(92,50,106), error 2.2
-
 @default-casing: white;
- at motorway-casing: #dc2a67; // Lch(50,70,10), error 1.1
- at trunk-casing: #c84e2f; // Lch(50,65,42), error 0.7
- at primary-casing: #a06b00; // Lch(50,60,74), error 1.6
- at secondary-casing: #707d05; // Lch(50,55,106), error 1.9
 @tertiary-casing: #8f8f8f;
 @residential-casing: #bbb;
 @road-casing: @residential-casing;
@@ -45,10 +31,7 @@
 @bridleway-casing: @default-casing;
 @track-casing: @default-casing;
 
- at motorway-low-zoom-casing: #c24e6b; // Lch(50,50,10), error 0.8
- at trunk-low-zoom-casing: #cf6649; // Lch(56,55,42), error 0.9
- at primary-low-zoom-casing: #c38a27; // Lch(62,60,74), error 2.1
- at secondary-low-zoom-casing: #9eae23; // Lch(68,65,106), error 2.3
+ at tertiary-shield: #3b3b3b;
 
 @unimportant-road: @residential-casing;
 
@@ -285,12 +268,6 @@
 @shield-font: @book-fonts;
 @shield-clip: false;
 
- at shield-motorway-fill: #620728; // Lch(20,40,10), error 0.5
- at shield-trunk-fill: #5d1b0b; // Lch(21,40,42), error 0.5
- at shield-primary-fill: #4c2e00; // Lch(22,40,74), error 2.9
- at shield-secondary-fill: #323b00; // Lch(23,40,106), error 3.4
- at shield-tertiary-fill: #3b3b3b; // Lch(25,0,0), error 0.1
-
 .roads-casing, .bridges-casing, .tunnels-casing {
   ::casing {
     [zoom = 9][feature = 'highway_secondary'] {
@@ -2611,22 +2588,22 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */
     shield-clip: @shield-clip;
 
     [highway = 'motorway'] {
-      shield-fill: @shield-motorway-fill;
+      shield-fill: @motorway-shield;
       shield-file: url("symbols/shields/motorway_[width]x[height].svg");
     }
 
     [highway = 'trunk'] {
-      shield-fill: @shield-trunk-fill;
+      shield-fill: @trunk-shield;
       shield-file: url("symbols/shields/trunk_[width]x[height].svg");
     }
 
     [highway = 'primary'] {
-      shield-fill: @shield-primary-fill;
+      shield-fill: @primary-shield;
       shield-file: url("symbols/shields/primary_[width]x[height].svg");
     }
 
     [highway = 'secondary'] {
-      shield-fill: @shield-secondary-fill;
+      shield-fill: @secondary-shield;
       shield-file: url("symbols/shields/secondary_[width]x[height].svg");
     }
   }
@@ -2656,7 +2633,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */
       shield-clip: @shield-clip;
 
       [highway = 'motorway'] {
-        shield-fill: @shield-motorway-fill;
+        shield-fill: @motorway-shield;
         shield-file: url("symbols/shields/motorway_[width]x[height].svg");
 
         [zoom >= 16] {
@@ -2667,7 +2644,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */
         }
       }
       [highway = 'trunk'] {
-        shield-fill: @shield-trunk-fill;
+        shield-fill: @trunk-shield;
         shield-file: url("symbols/shields/trunk_[width]x[height].svg");
 
         [zoom >= 16] {
@@ -2678,7 +2655,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */
         }
       }
       [highway = 'primary'] {
-        shield-fill: @shield-primary-fill;
+        shield-fill: @primary-shield;
         shield-file: url("symbols/shields/primary_[width]x[height].svg");
 
         [zoom >= 16] {
@@ -2689,7 +2666,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */
         }
       }
       [highway = 'secondary'] {
-        shield-fill: @shield-secondary-fill;
+        shield-fill: @secondary-shield;
         shield-file: url("symbols/shields/secondary_[width]x[height].svg");
 
         [zoom >= 16] {
@@ -2700,7 +2677,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */
         }
       }
       [highway = 'tertiary'] {
-        shield-fill: @shield-tertiary-fill;
+        shield-fill: @tertiary-shield;
         shield-file: url("symbols/shields/tertiary_[width]x[height].svg");
 
         [zoom >= 16] {
diff --git a/scripts/generate_road_colours.py b/scripts/generate_road_colours.py
index 3976463..6217b24 100755
--- a/scripts/generate_road_colours.py
+++ b/scripts/generate_road_colours.py
@@ -3,120 +3,117 @@
 from colormath.color_conversions import convert_color
 from colormath.color_objects import LabColor, LCHabColor, sRGBColor
 from colormath.color_diff import delta_e_cie2000
-import numpy
+import argparse
+import sys
+import yaml
 
 from collections import OrderedDict, namedtuple
 
 class Color:
-  def __init__(self, lch_tuple):
-    self.m_lch = LCHabColor(*lch_tuple)
-
-  def lch(self):
-    return "Lch({:.0f},{:.0f},{:.0f})".format(*(self.m_lch.get_value_tuple()))
-
-  def rgb(self):
-    rgb = convert_color(self.m_lch, sRGBColor)
-    if (rgb.rgb_r != rgb.clamped_rgb_r or rgb.rgb_g != rgb.clamped_rgb_g or rgb.rgb_b != rgb.clamped_rgb_b):
-      raise Exception("Colour {} is outside sRGB".format(self.lch()))
-    return rgb.get_rgb_hex()
-
-  def rgb_error(self):
-    return delta_e_cie2000(convert_color(self.m_lch, LabColor),
-                           convert_color(sRGBColor.new_from_rgb_hex(self.rgb()), LabColor))
-
-road_classes = ["motorway", "trunk", "primary", "secondary"]
-colour_divisions = len(road_classes) - 1
-hues = OrderedDict()
-
-# The minimum and maximum hue for the road colours
-# Because hue is a circle, it may be needed to add/subtract 360 to the min or
-# max when changing them
-
-min_h = 10
-max_h = 106
-delta_h = (max_h - min_h) / colour_divisions
-
-h = min_h
-for name in road_classes:
-  hues[name] = h
-  h = (h + delta_h) % 360
-
-print hues
-# A class to hold information for each line
-ColourInfo = namedtuple("ColourInfo", ["start_l", "end_l", "start_c", "end_c"])
-
-line_colour_infos = OrderedDict()
-
-# The saturation and lightness for each type of line
-line_colour_infos["fill"] = ColourInfo(start_l = 70, end_l = 97, start_c = 35, end_c = 29)
-line_colour_infos["low-zoom"] = ColourInfo(start_l = 62, end_l = 92, start_c = 50, end_c = 50)
-
-line_colour_infos["casing"] = ColourInfo(start_l = 50, end_l = 50, start_c = 70, end_c = 55)
-line_colour_infos["low-zoom-casing"] = ColourInfo(start_l = 50, end_l = 70, start_c = 50, end_c = 65)
-
-# Colours for the MSS
-colours = OrderedDict()
-
-for line_name, line_colour_info in line_colour_infos.iteritems():
-  c = line_colour_info.start_c
-  delta_c = (line_colour_info.end_c - line_colour_info.start_c) / colour_divisions
-  l = line_colour_info.start_l
-  delta_l = (line_colour_info.end_l - line_colour_info.start_l) / colour_divisions
-
-  for name in road_classes:
-    colours[name + "-" + line_name] = Color((l, c, hues[name]))
-    c += delta_c
-    l += delta_l
-
-for name, colour in colours.iteritems():
-  print "@{name}: {rgb}; // {lch}, error {delta:.1f}".format(name = name, rgb = colour.rgb(), lch = colour.lch(), delta = colour.rgb_error())
-
-# Generate colours for the shields
-shield_colour_info = {}
-shield_colour_info["fill"] = ColourInfo(start_l = 85, end_l = 95, start_c = 12, end_c = 14)
-shield_colour_info["stroke_fill"] = ColourInfo(start_l = 70, end_l = 80, start_c = 22, end_c = 24)
-shield_colour_info["text"] = ColourInfo(start_l = 20, end_l = 25, start_c = 40, end_c = 42)
-shield_colours = OrderedDict()
-
-
-c1 = shield_colour_info["fill"].start_c
-delta_c1 = (shield_colour_info["fill"].end_c - shield_colour_info["fill"].start_c) / colour_divisions
-l1 = shield_colour_info["fill"].start_l
-delta_l1 = (shield_colour_info["fill"].end_l - shield_colour_info["fill"].start_l) / colour_divisions
-
-c2 = shield_colour_info["stroke_fill"].start_c
-delta_c2 = (shield_colour_info["stroke_fill"].end_c - shield_colour_info["stroke_fill"].start_c) / colour_divisions
-l2 = shield_colour_info["stroke_fill"].start_l
-delta_l2 = (shield_colour_info["stroke_fill"].end_l - shield_colour_info["stroke_fill"].start_l) / colour_divisions
-
-c3 = shield_colour_info["text"].start_c
-delta_c3 = (shield_colour_info["text"].end_c - shield_colour_info["text"].start_c) / colour_divisions
-l3 = shield_colour_info["text"].start_l
-delta_l3 = (shield_colour_info["text"].end_l - shield_colour_info["text"].start_l) / colour_divisions
-
-for name in road_classes:
-  shield_colours[name] = {}
-  shield_colours[name]["fill"] = Color((l1, c1, hues[name]))
-  shield_colours[name]["stroke_fill"] = Color((l2, c2, hues[name]))
-  shield_colours[name]["text"] = Color((l3, c3, hues[name]))
-  c1 += delta_c1
-  l1 += delta_l1
-  c2 += delta_c2
-  l2 += delta_l2
-  c3 += delta_c3
-  l3 += delta_l3
-
-shield_colours["tertiary"] = {}
-shield_colours["tertiary"]["fill"] = Color((shield_colour_info["fill"].end_l, 0, 0))
-shield_colours["tertiary"]["stroke_fill"] = Color((shield_colour_info["stroke_fill"].end_l, 0, 0))
-shield_colours["tertiary"]["text"] = Color((shield_colour_info["text"].end_l, 0, 0))
-
-print "\n\nRoad shield information\n\n"
-for name, colour in shield_colours.iteritems():
-  print "@shield-{name}-fill: {rgb}; // {lch}, error {delta:.1f}".format(name = name, rgb = colour["text"].rgb(), lch = colour["text"].lch(), delta = colour["text"].rgb_error())
-
-print "\n"
-for name, colour in shield_colours.iteritems():
-  # note that the two additional blanks at the beginning are intentional
-  print "  config['{name}']['fill'] = '{rgb}' # {lch}, error {delta:.1f}".format(name = name, rgb = colour["fill"].rgb(), lch = colour["fill"].lch(), delta = colour["fill"].rgb_error())
-  print "  config['{name}']['stroke_fill'] = '{rgb}' # {lch}, error {delta:.1f}".format(name = name, rgb = colour["stroke_fill"].rgb(), lch = colour["stroke_fill"].lch(), delta = colour["stroke_fill"].rgb_error())
+    """A color in the CIE lch color space."""
+
+    def __init__(self, lch_tuple):
+        self.m_lch = LCHabColor(*lch_tuple)
+
+    def lch(self):
+        return "Lch({:.0f},{:.0f},{:.0f})".format(*(self.m_lch.get_value_tuple()))
+
+    def rgb(self):
+        rgb = convert_color(self.m_lch, sRGBColor)
+        if (rgb.rgb_r != rgb.clamped_rgb_r or rgb.rgb_g != rgb.clamped_rgb_g or rgb.rgb_b != rgb.clamped_rgb_b):
+            raise Exception("Colour {} is outside sRGB".format(self.lch()))
+        return rgb.get_rgb_hex()
+
+    def rgb_error(self):
+        return delta_e_cie2000(convert_color(self.m_lch, LabColor),
+                               convert_color(sRGBColor.new_from_rgb_hex(self.rgb()), LabColor))
+
+def load_settings():
+    """Read the settings from YAML."""
+    return yaml.load(open('road-colors.yaml', 'r'))
+
+def generate_colours(settings, section):
+    """Generate colour ranges.
+
+    Arguments:
+    settings -- The settings loaded by load_settings.
+    section -- Which section of the settings under 'classes' to use. Typically
+               'mss' or 'shields'.
+    """
+    road_classes = settings['roads']
+    colour_divisions = len(road_classes) - 1
+    hues = OrderedDict()
+    
+    min_h = settings['hue'][0]
+    max_h = settings['hue'][1]
+
+    delta_h = (max_h - min_h) / colour_divisions
+    
+    h = min_h
+    for name in road_classes:
+        hues[name] = h
+        h = (h + delta_h) % 360
+
+    # A class to hold information for each line
+    ColourInfo = namedtuple("ColourInfo", ["start_l", "end_l", "start_c", "end_c"])
+
+    line_colour_infos = OrderedDict()
+
+    # The lightness (l) and chroma (c; also known as saturation) for each type of colour.
+    # Lightness ranges from 0 to 100; dark to bright.
+    # Chroma ranges from 0 to 100 too; unsaturated to fully saturated.
+
+    # The higher the road classification, the higher its saturation. Conversely,
+    # the roads get brighter towards the lower end of the classification.
+
+    classes = settings['classes'][section]
+    for cls, params in classes.iteritems():
+        l = params['lightness']
+        c = params['chroma']
+        line_colour_infos[cls] = ColourInfo(start_l = l[0], end_l = l[1], start_c = c[0], end_c = c[1])
+
+    # Colours for the MSS
+    colours = OrderedDict()
+
+    for line_name, line_colour_info in line_colour_infos.iteritems():
+        c = line_colour_info.start_c
+        delta_c = (line_colour_info.end_c - line_colour_info.start_c) / colour_divisions
+        l = line_colour_info.start_l
+        delta_l = (line_colour_info.end_l - line_colour_info.start_l) / colour_divisions
+
+        colours[line_name] = OrderedDict()
+        for name in road_classes:
+            colours[line_name][name] = Color((l, c, hues[name]))
+            c += delta_c
+            l += delta_l
+
+    return colours
+
+def main():
+    parser = argparse.ArgumentParser(description='Generates road colours')
+    parser.add_argument('-v', '--verbose', dest='verbose', help='Generates information about colour differences', action='store_true', default=False)
+    args = parser.parse_args()
+
+    settings = load_settings()
+    road_classes = settings['roads']
+    colour_divisions = len(road_classes) - 1
+    colours = generate_colours(settings, 'mss')
+
+    # Print a warning about the nature of these definitions.
+    print "/* This is generated code, do not change this file manually.         */"
+    print "/*                                                                   */"
+    print "/* To change these definitions, alter road-colors.yaml and run:      */"
+    print "/*                                                                   */"
+    print "/*   ./scripts/generate_road_colours.py > road-colors-generated.mss  */"
+    print "/*                                                                   */"
+
+    for line_name, line_colours in colours.iteritems():
+        for name, colour in line_colours.iteritems():
+            if args.verbose:
+                line = "@{name}-{line_name}: {rgb}; // {lch}, error {delta:.1f}"
+            else:
+                line = "@{name}-{line_name}: {rgb};"
+            print line.format(name = name, line_name=line_name, rgb = colour.rgb(), lch = colour.lch(), delta = colour.rgb_error())
+
+if __name__ == "__main__":
+    main()
diff --git a/scripts/generate_shields.py b/scripts/generate_shields.py
index 32c780c..4faa207 100755
--- a/scripts/generate_shields.py
+++ b/scripts/generate_shields.py
@@ -1,132 +1,131 @@
 #!/usr/bin/env python
 
-# generate highway shields
+# Generate highway shields as SVG files in symbols/shields.
 
 from __future__ import print_function
 import copy, lxml.etree, math, os
+from generate_road_colours import load_settings, generate_colours
 
 def main():
 
-  namespace = 'http://www.w3.org/2000/svg'
-  svgns = '{' + namespace + '}'
-  svgnsmap = {None: namespace}
-
-  config = {}
-  config['base'] = {}
-
-  config['base']['rounded_corners'] = 2
-  config['base']['font_height'] = 9.1
-  config['base']['font_width'] = 5.9
-  config['base']['padding_x'] = 4
-  config['base']['padding_y'] = 2
-  config['base']['fill'] = '#ddd'
-  config['base']['stroke_width'] = 1
-  config['base']['stroke_fill'] = '#000'
-
-  config['global'] = {}
-
-  config['global']['types'] = ['motorway', 'trunk', 'primary', 'secondary', 'tertiary']
-  config['global']['max_width'] = 11
-  config['global']['max_height'] = 4
-  config['global']['output_dir'] = '../symbols/shields/' # specified relative to the script location
-
-  config['global']['additional_sizes'] = ['base', 'z16', 'z18']
-
-  # specific values overwrite config['base'] ones
-  config['motorway'] = {}
-  config['trunk'] = {}
-  config['primary'] = {}
-  config['secondary'] = {}
-  config['tertiary'] = {}
-
-  # colour values are generated by generate_road_colours.py
-
-  config['motorway']['fill'] = '#eccdd1' # Lch(85,12,10), error 0.3
-  config['motorway']['stroke_fill'] = '#d39da5' # Lch(70,22,10), error 0.2
-  config['trunk']['fill'] = '#f2d7ce' # Lch(88,12,42), error 1.0
-  config['trunk']['stroke_fill'] = '#d7a899' # Lch(73,22,42), error 0.9
-  config['primary']['fill'] = '#f3e3cf' # Lch(91,12,74), error 1.4
-  config['primary']['stroke_fill'] = '#d1b795' # Lch(76,22,74), error 1.8
-  config['secondary']['fill'] = '#eeefd7' # Lch(94,12,106), error 1.3
-  config['secondary']['stroke_fill'] = '#c4c69c' # Lch(79,22,106), error 1.5
-  config['tertiary']['fill'] = '#f1f1f1' # Lch(95,0,0), error 0.1
-  config['tertiary']['stroke_fill'] = '#c6c6c6' # Lch(80,0,0), error 0.1
-
-  # changes for different size versions
-  config['z16'] = {}
-  config['z18'] = {}
-
-  config['z16']['font_width'] = 6.5
-  config['z16']['font_height'] = 10.1
-  config['z18']['font_width'] = 7.2
-  config['z18']['font_height'] = 11.1
-
-  if not os.path.exists(os.path.dirname(config['global']['output_dir'])):
-    os.makedirs(os.path.dirname(config['global']['output_dir']))
-
-  for height in range(1, config['global']['max_height'] + 1):
-    for width in range(1, config['global']['max_width'] + 1):
-      for shield_type in config['global']['types']:
-
-        # merge base config and specific styles
-        vars = copy.deepcopy(config['base'])
-        if shield_type in config:
-          for option in config[shield_type]:
-            vars[option] = config[shield_type][option]
-
-        for shield_size in config['global']['additional_sizes']:
-
-          if shield_size != 'base':
-            if shield_size in config:
-              for option in config[shield_size]:
-                vars[option] = config[shield_size][option]
-
-          shield_width = 2 * vars['padding_x'] + math.ceil(vars['font_width'] * width)
-          shield_height = 2 * vars['padding_y'] + math.ceil(vars['font_height'] * height)
-
-          svg = lxml.etree.Element('svg', nsmap=svgnsmap)
-          svg.set('width', '100%')
-          svg.set('height', '100%')
-          svg.set('viewBox', '0 0 ' + str(shield_width  + vars['stroke_width']) + ' ' + str(shield_height + vars['stroke_width']))
-
-          if vars['stroke_width'] > 0:
-            offset_x = vars['stroke_width'] / 2.0
-            offset_y = vars['stroke_width'] / 2.0
-          else:
-            offset_x = 0
-            offset_y = 0
-
-          shield = lxml.etree.Element(svgns + 'rect')
-          shield.set('x', str(offset_x))
-          shield.set('y', str(offset_y))
-          shield.set('width', str(shield_width))
-          shield.set('height', str(shield_height))
-          if vars['rounded_corners'] > 0:
-            shield.set('rx', str(vars['rounded_corners']))
-            shield.set('ry', str(vars['rounded_corners']))
-          shield.set('id', 'shield')
-
-          stroke = ''
-          if vars['stroke_width'] > 0:
-            stroke = 'stroke:' + vars['stroke_fill'] + ';stroke-width:' + str(vars['stroke_width']) + ';'
-
-          shield.set('style', 'fill:' + vars['fill'] + ';' + stroke)
-
-          svg.append(shield)
-
-          filename = shield_type + '_' + str(width) + 'x' + str(height)
-          if shield_size != 'base':
-            filename = filename + '_' + shield_size
-
-          filename = filename + '.svg'
-
-          # save file
-          try:
-            shieldfile = open(os.path.join(os.path.dirname(__file__), config['global']['output_dir'] + filename), 'w')
-            shieldfile.write(lxml.etree.tostring(svg, encoding='utf-8', xml_declaration=True, pretty_print=True))
-            shieldfile.close()
-          except IOError:
-            print('Could not save file ' + filename + '.')
-            continue
-
-if __name__ == "__main__": main()
+    settings = load_settings()
+    colours = generate_colours(settings, 'shield')
+
+    namespace = 'http://www.w3.org/2000/svg'
+    svgns = '{' + namespace + '}'
+    svgnsmap = {None: namespace}
+
+    config = {}
+    config['base'] = {}
+
+    config['base']['rounded_corners'] = 2
+    config['base']['font_height'] = 9.1
+    config['base']['font_width'] = 5.9
+    config['base']['padding_x'] = 4
+    config['base']['padding_y'] = 2
+    config['base']['stroke_width'] = 1
+
+    # Fall back colours used if no colours are defined in road-colours.yaml for a road type.
+    config['base']['fill'] = '#f1f1f1'
+    config['base']['stroke_fill'] = '#c6c6c6'
+
+    config['global'] = {}
+
+    config['global']['types'] = ['motorway', 'trunk', 'primary', 'secondary', 'tertiary']
+    config['global']['max_width'] = 11
+    config['global']['max_height'] = 4
+    config['global']['output_dir'] = '../symbols/shields/' # specified relative to the script location
+
+    config['global']['additional_sizes'] = ['base', 'z16', 'z18']
+
+    # specific values overwrite config['base'] ones
+    config['motorway'] = {}
+    config['trunk'] = {}
+    config['primary'] = {}
+    config['secondary'] = {}
+    config['tertiary'] = {}
+
+    # Colour values generated by generate_road_colours.py.
+    for line_name, line_colours in colours.iteritems():
+        for name, colour in line_colours.iteritems():
+            config[name][line_name] = colour.rgb()
+
+    # changes for different size versions
+    config['z16'] = {}
+    config['z18'] = {}
+
+    config['z16']['font_width'] = 6.5
+    config['z16']['font_height'] = 10.1
+    config['z18']['font_width'] = 7.2
+    config['z18']['font_height'] = 11.1
+
+    if not os.path.exists(os.path.dirname(config['global']['output_dir'])):
+        os.makedirs(os.path.dirname(config['global']['output_dir']))
+
+    for height in range(1, config['global']['max_height'] + 1):
+        for width in range(1, config['global']['max_width'] + 1):
+            for shield_type in config['global']['types']:
+
+                # merge base config and specific styles
+                vars = copy.deepcopy(config['base'])
+                if shield_type in config:
+                    for option in config[shield_type]:
+                        vars[option] = config[shield_type][option]
+
+                for shield_size in config['global']['additional_sizes']:
+
+                    if shield_size != 'base':
+                        if shield_size in config:
+                            for option in config[shield_size]:
+                                vars[option] = config[shield_size][option]
+
+                    shield_width = 2 * vars['padding_x'] + math.ceil(vars['font_width'] * width)
+                    shield_height = 2 * vars['padding_y'] + math.ceil(vars['font_height'] * height)
+
+                    svg = lxml.etree.Element('svg', nsmap=svgnsmap)
+                    svg.set('width', '100%')
+                    svg.set('height', '100%')
+                    svg.set('viewBox', '0 0 ' + str(shield_width    + vars['stroke_width']) + ' ' + str(shield_height + vars['stroke_width']))
+
+                    if vars['stroke_width'] > 0:
+                        offset_x = vars['stroke_width'] / 2.0
+                        offset_y = vars['stroke_width'] / 2.0
+                    else:
+                        offset_x = 0
+                        offset_y = 0
+
+                    shield = lxml.etree.Element(svgns + 'rect')
+                    shield.set('x', str(offset_x))
+                    shield.set('y', str(offset_y))
+                    shield.set('width', str(shield_width))
+                    shield.set('height', str(shield_height))
+                    if vars['rounded_corners'] > 0:
+                        shield.set('rx', str(vars['rounded_corners']))
+                        shield.set('ry', str(vars['rounded_corners']))
+                    shield.set('id', 'shield')
+
+                    stroke = ''
+                    if vars['stroke_width'] > 0:
+                        stroke = 'stroke:' + vars['stroke_fill'] + ';stroke-width:' + str(vars['stroke_width']) + ';'
+
+                    shield.set('style', 'fill:' + vars['fill'] + ';' + stroke)
+
+                    svg.append(shield)
+
+                    filename = shield_type + '_' + str(width) + 'x' + str(height)
+                    if shield_size != 'base':
+                        filename = filename + '_' + shield_size
+
+                    filename = filename + '.svg'
+
+                    # save file
+                    try:
+                        shieldfile = open(os.path.join(os.path.dirname(__file__), config['global']['output_dir'] + filename), 'w')
+                        shieldfile.write(lxml.etree.tostring(svg, encoding='utf-8', xml_declaration=True, pretty_print=True))
+                        shieldfile.close()
+                    except IOError:
+                        print('Could not save file ' + filename + '.')
+                        continue
+
+if __name__ == "__main__":
+    main()
diff --git a/scripts/yaml2mml.py b/scripts/yaml2mml.py
index f73c24e..4213a6d 100755
--- a/scripts/yaml2mml.py
+++ b/scripts/yaml2mml.py
@@ -17,7 +17,7 @@ try:
 
   try:
     if (args.check == False):
-      mml_file = open(mml_path, 'w')
+      mml_file = open(mml_path, 'wb')
       json.dump(yaml, mml_file, indent=2, separators=(',', ': '))
       mml_file.close()
     else:
diff --git a/style.mss b/style.mss
index 86083cb..a6aca14 100644
--- a/style.mss
+++ b/style.mss
@@ -2,17 +2,17 @@ Map {
   background-color: @water-color;
 }
 
- at book-fonts:    "DejaVu Sans Book", "Arundina Sans Regular", "Padauk Regular", "Khmer OS Metal Chrieng Regular",
-                "Mukti Narrow Regular", "gargi Medium", "TSCu_Paranar Regular", "Tibetan Machine Uni Regular", "Mallige Normal",
+ at book-fonts:    "DejaVu Sans Book", "Arundina Regular", "Arundina Sans Regular", "Padauk Regular", "Khmer OS Metal Chrieng Regular",
+                "Mukti Narrow Regular", "Gargi Regular", "TSCu_Paranar Regular", "Tibetan Machine Uni Regular",
                 "Droid Sans Fallback Regular", "Unifont Medium", "unifont Medium";
- at bold-fonts:    "DejaVu Sans Bold", "Arundina Sans Bold", "Padauk Bold", "Mukti Narrow Bold", "TSCu_Paranar Bold", "Mallige Bold",
-                "DejaVu Sans Book", "Arundina Sans Regular", "Padauk Regular", "Khmer OS Metal Chrieng Regular",
-                "Mukti Narrow Regular", "gargi Medium", "TSCu_Paranar Regular", "Tibetan Machine Uni Regular", "Mallige Normal",
+ at bold-fonts:    "DejaVu Sans Bold", "Arundina Bold", "Arundina Sans Bold", "Padauk Bold", "TSCu_Paranar Bold",
+                "DejaVu Sans Book", "Arundina Regular", "Arundina Sans Regular", "Padauk Regular", "Khmer OS Metal Chrieng Regular",
+                "Mukti Narrow Regular", "gargi Medium", "TSCu_Paranar Regular", "Tibetan Machine Uni Regular",
                 "Droid Sans Fallback Regular", "Unifont Medium", "unifont Medium";
 
- at oblique-fonts: "DejaVu Sans Oblique", "Arundina Sans Italic", "TSCu_Paranar Italic", "Mallige NormalItalic",
-                "DejaVu Sans Book", "Arundina Sans Regular", "Padauk Regular", "Khmer OS Metal Chrieng Regular",
-                "Mukti Narrow Regular", "gargi Medium", "TSCu_Paranar Regular", "Tibetan Machine Uni Regular", "Mallige Normal",
+ at oblique-fonts: "DejaVu Sans Oblique", "Arundina Italic", "Arundina Sans Italic", "TSCu_Paranar Italic",
+                "DejaVu Sans Book", "Arundina Regular", "Arundina Sans Regular", "Padauk Regular", "Khmer OS Metal Chrieng Regular",
+                "Mukti Narrow Regular", "Gargi Regular", "TSCu_Paranar Regular", "Tibetan Machine Uni Regular",
                 "Droid Sans Fallback Regular", "Unifont Medium", "unifont Medium";
 
 @water-color: #b5d0d0;
diff --git a/symbols/dog_park.16.svg b/symbols/dog_park.16.svg
new file mode 100644
index 0000000..7373f86
--- /dev/null
+++ b/symbols/dog_park.16.svg
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="100%"
+   height="100%"
+   viewBox="0 0 16 16"
+   id="svg2"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="fast_food.16.svg">
+  <metadata
+     id="metadata10">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs8" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1855"
+     inkscape:window-height="1056"
+     id="namedview6"
+     showgrid="false"
+     inkscape:zoom="14.75"
+     inkscape:cx="8"
+     inkscape:cy="8"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg2" />
+  <path
+     id="path2193-6"
+     style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill-opacity:1;fill-rule:nonzero;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+     d="m 12.687351,8.6978703 c 0.882828,-0.234079 1.711529,0.194669 1.851022,0.957622 0.13961,0.7629817 -0.463039,1.5713077 -1.345824,1.8054887 -0.882813,0.234181 -1.711601,-0.194436 -1.851255,-0.95736 -0.139609,-0.7629377 0.462807,-1.5713367 1.345577,-1.8056337 M 10.909827,4.123512 c 0.965591,-0.6676112 2.00599,-0.5184178 2.323878,0.333202 0.317874,0.8516052 -0.207131,2.0832254 -1.172649,2.7509529 C 11.095508,7.8753944 10.055052,7.72639 9.7370185,6.8748866 9.4189985,6.0233541 9.9438294 [...]
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="csssccsssccsssccssscssssss" />
+</svg>
diff --git a/symbols/dog_park.png b/symbols/dog_park.png
new file mode 100644
index 0000000..e9a819d
Binary files /dev/null and b/symbols/dog_park.png differ

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/openstreetmap-carto.git



More information about the Pkg-grass-devel mailing list