GPS-Point-0.20/0000755000076400007640000000000012155631170012514 5ustar mdavismdavisGPS-Point-0.20/README0000755000076400010150000000063112031101213013107 0ustar mdavistier3pod2text GPS::Point.pm > README If this is still here it means the programmer was too lazy to create the readme file. You can create it now by using the command shown above from this directory. At the very least you should be able to use this set of instructions to install the module... perl Makefile.PL make make test make install If you are on a windows box you should use 'nmake' rather than 'make'. GPS-Point-0.20/Todo0000755000076400010150000000006412031101213013057 0ustar mdavistier3TODO list for Perl module GPS::Point - Nothing yet GPS-Point-0.20/META.yml0000664000076400007640000000106612155631170013772 0ustar mdavismdavis--- #YAML:1.0 name: GPS-Point version: 0.20 abstract: Provides an object interface for a GPS point. license: bsd author: - Michael R. Davis (account=>perl,tld=>com,domain=>michaelrdavis) generated_by: ExtUtils::MakeMaker version 6.42 distribution_type: module requires: Scalar::Util: 1.02 Test::Number::Delta: 0 Test::Simple: 0.44 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.3.html version: 1.3 GPS-Point-0.20/Makefile.PL0000644000076400010150000000067612031101213014207 0ustar mdavistier3use ExtUtils::MakeMaker; WriteMakefile( NAME =>'GPS::Point', VERSION_FROM =>'lib/GPS/Point.pm', AUTHOR =>'Michael R. Davis (account=>perl,tld=>com,domain=>michaelrdavis)', ABSTRACT_FROM=> 'lib/GPS/Point.pm', LICENSE => 'bsd', PREREQ_PM => { 'Test::Simple' => 0.44, 'Test::Number::Delta' => 0, 'Scalar::Util' => 1.02, }, ); GPS-Point-0.20/scripts/0000755000076400007640000000000012155631170014203 5ustar mdavismdavisGPS-Point-0.20/scripts/GPS-Point-Example.pl0000644000076400010150000000035112031101212017357 0ustar mdavistier3#!/usr/bin/perl use strict; use warnings; use GPS::Point; =head1 NAME GPS-Point-Example.pl - GPS-Point Simple Example =cut my $point=GPS::Point->new(lat=>38.894022, lon=>-77.036626); printf "Lat: %s, Lon: %s\n", $point->latlon; GPS-Point-0.20/Changes0000755000076400010150000000423212155630246013547 0ustar mdavistier3Revision history for Perl module GPS::Point TODO - Port new error methods from gpsd - Allow the setting of the DateTime property 0.20 2013-06-11 - Added GPS::Point->buffer method and tests - Updated all tests to use strict - Fixed three spelling issues 0.19 2011-05-05 - Added spec file to distribution 0.18 2010-02-17 - Require a Geo::ECEF->can("new") - Update to get tests to pass on Win32 - Removed test using Geo::WebService::Elevation::USGS from dist 0.17 2010-01-02 - Win32 Test fail becuse they cannot tell difference between Geo::ECEF and geo::ecef. "geo" is a depricated name space in favor of Geo. 0.16 2009-12-15 - RT 52364 fixed test - Added test for datetime method - Renamed q2u to _q2u 0.15 2009-11-27 - Fixed bug where a 0 lat, lon, or alt returns as undef in initializeMulti 0.14 2009-11-26 - Broke out forward method - Re-wrote track method as a wrapper around forward method - Added tests for track method - Added tests for forward method - Updated SKIP in tests 0.13 2008-12-31 - Updated SKIP in test 0.12 2008-12-30 - Updated setAltitude method to handle undef return - Added setAltitude tests 0.11 2008-12-29 - Documentation - Organized tests - Added setAltitude method 0.10 2008-12-28 - Fixed time ||/+ precedent bug in track method in version 0.09 - Added copy and track tests - Updated documentation - Exposed point capabilities from distance method as newMulti constructor - Added datetime method 0.09 2008-12-27 - Added track method (ported from Net::GPSD::Point) 0.08 2008-07-28 - Require Geo::Inverse to pass tests - Changed license to BSD from perl - Fixed test issue 0.07 2008-07-27 - updated distance method to support multiple point formats. 0.06 2007-04-08 - Documentation 0.05 2007-04-07 - Documentation - Added method aliases e.g long, latitude... - Added fix method 0.04 2007-04-07 - test floats with Test::Number::Delta - added skip tests - newGPSD constructor - documentation 0.03 2007-04-06 - Added ecef, distance, GeoPoint methods 0.02 2007-03-29 - First Version on CPAN 0.01 2007-02-26 - original version; created by ExtUtils::ModuleMaker 0.47 GPS-Point-0.20/perl-GPS-Point.spec0000644000076400010150000000253512155631146015611 0ustar mdavistier3Name: perl-GPS-Point Version: 0.20 Release: 1%{?dist} Summary: Provides an object interface for a GPS point License: BSD Group: Development/Libraries URL: http://search.cpan.org/dist/GPS-Point/ Source0: http://www.cpan.org/modules/by-module/GPS/GPS-Point-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildArch: noarch BuildRequires: perl(ExtUtils::MakeMaker) BuildRequires: perl(Test::Number::Delta) BuildRequires: perl(Test::Simple) >= 0.44 Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version)) %description This is a re-write of Net::GPSD::Point with the goal of being more re-usable. %prep %setup -q -n GPS-Point-%{version} %build %{__perl} Makefile.PL INSTALLDIRS=vendor make %{?_smp_mflags} %install rm -rf $RPM_BUILD_ROOT make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} \; find $RPM_BUILD_ROOT -depth -type d -exec rmdir {} 2>/dev/null \; %{_fixperms} $RPM_BUILD_ROOT/* %check make test %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root,-) %doc Changes LICENSE README Todo %{perl_vendorlib}/* %{_mandir}/man3/* %changelog * Thu May 05 2011 Michael R. Davis (mdavis@stopllc.com) 0.18-1 - Specfile autogenerated by cpanspec 1.78. GPS-Point-0.20/t/0000755000076400007640000000000012155631170012757 5ustar mdavismdavisGPS-Point-0.20/t/004_newMulti.t0000755000076400010150000000326512155630030015067 0ustar mdavistier3# -*- perl -*- use strict; use warnings; use Test::More tests => 29; BEGIN { use_ok( 'GPS::Point' ); } my $lat=39; my $lon=-77; my $alt=72; my $point; $point = GPS::Point->newMulti({lat=>$lat,lon=>$lon,alt=>$alt}); isa_ok ($point, 'GPS::Point'); is($point->lat, $lat, '$point->lat'); is($point->lon, $lon, '$point->lon'); is($point->alt, $alt, '$point->lon'); $point = GPS::Point->newMulti(bless {lat=>$lat,lon=>$lon,alt=>$alt}, "My::Point"); isa_ok ($point, 'GPS::Point'); is($point->lat, $lat, '$point->lat'); is($point->lon, $lon, '$point->lon'); is($point->alt, $alt, '$point->lon'); $point = GPS::Point->newMulti(bless {latitude=>$lat, longitude=>$lon, elev=>$alt}, "My::Point"); isa_ok ($point, 'GPS::Point'); is($point->lat, $lat, '$point->lat'); is($point->lon, $lon, '$point->lon'); is($point->alt, $alt, '$point->lon'); $point = GPS::Point->newMulti(bless {lat=>$lat, long=>$lon, altitude=>$alt}, "My::Point"); isa_ok ($point, 'GPS::Point'); is($point->lat, $lat, '$point->lat'); is($point->lon, $lon, '$point->lon'); is($point->alt, $alt, '$point->lon'); $point = GPS::Point->newMulti({latitude=>$lat, long=>$lon, elevation=>$alt}); isa_ok ($point, 'GPS::Point'); is($point->lat, $lat, '$point->lat'); is($point->lon, $lon, '$point->lon'); is($point->alt, $alt, '$point->lon'); $point = GPS::Point->newMulti([$lat, $lon, $alt]); isa_ok ($point, 'GPS::Point'); is($point->lat, $lat, '$point->lat'); is($point->lon, $lon, '$point->lon'); is($point->alt, $alt, '$point->lon'); $point = GPS::Point->newMulti(bless [$lat, $lon, $alt], "My::Point::Array"); isa_ok ($point, 'GPS::Point'); is($point->lat, $lat, '$point->lat'); is($point->lon, $lon, '$point->lon'); is($point->alt, $alt, '$point->lon'); GPS-Point-0.20/t/005_value.t0000755000076400010150000000574612155630042014411 0ustar mdavistier3# -*- perl -*- use strict; use warnings; use Test::More tests => 36; use Test::Number::Delta; BEGIN { use_ok( 'GPS::Point' ); } my $pt1 = GPS::Point->new(lat=>39, lon=>-77, mode=>2); isa_ok ($pt1, 'GPS::Point'); is($pt1->lat, 39, "lat"); is($pt1->lon, -77, "lon"); is($pt1->mode, 2, "lon"); is($pt1->fix, "1", "fix method"); $pt1->mode(undef); is($pt1->fix, "0", "fix method"); $pt1->mode(3); is($pt1->fix, "1", "fix method"); is(scalar($pt1->latlon), "39 -77", "latlon method scalar context"); my @latlon=$pt1->latlon; is($latlon[0], 39, "latlon method array context"); is($latlon[1], -77, "latlon method array context"); SKIP: { eval { require Geo::ECEF }; skip "Geo::ECEF not installed", 5 if $@; ok(1, "We have Geo::ECEF but is it geo::ecef on Win32?"); my $sub=Geo::ECEF->can("new"); skip "We have geo::ecef but need Geo::ECEF on Win32", 4 unless $sub; ok(1, "Running tests that require Geo::ECEF"); my @xyz=$pt1->ecef; delta_ok($xyz[0], 3857229.79658403, "ecef method x" ); delta_ok($xyz[1], 3123523.10163777, "ecef method y" ); delta_ok($xyz[2], 3992317.02275173, "ecef method z" ); } SKIP: { eval { require Geo::Point }; skip "Geo::Point not installed", 5 if $@; ok(1, "Running tests that require Geo::Point"); my $pt=$pt1->GeoPoint; is( ref($pt), "Geo::Point", "Geo::Point"); is( $pt->lat, "39", "GeoPoint->lat"); is( $pt->long, "-77", "GeoPoint->long"); is( $pt->proj, "wgs84", "GeoPoint->proj"); } SKIP: { eval { require Geo::Inverse }; skip "Geo::Inverse not installed", 5 if $@; ok(1, "Running tests that require Geo::Inverse"); my $pt1=GPS::Point->new(lat=>39, lon=>-77); my $pt2=GPS::Point->new(lat=>39.1, lon=>-77.1); my @dist=$pt1->distance($pt2); delta_ok($dist[2], 14077.7169524386, "distance method array context"); delta_ok($dist[0], 322.08605713267, "distance faz"); delta_ok($dist[1], 142.02305726502, "distance baz"); my $dist=$pt1->distance($pt2); delta_ok( $dist, "14077.7169524386", "distance method scalar context"); } SKIP: { eval { require Geo::Forward }; skip "Geo::Forward not installed", 5 if $@; ok(1, "Running tests that require Geo::Forward"); my $pt1=GPS::Point->new(lat=>39, lon=>-77, heading=>322.08605713267, speed=>100); my $pt2=$pt1->forward(14077.7169524386); delta_ok($pt2->lat, 39.1, 'forward->lat'); delta_ok($pt2->lon, -77.1, 'forward->lon'); my $pt3=$pt1->track(140.777169524386); delta_ok($pt3->lat, 39.1, 'track->lat'); delta_ok($pt3->lon, -77.1, 'track->lon'); } my $pt4=GPS::Point->new(time=>"1260855713"); is($pt4->time, "1260855713", "time method" ); SKIP: { eval { require DateTime }; skip "DateTime not installed", 4 if $@; ok(1, "Running tests that require DateTime"); isa_ok($pt4->datetime, "DateTime", "datetime method" ); is($pt4->datetime->datetime, "2009-12-15T05:41:53", "datetime method" ); is($pt4->datetime->epoch, "1260855713", "datetime method" ); } GPS-Point-0.20/t/007_buffer.t0000755000076400007640000000250312155630054015006 0ustar mdavismdavis# -*- perl -*- use strict; use warnings; use Test::More tests => 16; use Test::Number::Delta; BEGIN { use_ok( 'GPS::Point' ); } SKIP: { eval { require Geo::Forward }; skip "Geo::Forward not installed", 15 if $@; ok(1, "Running tests that require Geo::Forward"); my $pt=GPS::Point->new(lat=>38.907671, lon=>-76.864482, alt=>59.6811); #Fedex Field my $buffer=$pt->buffer(91.44/2, 60); #100 yards = 91.44 meters isa_ok($buffer, "ARRAY"); is(scalar(@$buffer), 61, "points not sections in buffer"); isa_ok($buffer->[0], "GPS::Point"); isa_ok($buffer->[1], "GPS::Point"); isa_ok($buffer->[2], "GPS::Point"); isa_ok($buffer->[3], "GPS::Point"); isa_ok($buffer->[4], "GPS::Point"); isa_ok($buffer->[5], "GPS::Point"); is($buffer->[0]->alt, 59.6811, 'altitude'); is($buffer->[1]->alt, 59.6811, 'altitude'); is($buffer->[2]->alt, 59.6811, 'altitude'); is($buffer->[3]->alt, 59.6811, 'altitude'); is($buffer->[4]->alt, 59.6811, 'altitude'); is($buffer->[5]->alt, 59.6811, 'altitude'); eval { require Geo::Google::StaticMaps::V2 }; unless ($@) { my $map=Geo::Google::StaticMaps::V2->new(type=>"satellite", scale=>2); $map->path(locations => [map {[$_->lat => $_->lon]} @$buffer]); #foreach my $pt (@$buffer) { #$map->marker(location => [$pt->lat=>$pt->lon]); #} diag $map->url; } } GPS-Point-0.20/t/002_newcopy.t0000755000076400010150000000061312155630000014734 0ustar mdavistier3# -*- perl -*- use strict; use warnings; use Test::More tests => 7; BEGIN { use_ok( 'GPS::Point' ); } my $pt1 = GPS::Point->new(lat=>39, lon=>-77); isa_ok ($pt1, 'GPS::Point'); my $pt2=GPS::Point->new(%$pt1); is($pt1->lat, 39, "pt1 lat"); is($pt2->lat, 39, "pt2 lat"); is($pt1->lat(38), 38, "pt1 lat"); is($pt1->lat, 38, "pt1 lat"); is($pt2->lat, 39, "pt2 lat"); GPS-Point-0.20/t/003_newGPSD.t0000755000076400010150000000305112155630016014526 0ustar mdavistier3# -*- perl -*- use strict; use warnings; use Test::More tests => 23; BEGIN { use_ok( 'GPS::Point' ); } my $line=q{GPSD,O=MID2 1175911006.190 ? 53.527185 -113.530093 705.51 4.00 3.49 0.0000 0.074 0.101 ? 8.00 6.99 3}; my $object = GPS::Point->newGPSD($line); isa_ok ($object, 'GPS::Point'); my @test=split(/=/, $line); @test=map {q2u($_)} split(/\s+/, $test[1]); is($object->tag, $test[ 0], "newGPSD tag"); is($object->time, $test[ 1], "newGPSD time"); is($object->etime, $test[ 2], "newGPSD etime"); is($object->lat, $test[ 3], "newGPSD lat"); is($object->latitude, $test[ 3], "newGPSD lat"); is($object->lon, $test[ 4], "newGPSD lon"); is($object->long, $test[ 4], "newGPSD long"); is($object->longitude, $test[ 4], "newGPSD longitude"); is($object->alt, $test[ 5], "newGPSD alt"); is($object->altitude, $test[ 5], "newGPSD altitude"); is($object->ehorizontal, $test[ 6], "newGPSD ehorizontal"); is($object->evertical, $test[ 7], "newGPSD evertical"); is($object->heading, $test[ 8], "newGPSD heading"); is($object->bearing, $test[ 8], "newGPSD bearing"); is($object->speed, $test[ 9], "newGPSD speed"); is($object->climb, $test[10], "newGPSD climb"); is($object->eheading, $test[11], "newGPSD eheading"); is($object->espeed, $test[12], "newGPSD espeed"); is($object->eclimb, $test[13], "newGPSD eclimb"); is($object->mode, $test[14], "newGPSD mode"); is($object->fix, 1, "newGPSD fix"); sub q2u { my $s=shift(); return $s eq '?' ? undef() : $s; } GPS-Point-0.20/t/001_load.t0000755000076400010150000000025212155627755014214 0ustar mdavistier3# -*- perl -*- use strict; use warnings; use Test::More tests => 2; BEGIN { use_ok( 'GPS::Point' ); } my $object = GPS::Point->new (); isa_ok ($object, 'GPS::Point'); GPS-Point-0.20/LICENSE0000755000076400010150000000276112031101213013242 0ustar mdavistier3The BSD License Copyright (c) 2008, Michael R. Davis All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the STOP, LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. GPS-Point-0.20/MANIFEST0000644000076400007640000000043512155631170013647 0ustar mdavismdavisChanges lib/GPS/Point.pm LICENSE Makefile.PL MANIFEST README t/001_load.t t/002_newcopy.t t/003_newGPSD.t t/004_newMulti.t t/005_value.t t/007_buffer.t scripts/GPS-Point-Example.pl Todo perl-GPS-Point.spec META.yml Module meta-data (added by MakeMaker) GPS-Point-0.20/lib/0000755000076400007640000000000012155631170013262 5ustar mdavismdavisGPS-Point-0.20/lib/GPS/0000755000076400007640000000000012155631170013713 5ustar mdavismdavisGPS-Point-0.20/lib/GPS/Point.pm0000755000076400010150000004130412155627562015112 0ustar mdavistier3package GPS::Point; use strict; use warnings; use Scalar::Util qw{reftype}; our $VERSION = '0.20'; =head1 NAME GPS::Point - Provides an object interface for a GPS point. =head1 SYNOPSIS use GPS::Point; my $obj=GPS::Point->newGPSD($GPSD_O_line);#e.g. GPSD,O=.... my $obj=GPS::Point->new( time => $time, #float seconds from the unix epoch lat => $lat, #signed degrees lon => $lon, #signed degrees alt => $hae, #meters above the WGS-84 ellipsoid speed => $speed, #meters/second (over ground) heading => $heading, #degrees clockwise from North climb => $climb, #meters/second etime => $etime, #float seconds ehorizontal => $ehz, #float meters evertical => $evert, #float meters espeed => $espeed, #meters/second eheading => $ehead, #degrees eclimb => $eclimb, #meters/second mode => $mode, #GPS mode [?=>undef,None=>1,2D=>2,3D=>3] tag => $tag, #Name of the GPS message for data ); =head1 DESCRIPTION This is a re-write of L with the goal of being more re-usable. GPS::Point - Provides an object interface for a GPS fix (e.g. Position, Velocity and Time). Note: Please use Geo::Point, if you want 2D or projection support. =head1 USAGE print scalar($point->latlon), "\n"; #latlon in scalar context my ($x,$y,$z)=$point->ecef; #if Geo::ECEF is available my $GeoPointObject=$point->GeoPoint; #if Geo::Point is available my @distance=$point->distance($point2); #if Geo::Inverse is available my $distance=$point->distance($point2); #if Geo::Inverse->VERSION >=0.05 =head1 USAGE TODO my $obj=GPS::Point->newNMEA($NMEA_lines); #e.g. GGA+GSA+RMC =head1 CONSTRUCTORS =head2 new my $obj = GPS::Point->new(); =cut sub new { my $this = shift(); my $class = ref($this) || $this; my $self = {}; bless $self, $class; $self->initialize(@_); return $self; } =head2 newGPSD my $obj=GPS::Point->newGPSD($GPSD_O_line);#e.g. GPSD,O=.... Note: GPSD protocol 2 is soon to be defunct. =cut sub newGPSD { my $this = shift(); my $class = ref($this) || $this; my $self = {}; bless $self, $class; $self->initializeGPSD(@_); return $self; } =head2 newMulti Constructs a GPS::Point from a Multitude of arguments. Arguments can be a L, L, {lat=>$lat,lon=>$lon} (can be blessed), [$lat, $lon] (can be blessed) or a ($lat, $lon) pair. my $point=GPS::Point->newMulti( $lat, $lon, $alt ); #supports lat, lon and alt my $point=GPS::Point->newMulti([$lat, $lon, $alt]); #supports lat, lon and alt my $point=GPS::Point->newMulti({lat=>$lat, lon=>$lon, ...}); my $point=GPS::Point->newMulti(GPS::Point->new(lat=>$lat, lon=>$lon)); my $point=GPS::Point->newMulti(Geo::Point->new(lat=>$lat, long=>$lon, proj=>'wgs84')); my $point=GPS::Point->newMulti({latitude=>$lat, longtude=>$lon}); Note: Hash reference context supports the following keys lat, lon, alt, latitude, longitude, long, altitude, elevation, hae, elev. Note: Units are always decimal degrees for latitude and longitude and meters above the WGS-84 ellipsoid for altitude. =cut sub newMulti { my $this = shift(); my $class = ref($this) || $this; my $self = {}; bless $self, $class; $self->initializeMulti(@_); return $self; } =head2 initialize, initializeGPSD, initializeMulti =cut sub initialize { my $self = shift(); %$self=@_; } sub initializeGPSD { my $self=shift(); my $line=shift(); #GPSD,O=MID2 1175911006.190 ? 53.527185 -113.530093 705.51 4.00 3.49 0.0000 0.074 0.101 ? 8.00 6.99 3 my @line=split(/,/, $line); warn("Warning: Expected GPSD formatted line.") unless $line[0] eq "GPSD"; my $obj=undef(); foreach (@line) { #I pull the last one if O=?,O=?,... my @rpt=split(/=/, $_); if ($rpt[0] eq 'O') { my @data=map {&_q2u($_)} split(/\s+/, $rpt[1]); %$self=(tag => $data[ 0], time => $data[ 1], etime => $data[ 2], lat => $data[ 3], lon => $data[ 4], alt => $data[ 5], ehorizontal => $data[ 6], evertical => $data[ 7], heading => $data[ 8], speed => $data[ 9], climb => $data[10], eheading => $data[11], espeed => $data[12], eclimb => $data[13], mode => $data[14]); } } } sub initializeMulti { my $self=shift; my $point=shift; if (!ref($point)) { $self->{'lat'}=$point ||0; $self->{'lon'}=shift ||0; $self->{'alt'}=shift ||0; } elsif (ref($point) eq "Geo::Point") { $point=$point->in('wgs84') unless $point->proj eq "wgs84"; $self->{'lat'}=$point->latitude ||0; $self->{'lon'}=$point->longitude ||0; } elsif (ref($point) eq "GPS::Point") { %$self=%$point; } elsif (ref($point) eq "Net::GPSD::Point") { $self->{'time'}=$point->time; $self->{'lat'}=$point->latitude ||0; $self->{'lon'}=$point->longitude ||0; $self->{'alt'}=$point->altitude ||0; $self->{'speed'}=$point->speed; $self->{'heading'}=$point->heading; $self->{'climb'}=$point->climb; $self->{'etime'}=$point->errortime; $self->{'ehorizontal'}=$point->errorhorizontal; $self->{'evertical'}=$point->errorvertical; $self->{'espeed'}=$point->errorspeed; $self->{'eheading'}=$point->errorheading; $self->{'eclimb'}=$point->errorclimb; $self->{'mode'}=$point->mode; $self->{'tag'}=$point->tag; } elsif (reftype($point) eq "HASH") { %$self=%$point; $self->{'lat'}=$point->{'lat'} || delete($point->{'latitude'}) ||0; $self->{'lon'}=$point->{'lon'} || delete($point->{'long'}) || delete($point->{'longitude'}) ||0; $self->{'alt'}=$point->{'alt'} || delete($point->{'altitude'}) || delete($point->{'elevation'}) || delete($point->{'hae'}) || delete($point->{'elev'}) ||0; } elsif (reftype($point) eq "ARRAY") { $self->{'lat'}=$point->[0] ||0; $self->{'lon'}=$point->[1] ||0; $self->{'alt'}=$point->[2] ||0; } } =head1 METHODS (Base) =head2 time Sets or returns seconds since the Unix epoch, UTC (float, seconds) print $obj->time, "\n"; =cut sub time { my $self = shift(); $self->{'time'}=shift() if @_; return $self->{'time'}; } =head2 lat, latitude Sets or returns Latitude (float, degrees) print $obj->lat, "\n"; =cut *latitude=\⪫ sub lat { my $self=shift; $self->{'lat'}=shift if @_; return $self->{'lat'}; } =head2 lon, long, longitude Sets or returns Longitude (float, degrees) print $obj->lon, "\n"; =cut *longitude=\&lon; *long=\&lon; sub lon { my $self = shift(); $self->{'lon'}=shift() if @_; return $self->{'lon'}; } =head2 alt, altitude, hae, elevation Sets or returns Altitude (float, meters) print $obj->alt, "\n"; =cut *altitude=\&alt; *hae=\&alt; *elevation=\&alt; sub alt { my $self = shift(); $self->{'alt'}=shift() if @_; return $self->{'alt'}; } =head2 speed Sets or returns speed (float, meters/sec) print $obj->speed, "\n"; =cut sub speed { my $self = shift(); $self->{'speed'}=shift() if @_; return $self->{'speed'}; } =head2 heading, bearing Sets or returns heading (float, degrees) print $obj->heading, "\n"; =cut *bearing=\&heading; sub heading { my $self = shift(); $self->{'heading'}=shift() if @_; return $self->{'heading'}; } =head2 climb Sets or returns vertical velocity (float, meters/sec) print $obj->climb, "\n"; =cut sub climb { my $self = shift(); $self->{'climb'}=shift() if @_; return $self->{'climb'}; } =head2 etime Sets or returns estimated timestamp error (float, seconds, 95% confidence) print $obj->etime, "\n"; =cut sub etime { my $self = shift(); $self->{'etime'}=shift() if @_; return $self->{'etime'}; } =head2 ehorizontal Sets or returns horizontal error estimate (float, meters) print $obj->ehorizontal, "\n"; =cut sub ehorizontal { my $self = shift(); $self->{'ehorizontal'}=shift() if @_; return $self->{'ehorizontal'}; } =head2 evertical Sets or returns vertical error estimate (float, meters) print $obj->evertical, "\n"; =cut sub evertical { my $self = shift(); $self->{'evertical'}=shift() if @_; return $self->{'evertical'}; } =head2 espeed Sets or returns error estimate for speed (float, meters/sec, 95% confidence) print $obj->espeed, "\n"; =cut sub espeed { my $self = shift(); $self->{'espeed'}=shift() if @_; return $self->{'espeed'}; } =head2 eheading Sets or returns error estimate for course (float, degrees, 95% confidence) print $obj->eheading, "\n"; =cut sub eheading { my $self = shift(); $self->{'eheading'}=shift() if @_; return $self->{'eheading'}; } =head2 eclimb Sets or returns Estimated error for climb/sink (float, meters/sec, 95% confidence) print $obj->eclimb, "\n"; =cut sub eclimb { my $self = shift(); $self->{'eclimb'}=shift() if @_; return $self->{'eclimb'}; } =head2 mode Sets or returns the NMEA mode (integer; undef=>no mode value yet seen, 1=>no fix, 2=>2D, 3=>3D) print $obj->mode, "\n"; =cut sub mode { my $self = shift(); $self->{'mode'}=shift() if @_; return $self->{'mode'}; } =head2 tag Sets or returns a tag identifying the last sentence received. For NMEA devices this is just the NMEA sentence name; the talker-ID portion may be useful for distinguishing among results produced by different NMEA talkers in the same wire. (string) print $obj->tag, "\n"; =cut sub tag { my $self = shift(); $self->{'tag'}=shift() if @_; return $self->{'tag'}; } =head1 METHODS (Value Added) =head2 fix Returns either 1 or 0 based upon if the GPS point is from a valid fix or not. print $obj->fix, "\n"; At a minimum this method requires mode to be set. =cut sub fix { my $self=shift; if (defined($self->mode) and $self->mode > 1) { return 1; } else { return 0; } } =head2 datetime Returns a L object from time my $dt=$point->datetime; At a minimum this method requires time to be set. =cut sub datetime { my $self=shift; eval 'use DateTime'; if ($@) { die("Error: The datetime method requires DateTime"); } else { return DateTime->from_epoch(epoch=>$self->time); } } =head2 latlon, latlong Returns Latitude, Longitude as an array in array context and as a space joined string in scalar context my @latlon=$point->latlon; my $latlon=$point->latlon; At a minimum this method requires lat and lon to be set. =cut *latlong=\&latlon; sub latlon { my $self = shift(); my @latlon=($self->lat, $self->lon); return wantarray ? @latlon : join(" ", @latlon); } =head2 setAltitude Sets altitude from USGS web service and then returns the GPS::Point object. This method is a wrapper around L. my $point=GPS::Point->new(lat=>$lat, lon=>$lon)->setAltitude; $point->setAltitude; my $alt=$point->alt; At a minimum this method requires lat and lon to be set and alt to be undef. =cut sub setAltitude { my $self=shift; unless (defined $self->alt) { eval 'use Geo::WebService::Elevation::USGS'; if ($@) { die("Error: The setAltitude method requires Geo::WebService::Elevation::USGS"); } else { my $eq=Geo::WebService::Elevation::USGS->new(units=>"METERS", croak=>0); my $return=$eq->getElevation($self); #Assume this is HAE WGS-84 $self->alt($return->{'Elevation'}) if ref($return) eq "HASH"; } } return $self; } =head2 ecef Returns ECEF coordinates. This method is a wrapper around L. my ($x,$y,$z) = $point->ecef; my @xyz = $point->ecef; my $xyz_aref = $point->ecef; #if Geo::ECEF->VERSION >= 0.08 At a minimum this method requires lat and lon to be set. (alt of 0 is assumed by Geo::ECEF->ecef). =cut sub ecef { my $self=shift; eval 'use Geo::ECEF'; die("Error: The ecef method requires Geo::ECEF") if $@; die("Error: The found geo::ecef not Geo::ECEF.") unless Geo::ECEF->can("new"); my $obj=Geo::ECEF->new; return $obj->ecef($self->lat, $self->lat, $self->alt); } =head2 GeoPoint Returns a L Object in the WGS-84 projection. my $GeoPointObject = $point->GeoPoint; At a minimum this method requires lat and lon to be set. =cut sub GeoPoint { my $self = shift(); eval 'use Geo::Point'; if ($@) { die("Error: The GeoPoint method requires Geo::Point"); } else { return Geo::Point->new(lat=>$self->lat, long=>$self->lon, proj=>'wgs84'); } } =head2 distance Returns distance in meters between the object point and the argument point. The argument can be any valid argument of newMulti constructor. This method is a wrapper around Geo::Inverse. my ($faz, $baz, $dist) = $point->distance($pt2); #Array context my $dist = $point->distance($lat, $lon); #if Geo::Inverse->VERSION >=0.05 At a minimum this method requires lat and lon to be set. =cut sub distance { my $self=shift; my $point=$_[0]; $point=GPS::Point->newMulti(@_) unless ref($point) eq "GPS::Point"; if (defined $point) { eval 'use Geo::Inverse'; if ($@) { die("Error: The distance method requires Geo::Inverse"); } else { my $gi=Geo::Inverse->new; return $gi->inverse($self->latlon, $point->latlon); } } else { die(qq{Error: Could not create point from parameters.}); } } =head2 track Returns a point object at the predicted location in time seconds assuming constant velocity. Using L calculation. my $new_point=$point->track($seconds); #default $point->heading my $new_point=$point->track($seconds => $heading); At a minimum this method requires lat and lon to be set. It might be very useful to have speed, heading and time set although they all default to zero. =cut sub track { my $self=shift; my $seconds=shift||0; #seconds my $heading=shift; #degrees $heading=$self->heading || 0 unless defined $heading; #support 0 degrees passed my $speed=$self->speed || 0; #m/s my $dist=$speed * $seconds; #meters my $point=$self->forward($dist => $heading); $point->time(($self->time||0) + $seconds); return $point; } =head2 forward Returns a point object at the distance and heading using L calculations. my $point=$point->forward($dist); #default $point->heading my $point=$point->forward($dist => $heading); #meters => degrees At a minimum this method requires lat and lon to be set. It might be useful to have heading set although the default is zero. =cut sub forward { my $self=shift; my $dist=shift || 0; #meters my $faz=shift; #degrees $faz=$self->heading || 0 unless defined $faz; eval 'use Geo::Forward'; if ($@) { die("Error: The track method requires Geo::Forward"); } else { my $gf=Geo::Forward->new; my ($lat2,$lon2,$baz) = $gf->forward($self->latlon, $faz, $dist); my $point=GPS::Point->new(%$self); $point->lat($lat2); $point->lon($lon2); return $point; } } =head2 buffer Returns a list of L objects equidistant from the current object location. my @buffer=$point->buffer($radius_meters, $sections); #returns (GPS::Point, GPS::Point, ...) my $buffer=$point->buffer($radius_meters, $sections); #returns [GPS::Point, GPS::Point, ...] =cut sub buffer { my $self=shift; my $radius=shift; #meters my $sections=shift || 60; #60 sections = 61 verticies my @buffer=(); my $arc=360/$sections; #not zero! foreach my $step (0 .. $sections) { my $angle=$arc * $step; push @buffer, $self->forward($radius => $angle); } return wantarray ? @buffer : \@buffer; } sub _q2u { my $a=shift(); return $a eq '?' ? undef() : $a; } =head1 BUGS Please log on RT and send email to GPSD-DEV or GEO-PERL email lists. =head1 SUPPORT DavisNetworks.com supports all Perl applications including this package. =head1 AUTHOR Michael R. Davis CPAN ID: MRDVT DavisNetworks.com account=>perl,tld=>com,domain=>michaelrdavis http://www.davisnetworks.com/ =head1 COPYRIGHT This program is free software licensed under the... The BSD License The full text of the license can be found in the LICENSE file included with this module. =head1 SEE ALSO L, L, L, L, L, L, L, L, L, L, L =cut 1;