// Content-type: text/javascript
// File-name: wgsgmap.js
// NAME: WPoint and WBounds for Google Maps API
// VERSION: 1.5 Aug. 10 2005
// SYNOPSYS:
//   var wpoint = new WPoint(WGS_x, WGS_y, map);
//   var wpoint = WPoint.fromGPoint(gpoint, map);
//   var gpoint = wpoint.gpoint();
//   map.centerLatLng((new WPoint(WGS_x, WGS_y, map)).gpoint());
//   var wpoint = WPoint.fromGPoint(map.getCenterLatLng(), map);
//   var wbounds = new WBounds(WGS_minX, WGS_minY, WGS_maxX, WGS_maxY, map);
//   var wbounds = WBounds.fromGBounds(gbounds, map);
//   var gbounds = wbounds.gbounds();
//   var wbounds = WBounds.fromGBounds(map.getBoundsLatLng(), map);
// DESCRIPTION:
//   From 12 Jul. 2005, Google Maps uses
//   the Geodetic System mixed World and Tokyo.
//   Later is available in the range of
//     east longitude between 115.0 to 152.0 degree
//     and north latitude between 30.0 to 50.0 degree.
//   Following snipets provides you using WGS84 for all area on the earth.
// OBSOLUTE:
//   Version 1.3 make Psudo Tokyo Datum on the sea.
//   Version 1.1 lost 3 columns at most east.
// LICENSE:
//   This is the free software under Berkeley Software Distribution License.
//   You can use, modify, and redistribute it without author's permissions.
// AUTHOR: MIZUTANI Tociyuki
// URL: http://tociyuki.cool.ne.jp/ (sorry japanese only)

function WPoint(a, b, c) {
  this.x = a; this.y = b; this.map = c;
}

WPoint.VERSION = '1.13';

WPoint.prototype.toString = function() {
  return '(' + this.x + ', ' + this.y + ')';
}

WPoint.prototype.gpoint = function() {
  var d = WPoint.delta(this.x, this.y, this.map);
  return new GPoint(this.x - d.x, this.y - d.y);
}

WPoint.fromGPoint = function(a, b) {
  return WPoint.fromGPointXY(a.x, a.y, b);
}

WPoint.fromGPointXY = function(a, b, c) {
  var r = WPoint.delta(a, b, c);
  r.x = a + r.x;
  r.y = b + r.y;
  return r;
}

// WGS = Tokyo + ( latitude(dy), longitude(dx) ) in second.
// The license of following data is as same as the web page
//   <http://vldb.gsi.go.jp/sokuchi/coordinates/localtrans.html>.
WPoint.tTokyo2WGS84 = [
[[0,0],[12.71,-8.17],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],
[[0,0],[12.53,-8.21],[12.57,-8.4],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],
[[0,0],[12.28,-8.25],[12.37,-8.55],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],
[[12,-8.15],[12.06,-8.38],[12.17,-8.69],[12.23,-8.99],[12.21,-9.21],[12.28,-9.6],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],
[[11.87,-8.23],[11.84,-8.44],[11.94,-8.71],[11.99,-9.02],[12.05,-9.36],[12.1,-9.64],[12.1,-10.08],[12.07,-10.25],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],
[[0,0],[11.65,-8.59],[11.68,-8.8],[11.73,-9.04],[11.72,-9.48],[11.81,-9.74],[11.88,-10.1],[11.91,-10.35],[11.9,-10.7],[12.02,-11.09],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],
[[0,0],[0,0],[0,0],[11.44,-9.21],[11.47,-9.52],[11.55,-9.8],[11.61,-10.12],[11.66,-10.47],[11.78,-10.79],[11.85,-11.13],[11.9,-11.47],[11.91,-11.69],[0,0],[0,0],[0,0],[0,0],[0,0]],
[[0,0],[0,0],[0,0],[11.27,-9.31],[11.33,-9.52],[11.38,-9.86],[11.41,-10.14],[11.39,-10.52],[11.49,-10.83],[11.58,-11.21],[11.65,-11.53],[11.72,-11.8],[0,0],[0,0],[0,0],[0,0],[0,0]],
[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[11.11,-10.59],[11.16,-10.97],[11.29,-11.23],[11.36,-11.59],[11.44,-11.88],[0,0],[0,0],[0,0],[0,0],[0,0]],
[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[10.83,-10.77],[10.95,-11],[10.97,-11.34],[11.04,-11.69],[11.17,-12.05],[0,0],[0,0],[0,0],[0,0],[0,0]],
[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[10.67,-10.86],[10.68,-10.97],[10.8,-11.53],[10.8,-11.73],[10.92,-12.16],[11,-12.25],[0,0],[0,0],[0,0],[0,0]],
[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[10.54,-11.96],[10.65,-12.27],[10.67,-12.5],[0,0],[0,0],[0,0],[0,0]],
[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[10.29,-12.13],[10.33,-12.27],[10.45,-12.61],[0,0],[0,0],[0,0],[0,0]],
[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[9.91,-12.21],[10.08,-12.35],[10.19,-12.74],[0,0],[0,0],[0,0],[0,0]],
[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[9.81,-12.29],[9.81,-12.45],[9.92,-12.79],[0,0],[0,0],[0,0],[0,0]],
[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[9.55,-12.63],[9.62,-12.62],[0,0],[0,0],[0,0],[0,0]],
[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[9.25,-12.72],[9.39,-12.91],[0,0],[0,0],[0,0],[0,0]],
[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[8.9,-12.68],[8.99,-12.8],[9,-13.07],[9.21,-13.51],[9.33,-13.66],[0,0],[0,0]],
[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[8.79,-13],[8.84,-13.31],[8.98,-13.59],[9.1,-13.91],[9.17,-14.27],[9.23,-14.52]],
[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[8.63,-13.49],[8.71,-13.73],[8.84,-14.03],[8.98,-14.33],[9.1,-14.56]],
[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[8.37,-13.65],[8.44,-13.87],[8.61,-14.06],[8.73,-14.3],[0,0]],
[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[8.1,-13.81],[8.15,-13.95],[0,0],[0,0],[0,0]],
[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[7.92,-13.88],[7.94,-13.97],[0,0],[0,0],[0,0]],
];

WPoint.delta = function(a, b, c) {
  var v;
  var dx = 0, dy = 0;
  if (_SATELLITE_TYPE.japanDatumHack) {
    if (a > 115 && a < 152 && b > 30 && b < 50) {
      var m = b * 60;
      if (1840 <= m && m <= 2800 && 129 <= a && a <= 146) {
        var j = Math.floor((m - 1840)/40);
        var i = Math.floor(a - 129);
        v = WPoint.tTokyo2WGS84[j][i];
        dx = v[1]/3600;
        dy = v[0]/3600;
      }
      if ( dx == 0 || dy == 0 ) {
        dx = -0.0032027777777777775;
        dy = +0.003236111111111111;
      }
    } else if ( a > 123 && a < 144 && b > 24 && b < 30 ) {
      if ( c && c.getCurrentMapType() == G_MAP_TYPE ) {
        v = WPoint.molodensky(a, b, WPoint.eTokyo, WPoint.eWGS84);
        dx = v[1];
        dy = v[0];
      }
    }
  }
  return new WPoint(dx, dy, c);
}

WPoint.adjust_okinawa = function(a, b, c) {
  if ( b == G_MAP_TYPE || c == G_MAP_TYPE ) {
    var p = a.getCenterLatLng();
    if ( p.x > 123 && p.x < 144 && p.y > 24 && p.y < 30 ) {
      var v = WPoint.molodensky(p.x, p.y, WPoint.eTokyo, WPoint.eWGS84);
      if ( c == G_MAP_TYPE ) {
        v[0] = -v[0];
        v[1] = -v[1];
      }
      a.centerAtLatLng(new GPoint(p.x+v[1], p.y+v[0]));
    }
  }
}

WPoint.eTokyo = [6377397.155, 1 / 299.152813, 148, -507, -681];
WPoint.eWGS84 = [6378137, 1 / 298.257223, 0, 0, 0];

// Original code from
// http://homepage3.nifty.com/Nowral/02_DATUM/Molodensky.html
// by Nowral
WPoint.molodensky = function(x, y, src, dst) {
  var a = src[0];
  var f = src[1];
  var a1 = dst[0];
  var f1 = dst[1];
  var dx = dst[2] - src[2];
  var dy = dst[3] - src[3];
  var dz = dst[4] - src[4];
  
  var rad = Math.PI/180;
  
  var b = y * rad;
  var l = x * rad;

  var e2 = 2 * f - f * f;
  var bda = 1 - f;
  var da = a1 - a;
  var df = f1 - f;
  var sb = Math.sin(b);
  var cb = Math.cos(b);
  var sl = Math.sin(l);
  var cl = Math.cos(l);

  var rn = 1 / Math.sqrt(1 - e2 * sb * sb); 
  var rm = a * (1 - e2) * rn * rn * rn;
  rn *= a;

  var db = -dx * sb * cl - dy * sb * sl + dz * cb
    + da * rn * e2 * sb * cb / a + (rm / bda + rn * bda) * df * sb * cb;
  var dl = - dx * sl + dy * cl;
  db = db / rm / rad;
  dl = dl / rn / cb / rad;

  return [db, dl];
}

function WBounds(a,b,c,d,e) {
  this.minX = a; this.minY = b; this.maxX = c; this.maxY = d; this.map = e;
}

WBounds.VERSION = '1.1';

WBounds.prototype.toString = function() {
  return 'Bounds(' + this.minX + ',' + this.minY + ',' + this.maxX + ',' + this.maxY + ')';
}

WBounds.prototype.gbounds = function() {
  var minR = (new WPoint(this.minX, this.minY, this.map)).gpoint();
  var maxR = (new WPoint(this.maxX, this.maxX, this.map)).gpoint();
  return new GBounds(minR.x, minR.y, maxR.x, maxR.y);
}

WBounds.fromGBounds = function(a, b) {
  var minR = WPoint.fromGPointXY(a.minX, a.minY, b);
  var maxR = WPoint.fromGPointXY(a.maxX, a.maxY, b);
  return new WBounds(minR.x, minR.y, maxR.x, maxR.y, b);
}
