Open matteblair opened 8 years ago
After adding an automated check for rule ambiguity and exploring the map, I've found that this problem is more pervasive than I'd thought. Here is a non-exhaustive list of ambiguous rules that I've encountered:
order
in rule lines
in layer roads:z-order
conflicts with layer roads:highway
order
in rule lines
in layer roads:z-order
conflicts with layer roads:path
order
in rule lines
in layer roads:z-order
conflicts with layer roads:track
sprite
in rule icons
in layer pois_and_landuse_labels:has-name:station-train-subway
conflicts with layer pois_and_landuse_labels:has-name:direct-match
visible
in rule icons
in layer pois_and_landuse_labels:has-name:direct-match
conflicts with layer pois_and_landuse_labels:has-name:bank-early
visible
in rule text
in layer pois_and_landuse_labels:has-name:default-label-text
conflicts with layer pois_and_landuse_labels:has-name:bank-early
outline:color
in rule lines
in layer roads:path:in_park
conflicts with layer roads:path:pedestrian
color
in rule polygons
in layer buildings:in_university
conflicts with layer buildings:extrude
color
in rule polygons
in layer buildings:in_hospital
conflicts with layer buildings:extrude
color
in rule polygons
in layer buildings:in_park
conflicts with layer buildings:extrude
visible
in rule icons
in layer pois_and_landuse_labels:has-name:direct-match
conflicts with layer pois_and_landuse_labels:has-name:atm-early
visible
in rule text
in layer pois_and_landuse_labels:has-name:default-label-text
conflicts with layer pois_and_landuse_labels:has-name:atm-early
sprite
in rule icons
in layer pois_and_landuse_labels:has-name:icons:mosque
conflicts with layer pois_and_landuse_labels:has-name:icons:spiritual-center
font:fill
in rule text
in layer roads:service_road:labels-service_road2
conflicts with layer roads:service_road:labels-service_road
font:size
in rule text
in layer roads:service_road:labels-service_road2
conflicts with layer roads:service_road:labels-service_road
sprite
in rule icons
in layer pois_and_landuse_labels:has-name:icons:buddhist
conflicts with layer pois_and_landuse_labels:has-name:icons:spiritual-center
sprite
in rule icons
in layer pois_and_landuse_labels:has-name:icons:synagogue
conflicts with layer pois_and_landuse_labels:has-name:icons:spiritual-center
sprite
in rule icons
in layer pois_and_landuse_labels:has-name:icons:church
conflicts with layer pois_and_landuse_labels:has-name:icons:spiritual-center
outline:color
in rule lines
in layer roads:path:in_cemetery_garden
conflicts with layer roads:path:in_park
visible
in rule icons
in layer pois_and_landuse_labels:has-name:direct-match
conflicts with layer pois_and_landuse_labels:has-name:parking-labels-early
visible
in rule text
in layer pois_and_landuse_labels:has-name:default-label-text
conflicts with layer pois_and_landuse_labels:has-name:parking-labels-early
color
in rule lines
in layer roads:major_road:secondary
conflicts with layer roads:major_road:tunnel
outline:color
in rule lines
in layer roads:major_road:secondary
conflicts with layer roads:major_road:tunnel
color
in rule lines
in layer roads:major_road:tunnel
conflicts with layer roads:major_road:trunk_primary
outline:color
in rule lines
in layer roads:major_road:tunnel
conflicts with layer roads:major_road:trunk_primary
visible
in rule icons
in layer pois_and_landuse_labels:has-name:direct-match
conflicts with layer pois_and_landuse_labels:has-name:university-poi
visible
in rule text
in layer pois_and_landuse_labels:has-name:default-label-text
conflicts with layer pois_and_landuse_labels:has-name:university-poi
order
in rule lines
in layer roads:z-order
conflicts with layer roads:aerialway
cap
in rule lines
in layer roads:minor_road:minor_road_bridge
conflicts with layer roads:minor_road:round
order
in rule lines
in layer roads:highway:tunnel
conflicts with layer roads:highway:not_link
outline:color
in rule lines
in layer roads:path:in_university
conflicts with layer roads:path:pedestrian
outline:color
in rule lines
in layer roads:major_road:tertiary
conflicts with layer roads:major_road:link
outline:color
in rule lines
in layer roads:path:in_university
conflicts with layer roads:path:bridge
order
in rule lines
in layer roads:minor_road:tunnel
conflicts with layer roads:minor_road:early
color
in rule lines
in layer roads:major_road:tertiary:in_park
conflicts with layer roads:major_road:tertiary:routes
outline:color
in rule lines
in layer roads:major_road:tertiary:in_park
conflicts with layer roads:major_road:tertiary:routes
outline:color
in rule lines
in layer roads:major_road:secondary:in_park
conflicts with layer roads:major_road:secondary:routes
color
in rule lines
in layer roads:major_road:tertiary
conflicts with layer roads:major_road:tunnel
outline:color
in rule lines
in layer roads:major_road:tertiary
conflicts with layer roads:major_road:tunnel
color
in rule dots2
in layer landuse:tier2:nature_reserve
conflicts with layer landuse:tier2:conservation
outline:color
in rule lines
in layer roads:path:bridge
conflicts with layer roads:path:pedestrian
order
in rule dots2
in layer landuse:tier2:parks-and-national-forests-not-national-park
conflicts with layer landuse:tier1:national_park
order
in rule lines
in layer roads:z-order
conflicts with layer roads:airport-lines
outline:color
in rule lines
in layer roads:service_road:in_cemetery_garden
conflicts with layer roads:service_road:in_park
color
in rule polygons
in layer buildings:in_retail
conflicts with layer buildings:extrude
priority
in rule text
in layer places:populated-places
conflicts with layer places:region
order
in rule lines
in layer roads:z-order
conflicts with layer roads:natural_earth_highways
priority
in rule text
in layer places:populated-places
conflicts with layer places:region-z6
priority
in rule text
in layer places:populated-places
conflicts with layer places:region-z5
priority
in rule text
in layer places:populated-places
conflicts with layer places:country-z4
priority
in rule text
in layer places:populated-places
conflicts with layer places:region-z4
priority
in rule text
in layer places:populated-places
conflicts with layer places:country-z3
priority
in rule text
in layer places:populated-places
conflicts with layer places:country-z2
To me this indicates that it is far easier to write ambiguous rules than we had anticipated. Short of changing the stylesheet syntax, one thing that we can do to improve the situation is to enforce that tangram resolves these conflicts in a consistent way. Even if conflicts are resolved in a completely arbitrary way, this would prevent the problem we have now where styles authored in one renderer can be validly interpreted differently in another renderer.
@bcamper I now think that addressing this should be the highest priority task for both tangram implementations right now. Let's work together on a way to resolve these conflicts consistently!
Yes, I think we need to work within the current syntax for now, as it would be a much bigger refactor (and a syntax change I don't want to rush) to change that behavior.
I will look into the easiest way to accomplish this in JS. Lexical sort by layer name may be the most straightforward (which doesn't need the fully qualified layer name, because this only needs to be resolved for rules at the same depth, right?).
On Sat, Dec 5, 2015 at 4:15 PM, Matt Blair notifications@github.com wrote:
After adding an automated check for rule ambiguity and exploring the map, I've found that this problem is more pervasive than I'd thought. Here is a non-exhaustive list of ambiguous rules that I've encountered:
- order in rule lines in layer roads:z-order conflicts with layer roads:highway
- order in rule lines in layer roads:z-order conflicts with layer roads:path
- order in rule lines in layer roads:z-order conflicts with layer roads:track
- sprite in rule icons in layer pois_and_landuse_labels:has-name:station-train-subway conflicts with layer pois_and_landuse_labels:has-name:direct-match
- visible in rule icons in layer pois_and_landuse_labels:has-name:direct-match conflicts with layer pois_and_landuse_labels:has-name:bank-early
- visible in rule text in layer pois_and_landuse_labels:has-name:default-label-text conflicts with layer pois_and_landuse_labels:has-name:bank-early
- outline:color in rule lines in layer roads:path:in_park conflicts with layer roads:path:pedestrian
- color in rule polygons in layer buildings:in_university conflicts with layer buildings:extrude
- color in rule polygons in layer buildings:in_hospital conflicts with layer buildings:extrude
- color in rule polygons in layer buildings:in_park conflicts with layer buildings:extrude
- visible in rule icons in layer pois_and_landuse_labels:has-name:direct-match conflicts with layer pois_and_landuse_labels:has-name:atm-early
- visible in rule text in layer pois_and_landuse_labels:has-name:default-label-text conflicts with layer pois_and_landuse_labels:has-name:atm-early
- sprite in rule icons in layer pois_and_landuse_labels:has-name:icons:mosque conflicts with layer pois_and_landuse_labels:has-name:icons:spiritual-center
- font:fill in rule text in layer roads:service_road:labels-service_road2 conflicts with layer roads:service_road:labels-service_road
- font:size in rule text in layer roads:service_road:labels-service_road2 conflicts with layer roads:service_road:labels-service_road
- sprite in rule icons in layer pois_and_landuse_labels:has-name:icons:buddhist conflicts with layer pois_and_landuse_labels:has-name:icons:spiritual-center
- sprite in rule icons in layer pois_and_landuse_labels:has-name:icons:synagogue conflicts with layer pois_and_landuse_labels:has-name:icons:spiritual-center
- sprite in rule icons in layer pois_and_landuse_labels:has-name:icons:church conflicts with layer pois_and_landuse_labels:has-name:icons:spiritual-center
- outline:color in rule lines in layer roads:path:in_cemetery_garden conflicts with layer roads:path:in_park
- visible in rule icons in layer pois_and_landuse_labels:has-name:direct-match conflicts with layer pois_and_landuse_labels:has-name:parking-labels-early
- visible in rule text in layer pois_and_landuse_labels:has-name:default-label-text conflicts with layer pois_and_landuse_labels:has-name:parking-labels-early
- color in rule lines in layer roads:major_road:secondary conflicts with layer roads:major_road:tunnel
- outline:color in rule lines in layer roads:major_road:secondary conflicts with layer roads:major_road:tunnel
- color in rule lines in layer roads:major_road:tunnel conflicts with layer roads:major_road:trunk_primary
- outline:color in rule lines in layer roads:major_road:tunnel conflicts with layer roads:major_road:trunk_primary
- visible in rule icons in layer pois_and_landuse_labels:has-name:direct-match conflicts with layer pois_and_landuse_labels:has-name:university-poi
- visible in rule text in layer pois_and_landuse_labels:has-name:default-label-text conflicts with layer pois_and_landuse_labels:has-name:university-poi
- order in rule lines in layer roads:z-order conflicts with layer roads:aerialway
- cap in rule lines in layer roads:minor_road:minor_road_bridge conflicts with layer roads:minor_road:round
- order in rule lines in layer roads:highway:tunnel conflicts with layer roads:highway:not_link
- outline:color in rule lines in layer roads:path:in_university conflicts with layer roads:path:pedestrian
- outline:color in rule lines in layer roads:major_road:tertiary conflicts with layer roads:major_road:link
- outline:color in rule lines in layer roads:path:in_university conflicts with layer roads:path:bridge
- order in rule lines in layer roads:minor_road:tunnel conflicts with layer roads:minor_road:early
- color in rule lines in layer roads:major_road:tertiary:in_park conflicts with layer roads:major_road:tertiary:routes
- outline:color in rule lines in layer roads:major_road:tertiary:in_park conflicts with layer roads:major_road:tertiary:routes
- outline:color in rule lines in layer roads:major_road:secondary:in_park conflicts with layer roads:major_road:secondary:routes
- color in rule lines in layer roads:major_road:tertiary conflicts with layer roads:major_road:tunnel
- outline:color in rule lines in layer roads:major_road:tertiary conflicts with layer roads:major_road:tunnel
- color in rule dots2 in layer landuse:tier2:nature_reserve conflicts with layer landuse:tier2:conservation
- outline:color in rule lines in layer roads:path:bridge conflicts with layer roads:path:pedestrian
- order in rule dots2 in layer landuse:tier2:parks-and-national-forests-not-national-park conflicts with layer landuse:tier1:national_park
- order in rule lines in layer roads:z-order conflicts with layer roads:airport-lines
- outline:color in rule lines in layer roads:service_road:in_cemetery_garden conflicts with layer roads:service_road:in_park
- color in rule polygons in layer buildings:in_retail conflicts with layer buildings:extrude
- priority in rule text in layer places:populated-places conflicts with layer places:region
- order in rule lines in layer roads:z-order conflicts with layer roads:natural_earth_highways
- priority in rule text in layer places:populated-places conflicts with layer places:region-z6
- priority in rule text in layer places:populated-places conflicts with layer places:region-z5
- priority in rule text in layer places:populated-places conflicts with layer places:country-z4
- priority in rule text in layer places:populated-places conflicts with layer places:region-z4
- priority in rule text in layer places:populated-places conflicts with layer places:country-z3
- priority in rule text in layer places:populated-places conflicts with layer places:country-z2
To me this indicates that it is far easier to write ambiguous rules than we had anticipated. Short of changing the stylesheet syntax, one thing that we can do to improve the situation is to enforce that tangram resolves these conflicts in a consistent way. Even if conflicts are resolved in a completely arbitrary way, this would prevent the problem we have now where styles authored in one renderer can be validly interpreted differently in another renderer.
@bcamper https://github.com/bcamper I now think that addressing this should be the highest priority task for both tangram implementations right now. Let's work together on a way to resolve these conflicts consistently!
— Reply to this email directly or view it on GitHub https://github.com/tangrams/eraser-map/issues/112#issuecomment-162248557 .
Cool, thanks! If we were going to use layer name, I think it would have to be the fully-qualified layer name; two "sibling" layers could both have sublayers with the same name and conflicting rules.
Could it be the relative order within the scene file (versus layer name, which is also random)?
Sent from my handsful device.
On Dec 5, 2015, at 13:44, Matt Blair notifications@github.com wrote:
Cool, thanks! If we were going to use layer name, I think it would have to be the fully-qualified layer name; two "sibling" layers could both have sublayers with the same name and conflicting rules.
― Reply to this email directly or view it on GitHub.
I am not sure relative order will work because yaml parsing of these layers is not deterministic, at least on the es side. On Dec 5, 2015 7:42 PM, "Nathaniel V. KELSO" notifications@github.com wrote:
Could it be the relative order within the scene file (versus layer name, which is also random)?
Sent from my handsful device.
On Dec 5, 2015, at 13:44, Matt Blair notifications@github.com wrote:
Cool, thanks! If we were going to use layer name, I think it would have to be the fully-qualified layer name; two "sibling" layers could both have sublayers with the same name and conflicting rules.
― Reply to this email directly or view it on GitHub.
— Reply to this email directly or view it on GitHub https://github.com/tangrams/eraser-map/issues/112#issuecomment-162260286 .
And I agree with Matt, lexical order of fully qualified layer names will be required. On Dec 5, 2015 7:44 PM, "Varun Talwar" varun@mapzen.com wrote:
I am not sure relative order will work because yaml parsing of these layers is not deterministic, at least on the es side. On Dec 5, 2015 7:42 PM, "Nathaniel V. KELSO" notifications@github.com wrote:
Could it be the relative order within the scene file (versus layer name, which is also random)?
Sent from my handsful device.
On Dec 5, 2015, at 13:44, Matt Blair notifications@github.com wrote:
Cool, thanks! If we were going to use layer name, I think it would have to be the fully-qualified layer name; two "sibling" layers could both have sublayers with the same name and conflicting rules.
― Reply to this email directly or view it on GitHub.
— Reply to this email directly or view it on GitHub https://github.com/tangrams/eraser-map/issues/112#issuecomment-162260286 .
Right, unfortunately it is not possible to determine order from a YAML mapping (or JS object/hash either for that matter). The use of lexical manner is not really because it's "logical", it's so that it's consistent and predictable. This is still a rule behavior that we want to avoid (but thinking about syntax alternatives is a bigger topic that can't be done on a short timeline).
I will have a working version of lexical rule sort in JS shortly.
On Saturday, December 5, 2015, Varun notifications@github.com wrote:
I am not sure relative order will work because yaml parsing of these layers is not deterministic, at least on the es side. On Dec 5, 2015 7:42 PM, "Nathaniel V. KELSO" <notifications@github.com javascript:_e(%7B%7D,'cvml','notifications@github.com');> wrote:
Could it be the relative order within the scene file (versus layer name, which is also random)?
Sent from my handsful device.
On Dec 5, 2015, at 13:44, Matt Blair <notifications@github.com javascript:_e(%7B%7D,'cvml','notifications@github.com');> wrote:
Cool, thanks! If we were going to use layer name, I think it would have to be the fully-qualified layer name; two "sibling" layers could both have sublayers with the same name and conflicting rules.
― Reply to this email directly or view it on GitHub.
— Reply to this email directly or view it on GitHub < https://github.com/tangrams/eraser-map/issues/112#issuecomment-162260286> .
— Reply to this email directly or view it on GitHub https://github.com/tangrams/eraser-map/issues/112#issuecomment-162260376 .
In tangram-es it would be pretty easy to resolve conflicts by order within the file (yaml-cpp provides positional information about each node). This seems like it would be a more intuitive solution than sorting by layer name, but it sounds like this might not be technically possible in tangram-js?
Ah, didn't know that was possible in the C++ yaml parser!
Unfortunately it is not currently possible with the JS yaml parser, because it uses plain JS objects, and there is no guaranteed order for those keys. So I think lexical order is the only practical solution for now (though I agree it isn't the most intuitive and I initially wasn't so into the idea.. just don't see an alternative).
I have an idea to try forking js-yaml and making it use ES6's native Map, which does provide a way to iterate keys in insertion order. But, I don't know the scope of that project, it could be quite large and would necessitate a major API change for YAML access, (and forking cost...) so it will have to wait for the future.
On Saturday, December 5, 2015, Matt Blair notifications@github.com wrote:
In tangram-es it would be pretty easy to resolve conflicts by order within the file (yaml-cpp provides positional information about each node). This seems like it would be a more intuitive solution than sorting by layer name, but it sounds like this might not be technically possible in tangram-js?
— Reply to this email directly or view it on GitHub https://github.com/tangrams/eraser-map/issues/112#issuecomment-162262196 .
So with lexical sort, is the preferred behavior that first ('rule-a') or last ('rule-z') wins? :)
No preference here. I'd try both on the eraser-map style and see if one produces noticeably fewer differences.
There are probably better ways to solve this, but also occurred to me that we could have an optional priority
set on the layer to allow precedence control where needed.
BTW I looked at how CSS resolves conflicts like this, and later selectors overwrite earlier ones. As discussed that would be the preferred behavior here if it was easy to implement (unfortunately I still don't think it is, though I started taking a look at js-yaml for future functionality).
Of course, for CSS like Tangram, it's preferable not to have conflicting rules in the the first place, but we may need new or revised syntax since it looks like it's easy to write them accidentally. Though having live Tangram Play warnings for this could help a lot :)
Just having some well-defined method of resolving conflicts will make a world of difference here, refinements on that method (priority, document order, etc) will be nice enhancements for later.
This raises a question about the documentation/specification: Does this layer-name-resolution behavior become part of the specified behavior for tangram? Or do we leave it officially unspecified to allow for possibly changing the resolution behavior in the future? (I lean towards the latter)
@blair1618 Can you please run this analysis again now that the stylesheet has been updated, and Tangram has been updated?
The layers pois_and_landuse_labels:has-name:default-label-text and pois_and_landuse_labels:has-name:bank-early* can both match the same feature and assign the
visible
parameter to thetext
rule with different values at the same depth.There is no way for tangram to determine which rule should "win" in cases like this and therefore it is totally valid for an implementation to choose either value at random. This is a known limitation of the stylesheet syntax. To get well-defined behavior, some of these rules will have to be removed or re-structured such that they don't collide.
*= The nearby layers 'office-early', 'post-office-early', 'atm-early', 'memorial-early', and 'parking-labels-early' will almost certainly have this problem as well.