Android карты наложение круга, динамически изменить радиус? - PullRequest
4 голосов
/ 20 апреля 2011

У меня есть MapView в моем приложении, и я рисую несколько круговых оверлеев на этой карте.Все работает нормально, но когда я масштабирую карту, радиус наложения не меняется.Я пытался найти решение на форумах и в Google, но не смог найти подходящее для меня.У кого-нибудь есть идеи?

Вот мой код:

HelloGoogleMaps.java (основная деятельность)

package com.adam.maps;

import java.util.Iterator;
import java.util.List;

import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.AbsoluteLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;
import android.widget.ZoomButtonsController.OnZoomListener;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;

public class HelloGoogleMaps extends MapActivity {  
//create new LocationManager
//and LocationListener objects
LocationManager lm;
LocationListener locationListener;

OnZoomListener listener;

//create a new MapView
//and MapController object
MapView mapView;
MapController mc;

RelativeLayout parent;

int num = 4;
//LoopRegion region[] = new LoopRegion[num];
//LoopRegion border[] = new LoopRegion[num];
float regionX[] = {(float) 42.91556645193364, (float) 42.9151598328247, 
        (float) 43.00110298764482, (float) 43.00054196511636};
float regionY[] = {(float) -78.87073255078127, (float) -78.8714594294243, 
        (float) -78.78354466454317, (float) -78.78226256863405};
int regionR[] = {100, 70, 150, 75};
GeoPoint regionC[] = new GeoPoint[num];
CustomOverlay overlay[] = new CustomOverlay[num];
CustomOverlay overlayLoc;


/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Toast.makeText(getBaseContext(), 
            "Welcome to 'sound clusters'" , 
            Toast.LENGTH_LONG).show();

    //---use the LocationManager class to obtain GPS locations---
    lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);    

    locationListener = new MyLocationListener();

    lm.requestLocationUpdates(
        LocationManager.GPS_PROVIDER, 
        0, 
        0, 
        locationListener);

    //set our mapViewer object to our "mapview" namespace in the xml layout file
    //this allows us to set the zoom control "ON" in our view
    mapView = (MapView) findViewById(R.id.mapview);
    //this will enable zoom controls, and put it on the screen
    mapView.setBuiltInZoomControls(true);
    //--------------------------------------------------------//
    parent = (RelativeLayout) findViewById(R.id.parent);

    //-------this is part of creating an overlay icon-------------------------------
    /*List<Overlay> mapOverlays = mapView.getOverlays();
    Drawable drawable = this.getResources().getDrawable(R.drawable.icon);
    CustomItemizedOverlay itemizedOverlay =
        new CustomItemizedOverlay(drawable, this);*/
    //------------------------------------------------------------------------------

    // Create new Overlay
    for (int i = 0; i < num; i++){
        regionC[i] = new GeoPoint(
                (int) (regionX[i] * 1E6), 
                (int) (regionY[i] * 1E6));
        int newRadius = (int) feetToPixels(mapView.getZoomLevel(), regionR[i]);
        overlay[i] = new CustomOverlay(regionC[i], newRadius);
        mapView.getOverlays().add(overlay[i]);
    }

    //-------this is part of creating an overlay icon-------------------------------
    /*OverlayItem overlayitem =
         new OverlayItem(point, "Hello", "I'm in Athens, Greece!");
    itemizedOverlay.addOverlay(overlayitem);
    mapOverlays.add(itemizedOverlay);*/
    //------------------------------------------------------------------------------



    mc = mapView.getController();
    mc.setZoom(20);
    mapView.setSatellite(true);
    Toast.makeText(getBaseContext(), 
            "Zoom level: " + mapView.getZoomLevel(), 
            Toast.LENGTH_SHORT).show();


}

//not sure what this does, but Google says you need it----//
@Override
protected boolean isRouteDisplayed() {
    return false;
}
//--------------------------------------------------------//    

private class MyLocationListener implements LocationListener 
{

    //@Override
    public void onLocationChanged(Location loc) {
        if (loc != null) {

            List overlays = mapView.getOverlays();
            // first remove old overlay
            if (overlays.size() > 0) {
                for (Iterator iterator = overlays.iterator(); iterator
                        .hasNext();) {
                    iterator.next();
                    iterator.remove();
                }
            }

            GeoPoint p = new GeoPoint(
                    (int) (loc.getLatitude() * 1E6), 
                    (int) (loc.getLongitude() * 1E6));

            overlayLoc = new CustomOverlay(p, 5);
            mapView.getOverlays().add(overlayLoc);
            for (int i = 0; i < num; i++){
                mapView.getOverlays().add(overlay[i]);
            }
            //mc.animateTo(p);
            //mc.setZoom(16);
            mapView.invalidate();
        }
    }

    //@Override
    public void onProviderDisabled(String provider) {
        // TODO Auto-generated method stub
    }

    //@Override
    public void onProviderEnabled(String provider) {
        // TODO Auto-generated method stub
    }

    //@Override
    public void onStatusChanged(String provider, int status, 
        Bundle extras) {
        // TODO Auto-generated method stub
    }
}

//custom functions--------------------------------------------------------------------
private static final double equatorFeet = 131479920; 
private double feetToPixels(int zoomLevel, int feet) { 
    double equatorPixels = 256; 
    for (int i = 1; i < zoomLevel; i++) { 
        equatorPixels = equatorPixels * 2; 
    } 
    double pixelPerFoot = equatorPixels / equatorFeet; 
    return feet * pixelPerFoot; 
} 
//------------------------------------------------------------------------------------

}

И класс Overlay CustomOverlay.java

package com.adam.maps;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;

public class CustomOverlay extends Overlay {

private GeoPoint geopoint;
private int rad;

public CustomOverlay(GeoPoint point, int radius) {
    geopoint = point;
    rad = radius;
}


@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
    // Transform geo-position to Point on canvas
    Projection projection = mapView.getProjection();
    Point point = new Point();
    //store the transformed geopoint into a point with pixel values
    projection.toPixels(geopoint, point);

    /*// text "My Location"
    Paint text = new Paint();
    text.setAntiAlias(true);
    text.setColor(Color.BLUE);
    text.setTextSize(12);
    text.setTypeface(Typeface.MONOSPACE);*/

    // the circle to mark the spot
    Paint circlePaint = new Paint();
    circlePaint.setAntiAlias(true);
    //fill region
    circlePaint.setColor(Color.RED);
    circlePaint.setAlpha(90);
    circlePaint.setStyle(Paint.Style.FILL);
    canvas.drawCircle(point.x, point.y, rad, circlePaint);
    //border region
    circlePaint.setColor(Color.WHITE);
    circlePaint.setAlpha(255);
    circlePaint.setStyle(Paint.Style.STROKE);
    circlePaint.setStrokeWidth(3);
    canvas.drawCircle(point.x, point.y, rad, circlePaint);

    /*canvas.drawText("My Location", point.x + 3 * CIRCLERADIUS, point.y + 3
            * CIRCLERADIUS, text);*/
}
}

Заранее благодарим за помощь!

Ответы [ 5 ]

7 голосов
/ 04 марта 2012
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;

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

public class MapCircleOverlay extends Overlay {

private GeoPoint point;
private Paint paint1, paint2;
private float radius; //in meters

public MapCircleOverlay(GeoPoint point, float radius) {
    this.point = point;

    paint1 = new Paint();
    paint1.setARGB(128, 0, 0, 255);
    paint1.setStrokeWidth(2);
    paint1.setStrokeCap(Paint.Cap.ROUND);
    paint1.setAntiAlias(true);
    paint1.setDither(false);
    paint1.setStyle(Paint.Style.STROKE);

    paint2 = new Paint();
    paint2.setARGB(64, 0, 0, 255);

    this.radius = radius;
}

@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {

    Point pt = mapView.getProjection().toPixels(point, null);
    float projectedRadius = mapView.getProjection().metersToEquatorPixels(radius);

    canvas.drawCircle(pt.x, pt.y, projectedRadius, paint2);
    canvas.drawCircle(pt.x, pt.y, projectedRadius, paint1);

}

}

Я изменил ответ Бандиуса, чтобы он работал со счетчиками, которые можно вводить как часть конструктора.

3 голосов
/ 09 сентября 2011

Я знаю, что этой ветке несколько месяцев, но ВСЕГДА есть более простые способы достижения очень похожих результатов.Я понимаю, что представленный метод дает гораздо более точный расчет относительно размера круга, но, тем не менее, если вам нужен только какой-либо круг вокруг усреднения некоторой области, этот код требует гораздо меньше обработки, что делает интерфейс более плавным:

public class MapCircleOverlay extends Overlay {

private GeoPoint point;
private Paint paint1, paint2;

public MapCircleOverlay(GeoPoint point) {
    this.point = point;

    paint1 = new Paint();
    paint1.setARGB(128, 0, 0, 255);
    paint1.setStrokeWidth(2);
    paint1.setStrokeCap(Paint.Cap.ROUND);
    paint1.setAntiAlias(true);
    paint1.setDither(false);
    paint1.setStyle(Paint.Style.STROKE);

    paint2 = new Paint();
    paint2.setARGB(64, 0, 0, 255);  

}

@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {

    Point pt = mapView.getProjection().toPixels(point, null);
    float radius = (float) Math.pow(2, mapView.getZoomLevel() - 10);

    if(radius < canvas.getHeight()/25){
        radius = canvas.getHeight()/25;
    }

    canvas.drawCircle(pt.x, pt.y, radius, paint2);
    canvas.drawCircle(pt.x, pt.y, radius, paint1);

}

}

Объяснение: в документации говорится, что для каждого zoomLevel карта удваивает (или уменьшает вдвое) размер, поэтому, если радиус удваивается или уменьшается вдвое, его размер будет одинаковым для всех чертежей.

"-10 "можно изменить, чтобы изменить размер круга (при желании это можно сделать в Конструкторе)

Кроме того, вычисление min_r (минимального радиуса) можно настроить по желанию, оно только там, чтобы предотвратитьполностью исчезает, когда пользователь уменьшает масштаб.

надеюсь, это кому-нибудь поможет;)

1 голос
/ 10 августа 2017
private CircleOptions circle;
double radiusInMeters = 50.0;
int strokeColor = 0xffff0000; //red outline
int shadeColor = 0x44ff0000;

 @Override
 public void onLocationChanged(Location location) {

 ...
    LatLng mylatlng= new LatLng(currentLat, currentLon);
    circle = new CircleOptions().center(mylatlng).radius(radiusInMeters).fillColor(shadeColor).strokeColor(strokeColor).strokeWidth(3);
    mMap.addCircle(circle);

 ...

}
1 голос
/ 17 июля 2014

Извините, я знаю, что полученный ответ старый, но существует собственное и лучшее решение.

 // Add a circle in Sydney
 Circle circle = map.addCircle(new CircleOptions()
     .center(new LatLng(-33.87365, 151.20689))
     .radius(10000)
     .strokeColor(Color.RED)
     .fillColor(Color.BLUE));

Надеюсь, это поможет кому-то =)

Ссылка: Здесь

1 голос
/ 01 мая 2011
class myLocationOverlay extends com.google.android.maps.Overlay {

    private static final double defaultLatitude = Double.parseDouble("your_default_latitude");
    private static final double defaultLongitude = Double.parseDouble("your_default_longitude");
    private static final float defaultAccuracy = 250f; // or whatever you wish it to be


    Location currentLocation; // this should be already known

    private Paint accuracyPaint;
    private Point center;
    private Point left;
    private Drawable drawable;
    private int width;
    private int height;

    @Override
    public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
        super.draw(canvas, mapView, shadow);

        accuracyPaint = new Paint();
        accuracyPaint.setAntiAlias(true);
        accuracyPaint.setStrokeWidth(2.0f);

        drawable = mapView.getContext().getResources().getDrawable(R.drawable.my_location_dot);
        width = drawable.getIntrinsicWidth();
        height = drawable.getIntrinsicHeight();
        center = new Point();
        left = new Point();
        double latitude;
        double longitude;
        float accuracy;
        Projection projection = mapView.getProjection();

        if(currentLocation == null) {
            latitude = defaultLatitude;
            longitude = defaultLongitude;
            accuracy = defaultAccuracy;
        } else {
            latitude = currentLocation.getLatitude();
            longitude = currentLocation.getLongitude();
            accuracy = currentLocation.getAccuracy();
        }            

        float[] result = new float[1];

        Location.distanceBetween(latitude, longitude, latitude, longitude + 1, result);
        float longitudeLineDistance = result[0];

        GeoPoint leftGeo = new GeoPoint((int)(latitude * 1E6), (int)((longitude - accuracy / longitudeLineDistance) * 1E6));
        projection.toPixels(leftGeo, left);
        projection.toPixels(myLocationPoint, center);
        int radius = center.x - left.x;

        accuracyPaint.setColor(0xff6666ff);
        accuracyPaint.setStyle(Style.STROKE);
        canvas.drawCircle(center.x, center.y, radius, accuracyPaint);

        accuracyPaint.setColor(0x186666ff);
        accuracyPaint.setStyle(Style.FILL);
        canvas.drawCircle(center.x, center.y, radius, accuracyPaint);

        drawable.setBounds(center.x - width / 2, center.y - height / 2, center.x + width / 2, center.y + height / 2);
        drawable.draw(canvas);

        return true;
    }
}

Измените R.drawable. my_location_dot на то, что вы используете в качестве маркера местоположения, и увидите, что currentLocation известен

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...