Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Android Maps API v2 dibujar círculo

Tener el siguiente código para dibujar un círculo (tomado de la muestra "mapas" de Google Play Services):

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

Esto es lo que se dibuja en diferentes partes del mundo:

SydneyScandic

Como ves círculos no son realmente círculos e incluso el segundo es la elipse básicamente.

Supongo que "anti-aliasing" de círculo dependiendo del número de puntos en la variable int numPoints .

  1. ¿Qué es int radius = 5 variable en el código de ejemplo? Me refiero a qué medida es?
  2. Y pregunta principal ¿cuál sería la manera correcta de dibujar un círculo agradable con un radio dado en metros ? Algo smiliar a lo que teníamos en api v1 con canvas.drawCircle()

ACTUALIZAR ——————–

Aceptar después de mejorar las matemáticas que era capaz de dibujar "derecho" círculo:

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

Sin embargo el anti-aliasing del círculo supongo es un poco más allá del control, y en algunos círculos del nivel del zumbido pudo conseguir feo:

Introduzca aquí la descripción de la imagen

  • API de Google Maps para Android da un NoClassDefFoundError
  • ¿Cómo puedo crear una aplicación de Android en Android Studio que usa Google Maps Api v2?
  • Google Maps API V2 'Error al cargar mapa. No se pudo contactar con Google Servers, ni siquiera comprobar permiso y keystore
  • Android Google Maps No se pudo encontrar el estilo 'mapViewStyle' en el tema actual
  • ¿Cómo ajustar el nivel de zoom para ajustar el límite y, a continuación, el mapa del centro en marcador de desplazamiento?
  • Intento de obtener la longitud de la matriz nula en google maps V2 android app
  • Ocultar infoWindow cuando se hace clic en el marcador por segunda vez (Google Map Android API V2)
  • Android Google Maps API v2 ruta de visualización
  • 6 Solutions collect form web for “Android Maps API v2 dibujar círculo”

    Cómo dibujar círculo en Google Maps v2 (mapa de bits)

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

    y resultado:

    google maps v2 draw circle

    Google hecho es simple en mapas v2. El siguiente fragmento muestra ambos marcadores de dibujo y círculos junto con la actualización de sus posiciones juntos.

     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 que puede utilizar CircleOption para dibujar un círculo, funciona muy bien, no hay conversiones desordenadas de píxeles a metros.

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

    Aquí está mi código, sólo para la variación añadida. No he encontrado una manera de resolver los problemas con antialiasing o la simplificación de la forma:

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

    Explicación de las matemáticas

    Google Earth utiliza la proyección de Mercator, lo que significa que los círculos físicos no aparecen como círculos en el mapa, sino que están distorsionados como se muestra en la pregunta. Cuanto más cerca de los polos que vaya, más distorsionados son. Para dibujar un círculo en el mapa pero con coordenadas dadas en latitud / longitud necesitamos invertir la distorsión.

    Primero encontramos el centro del círculo en radianes – que es bastante simple y se almacena en lat y lon .

    Entonces vamos alrededor del círculo encontrando puntos en su borde. Si estábamos haciendo un círculo físico, la latitud y longitud de cada punto es justa:

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

    Eso es bastante simple trigonometría. El radio (radius / EARTH_RADIUS) es el radio angular del círculo en radianes (por ejemplo, un círculo con un radio de 100 m tendría un radio angular de 0,000015 rad).

    Si usamos ese código simple encontraríamos que el círculo mostrado en el mapa fue aplastado por cos(lat) horizontalmente, así que simplemente dividimos por cos(lat) para desquitarlo.

    Podríamos igualmente haber hecho esto:

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

    Resultando en un círculo grande – depende si el parámetro de función de radius se refiere a la latitud o longitud.

    Esta explicación podría usar algunos diagramas pero no puedo molestarme, lo siento.

    Google hoy, 26 de febrero, acaba de lanzar Circle como un tipo de superposición.

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

    El equipo de desarrolladores de Android de ayer introdujo el servicio v3 de Google Play. ¡Abusar de ello! 😉 https://developers.google.com/maps/documentation/android/shapes#circles

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.