Skip Menu |

This queue is for tickets about the Geo-Calc-XS CPAN distribution.

Report information
The Basics
Id: 89303
Status: resolved
Priority: 0/
Queue: Geo-Calc-XS

People
Owner: Nobody in particular
Requestors: daviddlowe.flimm [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 0.25
Fixed in: 0.27



Subject: Documentation is incorrect, patch included
The documentation for Geo::Calc::XS is incorrect. For example, it says that the unit to be used for boundry_box is 'k-m', when in fact, it is the object's distance unit. I've included a patch which fixes the documentation, and which adds a test that verifies the behaviour of the methods match its documentation. The patch is meant to be applied after the patch in this bug report: https://rt.cpan.org/Public/Bug/Display.html?id=89302
Subject: 0002-Fix-documentation-and-add-test.patch
Makefile.PL | 1 + lib/Geo/Calc/XS.pm | 52 ++++++++++++++++++++------- t/04_units.t | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 13 deletions(-) create mode 100644 t/04_units.t diff --git a/Makefile.PL b/Makefile.PL index 1f7c11d..eeea4d2 100755 --- a/Makefile.PL +++ b/Makefile.PL @@ -18,6 +18,7 @@ WriteMakefile( 'Test::More' => 0, 'Test::Deep' => 0, 'Test::Warn' => 0, + 'Math::Units' => 0, 'Test::NoWarnings' => 0, }, LIBS => [''], # e.g., '-lm' diff --git a/lib/Geo/Calc/XS.pm b/lib/Geo/Calc/XS.pm index b437a9e..19e7fce 100644 --- a/lib/Geo/Calc/XS.pm +++ b/lib/Geo/Calc/XS.pm @@ -71,6 +71,9 @@ Returns ref to a Geo::Calc::XS object. =head2 Parameters +Each of these parameters can be accessed after construction using C<get_lat>, +C<get_lon>, C<get_radius> or C<get_units>. + =over 4 =item lat @@ -85,6 +88,10 @@ C<>=> longitude of the point ( required ) C<>=> earth radius in km ( defaults to 6371 ) +=item units + +C<>=> the distance unit received and output by this object ( default to 'm' ) + =back =cut @@ -109,7 +116,7 @@ angular distance in radians, and a is the square of half the chord length betwee the points). Returns with the distance using the precision defined or -6 -( -6 = 6 decimals ( eg 4.000001 ) ) +( -6 = 6 decimals ( eg 4.000001 ) ), in this object's distance unit. =cut @@ -142,9 +149,9 @@ see http://williams.best.vwh.net/avform.htm#Crs my $f_brng = $gc->final_bearing_to( { lat => 40.422371, lon => -3.704298 } ); my $f_brng = $gc->final_bearing_to( Geo::Calc::XS->new( lat => 40.422371, lon => -3.704298 ) ); -Returns final bearing arriving at supplied destination point from this point; -the final bearing will differ from the initial bearing by varying degrees -according to distance and latitude +Returns final bearing (in degrees) arriving at supplied destination point from +this point; the final bearing will differ from the initial bearing by varying +degrees according to distance and latitude =cut @@ -169,6 +176,9 @@ see http://mathforum.org/library/drmath/view/51822.html for derivation Returns the destination point and the final bearing using Vincenty inverse formula for ellipsoids. +C<$bearing> must be specified in degrees, where 0 is north and 90 is east, and +C<$distance> must be specified in this object's distance unit. + =cut =head2 destination_point_hs @@ -186,12 +196,17 @@ see http://williams.best.vwh.net/avform.htm#LL =head2 boundry_box - $gc->boundry_box( $width[, $height[, $precision]] ); # in km - $gc->boundry_box( 3, 4 ); # will generate a 3x4m box around the point - $gc->boundry_box( 1 ); # will generate a 2x2m box around the point (radius) + $gc->boundry_box( $width[, $height[, $precision]] ); + $gc->boundry_box( 3, 4 ); # will generate a 3x4m box around the point, assuming the object's distance unit is meters + $gc->boundry_box( 1 ); # will generate a 2x2m box around the point (radius), assuming the object's distance unit is meters Returns the boundry box min/max having the initial point defined as the center -of the boundry box, given the widht and height +of the boundry box, given the width and height. + +If only one dimension has been specified, than that dimension is considered a +radius. + +Dimensions should be specified in the object's distance unit. =cut @@ -201,8 +216,8 @@ of the boundry box, given the widht and height $gc->rhumb_distance_to( { lat => 40.422371, lon => -3.704298 } ); $gc->rhumb_distance_to( Geo::Calc::XS->new( lat => 40.422371, lon => -3.704298 ) ); -Returns the distance from this point to the supplied point, in km, travelling -along a rhumb line. +Returns the distance from this point to the supplied point, in the object's +distance unit, travelling along a rhumb line. A 'rhumb line' (or loxodrome) is a path of constant bearing, which crosses all meridians at the same angle. @@ -238,8 +253,9 @@ in degrees $gc->rhumb_destination_point( $brng, $distance[, $precision] ); $gc->rhumb_destination_point( 30, 1 ); -Returns the destination point from this point having travelled the given distance -(in km) on the given bearing along a rhumb line. +Returns the destination point from this point having travelled the given +distance (in the object's distance unit) on the given bearing along a rhumb +line. =cut @@ -258,12 +274,22 @@ see http://williams.best.vwh.net/avform.htm#Intersection =head2 distance_at Returns the distance in meters for 1deg of latitude and longitude at the -specified latitude +specified latitude. my $m_distance = $self->distance_at([$precision]); my $m_distance = $self->distance_at(); # at lat 2 with precision -6 returns { m_lat => 110575.625009, m_lon => 111252.098718 } +Note that this method always returns distances in meters, unlike all the other +methods which use the object's distance unit. This is kept as it is for backwards +compatibility. + +=head1 COMPATIBILITY + +A C<Geo::Calc::XS> object has the same interface as a C<Geo::Calc> object. +However, the results returned by these objects may differ in the latter decimal +points, due to the differing implementation. + =cut =head1 BUGS diff --git a/t/04_units.t b/t/04_units.t new file mode 100644 index 0000000..0d836d0 --- /dev/null +++ b/t/04_units.t @@ -0,0 +1,101 @@ +#!/usr/bin/perl -T + +use strict; +use warnings; + +use Test::More; +use Scalar::Util qw(looks_like_number); +use Math::Units; + +use_ok 'Geo::Calc::XS'; + +my %cardiff = ( + lat => '51.483435', + lon => '-3.213501', +); +my %london = ( + lat => '51.490277', + lon => '-0.181274', +); + +my @units = ("", "m", "k-m", "yd", "ft", "mi"); + +for my $original_unit (@units) { + note "Setting default unit to \"$original_unit\""; + my $gc = Geo::Calc::XS->new( + lat => $cardiff{lat}, + lon => $cardiff{lon}, + ($original_unit ? (units => $original_unit) : ()) + ); + + my $unit = $original_unit || "m"; + + # distance_to + is( + round( $gc->distance_to( \%london ) ), + round( Math::Units::convert( '209954.832717', 'm', $unit ) ), + "distance_to 20km original_unit: \"$original_unit\"" + ); + + # destination_point + is_deeply( + round( $gc->destination_point(0, Math::Units::convert(1, 'm', $unit)) ), + round( { lat => '51.483444', lon => '-3.213501', final_bearing => 0 } ), + "destination_point 1m north" + ); + + # boundary_box + is_deeply( + round( $gc->boundry_box( Math::Units::convert(1, 'm', $unit) ) ), + round( { lat_min => '51.483426', lon_min => '-3.213504', lat_max => '51.483444', lon_max => '-3.213486' } ), + "boundry_box 1m radius" + ); + is_deeply( + round( $gc->boundry_box( Math::Units::convert('0.5', 'm', $unit), Math::Units::convert('0.5', 'm', $unit) ) ), + round( { lat_min => '51.483426', lon_min => '-3.213504', lat_max => '51.483444', lon_max => '-3.213486' } ), + "boundry_box 0.5m width by 0.5m height" + ); + + # rhumb_distance_to + is( + round( $gc->rhumb_distance_to( \%london ) ), + round( Math::Units::convert( '209954.082043', 'm', $unit ) ), + "rhumb_distance_to" + ); + + # distance_at + is_deeply( + $gc->distance_at(), + { m_lat => '111257.478549', m_lon => '69465.660366' }, + "distance_at" + ); + + # rhumb_destination_point + is_deeply( + $gc->rhumb_destination_point( 0, Math::Units::convert( 30, 'm', $unit ) ), + { lat => '51.483705', lon => '-3.213501' }, + "rhumb_destination_point original_unit: \"$original_unit\"" + ); + +} + +done_testing(); + +sub round { + my ( $input ) = @_; + + if ( ref($input) eq 'HASH' ) { + my $result = {}; + for my $key (keys %$input) { + if (looks_like_number( $input->{$key} )) { + $result->{$key} = sprintf("%.2f", $input->{$key}); + } + else { + $result->{$key} = $input->{$key}; + } + } + return $result; + } + + return sprintf("%.2f", $input); +}