Google Maps v2 Projection.toScreenLocation(…) extr

2019-03-27 19:43发布

问题:

I have upgraded Google Maps v1 to v2 in my Android application.

And v2 was nice and so on BUT one method seems to be the slowest thing in my life.

Projection proj = map.getProjection();
Point point = proj.toScreenLocation(example.m_geopoint);

toScreenLocation(...) is so slow so the application slow downs to unusable slowmotion. The method updated maybe 100 times per frame but that works very very great on Google Maps v1.

And when I check in Android Console I see this:

10-06 13:53:04.460: D/dalvikvm(4889): GC_EXPLICIT freed 251K, 14% free 14622K/16839K, paused 3ms+5ms
10-06 13:53:05.859: D/dalvikvm(4889): GC_EXPLICIT freed 252K, 14% free 14622K/16839K, paused 2ms+5ms
10-06 13:53:07.222: D/dalvikvm(4889): GC_EXPLICIT freed 251K, 14% free 14622K/16839K, paused 3ms+6ms
...

This message is coming out all the time while the method is called.

And the difference between v2 and v1 is this:

pointOut = proj.toScreenLocation(geopointIn); // v2
projection.toPixels(geopointIn, pointOut); // v1

And the v1 seems to be more optimized solution. Is there some way to get it faster? Is it a performance bug?

回答1:

This answers comes probably too late, but if anybody else runs into the same problems, like me, a solution could be to pre-render an image on an own server with Java's Graphics2D (which works almost the same as drawing to the canvas) and download it within the app. You have to convert the geo points into cartesian coordinates. Within the app, you only have to position the image as GroundOverlay with LatLngBounds: https://developers.google.com/maps/documentation/android/groundoverlay#use_latlngbounds_to_position_an_image

and add it to the map... https://developers.google.com/maps/documentation/android/groundoverlay#change_an_overlay

For me, this approach works pretty fast. At least as fast as the Google Maps V1 approach.



回答2:

I come very, very late to the party, but I have an answer using android.graphics.Matrix:

float getYMercator(double latitude){
    return (float)Math.log(Math.tan(Math.PI*(0.25+latitude/360.0)));
}
float [] fastToScreenLocation(GoogleMap map, List<LatLng> coordinates,int viewHeight, int viewWidth){
    VisibleRegion visibleRegion = map.getProjection().getVisibleRegion();
    Matrix transformMatrix = new Matrix();
    boolean ok = transformMatrix.setPolyToPoly(
            new float[] {
                    (float)visibleRegion.farLeft.longitude, getYMercator(visibleRegion.farLeft.latitude),
                    (float)visibleRegion.farRight.longitude, getYMercator(visibleRegion.farRight.latitude),
                    (float)visibleRegion.nearRight.longitude, getYMercator(visibleRegion.nearRight.latitude),
                    (float)visibleRegion.nearLeft.longitude, getYMercator(visibleRegion.nearLeft.latitude)
            },0,
            new float[] {
                    0, 0,
                    viewWidth, 0,
                    viewWidth,viewHeight,
                    0, viewHeight
            }, 0,
            4);
    if(!ok) return null;
    float[] points = new float[2*coordinates.size()];
    for(int i=0;i<coordinates.size();++i){
        LatLng location = coordinates.get(i);
        points[2*i]=(float)location.longitude;
        points[2*i+1]=getYMercator(location.latitude);
    }
    transformMatrix.mapPoints(points);
    return points;
}

Basically, it projects the LatLng into pseudo WebMercator coordinates (WebMercator coordinates linearly transformed to save some calculations). Then it calculates the necessary matrix to transform the visible region to screen coordinates and applies the found matrix to the points in the coordinates list. Roughly 300x faster from my tests for a list of 150 coordinates on my Samsung J3 (avoiding array reallocation for multiple calls).