8

オーバーレイを使用して、任意のソースから取得した数万のジオポイントの形状を描画することで、Google マップ上の領域をマークしています。これは機能し、次のようになります。

    @Override
    public void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow)  {
        super.draw(canvas, mapView, false);

        Projection projection = mapView.getProjection();

        List<Zone> zones = ApplicationContext.getZones();

        path.rewind();

        for (Zone zone : zones) {
            paint.setDither(true);
            paint.setStyle(Style.FILL);
            paint.setAlpha(40);

            MultiPolygon multiPolygon = zone.getMultiPolygon();
            List<Polygon> polygons = multiPolygon.getPolygons();

            for (Polygon polygon : polygons) {
                for (List<Coordinate> coordinates : polygon.getCoordinates())  {
                    for (int i = 0; i < coordinates.size(); i++)  {
                        Point p = new Point();

                        projection.toPixels(new GeoPoint((int)(coordinates.get(i).getLatitude() * 1E6), (int)(coordinates.get(i).getLongitude() * 1E6)), p);

                        if (i == 0)  {
                            path.moveTo(p.x, p.y);
                        }
                        else  {
                            path.lineTo(p.x, p.y);
                        }
                    }
                }
            }
        }

        canvas.drawPath(path, paint);
    }

問題は、これが非常にリソースを消費することです。MapView でマップをスクロールまたは移動するたびに、ピクセル座標が変更されているため、パスを何度も計算する必要があります。描画された領域が非常に大きくなり、MapView でのスクロールが非常に遅くなり、機能的に使用できなくなる可能性があります。

私のアイデアは

  • パスが生成する「形状」を何らかの方法でキャッシュし、MapView でズーム レベルが変更されたときにそれを再描画するだけです。
  • 「その場で」ビットマップで何らかの方法で絵を描き、それをオーバーレイとして(おそらくItemizedOverlayとして)使用し、MapViewのスクロールをリッスンし、スクロールされた距離だけビットマップを移動します。

より良い方法があるかどうかはわかりません。

この問題を解決する方法はありますか? (Google Maps API 1 を使用しており、変更できません)。

4

2 に答える 2

4

マップの動きを一致させる方法を理解しようとする前に、現在のコードにいくつかの最適化があり、おそらく大幅な節約になります。特に、内部ループ内のこれら2行はほとんどの場合実行されますが、実行にはかなりのコストがかかります(2つのメモリ割り当て、浮動小数点乗算、および4つのメソッド呼び出し)。

Point p = new Point();    
projection.toPixels(new GeoPoint((int)(coordinates.get(i).getLatitude() * 1E6), (int)(coordinates.get(i).getLongitude() * 1E6)), p);

まず、必要なPointオブジェクトは1つだけなので、ループ内での割り当ては避けてください。すぐ下に移動しますpath.rewind();

GeoPoints次に、座標を毎回計算するのではなく、事前に計算しておけば、drawルーチンでの処理を大幅に節約できます。if少しの作業でそのステートメントを取り除くこともできます。coordinateのリストをのリストに事前変換し、GeoPointを介して利用できるようにpolygon.getGeoCoordinates()すると、内部ループは次のようになります。

for (List<GeoPoint> geoCoordinates : polygon.getGeoCoordinates())  {
    projection.toPixels(geoCoordinates.get(0),p);
    path.moveTo(p.x, p.y);  // move to first spot
    final List<GeoPoint> lineToList = geoCoordinates.sublist(1,geoCoordinates.size());  // A list of all the other points
    for(GeoPoint gp : lineToList) {
        projection.toPixels(gp, p);
        path.lineTo(p.x, p.y);
     }
}

そして、それはあなたが以前やっていたよりもずっと速く走るでしょう。

于 2013-01-31T01:09:14.620 に答える
1

ここ数日いじくり回した後、パスを何度も描画せずに現在の位置に移動するための可能な解決策を見つけました (より良い解決策はないと思います)。

難しいのは、描画された形状を何度も計算しないようにキャッシュする方法を見つけることでした。これは、Matrix を使用して実行できます。このマトリックス (私はこれをある種の「テンプレート」と考えています) を使用すると、パス内のポイント座標を操作できます。初めて(誰かがマップを動かし始めたとき)、いつものようにエリアを描きます。2回目以降の計算では、形状を描き直すのではなく、現在の点から最後の点までの「デルタ」を計算してパスを操作します。元のジオポイント (常に同じまま) を現在の投影の結果のポイントに常にマッピングしているため、現在のポイントが何であるかがわかります。「デルタ」はマトリックスとして設定する必要があります。その後、この新しい Matrix を使用してパスを変換します。結果は非常に高速です。

これは次のようになります (これは製品コードではなく、まだズームを処理することはできませんが、最適化の基礎として使用する原則を示しています)。

public class DistrictOverlay extends Overlay {

//  private final static String TAG = DistrictOverlay.class.getSimpleName();
    private Paint paint = new Paint();
    private Path path = new Path();
    private boolean alreadyDrawn = false;
    private GeoPoint origGeoPoint;
    Point p = new Point();
    Point lastPoint = new Point();

    @Override
    public void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow) {
        super.draw(canvas, mapView, false);

        Projection projection = mapView.getProjection();

        List<Zone> zones = ApplicationContext.getZones();

        if (!alreadyDrawn) {
            path.rewind();

            for (Zone zone : zones) {
                if (!zone.getZoneId().equals(MenuContext.getChosenZoneId())) {
                    continue;
                }

                String dateString = zone.getEffectiveFrom().trim().replace("CEST", "").replace("GMT", "").replace("CET", "").replace("MESZ", "");
                if (DateUtil.isBeforeCurrentDate(dateString)) {
                    paint.setColor(Color.RED);
                } else {
                    paint.setColor(Color.GREEN);
                }

                paint.setDither(true);
                paint.setStyle(Style.FILL);
                paint.setAlpha(40);

                MultiPolygon multiPolygon = zone.getMultiPolygon();
                List<Polygon> polygons = multiPolygon.getPolygons();

                for (Polygon polygon : polygons) {
                    for (List<GeoPoint> geoPoints : polygon.getGeoPoints()) {
                        projection.toPixels(geoPoints.get(0), p);
                        path.moveTo(p.x, p.y);

                        origGeoPoint = new GeoPoint(geoPoints.get(0).getLatitudeE6(), geoPoints.get(0).getLongitudeE6());
                        lastPoint = new Point(p.x, p.y);

                        final List<GeoPoint> pathAsList = geoPoints.subList(1, geoPoints.size());

                        for (GeoPoint geoPoint : pathAsList) {
                            projection.toPixels(geoPoint, p);
                            path.lineTo(p.x, p.y);
                        }
                    }
                }
            }           
        }
        else  {
            projection.toPixels(origGeoPoint, p);       
            Matrix translateMatrix = new Matrix();
            translateMatrix.setTranslate(p.x - lastPoint.x, p.y - lastPoint.y);
            path.transform(translateMatrix);

            lastPoint = new Point(p.x, p.y);
        }

        canvas.drawPath(path, paint);

        if (!path.isEmpty()) {
            alreadyDrawn = true;
        }
    }

    @Override
    public boolean onTap(GeoPoint p, MapView mapView) {
        return true;
    }
}
于 2013-02-03T15:35:46.280 に答える