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);
+}