-
-
Notifications
You must be signed in to change notification settings - Fork 93
Description
Design Proposal: Add trim-line paint property to LineLayer
Motivation
I have a route-line which is being erased by the car moving along it, the thing you can see in a navigator app.
Right now I'm updating the polyline geometry on every frame which seems to be a pretty CPU intensive and also require complex and hacky logic to not to thrash GC by mapping app's LatLon models to Maplibre's Point creating GC pressure and increasing memory footprint by storing two instances of the same polyline in memory.
I also tried to use line-gradient to set consumed part of the route to be transparent, but it changes discretely and doesn't let me to have a sharp cut or even a small fade-out cut which I'd be able to mask by rendering a car marker on top of it. It also has an issue where the length of the fading segment going from the polyline color to fully transparent seems to be depending on the polyline length and its distance from the poles.
In addition to that we also render congestions along the route and we either need to render them as a MultiLineString and update the whole geometry or have tens of LineLayer one per a congestion segment.
Proposed Change
Introduce line-trim paint property for the LineLayer which will can take values from 0 to 1 and from 0 to -1. Where:
0- the whole polyline is visible (default)1,-1- the whole polyline is invisible0.5- second half of the polyline is visible-0.5- first half of the polyline is visible (erased from the end)
The property should support expressions and data-driven styling, that will allow me to render all our congestion segments in a single LineLayer using MultiLineString and remap line-trim value passed to the actual lineTrim value for every element in MultiLineString. E.g. by setting 0.5 as line-trim to the LineLayer with all the congestions, using data-driven styling I'll be able to erase all MultiLineString elements that are before 0.5 point on my route and partially erase the segment that overlaps 0.5 point if any.
Mapbox already have something similar: https://docs.mapbox.com/android/maps/api/10.7.0/mapbox-maps-android/com.mapbox.maps.extension.style.layers.generated/-line-layer/line-trim-offset.html
The new property is expected to work only when lineMetrics set to true.
Implementation
To implement this behavior I suggest to introduce a new float32 vertex attribute (affecting all polylines) that will represent the progress along the polyline based on geodesic calculations. To do that we'd need:
- modify
polyline_generatorto reproject vertice positions of the polyline back to LatLon, calculate the length of given segments using harvestine for every line bucket. - modify
geojsonvtto change howmapbox_clip_startandmapbox_clip_endare being calculated, replacing euclidian distance by harvestine. - introduce new paint property to linelayer
I am not sure how easy it is to add another GeoJsonOption similar to lineMetrics to be able to enable/disable this behavior, I'd suggest to only calculate harvestine distances when lineMetrics == true so the change will only affect lines where it is enabled.
API Modifications
Add new LineLayer paint-property. On android: PropertyFactory.lineTrim(0.5) or PropertyFactory.lineTrim(Expression.get("myProperty"))
Migration Plan and Compatibility
The change is backwards compatible.
Rejected Alternatives
- Use gradient to erase the polyline
- Not accurate enough
- The minimal change to the position of a gradient segment is to coarse
- Cut the polyline into smaller chunks and modify smaller geometries on every frame
- Hard to implement even for a base case
- Creates a lot of LineLayers
- Can't be scaled with data-driven-styling