#!/usr/bin/perl
# A sun reflection template
# Copyright       : https://www.fsf.org/copyleft/gpl.html
# Author          : Dan Jacobson -- https://www.jidanni.org/
# Created On      : Mon May 31 19:31:41 2021
# Last Modified On: Mon May 31 22:03:09 2021
# Update Count    : 25
use strict;
use warnings FATAL => 'all';
use open qw/:std :encoding(utf8)/;
use Math::Trig '/./';
sub NESW { deg2rad( $_[0] ), deg2rad( 90 - $_[1] ) }
my $world_radius =
  6378137;    #meters. Or maybe I should use 6370997: #proj -le: sphere
my %location = (
    reflector => {
        longtude        => 120.873615,
        latitude        => 24.143174,
        above_sea_level => 901,          #meters
        azimuth         => 324.05,       #of perpendicular to plane of reflector
        vs_horizon      => 30
        , #0 is e.g., an average window, perpendicular makes 0 degrees angle with horizon
    },
    observer => {
        longtude        => 120.865225,
        latitude        => 24.181802,
        above_sea_level => 777
    }
);
my @light;
{
    my @t;
    for (qw/reflector observer/) {
        push @t, NESW( @{ $location{$_} }{qw/longtude latitude/} );
    }
    $location{observer}{azimuth}    = rad2deg great_circle_direction(@t);
    $location{observer}{vs_horizon} = rad2deg atan(
        (
            $location{observer}{above_sea_level} - $location{reflector}{above_sea_level}
        ) /
          great_circle_distance( @t, $world_radius )  #short distance, assume flat earth
    );
    @t = ();
    for (qw/reflector observer/) {
        push @t, NESW( @{ $location{$_} }{qw/azimuth vs_horizon/} );
    }
    @light = great_circle_waypoint( @t, -1 );
}
## Now we start to think using a sphere centered at the reflector.
## Compute the best time of day where the light (sun, moon, etc.) is closest to the
## spot in the sky where it reflects perfectly to the observer.
my ( $date, %best );
while (<>) {
    if (/./) {
        ( $date, my ( $time, $azimuth, $elevation ) ) = split;
        my $distance = great_circle_distance( @light, NESW( $azimuth, $elevation ) );
        if ( !%best or $distance < $best{distance} ) {
            $best{time}     = $time;
            $best{distance} = $distance;
        }
    }
    else {
        printf "%s %s\n", $date, $best{time};
        undef %best;
    }
}