出于某种原因,需要把百度地图中的聚合方法在java中实现,自己写了一份。

当时做的功能是把聚合后的点存入数据库中,并且需要计算的数值比较多,因此显得麻烦些,我已经把代码进行了一些删减。(本来是想提供一个更纯净的版本的,但是这个两年前的代码,实在是有点忘了,并且现在也并不需要使用,不打算再读一遍。等真正需要的时候再重写一份吧。)

其中DaoHelper是调用sql的公共方法,IClusterOpt 存储一些配置信息,比如地图缩放比等等。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.DaoHelper;
import com.util.bean.IClusterOpt;
import com.XUtils;
/**
 * 基于半径的点聚合
 * @author Administrator
 */
public class MarkerClusterUtil {

	//[1:20米,50米,100米,200米,500米,1公里,2公里,5公里,10公里,20公里,25公里,50公里,100公里,200公里,500公里,1000公里,2000公里,5000公里,10000公里]
	//[19级,    18级,17级,  16级,  15级,  14级, 13级,  12级,  11级,   10级,    9级,     8级,      7级,        6级,       5级,       4级,          3级,         2级,          1级]
	
	@SuppressWarnings("unchecked")
	private Map<String, Double> zoomRadius = new HashMap(){
		{
//			this.put("18", 30d);
//			this.put("17", 60d);
//			this.put("16", 120d);
//			this.put("15", 300d);
//			this.put("14", 600d);
//			this.put("13", 1200d);
//			this.put("12", 3000d);
//			this.put("11", 6000d);
//			this.put("10", 12000d);
//			this.put("9", 15000d);
			
			this.put("18", 62.5d);
			this.put("17", 125d);
			this.put("16", 250d);
			this.put("15", 625d);
			this.put("14", 1250d);
			this.put("13", 2500d);	//12500d
			this.put("12", 6250d);
			this.put("11", 12500d);
			this.put("10", 25000d);
			this.put("9", 31250d);
		}
	};
	
	private List<Map<String, String>> markers = new ArrayList<Map<String,String>>();
	private List<Cluster> clusters = new ArrayList(2048);
	private String[] zooms;
	
	private String sql;
	private DaoHelper daoHelper = XUtils.getDaoHelper();
	/**
	 *  select  '20171212', '2101', '17', 
	 */
	private StringBuffer aSql;
	
	public void createCluster(List<Map<String, String>> markers, IClusterOpt opt) throws Exception{
		this.clusters = new ArrayList(2048);
		this.markers = markers;
		this.zooms = opt.getZooms();
		
		//check
		if(markers == null || markers.size() == 0){
			throw new Exception("markers null");
		}
		for(String tz : zooms){
			if(!zoomRadius.containsKey(tz)){
				throw new Exception("zoom undefined");
			}
		}
		//check
		
		
		StringBuffer sb = new StringBuffer(" select '" + “” + "', '");
		for(String zoom : this.zooms){
			aSql = new StringBuffer(sb.toString() + "'" + zoom + "', ");
			Double radius = this.zoomRadius.get(zoom);
			this.clusters = this.doCluster(markers, radius);
			this.thisClustersToDb();
			this.clusters = new ArrayList(2048);
		}
	}
	
	private void thisClustersToDb(){
		int cacheNum = 20;
		List<Cluster> cacheClusters = new ArrayList(22);
		for(int i = 0; i < this.clusters.size(); i++){
			cacheClusters.add(this.clusters.get(i));
			if(i % cacheNum == (cacheNum - 1)){
				this.doInsert(cacheClusters);
				cacheClusters = new ArrayList(cacheNum + 5);
			}
		}
		this.doInsert(cacheClusters);
		cacheClusters = new ArrayList(22);
	}
	
	private void doInsert(List<Cluster> cl){
		if(cl == null || cl.size() == 0)
			return;
		StringBuffer sb = new StringBuffer();
		sb.append(" insert into map_cluster(id, zoom, cluster_num, lng, lat, ");
		sb.append(" gh1_num, kd2_num, gh3_num, kd4_num, ");
		sb.append(" gh5_num, kd6_num, gh7_fee_a, kd8_fee_a) ");
		
		sb.append(" select seq_cluster.nextval, t1.* from ( ");
		for(int i = 0; i < cl.size(); i++){
			
			Cluster cluster = cl.get(i);
			sb.append(this.aSql);
			sb.append("" + cluster.getExtInfo().get("cNum") + " c , ");
			sb.append("" + cluster.getCenter().getLng() + " a , ");
			sb.append("" + cluster.getCenter().getLat() + " b , ");
			sb.append("" + cluster.getExtInfo().get("a") + " d , ");
			sb.append("" + cluster.getExtInfo().get("b") + " e , ");
			sb.append("" + cluster.getExtInfo().get("c") + " f , ");
			sb.append("" + cluster.getExtInfo().get("d") + " g , ");
			sb.append("" + cluster.getExtInfo().get("e") + " h , ");
			sb.append("" + cluster.getExtInfo().get("f") + " i , ");
			sb.append("" + cluster.getExtInfo().get("g") + " j , ");
			sb.append("" + cluster.getExtInfo().get("h") + " k  ");
			sb.append(" from dual ");
			if(i != cl.size() - 1){
				sb.append(" union all ");
			}
		}
		sb.append(" ) t1 ");
		Map daoMap = new HashMap(2);
		daoMap.put("sql", sb.toString());
		System.out.println(daoMap.get("sql"));
		daoHelper.insert("clusterer.map.cacheSql", daoMap);
		sb = null;
	}
	
	private List<Cluster> doCluster(List<Map<String, String>> markers, Double radius){
		this.clusters = new ArrayList(2048);
		
		for(int i = 0; i < markers.size(); i++){
			int cIndex = -1;
			Double distance = 99999999d;
			Point tempMarkerPoint = 
					new Point(Double.valueOf(markers.get(i).get("m")), Double.valueOf(markers.get(i).get("l")));
			for(int j = 0; j < this.clusters.size(); j++){
				Double tempDistince = this.clusters.get(j).getDistance(tempMarkerPoint);
				if(tempDistince < distance){
					distance = tempDistince;
					cIndex = j;
				}
			}
			
			if(cIndex == -1 || distance > radius){
				Cluster cluster = new Cluster(tempMarkerPoint, radius, markers.get(i));
				this.clusters.add(cluster);
			}else {
				this.clusters.get(cIndex).addMarker(markers.get(i), tempMarkerPoint);
			}
			
			if(i % 1000 == 0){
				System.out.println(i);
			}
		}
		
		for(int i = 0; i < this.clusters.size(); i++){
			this.clusters.get(i).finish();
		}
		
		return this.clusters;
	}
	
	static class Cluster{
		Point center;
		//String text;
		Double r;
		private List<Map<String, String>> markers = new ArrayList<Map<String,String>>(50);
		Map<String, String> extInfo = new HashMap(16);
		
		Cluster(Point center, Double r){
			this.center = center;
			this.r = r;
		}
		
		Cluster(Point center, Double r, Map<String, String> marker){
			this.center = center;
			this.r = r;
			this.markers.add(marker);
		}
		
		private void updateCenter(Point point){
			this.center.setLng(this.center.getLng() * this.markers.size() / (this.markers.size() + 1) + 
					point.getLng() / (this.markers.size() + 1));
			this.center.setLat(this.center.getLat() * this.markers.size() / (this.markers.size() + 1) + 
					point.getLat() / (this.markers.size() + 1));
		}
		
		public void finish(){
			Double a = 0d;
			Double b = 0d;
			Double c = 0d;
			Double d = 0d;
			Double e = 0d;
			Double f = 0d;
			Double g = 0d;
			Double h = 0d;
			for(int i = 0; i < this.markers.size(); i++){
				a += Double.valueOf(this.markers.get(i).get("A"));
				b += Double.valueOf(this.markers.get(i).get("B"));
				c += Double.valueOf(this.markers.get(i).get("C"));
				d += Double.valueOf(this.markers.get(i).get("D"));
				e += Double.valueOf(this.markers.get(i).get("E"));
				f += Double.valueOf(this.markers.get(i).get("F"));
				g += Double.valueOf(this.markers.get(i).get("G"));
				h += Double.valueOf(this.markers.get(i).get("H"));
			}
			this.extInfo.put("cNum", this.markers.size() + "");
			this.extInfo.put("a", a + "");
			this.extInfo.put("b", b + "");
			this.extInfo.put("c", c + "");
			this.extInfo.put("d", d + "");
			this.extInfo.put("e", e + "");
			this.extInfo.put("f", f + "");
			this.extInfo.put("g", g + "");
			this.extInfo.put("h", h + "");
			
			this.markers = null;
		}
		
		public void addMarker(Map<String, String> allInfo, Point point){
			this.updateCenter(point);
			this.markers.add(allInfo);
		}
		
		public boolean isPointContains(Point point){
			return getDistance(point) < r ? true : false;
		}
		
		public Double getDistance(Point point){
			return MapUtil.getDistance(center.getLat(), center.getLng(), point.getLat(), point.getLng());
		}
		
//		public void addExtInfo(String key, String value){
//			if(this.extNumInfo.containsKey(key))
//				this.extNumInfo.put(key, this.extNumInfo.get(key) + value);
//			else
//				this.extNumInfo.put(key, value);
//		}
		
		public Point getCenter() {
			return center;
		}
		public void setCenter(Point center) {
			this.center = center;
		}
//		public String getText() {
//			return text;
//		}
//		public void setText(String text) {
//			this.text = text;
//		}
		public double getR() {
			return r;
		}
		public void setR(Double r) {
			this.r = r;
		}

		public Map<String, String> getExtInfo() {
			return extInfo;
		}
		
		
	}
	
	static class Point{
		double lng;
		double lat;
		Point(double lng, double lat){
			this.lng = lng;
			this.lat = lat;
		}
		public double getLng() {
			return lng;
		}
		public void setLng(double lng) {
			this.lng = lng;
		}
		public double getLat() {
			return lat;
		}
		public void setLat(double lat) {
			this.lat = lat;
		}
		
	}

	public String getSql() {
		return sql;
	}
	
	
}