ingress-intel-total-conversion/plugins/fix-googlemap-china-offset.user.js

203 lines
6.7 KiB
JavaScript

// ==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://*.ingress.com/intel*
// @include http://*.ingress.com/intel*
// @match https://*.ingress.com/intel*
// @match http://*.ingress.com/intel*
// @include https://*.ingress.com/mission/*
// @include http://*.ingress.com/mission/*
// @match https://*.ingress.com/mission/*
// @match http://*.ingress.com/mission/*
// @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@@