//--------------------------------------------------------------------
// 緯度経度計算オブジェクト(?)
//--------------------------------------------------------------------
//                                               http://www.oas.co.jp/
function objUTM()
{
  // public method
  this.conv         = oUTM_cnvStr;
  this.getDeg       = oUTM_cnvDeg;
  this.setDeg       = oUTM_setDeg;
  this.calcDegToUTM = oUTM_calcUTM;
  this.setUTM       = oUTM_setUTM;
  this.calcUTMToDeg = oUTM_calcDeg;
  
  // public property
  this.x = 0;
  this.y = 0;
  this.ido = 0;
  this.kdo = 0;
  this.kei = 1;
  this.sido = '';
  this.skdo = '';
  
  // private property
  this.ar_bo = new Array(   33,  33,      36,    33,      36,  36,      36,    36,      36,      40,     44,     44,     44,  26,    26,  26,  26,  20,  26);
  this.ar_lo = new Array(129.5, 131, 132+1/6, 133.5, 134+1/3, 136, 137+1/6, 138.5, 139+5/6, 140+5/6, 140.25, 142.25, 144.25, 142, 127.5, 124, 131, 136, 154);
  this.ar_len = this.ar_bo.length;
  
  // private method
  this.ll2xy = oUTM_ll2xy;
  this.xy2ll = oUTM_xy2ll;
  this.lom   = oUTM_lom;
  this.fai1  = oUTM_fai1;
  
  // private const
  this.a = 6377397.155;
  this.f = 1 / 299.152813;
  this.e2 = 2*this.f - this.f * this.f;
  this.rd = Math.PI / 180;
}
function oUTM_cnvStr(str,delim)
{
  var dlm = (delim)? delim: '/';
  var ars = str.split( dlm );
  var r = parseFloat( ars[0] );
  if (ars.length > 0)
  {
    r += parseFloat( ars[1] ) / 60;
    if (ars.length > 1)
    {
      r += parseFloat( ars[2] ) / 3600;
    }
  }
  return r;
}
function oUTM_cnvDeg(val,delim)
{
  var dlm = (delim)? delim: '/';
  var v = parseFloat( val );
  if (isNaN(v))
  {
    return '';
  }
  
  var sgn = (v >= 0)? 1: -1;
  v *= sgn;
  var d = Math.floor( v );
  v -= d;
  v *= 60;
  var m = Math.floor( v );
  v -= m;
  v *= 60;
  var s = Math.floor( v*1000 );
  s /= 1000;
  
  var r = '' + ((sgn>0)? '':'-') + d + dlm + m + dlm + s;
  return r;
}
function oUTM_setDeg(valIDO, valKDO, valKEI)
{
  this.ido = valIDO;
  this.kdo = valKDO;
  if (valKEI>=1 && 19>=valKEI)
  {
    this.kei = valKEI;
  }
  else
  {
    var i=0;
    var db, dl, d2;
    var d2min = 1000;
    for(var j=0; j<this.ar_len; ++j)
    {
      db = this.ido - this.ar_bo[j];
      dl = this.kdo - this.ar_lo[j];
      d2 = db*db + dl*dl;
      if(d2 < d2min) {d2min = d2; i = j + 1;}
    }
    this.kei = i;
  }
}
function oUTM_calcUTM()
{
  // 入力データ取得
  var b = this.ido;
  var l = this.kdo;
  var i = this.kei;
  
  pvec = this.ll2xy(b*this.rd, (l-this.ar_lo[i-1])*this.rd);
  pvec[0] -= this.lom(this.ar_bo[i-1]*this.rd);
  pvec[0] *= 0.9999;
  pvec[1] *= 0.9999;
  this.x = Math.round(pvec[0]*1000) / 1000;
  this.y = Math.round(pvec[1]*1000) / 1000;
}
function oUTM_setUTM(valX, valY, valKei)
{
  this.x = valX;
  this.y = valY;
  this.kei = valKei;
}
function oUTM_calcDeg()
{
  // 入力データ取得
  var x = this.x;
  var y = this.y;
  var k = this.kei;
  if (k<1 || this.ar_len<=k) {k=1;}
  
  pvec = this.xy2ll(x, y, k);
  this.ido = pvec[0];
  this.kdo = pvec[1];
  this.sido = this.getDeg( this.ido );
  this.skdo = this.getDeg( this.kdo );
}
function oUTM_xy2ll(x, y, kei)
{
  var org_kdo = this.ar_lo[kei-1] * this.rd;  // 系原点のラジアン
  var fai1 = this.fai1( kei, x );  // 基準子午線と垂線（新点より）との交点の緯度
  var m0 = 0.9999;   // 座標系の原点における縮尺係数
  var ed2 = this.e2 / (1 - this.e2);  // 第2離心率
  var eta2 = ed2*Math.cos(fai1)*Math.cos(fai1);
  var c = this.a * Math.sqrt(1 + ed2);
  var lm1 = c / Math.sqrt( Math.pow( (1+eta2), 3 ));
  var ln1 = c / Math.sqrt(1+eta2);
  var tanfai1 = Math.tan(fai1);
  var ym0 = y/m0;
  
  // 緯度(ido)
  var ido = fai1-(tanfai1/(2*lm1*ln1))*Math.pow(ym0,2)
          + (tanfai1/(24*lm1*Math.pow(ln1,3)))*(5+3*tanfai1*tanfai1+eta2-9*Math.pow((eta2*tanfai1),2)-4*eta2*eta2)*Math.pow(ym0,4)
          - (tanfai1/(720*lm1*Math.pow(ln1,5)))*(61+90*tanfai1*tanfai1+45*Math.pow(tanfai1,4))*Math.pow(ym0,6);
  
  // 経度(kdo)
  var d_kdo = (1/(ln1*Math.cos(fai1)))*ym0
           - ((1+2*tanfai1*tanfai1+eta2)/(6*Math.pow(ln1,3)*Math.cos(fai1)))*Math.pow(ym0,3)
           + ((5+28*tanfai1*tanfai1+24*Math.pow(tanfai1,4))/(120*Math.pow(ln1,5)*Math.cos(fai1)))*Math.pow(ym0,5);
  var  kdo = org_kdo + d_kdo;
  
  return new Array( ido/this.rd, kdo/this.rd );
}
function oUTM_ll2xy(b, dl)
{
  var a = this.a;
  var f = this.f;
  var e2= this.e2;

  var dl2 = dl * dl;
  var dl4 = dl2 * dl2;
  
  var sb = Math.sin(b);
  var cb = Math.cos(b);
  var cb3 = cb * cb * cb;
  var cb5 = cb3 * cb * cb;
  var tb2 = sb * sb / cb / cb;
  var tb4 = tb2 * tb2;
  
  var ed2 = e2 / (1-e2);  // 第2離心率
  var eta2 = ed2 * cb * cb;
  var rn = a / (1-f) / Math.sqrt(1+eta2); // 卯酉線曲率半径
  
  var x = this.lom(b);
  x += rn/2*sb*cb*dl2;
  x += rn/24*sb*cb3*(5-tb2+9*eta2+4*eta2*eta2)*dl4;
  x += rn/720*sb*cb5*(61-58*tb2+tb4)*dl4*dl2;
  
  var y = rn*cb*dl;
  y += rn/6*cb3*(1-tb2+eta2)*dl*dl2;
  y += rn/120*cb5*(5-18*tb2+tb4)*dl*dl4;
  return new Array (x, y);
}
// 赤道から座標系原点(b)までの子午線弧長(Ｓ0)
function oUTM_lom(b)
{
  var a = this.a;
  var e2= this.e2;
  
  var cad = 1.005037306045518;
  var cbd = 0.005047849237799;
  var ccd = 0.000010563786819;
  var cdd = 0.000000020633321;
  var ced = 0.000000000038853;
  var cfd = 0.000000000000070;
  
  var cds = cad*b - cbd/2*Math.sin(2*b) + ccd/4*Math.sin(4*b)
          - cdd/6*Math.sin(6*b) + ced/8*Math.sin(8*b)-cfd/10*Math.sin(b);
  var s0 = a * (1 - e2) * cds;
  
  return s0;
}
// 基準子午線と垂線（新点より）との交点の緯度
function oUTM_fai1(kei,x)
{
  var m0 = 0.9999;  // 縮尺係数
  var s0 = this.lom( this.ar_bo[kei-1] * this.rd );
  var t = (s0 + x/m0) / this.a;
  
  var a1  =  1.00167348290;
  var a2  =  0.00251126928;
  var a3  =  0.00000367878;
  var a4  =  0.00000840515;
  var a5  =  0.00000001134;
  var a6  =  0.00000002462;
  var a7  = -0.00000001407;
  var a8  = -0.00000000792;
  var a9  =  0.00000000001;
  var a10 =  0.00000000007;
  var a11 = -0.00000000005;
  var a12 = -0.00000000008;
  var a13 = -0.00000000002;
  var a14 =  0.00000000002;
  
  // 基準子午線と垂線（新点より）との交点の緯度
  var fai1 = a1*t + a2*Math.sin(2*t) + a3*Math.sin(4*t) + a4*t*Math.cos(2*t)
         + a5*Math.sin(6*t) + a6*t*Math.cos(4*t) + a7*t*t*Math.sin(2*t)
         + a8*Math.sin(2*t)*Math.cos(4*t) + a9*Math.sin(8*t) + a10*t*Math.cos(6*t)
         + a11*t*Math.sin(2*t)*Math.sin(4*t) + a12*t*t*Math.sin(4*t)
         + a13*Math.pow(t,3)*Math.cos(2*t) + a14*Math.sin(6*t)*Math.cos(2*t);
  
  return fai1;
}
