webdial

Incomplete JS port of moondial.
git clone https://code.literati.org/webdial.git
Log | Files | Refs

commit 150b1f0d960a84ce0f0bcbc72a017761a0a433cc
parent f42d6792e969a05241983af99f1fba00fcbfb073
Author: Sean Lynch <seanl@literati.org>
Date:   Wed,  7 Sep 2011 23:49:21 -0700

Try to draw night.

Diffstat:
Msun.js | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mwebdial.js | 52++++++++++++++++++++++++++++++++++++++++------------
2 files changed, 146 insertions(+), 12 deletions(-)

diff --git a/sun.js b/sun.js @@ -4,6 +4,10 @@ var Sun = function() { return d * _DtoR; } + function r_to_d(r) { + return d / _DtoR; + } + function dms_to_d(deg, min, sec) { var result = Math.abs(deg) + Math.abs(min) / 60.0 + Math.abs(sec) / 3600.0; @@ -37,6 +41,108 @@ var Sun = function() { return y; } + /** + * Convert ecliptic to equitorial coordinates. + * + * [Meeus-1998: equations 13.3, 13.4] + * + * Parameters: + * longitude : ecliptic longitude in radians + * latitude : ecliptic latitude in radians + * obliquity : obliquity of the ecliptic in radians + * + * Returns: + * Right accension in radians + * Declination in radians + */ + function ecl_to_equ(lon, lat, obl) { + var cose = Math.cos(obl); + var sine = Math.sin(obl); + var sinl = Math.sin(lon); + var ra = modpi2(Math.atan2(sinl * cose - Math.tan(lat) * sine, + Math.cos(lon))); + var dec = Math.asin(Math.sin(lon) * cose + Math.cos(lat) * sine * sinl); + return {"ra": ra, "dec": dec}; + } + + this.equ_to_geo = function(ra, dec, st) { + var lon = r_to_d(ra - st); + if (lon > 180.0) { + lon -= 360.0; + } + return {longitude: lon, latitude: r_to_d(dec)}; + }; + + this.sun_rst_altitude = -0.0145438286569; + + this.terminator = function(lat, lon, alt, w, h) { + lat = lat / 180.0 * Math.PI; + var x_offset = (lon + 180.0) * w / 360.0; + var obl = lat - Math.PI / 2; + var points = []; + var prev_x; + if (lat < 0.0) { + prev_x = w; + } else { + prev_x = -1; + } + + var deg, H, equ, x, y; + for (deg = 0; deg < 360; deg++) { + H = deg * Math.PI / 180.0; + equ = ecl_to_equ(H, alt, obj); + x = Math.round(equ.ra * w / PI2 + x_offset) % w; + y = Math.round((0.5 - equ.dec / Math.PI) * h); + if (lat < alt) { + if (x > prev_x) { + points.push([0,0]); + points.push([w-1,0]); + } + } else if (lat > -alt && x < prev_x) { + points.push([w-1,h-1]); + points.push([0,h-1]); + } + points.push([x,y]); + prev_x = x; + } + return points + }; + + this.cal_to_jd = function(date) { + var yr = date.getUTCFullYear(); + var mo = date.getUTCMonth() + 1; // WTF??? + var day = date.getUTCDate() + date.getUTCHour() / 12.0 + + date.getUTCMinute() / 1440.0 + + date.getUTCSecond() / 86400.0; + if (mo <= 2) { + yr -= 1; + mo += 12; + } + var A = parseInt(yr / 100); + var B = 2 - A + parseInt(A / 4) + + return parseInt(365.25 * (yr + 4716)) + parseInt(30.6001 * (mo + 1)) + + day + B - 1524.5 + }; + + this.sidereal_time_greenwich = function(jd) { + var T = jd_to_jcent(jd); + var T2 = T * T; + var T3 = T2 * T; + var theta0 = 280.46061837 + 360.98564736629 * (jd - 2451545.0) + + 0.000387933 * T2 - T3 / 38710000; + return modpi2(d_to_r(theta0)); + }; + + var _el0 = [d_to_r(dms_to_d(23, 26, 21.448)), + d_to_r(dms_to_d( 0, 0, -46.8150)), + d_to_r(dms_to_d( 0, 0, -0.00059)), + d_to_r(dms_to_d( 0, 0, 0.001813)))]; + + this.obliquity = function(jd) { + return polynomial(_el0, jd_to_jcent(jd)); + } + // Constant terms var _kL0 = [d_to_r(280.46646), d_to_r(36000.76983), d_to_r( 0.0003032)]; var _kM = [d_to_r(357.52911), d_to_r(35999.05029), d_to_r(-0.0001537)]; diff --git a/webdial.js b/webdial.js @@ -1,34 +1,62 @@ function WebDial(canvas) { var continents; - function drawMap() { + function drawPoly(ctx, w, h, points) { function lon2x(lon) { - return Math.round((lon + 180.0) * 10.0); + return Math.round((lon + 180.0) * w / 360.0); } function lat2y(lat) { - return Math.round((90.0 - lat) * 10.0); + return Math.round((90.0 - lat) * h / 180.0); } - var ctx = canvas[0].getContext("2d"); + ctx.beginPath(); + var lastPoint = points[points.length-1]; + ctx.moveTo(lon2x(lastPoint[0]), lat2y(lastPoint[1])); + $.each(points, function(j, point) { + ctx.lineTo(lon2x(point[0]), lat2y(point[1])); + }); + ctx.fill(); + } + + function drawMap(ctx, w, h) { ctx.fillStyle = "rgb(0, 192, 0)"; $.each(continents, function(continent, polygons) { console.debug("Drawing", continent); $.each(polygons, function(i, points) { - ctx.beginPath(); - var lastPoint = points[points.length-1]; - ctx.moveTo(lon2x(lastPoint[1]), lat2y(lastPoint[0])); - $.each(points, function(j, point) { - ctx.lineTo(lon2x(point[1]), lat2y(point[0])); - }); - ctx.fill(); + drawPoly(ctx, w, h, points); }); }); } + function drawNight(ctx, w, h) { + ctx.fillStyle = "rgba(0, 0, 0, 128)"; + var jd = Sun.cal_to_jd(new Date()); + var epsilon = Sun.obliquity(jd); + var geometric_lon = Sun.longitude_radius_low(jd).longitude; + var lon = Sun.apparent_longitude_low(jd, geometric_lon); + var equ = Sun.ecl_to_equ(lon, 0.0, epsilon); + var st = Sun.sidereal_time_greenwich(jd); + var geo = Sun.equ_to_geo(ra, dec, st); + var points = Sun.terminator(geo.latitude, geo.longitude, + Sun.sun_rst_altitude, w, h); + ctx.beginPath(); + var lastPoint = points[points.length-1]; + ctx.moveTo(lon2); + drawPoly(ctx, w, h, points); + } + + function draw() { + var ctx = canvas[0].getContext("2d"); + var w = canvas[0].width; + var h = canvas[0].height; + drawMap(ctx, w, h); + drawNight(ctx, w, h); + } + function mapCallback(data) { continents = data; - drawMap(); + draw(); } function errCallback(xhr, status, error) {