tangram-es icon indicating copy to clipboard operation
tangram-es copied to clipboard

Feature Request: Support meters as size unit for points

Open westnordost opened this issue 7 years ago • 6 comments

I am trying to show the accuracy radius of a location around the user. Here, I ran into some problems. I think part of it is a bug, part of it is a missing feature probably.

The relevant portion of the style file:

styles:
    location-radius:
        base: points
        blend: overlay
        blend_order: 2
layers:
    streetcomplete_location:
        data: { source: streetcomplete_location }
        draw:
            location-radius:
                collide: false
                color: '#44fd6c3e'
                size: function() { return feature.radius }

and the code

locationLayer.clear();
LngLat pos = new LngLat(location.getLongitude(), location.getLatitude());
int accuracy = (int)(Math.ceil(location.getAccuracy()));

Map<String, String> props = new HashMap<>();
props.put("type", "point");
props.put("radius", ""+accuracy+"m");
locationLayer.addPoint(pos, props);

However, this gives i.e. the error: styleParam.cpp:184: Invalid size parameter '22m'

If I set a static size in the style definition, I get no error, but it doesn't seem to show at all.

So my guess is that meters as a size unit for points is simply not implemented as there hasn't been a use case for this (until now :-P). At least it is not documented. That Tangram-ES does not report an error if you write size: 50m seems to be a bug then. In any case, this ticket shall be a feature request to support meters as a unit for points.

Plan B for the use case I have in mind would be to use a circle-polygon for the radius, but I find that rather ugly.

westnordost avatar Nov 30 '16 22:11 westnordost

Perhaps another use case would be tree-nodes. (natural=tree)

westnordost avatar Nov 30 '16 22:11 westnordost

@westnordost : one other posssible workaround would be to use a circular marker together with a js function for the size. That function would back out the size in pixel from the zoom level so it remains constant in meters. I haven't tested that yet.

Guillaume227 avatar Feb 22 '17 08:02 Guillaume227

Jup, I did that now, looks pretty nice and feels smooth. I call updateAccuracy whenever the zoom changes. However, it's still just a workaround, especially because there is no callback for when the map view changes. (See linked feature request).

private void updateAccuracy()
{
	if(accuracyMarker != null && lastLocation != null)
	{
		if(lastZoom == controller.getZoom()) return;
		LngLat pos = new LngLat(lastLocation.getLongitude(), lastLocation.getLatitude());
		float size = meters2Pixels(pos, lastLocation.getAccuracy());
		accuracyMarker.setStyling("{ style: 'points', color: 'white', size: ["+size+"px, "+size+"px], order: 2000, collide: false }");
		lastZoom = controller.getZoom();
	}
}

private float meters2Pixels(LngLat at, float meters) {
	LatLon pos0 = TangramConst.toLatLon(at);
	LatLon pos1 = SphericalEarthMath.translate(pos0, meters, 0);
	PointF screenPos0 = controller.lngLatToScreenPosition(at);
	PointF screenPos1 = controller.lngLatToScreenPosition(TangramConst.toLngLat(pos1));
	return Math.abs(screenPos1.y - screenPos0.y);
}

device-2017-03-15-131521

westnordost avatar Mar 14 '17 23:03 westnordost

Another use case where supporting meters for points would be helpful: Rendering mini-roundabouts and turning circles with some realistic diameter in meters on high zoom levels.

westnordost avatar Sep 08 '19 12:09 westnordost

Actually, nevermind my earlier algorithm, much easier is

pixels_per_meter = 2^zoom_level * 256 / (cos(latitude * pi/180) * earth_circumference)

There is also a $meters_per_pixel in the docs, which would make it trivial to workaround this via a javascript function, however in tangram-es it doesn't seem to be supported. See #2138

westnordost avatar Jan 27 '20 14:01 westnordost

(Ah, realized that $meters_per_pixel does actually not solve this, because it only changes on full zoom levels changes.)

westnordost avatar Jun 02 '20 17:06 westnordost