5

I am trying to solve a problem with drawing a path from huge (100k+) set of GeoPoints to a MapView on Android. Firstly I would like to say, I searched through StackOverflow a lot and haven't found an answer.The bottleneck of my code is not actually drawing into canvas, but Projection.toPixels(GeoPoint, Point) or Rect.contains(point.x, point.y) method..I am skipping points not visible on screen and also displaying only every nth point according to current zoom-level. When the map is zoomed-in I want to display as accurate path as possible so I skipping zero (or nearly to zero) points, so that when finding visible points I need to call the projection method for every single point in the collection. And that is what really takes a lot of time (not seconds, but map panning is not fluid and I am not testing it on HTC Wildfire:)). I tried caching calculated points, but since points be recalculated after every map pan/zoom it haven't helped at all.

I thought about usage of some kind of prune and search algorithm instead of iterate the array, but I figured out the input data is not sorted (I can't throw away any branch stacked between two invisible points). That could I possible solve with simple sort at the beginning, but I am still not sure even the logarithmic count of getProjection() and Rect.contains(point.x, point.y) calls instead of linear would solve the performance problem.

Bellow is my current code. Please help me if you know how to make this better. Thanks a lot!

public void drawPath(MapView mv, Canvas canvas) {
    displayed = false;

    tmpPath.reset();

    int zoomLevel = mapView.getZoomLevel();
    int skippedPoints = (int) Math.pow(2, (Math.max((19 - zoomLevel), 0)));
    int mPointsSize = mPoints.size();
    int mPointsLastIndex = mPointsSize - 1;
    int stop = mPointsLastIndex - skippedPoints;

    mapView.getDrawingRect(currentMapBoundsRect);
    Projection projection = mv.getProjection();

    for (int i = 0; i < mPointsSize; i += skippedPoints) {

        if (i > stop) {
            break;
        }
//HERE IS THE PROBLEM I THINK - THIS METHOD AND THE IF CONDITION BELOW
        projection.toPixels(mPoints.get(i), point);

        if (currentMapBoundsRect.contains(point.x, point.y)) {
            if (!displayed) {
                Point tmpPoint = new Point();
                projection.toPixels(mPoints.get(Math.max(i - 1, 0)),
                        tmpPoint);
                tmpPath.moveTo(tmpPoint.x, tmpPoint.y);
                tmpPath.lineTo(point.x, point.y);
                displayed = true;
            } else {

                tmpPath.lineTo(point.x, point.y);

            }

        } else if (displayed) {
            tmpPath.lineTo(point.x, point.y);
            displayed = false;

        }

    }

    canvas.drawPath(tmpPath, this.pathPaint);

}
4

1 に答える 1

3

だから私はそれをもっと速くする方法を見つけました!私はそれをここに投稿します、誰かが将来それが役に立つと思うかもしれません。の使用は、projection.toPixels()アプリケーションのパフォーマンスに実際に悪影響を与える可能性があることが明らかになりました。したがって、マップの実際のビューポート半径を次のように数えると、すべてを取得してGeoPoint変換し、それがマップビューポートに含まれているかどうかを確認するよりも優れていることがわかりました。Point

    mapView.getGlobalVisibleRect(currentMapBoundsRect);
    GeoPoint point1 = projection.fromPixels(currentMapBoundsRect.centerX(), currentMapBoundsRect.centerY());
    GeoPoint point2 = projection.fromPixels(currentMapBoundsRect.left, currentMapBoundsRect.top);
    float[] results2 = new float[3];
    Location.distanceBetween(point1.getLatitudeE6()/1E6, point1.getLongitudeE6()/1E6, point2.getLatitudeE6()/1E6, point2.getLongitudeE6()/1E6, results2);

半径はresults2[0]にあります。

次に、すべてを取得GeoPointして、それとマップの中心との間の距離を数えることができますmapView.getMapCenter()。次に、半径を計算された距離と比較して、ポイントを表示しないかどうかを決定できます。

以上です。お役に立てば幸いです。

于 2012-07-22T19:53:22.370 に答える