Composite ("zoom-and-property") functions behave differently in mapbox-gl-native and mapbox-gl-js: part of this is intentional and part is a bug.
Considering the following function:
"fill-extrusion-height": {
"type": "exponential",
"property": "height",
"stops": [
[{ "zoom": 15, "value": 0 }, 0],
[{ "zoom": 15, "value": 600 }, 0],
[{ "zoom": 15.2, "value": 0 }, 0],
[{ "zoom": 15.2, "value": 600 },600]
]
}
In mapbox-gl-js, this would cause fill-extrusions to rise from flat at z15 to property-based heights at z15.2, and then maintain that height at all higher zooms.
In mapbox-gl-native, since PaintPropertyBinders are evaluated at layout time at integer zoom levels, we won't be able to assign different slopes to z15-15.2 and 15.2-16, and it will, necessarily, behave differently.
However, current behavior is as such:
- from z15 to z15.2, fill-extrusions grow from flat to identity heights, as expected
- from z15.2 to z16 they continue to grow upward along that same slope and become 5x too high
- at z16 and onward they reset to flat
When I add another set of stops,
[{ "zoom": 22, "value": 0 }, 0],
[{ "zoom": 22, "value": 600 }, 600]
the above behavior only changes in that at z16 they reset to their intended property-based identity height and maintain that height to z22.
This is an issue with the logic in coveringRanges. I believe what needs to happen is:
- the
upper_bound line should look for zoom + 1
- if a stop chosen as one of the bounds is outside of the range of this integer zoom (n-n.99), and there is another stop between said outer stop and the other bounds stop, since we know that inside stop would otherwise be ignored altogether, then we need to insert an artificial stop at the exact outer bound of the zoom and, for its values, interpolate between the chosen outer bounds stop and the inner (otherwise ignored) stop.
The following shows the behavior with the above function for a feature with value=600: pink is how mapbox-gl-js behaves (and is the literal interpretation of the function stops), green is how mbgl-native currently works, yellow is how mbgl-native would work if only changing the upper_bound here to (zoom + 1), and blue is how I believe it should work, with artificial stops.

Same below, but for a function specified as
"fill-extrusion-height": {
"type": "exponential",
"property": "height",
"stops": [
[{ "zoom": 15, "value": 0 }, 0],
[{ "zoom": 15, "value": 600 }, 0],
[{ "zoom": 15.2, "value": 0 }, 0],
[{ "zoom": 15.2, "value": 600 },300],
[{ "zoom": 22, "value": 0 }, 0],
[{ "zoom": 22, "value": 600 }, 600]
]
}

Composite ("zoom-and-property") functions behave differently in mapbox-gl-native and mapbox-gl-js: part of this is intentional and part is a bug.
Considering the following function:
In mapbox-gl-js, this would cause fill-extrusions to rise from flat at z15 to property-based heights at z15.2, and then maintain that height at all higher zooms.
In mapbox-gl-native, since PaintPropertyBinders are evaluated at layout time at integer zoom levels, we won't be able to assign different slopes to z15-15.2 and 15.2-16, and it will, necessarily, behave differently.
However, current behavior is as such:
When I add another set of stops,
the above behavior only changes in that at z16 they reset to their intended property-based identity height and maintain that height to z22.
This is an issue with the logic in
coveringRanges. I believe what needs to happen is:upper_boundline should look forzoom + 1The following shows the behavior with the above function for a feature with value=600: pink is how mapbox-gl-js behaves (and is the literal interpretation of the function stops), green is how mbgl-native currently works, yellow is how mbgl-native would work if only changing the

upper_boundhere to(zoom + 1), and blue is how I believe it should work, with artificial stops.Same below, but for a function specified as