Android Open Source - SmartNavi Grid Marker Clusterer






From Project

Back to project page SmartNavi.

License

The source code is released under:

Apache License

If you think the Android project SmartNavi listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package org.osmdroid.bonuspack.clustering;
/*  w ww. j a v a  2 s  . c  o m*/
import java.util.ArrayList;
import org.osmdroid.bonuspack.overlays.Marker;
import org.osmdroid.util.BoundingBoxE6;
import org.osmdroid.views.MapView;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.support.v4.util.LongSparseArray;

/** 
 * Grid-based Clustering algorithm: all markers inside the same cell belong to the same cluster. 
 * The grid size is specified in screen pixels. <br/>
 * 
 * TODO: check what happens with map rotation. <br/>
 * TODO: clustering is not perfectly stable: if you zoom in then out, the mapview lat/lon span may change a little bit,
 * potentially changing the grid positioning. <br/>
 * 
 * Largely inspired from (open source) Google Maps Android utility library. 
 * 
 * @see https://github.com/googlemaps/android-maps-utils
 * @author M.Kergall
 *
 */
public class GridMarkerClusterer extends MarkerClusterer {

  protected int mGridSize = 50; //in pixels
  protected Paint mTextPaint;
  
  /** 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 GridMarkerClusterer(Context ctx) {
    super(ctx);
    mTextPaint = new Paint();
    mTextPaint.setColor(Color.WHITE);
    mTextPaint.setTextSize(15.0f);
    mTextPaint.setFakeBoldText(true);
    mTextPaint.setTextAlign(Paint.Align.CENTER);
    mTextPaint.setAntiAlias(true);
  }

  /** If you want to change the default text paint (color, size, font) */
  public Paint getTextPaint(){
    return mTextPaint;
  }
  
  /** Change the size of the clustering grid, in pixels. Default is 50px. */
  public void setGridSize(int gridSize){
    mGridSize = gridSize;
  }

  /** Grid-based clustering algorithm */
  @Override public ArrayList<StaticCluster> clusterer(MapView mapView){
    Rect mScreenRect = mapView.getIntrinsicScreenRect(null);
    
    BoundingBoxE6 bb = mapView.getBoundingBox();
    double latSpan = bb.getLatitudeSpanE6()*1E-6;
    double lonSpan = bb.getLongitudeSpanE6()*1E-6;
    //Log.d("ZOOM", "latSpan="+latSpan+"  lonSpan="+lonSpan);
    
    //convert grid size from pixels to degrees:
    double gridSizeX, gridSizeY;
    gridSizeX = lonSpan * (double)mGridSize / (double)(mScreenRect.right - mScreenRect.left);
    gridSizeY = latSpan * (double)mGridSize / (double)(mScreenRect.bottom - mScreenRect.top);
    
    int numCellsW = (int)(360.0f/gridSizeX);
    //Log.d("ZOOM", "zoomlevel="+mapView.getZoomLevel()+"  cells="+numCellsW);
    //Log.d("ZOOM", "gridSizeX="+gridSizeX+"  gridSizeY="+gridSizeY);
    
    ArrayList<StaticCluster> clusters = new ArrayList<StaticCluster>();
    LongSparseArray<StaticCluster> sparseArray = new LongSparseArray<StaticCluster>();
    for (Marker item:mItems){
      //TODO - add 180 Degree to prevent negative values
      long gridX = (long)(item.getPosition().getLongitude() / gridSizeX);
      long gridY = (long)(item.getPosition().getLatitude() / gridSizeY);
      long coord = numCellsW * gridX + gridY;
      StaticCluster cluster = sparseArray.get(coord);
      //Log.d("ZOOM", "coord="+coord+" =>cluster:"+(cluster==null?"new":"add"));
      if (cluster == null) {
        //GeoPoint clusterCorner = new GeoPoint(gridSizeY*(double)gridY, gridSizeX*(double)gridX);
                cluster = new StaticCluster(item.getPosition() /*clusterCorner*/);
                sparseArray.put(coord, cluster);
                clusters.add(cluster);
      }
            cluster.add(item);
    }
    return clusters;
  }
  
  /** Build the marker for a cluster. 
   * Uses the cluster icon, and displays inside the number of markers it contains. <br/>
   * In the standard Google coordinate system for Marker icons: <br/>
   * - The cluster icon is anchored at mAnchorU, mAnchorV. <br/>
   * - The text showing the number of markers is anchored at mTextAnchorU, mTextAnchorV. 
   * This text is centered horizontally and vertically. */
  @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 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));
    return m;
  }
  
  /** Build clusters markers to be used at next draw */
  @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);
      }
    }
  }
  
}




Java Source Code List

com.ilm.sandwich.BuildConfig.java
com.ilm.sandwich.Config.java
com.ilm.sandwich.GoogleMapActivity.java
com.ilm.sandwich.Info.java
com.ilm.sandwich.MySupportMapFragment.java
com.ilm.sandwich.OsmMapActivity.java
com.ilm.sandwich.Settings.java
com.ilm.sandwich.Smartgeo.java
com.ilm.sandwich.StartChooser.java
com.ilm.sandwich.TouchableWrapper.java
com.ilm.sandwich.helferklassen.HttpRequests.java
com.ilm.sandwich.helferklassen.Locationer.java
com.ilm.sandwich.helferklassen.MapDownload.java
com.ilm.sandwich.helferklassen.MyItemizedOverlay.java
com.ilm.sandwich.helferklassen.PlacesAutoComplete.java
com.ilm.sandwich.helferklassen.PlacesTextSearch.java
com.ilm.sandwich.helferklassen.Rechnung.java
com.ilm.sandwich.helferklassen.SuggestionsAdapter.java
org.osmdroid.bonuspack.BuildConfig.java
org.osmdroid.bonuspack.BuildConfig.java
org.osmdroid.bonuspack.cachemanager.CacheManager.java
org.osmdroid.bonuspack.clustering.GridMarkerClusterer.java
org.osmdroid.bonuspack.clustering.MarkerClusterer.java
org.osmdroid.bonuspack.clustering.StaticCluster.java
org.osmdroid.bonuspack.kml.ColorStyle.java
org.osmdroid.bonuspack.kml.IconStyle.java
org.osmdroid.bonuspack.kml.KmlDocument.java
org.osmdroid.bonuspack.kml.KmlFeature.java
org.osmdroid.bonuspack.kml.KmlFolder.java
org.osmdroid.bonuspack.kml.KmlGeometry.java
org.osmdroid.bonuspack.kml.KmlGroundOverlay.java
org.osmdroid.bonuspack.kml.KmlLineString.java
org.osmdroid.bonuspack.kml.KmlMultiGeometry.java
org.osmdroid.bonuspack.kml.KmlPlacemark.java
org.osmdroid.bonuspack.kml.KmlPoint.java
org.osmdroid.bonuspack.kml.KmlPolygon.java
org.osmdroid.bonuspack.kml.LineStyle.java
org.osmdroid.bonuspack.kml.Style.java
org.osmdroid.bonuspack.location.FlickrPOIProvider.java
org.osmdroid.bonuspack.location.GeoNamesPOIProvider.java
org.osmdroid.bonuspack.location.GeocoderGisgraphy.java
org.osmdroid.bonuspack.location.GeocoderNominatimOld.java
org.osmdroid.bonuspack.location.GeocoderNominatim.java
org.osmdroid.bonuspack.location.NominatimPOIProvider.java
org.osmdroid.bonuspack.location.POI.java
org.osmdroid.bonuspack.location.PicasaPOIProvider.java
org.osmdroid.bonuspack.mapsforge.GenericMapView.java
org.osmdroid.bonuspack.mapsforge.MapsForgeTileModuleProvider.java
org.osmdroid.bonuspack.mapsforge.MapsForgeTileProvider.java
org.osmdroid.bonuspack.mapsforge.MapsForgeTileSource.java
org.osmdroid.bonuspack.overlays.DefaultInfoWindow.java
org.osmdroid.bonuspack.overlays.ExtendedOverlayItem.java
org.osmdroid.bonuspack.overlays.FolderOverlay.java
org.osmdroid.bonuspack.overlays.GroundOverlay.java
org.osmdroid.bonuspack.overlays.InfoWindow.java
org.osmdroid.bonuspack.overlays.ItemizedOverlayWithBubble.java
org.osmdroid.bonuspack.overlays.MapEventsOverlay.java
org.osmdroid.bonuspack.overlays.MapEventsReceiver.java
org.osmdroid.bonuspack.overlays.MarkerInfoWindow.java
org.osmdroid.bonuspack.overlays.Marker.java
org.osmdroid.bonuspack.overlays.Polygon.java
org.osmdroid.bonuspack.overlays.Polyline.java
org.osmdroid.bonuspack.routing.GoogleRoadManager.java
org.osmdroid.bonuspack.routing.MapQuestRoadManager.java
org.osmdroid.bonuspack.routing.OSRMRoadManager.java
org.osmdroid.bonuspack.routing.RoadLeg.java
org.osmdroid.bonuspack.routing.RoadManager.java
org.osmdroid.bonuspack.routing.RoadNode.java
org.osmdroid.bonuspack.routing.Road.java
org.osmdroid.bonuspack.utils.BonusPackHelper.java
org.osmdroid.bonuspack.utils.DouglasPeuckerReducer.java
org.osmdroid.bonuspack.utils.HttpConnection.java
org.osmdroid.bonuspack.utils.PolylineEncoder.java
org.osmdroid.bonuspack.utils.WebImageCache.java