Closed cafesilencio closed 4 years ago
referenced ticket: #9694
FYI, this issue was filed in the GL JS repository with the understanding that the gradient stop precision used by gl-native is based on the precision used in GL JS.
/cc: @tmpsantos per the last comment.
Thanks for the details and referring to #9694! Yes, you are correct in the asumption that both gl-js and gl-native are matching as those changes have been cross-ported.
Short answer: You're feeding wrong values to the gradient expression. On one hand there are distances that are calculated using harvesine formulas, which gets the distance between two locations on a sphere accounting for curvature, and mapbox-gl which calculates distances in tile space post-projection.
Concerning the remark about precision, we have provided a vast increase in the work of #9694 as well as an option to use hard transition, which you should be able to leverage. What you are dealing with isn't exactly a lack of precision, it is there, but you are introducing an error by comparing the wrong values. We are providing precision close to pixel accuracy without any dependency on the length of the route line, which should fit your use case. Without going into too much detail, we're tiling the gradient data instead of using a global one, where data would previously gradually degrade as either you zoomed in, or increased the distance of the line. I would also refer to the turf documentation concerning the details of the function you are using.
Now to fix this error, you need to to match the way mapbox-gl calculates line distances before it uses it to infer its gradient. You could do that by updating the way you are calculating the line length to match the way we do it instead of using turf, first the two projection functions we use (EPSG:3857):
function projectX(x) {
return x / 360 + 0.5;
}
function projectY(y) {
var sin = Math.sin(y * Math.PI / 180);
var y2 = 0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI;
return y2 < 0 ? 0 : y2 > 1 ? 1 : y2;
}
Then the line distance calculation:
var distance_remaining = 0
for (let i = 0; i < remaining_line.geometry.coordinates.length - 1; ++i) {
var curr = remaining_line.geometry.coordinates[i];
var next = remaining_line.geometry.coordinates[i+1];
const d = [projectX(next[0]) - projectX(curr[0]), projectY(next[1]) - projectY(curr[1])];
distance_remaining += Math.sqrt(d[0] * d[0] + d[1] * d[1]);
}
Assuming you did the same distance calculation for the total route line distance, you can then can feed it to the gradient expression as such:
'line-gradient': [
'step',
['line-progress'],
"green",
1.0 - distance_remaining / total_distance, "yellow"
]
Here's a full example matching your code for reference with the resulting behavior:
Zoom 3:
Zoom 18:
Using the turf function with your method, where the location does not match and the error is clearly visible:
I don't believe there are any further change required in mapbox-gl to fit this case so I'll go ahead and close this ticket but feel free to continue the discussion if you need help or notice anything wrong with the suggestions above.
The Nav. SDK has a feature we call the "vanishing route line" which will make the color of the route line transparent or some other color behind the puck. As the puck moves across the map the gradient line is updated so the line in front of the puck is one color and the line behind the puck is another color or transparent.
There seems to be some lack of precision between the position of the puck and the "vanishing point". Depending on the route length and perhaps other factors, the "vanishing point is in front of or behind the puck. It looks to be off by a few meters which isn't noticeable with our default camera zoom level. However we have a customer with a more zoomed in camera while navigating so the issue is more noticeable.
@1ec5 referenced ticket: https://github.com/mapbox/mapbox-gl-js/pull/9694 cc @LukasPaczos @asheemmamoowala
Here is a screen shot. I calculated for the point designated with the red circle. However the vanishing point of the line is behind the circle. I would expect them visually line up.
I'll include the route as well as the calculations I"m using. If there's other information I can provide please let me know. The red circle in the screen shot is the point at index 12 in the route line coordinates. I chose that point arbitrarily.
This is how I create the gradient line expression:
The resulting expression is:
This is the route I used: