Pages

How to Draw a Day/Night World Map

Actually, there is nothing too hard. Nowadays we could do this using only plain JavaScript and a HTML5 canvas, so let's do it.

The algorithm is the following:
  1. Find the current equatorial coordinates of the Sun, the hour angle and declination (thus we automatically get the latitude and longitude of the subsolar point).
  2. Map each pixel of the Earth map to the geographic coordinates using the corresponding map projection transformations (actually it's convenient to have angle values in equatorial coordinate form for the following calculations).
  3. For each pixel of the map check, whether it distant from the subsolar point farther than 90 degrees (because the shadow edge is a great circle).
  4. If so, convert RGB values of the pixel to HSV color representation and decrease the Value channel by two (or get the same pixel from a night version of the map), then put processed pixel data back using reverse HSV to RGB conversion.
  5. That's all.
    Implementation details:
    1. To find estimate subsolar point coordinates it's only necessary to correct the current UTC time with the equation of time (to get the hour angle) and find position of the Sun on the ecliptic using the amount of time since the vernal eqinox (to find the declination) or this approximate algorithm. But there are more precise algorithms, which have deal with Earth axial precessions and nutations, Earth elliptical motion and other periodic theories, which are described in the book Astronomical Algorithms by Jean Meeus. Nevertheless, it's very hard to implement and debug them properly, so we will use existing JavaScript implementation by Henning Umland.
    2. Because we use equirectangular map projection, there is no need for pixel to spherical coordinate conversion, the longitude and latitude are mapped directly to the cartesian coordinates. We only need to adjust the origin of the map.
    3. To find the angular distance between the subsolar point and the pixel being processed, we need to use the spherical law of cosines in application to the angular coordinates of the corresponding points.
    4. Because HTML5 canvas has ability to draw semitransparent rectangles, we do not need to mess with HSV color representation, and it's possible to apply some optimizations to the algorithm. As we know that a projection of the sunlight shadow on the Earth map is a sine-like figure (unambiguous mapping), we only need to find the first top or bottom pixel (depends on the current season) of the shadow for a given pixel column and draw one pixel width semitransparent rectangle to the opposite map edge.
    5. There are Sunlight World Map HML5 Demo and a Windows Desktop Gadget are available. Enjoy freely by any of them.



    ¹ Make sure that daylight saving time settings are configured properly on your system
    -->

    7 comments:

    Vasilis Milingos said...

    Hi I was looking at a way to implement your code in my application. My application in silverlight is working with bingmaps api. So I made the necessary changes from js to c# and I am trying to make the curve draw on the map but I need to provide coordinates (lat, long) instead of pixels that you have in your solution. Since I am not that versed in that area is it possible that you could help me a bit?

    g/christensen said...

    I'm not familiar with bingmap APIs, but most likely you don't need pixel to degree conversion at all if you are able to get curve points in degrees and API takes degrees as an input (in this case it should maintain the projection under the hood).
    You need to "quantize" the equator (the number of pieces will define smoothness of the curve) and get latitude of the shadow edge for each longitude using the subsolar point and the law of consines.
    You still may need to convert equatorial coordinates to the form which Bing uses and take the season into account to draw the shadow properly.

    Vasilis Milingos said...

    Hi and thanks for your answer
    My mathematical and astronomical knowledge are not that good, so I got the files (calculations.js and sunlight.js) you have in github and translated them the best I could in c# code.
    Now BingMaps can take degrees (as double) as input so you only need to define a point in the map as a GeoPoint(Latitude, Longitude) with Latitude( -90 to +90) and Longitude(-180 to +180).
    So to draw the sun and moon I need only their Latitude and Longitude. But how to get that from GHAsun, DECsun, GHAmoon and DECmoon ?
    Drawing the Sun and moon on the map will be the first step and will also show me if the translation from js to c# was successful :)

    Thanks again for your time

    g/christensen said...

    If Bingmaps allow to draw circles you may try to cheat and just draw a circle with the centre at the point opposite to the subsolar point (you need to get the radius empirically), because the shadow edge is a big circle.
    If you want to draw a curve, you need to solve a system of equations in polar coordinates to get intersection points of the shadow edge and meridians (although there may be a simpler solution). So, geometry on sphere should be the area of your research.

    Vasilis Milingos said...

    Can you help me with the math? cause all the astronomy is greek to me.
    So in your demo you show the position of moon and sun. I have reached after all the maths(without understanding the phusics) to the point of having the GHAsun, DECsun, GHAmoon and DECmoon. I just need to translate them to Latitude(-90 , +90) and Longitude(-180, +180) but do not undesrstand how...

    g/christensen said...

    You already should have the latitude (DECsun) in degrees in the form you need, to transform the longitude (GHAsun) to geographical coordinates (if Bingmap uses them) you need to use the conditional computation: don't touch the value if it's less than 180 and use value - 360 in the opposite case.
    To find intersection points of the shadow edge with meridians you may use the following formulas: http://geospatialmethods.org/spheres/GCIntersect.html

    Vasilis Milingos said...

    Thanks alot, I am now at the point of testing with the moon and sun position. Unfortunately I do not get the correct GHAsun, DECsun, GHAmoon and DECmoon values. So I must check again the javascript code you have in github.com. Maybe I have a mistake cause i get differrent positions on my map than the positions on your windows gadget, which by the way is excellent.

    Post a Comment