File Coverage

blib/lib/Geo/Sun.pm
Criterion Covered Total %
statement 71 72 98.6
branch 11 14 78.5
condition 1 3 33.3
subroutine 21 21 100.0
pod 9 11 81.8
total 113 121 93.3


line stmt bran cond sub pod time code
1             package Geo::Sun;
2 3     3   60804 use strict;
  3         6  
  3         125  
3 3     3   16 use warnings;
  3         6  
  3         82  
4 3     3   3346 use Astro::Coord::ECI::Sun;
  3         200584  
  3         86  
5 3     3   6281 use DateTime;
  3         535525  
  3         142  
6 3     3   3011 use Geo::Constants qw{PI};
  3         2711  
  3         295  
7 3     3   2681 use Geo::Functions qw{deg_rad};
  3         2875  
  3         199  
8 3     3   2629 use Geo::Ellipsoids;
  3         5263  
  3         88  
9 3     3   2890 use GPS::Point;
  3         9322  
  3         138  
10              
11             BEGIN {
12 3     3   58 use vars qw($VERSION);
  3         8  
  3         162  
13 3     3   2190 $VERSION = '0.04';
14             }
15              
16             =head1 NAME
17              
18             Geo::Sun - Calculates the Geodetic Position of the Sun over the Surface of the Earth
19              
20             =head1 SYNOPSIS
21              
22             use Geo::Sun;
23             my $gs=Geo::Sun->new; #isa Geo::Sun
24             my $point=$gs->set_datetime(DateTime->now)->point; #Full OO interface
25             printf "Point isa %s\n", ref($point); #isa GPS::Point
26             printf "Latitude: %s, Longitude: %s\n", $point->latlon;
27              
28             =head1 DESCRIPTION
29              
30             The Geo::Sun package calculates the position of the Sun over the Earth. The user method point_dt takes a L object as a parameter and returns a L which is the point on the earth where the Sun is directly over at the given time.
31              
32             The Geo::Sun package is a wrapper around L with a user friendly interface.
33              
34             =head1 USAGE
35              
36             use Geo::Sun;
37             my $gs=Geo::Sun->new;
38             printf "Lat: %s, Lon: %s\n", $gs->point->latlon;
39              
40             =head1 CONSTRUCTOR
41              
42             =head2 new
43              
44             my $gs=Geo::Sun->new;
45              
46             =cut
47              
48             sub new {
49 4     4 1 64 my $this = shift();
50 4   33     28 my $class = ref($this) || $this;
51 4         8 my $self = {};
52 4         11 bless $self, $class;
53 4         30 $self->initialize(@_);
54 4         10 return $self;
55             }
56              
57             =head1 METHODS
58              
59             =cut
60              
61             sub initialize {
62 4     4 0 7 my $self=shift;
63 4         28 %$self=@_;
64 4 50       22 $self->sun(Astro::Coord::ECI::Sun->new)
65             unless ref($self->sun) eq "Astro::Coord::ECI::Sun";
66 4 50       23 $self->ellipsoid(Geo::Ellipsoids->new)
67             unless ref($self->ellipsoid) eq "Geo::Ellipsoids";
68 4 50       26 if (defined $self->datetime) {
69 0         0 $self->point_recalculate; #supports $gs->new(datetime=>$dt)
70             } else {
71 4         31 $self->datetime(DateTime->now)
72             }
73 4         13 $self->initialize2; #a hook if you need it
74 4         5 return $self;
75             }
76              
77             sub initialize2 {
78 2     2 0 3 my $self=shift;
79 2         4 return $self;
80             }
81              
82             =head2 point
83              
84             Returns a GPS::Point for the location of the sun at the current datetime.
85              
86             my $point=$gs->point;
87             my $point=$gs->set_datetime(DateTime->now)->point;
88              
89             =cut
90              
91             sub point {
92 17     17 1 20 my $self=shift;
93 17         53 return $self->{'point'};
94             }
95              
96             =head2 point_dt
97              
98             Set the current datetime and returns a GPS::Point
99              
100             my $point=$gs->point_dt($datetime);
101              
102             Implemented as
103              
104             my $point=$gs->set_datetime($datetime)->point;
105              
106             =cut
107              
108             sub point_dt {
109 6     6 1 3168 my $self=shift;
110 6         19 return $self->set_datetime(@_)->point;
111             }
112              
113             =head2 datetime
114              
115             Sets or returns the current datetime which is a L object. The default is DateTime->now.
116              
117             =cut
118              
119             sub datetime {
120 38     38 1 3210 my $self = shift;
121 38 100       80 if (@_) {
122 13         20 $self->{"datetime"}=shift;
123 13         60 $self->point_recalculate;
124             }
125 38         112 return $self->{"datetime"};
126             }
127              
128             =head2 set_datetime
129              
130             Sets datetime returns self
131              
132             =cut
133              
134             sub set_datetime {
135 11     11 1 4108 my $self=shift;
136 11 100       202 $self->datetime(@_) if @_;
137 11         38 return $self;
138             }
139              
140             =head1 METHODS (INTERNAL)
141              
142             =head2 point_recalculate
143              
144             Recalculates the point when the DateTime is changed.
145              
146             =cut
147              
148             sub point_recalculate {
149 15     15 1 21 my $self=shift;
150 15         35 my $epoch=$self->datetime->clone->set_time_zone("UTC")->epoch;
151 15         502 my ($psi, $lambda, $h) = $self->sun->universal($epoch)->geodetic;
152             #speed is 2 pi distance from the polar axis to the surface
153             #of the earth at latitude divided by 1 day (m/s)
154 15         4530 my $speed=2 * PI() * $self->ellipsoid->n_rad($psi) * cos($psi) / 24 / 60 / 60;
155 15         292 $self->{'point'}=GPS::Point->new(
156             time => $self->sun->universal, #float seconds unix epoch (UTC)
157             lat => deg_rad($psi), #signed decimal degrees
158             lon => deg_rad($lambda), #signed decimal degrees
159             alt => $h * 1000, #meters above the WGS-84 ellipsoid
160             speed => $speed, #is this right #meters/second (over ground)
161             heading => 270, #need real value #degrees clockwise from North
162             mode => 3, #GPS mode 3-D
163             tag => "Geo::Sun", #Name of the GPS message for data
164             );
165 15         576 $self->point_onchange; #a hook if you need it.
166 15         25 return $self;
167             }
168              
169             =head2 point_onchange
170              
171             Override this method if you want to calculate something when the point changes
172              
173             =cut
174              
175             sub point_onchange {
176 11     11 1 14 my $self=shift;
177 11         33 return $self;
178             }
179              
180             =head2 sun
181              
182             Sets or returns the L object.
183              
184             my $sun=$gs->sun;
185              
186             =cut
187              
188             sub sun {
189 40     40 1 520 my $self=shift;
190 40 100       87 $self->{'sun'}=shift if @_;
191 40         180 return $self->{'sun'};
192             }
193              
194             =head2 ellipsoid
195              
196             Set or returns the L object.
197              
198             my $ellipsoid=$gs->ellipsoid; #WGS84
199              
200             =cut
201              
202             sub ellipsoid {
203 25     25 1 2868 my $self = shift();
204 25 100       62 $self->{'ellipsoid'}=shift if (@_);
205 25         115 return $self->{'ellipsoid'};
206             }
207              
208             =head1 BUGS
209              
210             Please send to the geo-perl email list.
211              
212             =head1 SUPPORT
213              
214             Try the geo-perl email list.
215              
216             =head1 LIMITATIONS
217              
218             Calculations are only good to about 3 decimal places.
219              
220             =head1 AUTHOR
221              
222             Michael R. Davis
223             CPAN ID: MRDVT
224             STOP, LLC
225             domain=>stopllc,tld=>com,account=>mdavis
226             http://www.stopllc.com/
227              
228             =head1 COPYRIGHT
229              
230             This program is free software licensed under the...
231              
232             The BSD License
233              
234             The full text of the license can be found in the
235             LICENSE file included with this module.
236              
237             =head1 SEE ALSO
238              
239             =cut
240              
241             1;