diff --git a/bin/style.js b/bin/style.js index 3046b2d80..7d2b3557d 100644 --- a/bin/style.js +++ b/bin/style.js @@ -106,7 +106,8 @@ module.exports = { "text_field": "name", "path": "horizontal", "font": "Open Sans, Jomolhari, Siyam Rupali, Alef, Arial Unicode MS", - "fontSize": 18 + "fontSize": 18, + "alwaysVisible": true }, "road_label": { "source": "streets", diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp index 11b5a8f80..42bc3ca40 100644 --- a/include/llmr/style/properties.hpp +++ b/include/llmr/style/properties.hpp @@ -121,6 +121,8 @@ struct TextClass { Color halo = {{ 1, 1, 1, 0.75 }}; FunctionProperty haloRadius = 0.25f; FunctionProperty size = 12.0f; + FunctionProperty rotate = 0.0f; + FunctionProperty alwaysVisible = false; }; struct TextProperties { @@ -129,6 +131,8 @@ struct TextProperties { Color halo = {{ 1, 1, 1, 0.75 }}; float haloRadius = 0.25f; float size = 12.0f; + float rotate = 0.0f; + bool alwaysVisible = false; }; struct BackgroundClass { diff --git a/include/llmr/text/collision.hpp b/include/llmr/text/collision.hpp index c837738d2..364a255a9 100644 --- a/include/llmr/text/collision.hpp +++ b/include/llmr/text/collision.hpp @@ -14,7 +14,7 @@ public: PlacementProperty place(const PlacedGlyphs &boxes, const CollisionAnchor &anchor, float minPlacementScale, float maxPlacementScale, - float padding, bool horizontal); + float padding, bool horizontal, bool alwaysVisible); float getPlacementScale(const GlyphBoxes &glyphs, float minPlacementScale, float maxPlacementScale, float pad); PlacementRange getPlacementRange(const GlyphBoxes &glyphs, diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index d4e380461..344d2eb0b 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -493,8 +493,7 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons matrix::rotate_z(exMatrix, exMatrix, transform.getAngle()); } - // var rotate = layerStyle.rotate || 0; - float rotate = 0.0f; + const float rotate = properties.rotate; if (rotate != 0.0f) { matrix::rotate_z(exMatrix, exMatrix, rotate); } diff --git a/src/style/resources.cpp b/src/style/resources.cpp index 5d510ce31..3c0d9362a 100644 --- a/src/style/resources.cpp +++ b/src/style/resources.cpp @@ -3,5 +3,5 @@ using namespace llmr; -const unsigned char resources::style[] = R"JSON({"buckets":{"water":{"source":"streets","layer":"water","type":"fill"},"road_large":{"source":"streets","layer":"road","field":"class","value":["motorway","main"],"type":"line","cap":"round","join":"round"},"road_regular":{"source":"streets","layer":"road","field":"class","value":"street","type":"line","cap":"round","join":"round"},"road_limited":{"source":"streets","layer":"road","field":"class","value":"street_limited","type":"line","cap":"round","join":"round"},"park":{"source":"streets","layer":"landuse","field":"class","value":"park","type":"fill"},"wood":{"source":"streets","layer":"landuse","field":"class","value":"wood","type":"fill"},"school":{"source":"streets","layer":"landuse","field":"class","value":"school","type":"fill"},"cemetery":{"source":"streets","layer":"landuse","field":"class","value":"cemetery","type":"fill"},"industrial":{"source":"streets","layer":"landuse","field":"class","value":"industrial","type":"fill"},"building":{"source":"streets","layer":"building","type":"fill"},"alcohol_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Alcohol"],"type":"point"},"cafe_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Cafe"],"type":"point"},"embassy_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Embassy"],"type":"point"},"park_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Park"],"type":"point"},"restaurant_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Restaurant"],"type":"point"},"country_label":{"source":"streets","type":"text","layer":"country_label","feature_type":"point","padding":10,"text_field":"name","path":"horizontal","font":"Open Sans, Jomolhari, Siyam Rupali, Alef, Arial Unicode MS","fontSize":16},"place_label":{"source":"streets","type":"text","layer":"place_label","feature_type":"point","text_field":"name","path":"horizontal","font":"Open Sans, Jomolhari, Siyam Rupali, Alef, Arial Unicode MS","fontSize":18},"road_label":{"source":"streets","type":"text","layer":"road_label","feature_type":"line","text_field":"name","path":"curve","font":"Open Sans, Jomolhari, Siyam Rupali, Alef, Arial Unicode MS","fontSize":12,"textMinDistance":250,"maxAngleDelta":1.04}},"sprite":"img/maki-sprite","constants":{"park":"#c8df9f","text":"#000000"},"structure":[{"name":"park","bucket":"park"},{"name":"wood","bucket":"wood"},{"name":"water","bucket":"water"},{"name":"building","bucket":"building"},{"name":"road_limited","bucket":"road_limited"},{"name":"road_regular","bucket":"road_regular"},{"name":"road_large","bucket":"road_large"},{"name":"alcohol_poi","bucket":"alcohol_poi"},{"name":"cafe_poi","bucket":"cafe_poi"},{"name":"embassy_poi","bucket":"embassy_poi"},{"name":"park_poi","bucket":"park_poi"},{"name":"restaurant_poi","bucket":"restaurant_poi"},{"name":"country_label","bucket":"country_label"},{"name":"place_label","bucket":"place_label"},{"name":"road_label","bucket":"road_label"}],"classes":[{"name":"default","layers":{"background":{"type":"background","color":"#FFFFFF"},"park":{"type":"fill","color":"park","antialias":true,"image":"park"},"wood":{"type":"fill","color":"#33AA66","antialias":true,"opacity":0.1},"water":{"type":"fill","color":"#bae0e9","stroke":"#73b6e6","antialias":true,"image":"water_etsy"},"building":{"type":"fill","color":"#000000","antialias":true,"opacity":["linear",13,0,0.1,0,0.1]},"road_limited":{"type":"line","color":"#BBBBBB","width":["stops",{"z":0,"val":1},{"z":30,"val":1}]},"road_regular":{"type":"line","color":"#999999","width":["stops",{"z":0,"val":0.5},{"z":13,"val":0.5},{"z":16,"val":2},{"z":20,"val":16},{"z":30,"val":16}]},"road_large":{"type":"line","color":"#666666","width":["stops",{"z":0,"val":0.5},{"z":11,"val":0.5},{"z":13,"val":1},{"z":16,"val":4},{"z":20,"val":32},{"z":30,"val":32}]},"alcohol_poi":{"type":"point","color":"#cccccc","size":18,"image":"alcohol-shop","opacity":["linear",15,0,1,0,0.75]},"cafe_poi":{"type":"point","color":"#cccccc","size":18,"image":"cafe","opacity":["linear",15,0,1,0,0.75]},"embassy_poi":{"type":"point","color":"#cccccc","size":18,"image":"embassy","opacity":["linear",15,0,1,0,0.75]},"park_poi":{"type":"point","color":"#cccccc","size":18,"image":"park","opacity":["linear",15,0,1,0,0.75]},"restaurant_poi":{"type":"point","color":"#cccccc","size":18,"image":"restaurant","opacity":["linear",15,0,1,0,0.75]},"country_label":{"type":"text","stroke":[1,1,1,0.7],"color":"text","size":16},"place_label":{"type":"text","stroke":[1,1,1,0.7],"color":"text","size":18},"road_label":{"type":"text","color":"text","stroke":[1,1,1,0.7],"size":["exponential",14,8,1,8,12]}}}]})JSON"; +const unsigned char resources::style[] = R"JSON({"buckets":{"water":{"source":"streets","layer":"water","type":"fill"},"road_large":{"source":"streets","layer":"road","field":"class","value":["motorway","main"],"type":"line","cap":"round","join":"round"},"road_regular":{"source":"streets","layer":"road","field":"class","value":"street","type":"line","cap":"round","join":"round"},"road_limited":{"source":"streets","layer":"road","field":"class","value":"street_limited","type":"line","cap":"round","join":"round"},"park":{"source":"streets","layer":"landuse","field":"class","value":"park","type":"fill"},"wood":{"source":"streets","layer":"landuse","field":"class","value":"wood","type":"fill"},"school":{"source":"streets","layer":"landuse","field":"class","value":"school","type":"fill"},"cemetery":{"source":"streets","layer":"landuse","field":"class","value":"cemetery","type":"fill"},"industrial":{"source":"streets","layer":"landuse","field":"class","value":"industrial","type":"fill"},"building":{"source":"streets","layer":"building","type":"fill"},"alcohol_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Alcohol"],"type":"point"},"cafe_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Cafe"],"type":"point"},"embassy_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Embassy"],"type":"point"},"park_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Park"],"type":"point"},"restaurant_poi":{"source":"streets","layer":"poi_label","field":"type","value":["Restaurant"],"type":"point"},"country_label":{"source":"streets","type":"text","layer":"country_label","feature_type":"point","padding":10,"text_field":"name","path":"horizontal","font":"Open Sans, Jomolhari, Siyam Rupali, Alef, Arial Unicode MS","fontSize":16},"place_label":{"source":"streets","type":"text","layer":"place_label","feature_type":"point","text_field":"name","path":"horizontal","font":"Open Sans, Jomolhari, Siyam Rupali, Alef, Arial Unicode MS","fontSize":18,"alwaysVisible":true},"road_label":{"source":"streets","type":"text","layer":"road_label","feature_type":"line","text_field":"name","path":"curve","font":"Open Sans, Jomolhari, Siyam Rupali, Alef, Arial Unicode MS","fontSize":12,"textMinDistance":250,"maxAngleDelta":1.04}},"sprite":"img/maki-sprite","constants":{"park":"#c8df9f","text":"#000000"},"structure":[{"name":"park","bucket":"park"},{"name":"wood","bucket":"wood"},{"name":"water","bucket":"water"},{"name":"building","bucket":"building"},{"name":"road_limited","bucket":"road_limited"},{"name":"road_regular","bucket":"road_regular"},{"name":"road_large","bucket":"road_large"},{"name":"alcohol_poi","bucket":"alcohol_poi"},{"name":"cafe_poi","bucket":"cafe_poi"},{"name":"embassy_poi","bucket":"embassy_poi"},{"name":"park_poi","bucket":"park_poi"},{"name":"restaurant_poi","bucket":"restaurant_poi"},{"name":"country_label","bucket":"country_label"},{"name":"place_label","bucket":"place_label"},{"name":"road_label","bucket":"road_label"}],"classes":[{"name":"default","layers":{"background":{"type":"background","color":"#FFFFFF"},"park":{"type":"fill","color":"park","antialias":true,"image":"park"},"wood":{"type":"fill","color":"#33AA66","antialias":true,"opacity":0.1},"water":{"type":"fill","color":"#bae0e9","stroke":"#73b6e6","antialias":true,"image":"water_etsy"},"building":{"type":"fill","color":"#000000","antialias":true,"opacity":["linear",13,0,0.1,0,0.1]},"road_limited":{"type":"line","color":"#BBBBBB","width":["stops",{"z":0,"val":1},{"z":30,"val":1}]},"road_regular":{"type":"line","color":"#999999","width":["stops",{"z":0,"val":0.5},{"z":13,"val":0.5},{"z":16,"val":2},{"z":20,"val":16},{"z":30,"val":16}]},"road_large":{"type":"line","color":"#666666","width":["stops",{"z":0,"val":0.5},{"z":11,"val":0.5},{"z":13,"val":1},{"z":16,"val":4},{"z":20,"val":32},{"z":30,"val":32}]},"alcohol_poi":{"type":"point","color":"#cccccc","size":18,"image":"alcohol-shop","opacity":["linear",15,0,1,0,0.75]},"cafe_poi":{"type":"point","color":"#cccccc","size":18,"image":"cafe","opacity":["linear",15,0,1,0,0.75]},"embassy_poi":{"type":"point","color":"#cccccc","size":18,"image":"embassy","opacity":["linear",15,0,1,0,0.75]},"park_poi":{"type":"point","color":"#cccccc","size":18,"image":"park","opacity":["linear",15,0,1,0,0.75]},"restaurant_poi":{"type":"point","color":"#cccccc","size":18,"image":"restaurant","opacity":["linear",15,0,1,0,0.75]},"country_label":{"type":"text","stroke":[1,1,1,0.7],"color":"text","size":16},"place_label":{"type":"text","stroke":[1,1,1,0.7],"color":"text","size":18},"road_label":{"type":"text","color":"text","stroke":[1,1,1,0.7],"size":["exponential",14,8,1,8,12]}}}]})JSON"; const unsigned long resources::style_size = sizeof(resources::style); diff --git a/src/style/style.cpp b/src/style/style.cpp index 1bce72d76..5367da0bd 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -88,6 +88,8 @@ void Style::cascade(float z) { text.size = layer.size(z); text.halo = layer.halo; text.haloRadius = layer.haloRadius(z); + text.rotate = layer.rotate(z); + text.alwaysVisible = layer.alwaysVisible(z); } // Cascade background diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 17a1f6b81..cc2eccda6 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -529,6 +529,14 @@ TextClass StyleParser::parseTextClass(JSVal value) { klass.size = parseFloatFunction(value["size"]); } + if (value.HasMember("rotate")) { + klass.rotate = parseFloatFunction(value["rotate"]); + } + + if (value.HasMember("alwaysVisible")) { + klass.alwaysVisible = parseBoolFunction(value["alwaysVisible"]); + } + return klass; } diff --git a/src/text/collision.cpp b/src/text/collision.cpp index e02dfe697..ce09da460 100644 --- a/src/text/collision.cpp +++ b/src/text/collision.cpp @@ -74,7 +74,7 @@ PlacementProperty Collision::place(const PlacedGlyphs &placed_glyphs, const CollisionAnchor &anchor, float minPlacementScale, float maxPlacementScale, float padding, - bool horizontal) { + bool horizontal, bool alwaysVisible) { float minScale = std::numeric_limits::infinity(); for (const PlacedGlyph &placed_glyph : placed_glyphs) { @@ -111,8 +111,9 @@ PlacementProperty Collision::place(const PlacedGlyphs &placed_glyphs, // Calculate the minimum scale the entire label can be shown without // collisions - float scale = getPlacementScale(glyphs, minPlacementScale, - maxPlacementScale, padding); + float scale = alwaysVisible ? minPlacementScale + : getPlacementScale(glyphs, minPlacementScale, + maxPlacementScale, padding); // Return if the label can never be placed without collision if (scale < 0 || scale == std::numeric_limits::infinity()) { diff --git a/src/text/placement.cpp b/src/text/placement.cpp index 852236b71..88c947275 100644 --- a/src/text/placement.cpp +++ b/src/text/placement.cpp @@ -304,7 +304,7 @@ void Placement::addFeature(TextBucket& bucket, line, maxAngleDelta, rotate); PlacementProperty place = collision.place(glyphs, anchor, anchor.scale, maxPlacementScale, - padding, horizontal); + padding, horizontal, info.alwaysVisible); if (place) { bucket.addGlyphs(glyphs, place.zoom, place.rotationRange, zoom - zOffset);