view release on metacpan or search on metacpan
- Provide a .editorconfig instead of .lvimrc.
0.18 2019-05-10T20:31:31Z
- Switch to the GNU General Public License version 3.
- Fixed pod error as reported by CPANTS.
- Documentation edits.
0.17 2019-03-17T17:01:31Z
- Finalize the new internal formula interface.
0.16 2019-03-16T22:19:33Z
- Renamed the args and module attributes to formula_args
and formula_module to make them less generic and a bit
more accurate.
- Fix a pretty bad math typo in the SPEED section.
- Lots of other documentation edits.
0.15 2019-03-13T06:06:09Z
- Support using Geo::Point as arguments to distance().
- Lots of documentation edits.
- Moved TODO section into GitHub issues.
- Added a benchmark to the SPEED section.
- Made a bunch of improvements to the author tools.
0.14 2019-03-10T05:04:54Z
- Add GIS::Distance::ALT formula.
- Removed distance_km().
0.13 2019-03-09T12:32:55Z
- Add abs() to Haversine.
- Added GIS::Distance::Null, the fastest formula yet.
0.12 2019-03-08T18:32:13Z
- Added the distance_metal() method to GIS::Distance.
- Various documentation edits, including a new SPEED section.
0.11 2019-03-07T22:23:02Z
- Support the GIS_DISTANCE_PP environment variable.
- Don't support older ::Formula modules, makes no sense and
they wouldn't work anyways.
- Declare Carp dep.
- Lots and lots of documentation edits.
- Recommend the newer GIS::Distance::Fast.
0.10 2019-03-07T16:28:48Z
- WARNING: The GIS::Distance object is now immutable, thus the
formula can no longer be set with the formula attribute!
- Moved GIS::Distance::GeoEllipsoid to a separate distro.
- Added the distance_km() method to GIS::Distance.
- Removed Moo and Type::Tiny, all unecessary, simple OO.
- Move GIS::Distance::Formula:: modules to GIS::Distance::.
- Migrate build tooling from Dist::Zilla to Minilla.
0.09 2015-06-11
- Move away from Any::Moose to Moo (yay!).
- Better formula loading logic.
- Support single-arg (formula) GIS::Distance instantiation.
0.08 2012-03-23
- Release with Dist::Zilla.
- Fix Great Circle formula to use ** instead of ^.
0.07 2010-02-02
- Use Any::Moose instead of Moose directly.
- Declare namespace::autoclean dependency.
0.06 2010-01-30
- Minor build updates to include some extra info (github, etc).
- Fixed for latest Moose.
- Fixed for latest Class::Measure.
0.03
- Fixed for latest Moose.
- Reduced the README to a one-liner.
- Added docs to GIS::Distance::Formula.
- Fixed some documentation typos that were using GID instead of GIS.
- Fixed a typo that mispelled "formula" as "formuka".
- Refer to GIS::Distance::Fast in the SEE ALSO section.
- Added a one liner to the SYNOPSIS showing how to used the returned distance object.
- Added a TEST COVERAGE section with output from Devel::Cover.
0.02 2008-03-16
- Added Geoid to the TODO section.
- Using Module::Install now.
- Moved all formulas in to the GIS::Distance::Formula namespace.
- Using Moose for all OO now.
- Added tests (bout time!).
- Added support for the up-and-coming ::Fast:: modules.
- Added (BROKEN) to the abstract for the GreatCircle and Polar formulas.
- Fixed POD testing.
- Changed version scheme to use the simple x.xx format.
0.01001 2006-09-20
- Added basic META.yml.
- Geo::Ellipsoid support.
- Added a TODO section.
- Various bug fixes to the Vincenty formula.
- GreatCircle formula marked as broken.
- Added a dev script for graphing the deviations in the formulas.
0.01000 2006-09-19
- Renamed from Geo::Distance to GIS::Distance.
- Moved distance calculations in to their own modules.
- Use Class::Measure::Length to handle distance return values.
- Test POD syntax.
- Forked from Geo::Distance 0.11.
# NAME
GIS::Distance - Calculate geographic distances.
# SYNOPSIS
```perl
use GIS::Distance;
# Use the GIS::Distance::Haversine formula by default.
my $gis = GIS::Distance->new();
# Or choose a different formula.
my $gis = GIS::Distance->new( 'Polar' );
# Returns a Class::Measure object.
my $distance = $gis->distance( $lat1, $lon1, $lat2, $lon2 );
print $distance->meters();
```
# DESCRIPTION
This module calculates distances between geographic points on, at the moment,
planet Earth. Various ["FORMULAS"](#formulas) are available that provide different levels
of accuracy versus speed.
[GIS::Distance::Fast](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3AFast), a separate distribution, ships with C implementations of
some of the formulas shipped with GIS::Distance. If you're looking for speed
then install it and the ::Fast formulas will be automatically used by this module.
# METHODS
## distance
```perl
my $distance = $gis->distance( $lat1, $lon1, $lat2, $lon2 );
my $point1 = Geo::Point->latlong( $lat1, $lon1 );
my $point2 = Geo::Point->latlong( $lat2, $lon2 );
## distance\_metal
This works just like ["distance"](#distance) except for:
- Does not accept [Geo::Point](https://metacpan.org/pod/Geo%3A%3APoint) objects. Only decimal latitude and longitude
pairs.
- Does not return a [Class::Measure](https://metacpan.org/pod/Class%3A%3AMeasure) object. Instead kilometers are always
returned.
- Does no argument checking.
- Does not support formula arguments which are supported by at least the
[GIS::Distance::GeoEllipsoid](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3AGeoEllipsoid) formula.
Calling this gets you pretty close to the fastest bare metal speed you can get.
The speed improvements of calling this is noticeable over hundreds of thousands of
iterations only and you've got to decide if its worth the safety and features
you are dropping. Read more in the ["SPEED"](#speed) section.
# ARGUMENTS
```perl
my $gis = GIS::Distance->new( $formula );
```
When you call `new()` you may pass a partial or full formula class name as the
first argument. The default is `Haversive`.
If you pass a partial name, as in:
```perl
my $gis = GIS::Distance->new( 'Haversine' );
```
Then the following modules will be looked for in order:
```
GIS::Distance::Fast::Haversine
GIS::Distance::Haversine
Haversine
```
Install [GIS::Distance::Fast](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3AFast) to get access to the `Fast::` (XS) implementations
of the formula classes.
You may globally disable the automatic use of the `Fast::` formulas by setting
the `GIS_DISTANCE_PP` environment variable. Although, its likely simpler to
just provide a full class name to get the same effect:
```perl
my $gis = GIS::Distance->new( 'GIS::Distance::Haversine' );
```
# SPEED
Not that this module is slow, but if you're doing millions of distance
calculations a second you may find that adjusting your code a bit may
make it faster. Here are some options.
Install [GIS::Distance::Fast](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3AFast) to get the XS variants for most of the
PP formulas.
Use ["distance\_metal"](#distance_metal) instead of ["distance"](#distance).
Call the undocumented `_distance()` function that each formula class
has. For example you could bypass this module entirely and just do:
```perl
use GIS::Distance::Fast::Haversine;
my $km = GIS::Distance::Fast::Haversine::_distance( @coords );
```
The above would be the ultimate speed demon (as shown in benchmarking)
but throws away some flexibility and adds some foot-gun support.
# Precision Six Integer to Decimal
my $decimal = $integer * .000001;
```
If you want to convert from decimal radians to degrees you can use [Math::Trig](https://metacpan.org/pod/Math%3A%3ATrig)'s
rad2deg function.
# FORMULAS
These formulas come bundled with this distribution:
- [GIS::Distance::ALT](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3AALT)
- [GIS::Distance::Cosine](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3ACosine)
- [GIS::Distance::GreatCircle](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3AGreatCircle)
- [GIS::Distance::Haversine](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3AHaversine)
- [GIS::Distance::MathTrig](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3AMathTrig)
- [GIS::Distance::Null](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3ANull)
- [GIS::Distance::Polar](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3APolar)
- [GIS::Distance::Vincenty](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3AVincenty)
These formulas are available on CPAN:
- ["FORMULAS" in GIS::Distance::Fast](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3AFast#FORMULAS)
- [GIS::Distance::GeoEllipsoid](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3AGeoEllipsoid)
# AUTHORING
Take a look at [GIS::Distance::Formula](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3AFormula) for instructions on authoring
new formula classes.
# SEE ALSO
- [Geo::Distance](https://metacpan.org/pod/Geo%3A%3ADistance) - Is deprecated in favor of using this module.
- [Geo::Distance::Google](https://metacpan.org/pod/Geo%3A%3ADistance%3A%3AGoogle) - While in the Geo::Distance namespace, this isn't
actually related to Geo::Distance at all. Might be useful though.
- [GIS::Distance::Lite](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3ALite) - An old fork of this module, not recommended.
- [Geo::Distance::XS](https://metacpan.org/pod/Geo%3A%3ADistance%3A%3AXS) - Used to be used by [Geo::Distance](https://metacpan.org/pod/Geo%3A%3ADistance) but no longer is.
- [Geo::Ellipsoid](https://metacpan.org/pod/Geo%3A%3AEllipsoid) - Or use [GIS::Distance::GeoEllipsoid](https://metacpan.org/pod/GIS%3A%3ADistance%3A%3AGeoEllipsoid) for a uniform
interface.
author/bench view on Meta::CPAN
use List::Util qw( any );
use List::MoreUtils qw( zip uniq );
use Module::Find qw( findallmod );
use Getopt::Long;
Getopt::Long::Configure(qw(
gnu_getopt no_ignore_case
));
GetOptions(
'formula|f=s' => \my @formulas,
'pp!' => \my $do_pp,
'xs!' => \my $do_xs,
'geo' => \my $do_geo,
'iters|i=i' => \my $iters,
'dry-run|n' => \my $dry_run,
'h|help' => \my $help,
) or die "Unable to process options!\n";
if ($help) {
require Pod::Usage;
Pod::Usage::pod2usage( -verbose => 2 );
exit 0;
}
@formulas = split(/,/, join(',', @formulas));
$iters ||= 5_000_000;
$do_pp = 1 if !defined $do_pp;
$do_xs = 1 if !defined $do_xs;
my %gis_to_geo;
if ($do_geo) {
require Geo::Distance;
author/bench view on Meta::CPAN
my @installed_modules = (
grep { $_ !~ m{::Formula} }
grep { $_ ne 'GIS::Distance::Constants' }
grep { $_ ne 'GIS::Distance::Fast' }
findallmod('GIS::Distance')
);
my %installed_modules_lookup = map { $_=>1 } @installed_modules;
my @all_formulas = (
uniq
map { s{^GIS::Distance::}{}r }
map { s{^GIS::Distance::Fast::}{}r }
@installed_modules
);
@formulas = @all_formulas if !@formulas;
my @coords = ( 34.202361, -118.601875, 37.752258, -122.441254 );
my @geo_coords = @coords[1,0,3,2];
my @tests;
foreach my $formula (sort @formulas) {
my $pp_module = "GIS::Distance::$formula";
if ($do_pp and $installed_modules_lookup{$pp_module}) {
my $gis = GIS::Distance->new( $pp_module );
my $code = $pp_module->can('_distance');
push @tests, (
["PP $formula - GIS::Distance->distance" => sub{
return $gis->distance( @coords )->km();
}],
["PP $formula - GIS::Distance->distance_metal" => sub{
return $gis->distance_metal( @coords );
}],
["PP $formula - $pp_module\::_distance" => sub{
return $code->( @coords );
}],
);
}
my $xs_module = "GIS::Distance::Fast::$formula";
if ($do_xs and $installed_modules_lookup{$xs_module}) {
my $gis = GIS::Distance->new( $xs_module );
my $code = $xs_module->can('_distance');
push @tests, (
["XS $formula - GIS::Distance->distance" => sub{
return $gis->distance( @coords )->km();
}],
["XS $formula - GIS::Distance->distance_metal" => sub{
return $gis->distance_metal( @coords );
}],
["XS $formula - $xs_module\::_distance" => sub{
return $code->( @coords );
}],
);
}
my $geo_formula = $gis_to_geo{ $formula };
if ($do_geo and $geo_formula) {
my $geo = Geo::Distance->new();
$geo->formula( $geo_formula );
push @tests, (
["PP $geo_formula - Geo::Distance->old_distance" => sub{
return $geo->old_distance( 'kilometer', @geo_coords );
}],
) if $do_pp;
push @tests, (
["XS $geo_formula - Geo::Distance->new_distance" => sub{
return $geo->new_distance( 'kilometer', @geo_coords );
}],
["XS $geo_formula - Geo::Distance::XS->distance" => sub{
return $geo->distance( 'kilometer', @geo_coords );
}],
["XS $geo_formula - Geo::Distance::XS::distance" => sub{
return Geo::Distance::XS::distance(
$geo, 'kilometer', @geo_coords,
);
}],
) if $do_xs;
}
}
if ($dry_run) {
print "Tests to run:\n";
author/bench view on Meta::CPAN
cmpthese(
$iters,
{ map { @$_ } @tests },
);
__END__
=head1 NAME
author/bench - Benchmark formulas and the various interfaces to them.
=head1 SYNOPSIS
# Benchmark every GIS::Distance and GIS::Distance::Fast formula.
author/bench
# Show which benchmarks would be run for every GIS::Distance::Fast
# and Geo::Distance::XS formula, but don't run them.
author/bench --geo --no-pp --dry-run
# Displays this handy documentation!
author/bench --help
=head1 OPTIONS
=head2 formula
--formula=<formula-short-name>
--formaul=Null
-f Haversine -f Cosine
By default all formulas will be considered for benchmarking.
If you'd like to limit this then you can specify one or more
formulas with this option.
=head2 pp
--no-pp
Disable the C<pp> option, meaning no pure-perl formulas will
be included.
=head2 xs
--no-xs
Disable the C<xs> option, meaning no XS formulas will
be included.
=head2 geo
--geo
L<Geo::Distance> and/or L<Geo::Distance::XS> formulas will be
included.
=head2 iters
--iters=100
-i 10000000
The number of iterations to benchmark each formula against.
The default is C<5,000,000>.
=head2 dry-run
--dry-run
-n
Lists all the benchmarks which would be run, but does not run them.
author/distances view on Meta::CPAN
# Beirut to Dimashq.
@coords = ( 33.863146, 35.52824, 33.516496, 36.287842 );
# https://github.com/bluefeet/Geo-Distance/issues/15
#@coords = ( 52.484977, 13.385900, 52.485033, 13.370897 );
my %distances;
{
my @formulas = (
grep { $_ !~ m{::Formula} }
grep { $_ ne 'GIS::Distance::Constants' }
grep { $_ ne 'GIS::Distance::Fast' }
findallmod('GIS::Distance')
);
@formulas = (
grep { $_ !~ m{::Fast::} }
@formulas
) if !$do_xs;
@formulas = (
grep { $_ =~ m{::Fast::} }
@formulas
) if !$do_pp;
foreach my $formula (@formulas) {
my $gis = GIS::Distance->new( $formula );
my $km = $gis->distance( @coords )->km();
$distances{ $formula } = $km;
}
}
if ($do_geo and $do_pp) {
require Geo::Distance;
Geo::Distance->import();
my @formulas = @Geo::Distance::FORMULAS;
foreach my $formula (@formulas) {
my $geo = Geo::Distance->new();
$geo->formula( $formula );
my $km = $geo->old_distance( 'kilometer', reverse @coords );
$distances{ "Geo::Distance-$formula" } = $km;
}
}
if ($do_geo and $do_xs) {
require Geo::Distance::XS;
Geo::Distance::XS->import();
my @formulas = @Geo::Distance::XS::FORMULAS;
foreach my $formula (@formulas) {
my $geo = Geo::Distance->new();
$geo->formula( $formula );
my $km = $geo->distance( 'kilometer', reverse @coords );
$distances{ "Geo::Distance::XS-$formula" } = $km;
}
}
my %formulas_by_distance;
foreach my $formula (keys %distances) {
my $distance = sprintf("%.0${precision}f", $distances{$formula});
my $formulas = $formulas_by_distance{ $distance } ||= [];
push @$formulas, $formula;
}
foreach my $distance (sort keys %formulas_by_distance) {
print "$distance:\n";
print map { " - $_\n" } sort @{ $formulas_by_distance{$distance} };
}
__END__
=head1 NAME
author/distances - Display the distance generated by all the formulas.
=head1 SYNOPSIS
# List distances for every GIS::Distance and GIS::Distance::Fast
# formula.
author/distances
# List distances for every GIS::Distance::Fast and
# Geo::Distance::XS formula.
author/distances --geo --no-pp
# Displays this handy documentation!
author/distances --help
=head1 OPTIONS
=head2 pp
--no-pp
Disable the C<pp> option, meaning no pure-perl formulas will
be included.
=head2 xs
--no-xs
Disable the C<xs> option, meaning no XS formulas will
be included.
=head2 geo
--geo
L<Geo::Distance> and/or L<Geo::Distance::XS> formulas will be
included.
=head2 precision
--precision=14
-p 8
When grouping formulas format the timing to this number of
decimal places.
The default is C<12>, which does a good job of grouping the
formulas which really are producing the exact same result.
=head2 help
--help
-h
Displays this handy documentation!
=head1 AUTHORS AND LICENSE
lib/GIS/Distance.pm view on Meta::CPAN
package GIS::Distance;
use 5.008001;
use strictures 2;
our $VERSION = '0.20';
sub new {
my ($class, $formula, @args) = @_;
$formula ||= 'Haversine';
my @modules;
push @modules, "GIS::Distance::Fast::${formula}"
unless $ENV{GIS_DISTANCE_PP} or $ENV{GEO_DISTANCE_PP};
push @modules, "GIS::Distance::$formula";
push @modules, $formula;
foreach my $module (@modules) {
next if !_try_load_module( $module );
next if !$module->isa('GIS::Distance::Formula');
return $module->new( @args );
}
die "Cannot find a GIS::Distance::Formula class for $formula";
};
my %tried_modules;
sub _try_load_module {
my ($module) = @_;
return $tried_modules{ $module }
if defined $tried_modules{ $module };
lib/GIS/Distance.pm view on Meta::CPAN
=encoding utf8
=head1 NAME
GIS::Distance - Calculate geographic distances.
=head1 SYNOPSIS
use GIS::Distance;
# Use the GIS::Distance::Haversine formula by default.
my $gis = GIS::Distance->new();
# Or choose a different formula.
my $gis = GIS::Distance->new( 'Polar' );
# Returns a Class::Measure object.
my $distance = $gis->distance( $lat1, $lon1, $lat2, $lon2 );
print $distance->meters();
=head1 DESCRIPTION
This module calculates distances between geographic points on, at the moment,
planet Earth. Various L</FORMULAS> are available that provide different levels
of accuracy versus speed.
L<GIS::Distance::Fast>, a separate distribution, ships with C implementations of
some of the formulas shipped with GIS::Distance. If you're looking for speed
then install it and the ::Fast formulas will be automatically used by this module.
=head1 METHODS
=head2 distance
my $distance = $gis->distance( $lat1, $lon1, $lat2, $lon2 );
my $point1 = Geo::Point->latlong( $lat1, $lon1 );
my $point2 = Geo::Point->latlong( $lat2, $lon2 );
my $distance = $gis->distance( $point1, $point2 );
lib/GIS/Distance.pm view on Meta::CPAN
Does not return a L<Class::Measure> object. Instead kilometers are always
returned.
=item *
Does no argument checking.
=item *
Does not support formula arguments which are supported by at least the
L<GIS::Distance::GeoEllipsoid> formula.
=back
Calling this gets you pretty close to the fastest bare metal speed you can get.
The speed improvements of calling this is noticeable over hundreds of thousands of
iterations only and you've got to decide if its worth the safety and features
you are dropping. Read more in the L</SPEED> section.
=head1 ARGUMENTS
my $gis = GIS::Distance->new( $formula );
When you call C<new()> you may pass a partial or full formula class name as the
first argument. The default is C<Haversive>.
If you pass a partial name, as in:
my $gis = GIS::Distance->new( 'Haversine' );
Then the following modules will be looked for in order:
GIS::Distance::Fast::Haversine
GIS::Distance::Haversine
Haversine
Install L<GIS::Distance::Fast> to get access to the C<Fast::> (XS) implementations
of the formula classes.
You may globally disable the automatic use of the C<Fast::> formulas by setting
the C<GIS_DISTANCE_PP> environment variable. Although, its likely simpler to
just provide a full class name to get the same effect:
my $gis = GIS::Distance->new( 'GIS::Distance::Haversine' );
=head1 SPEED
Not that this module is slow, but if you're doing millions of distance
calculations a second you may find that adjusting your code a bit may
make it faster. Here are some options.
Install L<GIS::Distance::Fast> to get the XS variants for most of the
PP formulas.
Use L</distance_metal> instead of L</distance>.
Call the undocumented C<_distance()> function that each formula class
has. For example you could bypass this module entirely and just do:
use GIS::Distance::Fast::Haversine;
my $km = GIS::Distance::Fast::Haversine::_distance( @coords );
The above would be the ultimate speed demon (as shown in benchmarking)
but throws away some flexibility and adds some foot-gun support.
Here's a benchmarks for these options:
lib/GIS/Distance.pm view on Meta::CPAN
my $decimal = $degrees + ($minutes/60) + ($seconds/3600);
# Precision Six Integer to Decimal
my $decimal = $integer * .000001;
If you want to convert from decimal radians to degrees you can use L<Math::Trig>'s
rad2deg function.
=head1 FORMULAS
These formulas come bundled with this distribution:
=over
=item *
L<GIS::Distance::ALT>
=item *
L<GIS::Distance::Cosine>
lib/GIS/Distance.pm view on Meta::CPAN
=item *
L<GIS::Distance::Polar>
=item *
L<GIS::Distance::Vincenty>
=back
These formulas are available on CPAN:
=over
=item *
L<GIS::Distance::Fast/FORMULAS>
=item *
L<GIS::Distance::GeoEllipsoid>
=back
=head1 AUTHORING
Take a look at L<GIS::Distance::Formula> for instructions on authoring
new formula classes.
=head1 SEE ALSO
=over
=item *
L<Geo::Distance> - Is deprecated in favor of using this module.
=item *
lib/GIS/Distance/ALT.pm view on Meta::CPAN
__END__
=encoding utf8
=head1 NAME
GIS::Distance::ALT - Andoyer-Lambert-Thomas distance calculations.
=head1 DESCRIPTION
The ALT formula is intended as a much faster, but slightly less accurate,
alternative of the L<GIS::Distance::Vincenty> formula. This formulas is
about 5x faster than Vincenty.
The code for this formula was taken from L<Geo::Distance::XS> and
modified to fit.
A faster (XS) version of this formula is available as
L<GIS::Distance::Fast::ALT>.
Normally this module is not used directly. Instead L<GIS::Distance>
is used which in turn interfaces with the various formula classes.
=head1 SUPPORT
See L<GIS::Distance/SUPPORT>.
=head1 AUTHORS
See L<GIS::Distance/AUTHORS>.
=head1 LICENSE
lib/GIS/Distance/Constants.pm view on Meta::CPAN
const our $DEG_RATIO => 0.0174532925199433;
push @EXPORT_OK, '$DEG_RATIO';
1;
__END__
=encoding utf8
=head1 NAME
GIS::Distance::Constants - Constants used by formula classes.
=head1 CONSTANTS
=head2 $KILOMETER_RHO
Number of kilometers around the equator of the earth.
C<6371.64>
=head2 $DEG_RATIO
lib/GIS/Distance/Cosine.pm view on Meta::CPAN
__END__
=encoding utf8
=head1 NAME
GIS::Distance::Cosine - Spherical law of cosines distance calculations.
=head1 DESCRIPTION
Although this formula is mathematically exact, it is unreliable for
small distances. See L<GIS::Distance::MathTrig> for related details.
A faster (XS) version of this formula is available as
L<GIS::Distance::Fast::Cosine>.
Normally this module is not used directly. Instead L<GIS::Distance>
is used which in turn interfaces with the various formula classes.
=head1 FORMULA
a = sin(lat1) * sin(lat2)
b = cos(lat1) * cos(lat2) * cos(lon2 - lon1)
c = arccos(a + b)
d = R * c
=head1 SEE ALSO
lib/GIS/Distance/Formula.pm view on Meta::CPAN
__END__
=encoding utf8
=head1 NAME
GIS::Distance::Formula - Formula base class.
=head1 DESCRIPTION
This is the parent class for all L<GIS::Distance> formula classes such as
those listed at L<GIS::Distance/FORMULAS>.
To author your own formula class:
package My::Formula;
use parent 'GIS::Distance::Formula';
sub _distance {
my ($lat1, $lon1, $lat2, $lon2) = @_;
# ...
lib/GIS/Distance/GreatCircle.pm view on Meta::CPAN
=encoding utf8
=head1 NAME
GIS::Distance::GreatCircle - Great circle distance calculations.
=head1 DESCRIPTION
A true Great Circle Distance calculation. This was created because the
L<GIS::Distance::MathTrig> formula uses L<Math::Trig>'s
C<great_circle_distance()> which doesn't actually appear to use the
actual Great Circle Distance formula (more likely Cosine).
A faster (XS) version of this formula is available as
L<GIS::Distance::Fast::GreatCircle>.
Normally this module is not used directly. Instead L<GIS::Distance>
is used which in turn interfaces with the various formula classes.
=head1 FORMULA
c = 2 * asin( sqrt(
( sin(( lat1 - lat2 )/2) )**2 +
cos( lat1 ) * cos( lat2 ) *
( sin(( lon1 - lon2 )/2) )**2
) )
=head1 SUPPORT
lib/GIS/Distance/Haversine.pm view on Meta::CPAN
$lat2 = deg2rad($lat2);
my $dlon = $lon2 - $lon1;
my $dlat = $lat2 - $lat1;
my $a = (sin($dlat/2)) ** 2 + cos($lat1) * cos($lat2) * (sin($dlon/2)) ** 2;
my $c = 2 * atan2(sqrt($a), sqrt(abs(1-$a)));
return $KILOMETER_RHO * $c;
}
# 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));
#
# Maybe test for speed before tossing?
1;
lib/GIS/Distance/Haversine.pm view on Meta::CPAN
=head1 NAME
GIS::Distance::Haversine - Exact spherical distance calculations.
=head1 DESCRIPTION
This is the default distance calculation for L<GIS::Distance> as
it keeps a good balance between speed and accuracy.
A faster (XS) version of this formula is available as
L<GIS::Distance::Fast::Haversine>.
Normally this module is not used directly. Instead L<GIS::Distance>
is used which in turn interfaces with the various formula classes.
=head1 FORMULA
dlon = lon2 - lon1
dlat = lat2 - lat1
a = (sin(dlat/2))^2 + cos(lat1) * cos(lat2) * (sin(dlon/2))^2
c = 2 * atan2( sqrt(a), sqrt(1-a) )
d = R * c
=head1 SEE ALSO
lib/GIS/Distance/MathTrig.pm view on Meta::CPAN
__END__
=encoding utf8
=head1 NAME
GIS::Distance::MathTrig - Great cirlce distance calculations using Math::Trig.
=head1 DESCRIPTION
This formula uses L<Math::Trig>'s C<great_circle_distance()> which
at this time uses math almost exactly the same formula as the
L<GIS::Distance::Cosine> formula. And the Cosine formula is about 5%
faster than this formula.
Normally this module is not used directly. Instead L<GIS::Distance>
is used which in turn interfaces with the various formula classes.
=head1 FORMULA
lat0 = 90 degrees - phi0
lat1 = 90 degrees - phi1
d = R * arccos(cos(lat0) * cos(lat1) * cos(lon1 - lon01) + sin(lat0) * sin(lat1))
As stated in the L<Math::Trig> documentation.
=head1 SUPPORT
lib/GIS/Distance/Null.pm view on Meta::CPAN
=encoding utf8
=head1 NAME
GIS::Distance::Null - For planets with no surface.
=head1 DESCRIPTION
Always returns C<0>.
A faster (XS) version of this formula is available as
L<GIS::Distance::Fast::Null>.
Normally this module is not used directly. Instead L<GIS::Distance>
is used which in turn interfaces with the various formula classes.
=head1 FORMULA
d = 0
=head1 SEE ALSO
=over
=item *
lib/GIS/Distance/Polar.pm view on Meta::CPAN
__END__
=encoding utf8
=head1 NAME
GIS::Distance::Polar - Polar coordinate flat-earth distance calculations.
=head1 DESCRIPTION
Supposedly this is a formula to better calculate distances at the
poles.
While implemented, this formula has not been tested much. If you use it
PLEASE share your results with the author. I've tested the results of this
formula versus L<GIS::Distance::Vincenty> and it appears that this formula
is broken (or the implementation is) as you can see in C<t/polar.t>.
A faster (XS) version of this formula is available as
L<GIS::Distance::Fast::Polar>.
Normally this module is not used directly. Instead L<GIS::Distance>
is used which in turn interfaces with the various formula classes.
=head1 FORMULA
a = pi/2 - lat1
b = pi/2 - lat2
c = sqrt( a^2 + b^2 - 2 * a * b * cos(lon2 - lon1) )
d = R * c
=head1 SUPPORT
lib/GIS/Distance/Vincenty.pm view on Meta::CPAN
=encoding utf8
=head1 NAME
GIS::Distance::Vincenty - Thaddeus Vincenty distance calculations.
=head1 DESCRIPTION
For the benefit of the terminally obsessive (as well as the genuinely needy),
Thaddeus Vincenty devised formulae for calculating geodesic distances between
a pair of latitude/longitude points on the earth's surface, using an accurate
ellipsoidal model of the earth.
Vincenty's formula is accurate to within 0.5mm, or 0.000015", on the ellipsoid
being used. Calculations based on a spherical model, such as the (much simpler)
Haversine, are accurate to around 0.3% (which is still good enough for most
purposes).
The accuracy quoted by Vincenty applies to the theoretical ellipsoid
being used, which will differ (to varying degree) from the real earth geoid.
If you happen to be located in Colorado, 2km above msl, distances will be 0.03%
greater. In the UK, if you measure the distance from Land's End to John O'
Groats using WGS-84, it will be 28m - 0.003% - greater than using the Airy
ellipsoid, which provides a better fit for the UK.
Take a look at the L<GIS::Distance::ALT> formula for a much quicker
alternative with nearly the same accuracy.
A faster (XS) version of this formula is available as
L<GIS::Distance::Fast::Vincenty>.
Normally this module is not used directly. Instead L<GIS::Distance>
is used which in turn interfaces with the various formula classes.
=head1 FORMULA
a, b = major & minor semiaxes of the ellipsoid
f = flattening (a-b)/a
L = lon2 - lon1
u1 = atan((1-f) * tan(lat1))
u2 = atan((1-f) * tan(lat2))
sin_u1 = sin(u1)
cos_u1 = cos(u1)
t/accuracy.t view on Meta::CPAN
my $test_cases = {
'Canoga Park to San Francisco' => [ 34.202361, -118.601875, 37.752258, -122.441254, 524.347542197146, 'km'],
'Egypt to Anchorage' => [ 26.185018, 30.047607, 61.147543, -149.81575, 10324.656666156, 'km'],
'London to Sydney' => [ 51.497736, -0.115356, -33.81966, 151.169472, 16982.5402359324, 'km'],
'Santiago to Rio de Janeiro' => [-33.446339, -70.63591, -22.902981, -43.213177, 2923.66733201558, 'km'],
'Beirut to Dimashq' => [ 33.863146, 35.52824, 33.516496, 36.287842, 80241.1054436632, 'm' ],
};
my $test_case_count = @{[ keys %$test_cases ]} + 0;
my $formulas = [qw( ALT Cosine GreatCircle Haversine MathTrig Vincenty )];
foreach my $formula (@$formulas) {
subtest "run $formula" => sub {
test_formula( $formula );
done_testing;
};
}
done_testing;
sub test_formula {
my ($formula) = @_;
my $gis = GIS::Distance->new( "GIS::Distance::$formula" );
foreach my $title (keys %$test_cases) {
my $case = $test_cases->{$title};
my $unit = $case->[5];
my $distance = $case->[4];
my $length = $gis->distance( $case->[0], $case->[1], $case->[2], $case->[3] )->$unit();
is_close( $length, $distance, $title );
}
}
use GIS::Distance;
my @coords = ( -84.302183, 58.886719, -81.24166, -154.951172 );
my $vincenty = GIS::Distance->new( 'GIS::Distance::Vincenty' );
my $polar = GIS::Distance->new( 'GIS::Distance::Polar' );
my $v_length = $vincenty->distance( @coords );
my $p_length = $polar->distance( @coords );
todo 'Polar formula is broken' => sub{
is_close( $v_length->km(), $p_length->km(), 'Vincenty versus Polar' );
};
sub is_close {
my ($num1, $num2, $description) = @_;
my $lossy = $num2 * 0.01;
if (($num1 > $num2 + $lossy) or ($num1 < $num2 - $lossy)) {
fail( "$description - $num1 != $num2" );
}
else {