Support multiple lat/lons

master
David Wilkins 2014-07-05 13:00:59 +08:00
parent 54148bae21
commit 228a094be3
2 changed files with 134 additions and 92 deletions

View File

@ -13,6 +13,7 @@ zci is_cached => 1;
name 'Convert Latitude and Longitude';
description 'Convert between latitudes and longitudes expressed in degrees of arc and decimal';
primary_example_queries '71º 10\' 3" in decimal';
secondary_example_queries '71 degrees 10 minutes 3 seconds east in decimal', '- 16º 30\' 0" - 68º 9\' 0" as decimal';
category 'transformations';
topics 'geography', 'math', 'science';
code_url 'https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/ConvertLatLon.pm';
@ -82,7 +83,19 @@ my %cardinalName = (
handle query_nowhitespace => sub {
return unless $_ =~ /$latLonQR/;
return unless /$latLonQR/;
my @queries;
my @results;
my $toFormat;
#Loop over all provided latitudes/longitudes
# Not going to try and enforce strict latitude/longitude
# pairing — if the user wants to pass in a long list
# of latitudes or a single longitude, no problem as long
# as they're all in the same format
while (/$latLonQR/g) {
my $minus = $+{minus};
my $degrees = $+{degrees};
@ -113,6 +126,11 @@ handle query_nowhitespace => sub {
#If the degrees are expressed in decimal...
if ($degrees =~ /\./) {
#If this isn't the first conversion, make sure the
# user hasn't passed a mix of decimal and DMS
return if $toFormat && ! $toFormat eq 'DMS';
$toFormat = 'DMS';
#Validation: must not have provided minutes and seconds
return if $minutes || $seconds;
@ -143,12 +161,18 @@ handle query_nowhitespace => sub {
my $formattedDMS = format_dms($dmsDegrees, $dmsMinutes, $dmsSeconds, $dmsSign, $cardinal);
my $formattedQuery = format_decimal(($degrees * $sign));
return $formattedDMS, html => wrap_html($formattedQuery, $formattedDMS, 'DMS');
push(@queries, $formattedQuery);
push(@results, $formattedDMS);
#Otherwise, we assume type is DMS (even if no
# minutes/seconds given)
} else {
#If this isn't the first conversion, make sure the
# user hasn't passed a mix of decimal and DMS
return if $toFormat && ! $toFormat eq 'decimal';
$toFormat = 'decimal';
#Validation: must have given at least minutes
return unless $minutes;
@ -183,11 +207,16 @@ handle query_nowhitespace => sub {
my $formattedDec = format_decimal($decDegrees);
my $formattedQuery = format_dms($degrees, $minutes, $seconds, $sign, $cardinal);
return $formattedDec, html => wrap_html($formattedQuery, $formattedDec, 'decimal');
push(@queries, $formattedQuery);
push(@results, $formattedDec);
}
}
return;
my $answer = join(' ' , @results);
my $html = wrap_html(\@queries, \@results, $toFormat);
return $answer, html => $html;
};
#Format a degrees-minutes-seconds expression
@ -221,6 +250,7 @@ sub format_decimal {
#Add a minus sign if negative (decimal format
# never uses cardial notation)
# TODO this is incorrect change this
if ($decDegrees / abs($decDegrees) == -1) {
$formatted = '' . $formatted;
}
@ -237,11 +267,23 @@ sub append_css {
return "<style type='text/css'>$css</style>$html";
}
sub wrap_secondary {
my $secondary = shift;
return "<span class='text--secondary'>" . $secondary . "</span>";
}
sub wrap_html {
my ($query, $result, $toFormat) = @_;
my $from = encode_entities($query) . " <span class='text--secondary'>" . " in " . encode_entities($toFormat) . ":". "</span>";
my $to = encode_entities($result);
return append_css("<div class='zci--conversions text--primary'>$from $to</div>");
#TODO can we use prototypes in this version of perl?
my @queries = @{$_[0]};
my @results = @{$_[1]};
my $toFormat = $_[2];
my $queries = join wrap_secondary(', '), map { encode_entities($_) } @queries;
my $results = join wrap_secondary(', '), map { encode_entities($_) } @results;
my $html = "<div class='zci--conversions text--primary'>" . $queries . wrap_secondary(' in ' . $toFormat . ': ') . $results . "</div>";
return append_css($html);
}
1;

View File

@ -19,22 +19,18 @@ ddg_goodie_test(
#Secondary examples
'71 degrees 10 minutes 3 seconds east in decimal' => test_zci('71.1675°', html => qr/71\.1675/),
'- 16º 30\' 0" - 68º 9\' 0" as decimal' => test_zci('16.5° 68.15°', html => qr/&minus;16\.5.+&minus;68\.15/),
#Latitudes and longitudes of cities, various trigger combinations
#Values from Wikipedia/GeoHack toolserver
#Sydney
'convert 151.2094° E to degrees minutes seconds' => test_zci('151° 12 34″ E', html => qr/151.+12.+34.+E/),
'convert 33.859972º S 151.2094° E to degrees minutes seconds' => test_zci('33° 51 36″ S 151° 12 34″ E', html => qr/33.+51.+36.+S.+151.+12.+34.+E/),
#Moscow
'55° 45 00″ in decimal' => test_zci('55.75°', html => qr/55.75/),
'55° 45 0″ 37° 37 0″ in decimal' => test_zci('55.75° 37.616667°', html => qr/55\.75.+37\.616667/),
#Kinshasha
'kinshasha is 15.322222 degrees east convert to dms' => test_zci('15° 19 20″ E', html => qr/15.+19.+20.+E/),
'kinshasha is 4.325 degrees south 15.322222 degrees east convert to dms' => test_zci('4° 19 30″ S 15° 19 20″ E', html => qr/4.+19.+30.+S.+15.+19.+20.+E/),
#Copenhagen
'55.676111° latitude' => test_zci('55° 40 34″', html => qr/55.+40.+34/),
#La Paz
'- 68º 9\' 0" as decimal' => test_zci('68.15°', html => qr/&minus;68.15/),
#If two coordinates are given (e.g. lat/lon), only the first will be converted
'20 º 10 \' 0 " S, 57 deg 31 min 0 sec E convert' => test_zci('20.166667°', html => qr/&minus;20\.166667/),
#Make sure "plural S" works
"68 degrees 9 minutes S in decimal form" => test_zci('68.15°', html => qr/&minus;68.15/),
@ -59,6 +55,10 @@ ddg_goodie_test(
#Check for css
'71° 10\' 3" in decimal' => test_zci(qr/./, html => qr/css/),
#Check for to-format name
'16.5° S, 68.15° W dms' => test_zci(qr/./, html => qr/DMS/),
'16° 30 S, 68° 9 W decimal' => test_zci(qr/./, html => qr/decimal/),
);
done_testing;