/* Copyright (C) 2006 ALPS Mapping K.K. */
function SProjection(projCode, origin, factor) {this.m_projCode = projCode; this.origin = new LLPoint(origin.lat, origin.lon); this.factor = factor; };SProjection.prototype.release=function(){this.origin.release();this._release();};function EllipsoID(form) {this.form = form; if (form == 0) { this.a = 6370300.0;this.b = 6370300.0;this.e2 = 0.0;} else { this.a = 6377397.155;this.b = 6356078.96325;this.e2 = (this.a*this.a - this.b*this.b) / (this.a*this.a);}};function MercatorConversion(origin, form) {this.proj = new SProjection(1, origin, 1.0); this.ellipsoid = new EllipsoID(form); };MercatorConversion.prototype.QPI = Math.atan(1); MercatorConversion.prototype.EPS = 2.2204460492503131e-016; MercatorConversion.prototype.MAX = Number.MAX_VALUE; MercatorConversion.prototype.set = function(origin, form) {this.proj = new SProjection(1, origin, 1.0); this.ellipsoid = new EllipsoID(form); };MercatorConversion.prototype.getLLPoint = function(meterPoint) {var x = meterPoint.x;var y = meterPoint.y;var raOriginPhi = this.proj.origin.lat * Math.PI / 180;var raOriginLamda = this.proj.origin.lon * Math.PI / 180;var raLamda = 0;var raPhi = 0;var e, esin0, Radius0, Xm, XM, Y, delta;var a = this.ellipsoid.a;var b = this.ellipsoid.b;var e2 = this.ellipsoid.e2;e = Math.sqrt(e2); esin0 = e * Math.sin(raOriginPhi);Radius0 = a * Math.cos(raOriginPhi) / Math.sqrt(1 - e2*Math.sin(raOriginPhi)*Math.sin(raOriginPhi));Xm = -Radius0*(4*this.QPI + raOriginLamda);XM =  Radius0*(4*this.QPI - raOriginLamda);Y = this.MAX;if (-Y < y && y < Y) {raLamda = x/Radius0 + raOriginLamda;if (this.ellipsoid.form == 0) raPhi = 2*(Math.atan(Math.exp(y/Radius0)*Math.tan(this.QPI+raOriginPhi/2.0))-this.QPI);else { var i = 0;raPhi = 2*(Math.atan(Math.exp(y/Radius0)*Math.tan(this.QPI+raOriginPhi/2))-this.QPI); delta = Math.log(Math.tan(this.QPI+raPhi/2)/Math.tan(this.QPI+raOriginPhi/2))+e/2*(Math.log((1-e*Math.sin(raPhi))*(1+esin0)/(1-esin0)/(1+e*Math.sin(raPhi)))) - y/Radius0;while (delta <= -this.EPS || this.EPS <= delta) {raPhi -= delta/(1-e2)*(Math.cos(raPhi)*(1-e2*Math.sin(raPhi)));delta = Math.log(Math.tan(this.QPI+raPhi/2)/Math.tan(this.QPI+raOriginPhi/2))+e/2*(Math.log((1-e*Math.sin(raPhi))*(1+esin0)/(1-esin0)/(1+e*Math.sin(raPhi)))) - y/Radius0;i++;if ( 100 < i ) {break;}}}}if (raLamda > Math.PI) raLamda -= (2 * Math.PI);else if (raLamda < -Math.PI) raLamda += (2 * Math.PI);return new LLPoint(raPhi * 180 / Math.PI, raLamda * 180 / Math.PI);};MercatorConversion.prototype.getMeterPoint = function(lpPoint) {var raPhi = lpPoint.lat * Math.PI / 180;var raLamda = lpPoint.lon * Math.PI / 180;var raOriginPhi = this.proj.origin.lat * Math.PI / 180;var raOriginLamda = this.proj.origin.lon * Math.PI / 180;var a = this.ellipsoid.a;var b = this.ellipsoid.b;var e2 = this.ellipsoid.e2;var Radius0, esin0;var xx = 0, yy = 0;if( (-2*this.QPI + this.EPS < raPhi) && (raPhi < 2*this.QPI - this.EPS) ) {var e = Math.sqrt(e2); esin0 = e*Math.sin(raOriginPhi);Radius0 = a*Math.cos(raOriginPhi)/Math.sqrt(1-e2*Math.sin(raOriginPhi)*Math.sin(raOriginPhi));xx = Radius0*(raLamda-raOriginLamda);yy = Radius0*(Math.log(Math.tan(this.QPI+raPhi/2)/Math.tan(this.QPI+raOriginPhi/2)) +e/2*(Math.log((1-e*Math.sin(raPhi))/(1-esin0)) - Math.log((1+e*Math.sin(raPhi))/(1+esin0))));}return new Point(xx , yy);};MercatorConversion.prototype.release=function(){this.proj.release();this.ellipsoid.release();this._release();};function UTMConversion(origin, factor) {this.proj = new SProjection(0, origin, factor); };UTMConversion.prototype.A = 6377397.155; UTMConversion.prototype.E = 0.006674372231315; UTMConversion.prototype.meridian = function(raPhi1, raPhi2) {var Ba, Bb, Bc, Bd, Be;Ba = 1.005037306049 * (raPhi2 - raPhi1);Bb = 5.0478492403e-3 * (Math.sin(2*raPhi2) - Math.sin(2*raPhi1)) / 2;Bc = 1.05637868e-5 * (Math.sin(4*raPhi2) - Math.sin(4*raPhi1)) / 4;Bd = 2.063332e-8 * (Math.sin(6*raPhi2) - Math.sin(6*raPhi1)) / 6;Be = 3.8853e-11 * (Math.sin(8*raPhi2) - Math.sin(8*raPhi1)) / 8;return this.A * (1 - this.E) * (Ba - Bb + Bc - Bd + Be);};UTMConversion.prototype.getLLPoint = function(meterPoint) {var x = meterPoint.y;var y = meterPoint.x;var raOriginPhi = this.proj.origin.lat * Math.PI / 180;var raOriginLamda = this.proj.origin.lon * Math.PI / 180;var dbFactor = this.proj.factor;var ra0 = 0;var ab = 1;var ph0 = Math.PI * 0.2;var m = x / dbFactor + this.meridian(ra0, raOriginPhi);y = y / dbFactor;var mot = 1 / (this.A * (1 - this.E));var si;var n = 0;while (ab > 1.0e-14) {var s = this.meridian(ra0, ph0);si= Math.sin(ph0);var ph1 = ph0 + (m - s) * Math.pow(1 - this.E * si * si, 1.5) * mot;ab = ph1 - ph0;ph0 = ph1;if(ab < 0)ab = -ab;if (++n > 100) {break;}}var co = Math.cos(ph0);var cr = Math.sqrt(1 - this.E * si * si);var ni = cr / this.A;var ri = cr * cr * cr * mot;var eta2 = (co * co) * this.E / (1 - this.E);var t = Math.tan(ph0);var t2 = t * t;var t4 = t2 * t2;var y1 = y * ni;var y2 = y1 * y1;var y4 = y2 * y2;var f1 = -0.08333333333333333 * y2 * (5 + 3*t2 + eta2 - 9*t2*eta2);var f2 = 0.002777777777777777 * y4 * (61 + 90*t2 + 45*t4);var raPhi = ph0 - 0.5 * y * y1 * ri * t * (1 + f1 + f2);f1 = -0.1666666666666666 * y2 * (1 + 2*t2 + eta2);f2 = 0.008333333333333333 * y4 * (5 + 28*t2 + 24*t4);var raLamda = raOriginLamda + y1 / co * (1 + f1 + f2);if (raLamda > Math.PI) raLamda -= (2.0 * Math.PI);else if(raLamda < -Math.PI) raLamda += (2.0 * Math.PI);return new LLPoint(raPhi * 180 / Math.PI, raLamda * 180 / Math.PI);};UTMConversion.prototype.getMeterPoint = function (lpPoint) {var raPhi = lpPoint.lat * Math.PI / 180;var raLamda = lpPoint.lon * Math.PI / 180;var raOriginPhi = this.proj.origin.lat * Math.PI / 180;var raOriginLamda = this.proj.origin.lon * Math.PI / 180;var dbFactor = this.proj.factor;raLamda -= raOriginLamda;var s = Math.sin(raPhi);var c = Math.cos(raPhi);var c2 = c * c;var c4 = c2 * c2;var t = Math.tan(raPhi);var t2 = t * t;var t4 = t2 * t2;var h2 = this.E * c2 / (1 - this.E);var h4 = h2 * h2;var N = this.A / Math.sqrt(1 - this.E * s * s);          var lam2 = raLamda * raLamda;var lamc2 = lam2 * c2;var lamc4 = lamc2 * lamc2;var B = this.meridian(raOriginPhi, raPhi);var x1 = lamc2 * (5 - t2 + 9*h2 + 4*h4) / 24;var x2 = lamc4 * (61 - 58*t2 + t4 + 270*h2 - 330*h2*t2) / 720;var y1 = lamc2 * (1 - t2 + h2) / 6;var y2 = lamc4 * (5 - 18*t2 + t4 + 14*h2 - 58*h2*t2) / 120;var xx = dbFactor * (B + N * s * c * lam2 * (0.5 + x1 + x2));var yy = dbFactor * N * c * raLamda * (1 + y1 + y2);return new Point(yy, xx);};UTMConversion.prototype.release=function(){this.proj._release();this._release();};function MeterMMConversion(scale, angle) {this.scale = scale; this.angle = angle; };MeterMMConversion.prototype.getMMPoint = function(meterPoint) {var dbCos = Math.cos(-this.angle);var dbSin = Math.sin(-this.angle);var x = (meterPoint.x * dbCos - meterPoint.y * dbSin) * 1000 / this.scale;var y = (meterPoint.x * dbSin + meterPoint.y * dbCos) * 1000 / this.scale;return new Point(x, y);};MeterMMConversion.prototype.getMeterPoint = function(mmPoint) {var dbCos = Math.cos(this.angle);var dbSin = Math.sin(this.angle);var x = (mmPoint.x * dbCos - mmPoint.y * dbSin) * this.scale / 1000;var y = (mmPoint.x * dbSin + mmPoint.y * dbCos) * this.scale / 1000;return new Point(x, y);};function CoordinatesConversion() {this.m_projCode = 0;this.m_UTMConv = new UTMConversion(new LLPoint(0, 0), 0);this.m_MercatorConv = new MercatorConversion(new LLPoint(0, 0), 0);this.m_MeterMMConv = new MeterMMConversion(25000, 0);this.m_center = new LLPoint(0, 0);this.m_windowWidth = 100;this.m_windowHeight = 100;};CoordinatesConversion.prototype.getProjOrigin = function() {if (this.m_projCode == 0) { return this.m_UTMConv.proj.origin;} else {return this.m_MercatorConv.proj.origin;}};CoordinatesConversion.prototype.setProjConv = function(projCode, origin, info) {this.m_projCode = projCode;if (projCode == 0) { this.m_UTMConv = new UTMConversion(new LLPoint(origin.lat, origin.lon), info);} else { this.m_MercatorConv = new MercatorConversion(new LLPoint(origin.lat, origin.lon), info);}};CoordinatesConversion.prototype.setScale = function(scale) {this.m_MeterMMConv.scale = scale;};CoordinatesConversion.prototype.setAngle = function(angle) {this.m_MeterMMConv.angle = angle*Math.PI/180;};CoordinatesConversion.prototype.getScale = function() {return this.m_MeterMMConv.scale;};CoordinatesConversion.prototype.getAngle = function() {return this.m_MeterMMConv.angle*180/Math.PI;};CoordinatesConversion.prototype.setCenter = function(center) {while(center.lon<-30){center.lon+=360;}while(center.lon>330){center.lon-=360;}this.m_center = new LLPoint(center.lat, center.lon);};CoordinatesConversion.prototype.setWindowSize = function(width, height) {this.m_windowWidth = width;this.m_windowHeight = height;};CoordinatesConversion.prototype.LL2Meter = function(lpPoint) {if (this.m_projCode == 0) { return this.m_UTMConv.getMeterPoint(lpPoint);} else { return this.m_MercatorConv.getMeterPoint(lpPoint);}};CoordinatesConversion.prototype.Meter2LL = function(meterPoint) {if (this.m_projCode == 0) { return this.m_UTMConv.getLLPoint(meterPoint);} else { return this.m_MercatorConv.getLLPoint(meterPoint);}};CoordinatesConversion.prototype.MM2Log = function(mmPoint) {var mmCenter = this.m_MeterMMConv.getMMPoint(this.LL2Meter(this.m_center));var logX =  this.m_windowWidth/2  - mmCenter.x*10 + mmPoint.x*10;var logY = -this.m_windowHeight/2 - mmCenter.y*10 + mmPoint.y*10;return new Point(logX, -logY);};CoordinatesConversion.prototype.Log2MM = function(logPoint) {var mmCenter = this.m_MeterMMConv.getMMPoint(this.LL2Meter(this.m_center));var mmX = mmCenter.x - this.m_windowWidth/2/10  + logPoint.x/10;var mmY = mmCenter.y + this.m_windowHeight/2/10 - logPoint.y/10;return new Point(mmX, mmY);};CoordinatesConversion.prototype.LL2MM = function(lpPoint) {return this.m_MeterMMConv.getMMPoint(this.LL2Meter(lpPoint));};CoordinatesConversion.prototype.MM2LL = function(mmPoint) {return this.Meter2LL(this.m_MeterMMConv.getMeterPoint(mmPoint));};CoordinatesConversion.prototype.LL2Log = function(lpPoint) {return this.MM2Log(this.m_MeterMMConv.getMMPoint(this.LL2Meter(lpPoint)));};CoordinatesConversion.prototype.Meter2Log = function(meterPoint) {return this.MM2Log(this.m_MeterMMConv.getMMPoint(meterPoint));};CoordinatesConversion.prototype.Log2LL = function(logPoint) {return this.Meter2LL(this.m_MeterMMConv.getMeterPoint(this.Log2MM(logPoint)));};CoordinatesConversion.prototype.Log2Meter = function(logPoint) {return this.m_MeterMMConv.getMeterPoint(this.Log2MM(logPoint));};CoordinatesConversion.prototype.release=function(){this.m_UTMConv.release();this.m_MercatorConv.release();this.m_MeterMMConv.release();this.m_center.release();this._release();};
