From 06b2e422a2c4f1f3ec054aef01b0db8c15ed6c06 Mon Sep 17 00:00:00 2001 From: Breezewish Date: Fri, 7 Feb 2014 13:37:52 +0800 Subject: [PATCH] added fix-googlemap-china-offset plugin --- plugins/fix-googlemap-china-offset.user.js | 198 +++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 plugins/fix-googlemap-china-offset.user.js diff --git a/plugins/fix-googlemap-china-offset.user.js b/plugins/fix-googlemap-china-offset.user.js new file mode 100644 index 00000000..a25b271a --- /dev/null +++ b/plugins/fix-googlemap-china-offset.user.js @@ -0,0 +1,198 @@ +// ==UserScript== +// @id iitc-plugin-fix-googlemap-china-offset@breezewish +// @name IITC plugin: Fix Google Map offsets in China +// @category Tweaks +// @version 0.0.1.@@DATETIMEVERSION@@ +// @namespace https://github.com/jonatkins/ingress-intel-total-conversion +// @updateURL @@UPDATEURL@@ +// @downloadURL @@DOWNLOADURL@@ +// @description [@@BUILDNAME@@-@@BUILDDATE@@] Show correct Google Map for China user by applying offset tweaks. +// @include https://www.ingress.com/intel* +// @include http://www.ingress.com/intel* +// @match https://www.ingress.com/intel* +// @match http://www.ingress.com/intel* +// @grant none +// ==/UserScript== + +@@PLUGINSTART@@ + +// PLUGIN START //////////////////////////////////////////////////////// + +// use own namespace for plugin +window.plugin.fixChinaOffset = {}; + +// Before understanding how this plugin works, you should know 3 points: +// +// Point1. +// The coordinate system of Ingress is WGS-84. +// However, the tiles of Google maps (except satellite map) in China have +// offsets (base on GCJ-02 coordinate system) by China policy. +// That means, if you request map tiles by giving GCJ-02 position, you +// will get the correct map. +// +// Point2. +// Currently there are no easy algorithm to transform from GCJ-02 to WGS-84, +// but we can easily transform data from WGS-84 to GCJ-02. +// +// Point3. +// When using Google maps in IITC, the layer structure looks like this: +// ---------------------- +// | Other Leaflet layers | (Including portals, links, fields, and so on) +// ---------------------- +// | L.Google | (Only for controling) +// ---------------------- +// | Google Map layer | (Generated by Google Map APIs, for rendering maps) +// ---------------------- +// +// When users are interacting with L.Google (for example, dragging, zooming), +// L.Google will perform the same action on the Google Map layer using Google +// Map APIs. +// +// So, here is the internal of the plugin: +// +// The plugin overwrites behaviours of L.Google. When users are dragging the map, +// L.Google will pass offseted positions to Google Map APIs (WGS-84 to GCJ-02). +// So Google Map APIs will render a correct map. +// +// The offset between Google maps and Ingress objects can also be fixed by applying +// WGS-84 to GCJ-02 transformation on Ingress objects. However we cannot simply know +// the requesting bounds of Ingress objects because we cannot transform GCJ-02 to +// WGS-84. As a result, the Ingress objects on maps would be incomplete. +// +// The algorithm of transforming WGS-84 to GCJ-02 comes from: +// https://on4wp7.codeplex.com/SourceControl/changeset/view/21483#353936 +// There is no official algorithm because it is classified information. + +/////////// begin WGS84 to GCJ-02 transformer ///////// +var WGS84transformer = window.plugin.fixChinaOffset.WGS84transformer = function() {}; +// Krasovsky 1940 +// +// a = 6378245.0, 1/f = 298.3 +// b = a * (1 - f) +// ee = (a^2 - b^2) / a^2; +WGS84transformer.prototype.a = 6378245.0; +WGS84transformer.prototype.ee = 0.00669342162296594323; + +WGS84transformer.prototype.transform = function(wgLat, wgLng) { + + if(this.isOutOfChina(wgLat, wgLng)) + return {lat: wgLat, lng: wgLng}; + + dLat = this.transformLat(wgLng - 105.0, wgLat - 35.0); + dLng = this.transformLng(wgLng - 105.0, wgLat - 35.0); + radLat = wgLat / 180.0 * Math.PI; + magic = Math.sin(radLat); + magic = 1 - this.ee * magic * magic; + sqrtMagic = Math.sqrt(magic); + dLat = (dLat * 180.0) / ((this.a * (1 - this.ee)) / (magic * sqrtMagic) * Math.PI); + dLng = (dLng * 180.0) / (this.a / sqrtMagic * Math.cos(radLat) * Math.PI); + mgLat = wgLat + dLat; + mgLng = wgLng + dLng; + + return {lat: mgLat, lng: mgLng}; + +}; + +WGS84transformer.prototype.isOutOfChina = function(lat, lng) { + + if(lng < 72.004 || lng > 137.8347) return true; + if(lat < 0.8293 || lat > 55.8271) return true; + + return false; + +}; + +WGS84transformer.prototype.transformLat = function(x, y) { + + var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x)); + ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0; + ret += (20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin(y / 3.0 * Math.PI)) * 2.0 / 3.0; + ret += (160.0 * Math.sin(y / 12.0 * Math.PI) + 320 * Math.sin(y * Math.PI / 30.0)) * 2.0 / 3.0; + + return ret; + +}; + +WGS84transformer.prototype.transformLng = function(x, y) { + + var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x)); + ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0; + ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin(x / 3.0 * Math.PI)) * 2.0 / 3.0; + ret += (150.0 * Math.sin(x / 12.0 * Math.PI) + 300.0 * Math.sin(x / 30.0 * Math.PI)) * 2.0 / 3.0; + + return ret; + +}; +/////////// end WGS84 to GCJ-02 transformer ///////// + +var WGS84toGCJ02 = new WGS84transformer(); + +/////////// begin overwrited L.Google ///////// +window.plugin.fixChinaOffset.L = {}; +window.plugin.fixChinaOffset.L.Google = { + + _update: function(e) { + + if(!this._google) return; + this._resize(); + + var center = e && e.latlng ? e.latlng : this._map.getCenter(); + + ///// modified here /// + var _center = window.plugin.fixChinaOffset.getLatLng(center, this._type); + /////////////////////// + + this._google.setCenter(_center); + this._google.setZoom(this._map.getZoom()); + + this._checkZoomLevels(); + + }, + + _handleZoomAnim: function (e) { + + var center = e.center; + + ///// modified here /// + var _center = window.plugin.fixChinaOffset.getLatLng(center, this._type); + /////////////////////// + + this._google.setCenter(_center); + this._google.setZoom(e.zoom); + + } + +} +/////////// end overwrited L.Google ///////// + +window.plugin.fixChinaOffset.getLatLng = function(pos, type) { + + // No offsets in satellite and hybrid maps + if(type !== 'SATELLITE' && type !== 'HYBRID') { + var newPos = WGS84toGCJ02.transform(pos.lat, pos.lng); + return new google.maps.LatLng(newPos.lat, newPos.lng); + } else { + return new google.maps.LatLng(pos.lat, pos.lng); + } + +}; + +window.plugin.fixChinaOffset.overwrite = function(dest, src) { + + for(var key in src) { + if(src.hasOwnProperty(key)) { + dest[key] = src[key]; + } + } + +} + +var setup = function() { + + window.plugin.fixChinaOffset.overwrite(L.Google.prototype, window.plugin.fixChinaOffset.L.Google); + +} + +// PLUGIN END ////////////////////////////////////////////////////////// + +@@PLUGINEND@@