如何根据osmdroid中的标记数量设置簇的图标?

How to set the icon of cluster based on number of markers in osmdroid?

我在 osmdroid 中使用集群。最初有一个大集群。在缩放集群时,集群会分成两个单独的集群。然后在进一步缩放时,这些集群会分解为标记数量较少的较小集群。

我想要的是根据集群拥有的标记数量为集群设置不同的图标。

radiusMarkerClusterer.setRadius(40);
    radiusMarkerClusterer.setMaxClusteringZoomLevel(17);
    radiusMarkerClusterer.reversedClusters();



    for (int i = 0; i < alert.size(); i++) {
        position = new GeoPoint(Double.parseDouble(alert.get(i).getLatitude()), Double.parseDouble(alert.get(i).getLongitude()));
        marker = new Marker(map);
        marker.setPosition(position);
        mapController.animateTo(position);
        Log.i(TAG, "MArker added to cluster ");

        radiusMarkerClusterer.add(marker);
    }
map.getOverlays().add(radiusMarkerClusterer);

这就是我现在实现集群的方式。有办法吗?

RadiusMarkerClusterer 不支持不同缩放比例的不同绘图。您需要创建自定义 MarkerClusterer 子类。

查看 RadiusMarkerClusterer 的来源以获取指导和灵感。标记的可绘制对象是在方法 buildClusterMarker

中创建的
@Override public Marker buildClusterMarker(StaticCluster cluster, MapView mapView)

如您所见,可以访问 MapView,因此您可以获得当前缩放级别并决定应使用哪个图标。

创建自定义 class RadiusMarkerClusterer。

      import android.content.Context;
        import android.graphics.*;
        import android.graphics.drawable.BitmapDrawable;
        import android.graphics.drawable.Drawable;
        import android.support.v4.content.res.ResourcesCompat;
        import android.util.Log;
        import android.view.MotionEvent;
        import com.kintanpatel.mygmail.R;
        import org.osmdroid.bonuspack.clustering.MarkerClusterer;
        import org.osmdroid.bonuspack.clustering.StaticCluster;
        import org.osmdroid.util.BoundingBox;
        import org.osmdroid.util.GeoPoint;
        import org.osmdroid.views.MapView;
        import org.osmdroid.views.overlay.Marker;

        import java.util.ArrayList;
        import java.util.Iterator;
        import java.util.Objects;

/**
 * Radius-based Clustering algorithm:
 * create a cluster using the first point from the cloned list.
 * All points that are found within the neighborhood are added to this cluster.
 * Then all the neighbors and the main point are removed from the list of points.
 * It continues until the list is empty.
 * <p>
 * Largely inspired from GridMarkerClusterer by M.Kergall
 *
 * @author sidorovroman92@gmail.com
 */

public class RadiusMarkerClusterer extends MarkerClusterer {

    /**
     * cluster icon anchor
     */
    public float mAnchorU = Marker.ANCHOR_CENTER, mAnchorV = Marker.ANCHOR_CENTER;
    /**
     * anchor point to draw the number of markers inside the cluster icon
     */
    public float mTextAnchorU = Marker.ANCHOR_CENTER, mTextAnchorV = Marker.ANCHOR_CENTER;
    protected int mMaxClusteringZoomLevel = 17;
    protected int mRadiusInPixels = 100;
    protected double mRadiusInMeters;
    protected Paint mTextPaint;
    private ArrayList<Marker> mClonedMarkers;
    private Context mContext;

    public RadiusMarkerClusterer(Context ctx) {
        super();
        mTextPaint = new Paint();
        mTextPaint.setColor(Color.WHITE);
        mTextPaint.setTextSize(15 * ctx.getResources().getDisplayMetrics().density);
        mTextPaint.setFakeBoldText(true);
        mTextPaint.setTextAlign(Paint.Align.CENTER);
        mTextPaint.setAntiAlias(true);
        Drawable clusterIconD = ctx.getResources().getDrawable(org.osmdroid.bonuspack.R.drawable.marker_cluster);
        Bitmap clusterIcon = ((BitmapDrawable) clusterIconD).getBitmap();
        setIcon(clusterIcon);
        mContext = ctx;
    }

    /**
     * If you want to change the default text paint (color, size, font)
     */
    public Paint getTextPaint() {
        return mTextPaint;
    }

    /**
     * Set the radius of clustering in pixels. Default is 100px.
     */
    public void setRadius(int radius) {
        mRadiusInPixels = radius;
    }

    /**
     * Set max zoom level with clustering. When zoom is higher or equal to this level, clustering is disabled.
     * You can put a high value to disable this feature.
     */
    public void setMaxClusteringZoomLevel(int zoom) {
        mMaxClusteringZoomLevel = zoom;
    }

    /**
     * Radius-Based clustering algorithm
     */
    @Override
    public ArrayList<org.osmdroid.bonuspack.clustering.StaticCluster> clusterer(MapView mapView) {

        ArrayList<org.osmdroid.bonuspack.clustering.StaticCluster> clusters = new ArrayList<org.osmdroid.bonuspack.clustering.StaticCluster>();
        convertRadiusToMeters(mapView);

        mClonedMarkers = new ArrayList<Marker>(mItems); //shallow copy
        while (!mClonedMarkers.isEmpty()) {
            Marker m = mClonedMarkers.get(0);
            org.osmdroid.bonuspack.clustering.StaticCluster cluster = createCluster(m, mapView);
            clusters.add(cluster);
        }
        return clusters;
    }

    private org.osmdroid.bonuspack.clustering.StaticCluster createCluster(Marker m, MapView mapView) {
        GeoPoint clusterPosition = m.getPosition();

        org.osmdroid.bonuspack.clustering.StaticCluster cluster = new org.osmdroid.bonuspack.clustering.StaticCluster(clusterPosition);
        cluster.add(m);

        mClonedMarkers.remove(m);

        if (mapView.getZoomLevel() > mMaxClusteringZoomLevel) {
            //above max level => block clustering:
            return cluster;
        }

        Iterator<Marker> it = mClonedMarkers.iterator();
        while (it.hasNext()) {
            Marker neighbour = it.next();
            double distance = clusterPosition.distanceToAsDouble(neighbour.getPosition());
            if (distance <= mRadiusInMeters) {
                cluster.add(neighbour);
                it.remove();
            }
        }

        return cluster;
    }

    @Override
    public Marker buildClusterMarker(org.osmdroid.bonuspack.clustering.StaticCluster cluster, MapView mapView) {
        Marker m = new Marker(mapView);
        m.setPosition(cluster.getPosition());
        m.setInfoWindow(null);
        m.setAnchor(mAnchorU, mAnchorV);
        Log.e("cluster size", cluster.getSize() + "");

        int clusterSize = cluster.getSize();
        if (clusterSize < 1000 && clusterSize > 500) {
            Drawable clusterIconD = ResourcesCompat.getDrawable(mContext.getResources(), R.drawable.red_cluster, null);
            mClusterIcon = ((BitmapDrawable) Objects.requireNonNull(clusterIconD)).getBitmap();
        } else if (clusterSize > 50) {
            Drawable clusterIconD = ResourcesCompat.getDrawable(mContext.getResources(), R.drawable.red_cluster, null);
            mClusterIcon = ((BitmapDrawable) Objects.requireNonNull(clusterIconD)).getBitmap();
        } else {
            Drawable clusterIconD = ResourcesCompat.getDrawable(mContext.getResources(), R.drawable.cluster, null);
            mClusterIcon = ((BitmapDrawable) Objects.requireNonNull(clusterIconD)).getBitmap();
        }
        Bitmap finalIcon = Bitmap.createBitmap(mClusterIcon.getWidth(), mClusterIcon.getHeight(), mClusterIcon.getConfig());
        Canvas iconCanvas = new Canvas(finalIcon);
        iconCanvas.drawBitmap(mClusterIcon, 0, 0, null);
        String text = "" + cluster.getSize();
        int textHeight = (int) (mTextPaint.descent() + mTextPaint.ascent());
        iconCanvas.drawText(text,
                mTextAnchorU * finalIcon.getWidth(),
                mTextAnchorV * finalIcon.getHeight() - textHeight / 2,
                mTextPaint);
        m.setIcon(new BitmapDrawable(mapView.getContext().getResources(), finalIcon));
        // swapFunction(cluster.getSize());
        return m;
    }

    @Override
    public void renderer(ArrayList<org.osmdroid.bonuspack.clustering.StaticCluster> clusters, Canvas canvas, MapView mapView) {
        for (StaticCluster cluster : clusters) {
            if (cluster.getSize() == 1) {
                //cluster has only 1 marker => use it as it is:
                cluster.setMarker(cluster.getItem(0));
            } else {
                //only draw 1 Marker at Cluster center, displaying number of Markers contained
                Marker m = buildClusterMarker(cluster, mapView);
                cluster.setMarker(m);
            }
            Log.e("cluster size", cluster.getSize() + "");
        }


        //swapFunction(clusters, mapView);
    }

    private void convertRadiusToMeters(MapView mapView) {

        Rect mScreenRect = mapView.getIntrinsicScreenRect(null);

        int screenWidth = mScreenRect.right - mScreenRect.left;
        int screenHeight = mScreenRect.bottom - mScreenRect.top;

        BoundingBox bb = mapView.getBoundingBox();

        double diagonalInMeters = bb.getDiagonalLengthInMeters();
        double diagonalInPixels = Math.sqrt(screenWidth * screenWidth + screenHeight * screenHeight);
        double metersInPixel = diagonalInMeters / diagonalInPixels;

        mRadiusInMeters = mRadiusInPixels * metersInPixel;
    }

}

在您的地图中添加以下代码activity

GeoPoint startPoint = new GeoPoint(20.5992, 72.9342);
       /* Drawable clusterIconD = ResourcesCompat.getDrawable(getResources(), R.drawable.cluster, null);
        Bitmap clusterIcon = ((BitmapDrawable) Objects.requireNonNull(clusterIconD)).getBitmap();*/
        RadiusMarkerClusterer poiMarkers = new RadiusMarkerClusterer(this, this);
        // poiMarkers.setIcon(clusterIcon);
        poiMarkers.mTextAnchorU = 0.50f;
        poiMarkers.mTextAnchorV = 0.50f;
        poiMarkers.getTextPaint().setTextSize(12 * getResources().getDisplayMetrics().density);
        poiMarkers.mAnchorV = Marker.ANCHOR_CENTER;
        poiMarkers.setRadius(500);
        mapView.getOverlays().add(poiMarkers);
        for (LiveTrackingModel al : list) {
            Marker poiMarker = new Marker(mapView);
            poiMarker.setTitle(al.getVEHICLE_NUMBER());
            poiMarker.setPosition(new GeoPoint(Double.parseDouble(al.getLAT()), Double.parseDouble(al.getLON())));
            poiMarker.setIcon(this.getResources().getDrawable(R.drawable.compactor_running));
            poiMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);

           /* InfoWindow infoWindow = new MyInfoWindow(R.layout.bonuspack_bubble, mMapView);
            startMarker.setInfoWindow(infoWindow);*/
            //poiMarker.setInfoWindow();
            //poiMarker.setRelatedObject(poi);
            poiMarkers.add(poiMarker);
        }
        poiMarkers.buildClusterMarker(new StaticCluster(startPoint), mapView);
        poiMarkers.clusterer(mapView);