Draw A Circle On Android MapView

試著忘記壹切 提交于 2019-11-28 19:33:10

The accepted answer has an error. I attempted to correct it, but my edit was rejected for some strange reason. In any case, here is a corrected answer:

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;

public class CircleOverlay extends Overlay {

    Context context;
    double mLat;
    double mLon;
    float mRadius;

    public CircleOverlay(Context _context, double _lat, double _lon, float radius ) {
        context = _context;
        mLat = _lat;
        mLon = _lon;
        mRadius = radius;
    }

    public CircleOverlay(Context _context, double _lat, double _lon, float radius ) {
        context = _context;
        mLat = _lat;
        mLon = _lon;
        mRadius = radius;
    }

    public void draw(Canvas canvas, MapView mapView, boolean shadow) {
        super.draw(canvas, mapView, shadow); 

        if(shadow) return; // Ignore the shadow layer

        Projection projection = mapView.getProjection();

        Point pt = new Point();

        GeoPoint geo = new GeoPoint((int) (mLat *1e6), (int)(mLon * 1e6));

        projection.toPixels(geo ,pt);
        float circleRadius = projection.metersToEquatorPixels(mRadius) * (1/ FloatMath.cos((float) Math.toRadians(mLat)));

        Paint innerCirclePaint;

        innerCirclePaint = new Paint();
        innerCirclePaint.setColor(Color.BLUE);
        innerCirclePaint.setAlpha(25);
        innerCirclePaint.setAntiAlias(true);

        innerCirclePaint.setStyle(Paint.Style.FILL);

        canvas.drawCircle((float)pt.x, (float)pt.y, circleRadius, innerCirclePaint);
    }
}

The problem in Scott's answer is that the circleRadius was calculated using a method that converts from meters to pixels for points at the equator. If, however, your desired point is not on the equator, the radius will be too small because the conversion does not account for the fact that meridians come together at the poles. This can be corrected, however, by multiplying by (1/ FloatMath.cos((float) Math.toRadians(mLat))), which is the only change that I made to Scott's original answer.

I hope this helps someone because I discovered the problem the hard way. I live in Finland, where using the original method, the circles were drawn ~2 times smaller than they should have been!

I've taken the above sample and expanded it to take into account circles which need to be scaled with the map zoom level (ie: circles relative to ground distance).

Some people might find it useful.

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;

public class CircleOverlay extends Overlay {

    Context context;
    double mLat;
    double mLon;
    float mRadius;

     public CircleOverlay(Context _context, double _lat, double _lon, float radius ) {
            context = _context;
            mLat = _lat;
            mLon = _lon;
            mRadius = radius;
     }

     public void draw(Canvas canvas, MapView mapView, boolean shadow) {
         super.draw(canvas, mapView, shadow); 

         if(shadow) return; // Ignore the shadow layer

         Projection projection = mapView.getProjection();

         Point pt = new Point();

         GeoPoint geo = new GeoPoint((int) (mLat *1e6), (int)(mLon * 1e6));

         projection.toPixels(geo ,pt);
         float circleRadius = projection.metersToEquatorPixels(mRadius) * (1/ FloatMath.cos((float) Math.toRadians(mLat)));

         Paint innerCirclePaint;

         innerCirclePaint = new Paint();
         innerCirclePaint.setColor(Color.BLUE);
         innerCirclePaint.setAlpha(25);
         innerCirclePaint.setAntiAlias(true);

         innerCirclePaint.setStyle(Paint.Style.FILL);

         canvas.drawCircle((float)pt.x, (float)pt.y, circleRadius, innerCirclePaint);
    }
}
  1. Is the geo point you are trying to show (0.1275, 51.507222)? This is somewhere off the coast of Somalia.

  2. super.draw(..) should be the first statement in your draw() method.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!