CGI-Wiki-Plugin-Locator-UTM
view release on metacpan or search on metacpan
lib/CGI/Wiki/Plugin/Locator/UTM.pm view on Meta::CPAN
}
=item B<coordinates>
my ($zone, $x, $y) = $locator->coordinates( node => "King's Head" );
my ($zone, $x, $y) = $locator->coordinates( lat => 51.507497,
long => -0.271797);
Returns the UTM easting and northing co-ordinates.
See L<Geo::Coordinates::UTM> for the meaning of the zone value.
=cut
sub coordinates {
my ( $self, %args ) = @_;
my ( $lat, $long, $zone, $east, $north );
return @args{qw(zone easting northing)}
if exists( $args{zone} )
&& exists( $args{easting} )
&& exists( $args{northing} );
if ( exists $args{lat} ) {
( $lat, $long ) = @args{qw/lat long/};
}
else {
my $store = $self->datastore;
my %node_data = $store->retrieve_node( $args{node} );
$lat = $node_data{metadata}{lat}[0];
$long = $node_data{metadata}{long}[0];
# Use UTM metadata if it is available
$zone = $node_data{metadata}{zone}[0];
$east = $node_data{metadata}{easting}[0];
$north = $node_data{metadata}{northing}[0];
}
if ( !defined($zone) && !defined($east) && !defined($north) ) {
return undef unless defined($lat) && defined($long);
( $zone, $east, $north ) =
latlon_to_utm( $self->{ellipsoid}, $lat, $long );
}
( $zone, $east, $north );
}
=item B<distance>
# Find the straight-line distance between two nodes, in kilometres.
my $distance = $locator->distance( from_node => "King's Head",
to_node => "Duke Of York" );
# Or in metres between a node and a point.
my $distance = $locator->distance(from_lat => 51.507497,
from_long => -0.271797,
to_node => "Duke of Cambridge",
unit => "metres" );
Defaults to kilometres if C<unit> is not supplied or is not recognised.
Recognised units at the moment: C<metres>, C<kilometres>.
Returns C<undef> if one of the endpoints does not exist, or does not
have both co-ordinates defined.
B<Note:> Works to the nearest metre. Well, actually, calls C<int> and
rounds down, but if anyone cares about that they can send a patch.
=cut
sub distance {
my ( $self, %args ) = @_;
$args{unit} ||= "kilometres";
# Split off the prefix from_ or to_
my ( %from, %to );
while ( my ( $arg, $val ) = each %args ) {
$from{$1} = $val if $arg =~ /from_(.*)/;
$to{$1} = $val if $arg =~ /to_(.*)/;
}
my @from = $self->coordinates(%from);
my @to = $self->coordinates(%to);
return undef unless ( $from[0] and $from[1] and $to[0] and $to[1] );
croak("Locations are in different zones") unless $from[0] eq $to[0];
my $metres =
int( sqrt( ( $from[1] - $to[1] )**2 + ( $from[2] - $to[2] )**2 ) + 0.5 );
if ( $args{unit} eq "metres" ) {
return $metres;
}
else {
return $metres / 1000;
}
}
=item B<find_within_distance>
# Find all the things within 200 metres of a given place.
my @others = $locator->find_within_distance( node => "Albion",
metres => 200 );
# Or within 200 metres of a given location.
my @things = $locator->find_within_distance( lat => 51.507497,
long => -0.271797,
metres => 200 );
Requires the node metadata to be stored in the database, in particular
zone, easting and northing.
Units currently understood: C<metres>, C<kilometres>. If both C<node>
and C<os_x>/C<os_y> are supplied then C<node> takes precedence. Croaks
if insufficient start point data supplied.
=cut
sub find_within_distance {
my ( $self, %args ) = @_;
( run in 2.349 seconds using v1.01-cache-2.11-cpan-9581c071862 )