Geo-Distance
view release on metacpan or search on metacpan
Revision history for Perl extension Geo-Distance.
0.25 2021-01-30T06:24:44Z
- Lots of documentation edits.
0.24 2019-03-10T06:48:33Z
- Once again support the alt formula (now with a PP variant!).
0.23 2019-03-09T13:15:58Z
- Require GIS::Distance 0.13 so that tests pass.
- Fixed a coordinate ordering bug in distance().
- Added the null formula.
0.22 2019-03-08T18:36:39Z
- Made the distance() method faster.
0.21 2019-03-07T23:08:39Z
- Officially set the x_deprecated META flag.
- Use GIS::Distance 0.11+ for all distance calculations.
- Lots and lots of documentation edits for the above.
- Migrate build tooling from Dist::Zilla to Minilla.
0.20 2012-10-19
- Fix a test that was comparing floating point numbers and falling over on
some platforms.
0.19 2012-04-03
- Fix various typos.
- Fix floating point error in the hsin formula.
0.18 2012-03-23
- Fix gcd calculation to use ** instead of ^.
0.17 2011-06-28
- Fix circular package dependencies with Geo::Distance::XS (not really
an issue practically, but then again it wasn't really helping).
0.12
- Noted GIS::Distance in POD.
- Some cleanups to install process.
- Check for DBI in tests before using it.
0.11 2005-09-01
- Fixed some errors in the documentation.
- Added an highly accurate ellipsoid formula.
- lon_field and lat_field were not being used by closest. (D. Hageman)
0.10 2005-07-11
- The closest() method has a changed argument syntax and no longer
supports array searches.
- The closest() method works!
- A real gcd formula (still, hsin is much better).
- Tweaked docs.
- Added some tests (yay!).
0.09 2005-04-01
- Modified the todo list to include ideas for future algorithms.
- Fixed the nautical mile, mile, yard, and light second units.
- Added the British spellings for kilometre, metre, and centimetre.
- Added the poppy seed, barleycorn, rod, pole, perch, chain,
furlong, league, fathom, millimeter, and millimetre units.
- Intermixed documentation with code so it is easier to keep
the docs up-to-date.
- OO interface only - method interface completely removed.
- By default no units are defined. Call default_units.
- Slightly more precise measurement of the base kilometer rho.
- Added "nautical mile" unit type.
- Reworked the closest() function.
0.06 2004-06-29
- Optional Haversine formula.
- Misc documentation tweaks.
0.05 2003-03-19
- Added a note in the documentation about the
inaccuracies of using Math::Trig.
- The 'mile' unit was being calculated wrong which
meant it was returning very inaccurate distances.
- Fixed a silly bug where a sub was being relied
on that no longer exists.
# NAME
Geo::Distance - Calculate distances and closest locations. (DEPRECATED)
# SYNOPSIS
```perl
use Geo::Distance;
my $geo = new Geo::Distance;
$geo->formula('hsin');
$geo->reg_unit( 'toad_hop', 200120 );
$geo->reg_unit( 'frog_hop' => 6 => 'toad_hop' );
my $distance = $geo->distance( 'unit_type', $lon1,$lat1 => $lon2,$lat2 );
my $locations = $geo->closest(
dbh => $dbh,
table => $table,
lon => $lon,
lat/lon pairs while Geo::Distance takes lon/lat pairs.
# ARGUMENTS
## no\_units
Set this to disable the loading of the default units as described in ["UNITS"](#units).
# ACCESSORS
## formula
```
if ($geo->formula() eq 'hsin') { ... }
$geo->formula('cos');
```
Set and get the formula that is currently being used to calculate distances.
See the available ["FORMULAS"](#formulas).
`hsin` is the default.
# METHODS
## distance
```perl
my $distance = $geo->distance( 'unit_type', $lon1,$lat1 => $lon2,$lat2 );
```
lib/Geo/Distance.pm view on Meta::CPAN
tv Vincenty
));
const our @FORMULAS => (keys %GEO_TO_GIS_FORMULA_MAP);
sub new {
my $class = shift;
my $self = bless {}, $class;
my %args = @_;
$self->{formula} = 'hsin';
$self->{units} = {};
if(!$args{no_units}){
$self->reg_unit( $KILOMETER_RHO, 'kilometer' );
$self->reg_unit( 1000, 'meter', => 'kilometer' );
$self->reg_unit( 100, 'centimeter' => 'meter' );
$self->reg_unit( 10, 'millimeter' => 'centimeter' );
$self->reg_unit( 'kilometre' => 'kilometer' );
$self->reg_unit( 'metre' => 'meter' );
$self->reg_unit( 'centimetre' => 'centimeter' );
lib/Geo/Distance.pm view on Meta::CPAN
$self->reg_unit( 'perch' => 'rod' );
$self->reg_unit( 'chain' => 20.1168, 'meter' );
$self->reg_unit( 'furlong' => 201.168, 'meter' );
$self->reg_unit( 'league' => 4.828032, 'kilometer' );
$self->reg_unit( 1.8288, 'fathom' => 'meter' );
}
return $self;
}
sub formula {
my $self = shift;
return $self->{formula} if !$_[0];
my $formula = shift;
my $gis_formula = $GEO_TO_GIS_FORMULA_MAP{ $formula };
croak(
'Unknown formula (available formulas are ',
join(', ', sort @FORMULAS),
')',
) if !$gis_formula;
$self->{formula} = $formula;
$self->{gis_formula} = $gis_formula;
return $formula;
}
sub distance {
my ($self, $unit, $lon1, $lat1, $lon2, $lat2) = @_;
my $unit_rho = $self->{units}->{$unit};
croak('Unkown unit type "' . $unit . '"') if !$unit_rho;
my $gis = GIS::Distance->new( $self->{gis_formula} );
# Reverse lon/lat to lat/lon, the way GIS::Distance wants it.
my $km = $gis->{code}->( $lat1, $lon1, $lat2, $lon2 );
return $km * ($unit_rho / $KILOMETER_RHO);
}
use Math::Trig qw( acos asin atan deg2rad great_circle_distance pi tan );
sub old_distance {
my($self,$unit,$lon1,$lat1,$lon2,$lat2) = @_;
croak('Unkown unit type "'.$unit.'"') unless($unit = $self->{units}->{$unit});
return 0 if $self->{formula} eq 'null';
return 0 if $self->{formula} eq 'alt';
if($self->{formula} eq 'mt'){
return great_circle_distance(
deg2rad($lon1),
deg2rad(90 - $lat1),
deg2rad($lon2),
deg2rad(90 - $lat2),
$unit
);
}
$lon1 = deg2rad($lon1); $lat1 = deg2rad($lat1);
$lon2 = deg2rad($lon2); $lat2 = deg2rad($lat2);
my $c;
if($self->{formula} eq 'cos'){
my $a = sin($lat1) * sin($lat2);
my $b = cos($lat1) * cos($lat2) * cos($lon2 - $lon1);
$c = acos($a + $b);
}
elsif($self->{formula} eq 'hsin'){
my $dlon = $lon2 - $lon1;
my $dlat = $lat2 - $lat1;
my $a = (sin($dlat/2)) ** 2 + cos($lat1) * cos($lat2) * (sin($dlon/2)) ** 2;
$c = 2 * atan2(sqrt($a), sqrt(abs(1-$a)));
}
elsif($self->{formula} eq 'polar'){
my $a = pi/2 - $lat1;
my $b = pi/2 - $lat2;
$c = sqrt( $a ** 2 + $b ** 2 - 2 * $a * $b * cos($lon2 - $lon1) );
}
elsif($self->{formula} eq 'gcd'){
$c = 2*asin( sqrt(
( sin(($lat1-$lat2)/2) )**2 +
cos($lat1) * cos($lat2) *
( sin(($lon1-$lon2)/2) )**2
) );
# Eric Samuelson recommended this formula.
# http://forums.devshed.com/t54655/sc3d021a264676b9b440ea7cbe1f775a1.html
# http://williams.best.vwh.net/avform.htm
# It seems to produce the same results at the hsin formula, so...
#my $dlon = $lon2 - $lon1;
#my $dlat = $lat2 - $lat1;
#my $a = (sin($dlat / 2)) ** 2
# + cos($lat1) * cos($lat2) * (sin($dlon / 2)) ** 2;
#$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
}
elsif($self->{formula} eq 'tv'){
my($a,$b,$f) = (6378137,6356752.3142,1/298.257223563);
my $l = $lon2 - $lon1;
my $u1 = atan((1-$f) * tan($lat1));
my $u2 = atan((1-$f) * tan($lat2));
my $sin_u1 = sin($u1); my $cos_u1 = cos($u1);
my $sin_u2 = sin($u2); my $cos_u2 = cos($u2);
my $lambda = $l;
my $lambda_pi = 2 * pi;
my $iter_limit = 20;
my($cos_sq_alpha,$sin_sigma,$cos2sigma_m,$cos_sigma,$sigma);
lib/Geo/Distance.pm view on Meta::CPAN
}
undef if( $iter_limit==0 );
my $usq = $cos_sq_alpha*($a*$a-$b*$b)/($b*$b);
my $aa = 1 + $usq/16384*(4096+$usq*(-768+$usq*(320-175*$usq)));
my $bb = $usq/1024 * (256+$usq*(-128+$usq*(74-47*$usq)));
my $delta_sigma = $bb*$sin_sigma*($cos2sigma_m+$bb/4*($cos_sigma*(-1+2*$cos2sigma_m*$cos2sigma_m)-
$bb/6*$cos2sigma_m*(-3+4*$sin_sigma*$sin_sigma)*(-3+4*$cos2sigma_m*$cos2sigma_m)));
$c = ( $b*$aa*($sigma-$delta_sigma) ) / $self->{units}->{meter};
}
else{
croak('Unkown distance formula "'.$self->{formula}.'"');
}
return $unit * $c;
}
sub closest {
my $self = shift;
my %args = @_;
# Set defaults and prepare.
lib/Geo/Distance.pm view on Meta::CPAN
=head1 NAME
Geo::Distance - Calculate distances and closest locations. (DEPRECATED)
=head1 SYNOPSIS
use Geo::Distance;
my $geo = new Geo::Distance;
$geo->formula('hsin');
$geo->reg_unit( 'toad_hop', 200120 );
$geo->reg_unit( 'frog_hop' => 6 => 'toad_hop' );
my $distance = $geo->distance( 'unit_type', $lon1,$lat1 => $lon2,$lat2 );
my $locations = $geo->closest(
dbh => $dbh,
table => $table,
lon => $lon,
lib/Geo/Distance.pm view on Meta::CPAN
lat/lon pairs while Geo::Distance takes lon/lat pairs.
=head1 ARGUMENTS
=head2 no_units
Set this to disable the loading of the default units as described in L</UNITS>.
=head1 ACCESSORS
=head2 formula
if ($geo->formula() eq 'hsin') { ... }
$geo->formula('cos');
Set and get the formula that is currently being used to calculate distances.
See the available L</FORMULAS>.
C<hsin> is the default.
=head1 METHODS
=head2 distance
my $distance = $geo->distance( 'unit_type', $lon1,$lat1 => $lon2,$lat2 );
t/issue-github-2.t view on Meta::CPAN
#!/usr/bin/env perl
use 5.008001;
use strict;
use warnings;
use Test2::V0;
use Geo::Distance;
use Math::Trig qw( asin );
my $geo = Geo::Distance->new();
$geo->formula('gcd');
my $new_value = $geo->distance( 'mile', "-81.044","35.244", "-80.8272","35.1935" );
my $old_value = old_gcd( $geo, 'mile', "-81.044","35.244", "-80.8272","35.1935" );
$geo->formula('hsin');
my $control_value = $geo->distance( 'mile', "-81.044","35.244", "-80.8272","35.1935" );
cmp_ok(
abs($new_value - $control_value), '<', 0.00000000001,
'gcd now produces same result as hsin',
);
cmp_ok(
abs($old_value - $control_value), '>', 0.00000000001,
'old gcd did not produce same result as hsin',
( run in 0.564 second using v1.01-cache-2.11-cpan-3cd7ad12f66 )