diff options
-rwxr-xr-x | bin/style.json | 119 | ||||
-rw-r--r-- | include/mbgl/style/function_properties.hpp | 28 | ||||
-rw-r--r-- | src/style/function_properties.cpp | 87 | ||||
-rw-r--r-- | src/style/style_parser.cpp | 105 | ||||
-rw-r--r-- | test/fixtures/styles/road-width.style.json | 1 | ||||
-rw-r--r-- | test/functions.cpp | 44 |
6 files changed, 71 insertions, 313 deletions
diff --git a/bin/style.json b/bin/style.json index dc6eb78dda..aea2a1a3ac 100755 --- a/bin/style.json +++ b/bin/style.json @@ -64,124 +64,94 @@ "@street_night": "#0186ac", "@contour_night": "#ffff80", "@river_canal_width": { - "fn": "stops", "stops": [[10, 0.5], [11, 1], [13, 2], [15, 3]] }, "@stream_width": { - "fn": "stops", "stops": [[12, 0.25], [13, 0.5], [15, 1.5], [17, 2]] }, "@motorway_width": { - "fn": "stops", "stops": [[4, 0], [5, 0.5], [7, 0.8], [9, 1], [10, 1.2], [11, 2], [12, 3], [13, 4], [14, 6], [15, 9], [16, 12], [17, 14]] }, "@motorway_casing_width": { - "fn": "stops", "stops": [[6.5, 0.6], [7, 0.8], [9, 2.8], [10, 3], [11, 4], [12, 5], [13, 6.5], [14, 9], [15, 12], [16, 15], [17, 17]] }, "@motorway_link_width": { - "fn": "stops", "stops": [[11, 1.2], [13, 2], [15, 3], [17, 4]] }, "@motorway_link_casing_width": { - "fn": "stops", "stops": [[11, 2.8], [13, 3.5], [15, 5], [17, 6]] }, "@main_width": { - "fn": "stops", "stops": [[4, 1], [11, 1], [12, 1.5], [13, 2], [14, 3], [15, 6], [16, 10], [17, 12]] }, "@main_casing_width": { - "fn": "stops", "stops": [[8, 2.9], [11, 2.9], [12, 3.5], [13, 4], [14, 5.5], [15, 9], [16, 12], [17, 14]] }, "@street_width": { - "fn": "stops", "stops": [[13.5, 0], [14, 1.5], [15, 3], [16, 8]] }, "@street_casing_width": { - "fn": "stops", "stops": [[12, 0.4], [13, 1], [14, 2.5], [15, 4], [16, 10]] }, "@street_casing_opacity": { - "fn": "stops", "stops": [[13, 0], [13.5, 1]] }, "@service_casing_width": { - "fn": "stops", "stops": [[13, 0.5], [14, 3], [15, 3.5], [16, 4], [17, 5], [18, 6]] }, "@runway_width": { - "fn": "stops", "stops": [[9, 1], [10, 2], [11, 3], [12, 5], [13, 7], [14, 11], [15, 15], [16, 19], [17, 23]] }, "@taxiway_width": { - "fn": "stops", "stops": [[9, 0.2], [11, 0.2], [12, 1], [13, 1.5], [14, 2], [15, 3], [16, 4], [17, 5]] }, "@aerialway_width": { - "fn": "stops", "stops": [[12.5, 0.8], [13, 1.4], [14, 1.6], [15, 2], [16, 2.4], [17, 3]] }, "@aerialway_casing_width": { - "fn": "stops", "stops": [[12.5, 2], [13, 2.5], [14, 3], [15, 3.5], [16, 4], [21, 5]] }, "@path_width": { - "fn": "stops", "stops": [[13, 1.2], [14, 1.5], [15, 1.8]] }, "@admin_l2_width": { - "fn": "stops", "stops": [[1, 0.5], [2, 0.7], [3, 0.7], [4, 0.8], [5, 1], [7, 2], [9, 3]] }, "@admin_l3_width": { - "fn": "stops", "stops": [[5, 0.6], [7, 1], [11, 2]] }, "@road_label_1_size": { - "fn": "stops", "stops": [[12, 11], [13, 12], [14, 13], [15, 14], [16, 16], [17, 18]] }, "@road_label_2_size": { - "fn": "stops", "stops": [[12, 11], [13, 12], [15, 14], [17, 16]] }, "@road_label_3_size": { - "fn": "stops", "stops": [[14, 10], [15, 12], [17, 14]] }, "@fence_width": { - "fn": "stops", "stops": [[16, 0.6], [18, 1]] }, "@hedge_width": { - "fn": "stops", "stops": [[15, 0.6], [16, 1.2], [18, 1.6]] }, "@barrier_line_land_width": { - "fn": "stops", "stops": [[13, 0.4], [14, 0.75], [15, 1.5], [16, 3], [17, 6], [18, 12], [19, 24], [20, 48]] }, "@country_label_size": { - "fn": "stops", "stops": [[0, 14], [11, 24]] }, "@poi_label_1-2_size": { - "fn": "stops", "stops": [[14, 10], [15, 11], [16, 12]] }, "@poi_label_3_size": { - "fn": "stops", "stops": [[15, 10], [16, 11]] }, "@hillshade_rasterize": { "enabled": { - "fn": "stops", "stops": [[10, false], [11, true]] }, "size": { - "fn": "stops", "stops": [[10, 1024], [11, 512], [12, 256]] }, "blur": 1 @@ -229,14 +199,12 @@ "style": { "fill-color": "@grass", "fill-opacity": { - "fn": "stops", "stops": [[12, 1], [13, 0.8], [16, 0.2]] } }, "style.night": { "fill-color": "@grass_night", "fill-opacity": { - "fn": "stops", "stops": [[12, 1], [13, 0.8], [16, 0.2]] } } @@ -249,14 +217,12 @@ "style": { "fill-color": "@scrub", "fill-opacity": { - "fn": "stops", "stops": [[12, 1], [13, 0.8], [16, 0.2]] } }, "style.night": { "fill-color": "@scrub_night", "fill-opacity": { - "fn": "stops", "stops": [[12, 1], [13, 0.8], [16, 0.2]] } } @@ -269,14 +235,12 @@ "style": { "fill-color": "@wood", "fill-opacity": { - "fn": "stops", "stops": [[12, 1], [13, 0.8], [16, 0.2]] } }, "style.night": { "fill-color": "@wood_night", "fill-opacity": { - "fn": "stops", "stops": [[12, 1], [13, 0.8], [16, 0.2]] } } @@ -514,7 +478,6 @@ "fill-color": "#d5d1c6", "fill-translate": [1, 1], "fill-opacity": { - "fn": "stops", "stops": [[15.5, 0], [16, 1]] }, "fill-outline-color": "#d5d1c6" @@ -523,7 +486,6 @@ "fill-color": "#026688", "fill-translate": [1, 1], "fill-opacity": { - "fn": "stops", "stops": [[15.5, 0], [16, 1]] }, "fill-outline-color": "#026688" @@ -543,7 +505,6 @@ "style": { "fill-color": "#ebe7db", "fill-opacity": { - "fn": "stops", "stops": [[15.5, 0], [16, 0.7]] }, "fill-outline-color": "#d5d1c6" @@ -551,7 +512,6 @@ "style.night": { "fill-color": "#027797", "fill-opacity": { - "fn": "stops", "stops": [[15.5, 0], [16, 0.7]] }, "fill-outline-color": "#026688" @@ -567,7 +527,6 @@ "fill-color": "#fffff3", "fill-antialias": false, "fill-opacity": { - "fn": "stops", "stops": [[14, 0.3], [15, 0.3], [16, 0.2], [17, 0.2], [18, 0.1]] } }, @@ -575,7 +534,6 @@ "fill-color": "#fdfdad", "fill-antialias": false, "fill-opacity": { - "fn": "stops", "stops": [[13, 0.4], [14, 0.3], [16, 0.2], [17, 0.1], [18, 0.05]] } } @@ -590,7 +548,6 @@ "fill-color": "#ffd", "fill-antialias": false, "fill-opacity": { - "fn": "stops", "stops": [[14, 0.3], [15, 0.3], [16, 0.2], [17, 0.2], [18, 0.1]] } }, @@ -598,7 +555,6 @@ "fill-color": "#ffe1b7", "fill-antialias": false, "fill-opacity": { - "fn": "stops", "stops": [[14, 0.3], [16, 0.2], [17, 0.15], [18, 0.05]] } } @@ -613,7 +569,6 @@ "fill-color": "#206", "fill-antialias": false, "fill-opacity": { - "fn": "stops", "stops": [[14, 0.08], [15, 0.075], [16, 0.05], [17, 0.05], [18, 0.025]] } }, @@ -621,7 +576,6 @@ "fill-color": "#206", "fill-antialias": false, "fill-opacity": { - "fn": "stops", "stops": [[15, 0.3], [16, 0.2], [17, 0.1], [18, 0.05]] } } @@ -636,7 +590,6 @@ "fill-color": "#103", "fill-antialias": false, "fill-opacity": { - "fn": "stops", "stops": [[14, 0.08], [15, 0.075], [16, 0.05], [17, 0.05], [18, 0.025]] } }, @@ -644,7 +597,6 @@ "fill-color": "#103", "fill-antialias": false, "fill-opacity": { - "fn": "stops", "stops": [[15, 0.3], [16, 0.2], [17, 0.1], [18, 0.05]] } } @@ -661,7 +613,6 @@ "line-color": "#008", "line-width": 0.9, "line-opacity": { - "fn": "stops", "stops": [[11, 0.05], [12, 0.11]] } }, @@ -669,7 +620,6 @@ "line-color": "@contour_night", "line-width": 0.9, "line-opacity": { - "fn": "stops", "stops": [[11, 0.1], [12, 0.2]] } } @@ -685,7 +635,6 @@ "line-color": "#008", "line-width": 0.5, "line-opacity": { - "fn": "stops", "stops": [[11, 0.05], [12, 0.11]] } }, @@ -693,7 +642,6 @@ "line-color": "@contour_night", "line-width": 0.5, "line-opacity": { - "fn": "stops", "stops": [[11, 0.1], [12, 0.4]] } } @@ -876,7 +824,6 @@ "line-dasharray": [6, 6], "line-width": "@main_casing_width", "line-opacity": { - "fn": "stops", "stops": [[8, 0], [9, 1]] } }, @@ -885,7 +832,6 @@ "line-dasharray": [6, 6], "line-width": "@main_casing_width", "line-opacity": { - "fn": "stops", "stops": [[8, 0], [9, 1]] } } @@ -945,7 +891,6 @@ "line-color": "#e6cec7", "line-width": "@main_width", "line-opacity": { - "fn": "stops", "stops": [[5.5, 0], [6, 1]] } }, @@ -953,7 +898,6 @@ "line-color": "#78b0c1", "line-width": "@main_width", "line-opacity": { - "fn": "stops", "stops": [[5.5, 0], [6, 1]] } } @@ -968,7 +912,6 @@ "line-dasharray": [6, 6], "line-width": "@motorway_casing_width", "line-opacity": { - "fn": "stops", "stops": [[8.5, 0], [9, 1]] } }, @@ -977,7 +920,6 @@ "line-dasharray": [6, 6], "line-width": "@motorway_casing_width", "line-opacity": { - "fn": "stops", "stops": [[8.5, 0], [9, 1]] } } @@ -988,7 +930,6 @@ "line-color": "#e6cec7", "line-width": "@motorway_width", "line-opacity": { - "fn": "stops", "stops": [[5.5, 0], [6, 1]] } }, @@ -996,7 +937,6 @@ "line-color": "#78b0c1", "line-width": "@motorway_width", "line-opacity": { - "fn": "stops", "stops": [[5.5, 0], [6, 1]] } } @@ -1010,7 +950,6 @@ "line-color": "#ffd", "line-opacity": 0.4, "line-width": { - "fn": "stops", "stops": [[14, 3], [15, 4]] } }, @@ -1045,7 +984,6 @@ "line-dasharray": [10, 4], "line-opacity": 0.8, "line-width": { - "fn": "stops", "stops": [[13, 0.8], [14, 0.9], [15, 1.2]] } }, @@ -1054,7 +992,6 @@ "line-dasharray": [10, 4], "line-opacity": 0.8, "line-width": { - "fn": "stops", "stops": [[13, 0.8], [14, 0.9], [15, 1.2]] } } @@ -1189,7 +1126,6 @@ "line-color": "@case", "line-width": "@main_casing_width", "line-opacity": { - "fn": "stops", "stops": [[8, 0], [9, 1]] } }, @@ -1197,7 +1133,6 @@ "line-color": "@case_night", "line-width": "@main_casing_width", "line-opacity": { - "fn": "stops", "stops": [[8, 0], [9, 1]] } } @@ -1261,7 +1196,6 @@ "line-color": "@main", "line-width": "@main_width", "line-opacity": { - "fn": "stops", "stops": [[5.5, 0], [6, 1]] } }, @@ -1269,7 +1203,6 @@ "line-color": "@main_night", "line-width": "@main_width", "line-opacity": { - "fn": "stops", "stops": [[5.5, 0], [6, 1]] } } @@ -1287,7 +1220,6 @@ "line-color": "@case", "line-width": "@motorway_casing_width", "line-opacity": { - "fn": "stops", "stops": [[8.5, 0], [9, 1]] } }, @@ -1295,7 +1227,6 @@ "line-color": "@case_night", "line-width": "@motorway_casing_width", "line-opacity": { - "fn": "stops", "stops": [[8.5, 0], [9, 1]] } } @@ -1306,7 +1237,6 @@ "line-color": "@motorway", "line-width": "@motorway_width", "line-opacity": { - "fn": "stops", "stops": [[5.5, 0], [6, 1]] } }, @@ -1314,7 +1244,6 @@ "line-color": "@motorway_night", "line-width": "@motorway_width", "line-opacity": { - "fn": "stops", "stops": [[5.5, 0], [6, 1]] } } @@ -1371,7 +1300,6 @@ "line-color": "@case", "line-width": "@main_casing_width", "line-opacity": { - "fn": "stops", "stops": [[8, 0], [9, 1]] } }, @@ -1379,7 +1307,6 @@ "line-color": "@case_night", "line-width": "@main_casing_width", "line-opacity": { - "fn": "stops", "stops": [[8, 0], [9, 1]] } } @@ -1439,7 +1366,6 @@ "line-color": "@main", "line-width": "@main_width", "line-opacity": { - "fn": "stops", "stops": [[5.5, 0], [6, 1]] } }, @@ -1447,7 +1373,6 @@ "line-color": "@main_night", "line-width": "@main_width", "line-opacity": { - "fn": "stops", "stops": [[5.5, 0], [6, 1]] } } @@ -1461,7 +1386,6 @@ "line-color": "@case", "line-width": "@motorway_casing_width", "line-opacity": { - "fn": "stops", "stops": [[8.5, 0], [9, 1]] } }, @@ -1469,7 +1393,6 @@ "line-color": "@case_night", "line-width": "@motorway_casing_width", "line-opacity": { - "fn": "stops", "stops": [[8.5, 0], [9, 1]] } } @@ -1480,7 +1403,6 @@ "line-color": "@motorway", "line-width": "@motorway_width", "line-opacity": { - "fn": "stops", "stops": [[5.5, 0], [6, 1]] } }, @@ -1488,7 +1410,6 @@ "line-color": "@motorway_night", "line-width": "@motorway_width", "line-opacity": { - "fn": "stops", "stops": [[5.5, 0], [6, 1]] } } @@ -1534,7 +1455,6 @@ "line-color": "#88a", "line-dasharray": [60, 20], "line-opacity": { - "fn": "stops", "stops": [[3, 0], [5, 1]] }, "line-width": "@admin_l3_width" @@ -1543,7 +1463,6 @@ "line-color": "@admin_night", "line-dasharray": [60, 20], "line-opacity": { - "fn": "stops", "stops": [[3, 0], [5, 1]] }, "line-width": "@admin_l3_width" @@ -1590,14 +1509,12 @@ "style": { "line-color": "#c0d6d6", "line-width": { - "fn": "stops", "stops": [[5, 1], [7, 2], [11, 3]] } }, "style.night": { "line-color": "#0a1347", "line-width": { - "fn": "stops", "stops": [[5, 1], [7, 2], [11, 3]] } } @@ -1661,7 +1578,6 @@ "style": { "text-color": "@marine_text", "text-size": { - "fn": "stops", "stops": [[2, 20], [3, 25], [4, 30], [21, 30]] }, "text-halo-color": "@water" @@ -1669,7 +1585,6 @@ "style.night": { "text-color": "@water_dark_night", "text-size": { - "fn": "stops", "stops": [[2, 20], [3, 25], [4, 30], [21, 30]] }, "text-halo-color": "@water_night" @@ -1690,7 +1605,6 @@ "style": { "text-color": "@marine_text", "text-size": { - "fn": "stops", "stops": [[2, 13], [3, 14], [4, 20], [5, 24], [21, 24]] }, "text-halo-color": "@water" @@ -1698,7 +1612,6 @@ "style.night": { "text-color": "@water_dark_night", "text-size": { - "fn": "stops", "stops": [[2, 13], [3, 14], [4, 20], [5, 24], [21, 24]] }, "text-halo-color": "@water_night" @@ -1719,7 +1632,6 @@ "style": { "text-color": "@marine_text", "text-size": { - "fn": "stops", "stops": [[2, 12], [3, 13], [4, 15], [5, 18], [21, 18]] }, "text-halo-color": "@water" @@ -1727,7 +1639,6 @@ "style.night": { "text-color": "@water_dark_night", "text-size": { - "fn": "stops", "stops": [[2, 12], [3, 13], [4, 15], [5, 18], [21, 18]] }, "text-halo-color": "@water_night" @@ -1748,7 +1659,6 @@ "style": { "text-color": "@marine_text", "text-size": { - "fn": "stops", "stops": [[3, 12], [4, 14], [5, 16], [21, 16]] }, "text-halo-color": "@water" @@ -1756,7 +1666,6 @@ "style.night": { "text-color": "@water_dark_night", "text-size": { - "fn": "stops", "stops": [[3, 12], [4, 14], [5, 16], [21, 16]] }, "text-halo-color": "@water_night" @@ -1779,7 +1688,6 @@ "style": { "text-color": "@marine_text", "text-size": { - "fn": "stops", "stops": [[2, 20], [3, 25], [4, 30], [21, 30]] }, "text-halo-color": "@water" @@ -1787,7 +1695,6 @@ "style.night": { "text-color": "@water_dark_night", "text-size": { - "fn": "stops", "stops": [[2, 20], [3, 25], [4, 30], [21, 30]] }, "text-halo-color": "@water_night" @@ -1810,7 +1717,6 @@ "style": { "text-color": "@marine_text", "text-size": { - "fn": "stops", "stops": [[2, 13], [3, 14], [4, 20], [5, 24], [21, 24]] }, "text-halo-color": "@water" @@ -1818,7 +1724,6 @@ "style.night": { "text-color": "@water_dark_night", "text-size": { - "fn": "stops", "stops": [[2, 13], [3, 14], [4, 20], [5, 24], [21, 24]] }, "text-halo-color": "@water_night" @@ -1841,7 +1746,6 @@ "style": { "text-color": "@marine_text", "text-size": { - "fn": "stops", "stops": [[2, 12], [3, 13], [4, 15], [5, 18], [21, 18]] }, "text-halo-color": "@water" @@ -1849,7 +1753,6 @@ "style.night": { "text-color": "@water_dark_night", "text-size": { - "fn": "stops", "stops": [[2, 12], [3, 13], [4, 15], [5, 18], [21, 18]] }, "text-halo-color": "@water_night" @@ -1872,7 +1775,6 @@ "style": { "text-color": "@marine_text", "text-size": { - "fn": "stops", "stops": [[3, 12], [4, 14], [5, 16], [21, 16]] }, "text-halo-color": "@water" @@ -1880,7 +1782,6 @@ "style.night": { "text-color": "@water_dark_night", "text-size": { - "fn": "stops", "stops": [[3, 12], [4, 14], [5, 16], [21, 16]] }, "text-halo-color": "@water_night" @@ -1903,7 +1804,6 @@ "text-halo-width": 0.4, "text-halo-color": "rgba(244,239,225,0.8)", "text-size": { - "fn": "stops", "stops": [[2.99, 0], [3, 10], [8.99, 16], [9, 0]] } }, @@ -1912,7 +1812,6 @@ "text-halo-width": 0.4, "text-halo-color": "@land_night", "text-size": { - "fn": "stops", "stops": [[2.99, 0], [3, 10], [8.99, 16], [9, 0]] } } @@ -1934,7 +1833,6 @@ "text-halo-width": 0.4, "text-halo-color": "@text_stroke", "text-size": { - "fn": "stops", "stops": [[2.99, 0], [3, 10], [6, 14], [13.99, 20], [14, 0]] } }, @@ -1943,7 +1841,6 @@ "text-halo-width": 0.4, "text-halo-color": "@text2_stroke_night", "text-size": { - "fn": "stops", "stops": [[2.99, 0], [3, 10], [6, 14], [13.99, 20], [14, 0]] } } @@ -1965,7 +1862,6 @@ "text-halo-width": 0.3, "text-halo-color": "@text_stroke", "text-size": { - "fn": "stops", "stops": [[8, 10], [11, 13], [13, 17], [15, 22]] } }, @@ -1974,7 +1870,6 @@ "text-halo-width": 0.3, "text-halo-color": "@text2_stroke_night", "text-size": { - "fn": "stops", "stops": [[8, 10], [11, 13], [13, 17], [15, 22]] } } @@ -1996,7 +1891,6 @@ "text-halo-width": 0.3, "text-halo-color": "@text_stroke", "text-size": { - "fn": "stops", "stops": [[8, 8], [11, 10], [13, 14], [15, 16], [16, 20]] } }, @@ -2005,7 +1899,6 @@ "text-halo-width": 0.3, "text-halo-color": "@text2_stroke_night", "text-size": { - "fn": "stops", "stops": [[8, 8], [11, 10], [13, 14], [15, 16], [16, 20]] } } @@ -2026,7 +1919,6 @@ "text-color": "#7d6c55", "text-halo-color": "@text_stroke", "text-size": { - "fn": "stops", "stops": [[12, 11], [13, 12], [15, 14], [17, 18]] } }, @@ -2035,7 +1927,6 @@ "text-halo-color": "@text2_stroke_night", "text-halo-width": 0.3, "text-size": { - "fn": "stops", "stops": [[12, 11], [13, 12], [15, 14], [17, 18]] } } @@ -2235,13 +2126,11 @@ }, "style": { "icon-opacity": { - "fn": "stops", "stops": [[15.5, 0], [15.75, 1]] } }, "style.night": { "icon-opacity": { - "fn": "stops", "stops": [[15.5, 0], [15.75, 1]] } } @@ -2266,7 +2155,6 @@ "text-halo-color": "@land", "text-halo-width": 0.3, "text-opacity": { - "fn": "stops", "stops": [[15.5, 0], [15.75, 1]] } }, @@ -2276,7 +2164,6 @@ "text-halo-color": "@text2_stroke_night", "text-halo-width": 0.3, "text-opacity": { - "fn": "stops", "stops": [[15.5, 0], [15.75, 1]] } } @@ -2292,13 +2179,11 @@ }, "style": { "icon-opacity": { - "fn": "stops", "stops": [[17.5, 0], [17.75, 1]] } }, "style.night": { "icon-opacity": { - "fn": "stops", "stops": [[17.5, 0], [17.75, 1]] } } @@ -2321,7 +2206,6 @@ "text-color": "#444", "text-size": 10, "text-opacity": { - "fn": "stops", "stops": [[17.5, 0], [17.75, 1]] }, "text-halo-color": "@land", @@ -2331,7 +2215,6 @@ "text-color": "#fff", "text-size": 10, "text-opacity": { - "fn": "stops", "stops": [[17.5, 0], [17.75, 1]] }, "text-halo-color": "@text2_stroke_night", @@ -2349,13 +2232,11 @@ }, "style": { "icon-opacity": { - "fn": "stops", "stops": [[12, 0], [12.25, 1]] } }, "style.night": { "icon-opacity": { - "fn": "stops", "stops": [[12, 0], [12.25, 1]] } } diff --git a/include/mbgl/style/function_properties.hpp b/include/mbgl/style/function_properties.hpp index 74ac80f83c..8cd7ce6e28 100644 --- a/include/mbgl/style/function_properties.hpp +++ b/include/mbgl/style/function_properties.hpp @@ -17,43 +17,19 @@ private: }; template <typename T> -struct LinearFunction { - inline LinearFunction(const T &value, float z_base, float slope, const T &min, const T &max) - : value(value), min(min), max(max), z_base(z_base), slope(slope) {} - T evaluate(float z) const; - -private: - const T value, min, max; - const float z_base, slope; -}; - -template <typename T> -struct ExponentialFunction { - inline ExponentialFunction(const T &value, float z_base, float exp_base, float slope, const T &min, - const T &max) - : value(value), min(min), max(max), z_base(z_base), exp_base(exp_base), slope(slope) {} - T evaluate(float z) const; - -private: - const T value, min, max; - const float z_base, exp_base, slope; -}; - -template <typename T> struct StopsFunction { - inline StopsFunction(const std::vector<std::pair<float, T>> &values) : values(values) {} + inline StopsFunction(const std::vector<std::pair<float, T>> &values, float base) : values(values), base(base) {} T evaluate(float z) const; private: const std::vector<std::pair<float, T>> values; + const float base; }; template <typename T> using Function = util::variant< std::false_type, ConstantFunction<T>, - LinearFunction<T>, - ExponentialFunction<T>, StopsFunction<T> >; diff --git a/src/style/function_properties.cpp b/src/style/function_properties.cpp index 2b378fb6b9..879de84f85 100644 --- a/src/style/function_properties.cpp +++ b/src/style/function_properties.cpp @@ -6,82 +6,36 @@ namespace mbgl { -template <> -bool LinearFunction<bool>::evaluate(float z) const { - return z < z_base ? slope >= 0 : z > z_base ? slope >= 0 : value; -} - -template <> -float LinearFunction<float>::evaluate(float z) const { - return std::fmin(std::fmax(min, value + (z - z_base) * slope), max); -} - -template <> -Color LinearFunction<Color>::evaluate(float z) const { - return {{ - std::fmin(std::fmax(min[0], value[0] + (z - z_base) * slope), max[0]), - std::fmin(std::fmax(min[1], value[1] + (z - z_base) * slope), max[1]), - std::fmin(std::fmax(min[2], value[2] + (z - z_base) * slope), max[2]), - std::fmin(std::fmax(min[3], value[3] + (z - z_base) * slope), max[3]) - }}; -} - - -template <> -bool ExponentialFunction<bool>::evaluate(float z) const { - return z < z_base ? slope >= 0 : z > z_base ? slope >= 0 : value; -} - -template <> -float ExponentialFunction<float>::evaluate(float z) const { - return std::fmin(std::fmax(min, value + std::pow(exp_base, (z - z_base)) * slope), max); -} - -template <> -Color ExponentialFunction<Color>::evaluate(float z) const { - return {{ - std::fmin(std::fmax(min[0], value[0] + float(std::pow(exp_base, (z - z_base))) * slope), max[0]), - std::fmin(std::fmax(min[1], value[1] + float(std::pow(exp_base, (z - z_base))) * slope), max[1]), - std::fmin(std::fmax(min[2], value[2] + float(std::pow(exp_base, (z - z_base))) * slope), max[2]), - std::fmin(std::fmax(min[3], value[3] + float(std::pow(exp_base, (z - z_base))) * slope), max[3]) - }}; -} - template <typename T> -inline T exponentialInterpolate(T smaller, T larger, const float factor); +inline T interpolate(T smaller, T larger, const float factor); template <> -inline float exponentialInterpolate(const float smaller, const float larger, const float factor) { - // Linear interpolation if base is 0 - if (smaller == 0.0f) { - return factor * larger; - } - // Exponential interpolation between the values - return smaller * std::pow(larger / smaller, factor); +inline float interpolate(const float smaller, const float larger, const float factor) { + return (smaller * (1 - factor)) + (larger * factor); } template <> -inline bool exponentialInterpolate(const bool smaller, const bool larger, const float factor) { - return exponentialInterpolate(float(smaller), float(larger), factor); +inline bool interpolate(const bool smaller, const bool larger, const float factor) { + return interpolate(float(smaller), float(larger), factor); } template <> -inline Color exponentialInterpolate(const Color smaller, const Color larger, const float factor) { +inline Color interpolate(const Color smaller, const Color larger, const float factor) { return {{ - exponentialInterpolate(smaller[0], larger[0], factor), - exponentialInterpolate(smaller[1], larger[1], factor), - exponentialInterpolate(smaller[2], larger[2], factor), - exponentialInterpolate(smaller[3], larger[3], factor) + interpolate(smaller[0], larger[0], factor), + interpolate(smaller[1], larger[1], factor), + interpolate(smaller[2], larger[2], factor), + interpolate(smaller[3], larger[3], factor) }}; } template <typename T> -T exponentialDefault(); +inline T defaultStopsValue(); -template <> bool exponentialDefault() { return true; } -template <> float exponentialDefault() { return 1.0f; } -template <> Color exponentialDefault() { return {{ 0, 0, 0, 1 }}; } +template <> inline bool defaultStopsValue() { return true; } +template <> inline float defaultStopsValue() { return 1.0f; } +template <> inline Color defaultStopsValue() { return {{ 0, 0, 0, 1 }}; } template <typename T> @@ -112,15 +66,22 @@ T StopsFunction<T>::evaluate(float z) const { if (larger_z == smaller_z || larger_val == smaller_val) { return smaller_val; } - float factor = (z - smaller_z) / (larger_z - smaller_z); - return exponentialInterpolate<T>(smaller_val, larger_val, factor); + const float zoomDiff = larger_z - smaller_z; + const float zoomProgress = z - smaller_z; + if (base == 1.0f) { + const float t = zoomProgress / zoomDiff; + return interpolate<T>(smaller_val, larger_val, t); + } else { + const float t = (std::pow(base, zoomProgress) - 1) / (std::pow(base, zoomDiff) - 1); + return interpolate<T>(smaller_val, larger_val, t); + } } else if (larger) { return larger_val; } else if (smaller) { return smaller_val; } else { // No stop defined. - return exponentialDefault<T>(); + return defaultStopsValue<T>(); } } diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index c4faf81f5a..e5aa3acc15 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -231,95 +231,56 @@ Color StyleParser::parseFunctionArgument(JSVal value) { return parseColor(rvalue); } +template <typename T> inline float defaultBaseValue() { return 1.75; } +template <> inline float defaultBaseValue<Color>() { return 1.0; } + template <typename T> std::tuple<bool, Function<T>> StyleParser::parseFunction(JSVal value) { - if (!value.HasMember("fn")) { - Log::Warning(Event::ParseStyle, "function must specify a function name"); - return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; - } - - JSVal value_fn = value["fn"]; - if (!value_fn.IsString()) { + if (!value.HasMember("stops")) { Log::Warning(Event::ParseStyle, "function must specify a function type"); return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; } - const std::string type { value_fn.GetString(), value_fn.GetStringLength() }; + float base = defaultBaseValue<T>(); - if (type == "linear") { - if (!value.HasMember("z")) { - Log::Warning(Event::ParseStyle, "linear function must specify a base zoom level"); - return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; - } - if (!value.HasMember("val")) { - Log::Warning(Event::ParseStyle, "linear function must specify a base value"); - return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; + if (value.HasMember("base")) { + JSVal value_base = value["base"]; + if (value_base.IsNumber()) { + base = value_base.GetDouble(); + } else { + Log::Warning(Event::ParseStyle, "base must be numeric"); } - const float z_base = parseFunctionArgument<float>(value["z"]); - const T val = parseFunctionArgument<T>(value["val"]); - const float slope = value.HasMember("slope") ? parseFunctionArgument<float>(value["slope"]) : 1; - const T min = value.HasMember("min") ? parseFunctionArgument<T>(value["min"]) : T(); - const T max = value.HasMember("max") ? parseFunctionArgument<T>(value["max"]) : T(); - return std::tuple<bool, Function<T>> { true, LinearFunction<T>(val, z_base, slope, min, max) }; } - else if (type == "exponential") { - if (!value.HasMember("z")) { - Log::Warning(Event::ParseStyle, "exponential function must specify a base zoom level"); - return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; - } - if (!value.HasMember("val")) { - Log::Warning(Event::ParseStyle, "exponential function must specify a base value"); - return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; - } - const float z_base = parseFunctionArgument<float>(value["z"]); - const float exp_base = value.HasMember("base") ? parseFunctionArgument<float>(value["base"]) : 1.75; - const T val = parseFunctionArgument<T>(value["val"]); - const float slope = value.HasMember("slope") ? parseFunctionArgument<float>(value["slope"]) : 1; - const T min = value.HasMember("min") ? parseFunctionArgument<T>(value["min"]) : T(); - const T max = value.HasMember("max") ? parseFunctionArgument<T>(value["max"]) : T(); - return std::tuple<bool, Function<T>> { true, ExponentialFunction<T>(val, z_base, exp_base, slope, min, max) }; - } - else if (type == "stops") { - if (!value.HasMember("stops")) { - Log::Warning(Event::ParseStyle, "stops function must specify a stops array"); - return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; - } - JSVal value_stops = value["stops"]; - if (!value_stops.IsArray()) { - Log::Warning(Event::ParseStyle, "stops function must specify a stops array"); - return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; - } - - std::vector<std::pair<float, T>> stops; - for (rapidjson::SizeType i = 0; i < value_stops.Size(); ++i) { - JSVal stop = value_stops[i]; - if (stop.IsArray()) { - if (stop.Size() != 2) { - Log::Warning(Event::ParseStyle, "stop must have zoom level and value specification"); - return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; - } + JSVal value_stops = value["stops"]; + if (!value_stops.IsArray()) { + Log::Warning(Event::ParseStyle, "stops function must specify a stops array"); + return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; + } - JSVal z = stop[rapidjson::SizeType(0)]; - if (!z.IsNumber()) { - Log::Warning(Event::ParseStyle, "zoom level in stop must be a number"); - return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; - } + std::vector<std::pair<float, T>> stops; + for (rapidjson::SizeType i = 0; i < value_stops.Size(); ++i) { + JSVal stop = value_stops[i]; + if (stop.IsArray()) { + if (stop.Size() != 2) { + Log::Warning(Event::ParseStyle, "stop must have zoom level and value specification"); + return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; + } - stops.emplace_back(z.GetDouble(), parseFunctionArgument<T>(stop[rapidjson::SizeType(1)])); - } else { - Log::Warning(Event::ParseStyle, "function argument must be a numeric value"); + JSVal z = stop[rapidjson::SizeType(0)]; + if (!z.IsNumber()) { + Log::Warning(Event::ParseStyle, "zoom level in stop must be a number"); return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; } - } - return std::tuple<bool, Function<T>> { true, StopsFunction<T>(stops) }; - } - else { - Log::Warning(Event::ParseStyle, "function type '%s' is unknown", type.c_str()); + stops.emplace_back(z.GetDouble(), parseFunctionArgument<T>(stop[rapidjson::SizeType(1)])); + } else { + Log::Warning(Event::ParseStyle, "function argument must be a numeric value"); + return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; + } } - return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; + return std::tuple<bool, Function<T>> { true, StopsFunction<T>(stops, base) }; } diff --git a/test/fixtures/styles/road-width.style.json b/test/fixtures/styles/road-width.style.json index 5738546b33..76d7b5258c 100644 --- a/test/fixtures/styles/road-width.style.json +++ b/test/fixtures/styles/road-width.style.json @@ -23,7 +23,6 @@ "type": "line", "style": { "line-width": { - "fn": "stops", "stops": [[13, 0], [13.999, 0], [14, 4], [14.1, 10], [14.2, 20]] } } diff --git a/test/functions.cpp b/test/functions.cpp index a2ad93c4e1..56b2a31706 100644 --- a/test/functions.cpp +++ b/test/functions.cpp @@ -19,11 +19,11 @@ TEST(Function, Constant) { TEST(Function, Stops) { // Explicit constant slope in fringe regions. - mbgl::StopsFunction<float> slope_1({ { 0, 1.5 }, { 6, 1.5 }, { 8, 3 }, { 22, 3 } }); + mbgl::StopsFunction<float> slope_1({ { 0, 1.5 }, { 6, 1.5 }, { 8, 3 }, { 22, 3 } }, 1.75); EXPECT_EQ(1.5, slope_1.evaluate(0)); EXPECT_EQ(1.5, slope_1.evaluate(4)); EXPECT_EQ(1.5, slope_1.evaluate(6)); - ASSERT_FLOAT_EQ(2.12132, slope_1.evaluate(7)); + ASSERT_FLOAT_EQ(2.0454545454545454, slope_1.evaluate(7)); EXPECT_EQ(3.0, slope_1.evaluate(8)); EXPECT_EQ(3.0, slope_1.evaluate(9)); EXPECT_EQ(3.0, slope_1.evaluate(15)); @@ -31,48 +31,28 @@ TEST(Function, Stops) { // Test constant values in fringe regions. - mbgl::StopsFunction<float> slope_2({ { 6, 1.5 }, { 8, 3 } }); + mbgl::StopsFunction<float> slope_2({ { 6, 1.5 }, { 8, 3 } }, 1.75); EXPECT_EQ(1.5, slope_2.evaluate(0)); EXPECT_EQ(1.5, slope_2.evaluate(4)); EXPECT_EQ(1.5, slope_2.evaluate(6)); - ASSERT_FLOAT_EQ(2.12132, slope_2.evaluate(7)); + ASSERT_FLOAT_EQ(2.0454545454545454, slope_2.evaluate(7)); EXPECT_EQ(3.0, slope_2.evaluate(8)); EXPECT_EQ(3.0, slope_2.evaluate(9)); EXPECT_EQ(3.0, slope_2.evaluate(15)); EXPECT_EQ(3.0, slope_2.evaluate(22)); // Test no values. - mbgl::StopsFunction<float> slope_3({}); + mbgl::StopsFunction<float> slope_3({}, 1.75); EXPECT_EQ(1, slope_3.evaluate(2)); EXPECT_EQ(1, slope_3.evaluate(6)); EXPECT_EQ(1, slope_3.evaluate(12)); -} - - -TEST(Function, Linear) { - mbgl::LinearFunction<float> slope_1(/* val */ 7.5, /* z_base */ 4, /* slope */ 2, /* min */ 7.5, /* max */ 20); - ASSERT_FLOAT_EQ(7.5, slope_1.evaluate(3)); - ASSERT_FLOAT_EQ(7.5, slope_1.evaluate(4)); - ASSERT_FLOAT_EQ(8.5, slope_1.evaluate(4.5)); - ASSERT_FLOAT_EQ(9.5, slope_1.evaluate(5)); - ASSERT_FLOAT_EQ(11.5, slope_1.evaluate(6)); - ASSERT_FLOAT_EQ(19.5, slope_1.evaluate(10)); - ASSERT_FLOAT_EQ(20, slope_1.evaluate(11)); - ASSERT_FLOAT_EQ(20, slope_1.evaluate(20)); -} -TEST(Function, Exponential) { - mbgl::ExponentialFunction<float> slope_1(/* val */ 7.5, /* z_base */ 4, /* exp_base */ 1.75, /* slope */ 2, /* min */ 7.5, /* max */ 20); - ASSERT_FLOAT_EQ(8.6428576, slope_1.evaluate(3)); // 7.5 + 1.75^(3 - 4) * 2 - ASSERT_FLOAT_EQ(9.5, slope_1.evaluate(4)); // 7.5 + 1.75^(4 - 4) * 2 - ASSERT_FLOAT_EQ(10.145751, slope_1.evaluate(4.5)); // 7.5 + 1.75^(4.5 - 4) * 2 - ASSERT_FLOAT_EQ(11, slope_1.evaluate(5)); // 7.5 + 1.75^(5 - 4) * 2 - ASSERT_FLOAT_EQ(13.625, slope_1.evaluate(6)); // 7.5 + 1.75^(6 - 4) * 2 - ASSERT_FLOAT_EQ(18.21875, slope_1.evaluate(7)); // 7.5 + 1.75^(7 - 4) * 2 - ASSERT_FLOAT_EQ(20, slope_1.evaluate(8)); // 7.5 + 1.75^(8 - 4) * 2 ==> clamped to 20 - ASSERT_FLOAT_EQ(20, slope_1.evaluate(20)); // 7.5 + 1.75^(20 - 4) * 2 ==> clamped to 20 + // Explicit constant slope in fringe regions. + mbgl::StopsFunction<float> slope_4({ { 0, 2 }, { 8, 10 } }, 1); + EXPECT_EQ(2, slope_4.evaluate(0)); + EXPECT_EQ(3, slope_4.evaluate(1)); + EXPECT_EQ(4, slope_4.evaluate(2)); + EXPECT_EQ(4.75, slope_4.evaluate(2.75)); + EXPECT_EQ(10, slope_4.evaluate(8)); } - - - |