From 20c517ab8752f968402ffe3ab496429cc96977d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E6=AD=A3=E5=AD=A6?= <zhengxue.lzx@antfin.com>
Date: Fri, 25 Jan 2019 11:36:11 +0800
Subject: [PATCH 1/9] feat(mapbox): add mapbox

---
 src/map/baseMap.js |   0
 src/map/mapbox.js  | 124 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 124 insertions(+)
 delete mode 100644 src/map/baseMap.js
 create mode 100644 src/map/mapbox.js

diff --git a/src/map/baseMap.js b/src/map/baseMap.js
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/src/map/mapbox.js b/src/map/mapbox.js
new file mode 100644
index 0000000000..3512c51150
--- /dev/null
+++ b/src/map/mapbox.js
@@ -0,0 +1,124 @@
+import Base from '../core/base';
+import Util from '../util';
+import { scene } from '../global';
+import * as THREE from '../core/three';
+const WORLD_SIZE = 512;
+export class MapBoxProvider extends Base {
+  getDefaultCfg() {
+    return Util.assign(scene, {
+      resizeEnable: true,
+      viewMode: '3D'
+    });
+  }
+  constructor(container, cfg, engine) {
+    super(cfg);
+    this.container = container;
+    this.engine = engine;
+    const scene = engine._scene;
+    this.initMap();
+    this.addOverLayer();
+    scene.position.x = scene.position.y = WORLD_SIZE / 2;
+    scene.matrixAutoUpdate = false;
+    setTimeout(() => {
+      this.emit('mapLoad');
+    }, 100);
+
+  }
+
+  initMap() {
+    mapboxgl.accessToken = 'pk.eyJ1IjoibHp4dWUiLCJhIjoiYnhfTURyRSJ9.Ugm314vAKPHBzcPmY1p4KQ';
+    this.map = new mapboxgl.Map(this._attrs);
+    this.map.on('move', () => {
+      this.updateCamera();
+    });
+    this.updateCamera();
+  }
+  asyncCamera() {
+    const engine = this.engine;
+    const camera = engine._camera;
+    const scene = engine._scene;
+    // Build a projection matrix, paralleling the code found in Mapbox GL JS
+    const fov = 0.6435011087932844;
+    const cameraToCenterDistance = 0.5 / Math.tan(fov / 2) * this.map.transform.height;
+    const halfFov = fov / 2;
+    const groundAngle = Math.PI / 2 + this.map.transform._pitch;
+    const topHalfSurfaceDistance = Math.sin(halfFov) * cameraToCenterDistance / Math.sin(Math.PI - groundAngle - halfFov);
+
+    // Calculate z distance of the farthest fragment that should be rendered.
+    const furthestDistance = Math.cos(Math.PI / 2 - this.map.transform._pitch) * topHalfSurfaceDistance + cameraToCenterDistance;
+
+    // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance`
+    const farZ = furthestDistance * 1.01;
+
+    camera.projectionMatrix = this.makePerspectiveMatrix(fov, this.map.transform.width / this.map.transform.height, 1, farZ);
+
+
+    const cameraWorldMatrix = new THREE.Matrix4();
+    const cameraTranslateZ = new THREE.Matrix4().makeTranslation(0, 0, cameraToCenterDistance);
+    const cameraRotateX = new THREE.Matrix4().makeRotationX(this.map.transform._pitch);
+    const cameraRotateZ = new THREE.Matrix4().makeRotationZ(this.map.transform.angle);
+
+    // Unlike the Mapbox GL JS camera, separate camera translation and rotation out into its world matrix
+    // If this is applied directly to the projection matrix, it will work OK but break raycasting
+    cameraWorldMatrix
+        .premultiply(cameraTranslateZ)
+        .premultiply(cameraRotateX)
+        .premultiply(cameraRotateZ);
+
+    camera.matrixWorld.copy(cameraWorldMatrix);
+
+
+    const zoomPow = this.map.transform.scale;
+    // Handle scaling and translation of objects in the map in the world's matrix transform, not the camera
+    const scale = new THREE.Matrix4();
+    const translateCenter = new THREE.Matrix4();
+    const translateMap = new THREE.Matrix4();
+    const rotateMap = new THREE.Matrix4();
+    scale
+        .makeScale(zoomPow, zoomPow, zoomPow);
+    translateCenter
+        .makeTranslation(WORLD_SIZE / 2, -WORLD_SIZE / 2, 0);
+    translateMap
+        .makeTranslation(-this.map.transform.x, this.map.transform.y, 0);
+    rotateMap
+        .makeRotationZ(Math.PI);
+
+    scene.matrix = new THREE.Matrix4();
+    scene.matrix
+        .premultiply(rotateMap)
+        .premultiply(translateCenter)
+        .premultiply(scale)
+        .premultiply(translateMap);
+  }
+  makePerspectiveMatrix(fovy, aspect, near, far) {
+    const out = new THREE.Matrix4();
+    const f = 1.0 / Math.tan(fovy / 2),
+      nf = 1 / (near - far);
+    const newMatrix = [
+      f / aspect, 0, 0, 0,
+      0, f, 0, 0,
+      0, 0, (far + near) * nf, -1,
+      0, 0, (2 * far * near) * nf, 0
+    ];
+    out.elements = newMatrix;
+    return out;
+  }
+
+  projectFlat(lnglat) {
+    return this.map.lngLatToGeodeticCoord(lnglat);
+  }
+  getCenter() {
+    return this.map.getCenter();
+  }
+  getCenterFlat() {
+    return this.projectFlat(this.getCenter());
+  }
+  addOverLayer() {
+    const canvasContainer = document.getElementById(this.container);
+    this.canvasContainer = canvasContainer;
+    this.renderDom = document.createElement('div');
+    this.renderDom.style.cssText += 'position: absolute;top: 0; z-index:1;height: 100%;width: 100%;pointer-events: none;';
+    this.renderDom.id = 'l7_canvaslayer';
+    canvasContainer.appendChild(this.renderDom);
+  }
+}

From b43a30e396ed1901338089e058842e0150d0b043 Mon Sep 17 00:00:00 2001
From: thinkinggis <lzx199065@gmail.com>
Date: Tue, 12 Feb 2019 20:21:14 +0800
Subject: [PATCH 2/9] feat(map): add mapbox

---
 src/core/controller/geom.js      | 36 ----------------------
 src/core/controller/map.js       | 24 +++++++++++++++
 src/core/engine/index.js         |  3 ++
 src/core/layer.js                |  4 +--
 src/core/scene.js                | 20 ++++++-------
 src/core/source.js               | 14 ++++-----
 src/core/three.js                |  1 +
 src/map/{provider.js => AMap.js} | 51 +++++++++++++++++++++++++++++---
 src/map/gaodeMap.js              |  2 +-
 src/map/index.js                 | 22 ++++++++++++++
 src/map/mapbox.js                | 51 +++++++++++++++++++++-----------
 11 files changed, 148 insertions(+), 80 deletions(-)
 delete mode 100644 src/core/controller/geom.js
 create mode 100644 src/core/controller/map.js
 rename src/map/{provider.js => AMap.js} (57%)
 create mode 100644 src/map/index.js

diff --git a/src/core/controller/geom.js b/src/core/controller/geom.js
deleted file mode 100644
index b0d474ac01..0000000000
--- a/src/core/controller/geom.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import geom from '../../geom/geom';
-import { GeoBuffer, bufferGeometry, Material } from '../../geom/index';
-
-
-// geom shape buffer geometry material
-// shape name type()
-// buffer  1:n  geometry
-// geometry
-//
-export default function polygonGeom(shape, coordinates, properties, layerid) {
-  const polygongeom = geom.polygon;
-  const { buffer, geometry, material } = polygongeom[shape];// polygon 映射表
-  const bufferData = new GeoBuffer[buffer]({
-    coordinates,
-    properties,
-    shape
-  });
-  bufferData.bufferStruct.name = layerid;
-  const bg = new bufferGeometry[geometry](bufferData.bufferStruct);
-  const mtl = Material[material]();
-  return {
-    geometry: bg,
-    mtl
-  };
-}
-
-export function pointGeom(shape, bufferData) {
-  const pointgeom = geom.point;
-  const { geometry, material } = pointgeom[shape];
-  const bg = new bufferGeometry[geometry](bufferData.bufferStruct);
-  const mtl = Material[material]();
-  return {
-    geometry: bg,
-    mtl
-  };
-}
diff --git a/src/core/controller/map.js b/src/core/controller/map.js
new file mode 100644
index 0000000000..3068e61cfe
--- /dev/null
+++ b/src/core/controller/map.js
@@ -0,0 +1,24 @@
+
+import { getMap } from '../../map';
+import Base from '../base';
+export default class MapContorller extends Base {
+  constructor(cfg, engine, scene) {
+    super(cfg);
+    this._engine = engine;
+    this.scene = scene;
+  }
+  _init() {
+    const mapType = this.get('mapType');
+    const mapCfg = this.get('mapCfg');
+    this.map = new getMap(mapType)(mapCfg);
+    this.map('mapLoad', this._mapload.bind(this));
+  }
+  _mapload() {
+    this.map.asyncCamera(this._engine);
+    this.emit('loaded');
+  }
+  _bindMapMethod() {
+
+  }
+
+}
diff --git a/src/core/engine/index.js b/src/core/engine/index.js
index d3a8eee42b..a12f2e06f6 100644
--- a/src/core/engine/index.js
+++ b/src/core/engine/index.js
@@ -11,6 +11,9 @@ export default class Engine extends EventEmitter {
     this._camera = new Camera(container).camera;
     this._renderer = new Renderer(container).renderer;
     this._world = world;
+    // for MapBox
+    this.world = new THREE.Group();
+    this._scene.add(this.world);
     this._picking = Picking(this._world, this._renderer, this._camera, this._scene);
     this.clock = new THREE.Clock();
   }
diff --git a/src/core/layer.js b/src/core/layer.js
index 50f2858587..4517ef695b 100644
--- a/src/core/layer.js
+++ b/src/core/layer.js
@@ -63,7 +63,8 @@ export default class Layer extends Base {
     const layerId = this._getUniqueId();
     this.layerId = layerId;
     this._activeIds = null;
-    scene._engine._scene.add(this._object3D);
+    const world = scene._engine.world;
+    world.add(this._object3D);
     this.layerMesh = null;
     this.layerLineMesh = null;
     this._initEvents();
@@ -110,7 +111,6 @@ export default class Layer extends Base {
     const { type = dataType } = cfg;
     cfg.data = data;
     cfg.mapType = this.get('mapType');
-
     this.layerSource = new source[type](cfg);
     // this.scene.workerPool.runTask({
     //   command: 'geojson',
diff --git a/src/core/scene.js b/src/core/scene.js
index 8879215fe2..115db9fdcd 100644
--- a/src/core/scene.js
+++ b/src/core/scene.js
@@ -3,8 +3,8 @@ import * as layers from '../layer';
 import Base from './base';
 import LoadImage from './image';
 import WorkerPool from './worker';
-import { MapProvider } from '../map/provider';
-import GaodeMap from '../map/gaodeMap';
+// import { MapProvider } from '../map/AMap';
+import { getMap } from '../map/index';
 import Global from '../global';
 export default class Scene extends Base {
   getDefaultCfg() {
@@ -13,7 +13,7 @@ export default class Scene extends Base {
   constructor(cfg) {
     super(cfg);
     this._initMap();
-    this._initAttribution();
+    // this._initAttribution();
     this.addImage();
     this._layers = [];
   }
@@ -29,16 +29,14 @@ export default class Scene extends Base {
   }
   _initMap() {
     this.mapContainer = this.get('id');
-    this._container = document.getElementById(this.mapContainer);
-    const Map = new MapProvider(this.mapContainer, this._attrs);
+    this.mapType = this.get('mapType');
+    const MapProvider = getMap(this.mapType);
+    const Map = new MapProvider(this._attrs);
+    Map.mixMap(this);
+    this._container = document.getElementById(Map.container);
+    // const Map = new MapProvider(this.mapContainer, this._attrs);
     Map.on('mapLoad', () => {
       this._initEngine(Map.renderDom);
-      const sceneMap = new GaodeMap(Map.map);
-      // eslint-disable-next-line
-      Object.getOwnPropertyNames(sceneMap.__proto__).forEach((key)=>{
-         // eslint-disable-next-line
-        if ('key' !== 'constructor') { this.__proto__[key] = sceneMap.__proto__[key]; }
-      });
       this.map = Map.map;
       Map.asyncCamera(this._engine);
       this.initLayer();
diff --git a/src/core/source.js b/src/core/source.js
index 3a61aead88..7b7cad5d10 100644
--- a/src/core/source.js
+++ b/src/core/source.js
@@ -1,12 +1,6 @@
-/*
- * @Author: ThinkGIS
- * @Date: 2018-06-08 11:19:06
- * @Last Modified by: mikey.zhaopeng
- * @Last Modified time: 2018-11-01 11:50:43
- */
 import Base from './base';
 const Controller = require('./controller/index');
-import { aProjectFlat } from '../geo/project';
+import { getMap } from '../map/index';
 export default class Source extends Base {
   getDefaultCfg() {
     return {
@@ -50,6 +44,8 @@ export default class Source extends Base {
   }
   _initControllers() {
     const defs = this.get('defs');
+    const mapType = this.get('mapType');
+    this.projectFlat = getMap(mapType).project;
     const scaleController = new Controller.Scale({
       defs
     });
@@ -83,8 +79,8 @@ export default class Source extends Base {
   }
   _coorConvert(geo) {
 
-    const ll = aProjectFlat(geo);
-    return [ ll.x, -ll.y, geo[2] || 0 ];
+    const ll = this.projectFlat(geo);
+    return [ ll.x, ll.y, geo[2] || 0 ];
 
   }
 
diff --git a/src/core/three.js b/src/core/three.js
index 75cbe58b5d..03359e840d 100644
--- a/src/core/three.js
+++ b/src/core/three.js
@@ -4,6 +4,7 @@ export { Scene } from 'three/src/scenes/Scene.js';
 export { WebGLRenderer } from 'three/src/renderers/WebGLRenderer.js';
 export { CanvasTexture } from 'three/src/textures/CanvasTexture.js';
 export { Object3D } from 'three/src/core/Object3D.js';
+export { Group } from 'three/src/objects/Group';
 export { Clock } from 'three/src/core/Clock';
 export { Points } from 'three/src/objects/Points.js';
 export { LineSegments } from 'three/src/objects/LineSegments.js';
diff --git a/src/map/provider.js b/src/map/AMap.js
similarity index 57%
rename from src/map/provider.js
rename to src/map/AMap.js
index 19763e8f45..e54615b94a 100644
--- a/src/map/provider.js
+++ b/src/map/AMap.js
@@ -1,18 +1,34 @@
 import Base from '../core/base';
+import { scene } from '../global';
 import * as Theme from '../theme/index';
 import Util from '../util';
-import { scene } from '../global';
 const DEG2RAD = Math.PI / 180;
-export class MapProvider extends Base {
+export default class GaodeMap extends Base {
   getDefaultCfg() {
     return Util.assign(scene, {
       resizeEnable: true,
       viewMode: '3D'
     });
   }
-  constructor(container, cfg) {
+  static project(lnglat) {
+    const maxs = 85.0511287798;
+    const lat = Math.max(Math.min(maxs, lnglat[1]), -maxs);
+    const scale = 256 << 20;
+    let d = Math.PI / 180;
+    let x = lnglat[0] * d;
+    let y = lat * d;
+    y = Math.log(Math.tan((Math.PI / 4) + (y / 2)));
+    const a = 0.5 / Math.PI,
+      b = 0.5,
+      c = -0.5 / Math.PI;
+    d = 0.5;
+    x = scale * (a * x + b) - 215440491;
+    y = -(scale * (c * y + d) - 106744817);
+    return { x, y };
+  }
+  constructor(cfg) {
     super(cfg);
-    this.container = container;
+    this.container = this.get('id');
     this.initMap();
     this.addOverLayer();
     setTimeout(() => {
@@ -85,4 +101,31 @@ export class MapProvider extends Base {
     this.renderDom.id = 'l7_canvaslayer';
     canvasContainer.appendChild(this.renderDom);
   }
+  mixMap(scene) {
+    const map = this.map;
+    scene.getZoom = () => { return map.getZoom(); };
+    scene.getCenter = () => { return map.getCenter(); };
+    scene.getSize = () => { return map.getSize(); };
+    scene.getPitch = () => { return map.getPitch(); };
+    scene.getRotation = () => { return map.getRotation(); };
+    scene.getStatus = () => { return map.getStatus(); };
+    scene.getScale = () => { return map.getScale(); };
+    scene.getZoom = () => { return map.getZoom(); };
+    scene.setZoom = () => { return map.setZoom(); };
+    scene.setBounds = () => { return map.setBounds(); };
+    scene.setRotation = () => { return map.setRotation(); };
+    scene.zoomIn = () => { return map.zoomIn(); };
+    scene.setRotation = () => { return map.setRotation(); };
+    scene.zoomOut = () => { return map.zoomOut(); };
+    scene.panTo = () => { return map.panTo(); };
+    scene.panBy = () => { return map.panBy(); };
+    scene.setPitch = () => { return map.setPitch(); };
+    scene.pixelToLngLat = () => { return map.pixelToLngLat(); };
+    scene.lngLatToPixel = () => { return map.lngLatToPixel(); };
+    scene.setMapStyle = () => { return map.setMapStyle(); };
+    scene.containerToLngLat = pixel => {
+      const ll = new AMap.Pixel(pixel.x, pixel.y);
+      return map.containerToLngLat(ll);
+    };
+  }
 }
diff --git a/src/map/gaodeMap.js b/src/map/gaodeMap.js
index 70f9dd8829..07301a8d3b 100644
--- a/src/map/gaodeMap.js
+++ b/src/map/gaodeMap.js
@@ -21,7 +21,7 @@ export default class GaodeMap {
     return this.map.getStatus();
   }
   getScale() {
-    return this.getScale();
+    return this.map.getScale();
   }
   setZoom(zoom) {
     return this.map.setZoom(zoom);
diff --git a/src/map/index.js b/src/map/index.js
new file mode 100644
index 0000000000..ae5b7dbb7d
--- /dev/null
+++ b/src/map/index.js
@@ -0,0 +1,22 @@
+import MapBox from './mapbox';
+import { default as AMap } from './AMap';
+export {
+  AMap,
+  MapBox
+};
+const MapType = {
+  amap: AMap,
+  mapbox: MapBox
+};
+export const getMap = type => {
+  return MapType[type.toLowerCase()];
+};
+
+export const registerMap = (type, map) => {
+  if (getMap(type)) {
+    throw new Error(`Map type '${type}' existed.`);
+  }
+  map.type = type;
+  // 存储到 map 中
+  MapType[type.toLowerCase()] = map;
+};
diff --git a/src/map/mapbox.js b/src/map/mapbox.js
index 3512c51150..b95fec04a1 100644
--- a/src/map/mapbox.js
+++ b/src/map/mapbox.js
@@ -3,22 +3,27 @@ import Util from '../util';
 import { scene } from '../global';
 import * as THREE from '../core/three';
 const WORLD_SIZE = 512;
-export class MapBoxProvider extends Base {
+const MERCATOR_A = 6378137.0;
+const WORLD_SCALE = 1.0;
+const PROJECTION_WORLD_SIZE = WORLD_SIZE / (MERCATOR_A * Math.PI) / 2;
+export default class MapBox extends Base {
   getDefaultCfg() {
     return Util.assign(scene, {
       resizeEnable: true,
       viewMode: '3D'
     });
   }
-  constructor(container, cfg, engine) {
+  static project(lnglat) {
+    const d = Math.PI / 180;
+    const x = -MERCATOR_A * lnglat[0] * d * PROJECTION_WORLD_SIZE;
+    const y = -MERCATOR_A * Math.log(Math.tan((Math.PI * 0.25) + (0.5 * lnglat[1] * d))) * PROJECTION_WORLD_SIZE;
+    return { x, y };
+  }
+  constructor(cfg) {
     super(cfg);
-    this.container = container;
-    this.engine = engine;
-    const scene = engine._scene;
+    this.container = this.get('container');
     this.initMap();
     this.addOverLayer();
-    scene.position.x = scene.position.y = WORLD_SIZE / 2;
-    scene.matrixAutoUpdate = false;
     setTimeout(() => {
       this.emit('mapLoad');
     }, 100);
@@ -28,15 +33,24 @@ export class MapBoxProvider extends Base {
   initMap() {
     mapboxgl.accessToken = 'pk.eyJ1IjoibHp4dWUiLCJhIjoiYnhfTURyRSJ9.Ugm314vAKPHBzcPmY1p4KQ';
     this.map = new mapboxgl.Map(this._attrs);
+  }
+  asyncCamera(engine) {
+    this.engine = engine;
+    const camera = engine._camera;
+    const scene = engine.world;
+    camera.matrixAutoUpdate = false;
+    scene.position.x = scene.position.y = WORLD_SIZE / 2;
+    scene.matrixAutoUpdate = false;
+    scene.autoUpdate = false;
+    this.updateCamera();
     this.map.on('move', () => {
       this.updateCamera();
     });
-    this.updateCamera();
   }
-  asyncCamera() {
+  updateCamera() {
     const engine = this.engine;
+    const scene = engine.world;
     const camera = engine._camera;
-    const scene = engine._scene;
     // Build a projection matrix, paralleling the code found in Mapbox GL JS
     const fov = 0.6435011087932844;
     const cameraToCenterDistance = 0.5 / Math.tan(fov / 2) * this.map.transform.height;
@@ -49,25 +63,22 @@ export class MapBoxProvider extends Base {
 
     // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance`
     const farZ = furthestDistance * 1.01;
-
+    const { x, y } = this.map.transform.point;
     camera.projectionMatrix = this.makePerspectiveMatrix(fov, this.map.transform.width / this.map.transform.height, 1, farZ);
-
-
     const cameraWorldMatrix = new THREE.Matrix4();
     const cameraTranslateZ = new THREE.Matrix4().makeTranslation(0, 0, cameraToCenterDistance);
     const cameraRotateX = new THREE.Matrix4().makeRotationX(this.map.transform._pitch);
     const cameraRotateZ = new THREE.Matrix4().makeRotationZ(this.map.transform.angle);
 
+    // const cameraTranslateCenter = new THREE.Matrix4().makeTranslation(0, 0, cameraToCenterDistance);
     // Unlike the Mapbox GL JS camera, separate camera translation and rotation out into its world matrix
     // If this is applied directly to the projection matrix, it will work OK but break raycasting
     cameraWorldMatrix
         .premultiply(cameraTranslateZ)
         .premultiply(cameraRotateX)
         .premultiply(cameraRotateZ);
-
     camera.matrixWorld.copy(cameraWorldMatrix);
 
-
     const zoomPow = this.map.transform.scale;
     // Handle scaling and translation of objects in the map in the world's matrix transform, not the camera
     const scale = new THREE.Matrix4();
@@ -82,7 +93,6 @@ export class MapBoxProvider extends Base {
         .makeTranslation(-this.map.transform.x, this.map.transform.y, 0);
     rotateMap
         .makeRotationZ(Math.PI);
-
     scene.matrix = new THREE.Matrix4();
     scene.matrix
         .premultiply(rotateMap)
@@ -117,8 +127,15 @@ export class MapBoxProvider extends Base {
     const canvasContainer = document.getElementById(this.container);
     this.canvasContainer = canvasContainer;
     this.renderDom = document.createElement('div');
-    this.renderDom.style.cssText += 'position: absolute;top: 0; z-index:1;height: 100%;width: 100%;pointer-events: none;';
+    this.renderDom.style.cssText += 'position: absolute;top: 0; z-index:10;height: 100%;width: 100%;pointer-events: none;';
     this.renderDom.id = 'l7_canvaslayer';
     canvasContainer.appendChild(this.renderDom);
   }
+  mixMap(scene) {
+    const map = this.map;
+    scene.getZoom = () => { return map.getZoom(); };
+    scene.getCenter = () => { return map.getCenter(); };
+    scene.getPitch = () => { return map.getPitch(); };
+
+  }
 }

From 45822d382d5ae9cf71e68267164a46d5835892ef Mon Sep 17 00:00:00 2001
From: thinkinggis <lzx199065@gmail.com>
Date: Tue, 12 Feb 2019 20:57:41 +0800
Subject: [PATCH 3/9] fixt(map): mapbox  double float

---
 src/map/mapbox.js | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/src/map/mapbox.js b/src/map/mapbox.js
index b95fec04a1..0480b520ba 100644
--- a/src/map/mapbox.js
+++ b/src/map/mapbox.js
@@ -4,7 +4,7 @@ import { scene } from '../global';
 import * as THREE from '../core/three';
 const WORLD_SIZE = 512;
 const MERCATOR_A = 6378137.0;
-const WORLD_SCALE = 1.0;
+const WORLD_SCALE = 1 / 100;
 const PROJECTION_WORLD_SIZE = WORLD_SIZE / (MERCATOR_A * Math.PI) / 2;
 export default class MapBox extends Base {
   getDefaultCfg() {
@@ -53,7 +53,7 @@ export default class MapBox extends Base {
     const camera = engine._camera;
     // Build a projection matrix, paralleling the code found in Mapbox GL JS
     const fov = 0.6435011087932844;
-    const cameraToCenterDistance = 0.5 / Math.tan(fov / 2) * this.map.transform.height;
+    const cameraToCenterDistance = 0.5 / Math.tan(fov / 2) * this.map.transform.height * WORLD_SCALE;
     const halfFov = fov / 2;
     const groundAngle = Math.PI / 2 + this.map.transform._pitch;
     const topHalfSurfaceDistance = Math.sin(halfFov) * cameraToCenterDistance / Math.sin(Math.PI - groundAngle - halfFov);
@@ -62,31 +62,36 @@ export default class MapBox extends Base {
     const furthestDistance = Math.cos(Math.PI / 2 - this.map.transform._pitch) * topHalfSurfaceDistance + cameraToCenterDistance;
 
     // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance`
-    const farZ = furthestDistance * 1.01;
+    let farZ = furthestDistance * 1.1;
+    if (this.pitch > 50) {
+      farZ = 1000;
+    }
     const { x, y } = this.map.transform.point;
     camera.projectionMatrix = this.makePerspectiveMatrix(fov, this.map.transform.width / this.map.transform.height, 1, farZ);
     const cameraWorldMatrix = new THREE.Matrix4();
     const cameraTranslateZ = new THREE.Matrix4().makeTranslation(0, 0, cameraToCenterDistance);
     const cameraRotateX = new THREE.Matrix4().makeRotationX(this.map.transform._pitch);
     const cameraRotateZ = new THREE.Matrix4().makeRotationZ(this.map.transform.angle);
-
+    const cameraTranslateXY = new THREE.Matrix4().makeTranslation(x * WORLD_SCALE, -y * WORLD_SCALE, 0);
     // const cameraTranslateCenter = new THREE.Matrix4().makeTranslation(0, 0, cameraToCenterDistance);
     // Unlike the Mapbox GL JS camera, separate camera translation and rotation out into its world matrix
     // If this is applied directly to the projection matrix, it will work OK but break raycasting
     cameraWorldMatrix
         .premultiply(cameraTranslateZ)
         .premultiply(cameraRotateX)
-        .premultiply(cameraRotateZ);
+        .premultiply(cameraRotateZ)
+        .premultiply(cameraTranslateXY);
+
     camera.matrixWorld.copy(cameraWorldMatrix);
 
-    const zoomPow = this.map.transform.scale;
+    const zoomPow = this.map.transform.scale * WORLD_SCALE;
     // Handle scaling and translation of objects in the map in the world's matrix transform, not the camera
     const scale = new THREE.Matrix4();
     const translateCenter = new THREE.Matrix4();
     const translateMap = new THREE.Matrix4();
     const rotateMap = new THREE.Matrix4();
     scale
-        .makeScale(zoomPow, zoomPow, zoomPow);
+        .makeScale(zoomPow, zoomPow, 1.0);
     translateCenter
         .makeTranslation(WORLD_SIZE / 2, -WORLD_SIZE / 2, 0);
     translateMap
@@ -97,8 +102,7 @@ export default class MapBox extends Base {
     scene.matrix
         .premultiply(rotateMap)
         .premultiply(translateCenter)
-        .premultiply(scale)
-        .premultiply(translateMap);
+        .premultiply(scale);
   }
   makePerspectiveMatrix(fovy, aspect, near, far) {
     const out = new THREE.Matrix4();

From bc0191ed3110776291c10ee1ccb47ddf23633164 Mon Sep 17 00:00:00 2001
From: thinkinggis <lzx199065@gmail.com>
Date: Fri, 15 Feb 2019 11:35:04 +0800
Subject: [PATCH 4/9] fix(mapbox): scale

---
 src/core/engine/picking/picking.js | 12 +++++++-----
 src/core/scene.js                  |  1 +
 src/geom/shader/polygon_vert.glsl  |  3 ++-
 src/map/mapbox.js                  | 13 +++++++++++--
 4 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/src/core/engine/picking/picking.js b/src/core/engine/picking/picking.js
index 0dfd718fbe..ea6ff5c0db 100755
--- a/src/core/engine/picking/picking.js
+++ b/src/core/engine/picking/picking.js
@@ -11,6 +11,8 @@ class Picking {
     this.scene = scene;
     this._raycaster.linePrecision = 10;
     this._pickingScene = PickingScene;
+    this.world = new THREE.Group();
+    this._pickingScene.add(this.world);
     const size = this._renderer.getSize();
     this._width = size.width;
     this._height = size.height;
@@ -61,12 +63,12 @@ class Picking {
 
   }
   _filterObject(id) {
-    this._pickingScene.children.forEach((object, index) => {
+    this.world.children.forEach((object, index) => {
       index === id ? object.visible = true : object.visible = false;
     });
   }
   _pickAllObject(point, normalisedPoint) {
-    this._pickingScene.children.forEach((object, index) => {
+    this.world.children.forEach((object, index) => {
       this._filterObject(index);
       const item = this._pick(point, normalisedPoint, object.name);
       item.type = point.type;
@@ -86,7 +88,6 @@ class Picking {
       id = -999;
       // return;
     }
-
     this._raycaster.setFromCamera(normalisedPoint, this._camera);
 
     const intersects = this._raycaster.intersectObjects(this._pickingScene.children, true);
@@ -111,13 +112,14 @@ class Picking {
   //
   // Picking ID should already be added as an attribute
   add(mesh) {
-    this._pickingScene.add(mesh);
+    this.world.add(mesh);
+
     this._needUpdate = true;
   }
 
   // Remove mesh from picking scene
   remove(mesh) {
-    this._pickingScene.remove(mesh);
+    this.world.remove(mesh);
     this._needUpdate = true;
   }
 
diff --git a/src/core/scene.js b/src/core/scene.js
index 115db9fdcd..6e9eb187cd 100644
--- a/src/core/scene.js
+++ b/src/core/scene.js
@@ -99,6 +99,7 @@ export default class Scene extends Base {
     events.forEach(event => {
       this.map.on(event, e => {
         // 要素拾取
+        e.pixel || (e.pixel = e.point);
         this._engine._picking.pickdata(e);
       }, false);
     });
diff --git a/src/geom/shader/polygon_vert.glsl b/src/geom/shader/polygon_vert.glsl
index 9c8508c674..eba0b62d02 100644
--- a/src/geom/shader/polygon_vert.glsl
+++ b/src/geom/shader/polygon_vert.glsl
@@ -15,8 +15,9 @@ varying float v_size;
 
 void main() {
    float scale = pow(2.0,(20.0 - u_zoom));
-  mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
+  mat4 matModelViewProjection = projectionMatrix * modelViewMatrix * 100.;
   vec3 newposition =  position;
+  // newposition.x -= 128.0;
    #ifdef SHAPE 
     newposition =position + a_size * scale* a_shape;
   #endif
diff --git a/src/map/mapbox.js b/src/map/mapbox.js
index 0480b520ba..927eba688f 100644
--- a/src/map/mapbox.js
+++ b/src/map/mapbox.js
@@ -38,10 +38,12 @@ export default class MapBox extends Base {
     this.engine = engine;
     const camera = engine._camera;
     const scene = engine.world;
+    const pickScene = engine._picking.world;
     camera.matrixAutoUpdate = false;
     scene.position.x = scene.position.y = WORLD_SIZE / 2;
     scene.matrixAutoUpdate = false;
-    scene.autoUpdate = false;
+    pickScene.position.x = pickScene.position.y = WORLD_SIZE / 2;
+    pickScene.matrixAutoUpdate = false;
     this.updateCamera();
     this.map.on('move', () => {
       this.updateCamera();
@@ -50,6 +52,7 @@ export default class MapBox extends Base {
   updateCamera() {
     const engine = this.engine;
     const scene = engine.world;
+    const pickScene = engine._picking.world;
     const camera = engine._camera;
     // Build a projection matrix, paralleling the code found in Mapbox GL JS
     const fov = 0.6435011087932844;
@@ -91,7 +94,7 @@ export default class MapBox extends Base {
     const translateMap = new THREE.Matrix4();
     const rotateMap = new THREE.Matrix4();
     scale
-        .makeScale(zoomPow, zoomPow, 1.0);
+        .makeScale(zoomPow / 100, zoomPow / 100, 1.0);
     translateCenter
         .makeTranslation(WORLD_SIZE / 2, -WORLD_SIZE / 2, 0);
     translateMap
@@ -103,6 +106,11 @@ export default class MapBox extends Base {
         .premultiply(rotateMap)
         .premultiply(translateCenter)
         .premultiply(scale);
+    pickScene.matrix = new THREE.Matrix4();
+    pickScene.matrix
+        .premultiply(rotateMap)
+        .premultiply(translateCenter)
+        .premultiply(scale);
   }
   makePerspectiveMatrix(fovy, aspect, near, far) {
     const out = new THREE.Matrix4();
@@ -140,6 +148,7 @@ export default class MapBox extends Base {
     scene.getZoom = () => { return map.getZoom(); };
     scene.getCenter = () => { return map.getCenter(); };
     scene.getPitch = () => { return map.getPitch(); };
+    scene.containerToLngLat = point => { return map.unproject(point); };
 
   }
 }

From 58804ef23b32f44d3ba5562490b7d5486a660c9a Mon Sep 17 00:00:00 2001
From: thinkinggis <lzx199065@gmail.com>
Date: Tue, 19 Feb 2019 11:08:38 +0800
Subject: [PATCH 5/9] mapbox

---
 src/map/mapbox.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/map/mapbox.js b/src/map/mapbox.js
index 927eba688f..8eebadc8ef 100644
--- a/src/map/mapbox.js
+++ b/src/map/mapbox.js
@@ -94,7 +94,7 @@ export default class MapBox extends Base {
     const translateMap = new THREE.Matrix4();
     const rotateMap = new THREE.Matrix4();
     scale
-        .makeScale(zoomPow / 100, zoomPow / 100, 1.0);
+        .makeScale(zoomPow, zoomPow, 1.0);
     translateCenter
         .makeTranslation(WORLD_SIZE / 2, -WORLD_SIZE / 2, 0);
     translateMap

From db5fc816781997d0ab1886e51ef0e89aaf907eca Mon Sep 17 00:00:00 2001
From: thinkinggis <lzx199065@gmail.com>
Date: Tue, 19 Feb 2019 13:58:48 +0800
Subject: [PATCH 6/9] add mapbox demo

---
 .gitignore        |  1 -
 demos/mapbox.html | 93 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 93 insertions(+), 1 deletion(-)
 create mode 100644 demos/mapbox.html

diff --git a/.gitignore b/.gitignore
index 73a92f7460..5fb73328f2 100755
--- a/.gitignore
+++ b/.gitignore
@@ -69,7 +69,6 @@ lib
 
 *.sw*
 *.un~
-demos/mapbox.html
 demos/gd.html
 demos/data
 demos/image
diff --git a/demos/mapbox.html b/demos/mapbox.html
new file mode 100644
index 0000000000..661b3c33c3
--- /dev/null
+++ b/demos/mapbox.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <meta http-equiv="X-UA-Compatible" content="ie=edge">
+  <meta name="geometry" content="diagram">
+  <link rel="stylesheet" href="./assets/common.css">
+    <link rel="stylesheet" href="./assets/info.css">
+  <title>point_circle</title>
+  <style>
+  body {
+    margin:0;
+    padding:0;
+  }
+	#map { position:absolute; top:0; bottom:0; width:100%; margin:0; }
+  </style>
+</head>
+
+<body>
+<div id="map"></div>
+<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.34.0/mapbox-gl.js'></script>
+<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.34.0/mapbox-gl.css' rel='stylesheet' />
+<script src="./assets/jquery-3.2.1.min.js"></script>
+<script src="./assets/dat.gui.min.js"></script>
+<script src="../build/L7.js"></script>
+<script>
+const colorObj ={
+  blue: ["#E8FCFF", "#CFF6FF", "#A1E9ff", "#65CEF7", "#3CB1F0", "#2894E0", "#1772c2", "#105CB3", "#0D408C", "#002466"].reverse(),
+  red: ["#FFF4F2", "#FFDFDB", "#FAADAA", "#F77472", "#F04850", "#D63147", "#BD223E", "#A81642", "#820C37", "#5C0023"].reverse(),
+  orange:["#FFF7EB", "#FFECD4", "#FAD09D", "#F7B16A", "#F08D41", "#DB6C2C", "#C2491D", "#AD2B11", "#871D0C", "#610800"].reverse(),
+  green:["#FAFFF0", "#EBF7D2", "#C8E695", "#A5D660", "#7DC238", "#59A616", "#3F8C0B", "#237804", "#125200", "#082B00"].reverse(),
+  yellow:["#FFFFE8", "#FFFECC", "#FAF896", "#F7E463", "#F0CE3A", "#DBB125", "#C29117", "#AD7410", "#87500C", "#613000"].reverse(),
+  purple:["#FCF2FF", "#F5DEFF", "#DDB3F2", "#BE7BE3", "#9B4ECF", "#7737B3", "#5B2899", "#411C85", "#270F5E", "#100338"].reverse()
+}
+
+
+const scene = new L7.Scene({
+  container: 'map',
+  mapType:'mapbox',
+  style: 'mapbox://styles/mapbox/streets-v9', // stylesheet location
+  center: [ 120.19382669582967, 30.258134 ],
+  pitch: 0,
+  hash:true,
+  zoom: 1,
+});
+window.scene = scene;
+scene.on('loaded', () => {
+  var colors = ["#FFF5B8","#FFDC7D","#FFAB5C","#F27049","#D42F31","#730D1C"];
+  $.getJSON('https://gw.alipayobjects.com/os/rmsportal/JToMOWvicvJOISZFCkEI.json', city => {
+    const citylayer = scene.PolygonLayer()
+    .source(city)
+    //.color('pm2_5_24h',["#FFF5B8","#FFDC7D","#FFAB5C","#F27049","#D42F31","#730D1C"])
+    .color('pm2_5_24h',(p)=>{
+        if(p>120){
+          return colors[5];
+        } else if(p>65){
+          return colors[4];
+        } else if(p>30) {
+          return colors[3];
+        } else if(p>15){
+          return colors[2];
+        } else if(p>8){
+          return colors[1];
+        }else {
+          return colors[0];
+        }
+    })
+    .shape('fill')
+    .active(true)
+    .style({
+      opacity: 1
+    })
+    .render();
+    console.log('success');
+  });
+   $.get('https://gw.alipayobjects.com/os/rmsportal/ggFwDClGjjvpSMBIrcEx.json', data => {
+    citylayer = scene.PolygonLayer({
+      zIndex: 2
+    })
+    .source(data)
+    .shape('extrude')
+    .active({fill:'red'})
+    .size('floor',[0.1,1])
+    .color('#aaa')
+    .render();
+   })
+});
+
+</script>
+</body>
+</html>
+

From 2c2684ae97d4538ef05d82f56dcd8c83423351f6 Mon Sep 17 00:00:00 2001
From: thinkinggis <lzx199065@gmail.com>
Date: Mon, 25 Feb 2019 23:56:37 +0800
Subject: [PATCH 7/9] refactor(source): source

---
 demos/01_point_circle.html              |   9 ++-
 demos/01_point_column.html              |   8 +-
 demos/01_point_distribute.html          |   8 +-
 demos/02_point_circle.html              |  77 ++++++++++++++++++
 demos/04_image.html                     |   7 +-
 demos/05_raster_dem.html                |  15 ++--
 demos/grid.html                         |  74 +++++++++++++++++
 package.json                            |   1 +
 src/core/engine/picking/picking.js      |   3 +-
 src/core/layer.js                       |  35 ++++----
 src/core/source.js                      |  52 ++++++++----
 src/geom/buffer/heatmap/grid.js         |  32 ++++++++
 src/geom/buffer/image.js                |   5 +-
 src/geom/buffer/line.js                 |  29 +++----
 src/geom/buffer/point/fillBuffer.js     |   8 +-
 src/geom/buffer/point/imageBuffer.js    |   8 +-
 src/geom/buffer/point/normalBuffer.js   |   8 +-
 src/geom/buffer/point/strokeBuffer.js   |   8 +-
 src/geom/buffer/point/textBuffer.js     |   8 +-
 src/geom/buffer/polygon.js              |  17 ++--
 src/geom/buffer/raster.js               |  12 ++-
 src/geom/buffer/text.js                 |  11 ++-
 src/geom/material/grid.js               |  31 ++++++++
 src/geom/shader/grid_frag.glsl          |   8 ++
 src/geom/shader/grid_vert.glsl          |  15 ++++
 src/layer/heatmap.js                    |  28 +++++++
 src/layer/imageLayer.js                 |  13 +--
 src/layer/index.js                      |   7 +-
 src/layer/lineLayer.js                  |   5 +-
 src/layer/pointLayer.js                 |  17 ++--
 src/layer/polygonLayer.js               |   4 +-
 src/layer/rasterLayer.js                |  16 ++--
 src/layer/render/heatmap/gird.js        |  21 +++++
 src/source/csvSource.js                 |  69 ----------------
 src/source/factory.js                   |  11 +++
 src/source/geojsonSource.js             |  47 -----------
 src/source/imageSource.js               |  37 ---------
 src/source/index.js                     |  28 +++++--
 src/source/parser/csv.js                |  23 ++++++
 src/source/parser/geojson.js            |  19 +++++
 src/source/parser/image.js              |  41 ++++++++++
 src/source/parser/json.js               |  21 +++++
 src/source/parser/raster.js             |  15 ++++
 src/source/rainSource.js                |  31 --------
 src/source/rasterSource.js              |  20 -----
 src/source/transform/grid-aggregator.js | 101 ++++++++++++++++++++++++
 src/source/transform/map.js             |   7 ++
 src/source/transform/statistics.js      |  10 +++
 48 files changed, 717 insertions(+), 363 deletions(-)
 create mode 100644 demos/02_point_circle.html
 create mode 100644 demos/grid.html
 create mode 100644 src/geom/buffer/heatmap/grid.js
 create mode 100644 src/geom/material/grid.js
 create mode 100644 src/geom/shader/grid_frag.glsl
 create mode 100644 src/geom/shader/grid_vert.glsl
 create mode 100644 src/layer/heatmap.js
 create mode 100644 src/layer/render/heatmap/gird.js
 delete mode 100644 src/source/csvSource.js
 create mode 100644 src/source/factory.js
 delete mode 100644 src/source/geojsonSource.js
 delete mode 100644 src/source/imageSource.js
 create mode 100644 src/source/parser/csv.js
 create mode 100644 src/source/parser/geojson.js
 create mode 100644 src/source/parser/image.js
 create mode 100644 src/source/parser/json.js
 create mode 100644 src/source/parser/raster.js
 delete mode 100644 src/source/rainSource.js
 delete mode 100644 src/source/rasterSource.js
 create mode 100644 src/source/transform/grid-aggregator.js
 create mode 100644 src/source/transform/map.js
 create mode 100644 src/source/transform/statistics.js

diff --git a/demos/01_point_circle.html b/demos/01_point_circle.html
index bb80671de8..7121179c29 100644
--- a/demos/01_point_circle.html
+++ b/demos/01_point_circle.html
@@ -10,6 +10,9 @@
   <title>point_circle</title>
   <style>
 	#map { position:absolute; top:0; bottom:0; width:100%; }
+  .amap-maps {
+     cursor: auto !important
+  }
   </style>
 </head>
 
@@ -55,15 +58,15 @@ scene.on('loaded', () => {
     .shape('2d:circle')
      .size('value', [ 2, 80]) // default 1
      //.size('value', [ 10, 300]) // default 1
-    .active(false)
+    .active(true)
      .filter('value', field_8 => {
       return field_8 * 1 > 500;
      })
-    .color('type', colorObj.red)
+    .color('type', colorObj.blue)
     .style({
       stroke: 'rgb(255,255,255)',
       strokeWidth: 1,
-      opacity: 0.9
+      opacity: 1.
     })
      .render();
      
diff --git a/demos/01_point_column.html b/demos/01_point_column.html
index 8e1abda83c..fd7d33ae02 100644
--- a/demos/01_point_column.html
+++ b/demos/01_point_column.html
@@ -34,9 +34,11 @@ scene.on('loaded', () => {
       zIndex: 2
     })
     .source(data.list, {
-      type: 'array',
-      x: 'j',
-      y: 'w',
+      parser:{
+        type: 'json',
+        x: 'j',
+        y: 'w',
+      }
     })
     .shape('cylinder')
     .size('t',(level)=> {
diff --git a/demos/01_point_distribute.html b/demos/01_point_distribute.html
index 18a714ab75..a3d1bd8f73 100644
--- a/demos/01_point_distribute.html
+++ b/demos/01_point_distribute.html
@@ -34,9 +34,11 @@ scene.on('loaded', () => {
       zIndex: 2
     })
      .source(data, {
-       type: 'csv',
-       y: 'lat',
-       x: 'lng'
+       parser:{
+          type: 'csv',
+          y: 'lat',
+          x: 'lng'
+       }
      })
     .size(1.0)
    .color('#0D408C')
diff --git a/demos/02_point_circle.html b/demos/02_point_circle.html
new file mode 100644
index 0000000000..cc95ad57d6
--- /dev/null
+++ b/demos/02_point_circle.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <meta http-equiv="X-UA-Compatible" content="ie=edge">
+  <meta name="geometry" content="diagram">
+  <link rel="stylesheet" href="./assets/common.css">
+    <link rel="stylesheet" href="./assets/info.css">
+  <title>point_circle</title>
+  <style>
+	#map { position:absolute; top:0; bottom:0; width:100%; }
+  .amap-maps {
+     cursor: auto !important
+  }
+  </style>
+</head>
+
+<body>
+<div id="map"></div>
+<script src="https://webapi.amap.com/maps?v=1.4.8&key=15cd8a57710d40c9b7c0e3cc120f1200&plugin=Map3D"></script>
+<script src="./assets/jquery-3.2.1.min.js"></script>
+<script src="./assets/dat.gui.min.js"></script>
+<script src="../build/L7.js"></script>
+<script>
+const colorObj ={
+  blue: ["#E8FCFF", "#CFF6FF", "#A1E9ff", "#65CEF7", "#3CB1F0", "#2894E0", "#1772c2", "#105CB3", "#0D408C", "#002466"].reverse(),
+  red: ["#FFF4F2", "#FFDFDB", "#FAADAA", "#F77472", "#F04850", "#D63147", "#BD223E", "#A81642", "#820C37", "#5C0023"].reverse(),
+  orange:["#FFF7EB", "#FFECD4", "#FAD09D", "#F7B16A", "#F08D41", "#DB6C2C", "#C2491D", "#AD2B11", "#871D0C", "#610800"].reverse(),
+  green:["#FAFFF0", "#EBF7D2", "#C8E695", "#A5D660", "#7DC238", "#59A616", "#3F8C0B", "#237804", "#125200", "#082B00"].reverse(),
+  yellow:["#FFFFE8", "#FFFECC", "#FAF896", "#F7E463", "#F0CE3A", "#DBB125", "#C29117", "#AD7410", "#87500C", "#613000"].reverse(),
+  purple:["#FCF2FF", "#F5DEFF", "#DDB3F2", "#BE7BE3", "#9B4ECF", "#7737B3", "#5B2899", "#411C85", "#270F5E", "#100338"].reverse()
+}
+
+
+const scene = new L7.Scene({
+  id: 'map',
+  mapStyle: 'light', // 样式URL
+  center: [ 120.19382669582967, 30.258134 ],
+  pitch: 0,
+  zoom: 4,
+  maxZoom:14,
+  minZoom:4,
+});
+window.scene = scene;
+scene.on('loaded', () => {
+  $.get('https://gw.alipayobjects.com/os/basement_prod/7359a5e9-3c5e-453f-b207-bc892fb23b84.csv', data => {
+    
+   
+    const circleLayer = scene.PointLayer({
+      zIndex: 2
+    })
+    .source(data,{
+      type: 'csv',
+      x: 'lng',
+      y: 'lat',
+    })
+    .size(1.0)
+    .color('#0D408C')
+    .style({
+      stroke: 'rgb(255,255,255)',
+      strokeWidth: 1,
+      opacity: 1.
+    })
+     .render();
+     
+    circleLayer.on('click',(e)=>{
+    console.log(e);
+  })
+  });
+    
+});
+
+</script>
+</body>
+</html>
+
diff --git a/demos/04_image.html b/demos/04_image.html
index 3f0773c96e..5acb717137 100644
--- a/demos/04_image.html
+++ b/demos/04_image.html
@@ -33,8 +33,11 @@ const scene = new L7.Scene({
 scene.on('loaded', () => {
   const imageLayer = scene.ImageLayer().
       source('https://gw.alipayobjects.com/zos/rmsportal/FnHFeFklTzKDdUESRNDv.jpg',{
-       
-      extent: [ 121.1680, 30.2828, 121.3840, 30.4219 ]
+       parser:{
+            type:'image',
+            extent: [ 121.1680, 30.2828, 121.3840, 30.4219 ]
+       }
+   
       })
       .style({
         opacity:1.0,
diff --git a/demos/05_raster_dem.html b/demos/05_raster_dem.html
index 0589eed6b4..fb560be45b 100644
--- a/demos/05_raster_dem.html
+++ b/demos/05_raster_dem.html
@@ -48,13 +48,14 @@ scene.on('loaded', () => {
 
       const layer = scene.RasterLayer({ zIndex: 2 }).
       source(values, {
-        type: 'raster',
-        width: n,
-        height: m,
-        min: 0,
-        max: 8000,
-        extent: [ 73.482190241, 3.82501784112, 135.106618732, 57.6300459963 ]
-
+        parser: {
+          type: 'raster',
+          width: n,
+          height: m,
+          min: 0,
+          max: 8000,
+          extent: [ 73.482190241, 3.82501784112, 135.106618732, 57.6300459963 ]
+        }
       })
        .style({
          rampColors: {
diff --git a/demos/grid.html b/demos/grid.html
new file mode 100644
index 0000000000..94c2000bb9
--- /dev/null
+++ b/demos/grid.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <meta http-equiv="X-UA-Compatible" content="ie=edge">
+  <meta name="geometry" content="diagram">
+  <link rel="stylesheet" href="./assets/common.css">
+  <title>point_circle</title>
+  <style>
+	#map { position:absolute; top:0; bottom:0; width:100%; }
+  </style>
+</head>
+
+<body>
+<div id="map"></div>
+<script src="https://webapi.amap.com/maps?v=1.4.8&key=15cd8a57710d40c9b7c0e3cc120f1200&plugin=Map3D"></script>
+<script src="./assets/jquery-3.2.1.min.js"></script>
+<script src="./assets/dat.gui.min.js"></script>
+<script src="../build/L7.js"></script>
+<script>
+
+const scene = new L7.Scene({
+  id: 'map',
+  mapStyle: 'dark', // 样式URL
+  center: [120.132624,30.281774],
+  pitch: 0,
+  zoom: 3.88
+});
+scene.on('loaded', () => {
+  $.get('https://gw.alipayobjects.com/os/basement_prod/7359a5e9-3c5e-453f-b207-bc892fb23b84.csv', data => {
+    var layer = scene.HeatMapLayer({
+      zIndex: 2
+    })
+    .source(data, {
+      parser: {
+        type: 'csv',
+        x: 'lng',
+        y: 'lat'
+      },
+      transforms:[
+        {
+          type: 'map',
+          callback:function(item){
+            const [x, y] = item.coordinates;
+            item.lat = item.lat*1;
+            item.lng = item.lng*1;
+            item.v = item.v *1;
+            item.coordinates = [x*1,y*1];
+            return item;
+          }
+
+        },
+        {
+        type: 'grid',
+        size: 15000,
+        field:'v',
+        method:'sum'
+      }
+      ]
+    })
+    .shape('gird')
+    .style({
+      coverage: 0.8
+    })
+    .color('count', ["#002466","#105CB3","#2894E0","#CFF6FF","#FFF5B8","#FFAB5C","#F27049","#730D1C"])
+     .render();
+  console.log(layer);
+  });
+});
+</script>
+</body>
+</html>
+
diff --git a/package.json b/package.json
index cbaf70578a..3ee6803cde 100755
--- a/package.json
+++ b/package.json
@@ -107,6 +107,7 @@
     "lodash": "^4.17.5",
     "polyline-normals": "^2.0.2",
     "rbush": "^2.0.2",
+    "simple-statistics": "^7.0.1",
     "three": "^0.96.0",
     "venn.js": "^0.2.20",
     "viewport-mercator-project": "^5.2.0",
diff --git a/src/core/engine/picking/picking.js b/src/core/engine/picking/picking.js
index e4fb4c2ee1..e70912ac16 100755
--- a/src/core/engine/picking/picking.js
+++ b/src/core/engine/picking/picking.js
@@ -42,7 +42,7 @@ class Picking {
     // this._world._container.addEventListener('mousemove', this._onWorldMove.bind(this), false);
   }
   pickdata(event) {
-    const point = { x: event.clientX, y: event.clientY, type: event.type };
+    const point = { x: event.offsetX, y: event.offsetY, type: event.type };
     const normalisedPoint = { x: 0, y: 0 };
     normalisedPoint.x = (point.x / this._width) * 2 - 1;
     normalisedPoint.y = -(point.y / this._height) * 2 + 1;
@@ -53,7 +53,6 @@ class Picking {
     // if (event.button !== 0) {
     //   return;
     // }
-
     const point = { x: event.clientX, y: event.clientY, type: event.type };
     const normalisedPoint = { x: 0, y: 0 };
     normalisedPoint.x = (point.x / this._width) * 2 - 1;
diff --git a/src/core/layer.js b/src/core/layer.js
index 50f2858587..e4d4467ab9 100644
--- a/src/core/layer.js
+++ b/src/core/layer.js
@@ -5,7 +5,7 @@
 import Base from './base';
 import * as THREE from './three';
 import ColorUtil from '../attr/color-util';
-import * as source from '../source/index';
+import source from './source';
 import PickingMaterial from '../core/engine/picking/pickingMaterial';
 import Attr from '../attr/index';
 import Util from '../util';
@@ -106,12 +106,10 @@ export default class Layer extends Base {
     this._object3D.visible = this.get('visible');
   }
   source(data, cfg = {}) {
-    const dataType = this._getDataType(data);
-    const { type = dataType } = cfg;
     cfg.data = data;
     cfg.mapType = this.get('mapType');
 
-    this.layerSource = new source[type](cfg);
+    this.layerSource = new source(cfg);
     // this.scene.workerPool.runTask({
     //   command: 'geojson',
     //   data: cfg
@@ -279,10 +277,10 @@ export default class Layer extends Base {
     const { featureId } = e;
     if (featureId < 0) return;
     const activeStyle = this.get('activedOptions');
-    const selectFeatureIds = this.layerSource.getSelectFeatureId(featureId);
+    // const selectFeatureIds = this.layerSource.getSelectFeatureId(featureId);
     // 如果数据不显示状态则不进行高亮
-    if (this.StyleData[selectFeatureIds[0]].hasOwnProperty('filter') && this.StyleData[selectFeatureIds[0]].filter === false) { return; }
-    const style = Util.assign({}, this.StyleData[featureId]);
+    if (this.layerData[featureId].hasOwnProperty('filter') && this.layerData[featureId].filter === false) { return; }
+    const style = Util.assign({}, this.layerData[featureId]);
     style.color = ColorUtil.toRGB(activeStyle.fill).map(e => e / 255);
     this.updateStyle([ featureId ], style);
   }
@@ -321,7 +319,7 @@ export default class Layer extends Base {
   _updateSize(zoom) {
     const sizeOption = this.get('attrOptions').size;
     const fields = parseFields(sizeOption.field);
-    const data = this.layerSource.propertiesData;
+    const data = this.layerSource.data.dataArray;
     if (!this.zoomSizeCache) this.zoomSizeCache = {};
     if (!this.zoomSizeCache[zoom]) {
       this.zoomSizeCache[zoom] = [];
@@ -339,7 +337,8 @@ export default class Layer extends Base {
     const self = this;
     const attrs = self.get('attrs');
     const mappedData = [];
-    const data = this.layerSource.propertiesData;
+    // const data = this.layerSource.propertiesData;
+    const data = this.layerSource.data.dataArray;
     for (let i = 0; i < data.length; i++) {
       const record = data[i];
       const newRecord = {};
@@ -362,18 +361,17 @@ export default class Layer extends Base {
           }
         }
       }
+      newRecord.coordinates = record.coordinates;
       mappedData.push(newRecord);
     }
-
-    this.StyleData = mappedData;
-    return mappedData;
+    this.layerData = mappedData;
   }
   // 更新地图映射
   _updateMaping() {
     const self = this;
     const attrs = self.get('attrs');
 
-    const data = this.layerSource.propertiesData;
+    const data = this.layerSource.data.dataArray;
     for (let i = 0; i < data.length; i++) {
       const record = data[i];
       for (const attrName in attrs) {
@@ -385,10 +383,10 @@ export default class Layer extends Base {
             for (let j = 0; j < values.length; j++) {
               const val = values[j];
               const name = names[j];
-              this.StyleData[i][name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值
+              this.layerData[i][name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值
             }
           } else {
-            this.StyleData[i][names[0]] = values.length === 1 ? values[0] : values;
+            this.layerData[i][names[0]] = values.length === 1 ? values[0] : values;
 
           }
           attr.neadUpdate = true;
@@ -468,6 +466,7 @@ export default class Layer extends Base {
       pickingMesh.material.setUniformsValue('u_zoom', zoom);
     };
     this._pickingMesh.add(pickingMesh);
+
   }
   _setPickingId() {
     this._pickingId = this.getPickingId();
@@ -532,13 +531,13 @@ export default class Layer extends Base {
    */
   _updateFilter(object) {
     this._updateMaping();
-    const filterData = this.StyleData;
+    const filterData = this.layerData;
     this._activeIds = null; // 清空选中元素
     const colorAttr = object.geometry.attributes.a_color;
     const pickAttr = object.geometry.attributes.pickingId;
     pickAttr.array.forEach((id, index) => {
       id = Math.abs(id);
-      const color = [ ...this.StyleData[id - 1].color ];
+      const color = [ ...this.layerData[id - 1].color ];
       id = Math.abs(id);
       const item = filterData[id - 1];
       if (item.hasOwnProperty('filter') && item.filter === false) {
@@ -584,7 +583,7 @@ export default class Layer extends Base {
     const pickingId = this.layerMesh.geometry.attributes.pickingId.array;
     const colorAttr = this.layerMesh.geometry.attributes.a_color;
     this._activeIds.forEach(index => {
-      const color = this.StyleData[index].color;
+      const color = this.layerData[index].color;
       const firstId = pickingId.indexOf(index + 1);
       for (let i = firstId; i < pickingId.length; i++) {
         if (pickingId[i] === index + 1) {
diff --git a/src/core/source.js b/src/core/source.js
index 3a61aead88..fdb37fa2de 100644
--- a/src/core/source.js
+++ b/src/core/source.js
@@ -2,16 +2,19 @@
  * @Author: ThinkGIS
  * @Date: 2018-06-08 11:19:06
  * @Last Modified by: mikey.zhaopeng
- * @Last Modified time: 2018-11-01 11:50:43
+ * @Last Modified time: 2019-02-25 20:58:08
  */
 import Base from './base';
 const Controller = require('./controller/index');
 import { aProjectFlat } from '../geo/project';
+import { getTransform, getParser } from '../source';
 export default class Source extends Base {
   getDefaultCfg() {
     return {
       data: null,
       defs: {},
+      parser: {},
+      transforms: [],
       scales: {
       },
       options: {}
@@ -19,26 +22,40 @@ export default class Source extends Base {
   }
   constructor(cfg) {
     super(cfg);
-
+    const transform = this.get('transforms');
+    this._transforms = transform || [];
     this._initControllers();
-    this.prepareData();
+    // 数据解析
+    this._excuteParser();
+    // 数据转换 统计,聚合,分类
+    this._executeTrans();
+    // 坐标转换
+    this._projectCoords();
   }
-
-  // 标准化数据
-  prepareData() {
+  _excuteParser() {
+    const parser = this.get('parser');
+    const { type = 'geojson' } = parser;
     const data = this.get('data');
-    this.propertiesData = [];// 临时使用
-    this.geoData = [];
-
-    data.coordinates.forEach(geo => {
-      const coord = this._coordProject(geo);
-      this.geoData.push(coord);
-      this.propertiesData.push([]);
+    this.data = getParser(type)(data, parser);
+  }
+  /**
+   * 数据统计
+   */
+  _executeTrans() {
+    const trans = this._transforms;
+    trans.forEach(tran => {
+      const { type } = tran;
+      this.data = getTransform(type)(this.data, tran);
+    });
+    this._transforms = trans;
+  }
+  _projectCoords() {
+    this.data.dataArray.forEach(data => {
+      data.coordinates = this._coordProject(data.coordinates);
     });
   }
-
   createScale(field) {
-    const data = this.propertiesData;
+    const data = this.data.dataArray;
     const scales = this.get('scales');
     let scale = scales[field];
     const scaleController = this.get('scaleController');
@@ -87,5 +104,10 @@ export default class Source extends Base {
     return [ ll.x, -ll.y, geo[2] || 0 ];
 
   }
+  getSelectFeature(featureId) {
+    const data = this.get('data');
+    // 如果是GeoJSON 数据返回原数
+    return data.features ? data.features[featureId] : this.data.dataArray[featureId];
+  }
 
 }
diff --git a/src/geom/buffer/heatmap/grid.js b/src/geom/buffer/heatmap/grid.js
new file mode 100644
index 0000000000..af089e408b
--- /dev/null
+++ b/src/geom/buffer/heatmap/grid.js
@@ -0,0 +1,32 @@
+export default function gridBuffer(layerData) {
+  const attribute = {
+    vertices: [],
+    miter: [],
+    colors: [],
+    pickingIds: []
+  };
+  layerData.forEach(element => {
+    const { color, id } = element;
+    const [ x, y, z ] = element.coordinates;
+    attribute.vertices.push(x, y, z);
+    attribute.miter.push(-1, -1);
+    attribute.vertices.push(x, y, z);
+    attribute.miter.push(1, 1);
+    attribute.vertices.push(x, y, z);
+    attribute.miter.push(-1, 1);
+    attribute.vertices.push(x, y, z);
+    attribute.miter.push(-1, -1);
+    attribute.vertices.push(x, y, z);
+    attribute.miter.push(1, -1);
+    attribute.vertices.push(x, y, z);
+    attribute.miter.push(1, 1);
+    attribute.colors.push(...color);
+    attribute.colors.push(...color);
+    attribute.colors.push(...color);
+    attribute.colors.push(...color);
+    attribute.colors.push(...color);
+    attribute.colors.push(...color);
+    attribute.pickingIds.push(id, id, id, id, id, id);
+  });
+  return attribute;
+}
diff --git a/src/geom/buffer/image.js b/src/geom/buffer/image.js
index 70b52aed51..262151b149 100644
--- a/src/geom/buffer/image.js
+++ b/src/geom/buffer/image.js
@@ -4,8 +4,9 @@ import * as THREE from '../../core/three';
 
 export default class ImageBuffer extends BufferBase {
   geometryBuffer() {
-    const coordinates = this.get('coordinates');
-    const images = this.get('image');
+    const layerData = this.get('layerData');
+    const coordinates = layerData[0].coordinates;
+    const images = layerData[0].images;
     const positions = [ ...coordinates[0],
       coordinates[1][0], coordinates[0][1], 0,
       ...coordinates[1],
diff --git a/src/geom/buffer/line.js b/src/geom/buffer/line.js
index a73006f07c..880ac2dc95 100644
--- a/src/geom/buffer/line.js
+++ b/src/geom/buffer/line.js
@@ -3,8 +3,7 @@ import { lineShape } from '../shape';
 
 export default class LineBuffer extends BufferBase {
   geometryBuffer() {
-    const coordinates = this.get('coordinates');
-    const properties = this.get('properties');
+    const layerData = this.get('layerData');
     const shapeType = this.shapeType = this.get('shapeType');
     const positions = [];
     const positionsIndex = [];
@@ -16,16 +15,16 @@ export default class LineBuffer extends BufferBase {
       this.attributes = this._getArcLineAttributes();
       return;
     }
-    coordinates.forEach((geo, index) => {
-      const props = properties[index];
-      const attrData = this._getShape(geo, props, index);
+    layerData.forEach((item, index) => {
+      const props = item;
+      const attrData = this._getShape(item.coordinates, props, index);
       positions.push(...attrData.positions);
       positionsIndex.push(...attrData.indexes);
       if (attrData.hasOwnProperty('instances')) {
         instances.push(...attrData.instances);
       }
     });
-    this.bufferStruct.style = properties;
+    this.bufferStruct.style = layerData;
     this.bufferStruct.verts = positions;
     this.bufferStruct.indexs = positionsIndex;
     if (instances.length > 0) {
@@ -50,17 +49,16 @@ export default class LineBuffer extends BufferBase {
 
   }
   _getArcLineAttributes() {
-    const coordinates = this.get('coordinates');
-    const properties = this.get('properties');
+    const layerData = this.get('layerData');
     const positions = [];
     const colors = [];
     const indexArray = [];
     const sizes = [];
     const instances = [];
-    coordinates.forEach((geo, index) => {
-      const props = properties[index];
+    layerData.forEach(item => {
+      const props = item;
       const positionCount = positions.length / 3;
-      const attrData = this._getShape(geo, props, positionCount);
+      const attrData = this._getShape(item.coordinates, props, positionCount);
       positions.push(...attrData.positions);
       colors.push(...attrData.colors);
       indexArray.push(...attrData.indexArray);
@@ -76,8 +74,7 @@ export default class LineBuffer extends BufferBase {
     };
   }
   _getMeshLineAttributes() {
-    const coordinates = this.get('coordinates');
-    const properties = this.get('properties');
+    const layerData = this.get('layerData');
     const { lineType } = this.get('style');
     const positions = [];
     const pickingIds = [];
@@ -87,10 +84,10 @@ export default class LineBuffer extends BufferBase {
     const indexArray = [];
     const sizes = [];
     const attrDistance = [];
-    coordinates.forEach((geo, index) => {
-      const props = properties[index];
+    layerData.forEach(item => {
+      const props = item;
       const positionCount = positions.length / 3;
-      const attr = lineShape.Line(geo, props, positionCount, (lineType !== 'soild'));
+      const attr = lineShape.Line(item.coordinates, props, positionCount, (lineType !== 'soild'));
       positions.push(...attr.positions);
       normal.push(...attr.normal);
       miter.push(...attr.miter);
diff --git a/src/geom/buffer/point/fillBuffer.js b/src/geom/buffer/point/fillBuffer.js
index 84d257c3ee..7179959827 100644
--- a/src/geom/buffer/point/fillBuffer.js
+++ b/src/geom/buffer/point/fillBuffer.js
@@ -3,7 +3,7 @@ import * as THREE from '../../../core/three';
 import * as polygonShape from '../../shape/polygon';
 import * as polygonPath from '../../shape/path';
 import Util from '../../../util';
-export default function fillBuffer(coordinates, properties) {
+export default function fillBuffer(layerData) {
   const attribute = {
     vertices: [],
     normals: [],
@@ -14,8 +14,8 @@ export default function fillBuffer(coordinates, properties) {
     faceUv: []
 
   };
-  coordinates.forEach((geo, index) => {
-    let { size, shape, color, id } = properties[index];
+  layerData.forEach(item => {
+    let { size, shape, color, id, coordinates } = item;
     let polygon = null;
     const path = polygonPath[shape]();
     if (pointShape['2d'].indexOf(shape) !== -1) {
@@ -27,7 +27,7 @@ export default function fillBuffer(coordinates, properties) {
     } else {
       throw new Error('Invalid shape type: ' + shape);
     }
-    toPointShapeAttributes(polygon, geo, { size, shape, color, id }, attribute);
+    toPointShapeAttributes(polygon, coordinates, { size, shape, color, id }, attribute);
 
   });
   return attribute;
diff --git a/src/geom/buffer/point/imageBuffer.js b/src/geom/buffer/point/imageBuffer.js
index 6bc37b052a..383134b6d9 100644
--- a/src/geom/buffer/point/imageBuffer.js
+++ b/src/geom/buffer/point/imageBuffer.js
@@ -1,4 +1,4 @@
-export default function ImageBuffer(coordinates, properties, opt) {
+export default function ImageBuffer(layerData, opt) {
   const attributes = {
     vertices: [],
     colors: [],
@@ -7,10 +7,10 @@ export default function ImageBuffer(coordinates, properties, opt) {
     pickingIds: [],
     uv: []
   };
-  coordinates.forEach((pos, index) => {
-    const { color, size, id, shape } = properties[index];
+  layerData.forEach(item => {
+    const { color, size, id, shape, coordinates } = item;
     const { x, y } = opt.imagePos[shape];
-    attributes.vertices.push(...pos);
+    attributes.vertices.push(...coordinates);
     attributes.colors.push(...color);
     attributes.pickingIds.push(id);
     attributes.sizes.push(size * window.devicePixelRatio); //
diff --git a/src/geom/buffer/point/normalBuffer.js b/src/geom/buffer/point/normalBuffer.js
index d35fd4217b..aaa50ee424 100644
--- a/src/geom/buffer/point/normalBuffer.js
+++ b/src/geom/buffer/point/normalBuffer.js
@@ -1,13 +1,13 @@
-export default function NormalBuffer(coordinates, properties) {
+export default function NormalBuffer(layerData) {
   const attributes = {
     vertices: [],
     colors: [],
     sizes: [],
     pickingIds: []
   };
-  coordinates.forEach((pos, index) => {
-    const { color, size, id } = properties[index];
-    attributes.vertices.push(...pos);
+  layerData.forEach(item => {
+    const { color, size, id, coordinates} = item;
+    attributes.vertices.push(...coordinates);
     attributes.colors.push(...color);
     attributes.pickingIds.push(id);
     attributes.sizes.push(size);
diff --git a/src/geom/buffer/point/strokeBuffer.js b/src/geom/buffer/point/strokeBuffer.js
index c71726cbd6..eff757e3c6 100644
--- a/src/geom/buffer/point/strokeBuffer.js
+++ b/src/geom/buffer/point/strokeBuffer.js
@@ -3,7 +3,7 @@ import * as polygonShape from '../../shape/polygon';
 import * as lineShape from '../../shape/line';
 import { pointShape } from '../../../global';
 import Util from '../../../util';
-export default function StrokeBuffer(coordinates, properties, style) {
+export default function StrokeBuffer(layerData, style) {
   const attribute = {
     shapes: [],
     normal: [],
@@ -15,8 +15,8 @@ export default function StrokeBuffer(coordinates, properties, style) {
     colors: []
   };
   const { stroke, strokeWidth } = style;
-  coordinates.forEach((geo, index) => {
-    let { size, shape, id } = properties[index];
+  layerData.forEach(item => {
+    let { size, shape, id, coordinates } = item;
     const path = polygonPath[shape]();
     const positionsIndex = attribute.miter.length;
     let polygon = null;
@@ -33,7 +33,7 @@ export default function StrokeBuffer(coordinates, properties, style) {
     } else {
       throw new Error('Invalid shape type: ' + shape);
     }
-    polygonLineBuffer(polygon, geo, size, attribute);
+    polygonLineBuffer(polygon, coordinates, size, attribute);
 
   });
   return attribute;
diff --git a/src/geom/buffer/point/textBuffer.js b/src/geom/buffer/point/textBuffer.js
index 0bbab7d759..1d68acb3b1 100644
--- a/src/geom/buffer/point/textBuffer.js
+++ b/src/geom/buffer/point/textBuffer.js
@@ -9,7 +9,7 @@ const metrics = {
   family: 'ios9',
   size: 24
 };
-export default function TextBuffer(coordinates, properties, style) {
+export default function TextBuffer(layerData, style) {
   EventEmitter.call(this);
   const attributes = {
     originPoints: [],
@@ -21,7 +21,7 @@ export default function TextBuffer(coordinates, properties, style) {
   const { textOffset = [ 0, 0 ] } = style;
   const chars = [];
   const textChars = {};
-  properties.forEach(element => {
+  layerData.forEach(element => {
     let text = element.shape || '';
     text = text.toString();
     for (let j = 0; j < text.length; j++) {
@@ -33,9 +33,9 @@ export default function TextBuffer(coordinates, properties, style) {
     }
   });
   loadTextInfo(chars, (chars, texture) => {
-    properties.forEach((element, index) => {
+    layerData.forEach(element => {
       const size = element.size;
-      const pos = coordinates[index];
+      const pos = layerData.coordinates;
       const pen = { x: textOffset[0], y: textOffset[1] };
       let text = element.shape || '';
       text = text.toString();
diff --git a/src/geom/buffer/polygon.js b/src/geom/buffer/polygon.js
index c90172802a..60c585d872 100644
--- a/src/geom/buffer/polygon.js
+++ b/src/geom/buffer/polygon.js
@@ -3,22 +3,21 @@ import BufferBase from './bufferBase';
 export default class PolygonBuffer extends BufferBase {
 
   geometryBuffer() {
-    const coordinates = this.get('coordinates');
-    const properties = this.get('properties');
+    const layerData = this.get('layerData');
     const shape = this.get('shape');
     const positions = [];
     const faceUv = [];
     const sizes = [];
     const positionsIndex = [];
     let indexCount = 0;
-    this.bufferStruct.style = properties;
-    const isExtrude = properties[0].hasOwnProperty('size');
+    this.bufferStruct.style = layerData;
+    const isExtrude = layerData[0].hasOwnProperty('size');
     // indices, normals, colors, UVs
-    coordinates.forEach((geo, index) => {
-      const heightValue = properties[index].size;
-      let extrudeData = polygonShape[shape](geo);
+    layerData.forEach(item => {
+      const heightValue = item.size;
+      let extrudeData = polygonShape[shape](item.coordinates);
       if (isExtrude && shape === 'extrude') {
-        extrudeData = polygonShape.extrude(geo);
+        extrudeData = polygonShape.extrude(item.coordinates);
         extrudeData.positions = extrudeData.positions.map(pos => {
           pos[2] *= heightValue;
           return pos;
@@ -48,7 +47,7 @@ export default class PolygonBuffer extends BufferBase {
     this.bufferStruct.indices = positionsIndex;
     this.bufferStruct.position = positions;
     this.bufferStruct.indexCount = indexCount;
-    this.bufferStruct.style = properties;
+    this.bufferStruct.style = layerData;
     this.bufferStruct.faceUv = faceUv;
     this.bufferStruct.sizes = sizes;
     if (shape !== 'line') {
diff --git a/src/geom/buffer/raster.js b/src/geom/buffer/raster.js
index 32fa14a3ba..9f62192699 100644
--- a/src/geom/buffer/raster.js
+++ b/src/geom/buffer/raster.js
@@ -3,8 +3,8 @@ import { colorScales } from '../../attr/colorscales';
 import * as THREE from '../../core/three';
 export class RasterBuffer extends BufferBase {
   geometryBuffer() {
-    const coordinates = this.get('coordinates');
-
+    const layerData = this.get('layerData');
+    const { coordinates, width, data, height } = layerData.dataArray[0];
     const positions = [
       ...coordinates[0],
       coordinates[1][0], coordinates[0][1], 0,
@@ -14,9 +14,8 @@ export class RasterBuffer extends BufferBase {
       coordinates[0][0], coordinates[1][1], 0
     ];
     const imgPosUv = [ 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0 ];
-    const raster = this.get('raster');
     const size = this.get('size');
-    const texture = new THREE.DataTexture(new Float32Array(raster.data), raster.width, raster.height, THREE.LuminanceFormat, THREE.FloatType);
+    const texture = new THREE.DataTexture(new Float32Array(data), width, height, THREE.LuminanceFormat, THREE.FloatType);
     texture.generateMipmaps = true;
     texture.needsUpdate = true;
     const colors = this.get('rampColors');
@@ -28,7 +27,7 @@ export class RasterBuffer extends BufferBase {
     this.bufferStruct.u_extent = [ coordinates[0][0], coordinates[0][1], coordinates[1][0], coordinates[1][1] ];
 
     this.bufferStruct.u_colorTexture = colorTexture; // 颜色表‘=
-    const triangles = this._buildTriangles(raster, size, this.bufferStruct.u_extent);
+    const triangles = this._buildTriangles(width, height, size, this.bufferStruct.u_extent);
     const attributes = {
       vertices: new Float32Array(triangles.vertices),
       uvs: new Float32Array(triangles.uvs),
@@ -78,9 +77,8 @@ export class RasterBuffer extends BufferBase {
     texture1.needsUpdate = true;
     return texture1;
   }
-  _buildTriangles(raster, size = 1, extent) {
+  _buildTriangles(width, height, size = 1, extent) {
     // const extent = [ 73.482190241, 3.82501784112, 135.106618732, 57.6300459963 ]
-    const { width, height } = raster;
     const indices = [];
     const vertices = [];
     const uvs = [];
diff --git a/src/geom/buffer/text.js b/src/geom/buffer/text.js
index 099f6d217f..5f906352b4 100644
--- a/src/geom/buffer/text.js
+++ b/src/geom/buffer/text.js
@@ -13,12 +13,11 @@ export default class TextBuffer extends BufferBase {
       family: 'ios9',
       size: 24
     };
-    const coordinates = this.get('coordinates');
-    const properties = this.get('properties');
+    const layerData = this.get('layerData');
     const { textOffset = [ 0, 0 ] } = this.get('style');
     const chars = [];
     const textChars = {};
-    properties.forEach(element => {
+    layerData.forEach(element => {
       let text = element.shape || '';
       text = text.toString();
       for (let j = 0; j < text.length; j++) {
@@ -39,9 +38,9 @@ export default class TextBuffer extends BufferBase {
       const originPoints = [];
       const textSizes = [];
       const textOffsets = [];
-      properties.forEach((element, index) => {
+      layerData.forEach(element => {
         const size = element.size;
-        const pos = coordinates[index];
+        const pos = element.coordinates;
         // const pen = { x: pos[0] - dimensions.advance / 2, y: pos[1] };
         const pen = { x: textOffset[0], y: textOffset[1] };
         let text = element.shape || '';
@@ -53,7 +52,7 @@ export default class TextBuffer extends BufferBase {
           this._drawGlyph(pos, text[i], pen, size, colors, textureElements, originPoints, textSizes, textOffsets, color);
         }
       });
-      this.bufferStruct.style = properties;
+      this.bufferStruct.style = layerData;
       this.attributes = {
         originPoints,
         textSizes,
diff --git a/src/geom/material/grid.js b/src/geom/material/grid.js
new file mode 100644
index 0000000000..65db262fcf
--- /dev/null
+++ b/src/geom/material/grid.js
@@ -0,0 +1,31 @@
+import grid_frag from '../shader/grid_frag.glsl';
+import grid_vert from '../shader/grid_vert.glsl';
+import Material from './material';
+
+
+export default class GridMaterial extends Material {
+  getDefaultParameters() {
+    return {
+      uniforms: {
+        u_opacity: { value: 1.0 },
+        u_time: { value: 0 },
+        u_xOffset: { value: 0.01 },
+        u_yOffset: { value: 0.01 },
+        u_coverage: { value: 0.8 }
+      },
+      defines: {
+
+      }
+    };
+  }
+  constructor(_uniforms, _defines, parameters) {
+    super(parameters);
+    const { uniforms, defines } = this.getDefaultParameters();
+    this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms));
+    this.type = 'GridMaterial';
+    this.defines = Object.assign(defines, _defines);
+    this.vertexShader = grid_vert;
+    this.fragmentShader = grid_frag;
+    this.transparent = true;
+  }
+}
diff --git a/src/geom/shader/grid_frag.glsl b/src/geom/shader/grid_frag.glsl
new file mode 100644
index 0000000000..042dde511e
--- /dev/null
+++ b/src/geom/shader/grid_frag.glsl
@@ -0,0 +1,8 @@
+    precision highp float;
+    uniform float u_opacity;
+    varying vec4 v_color;
+    void main() {
+      vec4 color = v_color;
+      gl_FragColor = color;
+      gl_FragColor.a =color.a*u_opacity;
+}
\ No newline at end of file
diff --git a/src/geom/shader/grid_vert.glsl b/src/geom/shader/grid_vert.glsl
new file mode 100644
index 0000000000..90c68a3b70
--- /dev/null
+++ b/src/geom/shader/grid_vert.glsl
@@ -0,0 +1,15 @@
+precision highp float;
+attribute vec2 miter;
+attribute vec4 a_color;
+uniform float u_xOffset;
+uniform float u_yOffset;
+uniform float u_coverage;
+varying vec4 v_color;
+
+void main() {
+   mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
+   v_color = a_color;
+  float x = position.x + miter.x * u_xOffset * u_coverage;
+  float y = position.y + miter.y * u_yOffset * u_coverage;
+  gl_Position = matModelViewProjection * vec4(x, y, position.z, 1.0);
+}
\ No newline at end of file
diff --git a/src/layer/heatmap.js b/src/layer/heatmap.js
new file mode 100644
index 0000000000..f9971a55da
--- /dev/null
+++ b/src/layer/heatmap.js
@@ -0,0 +1,28 @@
+import Layer from '../core/layer';
+import gridBuffer from '../geom/buffer/heatmap/grid';
+import DrawGrid from './render/heatmap/gird';
+
+export default class HeatMapLayer extends Layer {
+  shape(type) {
+    this.shapeType = type;
+    return this;
+  }
+  render() {
+    this._prepareRender();
+    return this;
+  }
+  _prepareRender() {
+    this.init();
+    this.type = 'heatmap';
+    const style = this.get('styleOptions');
+    const { xOffset, yOffset } = this.layerSource.data;
+    this._buffer = new gridBuffer(this.layerData);
+    const config = {
+      ...style,
+      xOffset,
+      yOffset
+    };
+    const girdMesh = new DrawGrid(this._buffer, config);
+    this.add(girdMesh);
+  }
+}
diff --git a/src/layer/imageLayer.js b/src/layer/imageLayer.js
index f3092da117..92e9a60b59 100644
--- a/src/layer/imageLayer.js
+++ b/src/layer/imageLayer.js
@@ -1,26 +1,19 @@
 import Layer from '../core/layer';
 import * as THREE from '../core/three';
-import imageSource from '../source/imageSource';
 import ImageBuffer from '../geom/buffer/image';
 // import ImageGeometry from '../geom/bufferGeometry/image';
 import ImageMaterial from '../geom/material/imageMaterial';
 export default class imageLayer extends Layer {
-  source(data, cfg = {}) {
-    cfg.mapType = this.get('mapType');
-    cfg.data = data;
-    this.layerSource = new imageSource(cfg);
-    return this;
-  }
   render() {
     this.init();
     this.type = 'image';
     const source = this.layerSource;
     const { opacity } = this.get('styleOptions');
     // 加载 完成事件
-    source.on('imageLoaded', () => {
+    source.data.images.then(images => {
+      this.layerData[0].images = images;
       const buffer = new ImageBuffer({
-        coordinates: source.geoData,
-        image: source.image
+        layerData: this.layerData
       });
       this.initGeometry(buffer.attributes);
       const material = new ImageMaterial({
diff --git a/src/layer/index.js b/src/layer/index.js
index 5e8fef27c6..1c2cad2fdf 100644
--- a/src/layer/index.js
+++ b/src/layer/index.js
@@ -4,17 +4,14 @@ import PointLayer from './pointLayer';
 import LineLayer from './lineLayer';
 import ImageLayer from './imageLayer';
 import RasterLayer from './rasterLayer';
+import HeatMapLayer from './heatmap';
 
 registerLayer('PolygonLayer', PolygonLayer);
 registerLayer('PointLayer', PointLayer);
 registerLayer('LineLayer', LineLayer);
 registerLayer('ImageLayer', ImageLayer);
 registerLayer('RasterLayer', RasterLayer);
+registerLayer('HeatMapLayer', HeatMapLayer);
 
 export { LAYER_MAP } from './factory';
-export { default as PolygonLayer } from './polygonLayer';
-export { default as PointLayer } from './pointLayer';
-export { default as LineLayer } from './lineLayer';
-export { default as ImageLayer } from './imageLayer';
-export { default as RasterLayer } from './rasterLayer';
 
diff --git a/src/layer/lineLayer.js b/src/layer/lineLayer.js
index 4d40755100..c83c3f0a88 100644
--- a/src/layer/lineLayer.js
+++ b/src/layer/lineLayer.js
@@ -12,11 +12,10 @@ export default class LineLayer extends Layer {
     this.type = 'polyline';
     this.init();
     const source = this.layerSource;
-    const StyleData = this.StyleData;
+    const layerData = this.layerData;
     const style = this.get('styleOptions');
     const buffer = this._buffer = new LineBuffer({
-      coordinates: source.geoData,
-      properties: StyleData,
+      layerData,
       shapeType: this.shapeType,
       style
     });
diff --git a/src/layer/pointLayer.js b/src/layer/pointLayer.js
index a21a80b4a7..02acff004f 100644
--- a/src/layer/pointLayer.js
+++ b/src/layer/pointLayer.js
@@ -46,12 +46,12 @@ export default class PointLayer extends Layer {
       case 'fill' :// 填充图形
         {
           if (fill !== 'none') { // 是否填充
-            const attributes = PointBuffer.FillBuffer(source.geoData, this.StyleData, style);
+            const attributes = PointBuffer.FillBuffer(this.layerData, style);
             const meshfill = drawPoint.DrawFill(attributes, this.get('styleOptions'));
             this.add(meshfill);
           }
           if (stroke !== 'none') { // 是否绘制边界
-            const lineAttribute = PointBuffer.StrokeBuffer(source.geoData, this.StyleData, style);
+            const lineAttribute = PointBuffer.StrokeBuffer(this.layerData, style);
             const meshStroke = drawPoint.DrawStroke(lineAttribute, this.get('styleOptions'));
             this.add(meshStroke, 'line');
           }
@@ -59,14 +59,14 @@ export default class PointLayer extends Layer {
         }
       case 'image':// 绘制图片标注
         {
-          const imageAttribute = PointBuffer.ImageBuffer(source.geoData, this.StyleData, { imagePos: this.scene.image.imagePos });
+          const imageAttribute = PointBuffer.ImageBuffer(this.layerData, { imagePos: this.scene.image.imagePos });
           const imageMesh = drawPoint.DrawImage(imageAttribute, { ...style, texture: this.scene.image.texture });
           this.add(imageMesh);
           break;
         }
       case 'normal' : // 原生点
         {
-          const normalAttribute = PointBuffer.NormalBuffer(source.geoData, this.StyleData, style);
+          const normalAttribute = PointBuffer.NormalBuffer(this.layerData, style);
           const normalPointMesh = drawPoint.DrawNormal(normalAttribute, style);
           this.add(normalPointMesh);
           break;
@@ -78,11 +78,11 @@ export default class PointLayer extends Layer {
 
   _getShape() {
     let shape = null;
-    if (!this.StyleData[0].hasOwnProperty('shape')) {
+    if (!this.layerData[0].hasOwnProperty('shape')) {
       return 'normal';
     }
-    for (let i = 0; i < this.StyleData.length; i++) {
-      shape = this.StyleData[i].shape;
+    for (let i = 0; i < this.layerData.length; i++) {
+      shape = this.layerData[i].shape;
       if (shape !== undefined) {
         break;
       }
@@ -103,8 +103,7 @@ export default class PointLayer extends Layer {
     const styleOptions = this.get('styleOptions');
     const buffer = new TextBuffer({
       type: this.shapeType,
-      coordinates: source.geoData,
-      properties: this.StyleData,
+      layerData: this.layerData,
       style: this.get('styleOptions')
     });
 
diff --git a/src/layer/polygonLayer.js b/src/layer/polygonLayer.js
index 53e7c9903e..ba37ed3b87 100644
--- a/src/layer/polygonLayer.js
+++ b/src/layer/polygonLayer.js
@@ -21,11 +21,9 @@ export default class PolygonLayer extends Layer {
   _prepareRender() {
     this.init();
     this.type = 'polygon';
-    const source = this.layerSource;
     this._buffer = new PolygonBuffer({
       shape: this.shape,
-      coordinates: source.geoData,
-      properties: this.StyleData
+      layerData: this.layerData
     });
     this.add(this._getLayerRender());
   }
diff --git a/src/layer/rasterLayer.js b/src/layer/rasterLayer.js
index 7a68dc8530..cb5d9f41a9 100644
--- a/src/layer/rasterLayer.js
+++ b/src/layer/rasterLayer.js
@@ -1,16 +1,10 @@
 import Layer from '../core/layer';
 import * as THREE from '../core/three';
-import RasterSource from '../source/rasterSource';
 import RasterMaterial from '../geom/material/rasterMaterial';
 import { RasterBuffer } from '../geom/buffer/raster';
 
 export default class RasterLayer extends Layer {
-  source(data, cfg = {}) {
-    cfg.mapType = this.get('mapType');
-    cfg.data = data;
-    this.layerSource = new RasterSource(cfg);
-    return this;
-  }
+
   render() {
     this.type = 'raster';
     this.init();
@@ -18,18 +12,18 @@ export default class RasterLayer extends Layer {
     // 加载 完成事件
     const styleOptions = this.get('styleOptions');
     const buffer = new RasterBuffer({
-      coordinates: source.geoData,
-      raster: source.rasterData,
+      layerData: source.data,
       rampColors: styleOptions.rampColors
     });
     this.initGeometry(buffer.attributes);
+    const rasterConfig = source.data.dataArray[0];
     const material = new RasterMaterial({
       u_texture: buffer.bufferStruct.u_raster,
       u_colorTexture: buffer.bufferStruct.u_colorTexture,
       u_opacity: 1.0,
       u_extent: buffer.bufferStruct.u_extent,
-      u_min: source.rasterData.min,
-      u_max: source.rasterData.max,
+      u_min: rasterConfig.min,
+      u_max: rasterConfig.max,
       u_dimension: buffer.attributes.dimension
 
     });
diff --git a/src/layer/render/heatmap/gird.js b/src/layer/render/heatmap/gird.js
new file mode 100644
index 0000000000..5aa4b07796
--- /dev/null
+++ b/src/layer/render/heatmap/gird.js
@@ -0,0 +1,21 @@
+import * as THREE from '../../../core/three';
+import GridMaterial from '../../../geom/material/grid';
+export default function DrawGrid(attributes, style) {
+  const { opacity, xOffset, yOffset, coverage } = style;
+  const geometry = new THREE.BufferGeometry();
+  geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
+  geometry.addAttribute('miter', new THREE.Float32BufferAttribute(attributes.miter, 2));
+  geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
+  geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
+  const material = new GridMaterial({
+    u_opacity: opacity,
+    u_xOffset: xOffset,
+    u_yOffset: yOffset,
+    u_coverage: coverage
+  }, {
+    SHAPE: false
+  });
+  const gridMesh = new THREE.Mesh(geometry, material);
+  return gridMesh;
+}
+
diff --git a/src/source/csvSource.js b/src/source/csvSource.js
deleted file mode 100644
index e5ce0b9834..0000000000
--- a/src/source/csvSource.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import Source from '../core/source';
-import FeatureIndex from '../geo/featureIndex';
-import { csvParse } from 'd3-dsv';
-export default class CSVSource extends Source {
-  prepareData() {
-    this.type = 'csv';
-    const data = this.get('data');
-    const x = this.get('x');
-    const y = this.get('y');
-    const x1 = this.get('x1');
-    const y1 = this.get('y1');
-    const coords = this.get('coordinates');
-    this.propertiesData = [];// 临时使用
-    this.geoData = [];
-    let csvdata = data;
-    Array.isArray(csvdata) || (csvdata = csvParse(data));
-    this.propertiesData = csvdata;
-    csvdata.forEach((col, featureIndex) => {
-      let coordinates = [];
-      if (col.coordinates) {
-        coordinates = col.coordinates;
-      }
-      if (x && y) { coordinates = [ col[x], col[y] ]; } // 点数据
-      if (x1 && y1) { // 弧线 或者线段
-        coordinates = [[ col[x], col[y] ], [ col[x1], col[y1] ]];
-      }
-      if (coords && col.coords) { coordinates = col.coords; }
-      col._id = featureIndex + 1;
-      this._coordProject(coordinates);
-      this.geoData.push(this._coordProject(coordinates));
-    });
-  }
-
-  featureIndex() {
-    const data = this.get('data');
-    this.featureIndex = new FeatureIndex(data);
-  }
-  getSelectFeatureId(featureId) {
-    return [ featureId ];
-  }
-  getSelectFeature(featureId) {
-    return this.propertiesData[featureId];
-
-  }
-  _getCoord(geo) {
-    if (geo.geometry) {
-      // GeoJSON feature
-      geo = geo.geometry.coordinates;
-    } else if (geo.coordinates) {
-      // GeoJSON geometry
-      geo = geo.coordinates;
-    }
-    return geo;
-  }
-  _coordProject(geo) {
-    if (Array.isArray(geo[0][0])) {
-      return geo.map(coor => {
-        return this._coordProject(coor);
-      });
-    }
-    if (!Array.isArray(geo[0])) {
-      return this._coorConvert(geo);
-    }
-    return geo.map(coor => {
-      return this._coorConvert(coor);
-    });
-  }
-
-}
diff --git a/src/source/factory.js b/src/source/factory.js
new file mode 100644
index 0000000000..37629b9e99
--- /dev/null
+++ b/src/source/factory.js
@@ -0,0 +1,11 @@
+
+const TRANSFORMS = {};
+const PARSERS = {};
+export const getParser = type => PARSERS[type];
+export const registerParser = (type, parserFunction) => {
+  PARSERS[type] = parserFunction;
+};
+export const getTransform = type => TRANSFORMS[type];
+export const registerTransform = (type, transFunction) => {
+  TRANSFORMS[type] = transFunction;
+};
diff --git a/src/source/geojsonSource.js b/src/source/geojsonSource.js
deleted file mode 100644
index df38e3fd13..0000000000
--- a/src/source/geojsonSource.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import Source from '../core/source';
-import * as turfMeta from '@turf/meta';
-import { default as cleanCoords } from '@turf/clean-coords';
-import { getCoords } from '@turf/invariant';
-import FeatureIndex from '../geo/featureIndex';
-
-export default class GeojsonSource extends Source {
-  prepareData() {
-    this.type = 'geojson';
-    const data = this.get('data');
-    this.propertiesData = [];
-    this.geoData = [];
-    turfMeta.flattenEach(data, (currentFeature, featureIndex) => {
-      const coord = getCoords(cleanCoords(currentFeature));
-      this.geoData.push(this._coordProject(coord));
-      currentFeature.properties._id = featureIndex + 1;
-      this.propertiesData.push(currentFeature.properties);
-    });
-  }
-  featureIndex() {
-    const data = this.get('data');
-    this.featureIndex = new FeatureIndex(data);
-  }
-  getSelectFeatureId(featureId) {
-    const data = this.get('data');
-    const selectFeatureIds = [];
-    let featureStyleId = 0;
-     /* eslint-disable */
-    turfMeta.flattenEach(data, (currentFeature, featureIndex, multiFeatureIndex) => {
-      /* eslint-disable */
-        if (featureIndex === (featureId)) {
-          selectFeatureIds.push(featureStyleId);
-        }
-        featureStyleId++;
-        if (featureIndex > featureId) {
-          return;
-        }
-      });
-    return selectFeatureIds;
-    
-  }
-  getSelectFeature(featureId){
-    const data = this.get('data');
-    return  data.features[featureId];
-  }
-
-}
diff --git a/src/source/imageSource.js b/src/source/imageSource.js
deleted file mode 100644
index 137f5a0772..0000000000
--- a/src/source/imageSource.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import Source from '../core/source';
-import { getImage } from '../util/ajax';
-export default class ImageSource extends Source {
-  prepareData() {
-    this.type = 'image';
-    const extent = this.get('extent');
-    const lb = this._coorConvert(extent.slice(0, 2));
-    const tr = this._coorConvert(extent.slice(2, 4));
-    this.geoData = [ lb, tr ];
-    this.propertiesData = [];
-    this._loadData();
-  }
-  _loadData() {
-    const url = this.get('data');
-    this.image = [];
-    if (typeof (url) === 'string') {
-      getImage({ url }, (err, img) => {
-        this.image = img;
-        this.emit('imageLoaded');
-      });
-    } else {
-      const imageCount = url.length;
-      let imageindex = 0;
-      url.forEach(item => {
-        getImage({ url: item }, (err, img) => {
-          imageindex++;
-          this.image.push(img);
-          if (imageindex === imageCount) {
-            this.emit('imageLoaded');
-          }
-
-        });
-      });
-
-    }
-  }
-}
diff --git a/src/source/index.js b/src/source/index.js
index ea6b260c09..307819cc1f 100644
--- a/src/source/index.js
+++ b/src/source/index.js
@@ -1,5 +1,23 @@
-export { default as geojson } from './geojsonSource';
-export { default as csv } from './csvSource';
-export { default as array } from './csvSource';
-export { default as basic } from '../core/source';
-export { default as imageSource } from './imageSource';
+// source parser
+
+import geojson from './parser/geojson';
+import image from './parser/image';
+import csv from './parser/csv';
+import json from './parser/json';
+import raster from './parser/raster';
+
+import { registerTransform, registerParser } from './factory';
+import { aggregatorToGrid } from './transform/grid-aggregator';
+import { map } from './transform/map';
+
+registerParser('geojson', geojson);
+registerParser('image', image);
+registerParser('csv', csv);
+registerParser('json', json);
+registerParser('raster', raster);
+// 注册transform
+
+registerTransform('grid', aggregatorToGrid);
+registerTransform('map', map);
+
+export { getTransform, registerTransform, getParser, registerParser } from './factory';
diff --git a/src/source/parser/csv.js b/src/source/parser/csv.js
new file mode 100644
index 0000000000..f727d18209
--- /dev/null
+++ b/src/source/parser/csv.js
@@ -0,0 +1,23 @@
+import { csvParse } from 'd3-dsv';
+export default function csv(data, cfg) {
+  const { x, y, x1, y1 } = cfg;
+  const csvdata = csvParse(data);
+  const resultdata = [];
+  csvdata.forEach((col, featureIndex) => {
+    let coordinates = [];
+    if (x && y) { coordinates = [ col[x], col[y] ]; } // 点数据
+    if (x1 && y1) { // 弧线 或者线段
+      coordinates = [[ col[x], col[y] ], [ col[x1], col[y1] ]];
+    }
+    col._id = featureIndex + 1;
+    const dataItem = {
+      ...col,
+      coordinates
+
+    };
+    resultdata.push(dataItem);
+  });
+  return {
+    dataArray: resultdata
+  };
+}
diff --git a/src/source/parser/geojson.js b/src/source/parser/geojson.js
new file mode 100644
index 0000000000..6385fa0d42
--- /dev/null
+++ b/src/source/parser/geojson.js
@@ -0,0 +1,19 @@
+import * as turfMeta from '@turf/meta';
+import { default as cleanCoords } from '@turf/clean-coords';
+import { getCoords } from '@turf/invariant';
+
+export default function geoJSON(data) {
+  const resultData = [];
+  turfMeta.flattenEach(data, (currentFeature, featureIndex) => { // 多个polygon 拆成一个
+    const coord = getCoords(cleanCoords(currentFeature));
+    const dataItem = {
+      ...currentFeature.properties,
+      coordinates: coord,
+      _id: featureIndex + 1
+    };
+    resultData.push(dataItem);
+  });
+  return {
+    dataArray: resultData
+  };
+}
diff --git a/src/source/parser/image.js b/src/source/parser/image.js
new file mode 100644
index 0000000000..e4a6f99ddf
--- /dev/null
+++ b/src/source/parser/image.js
@@ -0,0 +1,41 @@
+import { getImage } from '../../util/ajax';
+export default function image(data, cfg) {
+  const { extent } = cfg;
+
+  const images = new Promise(resolve => {
+    loadData(data, res => {
+      resolve(res);
+    });
+  });
+  const resultData = {
+    images,
+    _id: 1,
+    dataArray: [{ coordinates: [[ extent[0], extent[1] ], [ extent[2], extent[3] ]] }]
+  };
+  return resultData;
+}
+function loadData(data, done) {
+  const url = data;
+  let image = [];
+  if (typeof (url) === 'string') {
+    getImage({ url }, (err, img) => {
+      image = img;
+      done(image);
+    });
+  } else {
+    const imageCount = url.length;
+    let imageindex = 0;
+    url.forEach(item => {
+      getImage({ url: item }, (err, img) => {
+        imageindex++;
+        image.push(img);
+        if (imageindex === imageCount) {
+          done(image);
+        }
+
+      });
+    });
+
+  }
+  return image;
+}
diff --git a/src/source/parser/json.js b/src/source/parser/json.js
new file mode 100644
index 0000000000..37128bebce
--- /dev/null
+++ b/src/source/parser/json.js
@@ -0,0 +1,21 @@
+export default function json(data, cfg) {
+  const { x, y, x1, y1 } = cfg;
+  const resultdata = [];
+  data.forEach((col, featureIndex) => {
+    let coordinates = [];
+    if (x && y) { coordinates = [ col[x], col[y] ]; } // 点数据
+    if (x1 && y1) { // 弧线 或者线段
+      coordinates = [[ col[x], col[y] ], [ col[x1], col[y1] ]];
+    }
+    col._id = featureIndex + 1;
+    const dataItem = {
+      ...col,
+      coordinates
+
+    };
+    resultdata.push(dataItem);
+  });
+  return {
+    dataArray: resultdata
+  };
+}
diff --git a/src/source/parser/raster.js b/src/source/parser/raster.js
new file mode 100644
index 0000000000..7d33903a23
--- /dev/null
+++ b/src/source/parser/raster.js
@@ -0,0 +1,15 @@
+export default function raster(data, cfg) {
+  const { extent, width, height, min, max } = cfg;
+  const resultData = {
+    _id: 1,
+    dataArray: [
+      {
+        data,
+        width,
+        height,
+        min,
+        max,
+        coordinates: [[ extent[0], extent[1] ], [ extent[2], extent[3] ]] }]
+  };
+  return resultData;
+}
diff --git a/src/source/rainSource.js b/src/source/rainSource.js
deleted file mode 100644
index 6808878742..0000000000
--- a/src/source/rainSource.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import imageSource from './imageSource';
-export class RainSource extends imageSource {
-  prepareData() {
-    const extent = this.get('extent');
-    const lb = this._coorConvert(extent.slice(0, 2));
-    const tr = this._coorConvert(extent.slice(2, 4));
-    this.extent = [ lb, tr ];
-    this.propertiesData = [];
-    this._genaratePoints();
-    this._loadData();
-  }
-  _genaratePoints() {
-    const numParticles = 512 * 512;
-
-    const particleRes = this.particleRes = Math.ceil(Math.sqrt(numParticles));
-    const numPoints = particleRes * particleRes;
-    const particleState = [];
-    const particleState0 = new Uint8ClampedArray(numPoints * 4);
-    const particleState1 = new Uint8ClampedArray(numPoints * 4);
-    const emptyPixels = new Uint8ClampedArray(numPoints * 4);
-    for (let i = 0; i < particleState0.length; i++) {
-      particleState0[i] = Math.floor(Math.random() * 256); // randomize the initial particle positions
-    }
-    this.particleIndices = new Float32Array(numPoints);
-    for (let i = 0; i < numPoints; i++) this.particleIndices[i] = i;
-    this.particleImage0 = new ImageData(particleState0, particleRes, particleRes);
-    this.particleImage1 = new ImageData(particleState1, particleRes, particleRes);
-    this.backgroundImage = new ImageData(emptyPixels, particleRes, particleRes);
-    this.geoData = particleState;
-  }
-}
diff --git a/src/source/rasterSource.js b/src/source/rasterSource.js
deleted file mode 100644
index 2439422dce..0000000000
--- a/src/source/rasterSource.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import Source from '../core/source';
-export default class RasterSource extends Source {
-  prepareData() {
-    this.type = 'raster';
-    const extent = this.get('extent');
-    const lb = this._coorConvert(extent.slice(0, 2));
-    const tr = this._coorConvert(extent.slice(2, 4));
-    this.geoData = [ lb, tr ];
-    this.propertiesData = [];
-    this.rasterData = {
-      data: this.get('data'),
-      width: this.get('width'),
-      height: this.get('height'),
-      min: this.get('min'),
-      max: this.get('max')
-    };
-
-  }
-
-}
diff --git a/src/source/transform/grid-aggregator.js b/src/source/transform/grid-aggregator.js
new file mode 100644
index 0000000000..d2ace3476c
--- /dev/null
+++ b/src/source/transform/grid-aggregator.js
@@ -0,0 +1,101 @@
+/**
+ * 生成四边形热力图
+ */
+import * as statistics from './statistics';
+
+const R_EARTH = 6378000;
+
+/**
+ * 计算方格密度图
+ * @param {*} data 经纬度数据 和属性数据
+ * @param {*} size 半径大小 单位 km
+ * @return
+ */
+export function aggregatorToGrid(data, option) {
+  const dataArray = data.dataArray;
+  const { size = 10 } = option;
+  const { gridHash, gridOffset } = _pointsGridHash(dataArray, size);
+  const layerData = _getGridLayerDataFromGridHash(gridHash, gridOffset, option);
+  return {
+    xOffset: gridOffset.xOffset / 360 * (256 << 20) / 2,
+    yOffset: gridOffset.xOffset / 360 * (256 << 20) / 2,
+    dataArray: layerData
+  };
+}
+
+function _pointsGridHash(dataArray, size) {
+  let latMin = Infinity;
+  let latMax = -Infinity;
+  let pLat;
+  for (let index = 0; index < dataArray.length; index++) {
+    const point = dataArray[index];
+    pLat = point.coordinates[1];
+    if (Number.isFinite(pLat)) {
+      latMin = pLat < latMin ? pLat : latMin;
+      latMax = pLat > latMax ? pLat : latMax;
+    }
+
+  }
+  // const centerLat = (latMin + latMax) / 2;
+  const centerLat = 34.54083;
+  const gridOffset = _calculateGridLatLonOffset(size, centerLat);
+  if (gridOffset.xOffset <= 0 || gridOffset.yOffset <= 0) {
+    return { gridHash: {}, gridOffset };
+  }
+  const gridHash = {};
+  for (let index = 0; index < dataArray.length; index++) {
+    const point = dataArray[index];
+    const lat = point.coordinates[1];
+    const lng = point.coordinates[0];
+
+    if (Number.isFinite(lat) && Number.isFinite(lng)) {
+      const latIdx = Math.floor((lat + 90) / gridOffset.yOffset);
+      const lonIdx = Math.floor((lng + 180) / gridOffset.xOffset);
+      const key = `${latIdx}-${lonIdx}`;
+
+      gridHash[key] = gridHash[key] || { count: 0, points: [] };
+      gridHash[key].count += 1;
+      gridHash[key].points.push(point);
+    }
+  }
+
+  return { gridHash, gridOffset };
+}
+// 计算网格偏移量
+function _calculateGridLatLonOffset(cellSize, latitude) {
+  const yOffset = _calculateLatOffset(cellSize);
+  const xOffset = _calculateLonOffset(latitude, cellSize);
+  return { yOffset, xOffset };
+}
+
+function _calculateLatOffset(dy) {
+  return (dy / R_EARTH) * (180 / Math.PI);
+}
+
+function _calculateLonOffset(lat, dx) {
+  return ((dx / R_EARTH) * (180 / Math.PI)) / Math.cos((lat * Math.PI) / 180);
+}
+function _getGridLayerDataFromGridHash(gridHash, gridOffset, option) {
+  return Object.keys(gridHash).reduce((accu, key, i) => {
+    const idxs = key.split('-');
+    const latIdx = parseInt(idxs[0], 10);
+    const lonIdx = parseInt(idxs[1], 10);
+    const item = {};
+    if (option.field && option.method) {
+      const columns = getColumn(gridHash[key].points, option.field);
+      item[option.method] = statistics[option.method](columns);
+    }
+    Object.assign(item, {
+      _id: i + 1,
+      coordinates: [ -180 + gridOffset.xOffset * lonIdx, -90 + gridOffset.yOffset * latIdx ],
+      count: gridHash[key].count
+    });
+    accu.push(item);
+    return accu;
+  }, []);
+}
+function getColumn(data, columnName) {
+  return data.map(item => {
+    return item[columnName];
+  });
+}
diff --git a/src/source/transform/map.js b/src/source/transform/map.js
new file mode 100644
index 0000000000..47c66e1005
--- /dev/null
+++ b/src/source/transform/map.js
@@ -0,0 +1,7 @@
+export function map(data, options) {
+  const { callback } = options;
+  if (callback) {
+    data.dataArray = data.dataArray.map(callback);
+  }
+  return data;
+}
diff --git a/src/source/transform/statistics.js b/src/source/transform/statistics.js
new file mode 100644
index 0000000000..2a7a317846
--- /dev/null
+++ b/src/source/transform/statistics.js
@@ -0,0 +1,10 @@
+/* 支持 'max', 'mean', 'median', 'min', 'mode', 'product', 'standardDeviation',
+   *     'sum', 'sumSimple', 'variance', 'count', 'distinct'
+   */
+export { default as min } from 'simple-statistics/src/min';
+export { default as max } from 'simple-statistics/src/max';
+export { default as mean } from 'simple-statistics/src/mean';
+export { default as sum } from 'simple-statistics/src/sum';
+export { default as median } from 'simple-statistics/src/median';
+export { default as standardDeviation } from 'simple-statistics/src/standard_deviation';
+

From 4319210237ca3e8ed3fc1d654ddf2ba3d67a9fc9 Mon Sep 17 00:00:00 2001
From: thinkinggis <lzx199065@gmail.com>
Date: Tue, 26 Feb 2019 16:06:43 +0800
Subject: [PATCH 8/9] feat(source): hexagon

---
 package.json                                  |    1 +
 src/geo/lngLat.js                             |   87 +-
 src/geo/project.js                            |   17 +-
 src/source/index.js                           |    2 +-
 .../transform/{grid-aggregator.js => grid.js} |    0
 src/source/transform/hexagon.js               |   41 +
 test/asset/data/point.js                      | 1490 +++++++++++++++++
 test/unit/source/transfrom/hexagon.js         |   21 +
 8 files changed, 1641 insertions(+), 18 deletions(-)
 rename src/source/transform/{grid-aggregator.js => grid.js} (100%)
 create mode 100644 src/source/transform/hexagon.js
 create mode 100644 test/asset/data/point.js
 create mode 100644 test/unit/source/transfrom/hexagon.js

diff --git a/package.json b/package.json
index 3ee6803cde..a7004447ea 100755
--- a/package.json
+++ b/package.json
@@ -101,6 +101,7 @@
     "@turf/invariant": "^6.1.2",
     "@turf/meta": "^6.0.2",
     "d3-dsv": "^1.0.10",
+    "d3-hexbin": "^0.2.2",
     "earcut": "^2.1.3",
     "fecha": "^2.3.3",
     "gl-matrix": "^2.4.1",
diff --git a/src/geo/lngLat.js b/src/geo/lngLat.js
index edc7b59576..b635918f0c 100644
--- a/src/geo/lngLat.js
+++ b/src/geo/lngLat.js
@@ -1,20 +1,75 @@
-export class LatLng {
-  constructor(lat, lng, alt) {
-    if (isNaN(lat) || isNaN(lng)) {
-      throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');
-    }
-    this.lat = +lat;
-    this.lng = +lng;
-    if (alt !== undefined) {
-      this.alt = +alt;
-    }
+self._wkHandlers={};;
 
-  }
-  equal() {
+				function _prep_h17(){function a(b,c,d,e,g,k){var l=[0,0,0,0,0],n=d.slice(0,4).concat(l),p=[],s=Math.PI/180*6,A=void 0,I=void 0,A=d.slice(0,2),D=m(e),F=m(g),I=q.normalize(h(D).fg(h(A))),C=q.normalize(h(F).fg(h(A)));q.OK(I,k)?(A=q.oD(I),I=q.oD(C)):(A=q.oD(C),I=q.oD(I),k=[F,D],D=k[0],F=k[1],g=[g,e],e=g[0],g=g[1]);D=Math.ceil(Math.abs(I-A)/s);30<=D&&(D=60-D);for(k=0;k<D;k++)0===k?(n.push.apply(n,e.slice(0,4)),n.push.apply(n,l)):(F=(k*s+A)%(2*Math.PI),n.push.apply(n,d.slice(0,2).concat([0,0])),n.push(1* Math.cos(F),1*Math.sin(F),0,0,0)),0<k&&p.push(0,k,k+1);n.push.apply(n,g.slice(0,4));n.push.apply(n,l);p.push(0,D,D+1);var H=b.length/9;b.push.apply(b,n);c.push.apply(c,p.map(function(a){return a+H}));return n.length/9}function c(c,d,e,g,k,l){function n(a,b,c,d,e){var g=void 0;a.NC(b)||q.AW(a,b)?g=b:c&&d&&e?g=a:c&&!d&&e?g=b:c||d||e?c||!d||e?(g=q.normalize(a.mi(b)),I=q.cos(g,a),g=g.oJ(I)):g=a:g=b;return g}function p(a,b,c){if(void 0===c||!0===c)d.push(a[0],a[1]),d.push(-b.y,b.x,0,0),d.push(A,0,0),l.push(a[2]); if(void 0===c||!1===c)d.push(a[0],a[1]),d.push(b.y,-b.x,0,0),d.push(A,0,0),l.push(a[2])}var s=c.length,E=0,A=0,I=void 0,D=void 0;k&&(g="bevel");c.forEach(function(c,r,H){var K=H[r-1];H=H[r+1];var L=void 0;K&&(A+=q.Fd(c,K));if(0===r||r===s-1)0===r?(void 0===H&&(H=c),L=q.normalize(h(H[0]-c[0],H[1]-c[1])),e.push(0,1,2)):(L=q.normalize(h(c[0]-K[0],c[1]-K[1])),r=d.length/9+2,4===r?e.push(3,2,1):e.push(r-3-E,r-1,r-2)),p(c,L);else{var J=q.normalize(h(c[0]-K[0],c[1]-K[1])),N=q.normalize(h(H[0]-c[0],H[1]- c[1])),L=q.normalize(J.multiply(-1).mi(N));D=q.OK(L,J);I=q.cos(L,J);p(c,n(J,N,D,!0,!0),!0);p(c,n(J,N,D,!0,!1),!1);p(c,n(J,N,D,!1,!0),!0);p(c,n(J,N,D,!1,!1),!1);r=d.length/9;K=r-4;H=K+2;var M=9*K,T=M+9,W=T+9,Z=W+9;D?(W=m(d.slice(T,W)),M=m(d.slice(M,T)),M=q.normalize(h(W).fg(h(M))),M=Math.abs(q.cos(J,M)/q.sin(J,M)*2),d[T+7]=-M,d[Z+7]=M):(Z=m(d.slice(M,T)),T=m(d.slice(T,W)),T=q.normalize(h(Z).fg(h(T))),T=Math.abs(q.cos(T,J)/q.sin(T,J)*2),d[M+7]=-T,d[W+7]=T);q.AW(J,N)?e.push(K,K+1,K-2-E):e.push(K,K-1- E,K+1);"miter"==g&&(D?p(c,n(J,N,0,!0,!0),!0):p(c,n(J,N,0,!0,!0),!1),E=1);if("round"===g){M=N=J=void 0;D?(J=d.slice(9*(K+1),9*(K+2)),N=d.slice(9*K,9*(K+1)),M=d.slice(9*H,9*(H+1))):(J=d.slice(9*K,9*(K+1)),N=d.slice(9*(K+1),9*(K+2)),M=d.slice(9*(H+1),9*(H+2)));L=a(d,e,J,N,M,L.multiply(-1));if(l)for(;0<L--;)l.push(c[2]);E=d.length/9-r}e.push(H,H+1,H+2+E);k||"bevel"!=g&&"miter"!=g||(D?e.push(H,K,K+1):e.push(H,H-1,H+1),"miter"==g&&(D?e.push(H+2,H-2,H):e.push(H+2,H+1,H-1)))}})}function d(a,b,c,d){function e(a, b){var c=void 0;if(a.NC(b))c=b;else{var c=q.normalize(a.mi(b)),d=q.cos(c,a);d>Math.sqrt(3)/2&&(d=Math.sqrt(3)/2);c=c.oJ(d)}return c}function g(a,c,e){if(void 0===e||!0===e)b.push(a[0],a[1]),b.push(-c.y,c.x,0,0),b.push(m,0,0),d.push(a[2]);if(void 0===e||!1===e)b.push(a[0],a[1]),b.push(c.y,-c.x,0,0),b.push(m,0,0),d.push(a[2])}for(var k=a[0],l=a[a.length-1],m=0,n=void 0;k[0]===l[0]&&k[1]===l[1]&&k!==l;)a.pop(),l=a[a.length-1];a.push(k);a.push(a[1]);a.unshift(l);var p=a.length;a.forEach(function(a,d, k){var l=k[d-1];k=k[d+1];var r=void 0;l&&(m+=q.Fd(a,l));if(0===d||d===p-1)0===d?(r=q.normalize(h(k[0]-a[0],k[1]-a[1])),c.push(0,1,2)):(r=q.normalize(h(a[0]-l[0],a[1]-l[1])),d=b.length/9+2,c.push(d-3,d-1,d-2)),g(a,r);else{d=q.normalize(h(a[0]-l[0],a[1]-l[1]));k=q.normalize(h(k[0]-a[0],k[1]-a[1]));l=q.normalize(d.multiply(-1).mi(k));n=q.OK(l,d);g(a,e(d,k),!0);g(a,e(d,k),!1);g(a,e(d,k),!0);g(a,e(d,k),!1);a=b.length/9-4;k=a+2;var r=9*a,s=r+9,x=s+9,B=x+9;d=Math.abs(q.cos(d,l)/q.sin(d,l));n?(b[r+7]=d,b[s+ 7]=-d,b[x+7]=-d,b[B+7]=d):(b[r+7]=-d,b[s+7]=d,b[x+7]=d,b[B+7]=-d);c.push(a,a-1,a+1);c.push(k,k+1,k+2)}})}function e(c,d,e){function g(a,b){if(p)for(;0<a--;)p.push(b)}function m(a,b){E.push.apply(E,a.slice(0,k));E.push(b.x,b.y);E.push.apply(E,a.slice(l));E.push.apply(E,a)}var n=3<arguments.length&&void 0!==arguments[3]?arguments[3]:"butt",p=arguments[4],s=c.length-1,G=d.length,E=[],A=[],I=[d.slice(0,9),d.slice(9,18)],D=[d.slice(G-9,G),d.slice(G-18,G-9)];"square"===n?(n=q.normalize(h(c[0]).fg(h(c[1]))), m(I[0],n),m(I[1],n),n=q.normalize(h(c[s]).fg(h(c[s-1]))),m(D[0],n),m(D[1],n),A.push(0,2,3,3,1,0),A.push(6,7,4,4,7,5),p&&(p.push(c[0][2]),p.push(c[s][2]))):"round"===n&&(n=I[0].slice(0,2).concat(0,0,0,0).concat(I[0].slice(l)),I=a(d,e,n,I[0],I[1],q.normalize(h(c[0]).fg(h(c[1])))),g(I,c[0][2]),n=D[0].slice(0,2).concat(0,0,0,0).concat(D[0].slice(l)),I=a(d,e,n,D[0],D[1],q.normalize(h(c[s]).fg(h(c[s-1])))),g(I,c[s][2]));d.push.apply(d,E);e.push.apply(e,A.map(function(a){return a+G/9}))}function g(a,b){var c= [];a.forEach(function(a){var d=a[0],e=a[1];a=a[2];b&&(d-=p[0],e-=p[1]);var g=c.length-1;if(-1===g)c.push([d,e,a]);else if(d!==c[g][0]||e!==c[g][1]||a!==c[g][2])if(1<=g){var k=q.normalize(h(d-c[g][0],e-c[g][1])),l=q.normalize(h(c[g][0]-c[g-1][0],c[g][1]-c[g-1][1]));k.NC(l)&&a===c[g][2]?c[g]=[d,e,a]:c.push([d,e,a])}else c.push([d,e,a])});return c}function h(a,b){"object"===typeof a&&a.length&&(b=a[1],a=a[0]);return w.a.create(s,{x:{value:a},y:{value:b}})}var k,l;function m(a){return[a[0]+n*a[2],a[1]+ n*a[3]]}var n=1;k=4;l=6;var p=[215440491,106744817],q={normalize:function(a){var b=this.length(a);return a.oJ(b)},Qj:function(a,b){return a.multiply(b)},gJ:function(a,b){return a.x*b.y-a.y*b.x},length:function(a){return Math.sqrt(Math.pow(a.x,2)+Math.pow(a.y,2))},sin:function(a,b){return this.gJ(a,b)/(this.length(a)*this.length(b))},cos:function(a,b){return this.Qj(a,b)/(this.length(a)*this.length(b))},OK:function(a,b){return 0<this.gJ(a,b)},Fd:function(a,b){return Math.sqrt(Math.pow(b[0]-a[0],2)+ Math.pow(b[1]-a[1],2))},AW:function(a,b){return a.multiply(-1).NC(b)},oD:function(a){a=Math.atan2(a.y,a.x);0>=a&&(a+=2*Math.PI);return a}},s={mi:function(a){return h(this.x+a.x,this.y+a.y)},fg:function(a){return h(this.x-a.x,this.y-a.y)},multiply:function(a){return"number"===typeof a?h(this.x*a,this.y*a):this.x*a.x+this.y*a.y},oJ:function(a){return h(this.x/a,this.y/a)},NC:function(a){var b=a.y;return this.x===a.x&&this.y===b}};return{parse:function(a,b){var h=a.lineJoin,h=void 0===h?"bevel":h,k= a.lineCap,k=void 0===k?"butt":k,l=a.Zda,l=void 0===l?!1:l,m=a.tn,n=void 0===m?!1:m,p=a.LX,m=a.Iia,q=void 0===m?!0:m,m=a.Sda,s=[],A=[],I=g(a.Nr,void 0===p?!0:p),p=[];l?(d(I,s,A,p),h=s.length,[0,1,2,h/9-1,h/9-2].forEach(function(a){s[9*a+8]=-1})):(c(I,s,A,h,n,p),e(I,s,A,k,p));q&&(s=new Float32Array(s),A=65535<A.length?new Uint32Array(A):new Uint16Array(A));h=[s,A];m&&h.push(p);if(b)b(null,{data:h});else return h}}}
+				if (self._wkHandlers['w6__def_w6'] && true) {
+					throw new Error('w6__def_w6 already exists!')
+				} else {
+					if (false && self._wkHandlers['w6__def_w6']) {
+						var handlerFunObj = _prep_h17.call(null, self) || {}
 
-  }
-  distanceTo() {
+						if (typeof Object.assign === 'function') {
+							Object.assign(self._wkHandlers['w6__def_w6'], handlerFunObj)
+						} else {
+							for (var key in handlerFunObj) {
+								if (handlerFunObj.hasOwnProperty(key)) {
+									self._wkHandlers['w6__def_w6'][key] = handlerFunObj[key]
+								}
+							}
+						}
+					} else {
+						self._wkHandlers['w6__def_w6'] = _prep_h17.call(null, self) || {}	
+					}
+				}
 
-  }
+				_prep_h17 = null;
+			;
 
-}
+				function _prep_h18(a){return{injectCode:function(b,c){var d=null,e=null;try{d=(new Function("self",b))(a)}catch(g){console.error("error",e),e=g.toString()}c(e,d)}}}
+				if (self._wkHandlers['w6__g_'] && true) {
+					throw new Error('w6__g_ already exists!')
+				} else {
+					if (false && self._wkHandlers['w6__g_']) {
+						var handlerFunObj = _prep_h18.call(null, self) || {}
+
+						if (typeof Object.assign === 'function') {
+							Object.assign(self._wkHandlers['w6__g_'], handlerFunObj)
+						} else {
+							for (var key in handlerFunObj) {
+								if (handlerFunObj.hasOwnProperty(key)) {
+									self._wkHandlers['w6__g_'][key] = handlerFunObj[key]
+								}
+							}
+						}
+					} else {
+						self._wkHandlers['w6__g_'] = _prep_h18.call(null, self) || {}	
+					}
+				}
+
+				_prep_h18 = null;
+			;
+
+				function _prep_h19(){return{checkup:function(){var a=Array.prototype.slice.call(arguments,0);a.pop()(null,a)}}}
+				if (self._wkHandlers['w6__cln_w6'] && true) {
+					throw new Error('w6__cln_w6 already exists!')
+				} else {
+					if (false && self._wkHandlers['w6__cln_w6']) {
+						var handlerFunObj = _prep_h19.call(null, self) || {}
+
+						if (typeof Object.assign === 'function') {
+							Object.assign(self._wkHandlers['w6__cln_w6'], handlerFunObj)
+						} else {
+							for (var key in handlerFunObj) {
+								if (handlerFunObj.hasOwnProperty(key)) {
+									self._wkHandlers['w6__cln_w6'][key] = handlerFunObj[key]
+								}
+							}
+						}
+					} else {
+						self._wkHandlers['w6__cln_w6'] = _prep_h19.call(null, self) || {}	
+					}
+				}
+
+				_prep_h19 = null;
+			(function d(a){function b(c,d){function e(a,b,c){a={jv:Date.now(),Yu:h,error:a,result:b,Jr:!1,jn:!1};if(c)for(var g in c)c.hasOwnProperty(g)&&(a[g]=c[g]);d(a)}var g=c.AK,h=c.Yu,l=c.aJ,m=c.Gx,n=c.A$||[],p=a._wkHandlers[g];p?p[l]?m?
+p[l].apply(p,n.concat(e)):e(null,p[l].apply(p,n)):e("Unknown cmd: "+l):e("Can not find handler for: "+g)}var c=[],d=null,e=null;for(d in this._wkHandlers)-1!==d.indexOf("_def_")&&(e=this._wkHandlers.lna=d);"function"===typeof this._wkHandlers[e].B&&this._wkHandlers[e].B.call(this._wkHandlers[e]);a.vx=function(a){c.push.apply(c,a)};a.addEventListener("message",function(d){function e(b){if(t){t.push(b);var d=!!b.Jr;d||n++;b=n>=h||b.jn;if(d||b){d=1<t.length?{nha:t}:t[0];d.jv=Date.now();d.moa=p;if(c.length){try{a.postMessage(d,
+c)}catch(g){a.postMessage(d),console.error(g)}c.length=0}else a.postMessage(d);t.length=0;b&&(e=t=null)}}else console.error("Seemed callback already sent!!",b,b.result.Ac)}var g=d.data;d=g.kha||[g];for(var h=d.length,n=0,p=Date.now()-g.jv,t=[],g=0;g<h;g++)b(d[g],e)},!1)})(self)
\ No newline at end of file
diff --git a/src/geo/project.js b/src/geo/project.js
index c4f57b99fe..586a19cf0b 100644
--- a/src/geo/project.js
+++ b/src/geo/project.js
@@ -13,5 +13,20 @@ export function aProjectFlat(lnglat) {
   d = 0.5;
   x = scale * (a * x + b) - 215440491;
   y = scale * (c * y + d) - 106744817;
-  return { x, y };
+  return { x: parseInt(x), y: parseInt(y) };
+}
+export function unProjectFlat(px) {
+  const a = 0.5 / Math.PI,
+    b = 0.5,
+    c = -0.5 / Math.PI;
+  let d = 0.5;
+  const scale = 256 << 20;
+  let [ x, y ] = px;
+  x = ((x + 215440491) / scale - b) / a;
+  y = ((y + 106744817) / scale - d) / c;
+  y = (Math.atan(Math.pow(Math.E, y)) - (Math.PI / 4)) * 2;
+  d = Math.PI / 180;
+  const lat = y / d;
+  const lng = x / d;
+  return [ lng, lat ];
 }
diff --git a/src/source/index.js b/src/source/index.js
index 307819cc1f..ff88ba484e 100644
--- a/src/source/index.js
+++ b/src/source/index.js
@@ -7,7 +7,7 @@ import json from './parser/json';
 import raster from './parser/raster';
 
 import { registerTransform, registerParser } from './factory';
-import { aggregatorToGrid } from './transform/grid-aggregator';
+import { aggregatorToGrid } from './transform/grid';
 import { map } from './transform/map';
 
 registerParser('geojson', geojson);
diff --git a/src/source/transform/grid-aggregator.js b/src/source/transform/grid.js
similarity index 100%
rename from src/source/transform/grid-aggregator.js
rename to src/source/transform/grid.js
diff --git a/src/source/transform/hexagon.js b/src/source/transform/hexagon.js
new file mode 100644
index 0000000000..df796c7450
--- /dev/null
+++ b/src/source/transform/hexagon.js
@@ -0,0 +1,41 @@
+import { hexbin } from 'd3-hexbin';
+import { aProjectFlat, unProjectFlat } from '../../geo/project';
+import * as statistics from './statistics';
+const R_EARTH = 6378000;
+export function pointToHexbin(data, option) {
+  const dataArray = data.dataArray;
+  const { size = 10 } = option;
+  const pixlSize = size / (2 * Math.PI * R_EARTH) * (256 << 20) / 2;
+  const screenPoints = dataArray.map(point => {
+    const { x, y } = aProjectFlat(point.coordinates);
+    return {
+      ...point,
+      coordinates: [ x, y ]
+    };
+  });
+
+  const newHexbin = hexbin()
+    .radius(pixlSize)
+    .x(d => d.coordinates[0])
+    .y(d => d.coordinates[1]);
+  const hexbinBins = newHexbin(screenPoints);
+  const result = {
+    size: pixlSize
+  };
+  result.dataArray = hexbinBins.map((hex, index) => {
+    if (option.field && option.method) {
+      const columns = getColumn(hex, option.field);
+      hex[option.method] = statistics[option.method](columns);
+    }
+    return {
+      coordinates: unProjectFlat([ hex.x, hex.y ]),
+      id: index + 1
+    };
+  });
+  return result;
+}
+function getColumn(data, columnName) {
+  return data.map(item => {
+    return item[columnName];
+  });
+}
diff --git a/test/asset/data/point.js b/test/asset/data/point.js
new file mode 100644
index 0000000000..6fc7183712
--- /dev/null
+++ b/test/asset/data/point.js
@@ -0,0 +1,1490 @@
+export const pointData = [
+  { grid_y: 121055, count: 7600, grid_x: 480481 },
+  { grid_y: 121055, count: 3800, grid_x: 480487 },
+  { grid_y: 121055, count: 3800, grid_x: 480493 },
+  { grid_y: 121055, count: 7600, grid_x: 480501 },
+  { grid_y: 121055, count: 3800, grid_x: 480502 },
+  { grid_y: 121055, count: 15200, grid_x: 480503 },
+  { grid_y: 121055, count: 3800, grid_x: 480504 },
+  { grid_y: 121055, count: 7600, grid_x: 480505 },
+  { grid_y: 121055, count: 3800, grid_x: 480506 },
+  { grid_y: 121055, count: 3800, grid_x: 480507 },
+  { grid_y: 121055, count: 3800, grid_x: 480512 },
+  { grid_y: 121055, count: 3800, grid_x: 480530 },
+  { grid_y: 121056, count: 3800, grid_x: 480494 },
+  { grid_y: 121056, count: 3800, grid_x: 480496 },
+  { grid_y: 121056, count: 7600, grid_x: 480501 },
+  { grid_y: 121056, count: 11400, grid_x: 480502 },
+  { grid_y: 121056, count: 7600, grid_x: 480503 },
+  { grid_y: 121056, count: 7600, grid_x: 480504 },
+  { grid_y: 121056, count: 3800, grid_x: 480506 },
+  { grid_y: 121056, count: 3800, grid_x: 480508 },
+  { grid_y: 121056, count: 3800, grid_x: 480509 },
+  { grid_y: 121056, count: 3800, grid_x: 480520 },
+  { grid_y: 121056, count: 3800, grid_x: 480524 },
+  { grid_y: 121057, count: 11400, grid_x: 480484 },
+  { grid_y: 121057, count: 3800, grid_x: 480489 },
+  { grid_y: 121057, count: 3800, grid_x: 480500 },
+  { grid_y: 121057, count: 3800, grid_x: 480502 },
+  { grid_y: 121057, count: 3800, grid_x: 480509 },
+  { grid_y: 121057, count: 3800, grid_x: 480515 },
+  { grid_y: 121057, count: 3800, grid_x: 480522 },
+  { grid_y: 121057, count: 3800, grid_x: 480523 },
+  { grid_y: 121057, count: 15200, grid_x: 480524 },
+  { grid_y: 121057, count: 3800, grid_x: 480525 },
+  { grid_y: 121057, count: 3800, grid_x: 480527 },
+  { grid_y: 121058, count: 3800, grid_x: 480478 },
+  { grid_y: 121058, count: 3800, grid_x: 480482 },
+  { grid_y: 121058, count: 3800, grid_x: 480485 },
+  { grid_y: 121058, count: 3800, grid_x: 480486 },
+  { grid_y: 121058, count: 3800, grid_x: 480487 },
+  { grid_y: 121058, count: 3800, grid_x: 480490 },
+  { grid_y: 121058, count: 3800, grid_x: 480497 },
+  { grid_y: 121058, count: 3800, grid_x: 480499 },
+  { grid_y: 121058, count: 7600, grid_x: 480501 },
+  { grid_y: 121058, count: 3800, grid_x: 480502 },
+  { grid_y: 121058, count: 7600, grid_x: 480503 },
+  { grid_y: 121058, count: 3800, grid_x: 480521 },
+  { grid_y: 121058, count: 3800, grid_x: 480522 },
+  { grid_y: 121058, count: 3800, grid_x: 480523 },
+  { grid_y: 121058, count: 3800, grid_x: 480524 },
+  { grid_y: 121058, count: 3800, grid_x: 480528 },
+  { grid_y: 121059, count: 3800, grid_x: 480495 },
+  { grid_y: 121059, count: 3800, grid_x: 480499 },
+  { grid_y: 121059, count: 3800, grid_x: 480500 },
+  { grid_y: 121059, count: 7600, grid_x: 480502 },
+  { grid_y: 121059, count: 7600, grid_x: 480503 },
+  { grid_y: 121059, count: 3800, grid_x: 480504 },
+  { grid_y: 121059, count: 34200, grid_x: 480507 },
+  { grid_y: 121059, count: 3800, grid_x: 480511 },
+  { grid_y: 121059, count: 3800, grid_x: 480516 },
+  { grid_y: 121060, count: 7600, grid_x: 480491 },
+  { grid_y: 121060, count: 7600, grid_x: 480496 },
+  { grid_y: 121060, count: 3800, grid_x: 480497 },
+  { grid_y: 121060, count: 3800, grid_x: 480498 },
+  { grid_y: 121060, count: 7600, grid_x: 480499 },
+  { grid_y: 121060, count: 7600, grid_x: 480500 },
+  { grid_y: 121060, count: 7600, grid_x: 480502 },
+  { grid_y: 121060, count: 3800, grid_x: 480505 },
+  { grid_y: 121060, count: 3800, grid_x: 480506 },
+  { grid_y: 121060, count: 3800, grid_x: 480511 },
+  { grid_y: 121060, count: 3800, grid_x: 480513 },
+  { grid_y: 121060, count: 3800, grid_x: 480514 },
+  { grid_y: 121061, count: 3800, grid_x: 480491 },
+  { grid_y: 121061, count: 7600, grid_x: 480497 },
+  { grid_y: 121061, count: 7600, grid_x: 480499 },
+  { grid_y: 121061, count: 11400, grid_x: 480500 },
+  { grid_y: 121061, count: 3800, grid_x: 480501 },
+  { grid_y: 121061, count: 7600, grid_x: 480502 },
+  { grid_y: 121061, count: 15200, grid_x: 480503 },
+  { grid_y: 121061, count: 11400, grid_x: 480504 },
+  { grid_y: 121061, count: 7600, grid_x: 480505 },
+  { grid_y: 121061, count: 3800, grid_x: 480506 },
+  { grid_y: 121061, count: 3800, grid_x: 480507 },
+  { grid_y: 121061, count: 3800, grid_x: 480511 },
+  { grid_y: 121061, count: 3800, grid_x: 480526 },
+  { grid_y: 121062, count: 15200, grid_x: 480489 },
+  { grid_y: 121062, count: 7600, grid_x: 480491 },
+  { grid_y: 121062, count: 7600, grid_x: 480492 },
+  { grid_y: 121062, count: 7600, grid_x: 480499 },
+  { grid_y: 121062, count: 11400, grid_x: 480500 },
+  { grid_y: 121062, count: 3800, grid_x: 480502 },
+  { grid_y: 121062, count: 3800, grid_x: 480503 },
+  { grid_y: 121062, count: 7600, grid_x: 480504 },
+  { grid_y: 121062, count: 3800, grid_x: 480505 },
+  { grid_y: 121062, count: 3800, grid_x: 480517 },
+  { grid_y: 121062, count: 7600, grid_x: 480522 },
+  { grid_y: 121062, count: 3800, grid_x: 480527 },
+  { grid_y: 121062, count: 3800, grid_x: 480530 },
+  { grid_y: 121063, count: 3800, grid_x: 480488 },
+  { grid_y: 121063, count: 7600, grid_x: 480489 },
+  { grid_y: 121063, count: 15200, grid_x: 480492 },
+  { grid_y: 121063, count: 3800, grid_x: 480493 },
+  { grid_y: 121063, count: 3800, grid_x: 480497 },
+  { grid_y: 121063, count: 7600, grid_x: 480499 },
+  { grid_y: 121063, count: 7600, grid_x: 480500 },
+  { grid_y: 121063, count: 15200, grid_x: 480501 },
+  { grid_y: 121063, count: 11400, grid_x: 480502 },
+  { grid_y: 121063, count: 3800, grid_x: 480516 },
+  { grid_y: 121063, count: 3800, grid_x: 480518 },
+  { grid_y: 121063, count: 3800, grid_x: 480522 },
+  { grid_y: 121063, count: 11400, grid_x: 480524 },
+  { grid_y: 121063, count: 3800, grid_x: 480525 },
+  { grid_y: 121064, count: 7600, grid_x: 480488 },
+  { grid_y: 121064, count: 3800, grid_x: 480489 },
+  { grid_y: 121064, count: 7600, grid_x: 480490 },
+  { grid_y: 121064, count: 3800, grid_x: 480491 },
+  { grid_y: 121064, count: 3800, grid_x: 480493 },
+  { grid_y: 121064, count: 3800, grid_x: 480495 },
+  { grid_y: 121064, count: 3800, grid_x: 480496 },
+  { grid_y: 121064, count: 15200, grid_x: 480499 },
+  { grid_y: 121064, count: 3800, grid_x: 480500 },
+  { grid_y: 121064, count: 15200, grid_x: 480501 },
+  { grid_y: 121064, count: 7600, grid_x: 480502 },
+  { grid_y: 121064, count: 3800, grid_x: 480523 },
+  { grid_y: 121065, count: 3800, grid_x: 480487 },
+  { grid_y: 121065, count: 3800, grid_x: 480488 },
+  { grid_y: 121065, count: 3800, grid_x: 480489 },
+  { grid_y: 121065, count: 11400, grid_x: 480490 },
+  { grid_y: 121065, count: 7600, grid_x: 480491 },
+  { grid_y: 121065, count: 3800, grid_x: 480492 },
+  { grid_y: 121065, count: 7600, grid_x: 480499 },
+  { grid_y: 121065, count: 3800, grid_x: 480500 },
+  { grid_y: 121065, count: 7600, grid_x: 480501 },
+  { grid_y: 121065, count: 3800, grid_x: 480509 },
+  { grid_y: 121065, count: 3800, grid_x: 480512 },
+  { grid_y: 121065, count: 3800, grid_x: 480516 },
+  { grid_y: 121065, count: 3800, grid_x: 480527 },
+  { grid_y: 121066, count: 3800, grid_x: 480488 },
+  { grid_y: 121066, count: 7600, grid_x: 480489 },
+  { grid_y: 121066, count: 3800, grid_x: 480490 },
+  { grid_y: 121066, count: 11400, grid_x: 480491 },
+  { grid_y: 121066, count: 7600, grid_x: 480492 },
+  { grid_y: 121066, count: 3800, grid_x: 480496 },
+  { grid_y: 121066, count: 7600, grid_x: 480498 },
+  { grid_y: 121066, count: 3800, grid_x: 480500 },
+  { grid_y: 121066, count: 7600, grid_x: 480501 },
+  { grid_y: 121066, count: 3800, grid_x: 480505 },
+  { grid_y: 121066, count: 3800, grid_x: 480509 },
+  { grid_y: 121066, count: 3800, grid_x: 480511 },
+  { grid_y: 121066, count: 3800, grid_x: 480512 },
+  { grid_y: 121066, count: 3800, grid_x: 480514 },
+  { grid_y: 121067, count: 15200, grid_x: 480491 },
+  { grid_y: 121067, count: 3800, grid_x: 480493 },
+  { grid_y: 121067, count: 3800, grid_x: 480494 },
+  { grid_y: 121067, count: 7600, grid_x: 480495 },
+  { grid_y: 121067, count: 7600, grid_x: 480496 },
+  { grid_y: 121067, count: 7600, grid_x: 480497 },
+  { grid_y: 121067, count: 7600, grid_x: 480498 },
+  { grid_y: 121067, count: 3800, grid_x: 480499 },
+  { grid_y: 121067, count: 11400, grid_x: 480500 },
+  { grid_y: 121067, count: 3800, grid_x: 480501 },
+  { grid_y: 121067, count: 3800, grid_x: 480503 },
+  { grid_y: 121067, count: 3800, grid_x: 480509 },
+  { grid_y: 121067, count: 3800, grid_x: 480513 },
+  { grid_y: 121067, count: 3800, grid_x: 480515 },
+  { grid_y: 121068, count: 7600, grid_x: 480488 },
+  { grid_y: 121068, count: 7600, grid_x: 480489 },
+  { grid_y: 121068, count: 11400, grid_x: 480490 },
+  { grid_y: 121068, count: 3800, grid_x: 480491 },
+  { grid_y: 121068, count: 7600, grid_x: 480493 },
+  { grid_y: 121068, count: 3800, grid_x: 480494 },
+  { grid_y: 121068, count: 3800, grid_x: 480495 },
+  { grid_y: 121068, count: 41800, grid_x: 480499 },
+  { grid_y: 121068, count: 19000, grid_x: 480500 },
+  { grid_y: 121068, count: 3800, grid_x: 480501 },
+  { grid_y: 121068, count: 3800, grid_x: 480502 },
+  { grid_y: 121068, count: 3800, grid_x: 480504 },
+  { grid_y: 121068, count: 3800, grid_x: 480509 },
+  { grid_y: 121068, count: 3800, grid_x: 480515 },
+  { grid_y: 121069, count: 3800, grid_x: 480489 },
+  { grid_y: 121069, count: 3800, grid_x: 480491 },
+  { grid_y: 121069, count: 7600, grid_x: 480492 },
+  { grid_y: 121069, count: 7600, grid_x: 480493 },
+  { grid_y: 121069, count: 3800, grid_x: 480494 },
+  { grid_y: 121069, count: 3800, grid_x: 480495 },
+  { grid_y: 121069, count: 7600, grid_x: 480499 },
+  { grid_y: 121069, count: 3800, grid_x: 480502 },
+  { grid_y: 121069, count: 3800, grid_x: 480509 },
+  { grid_y: 121069, count: 3800, grid_x: 480513 },
+  { grid_y: 121069, count: 3800, grid_x: 480515 },
+  { grid_y: 121069, count: 3800, grid_x: 480517 },
+  { grid_y: 121069, count: 7600, grid_x: 480524 },
+  { grid_y: 121070, count: 3800, grid_x: 480490 },
+  { grid_y: 121070, count: 11400, grid_x: 480491 },
+  { grid_y: 121070, count: 3800, grid_x: 480492 },
+  { grid_y: 121070, count: 3800, grid_x: 480497 },
+  { grid_y: 121070, count: 3800, grid_x: 480501 },
+  { grid_y: 121070, count: 7600, grid_x: 480510 },
+  { grid_y: 121070, count: 19000, grid_x: 480513 },
+  { grid_y: 121070, count: 3800, grid_x: 480514 },
+  { grid_y: 121070, count: 3800, grid_x: 480515 },
+  { grid_y: 121070, count: 11400, grid_x: 480516 },
+  { grid_y: 121070, count: 7600, grid_x: 480517 },
+  { grid_y: 121070, count: 3800, grid_x: 480518 },
+  { grid_y: 121070, count: 3800, grid_x: 480519 },
+  { grid_y: 121070, count: 7600, grid_x: 480533 },
+  { grid_y: 121071, count: 11400, grid_x: 480491 },
+  { grid_y: 121071, count: 7600, grid_x: 480492 },
+  { grid_y: 121071, count: 15200, grid_x: 480493 },
+  { grid_y: 121071, count: 7600, grid_x: 480494 },
+  { grid_y: 121071, count: 3800, grid_x: 480495 },
+  { grid_y: 121071, count: 3800, grid_x: 480497 },
+  { grid_y: 121071, count: 3800, grid_x: 480502 },
+  { grid_y: 121071, count: 3800, grid_x: 480503 },
+  { grid_y: 121071, count: 3800, grid_x: 480510 },
+  { grid_y: 121071, count: 11400, grid_x: 480513 },
+  { grid_y: 121071, count: 7600, grid_x: 480515 },
+  { grid_y: 121071, count: 7600, grid_x: 480516 },
+  { grid_y: 121071, count: 7600, grid_x: 480517 },
+  { grid_y: 121071, count: 3800, grid_x: 480519 },
+  { grid_y: 121071, count: 3800, grid_x: 480520 },
+  { grid_y: 121071, count: 3800, grid_x: 480523 },
+  { grid_y: 121072, count: 15200, grid_x: 480492 },
+  { grid_y: 121072, count: 11400, grid_x: 480493 },
+  { grid_y: 121072, count: 3800, grid_x: 480494 },
+  { grid_y: 121072, count: 3800, grid_x: 480496 },
+  { grid_y: 121072, count: 3800, grid_x: 480500 },
+  { grid_y: 121072, count: 7600, grid_x: 480501 },
+  { grid_y: 121072, count: 3800, grid_x: 480508 },
+  { grid_y: 121072, count: 7600, grid_x: 480514 },
+  { grid_y: 121072, count: 3800, grid_x: 480515 },
+  { grid_y: 121072, count: 3800, grid_x: 480517 },
+  { grid_y: 121072, count: 3800, grid_x: 480518 },
+  { grid_y: 121073, count: 7600, grid_x: 480491 },
+  { grid_y: 121073, count: 7600, grid_x: 480492 },
+  { grid_y: 121073, count: 3800, grid_x: 480494 },
+  { grid_y: 121073, count: 3800, grid_x: 480497 },
+  { grid_y: 121073, count: 11400, grid_x: 480501 },
+  { grid_y: 121073, count: 7600, grid_x: 480502 },
+  { grid_y: 121073, count: 3800, grid_x: 480503 },
+  { grid_y: 121073, count: 3800, grid_x: 480504 },
+  { grid_y: 121073, count: 3800, grid_x: 480511 },
+  { grid_y: 121073, count: 3800, grid_x: 480512 },
+  { grid_y: 121073, count: 3800, grid_x: 480516 },
+  { grid_y: 121073, count: 3800, grid_x: 480517 },
+  { grid_y: 121074, count: 3800, grid_x: 480459 },
+  { grid_y: 121074, count: 3800, grid_x: 480491 },
+  { grid_y: 121074, count: 3800, grid_x: 480492 },
+  { grid_y: 121074, count: 3800, grid_x: 480493 },
+  { grid_y: 121074, count: 3800, grid_x: 480494 },
+  { grid_y: 121074, count: 7600, grid_x: 480497 },
+  { grid_y: 121074, count: 3800, grid_x: 480498 },
+  { grid_y: 121074, count: 3800, grid_x: 480499 },
+  { grid_y: 121074, count: 7600, grid_x: 480501 },
+  { grid_y: 121074, count: 15200, grid_x: 480502 },
+  { grid_y: 121074, count: 3800, grid_x: 480503 },
+  { grid_y: 121074, count: 3800, grid_x: 480507 },
+  { grid_y: 121074, count: 7600, grid_x: 480517 },
+  { grid_y: 121074, count: 3800, grid_x: 480520 },
+  { grid_y: 121075, count: 3800, grid_x: 480493 },
+  { grid_y: 121075, count: 3800, grid_x: 480495 },
+  { grid_y: 121075, count: 3800, grid_x: 480496 },
+  { grid_y: 121075, count: 3800, grid_x: 480497 },
+  { grid_y: 121075, count: 7600, grid_x: 480498 },
+  { grid_y: 121075, count: 7600, grid_x: 480499 },
+  { grid_y: 121075, count: 7600, grid_x: 480500 },
+  { grid_y: 121075, count: 7600, grid_x: 480501 },
+  { grid_y: 121075, count: 7600, grid_x: 480502 },
+  { grid_y: 121075, count: 7600, grid_x: 480503 },
+  { grid_y: 121075, count: 3800, grid_x: 480504 },
+  { grid_y: 121075, count: 7600, grid_x: 480506 },
+  { grid_y: 121075, count: 3800, grid_x: 480511 },
+  { grid_y: 121075, count: 3800, grid_x: 480517 },
+  { grid_y: 121075, count: 3800, grid_x: 480518 },
+  { grid_y: 121075, count: 3800, grid_x: 480519 },
+  { grid_y: 121075, count: 7600, grid_x: 480520 },
+  { grid_y: 121076, count: 3800, grid_x: 480491 },
+  { grid_y: 121076, count: 7600, grid_x: 480498 },
+  { grid_y: 121076, count: 7600, grid_x: 480499 },
+  { grid_y: 121076, count: 3800, grid_x: 480501 },
+  { grid_y: 121076, count: 3800, grid_x: 480502 },
+  { grid_y: 121076, count: 15200, grid_x: 480503 },
+  { grid_y: 121076, count: 3800, grid_x: 480509 },
+  { grid_y: 121076, count: 3800, grid_x: 480515 },
+  { grid_y: 121076, count: 3800, grid_x: 480516 },
+  { grid_y: 121076, count: 3800, grid_x: 480521 },
+  { grid_y: 121076, count: 3800, grid_x: 480523 },
+  { grid_y: 121077, count: 3800, grid_x: 480475 },
+  { grid_y: 121077, count: 3800, grid_x: 480496 },
+  { grid_y: 121077, count: 7600, grid_x: 480498 },
+  { grid_y: 121077, count: 7600, grid_x: 480499 },
+  { grid_y: 121077, count: 7600, grid_x: 480500 },
+  { grid_y: 121077, count: 3800, grid_x: 480501 },
+  { grid_y: 121077, count: 3800, grid_x: 480503 },
+  { grid_y: 121077, count: 7600, grid_x: 480506 },
+  { grid_y: 121077, count: 3800, grid_x: 480509 },
+  { grid_y: 121077, count: 3800, grid_x: 480511 },
+  { grid_y: 121077, count: 3800, grid_x: 480517 },
+  { grid_y: 121077, count: 3800, grid_x: 480518 },
+  { grid_y: 121077, count: 3800, grid_x: 480531 },
+  { grid_y: 121078, count: 3800, grid_x: 480462 },
+  { grid_y: 121078, count: 3800, grid_x: 480474 },
+  { grid_y: 121078, count: 3800, grid_x: 480479 },
+  { grid_y: 121078, count: 3800, grid_x: 480485 },
+  { grid_y: 121078, count: 3800, grid_x: 480496 },
+  { grid_y: 121078, count: 7600, grid_x: 480497 },
+  { grid_y: 121078, count: 3800, grid_x: 480499 },
+  { grid_y: 121078, count: 7600, grid_x: 480501 },
+  { grid_y: 121078, count: 3800, grid_x: 480502 },
+  { grid_y: 121078, count: 3800, grid_x: 480507 },
+  { grid_y: 121078, count: 7600, grid_x: 480509 },
+  { grid_y: 121078, count: 15200, grid_x: 480510 },
+  { grid_y: 121078, count: 3800, grid_x: 480512 },
+  { grid_y: 121078, count: 3800, grid_x: 480529 },
+  { grid_y: 121078, count: 3800, grid_x: 480530 },
+  { grid_y: 121079, count: 3800, grid_x: 480462 },
+  { grid_y: 121079, count: 3800, grid_x: 480478 },
+  { grid_y: 121079, count: 3800, grid_x: 480497 },
+  { grid_y: 121079, count: 3800, grid_x: 480499 },
+  { grid_y: 121079, count: 3800, grid_x: 480504 },
+  { grid_y: 121079, count: 3800, grid_x: 480511 },
+  { grid_y: 121079, count: 3800, grid_x: 480532 },
+  { grid_y: 121080, count: 3800, grid_x: 480479 },
+  { grid_y: 121080, count: 3800, grid_x: 480491 },
+  { grid_y: 121080, count: 3800, grid_x: 480492 },
+  { grid_y: 121080, count: 3800, grid_x: 480493 },
+  { grid_y: 121080, count: 7600, grid_x: 480494 },
+  { grid_y: 121080, count: 3800, grid_x: 480495 },
+  { grid_y: 121080, count: 3800, grid_x: 480499 },
+  { grid_y: 121080, count: 3800, grid_x: 480500 },
+  { grid_y: 121080, count: 3800, grid_x: 480510 },
+  { grid_y: 121080, count: 3800, grid_x: 480520 },
+  { grid_y: 121081, count: 11400, grid_x: 480462 },
+  { grid_y: 121081, count: 3800, grid_x: 480492 },
+  { grid_y: 121081, count: 3800, grid_x: 480493 },
+  { grid_y: 121081, count: 3800, grid_x: 480494 },
+  { grid_y: 121081, count: 11400, grid_x: 480495 },
+  { grid_y: 121081, count: 3800, grid_x: 480518 },
+  { grid_y: 121081, count: 3800, grid_x: 480522 },
+  { grid_y: 121081, count: 3800, grid_x: 480523 },
+  { grid_y: 121082, count: 3800, grid_x: 480490 },
+  { grid_y: 121082, count: 3800, grid_x: 480494 },
+  { grid_y: 121082, count: 3800, grid_x: 480507 },
+  { grid_y: 121082, count: 3800, grid_x: 480510 },
+  { grid_y: 121082, count: 3800, grid_x: 480519 },
+  { grid_y: 121082, count: 3800, grid_x: 480520 },
+  { grid_y: 121082, count: 3800, grid_x: 480521 },
+  { grid_y: 121083, count: 3800, grid_x: 480511 },
+  { grid_y: 121083, count: 7600, grid_x: 480513 },
+  { grid_y: 121083, count: 3800, grid_x: 480514 },
+  { grid_y: 121083, count: 3800, grid_x: 480515 },
+  { grid_y: 121083, count: 3800, grid_x: 480516 },
+  { grid_y: 121083, count: 3800, grid_x: 480520 },
+  { grid_y: 121083, count: 3800, grid_x: 480522 },
+  { grid_y: 121083, count: 3800, grid_x: 480523 },
+  { grid_y: 121083, count: 7600, grid_x: 480524 },
+  { grid_y: 121083, count: 3800, grid_x: 480525 },
+  { grid_y: 121084, count: 3800, grid_x: 480485 },
+  { grid_y: 121084, count: 3800, grid_x: 480486 },
+  { grid_y: 121084, count: 3800, grid_x: 480487 },
+  { grid_y: 121084, count: 3800, grid_x: 480494 },
+  { grid_y: 121084, count: 3800, grid_x: 480495 },
+  { grid_y: 121084, count: 3800, grid_x: 480497 },
+  { grid_y: 121084, count: 3800, grid_x: 480500 },
+  { grid_y: 121084, count: 3800, grid_x: 480512 },
+  { grid_y: 121084, count: 22800, grid_x: 480513 },
+  { grid_y: 121084, count: 7600, grid_x: 480514 },
+  { grid_y: 121084, count: 3800, grid_x: 480515 },
+  { grid_y: 121084, count: 3800, grid_x: 480520 },
+  { grid_y: 121084, count: 3800, grid_x: 480521 },
+  { grid_y: 121084, count: 3800, grid_x: 480522 },
+  { grid_y: 121084, count: 3800, grid_x: 480523 },
+  { grid_y: 121084, count: 3800, grid_x: 480531 },
+  { grid_y: 121085, count: 3800, grid_x: 480499 },
+  { grid_y: 121085, count: 7600, grid_x: 480500 },
+  { grid_y: 121085, count: 3800, grid_x: 480501 },
+  { grid_y: 121085, count: 3800, grid_x: 480504 },
+  { grid_y: 121085, count: 3800, grid_x: 480506 },
+  { grid_y: 121085, count: 7600, grid_x: 480513 },
+  { grid_y: 121085, count: 11400, grid_x: 480514 },
+  { grid_y: 121085, count: 3800, grid_x: 480515 },
+  { grid_y: 121085, count: 3800, grid_x: 480517 },
+  { grid_y: 121085, count: 3800, grid_x: 480518 },
+  { grid_y: 121085, count: 3800, grid_x: 480520 },
+  { grid_y: 121085, count: 3800, grid_x: 480527 },
+  { grid_y: 121085, count: 3800, grid_x: 480532 },
+  { grid_y: 121086, count: 3800, grid_x: 480483 },
+  { grid_y: 121086, count: 3800, grid_x: 480490 },
+  { grid_y: 121086, count: 7600, grid_x: 480494 },
+  { grid_y: 121086, count: 3800, grid_x: 480497 },
+  { grid_y: 121086, count: 7600, grid_x: 480498 },
+  { grid_y: 121086, count: 3800, grid_x: 480499 },
+  { grid_y: 121086, count: 7600, grid_x: 480500 },
+  { grid_y: 121086, count: 3800, grid_x: 480507 },
+  { grid_y: 121086, count: 3800, grid_x: 480511 },
+  { grid_y: 121086, count: 7600, grid_x: 480512 },
+  { grid_y: 121086, count: 7600, grid_x: 480516 },
+  { grid_y: 121086, count: 3800, grid_x: 480517 },
+  { grid_y: 121086, count: 7600, grid_x: 480518 },
+  { grid_y: 121086, count: 3800, grid_x: 480520 },
+  { grid_y: 121086, count: 11400, grid_x: 480521 },
+  { grid_y: 121086, count: 3800, grid_x: 480523 },
+  { grid_y: 121086, count: 3800, grid_x: 480524 },
+  { grid_y: 121086, count: 3800, grid_x: 480527 },
+  { grid_y: 121086, count: 7600, grid_x: 480528 },
+  { grid_y: 121086, count: 3800, grid_x: 480529 },
+  { grid_y: 121086, count: 3800, grid_x: 480531 },
+  { grid_y: 121087, count: 7600, grid_x: 480460 },
+  { grid_y: 121087, count: 3800, grid_x: 480463 },
+  { grid_y: 121087, count: 3800, grid_x: 480472 },
+  { grid_y: 121087, count: 3800, grid_x: 480489 },
+  { grid_y: 121087, count: 3800, grid_x: 480494 },
+  { grid_y: 121087, count: 3800, grid_x: 480495 },
+  { grid_y: 121087, count: 7600, grid_x: 480501 },
+  { grid_y: 121087, count: 15200, grid_x: 480502 },
+  { grid_y: 121087, count: 11400, grid_x: 480503 },
+  { grid_y: 121087, count: 7600, grid_x: 480504 },
+  { grid_y: 121087, count: 7600, grid_x: 480508 },
+  { grid_y: 121087, count: 3800, grid_x: 480518 },
+  { grid_y: 121087, count: 3800, grid_x: 480519 },
+  { grid_y: 121087, count: 3800, grid_x: 480527 },
+  { grid_y: 121087, count: 3800, grid_x: 480528 },
+  { grid_y: 121087, count: 3800, grid_x: 480529 },
+  { grid_y: 121087, count: 7600, grid_x: 480533 },
+  { grid_y: 121088, count: 3800, grid_x: 480460 },
+  { grid_y: 121088, count: 3800, grid_x: 480478 },
+  { grid_y: 121088, count: 7600, grid_x: 480479 },
+  { grid_y: 121088, count: 3800, grid_x: 480483 },
+  { grid_y: 121088, count: 3800, grid_x: 480487 },
+  { grid_y: 121088, count: 7600, grid_x: 480491 },
+  { grid_y: 121088, count: 3800, grid_x: 480493 },
+  { grid_y: 121088, count: 3800, grid_x: 480494 },
+  { grid_y: 121088, count: 7600, grid_x: 480496 },
+  { grid_y: 121088, count: 3800, grid_x: 480497 },
+  { grid_y: 121088, count: 3800, grid_x: 480498 },
+  { grid_y: 121088, count: 3800, grid_x: 480502 },
+  { grid_y: 121088, count: 7600, grid_x: 480503 },
+  { grid_y: 121088, count: 3800, grid_x: 480504 },
+  { grid_y: 121088, count: 3800, grid_x: 480505 },
+  { grid_y: 121088, count: 7600, grid_x: 480506 },
+  { grid_y: 121088, count: 3800, grid_x: 480507 },
+  { grid_y: 121088, count: 7600, grid_x: 480508 },
+  { grid_y: 121088, count: 7600, grid_x: 480510 },
+  { grid_y: 121088, count: 3800, grid_x: 480511 },
+  { grid_y: 121088, count: 7600, grid_x: 480512 },
+  { grid_y: 121088, count: 7600, grid_x: 480520 },
+  { grid_y: 121088, count: 3800, grid_x: 480529 },
+  { grid_y: 121089, count: 3800, grid_x: 480462 },
+  { grid_y: 121089, count: 3800, grid_x: 480470 },
+  { grid_y: 121089, count: 3800, grid_x: 480472 },
+  { grid_y: 121089, count: 3800, grid_x: 480474 },
+  { grid_y: 121089, count: 3800, grid_x: 480475 },
+  { grid_y: 121089, count: 3800, grid_x: 480476 },
+  { grid_y: 121089, count: 7600, grid_x: 480477 },
+  { grid_y: 121089, count: 3800, grid_x: 480480 },
+  { grid_y: 121089, count: 3800, grid_x: 480481 },
+  { grid_y: 121089, count: 7600, grid_x: 480482 },
+  { grid_y: 121089, count: 3800, grid_x: 480486 },
+  { grid_y: 121089, count: 3800, grid_x: 480489 },
+  { grid_y: 121089, count: 3800, grid_x: 480491 },
+  { grid_y: 121089, count: 7600, grid_x: 480493 },
+  { grid_y: 121089, count: 11400, grid_x: 480498 },
+  { grid_y: 121089, count: 3800, grid_x: 480501 },
+  { grid_y: 121089, count: 7600, grid_x: 480502 },
+  { grid_y: 121089, count: 3800, grid_x: 480503 },
+  { grid_y: 121089, count: 3800, grid_x: 480504 },
+  { grid_y: 121089, count: 3800, grid_x: 480505 },
+  { grid_y: 121089, count: 7600, grid_x: 480506 },
+  { grid_y: 121089, count: 3800, grid_x: 480508 },
+  { grid_y: 121089, count: 7600, grid_x: 480512 },
+  { grid_y: 121089, count: 3800, grid_x: 480514 },
+  { grid_y: 121089, count: 3800, grid_x: 480521 },
+  { grid_y: 121089, count: 3800, grid_x: 480530 },
+  { grid_y: 121090, count: 3800, grid_x: 480461 },
+  { grid_y: 121090, count: 3800, grid_x: 480467 },
+  { grid_y: 121090, count: 3800, grid_x: 480470 },
+  { grid_y: 121090, count: 3800, grid_x: 480474 },
+  { grid_y: 121090, count: 3800, grid_x: 480475 },
+  { grid_y: 121090, count: 7600, grid_x: 480480 },
+  { grid_y: 121090, count: 3800, grid_x: 480484 },
+  { grid_y: 121090, count: 3800, grid_x: 480487 },
+  { grid_y: 121090, count: 3800, grid_x: 480495 },
+  { grid_y: 121090, count: 3800, grid_x: 480498 },
+  { grid_y: 121090, count: 7600, grid_x: 480499 },
+  { grid_y: 121090, count: 3800, grid_x: 480500 },
+  { grid_y: 121090, count: 45600, grid_x: 480501 },
+  { grid_y: 121090, count: 34200, grid_x: 480502 },
+  { grid_y: 121090, count: 15200, grid_x: 480503 },
+  { grid_y: 121090, count: 7600, grid_x: 480504 },
+  { grid_y: 121090, count: 7600, grid_x: 480505 },
+  { grid_y: 121090, count: 3800, grid_x: 480506 },
+  { grid_y: 121090, count: 3800, grid_x: 480508 },
+  { grid_y: 121090, count: 3800, grid_x: 480509 },
+  { grid_y: 121090, count: 3800, grid_x: 480510 },
+  { grid_y: 121090, count: 3800, grid_x: 480511 },
+  { grid_y: 121090, count: 3800, grid_x: 480512 },
+  { grid_y: 121090, count: 3800, grid_x: 480521 },
+  { grid_y: 121090, count: 3800, grid_x: 480522 },
+  { grid_y: 121090, count: 3800, grid_x: 480523 },
+  { grid_y: 121090, count: 3800, grid_x: 480524 },
+  { grid_y: 121090, count: 7600, grid_x: 480525 },
+  { grid_y: 121090, count: 3800, grid_x: 480527 },
+  { grid_y: 121091, count: 3800, grid_x: 480461 },
+  { grid_y: 121091, count: 3800, grid_x: 480467 },
+  { grid_y: 121091, count: 7600, grid_x: 480472 },
+  { grid_y: 121091, count: 3800, grid_x: 480481 },
+  { grid_y: 121091, count: 3800, grid_x: 480486 },
+  { grid_y: 121091, count: 7600, grid_x: 480491 },
+  { grid_y: 121091, count: 7600, grid_x: 480493 },
+  { grid_y: 121091, count: 3800, grid_x: 480494 },
+  { grid_y: 121091, count: 15200, grid_x: 480495 },
+  { grid_y: 121091, count: 7600, grid_x: 480496 },
+  { grid_y: 121091, count: 11400, grid_x: 480498 },
+  { grid_y: 121091, count: 11400, grid_x: 480500 },
+  { grid_y: 121091, count: 3800, grid_x: 480501 },
+  { grid_y: 121091, count: 11400, grid_x: 480502 },
+  { grid_y: 121091, count: 7600, grid_x: 480503 },
+  { grid_y: 121091, count: 7600, grid_x: 480504 },
+  { grid_y: 121091, count: 3800, grid_x: 480508 },
+  { grid_y: 121091, count: 3800, grid_x: 480509 },
+  { grid_y: 121091, count: 3800, grid_x: 480520 },
+  { grid_y: 121091, count: 7600, grid_x: 480521 },
+  { grid_y: 121091, count: 7600, grid_x: 480522 },
+  { grid_y: 121091, count: 26600, grid_x: 480523 },
+  { grid_y: 121091, count: 7600, grid_x: 480524 },
+  { grid_y: 121091, count: 7600, grid_x: 480525 },
+  { grid_y: 121091, count: 15200, grid_x: 480526 },
+  { grid_y: 121091, count: 3800, grid_x: 480527 },
+  { grid_y: 121091, count: 3800, grid_x: 480528 },
+  { grid_y: 121091, count: 3800, grid_x: 480532 },
+  { grid_y: 121091, count: 3800, grid_x: 480533 },
+  { grid_y: 121092, count: 7600, grid_x: 480460 },
+  { grid_y: 121092, count: 3800, grid_x: 480465 },
+  { grid_y: 121092, count: 7600, grid_x: 480466 },
+  { grid_y: 121092, count: 3800, grid_x: 480467 },
+  { grid_y: 121092, count: 3800, grid_x: 480468 },
+  { grid_y: 121092, count: 3800, grid_x: 480469 },
+  { grid_y: 121092, count: 3800, grid_x: 480474 },
+  { grid_y: 121092, count: 7600, grid_x: 480482 },
+  { grid_y: 121092, count: 3800, grid_x: 480491 },
+  { grid_y: 121092, count: 3800, grid_x: 480492 },
+  { grid_y: 121092, count: 3800, grid_x: 480493 },
+  { grid_y: 121092, count: 7600, grid_x: 480494 },
+  { grid_y: 121092, count: 11400, grid_x: 480495 },
+  { grid_y: 121092, count: 3800, grid_x: 480496 },
+  { grid_y: 121092, count: 15200, grid_x: 480498 },
+  { grid_y: 121092, count: 7600, grid_x: 480499 },
+  { grid_y: 121092, count: 3800, grid_x: 480501 },
+  { grid_y: 121092, count: 7600, grid_x: 480502 },
+  { grid_y: 121092, count: 3800, grid_x: 480503 },
+  { grid_y: 121092, count: 3800, grid_x: 480504 },
+  { grid_y: 121092, count: 7600, grid_x: 480507 },
+  { grid_y: 121092, count: 3800, grid_x: 480508 },
+  { grid_y: 121092, count: 3800, grid_x: 480511 },
+  { grid_y: 121092, count: 3800, grid_x: 480512 },
+  { grid_y: 121092, count: 3800, grid_x: 480516 },
+  { grid_y: 121092, count: 7600, grid_x: 480523 },
+  { grid_y: 121092, count: 7600, grid_x: 480524 },
+  { grid_y: 121092, count: 7600, grid_x: 480525 },
+  { grid_y: 121092, count: 7600, grid_x: 480526 },
+  { grid_y: 121092, count: 3800, grid_x: 480532 },
+  { grid_y: 121092, count: 3800, grid_x: 480533 },
+  { grid_y: 121093, count: 3800, grid_x: 480463 },
+  { grid_y: 121093, count: 7600, grid_x: 480466 },
+  { grid_y: 121093, count: 3800, grid_x: 480468 },
+  { grid_y: 121093, count: 3800, grid_x: 480493 },
+  { grid_y: 121093, count: 3800, grid_x: 480494 },
+  { grid_y: 121093, count: 3800, grid_x: 480496 },
+  { grid_y: 121093, count: 3800, grid_x: 480498 },
+  { grid_y: 121093, count: 3800, grid_x: 480499 },
+  { grid_y: 121093, count: 3800, grid_x: 480502 },
+  { grid_y: 121093, count: 3800, grid_x: 480503 },
+  { grid_y: 121093, count: 3800, grid_x: 480504 },
+  { grid_y: 121093, count: 3800, grid_x: 480507 },
+  { grid_y: 121093, count: 3800, grid_x: 480508 },
+  { grid_y: 121093, count: 3800, grid_x: 480509 },
+  { grid_y: 121093, count: 3800, grid_x: 480512 },
+  { grid_y: 121093, count: 3800, grid_x: 480514 },
+  { grid_y: 121093, count: 3800, grid_x: 480520 },
+  { grid_y: 121093, count: 3800, grid_x: 480521 },
+  { grid_y: 121093, count: 3800, grid_x: 480523 },
+  { grid_y: 121093, count: 3800, grid_x: 480524 },
+  { grid_y: 121093, count: 3800, grid_x: 480526 },
+  { grid_y: 121093, count: 3800, grid_x: 480532 },
+  { grid_y: 121093, count: 3800, grid_x: 480533 },
+  { grid_y: 121094, count: 3800, grid_x: 480467 },
+  { grid_y: 121094, count: 3800, grid_x: 480491 },
+  { grid_y: 121094, count: 3800, grid_x: 480496 },
+  { grid_y: 121094, count: 3800, grid_x: 480497 },
+  { grid_y: 121094, count: 7600, grid_x: 480499 },
+  { grid_y: 121094, count: 3800, grid_x: 480503 },
+  { grid_y: 121094, count: 7600, grid_x: 480509 },
+  { grid_y: 121094, count: 3800, grid_x: 480514 },
+  { grid_y: 121094, count: 3800, grid_x: 480519 },
+  { grid_y: 121094, count: 3800, grid_x: 480521 },
+  { grid_y: 121094, count: 7600, grid_x: 480532 },
+  { grid_y: 121095, count: 3800, grid_x: 480462 },
+  { grid_y: 121095, count: 3800, grid_x: 480467 },
+  { grid_y: 121095, count: 3800, grid_x: 480472 },
+  { grid_y: 121095, count: 3800, grid_x: 480473 },
+  { grid_y: 121095, count: 3800, grid_x: 480476 },
+  { grid_y: 121095, count: 3800, grid_x: 480480 },
+  { grid_y: 121095, count: 3800, grid_x: 480497 },
+  { grid_y: 121095, count: 3800, grid_x: 480498 },
+  { grid_y: 121095, count: 3800, grid_x: 480501 },
+  { grid_y: 121095, count: 3800, grid_x: 480515 },
+  { grid_y: 121095, count: 3800, grid_x: 480520 },
+  { grid_y: 121095, count: 3800, grid_x: 480522 },
+  { grid_y: 121095, count: 3800, grid_x: 480530 },
+  { grid_y: 121095, count: 3800, grid_x: 480531 },
+  { grid_y: 121096, count: 3800, grid_x: 480465 },
+  { grid_y: 121096, count: 3800, grid_x: 480483 },
+  { grid_y: 121096, count: 7600, grid_x: 480485 },
+  { grid_y: 121096, count: 3800, grid_x: 480489 },
+  { grid_y: 121096, count: 3800, grid_x: 480491 },
+  { grid_y: 121096, count: 3800, grid_x: 480494 },
+  { grid_y: 121096, count: 7600, grid_x: 480497 },
+  { grid_y: 121096, count: 3800, grid_x: 480498 },
+  { grid_y: 121096, count: 3800, grid_x: 480499 },
+  { grid_y: 121096, count: 3800, grid_x: 480500 },
+  { grid_y: 121096, count: 7600, grid_x: 480502 },
+  { grid_y: 121096, count: 7600, grid_x: 480503 },
+  { grid_y: 121096, count: 3800, grid_x: 480504 },
+  { grid_y: 121096, count: 3800, grid_x: 480505 },
+  { grid_y: 121096, count: 3800, grid_x: 480507 },
+  { grid_y: 121096, count: 3800, grid_x: 480510 },
+  { grid_y: 121096, count: 3800, grid_x: 480511 },
+  { grid_y: 121096, count: 3800, grid_x: 480512 },
+  { grid_y: 121096, count: 7600, grid_x: 480515 },
+  { grid_y: 121096, count: 3800, grid_x: 480517 },
+  { grid_y: 121096, count: 7600, grid_x: 480520 },
+  { grid_y: 121096, count: 3800, grid_x: 480525 },
+  { grid_y: 121096, count: 3800, grid_x: 480527 },
+  { grid_y: 121096, count: 3800, grid_x: 480529 },
+  { grid_y: 121096, count: 3800, grid_x: 480531 },
+  { grid_y: 121097, count: 3800, grid_x: 480465 },
+  { grid_y: 121097, count: 3800, grid_x: 480472 },
+  { grid_y: 121097, count: 3800, grid_x: 480482 },
+  { grid_y: 121097, count: 11400, grid_x: 480483 },
+  { grid_y: 121097, count: 3800, grid_x: 480484 },
+  { grid_y: 121097, count: 3800, grid_x: 480485 },
+  { grid_y: 121097, count: 3800, grid_x: 480486 },
+  { grid_y: 121097, count: 11400, grid_x: 480487 },
+  { grid_y: 121097, count: 7600, grid_x: 480488 },
+  { grid_y: 121097, count: 7600, grid_x: 480489 },
+  { grid_y: 121097, count: 7600, grid_x: 480491 },
+  { grid_y: 121097, count: 11400, grid_x: 480492 },
+  { grid_y: 121097, count: 3800, grid_x: 480493 },
+  { grid_y: 121097, count: 3800, grid_x: 480494 },
+  { grid_y: 121097, count: 7600, grid_x: 480495 },
+  { grid_y: 121097, count: 3800, grid_x: 480497 },
+  { grid_y: 121097, count: 7600, grid_x: 480499 },
+  { grid_y: 121097, count: 3800, grid_x: 480501 },
+  { grid_y: 121097, count: 3800, grid_x: 480506 },
+  { grid_y: 121097, count: 3800, grid_x: 480509 },
+  { grid_y: 121097, count: 7600, grid_x: 480513 },
+  { grid_y: 121097, count: 3800, grid_x: 480515 },
+  { grid_y: 121097, count: 7600, grid_x: 480520 },
+  { grid_y: 121097, count: 3800, grid_x: 480522 },
+  { grid_y: 121097, count: 3800, grid_x: 480531 },
+  { grid_y: 121097, count: 7600, grid_x: 480532 },
+  { grid_y: 121097, count: 7600, grid_x: 480533 },
+  { grid_y: 121098, count: 7600, grid_x: 480464 },
+  { grid_y: 121098, count: 3800, grid_x: 480475 },
+  { grid_y: 121098, count: 7600, grid_x: 480484 },
+  { grid_y: 121098, count: 11400, grid_x: 480487 },
+  { grid_y: 121098, count: 11400, grid_x: 480489 },
+  { grid_y: 121098, count: 3800, grid_x: 480497 },
+  { grid_y: 121098, count: 7600, grid_x: 480499 },
+  { grid_y: 121098, count: 15200, grid_x: 480501 },
+  { grid_y: 121098, count: 3800, grid_x: 480502 },
+  { grid_y: 121098, count: 3800, grid_x: 480504 },
+  { grid_y: 121098, count: 3800, grid_x: 480509 },
+  { grid_y: 121098, count: 3800, grid_x: 480519 },
+  { grid_y: 121098, count: 3800, grid_x: 480521 },
+  { grid_y: 121098, count: 7600, grid_x: 480523 },
+  { grid_y: 121098, count: 3800, grid_x: 480524 },
+  { grid_y: 121098, count: 3800, grid_x: 480526 },
+  { grid_y: 121098, count: 3800, grid_x: 480529 },
+  { grid_y: 121098, count: 3800, grid_x: 480532 },
+  { grid_y: 121098, count: 7600, grid_x: 480533 },
+  { grid_y: 121099, count: 7600, grid_x: 480461 },
+  { grid_y: 121099, count: 3800, grid_x: 480464 },
+  { grid_y: 121099, count: 3800, grid_x: 480469 },
+  { grid_y: 121099, count: 7600, grid_x: 480470 },
+  { grid_y: 121099, count: 3800, grid_x: 480477 },
+  { grid_y: 121099, count: 3800, grid_x: 480481 },
+  { grid_y: 121099, count: 3800, grid_x: 480482 },
+  { grid_y: 121099, count: 7600, grid_x: 480485 },
+  { grid_y: 121099, count: 7600, grid_x: 480486 },
+  { grid_y: 121099, count: 19000, grid_x: 480487 },
+  { grid_y: 121099, count: 7600, grid_x: 480488 },
+  { grid_y: 121099, count: 3800, grid_x: 480497 },
+  { grid_y: 121099, count: 3800, grid_x: 480499 },
+  { grid_y: 121099, count: 7600, grid_x: 480500 },
+  { grid_y: 121099, count: 19000, grid_x: 480501 },
+  { grid_y: 121099, count: 7600, grid_x: 480502 },
+  { grid_y: 121099, count: 3800, grid_x: 480504 },
+  { grid_y: 121099, count: 7600, grid_x: 480505 },
+  { grid_y: 121099, count: 3800, grid_x: 480519 },
+  { grid_y: 121099, count: 3800, grid_x: 480520 },
+  { grid_y: 121099, count: 3800, grid_x: 480528 },
+  { grid_y: 121099, count: 7600, grid_x: 480532 },
+  { grid_y: 121100, count: 3800, grid_x: 480461 },
+  { grid_y: 121100, count: 3800, grid_x: 480462 },
+  { grid_y: 121100, count: 3800, grid_x: 480465 },
+  { grid_y: 121100, count: 3800, grid_x: 480480 },
+  { grid_y: 121100, count: 15200, grid_x: 480481 },
+  { grid_y: 121100, count: 3800, grid_x: 480484 },
+  { grid_y: 121100, count: 7600, grid_x: 480487 },
+  { grid_y: 121100, count: 11400, grid_x: 480488 },
+  { grid_y: 121100, count: 7600, grid_x: 480489 },
+  { grid_y: 121100, count: 3800, grid_x: 480490 },
+  { grid_y: 121100, count: 3800, grid_x: 480497 },
+  { grid_y: 121100, count: 7600, grid_x: 480502 },
+  { grid_y: 121100, count: 7600, grid_x: 480504 },
+  { grid_y: 121100, count: 7600, grid_x: 480505 },
+  { grid_y: 121100, count: 3800, grid_x: 480508 },
+  { grid_y: 121100, count: 3800, grid_x: 480523 },
+  { grid_y: 121100, count: 3800, grid_x: 480528 },
+  { grid_y: 121100, count: 3800, grid_x: 480529 },
+  { grid_y: 121100, count: 7600, grid_x: 480530 },
+  { grid_y: 121100, count: 3800, grid_x: 480531 },
+  { grid_y: 121100, count: 7600, grid_x: 480532 },
+  { grid_y: 121100, count: 7600, grid_x: 480533 },
+  { grid_y: 121101, count: 3800, grid_x: 480459 },
+  { grid_y: 121101, count: 3800, grid_x: 480462 },
+  { grid_y: 121101, count: 3800, grid_x: 480475 },
+  { grid_y: 121101, count: 7600, grid_x: 480482 },
+  { grid_y: 121101, count: 7600, grid_x: 480488 },
+  { grid_y: 121101, count: 7600, grid_x: 480489 },
+  { grid_y: 121101, count: 3800, grid_x: 480492 },
+  { grid_y: 121101, count: 3800, grid_x: 480497 },
+  { grid_y: 121101, count: 3800, grid_x: 480498 },
+  { grid_y: 121101, count: 3800, grid_x: 480501 },
+  { grid_y: 121101, count: 7600, grid_x: 480504 },
+  { grid_y: 121101, count: 11400, grid_x: 480505 },
+  { grid_y: 121101, count: 3800, grid_x: 480510 },
+  { grid_y: 121101, count: 3800, grid_x: 480517 },
+  { grid_y: 121101, count: 3800, grid_x: 480519 },
+  { grid_y: 121101, count: 7600, grid_x: 480520 },
+  { grid_y: 121101, count: 3800, grid_x: 480522 },
+  { grid_y: 121101, count: 3800, grid_x: 480527 },
+  { grid_y: 121101, count: 7600, grid_x: 480528 },
+  { grid_y: 121101, count: 7600, grid_x: 480529 },
+  { grid_y: 121101, count: 7600, grid_x: 480530 },
+  { grid_y: 121101, count: 7600, grid_x: 480531 },
+  { grid_y: 121101, count: 11400, grid_x: 480532 },
+  { grid_y: 121101, count: 11400, grid_x: 480533 },
+  { grid_y: 121102, count: 3800, grid_x: 480466 },
+  { grid_y: 121102, count: 3800, grid_x: 480468 },
+  { grid_y: 121102, count: 3800, grid_x: 480479 },
+  { grid_y: 121102, count: 3800, grid_x: 480480 },
+  { grid_y: 121102, count: 3800, grid_x: 480481 },
+  { grid_y: 121102, count: 3800, grid_x: 480486 },
+  { grid_y: 121102, count: 3800, grid_x: 480487 },
+  { grid_y: 121102, count: 3800, grid_x: 480488 },
+  { grid_y: 121102, count: 3800, grid_x: 480489 },
+  { grid_y: 121102, count: 3800, grid_x: 480490 },
+  { grid_y: 121102, count: 3800, grid_x: 480492 },
+  { grid_y: 121102, count: 7600, grid_x: 480493 },
+  { grid_y: 121102, count: 3800, grid_x: 480497 },
+  { grid_y: 121102, count: 3800, grid_x: 480499 },
+  { grid_y: 121102, count: 3800, grid_x: 480501 },
+  { grid_y: 121102, count: 3800, grid_x: 480503 },
+  { grid_y: 121102, count: 7600, grid_x: 480504 },
+  { grid_y: 121102, count: 11400, grid_x: 480505 },
+  { grid_y: 121102, count: 7600, grid_x: 480506 },
+  { grid_y: 121102, count: 3800, grid_x: 480514 },
+  { grid_y: 121102, count: 3800, grid_x: 480518 },
+  { grid_y: 121102, count: 7600, grid_x: 480519 },
+  { grid_y: 121102, count: 3800, grid_x: 480525 },
+  { grid_y: 121102, count: 7600, grid_x: 480527 },
+  { grid_y: 121102, count: 7600, grid_x: 480528 },
+  { grid_y: 121102, count: 7600, grid_x: 480529 },
+  { grid_y: 121102, count: 15200, grid_x: 480530 },
+  { grid_y: 121102, count: 3800, grid_x: 480531 },
+  { grid_y: 121102, count: 3800, grid_x: 480532 },
+  { grid_y: 121102, count: 7600, grid_x: 480533 },
+  { grid_y: 121103, count: 3800, grid_x: 480459 },
+  { grid_y: 121103, count: 3800, grid_x: 480460 },
+  { grid_y: 121103, count: 7600, grid_x: 480471 },
+  { grid_y: 121103, count: 3800, grid_x: 480472 },
+  { grid_y: 121103, count: 3800, grid_x: 480481 },
+  { grid_y: 121103, count: 3800, grid_x: 480482 },
+  { grid_y: 121103, count: 3800, grid_x: 480484 },
+  { grid_y: 121103, count: 3800, grid_x: 480485 },
+  { grid_y: 121103, count: 11400, grid_x: 480488 },
+  { grid_y: 121103, count: 15200, grid_x: 480489 },
+  { grid_y: 121103, count: 7600, grid_x: 480495 },
+  { grid_y: 121103, count: 7600, grid_x: 480496 },
+  { grid_y: 121103, count: 3800, grid_x: 480497 },
+  { grid_y: 121103, count: 3800, grid_x: 480501 },
+  { grid_y: 121103, count: 3800, grid_x: 480503 },
+  { grid_y: 121103, count: 7600, grid_x: 480505 },
+  { grid_y: 121103, count: 3800, grid_x: 480506 },
+  { grid_y: 121103, count: 3800, grid_x: 480507 },
+  { grid_y: 121103, count: 3800, grid_x: 480509 },
+  { grid_y: 121103, count: 3800, grid_x: 480510 },
+  { grid_y: 121103, count: 3800, grid_x: 480514 },
+  { grid_y: 121103, count: 3800, grid_x: 480517 },
+  { grid_y: 121103, count: 3800, grid_x: 480519 },
+  { grid_y: 121103, count: 3800, grid_x: 480522 },
+  { grid_y: 121103, count: 3800, grid_x: 480525 },
+  { grid_y: 121103, count: 3800, grid_x: 480528 },
+  { grid_y: 121103, count: 3800, grid_x: 480529 },
+  { grid_y: 121103, count: 3800, grid_x: 480530 },
+  { grid_y: 121103, count: 3800, grid_x: 480533 },
+  { grid_y: 121104, count: 3800, grid_x: 480460 },
+  { grid_y: 121104, count: 3800, grid_x: 480461 },
+  { grid_y: 121104, count: 3800, grid_x: 480463 },
+  { grid_y: 121104, count: 3800, grid_x: 480466 },
+  { grid_y: 121104, count: 3800, grid_x: 480477 },
+  { grid_y: 121104, count: 7600, grid_x: 480478 },
+  { grid_y: 121104, count: 7600, grid_x: 480479 },
+  { grid_y: 121104, count: 3800, grid_x: 480480 },
+  { grid_y: 121104, count: 7600, grid_x: 480481 },
+  { grid_y: 121104, count: 7600, grid_x: 480482 },
+  { grid_y: 121104, count: 3800, grid_x: 480483 },
+  { grid_y: 121104, count: 3800, grid_x: 480487 },
+  { grid_y: 121104, count: 11400, grid_x: 480488 },
+  { grid_y: 121104, count: 7600, grid_x: 480489 },
+  { grid_y: 121104, count: 15200, grid_x: 480490 },
+  { grid_y: 121104, count: 3800, grid_x: 480491 },
+  { grid_y: 121104, count: 3800, grid_x: 480494 },
+  { grid_y: 121104, count: 7600, grid_x: 480495 },
+  { grid_y: 121104, count: 7600, grid_x: 480496 },
+  { grid_y: 121104, count: 7600, grid_x: 480497 },
+  { grid_y: 121104, count: 3800, grid_x: 480499 },
+  { grid_y: 121104, count: 3800, grid_x: 480500 },
+  { grid_y: 121104, count: 3800, grid_x: 480506 },
+  { grid_y: 121104, count: 3800, grid_x: 480513 },
+  { grid_y: 121104, count: 3800, grid_x: 480515 },
+  { grid_y: 121104, count: 7600, grid_x: 480516 },
+  { grid_y: 121104, count: 7600, grid_x: 480517 },
+  { grid_y: 121104, count: 3800, grid_x: 480519 },
+  { grid_y: 121104, count: 7600, grid_x: 480520 },
+  { grid_y: 121104, count: 3800, grid_x: 480524 },
+  { grid_y: 121104, count: 7600, grid_x: 480525 },
+  { grid_y: 121104, count: 7600, grid_x: 480526 },
+  { grid_y: 121104, count: 3800, grid_x: 480527 },
+  { grid_y: 121104, count: 3800, grid_x: 480528 },
+  { grid_y: 121104, count: 7600, grid_x: 480530 },
+  { grid_y: 121104, count: 7600, grid_x: 480531 },
+  { grid_y: 121105, count: 3800, grid_x: 480460 },
+  { grid_y: 121105, count: 7600, grid_x: 480462 },
+  { grid_y: 121105, count: 3800, grid_x: 480463 },
+  { grid_y: 121105, count: 3800, grid_x: 480464 },
+  { grid_y: 121105, count: 3800, grid_x: 480467 },
+  { grid_y: 121105, count: 3800, grid_x: 480468 },
+  { grid_y: 121105, count: 3800, grid_x: 480469 },
+  { grid_y: 121105, count: 7600, grid_x: 480470 },
+  { grid_y: 121105, count: 7600, grid_x: 480472 },
+  { grid_y: 121105, count: 3800, grid_x: 480473 },
+  { grid_y: 121105, count: 3800, grid_x: 480476 },
+  { grid_y: 121105, count: 7600, grid_x: 480477 },
+  { grid_y: 121105, count: 7600, grid_x: 480480 },
+  { grid_y: 121105, count: 3800, grid_x: 480481 },
+  { grid_y: 121105, count: 7600, grid_x: 480482 },
+  { grid_y: 121105, count: 7600, grid_x: 480483 },
+  { grid_y: 121105, count: 3800, grid_x: 480485 },
+  { grid_y: 121105, count: 7600, grid_x: 480487 },
+  { grid_y: 121105, count: 3800, grid_x: 480488 },
+  { grid_y: 121105, count: 22800, grid_x: 480489 },
+  { grid_y: 121105, count: 15200, grid_x: 480490 },
+  { grid_y: 121105, count: 11400, grid_x: 480492 },
+  { grid_y: 121105, count: 3800, grid_x: 480493 },
+  { grid_y: 121105, count: 3800, grid_x: 480494 },
+  { grid_y: 121105, count: 3800, grid_x: 480495 },
+  { grid_y: 121105, count: 3800, grid_x: 480496 },
+  { grid_y: 121105, count: 7600, grid_x: 480497 },
+  { grid_y: 121105, count: 3800, grid_x: 480500 },
+  { grid_y: 121105, count: 3800, grid_x: 480501 },
+  { grid_y: 121105, count: 3800, grid_x: 480509 },
+  { grid_y: 121105, count: 3800, grid_x: 480515 },
+  { grid_y: 121105, count: 3800, grid_x: 480517 },
+  { grid_y: 121105, count: 3800, grid_x: 480518 },
+  { grid_y: 121105, count: 3800, grid_x: 480519 },
+  { grid_y: 121105, count: 3800, grid_x: 480520 },
+  { grid_y: 121105, count: 3800, grid_x: 480521 },
+  { grid_y: 121105, count: 3800, grid_x: 480522 },
+  { grid_y: 121105, count: 11400, grid_x: 480526 },
+  { grid_y: 121105, count: 11400, grid_x: 480527 },
+  { grid_y: 121105, count: 3800, grid_x: 480528 },
+  { grid_y: 121105, count: 3800, grid_x: 480529 },
+  { grid_y: 121105, count: 3800, grid_x: 480531 },
+  { grid_y: 121105, count: 7600, grid_x: 480532 },
+  { grid_y: 121105, count: 7600, grid_x: 480533 },
+  { grid_y: 121106, count: 3800, grid_x: 480464 },
+  { grid_y: 121106, count: 7600, grid_x: 480465 },
+  { grid_y: 121106, count: 3800, grid_x: 480466 },
+  { grid_y: 121106, count: 3800, grid_x: 480469 },
+  { grid_y: 121106, count: 3800, grid_x: 480471 },
+  { grid_y: 121106, count: 3800, grid_x: 480472 },
+  { grid_y: 121106, count: 3800, grid_x: 480473 },
+  { grid_y: 121106, count: 3800, grid_x: 480476 },
+  { grid_y: 121106, count: 11400, grid_x: 480479 },
+  { grid_y: 121106, count: 15200, grid_x: 480480 },
+  { grid_y: 121106, count: 3800, grid_x: 480484 },
+  { grid_y: 121106, count: 3800, grid_x: 480487 },
+  { grid_y: 121106, count: 3800, grid_x: 480488 },
+  { grid_y: 121106, count: 7600, grid_x: 480490 },
+  { grid_y: 121106, count: 7600, grid_x: 480494 },
+  { grid_y: 121106, count: 3800, grid_x: 480495 },
+  { grid_y: 121106, count: 3800, grid_x: 480497 },
+  { grid_y: 121106, count: 15200, grid_x: 480498 },
+  { grid_y: 121106, count: 15200, grid_x: 480499 },
+  { grid_y: 121106, count: 3800, grid_x: 480500 },
+  { grid_y: 121106, count: 3800, grid_x: 480501 },
+  { grid_y: 121106, count: 11400, grid_x: 480503 },
+  { grid_y: 121106, count: 3800, grid_x: 480504 },
+  { grid_y: 121106, count: 7600, grid_x: 480505 },
+  { grid_y: 121106, count: 3800, grid_x: 480506 },
+  { grid_y: 121106, count: 11400, grid_x: 480507 },
+  { grid_y: 121106, count: 3800, grid_x: 480508 },
+  { grid_y: 121106, count: 3800, grid_x: 480509 },
+  { grid_y: 121106, count: 3800, grid_x: 480511 },
+  { grid_y: 121106, count: 3800, grid_x: 480513 },
+  { grid_y: 121106, count: 3800, grid_x: 480514 },
+  { grid_y: 121106, count: 3800, grid_x: 480515 },
+  { grid_y: 121106, count: 3800, grid_x: 480519 },
+  { grid_y: 121106, count: 7600, grid_x: 480520 },
+  { grid_y: 121106, count: 3800, grid_x: 480523 },
+  { grid_y: 121106, count: 11400, grid_x: 480527 },
+  { grid_y: 121106, count: 7600, grid_x: 480528 },
+  { grid_y: 121106, count: 3800, grid_x: 480529 },
+  { grid_y: 121106, count: 3800, grid_x: 480530 },
+  { grid_y: 121106, count: 3800, grid_x: 480532 },
+  { grid_y: 121106, count: 7600, grid_x: 480533 },
+  { grid_y: 121107, count: 7600, grid_x: 480459 },
+  { grid_y: 121107, count: 7600, grid_x: 480461 },
+  { grid_y: 121107, count: 3800, grid_x: 480462 },
+  { grid_y: 121107, count: 3800, grid_x: 480464 },
+  { grid_y: 121107, count: 3800, grid_x: 480466 },
+  { grid_y: 121107, count: 3800, grid_x: 480467 },
+  { grid_y: 121107, count: 3800, grid_x: 480471 },
+  { grid_y: 121107, count: 3800, grid_x: 480472 },
+  { grid_y: 121107, count: 3800, grid_x: 480478 },
+  { grid_y: 121107, count: 3800, grid_x: 480479 },
+  { grid_y: 121107, count: 7600, grid_x: 480480 },
+  { grid_y: 121107, count: 3800, grid_x: 480483 },
+  { grid_y: 121107, count: 3800, grid_x: 480485 },
+  { grid_y: 121107, count: 7600, grid_x: 480497 },
+  { grid_y: 121107, count: 11400, grid_x: 480498 },
+  { grid_y: 121107, count: 19000, grid_x: 480499 },
+  { grid_y: 121107, count: 11400, grid_x: 480500 },
+  { grid_y: 121107, count: 3800, grid_x: 480501 },
+  { grid_y: 121107, count: 3800, grid_x: 480503 },
+  { grid_y: 121107, count: 7600, grid_x: 480507 },
+  { grid_y: 121107, count: 15200, grid_x: 480508 },
+  { grid_y: 121107, count: 3800, grid_x: 480510 },
+  { grid_y: 121107, count: 3800, grid_x: 480512 },
+  { grid_y: 121107, count: 7600, grid_x: 480513 },
+  { grid_y: 121107, count: 7600, grid_x: 480514 },
+  { grid_y: 121107, count: 3800, grid_x: 480516 },
+  { grid_y: 121107, count: 7600, grid_x: 480517 },
+  { grid_y: 121107, count: 3800, grid_x: 480520 },
+  { grid_y: 121107, count: 11400, grid_x: 480522 },
+  { grid_y: 121107, count: 7600, grid_x: 480523 },
+  { grid_y: 121107, count: 3800, grid_x: 480524 },
+  { grid_y: 121107, count: 7600, grid_x: 480525 },
+  { grid_y: 121107, count: 3800, grid_x: 480526 },
+  { grid_y: 121107, count: 3800, grid_x: 480527 },
+  { grid_y: 121107, count: 3800, grid_x: 480528 },
+  { grid_y: 121107, count: 7600, grid_x: 480529 },
+  { grid_y: 121107, count: 7600, grid_x: 480532 },
+  { grid_y: 121107, count: 7600, grid_x: 480533 },
+  { grid_y: 121108, count: 7600, grid_x: 480459 },
+  { grid_y: 121108, count: 7600, grid_x: 480460 },
+  { grid_y: 121108, count: 3800, grid_x: 480461 },
+  { grid_y: 121108, count: 3800, grid_x: 480464 },
+  { grid_y: 121108, count: 3800, grid_x: 480495 },
+  { grid_y: 121108, count: 3800, grid_x: 480497 },
+  { grid_y: 121108, count: 15200, grid_x: 480498 },
+  { grid_y: 121108, count: 19000, grid_x: 480499 },
+  { grid_y: 121108, count: 11400, grid_x: 480500 },
+  { grid_y: 121108, count: 11400, grid_x: 480501 },
+  { grid_y: 121108, count: 11400, grid_x: 480502 },
+  { grid_y: 121108, count: 11400, grid_x: 480503 },
+  { grid_y: 121108, count: 7600, grid_x: 480507 },
+  { grid_y: 121108, count: 3800, grid_x: 480513 },
+  { grid_y: 121108, count: 3800, grid_x: 480514 },
+  { grid_y: 121108, count: 3800, grid_x: 480515 },
+  { grid_y: 121108, count: 11400, grid_x: 480516 },
+  { grid_y: 121108, count: 7600, grid_x: 480517 },
+  { grid_y: 121108, count: 3800, grid_x: 480518 },
+  { grid_y: 121108, count: 3800, grid_x: 480519 },
+  { grid_y: 121108, count: 3800, grid_x: 480520 },
+  { grid_y: 121108, count: 3800, grid_x: 480524 },
+  { grid_y: 121108, count: 3800, grid_x: 480526 },
+  { grid_y: 121108, count: 7600, grid_x: 480527 },
+  { grid_y: 121108, count: 3800, grid_x: 480528 },
+  { grid_y: 121108, count: 3800, grid_x: 480529 },
+  { grid_y: 121108, count: 3800, grid_x: 480530 },
+  { grid_y: 121108, count: 7600, grid_x: 480533 },
+  { grid_y: 121109, count: 7600, grid_x: 480459 },
+  { grid_y: 121109, count: 7600, grid_x: 480460 },
+  { grid_y: 121109, count: 7600, grid_x: 480496 },
+  { grid_y: 121109, count: 7600, grid_x: 480497 },
+  { grid_y: 121109, count: 7600, grid_x: 480498 },
+  { grid_y: 121109, count: 11400, grid_x: 480499 },
+  { grid_y: 121109, count: 7600, grid_x: 480500 },
+  { grid_y: 121109, count: 3800, grid_x: 480501 },
+  { grid_y: 121109, count: 11400, grid_x: 480502 },
+  { grid_y: 121109, count: 3800, grid_x: 480503 },
+  { grid_y: 121109, count: 3800, grid_x: 480506 },
+  { grid_y: 121109, count: 7600, grid_x: 480507 },
+  { grid_y: 121109, count: 3800, grid_x: 480508 },
+  { grid_y: 121109, count: 3800, grid_x: 480510 },
+  { grid_y: 121109, count: 3800, grid_x: 480513 },
+  { grid_y: 121109, count: 7600, grid_x: 480514 },
+  { grid_y: 121109, count: 7600, grid_x: 480516 },
+  { grid_y: 121109, count: 11400, grid_x: 480517 },
+  { grid_y: 121109, count: 3800, grid_x: 480518 },
+  { grid_y: 121109, count: 3800, grid_x: 480523 },
+  { grid_y: 121109, count: 3800, grid_x: 480531 },
+  { grid_y: 121109, count: 3800, grid_x: 480533 },
+  { grid_y: 121110, count: 7600, grid_x: 480459 },
+  { grid_y: 121110, count: 3800, grid_x: 480460 },
+  { grid_y: 121110, count: 3800, grid_x: 480461 },
+  { grid_y: 121110, count: 3800, grid_x: 480465 },
+  { grid_y: 121110, count: 3800, grid_x: 480467 },
+  { grid_y: 121110, count: 3800, grid_x: 480471 },
+  { grid_y: 121110, count: 3800, grid_x: 480478 },
+  { grid_y: 121110, count: 3800, grid_x: 480479 },
+  { grid_y: 121110, count: 3800, grid_x: 480489 },
+  { grid_y: 121110, count: 7600, grid_x: 480497 },
+  { grid_y: 121110, count: 7600, grid_x: 480498 },
+  { grid_y: 121110, count: 7600, grid_x: 480499 },
+  { grid_y: 121110, count: 7600, grid_x: 480502 },
+  { grid_y: 121110, count: 3800, grid_x: 480504 },
+  { grid_y: 121110, count: 3800, grid_x: 480510 },
+  { grid_y: 121110, count: 7600, grid_x: 480511 },
+  { grid_y: 121110, count: 3800, grid_x: 480512 },
+  { grid_y: 121110, count: 11400, grid_x: 480516 },
+  { grid_y: 121110, count: 7600, grid_x: 480517 },
+  { grid_y: 121110, count: 3800, grid_x: 480518 },
+  { grid_y: 121110, count: 7600, grid_x: 480519 },
+  { grid_y: 121110, count: 3800, grid_x: 480521 },
+  { grid_y: 121110, count: 3800, grid_x: 480523 },
+  { grid_y: 121110, count: 3800, grid_x: 480526 },
+  { grid_y: 121111, count: 3800, grid_x: 480460 },
+  { grid_y: 121111, count: 3800, grid_x: 480493 },
+  { grid_y: 121111, count: 3800, grid_x: 480496 },
+  { grid_y: 121111, count: 11400, grid_x: 480500 },
+  { grid_y: 121111, count: 3800, grid_x: 480501 },
+  { grid_y: 121111, count: 7600, grid_x: 480502 },
+  { grid_y: 121111, count: 3800, grid_x: 480503 },
+  { grid_y: 121111, count: 3800, grid_x: 480504 },
+  { grid_y: 121111, count: 3800, grid_x: 480505 },
+  { grid_y: 121111, count: 3800, grid_x: 480506 },
+  { grid_y: 121111, count: 3800, grid_x: 480511 },
+  { grid_y: 121111, count: 3800, grid_x: 480515 },
+  { grid_y: 121111, count: 3800, grid_x: 480516 },
+  { grid_y: 121111, count: 7600, grid_x: 480517 },
+  { grid_y: 121111, count: 3800, grid_x: 480528 },
+  { grid_y: 121112, count: 3800, grid_x: 480459 },
+  { grid_y: 121112, count: 3800, grid_x: 480460 },
+  { grid_y: 121112, count: 3800, grid_x: 480465 },
+  { grid_y: 121112, count: 3800, grid_x: 480467 },
+  { grid_y: 121112, count: 3800, grid_x: 480478 },
+  { grid_y: 121112, count: 3800, grid_x: 480479 },
+  { grid_y: 121112, count: 7600, grid_x: 480496 },
+  { grid_y: 121112, count: 7600, grid_x: 480500 },
+  { grid_y: 121112, count: 7600, grid_x: 480501 },
+  { grid_y: 121112, count: 7600, grid_x: 480505 },
+  { grid_y: 121112, count: 3800, grid_x: 480506 },
+  { grid_y: 121112, count: 3800, grid_x: 480512 },
+  { grid_y: 121112, count: 3800, grid_x: 480519 },
+  { grid_y: 121112, count: 3800, grid_x: 480525 },
+  { grid_y: 121112, count: 3800, grid_x: 480530 },
+  { grid_y: 121112, count: 3800, grid_x: 480532 },
+  { grid_y: 121112, count: 3800, grid_x: 480533 },
+  { grid_y: 121113, count: 3800, grid_x: 480459 },
+  { grid_y: 121113, count: 3800, grid_x: 480460 },
+  { grid_y: 121113, count: 3800, grid_x: 480462 },
+  { grid_y: 121113, count: 3800, grid_x: 480463 },
+  { grid_y: 121113, count: 3800, grid_x: 480466 },
+  { grid_y: 121113, count: 7600, grid_x: 480479 },
+  { grid_y: 121113, count: 3800, grid_x: 480482 },
+  { grid_y: 121113, count: 7600, grid_x: 480483 },
+  { grid_y: 121113, count: 3800, grid_x: 480485 },
+  { grid_y: 121113, count: 3800, grid_x: 480496 },
+  { grid_y: 121113, count: 3800, grid_x: 480497 },
+  { grid_y: 121113, count: 3800, grid_x: 480498 },
+  { grid_y: 121113, count: 7600, grid_x: 480499 },
+  { grid_y: 121113, count: 7600, grid_x: 480500 },
+  { grid_y: 121113, count: 3800, grid_x: 480501 },
+  { grid_y: 121113, count: 3800, grid_x: 480502 },
+  { grid_y: 121113, count: 3800, grid_x: 480505 },
+  { grid_y: 121113, count: 3800, grid_x: 480506 },
+  { grid_y: 121113, count: 3800, grid_x: 480507 },
+  { grid_y: 121113, count: 3800, grid_x: 480514 },
+  { grid_y: 121113, count: 3800, grid_x: 480517 },
+  { grid_y: 121113, count: 7600, grid_x: 480518 },
+  { grid_y: 121113, count: 7600, grid_x: 480522 },
+  { grid_y: 121113, count: 3800, grid_x: 480527 },
+  { grid_y: 121113, count: 3800, grid_x: 480530 },
+  { grid_y: 121114, count: 3800, grid_x: 480459 },
+  { grid_y: 121114, count: 3800, grid_x: 480460 },
+  { grid_y: 121114, count: 3800, grid_x: 480462 },
+  { grid_y: 121114, count: 3800, grid_x: 480463 },
+  { grid_y: 121114, count: 3800, grid_x: 480466 },
+  { grid_y: 121114, count: 3800, grid_x: 480467 },
+  { grid_y: 121114, count: 3800, grid_x: 480468 },
+  { grid_y: 121114, count: 3800, grid_x: 480471 },
+  { grid_y: 121114, count: 7600, grid_x: 480474 },
+  { grid_y: 121114, count: 3800, grid_x: 480475 },
+  { grid_y: 121114, count: 7600, grid_x: 480478 },
+  { grid_y: 121114, count: 7600, grid_x: 480479 },
+  { grid_y: 121114, count: 3800, grid_x: 480480 },
+  { grid_y: 121114, count: 7600, grid_x: 480481 },
+  { grid_y: 121114, count: 15200, grid_x: 480482 },
+  { grid_y: 121114, count: 3800, grid_x: 480483 },
+  { grid_y: 121114, count: 7600, grid_x: 480484 },
+  { grid_y: 121114, count: 3800, grid_x: 480485 },
+  { grid_y: 121114, count: 7600, grid_x: 480486 },
+  { grid_y: 121114, count: 7600, grid_x: 480491 },
+  { grid_y: 121114, count: 3800, grid_x: 480496 },
+  { grid_y: 121114, count: 7600, grid_x: 480497 },
+  { grid_y: 121114, count: 7600, grid_x: 480498 },
+  { grid_y: 121114, count: 7600, grid_x: 480500 },
+  { grid_y: 121114, count: 11400, grid_x: 480501 },
+  { grid_y: 121114, count: 3800, grid_x: 480502 },
+  { grid_y: 121114, count: 3800, grid_x: 480507 },
+  { grid_y: 121114, count: 7600, grid_x: 480508 },
+  { grid_y: 121114, count: 7600, grid_x: 480510 },
+  { grid_y: 121114, count: 3800, grid_x: 480511 },
+  { grid_y: 121114, count: 7600, grid_x: 480515 },
+  { grid_y: 121114, count: 3800, grid_x: 480524 },
+  { grid_y: 121114, count: 3800, grid_x: 480533 },
+  { grid_y: 121115, count: 3800, grid_x: 480460 },
+  { grid_y: 121115, count: 3800, grid_x: 480468 },
+  { grid_y: 121115, count: 3800, grid_x: 480470 },
+  { grid_y: 121115, count: 3800, grid_x: 480471 },
+  { grid_y: 121115, count: 7600, grid_x: 480483 },
+  { grid_y: 121115, count: 7600, grid_x: 480484 },
+  { grid_y: 121115, count: 11400, grid_x: 480485 },
+  { grid_y: 121115, count: 3800, grid_x: 480486 },
+  { grid_y: 121115, count: 3800, grid_x: 480491 },
+  { grid_y: 121115, count: 3800, grid_x: 480494 },
+  { grid_y: 121115, count: 7600, grid_x: 480496 },
+  { grid_y: 121115, count: 3800, grid_x: 480499 },
+  { grid_y: 121115, count: 7600, grid_x: 480501 },
+  { grid_y: 121115, count: 3800, grid_x: 480507 },
+  { grid_y: 121115, count: 3800, grid_x: 480511 },
+  { grid_y: 121115, count: 7600, grid_x: 480515 },
+  { grid_y: 121115, count: 11400, grid_x: 480516 },
+  { grid_y: 121115, count: 3800, grid_x: 480517 },
+  { grid_y: 121115, count: 3800, grid_x: 480527 },
+  { grid_y: 121115, count: 3800, grid_x: 480528 },
+  { grid_y: 121116, count: 3800, grid_x: 480465 },
+  { grid_y: 121116, count: 7600, grid_x: 480468 },
+  { grid_y: 121116, count: 3800, grid_x: 480471 },
+  { grid_y: 121116, count: 3800, grid_x: 480476 },
+  { grid_y: 121116, count: 7600, grid_x: 480478 },
+  { grid_y: 121116, count: 7600, grid_x: 480479 },
+  { grid_y: 121116, count: 3800, grid_x: 480480 },
+  { grid_y: 121116, count: 3800, grid_x: 480482 },
+  { grid_y: 121116, count: 7600, grid_x: 480483 },
+  { grid_y: 121116, count: 11400, grid_x: 480484 },
+  { grid_y: 121116, count: 11400, grid_x: 480485 },
+  { grid_y: 121116, count: 7600, grid_x: 480487 },
+  { grid_y: 121116, count: 3800, grid_x: 480489 },
+  { grid_y: 121116, count: 3800, grid_x: 480491 },
+  { grid_y: 121116, count: 3800, grid_x: 480492 },
+  { grid_y: 121116, count: 3800, grid_x: 480493 },
+  { grid_y: 121116, count: 3800, grid_x: 480494 },
+  { grid_y: 121116, count: 3800, grid_x: 480501 },
+  { grid_y: 121116, count: 3800, grid_x: 480502 },
+  { grid_y: 121116, count: 3800, grid_x: 480503 },
+  { grid_y: 121116, count: 3800, grid_x: 480507 },
+  { grid_y: 121116, count: 3800, grid_x: 480509 },
+  { grid_y: 121116, count: 3800, grid_x: 480510 },
+  { grid_y: 121116, count: 3800, grid_x: 480512 },
+  { grid_y: 121116, count: 7600, grid_x: 480515 },
+  { grid_y: 121116, count: 15200, grid_x: 480516 },
+  { grid_y: 121116, count: 3800, grid_x: 480533 },
+  { grid_y: 121117, count: 3800, grid_x: 480459 },
+  { grid_y: 121117, count: 3800, grid_x: 480468 },
+  { grid_y: 121117, count: 3800, grid_x: 480470 },
+  { grid_y: 121117, count: 3800, grid_x: 480477 },
+  { grid_y: 121117, count: 3800, grid_x: 480478 },
+  { grid_y: 121117, count: 3800, grid_x: 480480 },
+  { grid_y: 121117, count: 3800, grid_x: 480482 },
+  { grid_y: 121117, count: 7600, grid_x: 480483 },
+  { grid_y: 121117, count: 7600, grid_x: 480484 },
+  { grid_y: 121117, count: 11400, grid_x: 480485 },
+  { grid_y: 121117, count: 7600, grid_x: 480486 },
+  { grid_y: 121117, count: 7600, grid_x: 480487 },
+  { grid_y: 121117, count: 11400, grid_x: 480488 },
+  { grid_y: 121117, count: 7600, grid_x: 480495 },
+  { grid_y: 121117, count: 3800, grid_x: 480496 },
+  { grid_y: 121117, count: 3800, grid_x: 480497 },
+  { grid_y: 121117, count: 3800, grid_x: 480509 },
+  { grid_y: 121117, count: 3800, grid_x: 480510 },
+  { grid_y: 121117, count: 3800, grid_x: 480516 },
+  { grid_y: 121117, count: 3800, grid_x: 480520 },
+  { grid_y: 121117, count: 7600, grid_x: 480526 },
+  { grid_y: 121117, count: 3800, grid_x: 480528 },
+  { grid_y: 121117, count: 3800, grid_x: 480533 },
+  { grid_y: 121118, count: 3800, grid_x: 480459 },
+  { grid_y: 121118, count: 3800, grid_x: 480460 },
+  { grid_y: 121118, count: 3800, grid_x: 480478 },
+  { grid_y: 121118, count: 3800, grid_x: 480481 },
+  { grid_y: 121118, count: 3800, grid_x: 480482 },
+  { grid_y: 121118, count: 7600, grid_x: 480483 },
+  { grid_y: 121118, count: 7600, grid_x: 480484 },
+  { grid_y: 121118, count: 3800, grid_x: 480486 },
+  { grid_y: 121118, count: 7600, grid_x: 480487 },
+  { grid_y: 121118, count: 7600, grid_x: 480488 },
+  { grid_y: 121118, count: 7600, grid_x: 480514 },
+  { grid_y: 121118, count: 3800, grid_x: 480516 },
+  { grid_y: 121118, count: 3800, grid_x: 480517 },
+  { grid_y: 121118, count: 3800, grid_x: 480518 },
+  { grid_y: 121118, count: 3800, grid_x: 480521 },
+  { grid_y: 121118, count: 3800, grid_x: 480528 },
+  { grid_y: 121118, count: 3800, grid_x: 480533 },
+  { grid_y: 121119, count: 3800, grid_x: 480467 },
+  { grid_y: 121119, count: 3800, grid_x: 480469 },
+  { grid_y: 121119, count: 3800, grid_x: 480478 },
+  { grid_y: 121119, count: 3800, grid_x: 480479 },
+  { grid_y: 121119, count: 3800, grid_x: 480483 },
+  { grid_y: 121119, count: 3800, grid_x: 480485 },
+  { grid_y: 121119, count: 7600, grid_x: 480486 },
+  { grid_y: 121119, count: 7600, grid_x: 480487 },
+  { grid_y: 121119, count: 3800, grid_x: 480514 },
+  { grid_y: 121119, count: 3800, grid_x: 480518 },
+  { grid_y: 121119, count: 3800, grid_x: 480526 },
+  { grid_y: 121120, count: 3800, grid_x: 480466 },
+  { grid_y: 121120, count: 3800, grid_x: 480468 },
+  { grid_y: 121120, count: 3800, grid_x: 480479 },
+  { grid_y: 121120, count: 3800, grid_x: 480480 },
+  { grid_y: 121120, count: 3800, grid_x: 480483 },
+  { grid_y: 121120, count: 3800, grid_x: 480484 },
+  { grid_y: 121120, count: 3800, grid_x: 480485 },
+  { grid_y: 121120, count: 7600, grid_x: 480486 },
+  { grid_y: 121120, count: 3800, grid_x: 480491 },
+  { grid_y: 121120, count: 3800, grid_x: 480497 },
+  { grid_y: 121120, count: 3800, grid_x: 480509 },
+  { grid_y: 121120, count: 3800, grid_x: 480515 },
+  { grid_y: 121120, count: 3800, grid_x: 480518 },
+  { grid_y: 121120, count: 3800, grid_x: 480526 },
+  { grid_y: 121121, count: 3800, grid_x: 480472 },
+  { grid_y: 121121, count: 3800, grid_x: 480473 },
+  { grid_y: 121121, count: 7600, grid_x: 480480 },
+  { grid_y: 121121, count: 3800, grid_x: 480481 },
+  { grid_y: 121121, count: 7600, grid_x: 480483 },
+  { grid_y: 121121, count: 7600, grid_x: 480484 },
+  { grid_y: 121121, count: 7600, grid_x: 480485 },
+  { grid_y: 121121, count: 7600, grid_x: 480486 },
+  { grid_y: 121121, count: 3800, grid_x: 480495 },
+  { grid_y: 121122, count: 3800, grid_x: 480474 },
+  { grid_y: 121122, count: 3800, grid_x: 480479 },
+  { grid_y: 121122, count: 3800, grid_x: 480481 },
+  { grid_y: 121122, count: 3800, grid_x: 480483 },
+  { grid_y: 121122, count: 7600, grid_x: 480484 },
+  { grid_y: 121122, count: 3800, grid_x: 480485 },
+  { grid_y: 121122, count: 7600, grid_x: 480491 },
+  { grid_y: 121122, count: 7600, grid_x: 480492 },
+  { grid_y: 121122, count: 7600, grid_x: 480493 },
+  { grid_y: 121122, count: 3800, grid_x: 480494 },
+  { grid_y: 121122, count: 7600, grid_x: 480495 },
+  { grid_y: 121122, count: 3800, grid_x: 480510 },
+  { grid_y: 121122, count: 3800, grid_x: 480517 },
+  { grid_y: 121123, count: 7600, grid_x: 480469 },
+  { grid_y: 121123, count: 7600, grid_x: 480477 },
+  { grid_y: 121123, count: 3800, grid_x: 480478 },
+  { grid_y: 121123, count: 3800, grid_x: 480479 },
+  { grid_y: 121123, count: 11400, grid_x: 480481 },
+  { grid_y: 121123, count: 7600, grid_x: 480482 },
+  { grid_y: 121123, count: 7600, grid_x: 480484 },
+  { grid_y: 121123, count: 7600, grid_x: 480485 },
+  { grid_y: 121123, count: 3800, grid_x: 480486 },
+  { grid_y: 121123, count: 3800, grid_x: 480491 },
+  { grid_y: 121123, count: 3800, grid_x: 480492 },
+  { grid_y: 121123, count: 3800, grid_x: 480493 },
+  { grid_y: 121123, count: 7600, grid_x: 480495 },
+  { grid_y: 121123, count: 3800, grid_x: 480509 },
+  { grid_y: 121123, count: 3800, grid_x: 480517 },
+  { grid_y: 121123, count: 7600, grid_x: 480518 },
+  { grid_y: 121124, count: 3800, grid_x: 480469 },
+  { grid_y: 121124, count: 3800, grid_x: 480474 },
+  { grid_y: 121124, count: 3800, grid_x: 480476 },
+  { grid_y: 121124, count: 3800, grid_x: 480478 },
+  { grid_y: 121124, count: 3800, grid_x: 480480 },
+  { grid_y: 121124, count: 3800, grid_x: 480481 },
+  { grid_y: 121124, count: 3800, grid_x: 480483 },
+  { grid_y: 121124, count: 3800, grid_x: 480485 },
+  { grid_y: 121124, count: 3800, grid_x: 480487 },
+  { grid_y: 121124, count: 3800, grid_x: 480493 },
+  { grid_y: 121124, count: 3800, grid_x: 480505 },
+  { grid_y: 121124, count: 3800, grid_x: 480530 },
+  { grid_y: 121125, count: 3800, grid_x: 480466 },
+  { grid_y: 121125, count: 3800, grid_x: 480472 },
+  { grid_y: 121125, count: 3800, grid_x: 480477 },
+  { grid_y: 121125, count: 3800, grid_x: 480478 },
+  { grid_y: 121125, count: 7600, grid_x: 480479 },
+  { grid_y: 121125, count: 3800, grid_x: 480480 },
+  { grid_y: 121125, count: 3800, grid_x: 480483 },
+  { grid_y: 121125, count: 3800, grid_x: 480484 },
+  { grid_y: 121125, count: 7600, grid_x: 480488 },
+  { grid_y: 121125, count: 3800, grid_x: 480496 },
+  { grid_y: 121125, count: 3800, grid_x: 480497 },
+  { grid_y: 121125, count: 3800, grid_x: 480509 },
+  { grid_y: 121126, count: 3800, grid_x: 480459 },
+  { grid_y: 121126, count: 3800, grid_x: 480469 },
+  { grid_y: 121126, count: 7600, grid_x: 480470 },
+  { grid_y: 121126, count: 7600, grid_x: 480472 },
+  { grid_y: 121126, count: 3800, grid_x: 480474 },
+  { grid_y: 121126, count: 7600, grid_x: 480478 },
+  { grid_y: 121126, count: 3800, grid_x: 480479 },
+  { grid_y: 121126, count: 15200, grid_x: 480480 },
+  { grid_y: 121126, count: 15200, grid_x: 480483 },
+  { grid_y: 121126, count: 7600, grid_x: 480485 },
+  { grid_y: 121126, count: 3800, grid_x: 480486 },
+  { grid_y: 121126, count: 3800, grid_x: 480489 },
+  { grid_y: 121126, count: 3800, grid_x: 480517 },
+  { grid_y: 121126, count: 3800, grid_x: 480529 },
+  { grid_y: 121127, count: 3800, grid_x: 480460 },
+  { grid_y: 121127, count: 7600, grid_x: 480465 },
+  { grid_y: 121127, count: 3800, grid_x: 480468 },
+  { grid_y: 121127, count: 3800, grid_x: 480470 },
+  { grid_y: 121127, count: 11400, grid_x: 480472 },
+  { grid_y: 121127, count: 7600, grid_x: 480473 },
+  { grid_y: 121127, count: 3800, grid_x: 480477 },
+  { grid_y: 121127, count: 3800, grid_x: 480478 },
+  { grid_y: 121127, count: 15200, grid_x: 480479 },
+  { grid_y: 121127, count: 11400, grid_x: 480480 },
+  { grid_y: 121127, count: 3800, grid_x: 480482 },
+  { grid_y: 121127, count: 38000, grid_x: 480483 },
+  { grid_y: 121127, count: 3800, grid_x: 480484 },
+  { grid_y: 121127, count: 3800, grid_x: 480486 },
+  { grid_y: 121127, count: 3800, grid_x: 480487 },
+  { grid_y: 121127, count: 3800, grid_x: 480488 },
+  { grid_y: 121127, count: 3800, grid_x: 480493 },
+  { grid_y: 121127, count: 3800, grid_x: 480496 },
+  { grid_y: 121127, count: 3800, grid_x: 480515 },
+  { grid_y: 121127, count: 3800, grid_x: 480517 },
+  { grid_y: 121127, count: 3800, grid_x: 480519 },
+  { grid_y: 121127, count: 3800, grid_x: 480522 },
+  { grid_y: 121128, count: 3800, grid_x: 480459 },
+  { grid_y: 121128, count: 3800, grid_x: 480463 },
+  { grid_y: 121128, count: 3800, grid_x: 480465 },
+  { grid_y: 121128, count: 3800, grid_x: 480467 },
+  { grid_y: 121128, count: 3800, grid_x: 480469 },
+  { grid_y: 121128, count: 11400, grid_x: 480470 },
+  { grid_y: 121128, count: 3800, grid_x: 480471 },
+  { grid_y: 121128, count: 3800, grid_x: 480472 },
+  { grid_y: 121128, count: 3800, grid_x: 480473 },
+  { grid_y: 121128, count: 3800, grid_x: 480474 },
+  { grid_y: 121128, count: 7600, grid_x: 480475 },
+  { grid_y: 121128, count: 3800, grid_x: 480476 },
+  { grid_y: 121128, count: 3800, grid_x: 480483 },
+  { grid_y: 121128, count: 7600, grid_x: 480484 },
+  { grid_y: 121128, count: 11400, grid_x: 480486 },
+  { grid_y: 121128, count: 11400, grid_x: 480487 },
+  { grid_y: 121128, count: 3800, grid_x: 480488 },
+  { grid_y: 121128, count: 3800, grid_x: 480490 },
+  { grid_y: 121128, count: 3800, grid_x: 480495 },
+  { grid_y: 121128, count: 11400, grid_x: 480496 },
+  { grid_y: 121128, count: 7600, grid_x: 480498 },
+  { grid_y: 121128, count: 7600, grid_x: 480499 },
+  { grid_y: 121128, count: 3800, grid_x: 480507 },
+  { grid_y: 121128, count: 3800, grid_x: 480509 },
+  { grid_y: 121128, count: 3800, grid_x: 480515 },
+  { grid_y: 121128, count: 3800, grid_x: 480517 },
+  { grid_y: 121128, count: 3800, grid_x: 480523 },
+  { grid_y: 121128, count: 3800, grid_x: 480531 },
+  { grid_y: 121129, count: 3800, grid_x: 480467 },
+  { grid_y: 121129, count: 3800, grid_x: 480468 },
+  { grid_y: 121129, count: 7600, grid_x: 480469 },
+  { grid_y: 121129, count: 3800, grid_x: 480470 },
+  { grid_y: 121129, count: 7600, grid_x: 480471 },
+  { grid_y: 121129, count: 30400, grid_x: 480472 },
+  { grid_y: 121129, count: 7600, grid_x: 480473 },
+  { grid_y: 121129, count: 3800, grid_x: 480479 },
+  { grid_y: 121129, count: 7600, grid_x: 480480 },
+  { grid_y: 121129, count: 7600, grid_x: 480481 },
+  { grid_y: 121129, count: 3800, grid_x: 480482 },
+  { grid_y: 121129, count: 3800, grid_x: 480483 },
+  { grid_y: 121129, count: 3800, grid_x: 480486 },
+  { grid_y: 121129, count: 3800, grid_x: 480487 },
+  { grid_y: 121129, count: 3800, grid_x: 480490 },
+  { grid_y: 121129, count: 3800, grid_x: 480492 },
+  { grid_y: 121129, count: 3800, grid_x: 480493 },
+  { grid_y: 121129, count: 3800, grid_x: 480494 },
+  { grid_y: 121129, count: 3800, grid_x: 480498 },
+  { grid_y: 121129, count: 7600, grid_x: 480500 },
+  { grid_y: 121129, count: 3800, grid_x: 480502 },
+  { grid_y: 121129, count: 7600, grid_x: 480511 },
+  { grid_y: 121129, count: 7600, grid_x: 480514 },
+  { grid_y: 121129, count: 7600, grid_x: 480518 },
+  { grid_y: 121130, count: 3800, grid_x: 480468 },
+  { grid_y: 121130, count: 7600, grid_x: 480470 },
+  { grid_y: 121130, count: 7600, grid_x: 480471 },
+  { grid_y: 121130, count: 7600, grid_x: 480472 },
+  { grid_y: 121130, count: 3800, grid_x: 480476 },
+  { grid_y: 121130, count: 3800, grid_x: 480477 },
+  { grid_y: 121130, count: 7600, grid_x: 480481 },
+  { grid_y: 121130, count: 3800, grid_x: 480482 },
+  { grid_y: 121130, count: 3800, grid_x: 480485 },
+  { grid_y: 121130, count: 3800, grid_x: 480492 },
+  { grid_y: 121130, count: 7600, grid_x: 480494 },
+  { grid_y: 121130, count: 3800, grid_x: 480497 },
+  { grid_y: 121130, count: 3800, grid_x: 480498 },
+  { grid_y: 121130, count: 3800, grid_x: 480500 },
+  { grid_y: 121130, count: 3800, grid_x: 480503 },
+  { grid_y: 121130, count: 3800, grid_x: 480506 },
+  { grid_y: 121130, count: 7600, grid_x: 480507 },
+  { grid_y: 121130, count: 3800, grid_x: 480509 },
+  { grid_y: 121130, count: 7600, grid_x: 480510 },
+  { grid_y: 121130, count: 3800, grid_x: 480511 },
+  { grid_y: 121130, count: 7600, grid_x: 480514 },
+  { grid_y: 121130, count: 3800, grid_x: 480527 },
+  { grid_y: 121130, count: 3800, grid_x: 480530 },
+  { grid_y: 121131, count: 3800, grid_x: 480459 },
+  { grid_y: 121131, count: 3800, grid_x: 480468 },
+  { grid_y: 121131, count: 3800, grid_x: 480471 },
+  { grid_y: 121131, count: 3800, grid_x: 480478 },
+  { grid_y: 121131, count: 3800, grid_x: 480485 },
+  { grid_y: 121131, count: 3800, grid_x: 480486 },
+  { grid_y: 121131, count: 3800, grid_x: 480489 },
+  { grid_y: 121131, count: 3800, grid_x: 480490 },
+  { grid_y: 121131, count: 7600, grid_x: 480499 },
+  { grid_y: 121131, count: 3800, grid_x: 480507 },
+  { grid_y: 121131, count: 3800, grid_x: 480508 },
+  { grid_y: 121131, count: 3800, grid_x: 480509 },
+  { grid_y: 121131, count: 19000, grid_x: 480515 },
+  { grid_y: 121131, count: 7600, grid_x: 480516 },
+  { grid_y: 121131, count: 7600, grid_x: 480517 },
+  { grid_y: 121131, count: 3800, grid_x: 480526 },
+  { grid_y: 121131, count: 3800, grid_x: 480529 },
+  { grid_y: 121131, count: 3800, grid_x: 480533 },
+  { grid_y: 121132, count: 7600, grid_x: 480469 },
+  { grid_y: 121132, count: 3800, grid_x: 480470 },
+  { grid_y: 121132, count: 3800, grid_x: 480472 },
+  { grid_y: 121132, count: 3800, grid_x: 480474 },
+  { grid_y: 121132, count: 3800, grid_x: 480479 },
+  { grid_y: 121132, count: 3800, grid_x: 480480 },
+  { grid_y: 121132, count: 3800, grid_x: 480489 },
+  { grid_y: 121132, count: 3800, grid_x: 480495 },
+  { grid_y: 121132, count: 3800, grid_x: 480497 },
+  { grid_y: 121132, count: 3800, grid_x: 480499 },
+  { grid_y: 121132, count: 3800, grid_x: 480503 },
+  { grid_y: 121132, count: 3800, grid_x: 480508 },
+  { grid_y: 121132, count: 3800, grid_x: 480519 },
+  { grid_y: 121133, count: 3800, grid_x: 480464 },
+  { grid_y: 121133, count: 3800, grid_x: 480466 },
+  { grid_y: 121133, count: 3800, grid_x: 480477 },
+  { grid_y: 121133, count: 3800, grid_x: 480478 },
+  { grid_y: 121133, count: 3800, grid_x: 480482 },
+  { grid_y: 121133, count: 3800, grid_x: 480490 },
+  { grid_y: 121133, count: 3800, grid_x: 480491 },
+  { grid_y: 121133, count: 7600, grid_x: 480497 },
+  { grid_y: 121133, count: 3800, grid_x: 480498 },
+  { grid_y: 121133, count: 3800, grid_x: 480499 },
+  { grid_y: 121133, count: 3800, grid_x: 480502 },
+  { grid_y: 121133, count: 3800, grid_x: 480516 },
+  { grid_y: 121133, count: 3800, grid_x: 480519 },
+  { grid_y: 121133, count: 3800, grid_x: 480520 },
+  { grid_y: 121134, count: 3800, grid_x: 480468 },
+  { grid_y: 121134, count: 7600, grid_x: 480477 },
+  { grid_y: 121134, count: 3800, grid_x: 480481 },
+  { grid_y: 121134, count: 7600, grid_x: 480482 },
+  { grid_y: 121134, count: 3800, grid_x: 480484 },
+  { grid_y: 121134, count: 3800, grid_x: 480485 },
+  { grid_y: 121134, count: 3800, grid_x: 480493 },
+  { grid_y: 121134, count: 3800, grid_x: 480501 },
+  { grid_y: 121134, count: 3800, grid_x: 480508 },
+  { grid_y: 121134, count: 3800, grid_x: 480514 },
+  { grid_y: 121134, count: 3800, grid_x: 480516 },
+  { grid_y: 121134, count: 3800, grid_x: 480519 },
+  { grid_y: 121134, count: 3800, grid_x: 480520 },
+  { grid_y: 121134, count: 3800, grid_x: 480526 },
+  { grid_y: 121134, count: 3800, grid_x: 480527 },
+  { grid_y: 121135, count: 3800, grid_x: 480460 },
+  { grid_y: 121135, count: 3800, grid_x: 480477 },
+  { grid_y: 121135, count: 3800, grid_x: 480481 },
+  { grid_y: 121135, count: 7600, grid_x: 480482 },
+  { grid_y: 121135, count: 11400, grid_x: 480483 },
+  { grid_y: 121135, count: 7600, grid_x: 480484 },
+  { grid_y: 121135, count: 3800, grid_x: 480486 },
+  { grid_y: 121135, count: 3800, grid_x: 480489 },
+  { grid_y: 121135, count: 3800, grid_x: 480493 },
+  { grid_y: 121135, count: 3800, grid_x: 480503 },
+  { grid_y: 121135, count: 3800, grid_x: 480510 },
+  { grid_y: 121135, count: 3800, grid_x: 480529 },
+  { grid_y: 121135, count: 3800, grid_x: 480533 }
+];
diff --git a/test/unit/source/transfrom/hexagon.js b/test/unit/source/transfrom/hexagon.js
new file mode 100644
index 0000000000..b0877e7b80
--- /dev/null
+++ b/test/unit/source/transfrom/hexagon.js
@@ -0,0 +1,21 @@
+import { expect } from 'chai';
+import { pointData } from '../../../asset/data/point';
+import { pointToHexbin } from '../../../../src/source/transform/hexagon';
+describe('hexagon  Test', function() {
+
+  it('pointToHexbin', function() {
+    const dataArray = pointData.map(item => {
+      const lng = 1e-6 * (250 * item.grid_x + 125),
+        lat = 1e-6 * (250 * item.grid_y + 125);
+      return {
+        v: item.count * 1,
+        coordinates: [ lng, lat ]
+      };
+    });
+
+    const data = {
+      dataArray
+    };
+    const hexgonGrid = pointToHexbin(data, { size: 100, field: 'count', method: 'sum' });
+  });
+});

From 3360189416023c13a2ca40f846b932c6efc5524b Mon Sep 17 00:00:00 2001
From: thinkinggis <lzx199065@gmail.com>
Date: Tue, 26 Feb 2019 16:40:15 +0800
Subject: [PATCH 9/9] fix(pick): event

---
 src/core/engine/picking/picking.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/core/engine/picking/picking.js b/src/core/engine/picking/picking.js
index e4fb4c2ee1..24790e82a1 100755
--- a/src/core/engine/picking/picking.js
+++ b/src/core/engine/picking/picking.js
@@ -42,7 +42,7 @@ class Picking {
     // this._world._container.addEventListener('mousemove', this._onWorldMove.bind(this), false);
   }
   pickdata(event) {
-    const point = { x: event.clientX, y: event.clientY, type: event.type };
+    const point = { x: event.offsetX, y: event.offsetY, type: event.type };
     const normalisedPoint = { x: 0, y: 0 };
     normalisedPoint.x = (point.x / this._width) * 2 - 1;
     normalisedPoint.y = -(point.y / this._height) * 2 + 1;