Android Maps API v2绘制圆圈

使用以下代码绘制圆圈(从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)); 

这是在世界的不同部分得到的东西:

悉尼斯堪

正如你看到的圆圈不是真的圆圈,甚至第二个椭圆基本上。

我猜圆圈的“反锯齿”取决于int numPointsvariables。

  1. 示例代码中的int radius = 5variables是什么? 我的意思是它是什么措施?
  2. 主要问题是以为单位绘制圆弧的正确方法是什么? 与canvas.drawCircle()在api v1中有什么canvas.drawCircle()

更新——————–

好的,在提高math后,我可以画出“右”的圆圈:

 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)); } 

然而,我猜圆圈的抗锯齿有点难以控制,在一些缩放级别上,圆圈可能会变得很难看:

在这里输入图像说明

Solutions Collecting From Web of "Android Maps API v2绘制圆圈"

如何在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(px, py + 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绘制圆

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); } 

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()); 

这是我的代码,只是为了增加变化。 我还没有find解决抗锯齿或形状简化问题的方法:

 // 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; } 

math解释

Google地球使用墨卡托投影 ,这意味着物理圈不会在地图上显示为圆形,而是像问题中所示的那样扭曲。 越接近两极,他们就越扭曲。 要在地图上绘制一个圆,但是在纬度/经度上给出的坐标,我们需要反转失真。

首先我们find圆弧的中心 – 这是非常简单的,并存储在lon

然后我们绕着它的边缘find点。 如果我们做一个物理圈,每个点的经度和纬度就是:

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

这是非常简单的三angular。 (radius / EARTH_RADIUS)是以弧度表示的圆的angular半径(例如,半径为100 m的圆的angular半径为0.000015 rad)。

如果我们使用这个简单的代码,我们会发现地图上显示的圆被水平方向上的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函数参数是指纬度还是经度。

这个解释可以使用一些图表,但我不能打扰,抱歉。

昨天,Android开发团队推出了Google Play服务v3。 虐待它! ;) https://developers.google.com/maps/documentation/android/shapes#circles