Geo-Distance

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

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).

Changes  view on Meta::CPAN


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.

Changes  view on Meta::CPAN

 - 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.

README.md  view on Meta::CPAN

# 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,

README.md  view on Meta::CPAN

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 )