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;