Skip to content

Instantly share code, notes, and snippets.

@wviana
Created March 22, 2016 12:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wviana/ae07cafe4526f167e0d1 to your computer and use it in GitHub Desktop.
Save wviana/ae07cafe4526f167e0d1 to your computer and use it in GitHub Desktop.
package neocom.dealerbook.models.layer.presenters;
import com.androidmapsextensions.GoogleMap;
import com.androidmapsextensions.TileOverlay;
import com.androidmapsextensions.TileOverlayOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.maps.android.heatmaps.HeatmapTileProvider;
import java.util.List;
import neocom.dealerbook.models.layer.dataAdapter.LayerDataAdapter;
/**
* Created by wviana on 04/03/16.
*/
public class HeatPresenter implements LayerPresenter {
protected HeatmapTileProvider tileProvider;
protected TileOverlay tileOverlay;
@Override
public void present(LayerDataAdapter data, GoogleMap map) {
updateTileProvider(data.getLatLngList());
if(tileOverlay == null && tileProvider != null) {
tileOverlay = createTileProvider(map);
}
}
protected TileOverlay createTileProvider(GoogleMap map) {
return map.addTileOverlay(new TileOverlayOptions().tileProvider(tileProvider));
}
private void updateTileProvider(List<LatLng> points) {
if(tileProvider == null){
tileProvider = new HeatmapTileProvider.Builder()
.data(points)
.build();
} else {
tileProvider.setData(points);
if (tileOverlay != null) tileOverlay.clearTileCache();
}
}
@Override
public void clear() {
if (tileOverlay != null) {
tileOverlay.remove();
tileOverlay = null;
}
}
}
package neocom.dealerbook.models.layer.presenters;
import com.androidmapsextensions.GoogleMap;
import com.cocoahero.android.geojson.GeoJSON;
import com.cocoahero.android.geojson.GeoJSONObject;
import neocom.dealerbook.models.layer.dataAdapter.LayerDataAdapter;
/**
* Created by wviana on 03/03/16.
*/
public interface LayerPresenter {
void present(LayerDataAdapter data, GoogleMap map);
void clear();
}
package neocom.dealerbook.models.layer.presenters;
import android.graphics.Color;
import android.support.annotation.NonNull;
import android.util.Log;
import com.androidmapsextensions.GoogleMap;
import com.androidmapsextensions.TileOverlay;
import com.androidmapsextensions.TileOverlayOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.maps.android.geometry.Point;
import com.google.maps.android.heatmaps.Gradient;
import com.google.maps.android.heatmaps.HeatmapTileProvider;
import com.google.maps.android.heatmaps.WeightedLatLng;
import com.google.maps.android.projection.SphericalMercatorProjection;
import org.apache.commons.math3.ml.clustering.CentroidCluster;
import org.apache.commons.math3.ml.clustering.KMeansPlusPlusClusterer;
import java.util.ArrayList;
import java.util.List;
import neocom.dealerbook.models.layer.dataAdapter.LayerDataAdapter;
import neocom.dealerbook.models.layer.dataAdapter.WeightedLatLngWrapper;
/**
* Created by wviana on 04/03/16.
*/
public class WeightedHeatPresenter extends HeatPresenter {
public static final int CLUSTER_NUMBER = 5;
public static final int CLUSTER_MAX_ITERATIONS = 10;
public static final int HEAT_RADIUS_SIZE = 40;
private final int[] colors = {
Color.rgb(254, 217, 118),
Color.rgb(254, 178, 76),
Color.rgb(253, 141, 60),
Color.rgb(252, 78, 42),
Color.rgb(227, 26, 28),
Color.rgb(177, 0, 38)
};
private final float[] range = {0.4f, 0.5f, 0.6f, 0.7f, 0.9f, 1f};
@Override
public void present(LayerDataAdapter data, GoogleMap map) {
LatLngBounds currentBound = map.getProjection().getVisibleRegion().latLngBounds;
List<WeightedLatLng> showablePoints = filterByBound(data, currentBound);
if (showablePoints.size() > CLUSTER_NUMBER) {
showablePoints = normalizePoints(showablePoints);
}
updateTileProvider(showablePoints);
if(tileOverlay == null && tileProvider != null) {
tileOverlay = createTileProvider(map);
}
}
@NonNull
private List<WeightedLatLng> normalizePoints(List<WeightedLatLng> pointsInsideBound) {
List<WeightedLatLngWrapper> wrapperedPoints = WeightedLatLngWrapper.wrappeList(pointsInsideBound);
KMeansPlusPlusClusterer<WeightedLatLngWrapper> clusterer = new KMeansPlusPlusClusterer<>(CLUSTER_NUMBER, CLUSTER_MAX_ITERATIONS);
List<CentroidCluster<WeightedLatLngWrapper>> clusterResults = clusterer.cluster(wrapperedPoints);
List<WeightedLatLng> reValuedPoints = new ArrayList<>();
for(CentroidCluster<WeightedLatLngWrapper> cluster : clusterResults){
for (WeightedLatLngWrapper point : cluster.getPoints()){
LatLng latLng = pointToLatLng(point.getWeightedLatLng().getPoint());
double value = cluster.getCenter().getPoint()[0];
reValuedPoints.add(new WeightedLatLng(latLng, value));
}
}
return reValuedPoints;
}
@NonNull
private List<WeightedLatLng> filterByBound(LayerDataAdapter data, LatLngBounds currentBound) {
List<WeightedLatLng> pointsInsideBound = new ArrayList<>();
for (WeightedLatLng point : data.getWeightedLatLngList()){
LatLng pointLL = pointToLatLng(point.getPoint());
if (currentBound.contains(pointLL)){
pointsInsideBound.add(point);
}
}
return pointsInsideBound;
}
private LatLng pointToLatLng(Point point1) {
SphericalMercatorProjection projection = new SphericalMercatorProjection(1.0D);
return projection.toLatLng(point1);
}
//TODO refactoring de HeatPresenter ser super classe.
private void updateTileProvider(List<WeightedLatLng> points) {
try {
if(tileProvider == null){
tileProvider = new HeatmapTileProvider.Builder()
.weightedData(points)
.radius(HEAT_RADIUS_SIZE)
.gradient(new Gradient(colors, range))
.build();
} else {
tileProvider.setWeightedData(points);
if (tileOverlay != null) tileOverlay.clearTileCache();
}
} catch (IllegalArgumentException e) {
//clear();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment