Acme-Geo-Whitwell-Name
view release on metacpan or search on metacpan
lib/Acme/Geo/Whitwell/Name.pm view on Meta::CPAN
}
my $lat = $value;
($value, $negative) = _coord_for(lc($lon_name));
if ($negative) {
if ($opts{signed}) {
$value = -$value;
}
else {
$value .= "W";
}
}
else {
unless ($opts{signed}) {
$value .= "E";
}
}
my $lon = $value;
return ($lat, $lon);
}
sub _coord_for {
my($original) = my($string) = @_;
# Determine if the string starts in the vowel table or the consonant table.
my @tables = (\@consonants, \@vowels);
my $vowel_found;
my $current = ($string =~ /^[aeiouy]/) || 0;
# Decompose and look up the character(s).
my $coord_string;
my $try_sign = 0;
my $is_negative = 0;
my $sign_checked = 0;
PARSE:
while ($string) {
# If we need to look for the sign character,
# do so. Since we've allowed names to start in either table
# as seems to have been the historical precedent (yes, someone
# actually did use this at least once for a real placename),
# we check for both sign characters and record whether or not
# we found one.
if ($try_sign) {
# Don't try more than once.
$try_sign = 0;
if ($string =~ s/^[vs]//) {
$is_negative = 1;
# Return to the vowel table again.
$current = 1;
next PARSE;
}
# Note we've looked for the sign once, so we shouldn't look
# again. This wil trap badly-placed sign characters.
$sign_checked = 1;
}
# Longer entries occur at the end of the vowel table, so
# to avoid parsing 'ee' as 'e' and 'e', we try the longer
# strings first. However: complicating this process is the '0'
# entry, which is also a longer one, so it has to be checked first.
for my $i (0, reverse 1..9) {
my $char = $tables[$current]->[$i];
if ($string =~ s/^$char//) {
# Found it. Tack the number onto the coordinate string,
# swap tables, and see if we need to check the sign.
$coord_string .= $i;
$try_sign = ($current == 1 and !$sign_checked);
$current = !$current;
next PARSE;
}
}
# The current table should have matched, so the input string is bad.
croak "Bad character or sequencing found in '$original' at '$string'";
}
# Insert the decimal point such that the resulting number is < 180.
# This allows "high-precision" Whitwell names (constructed in some
# manner other than via to_whitwell) to be converted back correctly.
if (length($coord_string) >= 3) {
# Need to insert a decimal point. The final value must be < 180,
# and we asssume at least two decimal places.
# Let's try the easy case first, and insert a decimal point
# right before the last two digits. All names generated via
# to_whitwell() will work with this case. Since we know the
# coordinate string only has numbers in it, we can just divide
# by 100.
my $trial_value = $coord_string/100;
# Manufactured by some other means. Move the decimal left one
# character at a time until the number is < 180. We never do this
# at all if our initial guess worked.
$trial_value /= 10 while $trial_value > 180;
$coord_string = $trial_value;
}
else {
# < 3, so can't be > 180. Just add decimals.
$coord_string .= ".00";
}
return ($coord_string, $is_negative);
}
=head1 AUTHOR
Joe McMahon, C<< <mcmahon at cpan.org> >>
=head1 BUGS
Please report any bugs or feature requests to C<bug-acme-geo-whitwell-name at
rt.cpan.org>, or through the web interface at
L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Acme-Geo-Whitwell-Name>. I
will be notified, and then you'll automatically be notified of progress on your
bug as I make changes.
=head2 KNOWN BUGS
=over
=item * (0,0) isn't handled correctly; however, since there's nothing there
but water, this is not a practical limitation.
( run in 2.626 seconds using v1.01-cache-2.11-cpan-600a1bdf6e4 )