Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Maps v2 Projection.toScreenLocation(...) extremely slow

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?

like image 338
Alexander Avatar asked Oct 06 '14 12:10

Alexander


1 Answers

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).

like image 92
chubakueno Avatar answered Oct 12 '22 22:10

chubakueno