The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Geo::WebService::Elevation::USGS - Elevation queries against USGS web services.

SYNOPSIS

 use Geo::WebService::Elevation::USGS;
 
 my $eq = Geo::WebService::Elevation::USGS->new();
 print "The elevation of the White House is ",
   $eq->elevation( 38.898748, -77.037684 )->{Elevation},
   " feet above sea level.\n";

NOTICE

The GIS data web service this module was originally based on has gone the way of the dodo. This release uses the NED service, which is similar but simpler. I have taken advantage of the new service's ability to provide output in JSON to simplify processing, and have added a compatibility mode to make the output from the new service as much like the output of the old as possible, but there are still differences:

* The new service does not expose data source selection. Therefore all functionality related to selecting data from a particular source now does nothing.

* The new service does not support retrieval of data from more than one source. Therefore any functionality that used to do this now returns data from a single source.

* The new service does not return the {Data_ID} information in any way whatsoever. So, at least in compatibility mode, this is set to the value of {Data_Source}.

* The new service does not report extent errors. Instead it appears to return an elevation of 0.

* The structure returned by the new service is similar to that returned by the old service, but the top-level hash key name is different. This module will attempt to hide this difference in compatibility mode.

Because this module attempts to hide the differences from the data returned by the old service, a new attribute, compatible, is added to manage this. If this attribute is true (the default) returned data will be as close to the old server's data as possible.

With release 0.100, the following functionality is deprecated:

* Attributes default_ns, proxy, source, and use_all_limit.

* Methods getElevation() and getAllElevations(). The elevation() method will remain.

Starting with release 0.104_01, all deprecated functionality will warn every time it is used. Six months after that it will become fatal. After a further six months, all code related to the deprecated functionality will be removed.

In the meantime you can suppress the warnings with

 no warnings qw{ deprecated };

At the point where the deprecated functionality warns on every use, the compatible attribute will also become deprecated. Six months after that, its default will become false, and it will warn when set true. Six months after that it will become a fatal error to use it.

DESCRIPTION

This module executes elevation queries against the United States Geological Survey's web NAD server. You provide the latitude and longitude in degrees, with south latitude and west longitude being negative. The return is typically a hash containing the data you want. Query errors are exceptions by default, though the object can be configured to signal an error by an undef response, with the error retrievable from the 'error' attribute.

For documentation on the underlying web service, see http://ned.usgs.gov.

For all methods, the input latitude and longitude are documented at the above web site as being WGS84, which for practical purposes I understand to be equivalent to NAD83. The vertical reference is not documented under the above link, but correspondence with the USGS says that it is derived from the National Elevation Dataset (NED; see http://ned.usgs.gov). This is referred to NAD83 (horizontal) and NAVD88 (vertical). NAVD88 is based on geodetic leveling surveys, not the WGS84/NAD83 ellipsoid, and takes as its zero datum sea level at Father Point/Rimouski, in Quebec, Canada. Alaska is an exception, and is based on NAD27 (horizontal) and NAVD29 (vertical).

Anyone interested in the gory details may find the paper Converting GPS Height into NAVD88 Elevation with the GEOID96 Geoid Height Model by Dennis G. Milbert, Ph.D. and Dru A. Smith, Ph.D helpful. This is available at http://www.ngs.noaa.gov/PUBS_LIB/gislis96.html. This paper states that the difference between ellipsoid and geoid heights ranges between -75 and +100 meters globally, and between -53 and -8 meters in "the conterminous United States."

Methods

The following public methods are provided:

$eq = Geo::WebService::Elevation::USGS->new();

This method instantiates a query object. If any arguments are given, they are passed to the set() method. The instantiated object is returned.

%values = $eq->attributes();

This method returns a list of the names and values of all attributes of the object. If called in scalar context it returns a hash reference.

$rslt = $usgs->elevation($lat, $lon, $valid);

This method queries the data base for the elevation at the given latitude and longitude, returning the results as a hash reference. This hash will contain the following keys:

{Data_Source} => A text description of the data source;

{Elevation} => The elevation in the given units;

{Units} => The units of the elevation ('Feet' or 'Meters');

{x} => The $lon argument;

{y} => The $lat argument.

For compatibility with versions of this module before 0.100, this method behaves slightly differently if the compatible attribute is true:

* The {Data_ID} key of the return will be set to the value of the {Data_Source} key;

* The {Units} key will be converted to upper case;

* If called in scalar context the return will be a reference to an array whose single element is the results hash.

You can also pass a Geo::Point, GPS::Point, or Net::GPSD::Point object in lieu of the $lat and $lon arguments. If you do this, $valid becomes the second argument, rather than the third.

If the optional $valid argument is specified and the returned data are invalid, nothing is returned. This means an empty array if compatible is true. The NAD source does not seem to produce data recognizable as invalid, so you will probably not see this.

The NAD server appears to return an elevation of 0 if the elevation is unavailable.

$value = $eq->get($attribute);

This method returns the value of the given attribute. It will croak if the attribute does not exist.

$rslt = $eq->getAllElevations($lat, $lon, $valid);

Starting with version 0.100, this method is essentially a wrapper for the elevation() method. For compatibility with the prior version of this module it returns an array reference in scalar context.

$rslt = $eq->getElevation($lat, $lon, $source, $elevation_only);

Starting with version 0.100, this method is essentially a wrapper for the elevation() method.

The $source argument is both optional and ignored, but must be present for backwards compatibility if the $elevation_only argument is used. Feel free to pass undef.

The $elevation_only argument is optional. If provided and true (in the Perl sense) it causes the return on success to be the numeric value of the elevation, rather than the hash reference described below.

$boolean = $eq->is_valid($elevation);

This method (which can also be called as a static method or as a subroutine) returns true if the given datum represents a valid elevation, and false otherwise. A valid elevation is a number having a value greater than -1e+300. The input can be either an elevation value or a hash whose {Elevation} key supplies the elevation value.

$eq = $eq->set($attribute => $value ...);

This method sets the value of the given attribute. Multiple attribute/value pairs may be specified. The object itself is returned, to allow call chaining. An attempt to set a non-existent attribute will result in an exception being thrown.

Attributes

carp (boolean)

This boolean attribute determines whether the data acquisition methods carp on encountering an error. If false, they silently return undef. Note, though, that the croak attribute trumps this one.

If retry is set to a number greater than 0, you will get a carp on each failed query, provided croak is false. If croak is true, no retries will be carped.

This attribute was introduced in Geo::WebService::Elevation::USGS version 0.005_01.

The default is 0 (i.e. false).

compatible (boolean)

This boolean attribute determines whether this object attempts to make returned data consistent with the old GIS server.

The default is 1 (i.e. true) for the moment, but see the NOTICE above for plans to change this.

croak (boolean)

This attribute determines whether the data acquisition methods croak on encountering an error. If false, they return undef on an error.

If retry is set to a number greater than 0, the data acquisition method will not croak until all retries are exhausted.

The default is 1 (i.e. true).

default_ns (string)

This attribute is deprecated. See the NOTICE above for the deprecation schedule.

This attribute records the XML namespace used by the SOAP query. This must agree with the targetNamespace value given in the USGS' WSDL found at http://gisdata.usgs.gov/XMLWebServices/TNM_Elevation_service.asmx?WSDL.

This attribute should not ordinarily need to be modified, but the desperate user may be able to use it to get him- or herself going again if the USGS changes the WSDL and this module has not been modified to track the change.

The default is 'http://gisdata.usgs.gov/XMLWebServices2/'.

error (string)

This attribute records the error returned by the last query operation, or undef if no error occurred. This attribute can be set by the user, but will be reset by any query operation.

The default (before any queries have occurred) is undef.

places (integer)

If this attribute is set to a non-negative integer, elevation results will be rounded to this number of decimal places by running them through sprintf "%.${places}f".

The default is undef.

proxy (string)

This attribute is deprecated. See the NOTICE above for the deprecation schedule.

This attribute specifies the actual url to which the SOAP query is posted. It must agree with the soap:address location value given for wsdl:port name "Elevation_ServiceSoap" given in the USGS' WSDL found at http://gisdata.usgs.gov/XMLWebServices/TNM_Elevation_service.asmx?WSDL.

This attribute should not ordinarily need to be modified, but the desperate user may be able to use it to get him- or herself going again if the USGS changes the WSDL and this module has not been modified to track the change.

The default is 'http://gisdata.usgs.gov/XMLWebServices2/Elevation_Service.asmx'.

retry (unsigned integer)

This attribute specifies the number of retries to be done by getAllElevations() and getElevation() when an error is encountered. The first try is not considered a retry, so if you set this to 1 you get a maximum of two queries (the try and the retry).

Retries are done only on actual errors, not on bad extents. They are also subject to the "throttle" setting if any.

The default is 0, i.e. no retries.

retry_hook (code reference)

This attribute specifies a piece of code to be called before retrying. The code will be called before a retry takes place, and will be passed the Geo::WebService::Elevation::USGS object, the number of the retry (from 1), the name of the method being retried ('getAllElevations' or 'getElevation'), and the arguments to that method. If the position was passed as an object, the hook gets the latitude and longitude unpacked from the object. The hook will not be called before the first try, nor after the last retry.

Examples:

 # To sleep 5 seconds between retries:
 $eq->set( retry_hook => sub { sleep 5 } );
 
 # To sleep 1 second before the first retry, 2 seconds
 # before the second, and so on:
 $eq->set( retry_hook => sub { sleep $_[1] } );
 
 # To do nothing between retries:
 $eq->set( retry_hook => sub {} );

The default is the null subroutine, i.e. sub {}.

source

This attribute is deprecated. See the NOTICE above for the deprecation schedule.

This attribute specifies the ID of the source layer to be queried by the elevation() method. Valid layer IDs are documented at http://gisdata.usgs.gov/XMLWebServices/TNM_Elevation_Service_Methods.php.

A legal value is a scalar, or an ARRAY, CODE, HASH, or Regexp reference. Please see the elevation() method's documentation for how these are used.

The default is '-1', which requests a response from the 'best' data source for the given point.

throttle (non-negative number, or undef)

 Geo::WebService::Elevation::USGS->set( throttle => 5 );

This attribute, if defined and positive, specifies the minimum interval between queries, in seconds. This attribute may be set statically only, and the limit applies to all queries, not just the ones from a given object. If Time::HiRes can be loaded, then sub-second intervals are supported, otherwise not.

This functionality, and its implementation, are experimental, and may be changed or retracted without notice. Heck, I may even go back to $TARGET, though I don't think so.

timeout (integer, or undef)

This attribute specifies the timeout for the SOAP query in seconds.

The default is 30.

trace (boolean)

If true, this attribute requests that network requests and responses be dumped to standard error. This should only be used for troubleshooting, and the author makes no representation about and has no control over what output you get if you set this true.

The default is undef (i.e. false).

units (string)

This attribute specifies the desired units for the resultant elevations. Valid values are 'Feet' and 'Meters'. In practice these are not case-sensitive, and any value other than case-insensitive 'Meters' will be taken as 'Feet'.

The default is 'FEET', but this will become 'Feet' when the compatibility code goes away.

use_all_limit (integer)

This attribute is deprecated. See the NOTICE above for the deprecation schedule.

This attribute is used to optimize the behavior of the elevation() method when the 'source' attribute is an array or hash reference. If the number of elements in the array or hash is greater than or equal to this, elevation() gets its data by calling getAllElevations() and then dropping unwanted data. If the number of elements is less than this number, elevation() iterates over the elements of the array or the sorted keys of the hash, calling getElevation() on each.

Note that setting this to 0 causes getAllElevations() to be used always. Setting this to -1 (or any negative number) is special-cased to cause getElevation() to be used whenever the 'source' array or hash has any entries at all, no matter how many it has.

The default is 5, which was chosen based on timings of the two methods.

ACKNOWLEDGMENTS

The author wishes to acknowledge the following individuals and groups.

The members of the geo-perl mailing list provided valuable suggestions and feedback, and generally helped me thrash through such issues as how the module should work and what it should actually be called.

Michael R. Davis provided prompt and helpful feedback on a testing problem in my first module to rely heavily on Test::More.

BUGS

Bugs can be reported to the author by mail, or through http://rt.cpan.org/.

SEE ALSO

AUTHOR

Thomas R. Wyant, III; wyant at cpan dot org

COPYRIGHT AND LICENSE

Copyright (C) 2008-2016 Thomas R. Wyant, III

This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES.

This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.