使用osmdroid根据群集大小更改群集颜色

时间:2018-09-06 18:05:18

标签: android openstreetmap osmdroid

我正在尝试根据群集大小在地图上使用不同颜色的群集。

为此,我子类化 MarkerClusterer ,并根据我的要求更改了代码。

下面是代码

public class CustomMarkerClusterer extends MarkerClusterer {

protected int mMaxClusteringZoomLevel = 17;
protected int mRadiusInPixels = 100;
protected double mRadiusInMeters;
protected Paint mTextPaint;
private ArrayList<Marker> mClonedMarkers;
private Context context;

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

public CustomMarkerClusterer(Context ctx) {
    super();
    mTextPaint = new Paint();
    mTextPaint.setColor(Color.BLACK);
    mTextPaint.setTextSize(15 * ctx.getResources().getDisplayMetrics().density);
    mTextPaint.setFakeBoldText(true);
    mTextPaint.setTextAlign(Paint.Align.CENTER);
    mTextPaint.setAntiAlias(true);
    this.context = ctx;
    Drawable clusterIconD = ctx.getResources().getDrawable(R.drawable.cluster2);
    Bitmap clusterIcon = ((BitmapDrawable) clusterIconD).getBitmap();
    setIcon(clusterIcon);
}

/**
 * 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<StaticCluster> clusterer(MapView mapView) {

    ArrayList<StaticCluster> clusters = new ArrayList<StaticCluster>();
    convertRadiusToMeters(mapView);

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

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

    StaticCluster cluster = new 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(StaticCluster cluster, MapView mapView) {
    Marker m = new Marker(mapView);
    m.setPosition(cluster.getPosition());
    m.setInfoWindow(null);
    m.setAnchor(mAnchorU, mAnchorV);
    Bitmap mutableBitmap=null;

    if (cluster.getSize() < 10) {
        Bitmap icon = Bitmap.createBitmap(((BitmapDrawable) context.getResources().getDrawable(R.drawable.cluster1)).getBitmap());
        mutableBitmap = icon.copy(Bitmap.Config.ARGB_8888, true);

        Canvas iconCanvas = new Canvas(mutableBitmap);
        iconCanvas.drawBitmap(mClusterIcon, 0, 0, null);
        String text = "" + cluster.getSize();
        int textHeight = (int) (mTextPaint.descent() + mTextPaint.ascent());
        iconCanvas.drawText(text,
                mTextAnchorU * icon.getWidth(),
                mTextAnchorV * icon.getHeight() - textHeight / 2,
                mTextPaint);
       // m.setIcon(new BitmapDrawable(mapView.getContext().getResources(), mutableBitmap));
    } else if (cluster.getSize() > 10 && cluster.getSize() < 100) {
        Bitmap icon = Bitmap.createBitmap(((BitmapDrawable) context.getResources().getDrawable(R.drawable.cluster3)).getBitmap());
         mutableBitmap = icon.copy(Bitmap.Config.ARGB_8888, true);
        Canvas iconCanvas = new Canvas(mutableBitmap);
        iconCanvas.drawBitmap(mClusterIcon, 0, 0, null);
        String text = "" + cluster.getSize();
        int textHeight = (int) (mTextPaint.descent() + mTextPaint.ascent());
        iconCanvas.drawText(text,
                mTextAnchorU * icon.getWidth(),
                mTextAnchorV * icon.getHeight() - textHeight / 2,
                mTextPaint);
       // m.setIcon(new BitmapDrawable(mapView.getContext().getResources(), mutableBitmap));
    } else if (cluster.getSize() > 100) {
        Bitmap icon = Bitmap.createBitmap(((BitmapDrawable) context.getResources().getDrawable(R.drawable.cluster2)).getBitmap());
        mutableBitmap = icon.copy(Bitmap.Config.ARGB_8888, true);
        Canvas iconCanvas = new Canvas(mutableBitmap);
        iconCanvas.drawBitmap(mClusterIcon, 0, 0, null);
        String text = "" + cluster.getSize();
        int textHeight = (int) (mTextPaint.descent() + mTextPaint.ascent());
        iconCanvas.drawText(text,
                mTextAnchorU * icon.getWidth(),
                mTextAnchorV * icon.getHeight() - textHeight / 2,
                mTextPaint);
      //  m.setIcon(new BitmapDrawable(mapView.getContext().getResources(), mutableBitmap));
    }
    m.setIcon(new BitmapDrawable(mapView.getContext().getResources(), mutableBitmap));

    return m;
}

@Override
public void renderer(ArrayList<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);
        }
    }
}

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

buildClusterMarker()是我尝试根据群集的大小将其他图像分配给群集的方法。

当我调试代码时,它可以正常工作,但它只能设置在类的构造函数中定义的单色群集。如果我在那里更改图像,则它会更改,但适用于所有群集。

1 个答案:

答案 0 :(得分:2)

buildClusterMakerMethod()中有三个类似的分支(如果有代码),这是第一个分支:

    Bitmap icon = Bitmap.createBitmap(((BitmapDrawable) context.getResources().getDrawable(R.drawable.cluster1)).getBitmap());
    mutableBitmap = icon.copy(Bitmap.Config.ARGB_8888, true);

    Canvas iconCanvas = new Canvas(mutableBitmap);
    iconCanvas.drawBitmap(mClusterIcon, 0, 0, null); //<=== HERE
    ...

让我们逐行浏览代码。

1)从可绘制R.drawable.cluster1创建了一个位图,并将其存储在icon变量中。

2)图标的副本存储在mutableBitmap变量中。

3)mutableBitmap用于创建画布。这意味着,在画布上执行的所有操作都将被绘制到该位图中。

4)原始图标(存储在mClusterIcon域中)在所需位图上绘制在画布上,从而用构造函数中设置的图标/位图覆盖。

这发生在所有3个分支上。

您可以删除所有出现的行(iconCanvas.drawBitmap(mClusterIcon, 0, 0, null);来解决问题。