Расчет наложения день / ночь для Карт Google - PullRequest
12 голосов
/ 18 августа 2011

Я пытаюсь найти способ создания наложения для Google Maps API V3, который показывает освещенные солнцем области мира. Это основной результат, который я ищу:

http://www.daylightmap.com/index.php

Но вам нужно больше контроля над внешним видом (в идеале, просто наложение черного цвета на 10% без городских огней). Я могу нарисовать фигуру в элементе canvas, но не могу понять, как рассчитать фигуру на основе наклона и вращения Земли и т. Д.

Любая помощь будет оценена.

РЕДАКТИРОВАТЬ: Javascript

Я до сих пор не знаю, где реализовать переменную y-offset ниже. Мне также нужно выяснить, как отрегулировать / растянуть смещение по оси Y от этого (равных удаленных широтных линий) до меркатора (ближе к полюсам).

// Get the canvas element
var ctx = document.getElementById('canvas').getContext('2d');
ctx.clearRect( 0, 0, 800, 620 );

// Current time
var map_width = $("#canvas").width();
var map_height = $("#canvas").height();
var now = new Date();
var cur_hour = now.getHours();
var cur_min = now.getMinutes();
var cur_sec = now.getSeconds();
var cur_jul = now.julianDate() - 1;
var equinox_jul = new Date(now.getFullYear(),2,20,24,-now.getTimezoneOffset(),0,0).julianDate() - 1;

var offset_x = Math.round(((cur_hour*3600 + cur_min*60 + cur_sec)/86400) * map_width); // Resulting offset X
var offset_sin = ((365.25 - equinox_jul + cur_jul)%365.25)/365.25; // Day offset, mapped on the equinox offset
var offset_sin_factor = Math.sin(offset_sin * 2 * Math.PI); // Sine wave offset
var offset_y = offset_sin_factor * 23.44; // Map onto angle. Maximum angle is 23.44° in both directions

var degrees_per_radian = 180.0 / Math.PI;
var offset_y_mercator = Math.atan( offset_y.sinh() ) * degrees_per_radian;


// Global wave variables
var period = 1 / 6.28291;   // Original value 2Pi: 6.28291
var amplitude = (map_height/2);

// Draw vertical lines: One for each horizontal pixel on the map
for( var x = 0; x <= map_width; x++ ) {
    ctx.beginPath();

    // Start at the bottom of the map
    ctx.moveTo(x,map_height);

    // Get the y value for the x pixel on the sine wave
    var y = (map_height/2) - (Math.sin( (offset_x / map_width) / period ) * amplitude);

    offset_x++;

    // Draw the line up to the point on the sine wave
    ctx.lineTo(x,y);
    ctx.stroke();
}

Ответы [ 2 ]

7 голосов
/ 27 августа 2011

Если вы хотите, чтобы он был физически точным, вам нужно учитывать два смещения: вертикальное (в зависимости от текущей даты) и горизонтальное (в зависимости от текущего времени).

Горизонтальное смещение Xможно рассчитать, посмотрев на текущее время в некотором фиксированном географическом местоположении на земле.Смещение тени будет 0 в полночь и будет увеличиваться на 1/86400 каждые секунды после полуночи.Таким образом, формула имеет вид

offsetX = (curHour*3600 + curMinute*60 + curSeconds)/86400

Вертикальное смещение будет изменяться между Солнцестояниями 21 июня и 22 декабря (если это не високосный год, когда Солнцестояния происходят 20 июня и декабря21-е).Максимальные углы составляют 23,44 ° в обоих направлениях.У нас 90 ° на полушарие и 365/2 = 182,5 дня между двумя солнцестояниями, и мы работаем с отображением кругового движения, поэтому необходимо использовать функцию sin ().Длина волны синусоидальной волны равна 2pi, поэтому нам нужно пи для половины вертикального смещения Y одного года.

Обратите внимание, что я не учел високосные секунды, поэтому вычисление может быть немного неправильнымв далеком прошлом / будущем.

// current time
$curHour = date("H");
$curMin  = date("i");
$curSec  = date("s");

// resulting offset X
$offsetX = ($curHour*3600 + $curMin*60 + $curSec)/86400;


echo "======== OFFSET X ==========\n";
echo "curHour:      $curHour\n";
echo "curMin:       $curMin\n";
echo "curSec:       $curSec\n";
echo "offsetX:      $offsetX\n\n";


// spring equinox date as day of year
$equinox = date("z", mktime(0, 0, 0, 3, 20));

// current day of year
    // first line is for testing purposes
//$curDay = date("z", mktime(0, 0, 0, 6, 21));
    $curDay = date("z");

// Day offset, mapped on the equinox offset
$offsetSin = ((365.25 - $equinox + $curDay)%365.25)/365.25;

// sinus wave offset
$offsetSinFactor = sin($offsetSin * 2 * pi());

// map onto angle
$offsetY = $offsetSinFactor * 23.44;

// optional: Mercator projection
$degreesPerRadian = 180.0 / pi();
$offsetYmercator = atan(sinh($offsetY)) * $degreesPerRadian;

// missing: mapping onto canvas height (it's currently
// mapped on $offsetY = 90 as the total height of the
// canvas.


echo "========= OFFSET Y =========\n";
echo "equinox day:  $equinox\n";
echo "curDay:       $curDay\n";
echo "offsetSin:    $offsetSin\n";
echo "offsetSinFac: $offsetSinFactor\n";
echo "offsetY:      $offsetY\n";
echo "offsetYmerc:  $offsetYmercator\n";

Вы должны быть в состоянии перенести этот расчет на любой язык.

1 голос
/ 29 августа 2011

Вы запросили больший контроль над внешним видом

Ознакомьтесь с Geocommons JS api , который может более соответствовать вашим целям, чем Google Maps.

Если вам нужна гибкость, то GEOS предпочтительнее, чем рисование фигуры для конкретной проекции. Я знаю, что есть php-привязки , но я сам ими не пользовался.

У Хелмера Аслаксена есть отличная статья о небесной математике , которая должна помочь вам создать алоритмнарисовать многоугольник освещенной солнцем области, используя геос.Вы можете проверить свой код по измеренным временам восхода / заката для точности.

Редактировать 1

Должны ли вы быть Python и Google Maps, говорите?

...