Thx, man. You are honestly one of the people who makes the internet fun as well as manageable and informative.
Just effin wow. What does this line in particular represent? [!foot], etc...
I may have worn out my welcome with the server because it didn't always not want to talk to me at all. Full script here for dedicated parties (80 lines less without dialing up google; I don't want to post it on gitlab until it looks and behaves better.):
#!/usr/bin/perl
use v5.028; # strictness implied
use warnings;
use feature qw[ signatures ];
no warnings qw[ experimental::signatures ];
use DateTime;
use DateTime::Format::ISO8601;
use DateTime::TimeZone;
use Log::Log4perl;
use Try::Tiny;
our $debug = 0;
my $logger = init_log();
my $ref_events = init_event();
my $date_str = "2021-10-14";
my $time_str = "03:22:31";
@{$_}{qw(date time)} = ( $date_str, $time_str ) for @$ref_events;
my @events = @$ref_events;
my $pi = atan2( 1, 1 ) * 4;
$logger->info("pi is $pi ");
my $redrock = 5200; #Willsey thumbnail for Bonneville Trail elevati
+on
$logger->info("Bonneville max altitude in feet: $redrock");
## event loop
# Initial previous event to something
my ( $prev_lat, $prev_long ) =
( -112, 42 ); #some point in the snake river plain
for my $event (@events) {
my $epoch = parse_event($event);
### determine altitude withOUT google
die unless exists $event->{location}; # restriction
my $return = get_open_elevation( $event->{location}->{lat},
$event->{location}->{lon}, $debug );
$logger->info(
" $event->{name} $event->{location}->{lat} $event->{location}->{l
+on}");
$logger->info("return from the google is $return meters");
my $feet = 3.28084 * $return;
$logger->info("Altitude in feet is $feet");
my $diff = $redrock - $feet;
$logger->info("Difference from max Bonneville elevation is $diff ft"
+);
### Elevation with USGS
use Geo::WebService::Elevation::USGS;
my $eq = Geo::WebService::Elevation::USGS->new();
my $alt =
$eq->elevation( $event->{location}->{lat}, $event->{location}->{lo
+n} )
->{Elevation};
$logger->info("USGS elevation is $alt ft");
### compare values
my $percent = percent_error( $feet, $alt );
$logger->info("Percent difference is $percent");
### distance with GPS::Point
use GPS::Point;
my $gps = GPS::Point->new( lat => $prev_lat, lon => $prev_long );
my $dist =
$gps->distance( $event->{location}->{lat}, $event->{location}->{lo
+n} );
my $feet2 = 3.28084 * $dist;
my $miles = $feet2 / 5280;
#$logger->info("distance is $feet2 feet");
$logger->info("distance is $miles miles");
### rotate values
$prev_lat = $event->{location}->{lat};
$prev_long = $event->{location}->{lon};
$logger->info("==============");
}
## end event loop
#### end main
sub init_event {
# define unique event records as anonymous hash refs.
# thx anomalous monk
my $ar_events = [
{
"name" => "Boise",
"location" => { lon => -116.2, lat => 43.61 },
},
{
"name" => "near sublett",
"location" => { lon => -113.2104084, lat => 42.3278114 },
},
{
"name" => "snowville",
"location" => { lon => -112.7105234, lat => 41.9655701 },
},
{
"name" => "juniper",
"location" => { lon => -112.9842191, lat => 42.152429 },
},
# and so on...
];
return $ar_events;
}
sub percent_error {
my ( $val1, $val2 ) = @_;
my $diff = abs( $val2 - $val1 );
my $median = ( $val1 + $val2 ) / 2.0;
my $percent = $diff * 100 / $median;
return ($percent);
}
sub init_log {
{
package Log::Log4perl;
sub get_logger ($pkg) { return bless [], $pkg; }
sub show (@arg) { warn @arg, "\n"; }
sub debug ( $ignore, @rest ) { show( 'DEBUG: ', @rest ); }
sub info ( $ignore, @rest ) { show( 'INFO: ', @rest ); }
sub warn ( $ignore, @rest ) { show( 'WARNING: ', @rest ); }
sub error ( $ignore, @rest ) { die 'ERROR: ', @rest, "\n"; }
}
my $logger2 = Log::Log4perl->get_logger();
$logger2->info("$0");
return $logger2;
}
sub event2str {
my $event = shift;
if ( !exists $event->{_is_parsed} ) {
warn "event has not been parsed, just dumping it...";
print Dump($event);
}
my $str =
$event->{name} . " on "
. $event->{datetime} . " ("
. $event->{datetime}->epoch
. " seconds unix-epoch)"
. " timezone: "
. $event->{datetime}->time_zone->name;
if ( exists $event->{location} ) {
if ( ref( $event->{location} ) eq 'HASH' ) {
$str .=
" (lat: "
. $event->{location}->{lat}
. ", lon: "
. $event->{location}->{lon} . ")";
}
else { $str .= "(" . $event->{location} . ")" }
}
return $str;
}
sub parse_event {
my $event = shift;
$debug //= 0;
if ( !exists $event->{date} ) { die "date field is missing from even
+t." }
my $datestr = $event->{date};
die "event does not have a 'name' field, please specify one, anythin
+g really."
unless exists $event->{name};
my $timestr = "00:00:01";
if ( exists $event->{time} ) {
$timestr = $event->{time};
print "event2epoch(): setting time to '$timestr' ...\n"
if $debug > 0;
die "time '$timestr' is not valid, it must be in the form 'hh:mm:s
+s'."
unless $timestr =~ /^\d{2}:\d{2}:\d{2}$/;
}
else { $event->{time} = $timestr }
my $isostr = $datestr . 'T' . $timestr;
my $dt = DateTime::Format::ISO8601->parse_datetime($isostr);
die "failed to parse date '$isostr', check date and time fields."
unless defined $dt;
$event->{datetime} = $dt;
my $tzstr = 'UTC';
if ( exists $event->{timezone} ) {
$tzstr = $event->{timezone};
print
"event2epoch(): found a timezone via 'timezone' field as '$tzstr' (tha
+t does not mean it is valid) ...\n"
if $debug > 0;
}
elsif ( exists $event->{location} ) {
my $loc = $event->{location};
if ( ( ref($loc) eq '' ) && ( $loc =~ /^[a-zA-Z]$/ ) ) {
# we have a location string
my @alltzs = DateTime::TimeZone->all_names;
my $tzstr;
for (@alltzs) {
if ( $_ =~ /$loc/i ) { $tzstr = $_; last }
}
die
"event's location can not be converted to a timezone, consider specify
+ing the 'timezone' directly or setting 'location' coordinates with: \
+[lat,lon\]."
unless $tzstr;
print
"event2epoch(): setting timezone via 'location' name to '$timestr' ...
+\n"
if $debug > 0;
}
elsif ( ( ref($loc) eq 'HASH' )
&& ( exists $loc->{lat} )
&& ( exists $loc->{lon} ) )
{
# we have a [lat,lon] array for location
require Geo::Location::TimeZone;
my $gltzobj = Geo::Location::TimeZone->new();
$tzstr = $gltzobj->lookup( lat => $loc->{lat}, lon => $loc->{lon
+} );
if ( !$tzstr ) {
die "timezone lookup from location coordinates lat:"
. $loc->{lat}
. ", lon:"
. $loc->{lon}
. " has failed.";
}
print "event2epoch(): setting timezone via 'location' coordinate
+s lat:"
. $loc->{lat}
. ", lon:"
. $loc->{lon}
. " ...\n"
if $debug > 0;
}
}
if ($tzstr) {
print "event2epoch(): deduced timezone to '$tzstr' and setting it
+...\n"
if $debug > 0;
try {
$dt->set_time_zone($tzstr)
}
catch {
die "$_\n failed to set the timezone '$tzstr', is it valid?"
}
}
$event->{_is_parsed} = 1;
$event->{epoch} = $dt->epoch;
return $event->{epoch};
}
sub get_open_elevation {
my ( $lat, $lon, $debug ) = @_;
use LWP::UserAgent;
use HTTP::Request;
use Data::Roundtrip;
$debug //= 0;
#my $ua = LWP::UserAgent->new( 'send_te' => '0' );
my $ua = LWP::UserAgent->new( agent =>
'Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox
+/78.0', );
my $r = HTTP::Request->new(
'GET' =>
'https://api.open-elevation.com/api/v1/lookup?locations=$lat%2C$lon',
[
'Accept' => '*/*',
'User-Agent' => 'curl/7.55.1'
],
);
my $response = $ua->request( $r, );
if ( $debug > 0 ) {
$logger->debug("$0 : verbose");
}
die "Error fetching: " . $response->status_line
unless $response->is_success;
my $content = $response->decoded_content;
my $data = Data::Roundtrip::json2perl($content);
warn "failed to parse received data:\n$content\n"
unless exists $data->{'elevation'};
return 5000;
}
__END__