17

円を描くための次のコードがあります(Google Playサービスの「マップ」サンプルから取得)。

    PolylineOptions options = new PolylineOptions();
    int radius = 5; //What is that?
    int numPoints = 100;
    double phase = 2 * Math.PI / numPoints;
    for (int i = 0; i <= numPoints; i++) {
        options.add(new LatLng(SYDNEY.latitude + radius * Math.sin(i * phase),
                SYDNEY.longitude + radius * Math.cos(i * phase)));
    }
    int color = Color.RED;
    mMap.addPolyline(options
            .color(color)
            .width(2));

これは、世界のさまざまな部分に描かれるものです。

シドニー スカンディック

ご覧のとおり、円は実際には円ではなく、2番目の円でさえ基本的に楕円です。

int numPoints変数内の点の数に応じて、円の「アンチエイリアシング」だと思います。

  1. int radius = 5サンプルコードの変数は何ですか?私はそれが何の尺度であるかを意味しますか?
  2. そして主な質問は、メートル単位で与えられた半径で素敵な円を描く正しい方法は何でしょうか?apiv1で持っていたものに似た何かcanvas.drawCircle()

アップデート - - - - - - - - - -

数学を改善した後、私は「正しい」円を描くことができました。

private void addCircle(LatLng latLng, double radius)
    {
        double R = 6371d; // earth's mean radius in km
        double d = radius/R; //radius given in km
        double lat1 = Math.toRadians(latLng.latitude);
        double lon1 = Math.toRadians(latLng.longitude);         
        PolylineOptions options = new PolylineOptions();
        for (int x = 0; x <= 360; x++)
        {                      
            double brng = Math.toRadians(x);
            double latitudeRad = Math.asin(Math.sin(lat1)*Math.cos(d) + Math.cos(lat1)*Math.sin(d)*Math.cos(brng));
            double longitudeRad = (lon1 + Math.atan2(Math.sin(brng)*Math.sin(d)*Math.cos(lat1), Math.cos(d)-Math.sin(lat1)*Math.sin(latitudeRad)));             
            options.add(new LatLng(Math.toDegrees(latitudeRad), Math.toDegrees(longitudeRad)));
        }           
        mMap.addPolyline(options.color(Color.BLACK).width(2));          
    }

ただし、円のアンチエイリアシングは制御できないと思います。一部のズームレベルでは、円が醜くなる可能性があります。

ここに画像の説明を入力してください

4

6 に答える 6

23

Googleが作成したマップv2はシンプルです。以下のスニペットは、マーカーと円の両方を描画し、それらの位置を一緒に更新する方法を示しています。

private Circle mCircle;
private Marker mMarker;
private GoogleMap mGoogleMap;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mGoogleMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.mapFragment)).getMap();
    mGoogleMap.setMyLocationEnabled(true);
    mGoogleMap.setOnMyLocationChangeListener(new GoogleMap.OnMyLocationChangeListener() {
        @Override
        public void onMyLocationChange(Location location) {
            LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
            if(mCircle == null || mMarker == null){
                drawMarkerWithCircle(latLng);
            }else{
                updateMarkerWithCircle(latLng);
            }
        }
    });
}

private void updateMarkerWithCircle(LatLng position) {
    mCircle.setCenter(position);
    mMarker.setPosition(position);
}

private void drawMarkerWithCircle(LatLng position){
    double radiusInMeters = 100.0;
    int strokeColor = 0xffff0000; //red outline
    int shadeColor = 0x44ff0000; //opaque red fill

    CircleOptions circleOptions = new CircleOptions().center(position).radius(radiusInMeters).fillColor(shadeColor).strokeColor(strokeColor).strokeWidth(8);
    mCircle = mGoogleMap.addCircle(circleOptions);

    MarkerOptions markerOptions = new MarkerOptions().position(position);
    mMarker = mGoogleMap.addMarker(markerOptions);
}
于 2013-08-31T08:36:53.677 に答える
21

Google Maps v2(ビットマップ)で円を描く方法

// 1. some variables:

    private static final double EARTH_RADIUS = 6378100.0;
    private int offset;

// 2. convert meters to pixels between 2 points in current zoom:

    private int convertMetersToPixels(double lat, double lng, double radiusInMeters) {

         double lat1 = radiusInMeters / EARTH_RADIUS;
         double lng1 = radiusInMeters / (EARTH_RADIUS * Math.cos((Math.PI * lat / 180)));

         double lat2 = lat + lat1 * 180 / Math.PI;
         double lng2 = lng + lng1 * 180 / Math.PI; 

         Point p1 = YourActivity.getMap().getProjection().toScreenLocation(new LatLng(lat, lng));
         Point p2 = YourActivity.getMap().getProjection().toScreenLocation(new LatLng(lat2, lng2));

         return Math.abs(p1.x - p2.x);
    }

// 3. bitmap creation:

    private Bitmap getBitmap() {

        // fill color
        Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint1.setColor(0x110000FF);
        paint1.setStyle(Style.FILL);

        // stroke color
        Paint paint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint2.setColor(0xFF0000FF);
        paint2.setStyle(Style.STROKE);

        // icon
        Bitmap icon = BitmapFactory.decodeResource(YourActivity.getResources(), R.drawable.blue);

        // circle radius - 200 meters
        int radius = offset = convertMetersToPixels(lat, lng, 200);

        // if zoom too small
        if (radius < icon.getWidth() / 2) {

            radius = icon.getWidth() / 2;
        }

        // create empty bitmap 
        Bitmap b = Bitmap.createBitmap(radius * 2, radius * 2, Config.ARGB_8888);
        Canvas c = new Canvas(b);

        // draw blue area if area > icon size
        if (radius != icon.getWidth() / 2) {

            c.drawCircle(radius, radius, radius, paint1);
            c.drawCircle(radius, radius, radius, paint2);
        }

        // draw icon
        c.drawBitmap(icon, radius - icon.getWidth() / 2, radius - icon.getHeight() / 2, new Paint());

        return b;
    }

// 4. calculate image offset:

    private LatLng getCoords(double lat, double lng) {

        LatLng latLng = new LatLng(lat, lng);

        Projection proj = YourActivity.getMap().getProjection();
        Point p = proj.toScreenLocation(latLng);
        p.set(p.x, p.y + offset);

        return proj.fromScreenLocation(p);
    }

// 5. draw:

        MarkerOptions options = new MarkerOptions();
            options.position(getCoords(lat, lng));
            options.icon(BitmapDescriptorFactory.fromBitmap(getBitmap()));

            marker = YourActivity.getMap().addMarker(options);

結果:

グーグルマップv2ドローサークル

于 2013-01-20T19:15:41.407 に答える
7

Android 2.0 APIは、CircleOptionを使用して円を描くことができ、非常にうまく機能し、ピクセルからメートルへの面倒な変換はありません。

public CircleOptions getCircleOptions() {
    CircleOptions co = new CircleOptions();
    co.center(latlng);
    co.radius(getCircleSize());
    co.fillColor(getCircleColor());
    co.strokeColor(getStrokeColor());
    co.strokeWidth(2.0f);
    return co;
}

    Circle circle = mapView.getMap().addCircle(munzeeMarker.getCircleOptions());
于 2013-05-27T21:10:23.433 に答える
4

これが私のコードです。バリエーションを追加するためだけのものです。アンチエイリアシングまたは形状の単純化に関する問題を解決する方法が見つかりませんでした。

// Make a circle of latitude and longitude points.
// Radius is in metres.
// Probably won't work if the circle is large or near the poles.
private ArrayList<LatLng> makeCircle(LatLng centre, double radius)
{
    ArrayList<LatLng> points = new ArrayList<LatLng>();

    double EARTH_RADIUS = 6378100.0;
    // Convert to radians.
    double lat = centre.latitude * Math.PI / 180.0;
    double lon = centre.longitude * Math.PI / 180.0;

    for (double t = 0; t <= Math.PI * 2; t += 0.1)
    {
        // y
        double latPoint = lat + (radius / EARTH_RADIUS) * Math.sin(t);
        // x
        double lonPoint = lon + (radius / EARTH_RADIUS) * Math.cos(t) / Math.cos(lat);
        points.add(new LatLng(latPoint * 180.0 / Math.PI, lonPoint * 180.0 / Math.PI));
    }

    return points;
}

数学の説明

Google Earthはメルカトル図法を使用しています。つまり、物理的な円は地図上に円として表示されません。代わりに、質問に示されているように歪んでいます。ポールに近づくほど、歪みが大きくなります。地図上に円を描くには、緯度/経度で座標を指定して、歪みを反転させる必要があります。

まず、円の中心をラジアンで見つけます。これは非常に単純で、とに格納されlatlonいます。

次に、円の端にある点を見つけて円を一周します。物理的な円を作成している場合、各ポイントの緯度と経度は次のようになります。

        double latPoint = lat + (radius / EARTH_RADIUS) * Math.sin(t);
        double lonPoint = lon + (radius / EARTH_RADIUS) * Math.cos(t);

これは非常に単純な三角法です。(radius / EARTH_RADIUS)は、ラジアン単位の円の角半径です(たとえば、半径100 mの円の角半径は0.000015ラジアンになります)。

その単純なコードを使用すると、マップに表示されている円がcos(lat)水平方向に押しつぶされていることがわかります。そのため、単純に除算しcos(lat)て押しつぶしを解除します。

これも同様に行うことができます。

        double latPoint = lat + (radius / EARTH_RADIUS) * Math.sin(t) * Math.cos(lat);
        double lonPoint = lon + (radius / EARTH_RADIUS) * Math.cos(t);

radius結果として大きな円になります-関数パラメータが緯度または経度のどちらを参照しているかによって異なります。

この説明ではいくつかの図を使用できますが、気にすることはできません。申し訳ありません。

于 2013-01-10T13:34:48.250 に答える
2

Googleは本日2月26日、オーバーレイタイプとしてCircleをリリースしました。

https://developers.google.com/maps/documentation/android/reference/com/google/android/gms/maps/model/Circle

于 2013-02-27T00:35:58.503 に答える
1

昨日、AndroidデベロッパーチームはGooglePlayサービスv3を導入しました。それを乱用します!;) https://developers.google.com/maps/documentation/android/shapes#circles

于 2013-02-27T09:08:56.677 に答える