line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Ham::Resources::Utils; |
2
|
|
|
|
|
|
|
|
3
|
9
|
|
|
9
|
|
605415
|
use 5.006; |
|
9
|
|
|
|
|
118
|
|
4
|
9
|
|
|
9
|
|
4690
|
use Math::Trig qw(great_circle_distance deg2rad great_circle_direction rad2deg pi asin acos tan); |
|
9
|
|
|
|
|
140171
|
|
|
9
|
|
|
|
|
954
|
|
5
|
9
|
|
|
9
|
|
4884
|
use Ham::Locator; |
|
9
|
|
|
|
|
176128
|
|
|
9
|
|
|
|
|
54
|
|
6
|
9
|
|
|
9
|
|
358
|
use strict; |
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
225
|
|
7
|
9
|
|
|
9
|
|
52
|
use warnings; |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
30134
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 NAME |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
Ham::Resources::Utils - Calculation of distance and course beetwen two points |
12
|
|
|
|
|
|
|
on Earth (through coordinates or grid locator), and Sunrise, Sunset and Midday time for these locations (in UTC). Also sexagesimal degrees and decimal degrees convertion and grid location. For use mainly for Radio Amateurs. |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 VERSION |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
Version 0.05 |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=cut |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
our $VERSION = '0.05'; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
my %coordinates = ( |
23
|
|
|
|
|
|
|
long_1 => "", |
24
|
|
|
|
|
|
|
lat_1 => "", |
25
|
|
|
|
|
|
|
long_2 => "", |
26
|
|
|
|
|
|
|
lat_2 => "", |
27
|
|
|
|
|
|
|
); |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
my $locator_precision = 8; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
my $self = {}; |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=head1 SYNOPSIS |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
This module calculates the distance and course between two points on the Earth. |
36
|
|
|
|
|
|
|
Also Sunrise, Sunset and Midday time for both locations. |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
The data of the locations may be in terrestrial coordinates or through 'Maidenhead Locator System' (grid Locator) notacion. |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
The module offer the possibility to access to some methods that uses it, for |
41
|
|
|
|
|
|
|
example conversions between sexagesimal degrees into decimal degrees or |
42
|
|
|
|
|
|
|
conversion between grid locator to sexagesimal degrees. |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
Also access to convert decimal degrees to compass names, and more. |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
use Ham::Resources::Utils; |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
my $foo = Ham::Resources::Utils->new(); |
49
|
|
|
|
|
|
|
... |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=head1 SUBROUTINES/METHODS |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=head2 new |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
This is the constructor. |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
my $foo = Ham::Resources::Utils->new(); |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=cut |
61
|
|
|
|
|
|
|
|
62
|
8
|
|
|
8
|
1
|
723
|
sub new { bless {}, shift } |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=head2 data_by_coordinates |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
Gets a string with the date and a hash with the coordinates in sexagesimal |
68
|
|
|
|
|
|
|
values from point A and point B and returns a hash with all previous |
69
|
|
|
|
|
|
|
data and Distance, course and compass values and Sunrise, Sunset and Midday |
70
|
|
|
|
|
|
|
times for both locations if needed. |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
my $date = "14-03-2012"; |
73
|
|
|
|
|
|
|
my %coordinates = ( lat_1 => "41N23", |
74
|
|
|
|
|
|
|
long_1 => "2E11", |
75
|
|
|
|
|
|
|
lat_2 => "30S0", |
76
|
|
|
|
|
|
|
long_2 => "10W45"); |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
my %data = $foo->data_by_coordinates{$date, %coordinates}; |
79
|
|
|
|
|
|
|
print Dumper(%data); |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
The $date argument is necessary for the Sun time calculations (Sunrise, Sunset and Midday). |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
Distances are in kilometers (km) and Miles (mi). Times are in UTC (Universal Time). |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
An output example: |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
DATA_BY_COORDINATES() |
88
|
|
|
|
|
|
|
compass: S # compass direction to point B or destination |
89
|
|
|
|
|
|
|
course_dec: 190.94 # direction to destination in decimal degree |
90
|
|
|
|
|
|
|
course_sexag: 190.56 # direction to destination in sexagesimal degree |
91
|
|
|
|
|
|
|
date: 14-3-2012 # date of event (for Sun calculation porpouses) |
92
|
|
|
|
|
|
|
distance_km: 9377.83 # distance to destination in kilometers |
93
|
|
|
|
|
|
|
distance_mi: 17367.74 # distance to destination in miles |
94
|
|
|
|
|
|
|
lat_1: 41N23" # Latitude of point A or origin in sexagesinal notation |
95
|
|
|
|
|
|
|
lat_1_dec: 41.3833333333333 # Latitude of origin in decimal notation |
96
|
|
|
|
|
|
|
lat_2: 41S54" # Latitude of point B or destination in sexagesimal notation |
97
|
|
|
|
|
|
|
lat_2_dec: -41.9 # Latiude of destination in decimal notation |
98
|
|
|
|
|
|
|
locator_1: JN11cj # Grid Locator of origin point |
99
|
|
|
|
|
|
|
locator_2: IE38sc # Grid Locator of destination point |
100
|
|
|
|
|
|
|
long_1: 2E12" # Longitude of point A or origin in sexagesimal notation |
101
|
|
|
|
|
|
|
long_1_dec: 2.2 # Longitude of origin in decimal notation |
102
|
|
|
|
|
|
|
long_2: 12W30" # Longitude of point B or destination in sexagesimal notation |
103
|
|
|
|
|
|
|
long_2_dec: -12.5 # Longitude of destination in decimal notation |
104
|
|
|
|
|
|
|
midday_arrive: 12h 1m # Midday time on point B (destination) in UTC |
105
|
|
|
|
|
|
|
midday_departure: 12h 1m # Midday time on point A (origin) in UTC |
106
|
|
|
|
|
|
|
sunrise_arrive: 6h 5m # Sun rise time on point B (destination) in UTC |
107
|
|
|
|
|
|
|
sunrise_departure: 6h 5m # Sun rise time on point A (origin) in UTC |
108
|
|
|
|
|
|
|
sunset_arrive: 17h 58m # Sun set time on point B (destination) in UTC |
109
|
|
|
|
|
|
|
sunset_departure: 17h 58m # Sun set time on point A (origin) in UTC |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
=cut |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
sub data_by_coordinates { |
115
|
1
|
|
|
1
|
1
|
626
|
my $self = shift; |
116
|
1
|
|
|
|
|
3
|
my $date = shift; |
117
|
1
|
|
|
|
|
6
|
my %coordinates = @_; |
118
|
1
|
|
|
|
|
5
|
my %data = data_constructor($self, $date, %coordinates); |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=head2 data_by_locator |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
Gets a string with the date and a string with the locator of point 'A' and an |
124
|
|
|
|
|
|
|
string with a locator for point 'B'. Returns a hash with the data shown it in the |
125
|
|
|
|
|
|
|
previous method. |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
my $date = "14-03-2012"; # date in 'dd-mm-yyyy' format |
128
|
|
|
|
|
|
|
my $locator_dep = "JN11cj"; |
129
|
|
|
|
|
|
|
my $locator_arr = "IJ90ca"; |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
my %data = $foo->data_by_locator($date,$locator_dep,$locator_arr); |
132
|
|
|
|
|
|
|
print Dumper(%data); |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=cut |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub data_by_locator { |
137
|
1
|
|
|
1
|
1
|
483
|
my $self = shift; |
138
|
1
|
|
|
|
|
2
|
my $date = shift; |
139
|
1
|
|
|
|
|
3
|
my ($locator_dep, $locator_arr) = @_; |
140
|
1
|
|
|
|
|
3
|
my ($lat_dep, $long_dep, $lat_arr, $long_arr) = undef; |
141
|
1
|
50
|
|
|
|
6
|
($lat_dep, $long_dep) = loc2degree($self,$locator_dep) if ($locator_dep); |
142
|
1
|
50
|
|
|
|
6
|
($lat_arr, $long_arr) = loc2degree($self,$locator_arr) if ($locator_arr); |
143
|
|
|
|
|
|
|
|
144
|
1
|
50
|
|
|
|
9
|
$lat_dep =~ s/\./N/ if ($lat_dep !~ /^\s\d+/); |
145
|
1
|
50
|
|
|
|
4
|
$lat_dep =~ s/\./S/ if ($lat_dep =~ /^\s\d+/); |
146
|
1
|
50
|
|
|
|
5
|
$lat_arr =~ s/\./N/ if ($lat_arr !~ /^\s\d+/); |
147
|
1
|
50
|
|
|
|
5
|
$lat_arr =~ s/\./S/ if ($lat_arr =~ /^\s\d+/); |
148
|
|
|
|
|
|
|
|
149
|
1
|
50
|
|
|
|
5
|
$long_dep =~ s/\./E/ if ($long_dep !~ /^\s\d+/); |
150
|
1
|
50
|
|
|
|
4
|
$long_dep =~ s/\./W/ if ($long_dep =~ /^\s\d+/); |
151
|
1
|
50
|
|
|
|
4
|
$long_arr =~ s/\./E/ if ($long_arr !~ /^\s\d+/); |
152
|
1
|
50
|
|
|
|
5
|
$long_arr =~ s/\./W/ if ($long_arr =~ /^\s\d+/); |
153
|
|
|
|
|
|
|
|
154
|
1
|
|
|
|
|
17
|
my %coordinates = ( |
155
|
|
|
|
|
|
|
long_1 => $long_dep, |
156
|
|
|
|
|
|
|
lat_1 => $lat_dep, |
157
|
|
|
|
|
|
|
long_2 => $long_arr, |
158
|
|
|
|
|
|
|
lat_2 => $lat_arr, |
159
|
|
|
|
|
|
|
); |
160
|
|
|
|
|
|
|
|
161
|
1
|
|
|
|
|
7
|
my %data = data_constructor($self, $date, %coordinates); |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
sub data_constructor { |
165
|
2
|
|
|
2
|
1
|
5
|
my $self = shift; |
166
|
2
|
|
|
|
|
4
|
my $date = shift; |
167
|
2
|
|
|
|
|
6
|
my %coord = @_; |
168
|
2
|
|
|
|
|
6
|
my $error = ""; |
169
|
|
|
|
|
|
|
|
170
|
2
|
|
|
|
|
10
|
%coord = (%coord, sexag2dec($self, %coord)); |
171
|
2
|
|
|
|
|
12
|
%coord = check_error(%coord); |
172
|
|
|
|
|
|
|
|
173
|
2
|
|
|
|
|
14
|
my @DEPARTURE = NESW( $coord{long_1_dec}, $coord{lat_1_dec} ); |
174
|
2
|
|
|
|
|
62
|
my @ARRIVE = NESW( $coord{long_2_dec}, $coord{lat_2_dec} ); |
175
|
2
|
|
|
|
|
32
|
my $km = great_circle_distance(@DEPARTURE, @ARRIVE, 6371); # medium value for Earth radii |
176
|
2
|
|
|
|
|
141
|
$km = sprintf("%.2f",$km); |
177
|
2
|
|
|
|
|
8
|
my $mi = $km / 1.609344; # miles conversion |
178
|
2
|
|
|
|
|
11
|
$mi = sprintf("%.2f",$mi); |
179
|
2
|
|
|
|
|
9
|
my $rad = great_circle_direction(@DEPARTURE, @ARRIVE); |
180
|
2
|
|
|
|
|
77
|
my $sexag = dec2sexag($self, rad2deg($rad)); |
181
|
2
|
|
|
|
|
9
|
my $rad_round = sprintf("%.2f",(rad2deg($rad))); |
182
|
2
|
|
|
|
|
24
|
my $compass = compass($self, rad2deg($rad)); |
183
|
|
|
|
|
|
|
|
184
|
2
|
|
|
|
|
9
|
my $locator_dep = degree2loc($self, $coord{lat_1}, $coord{long_1}); |
185
|
2
|
|
|
|
|
472
|
my $locator_arr = degree2loc($self, $coord{lat_2}, $coord{long_2}); |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
|
188
|
2
|
|
|
|
|
303
|
my %sun_departure = cicle_sun($self, $coord{lat_1_dec}, $coord{long_1_dec}, $date, "_departure"); |
189
|
2
|
|
|
|
|
11
|
my %sun_arrive = cicle_sun($self, $coord{lat_2_dec}, $coord{long_2_dec}, $date, "_arrive"); |
190
|
|
|
|
|
|
|
|
191
|
2
|
|
|
|
|
37
|
%coord = ( %coord, |
192
|
|
|
|
|
|
|
distance_km => $km, |
193
|
|
|
|
|
|
|
distance_mi => $mi, |
194
|
|
|
|
|
|
|
course_sexag => $sexag, |
195
|
|
|
|
|
|
|
course_dec => $rad_round, |
196
|
|
|
|
|
|
|
compass => $compass, |
197
|
|
|
|
|
|
|
date => $date, |
198
|
|
|
|
|
|
|
locator_1 => $locator_dep, |
199
|
|
|
|
|
|
|
locator_2 => $locator_arr, |
200
|
|
|
|
|
|
|
%sun_departure, %sun_arrive |
201
|
|
|
|
|
|
|
); |
202
|
2
|
50
|
|
|
|
9
|
if ($error) { return my %error = (_error => $error); } |
|
0
|
|
|
|
|
0
|
|
203
|
|
|
|
|
|
|
|
204
|
2
|
|
|
|
|
47
|
return %coord; |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=head2 loc2degree |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
Gets a string with grid locator value and returns an array with the latitude and |
210
|
|
|
|
|
|
|
longitude in sexagesimal degrees form. Grid precision only 6 digit. |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
=cut |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
sub loc2degree { |
215
|
2
|
|
|
2
|
1
|
5
|
my ($self,$loc) = @_; |
216
|
2
|
|
|
|
|
15
|
my $grid = new Ham::Locator; |
217
|
2
|
|
|
|
|
17
|
$grid->set_precision($locator_precision); |
218
|
2
|
50
|
|
|
|
37
|
$loc = substr($loc, 0, 6) if (length($loc) > 6); |
219
|
|
|
|
|
|
|
|
220
|
2
|
|
|
|
|
9
|
$grid->set_loc($loc); |
221
|
2
|
|
|
|
|
24
|
my ($latitude, $longitude) = $grid->loc2latlng; |
222
|
2
|
|
|
|
|
380
|
my $lat_sexag = dec2sexag($self, $latitude); |
223
|
2
|
|
|
|
|
5
|
my $long_sexag = dec2sexag($self, $longitude); |
224
|
|
|
|
|
|
|
|
225
|
2
|
100
|
|
|
|
7
|
$lat_sexag =~ tr/-/ / if($latitude < 0); |
226
|
2
|
100
|
|
|
|
7
|
$long_sexag =~ tr/S/W/ if($longitude < 0); |
227
|
2
|
100
|
|
|
|
7
|
$long_sexag =~ tr/N/E/ if($longitude > 0); |
228
|
2
|
100
|
|
|
|
6
|
$long_sexag =~ tr/-/ / if($longitude < 0); |
229
|
|
|
|
|
|
|
|
230
|
2
|
|
|
|
|
14
|
return ($lat_sexag, $long_sexag); |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=head2 degree2loc |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
Gets a string with the latitude and a string with the longitude, in sexagesimal |
236
|
|
|
|
|
|
|
notation, of a point on Earth and returns a string with the grid locator notation. |
237
|
|
|
|
|
|
|
Grid precision now is 8 digit. |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
my $lat = "41N23"; |
240
|
|
|
|
|
|
|
my $long = "2E11"; |
241
|
|
|
|
|
|
|
my $locator = $foo->degree2loc($lat, $long); |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
=cut |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
sub degree2loc { |
246
|
5
|
|
|
5
|
1
|
515
|
my ($self, $lat, $long) = @_; |
247
|
5
|
|
|
|
|
21
|
my %deg_coord = ( |
248
|
|
|
|
|
|
|
lat_1 => $lat, |
249
|
|
|
|
|
|
|
long_1 => $long |
250
|
|
|
|
|
|
|
); |
251
|
5
|
|
|
|
|
19
|
my %dec_coord = sexag2dec($self, %deg_coord); |
252
|
5
|
|
|
|
|
22
|
my %check = check_error(%dec_coord); |
253
|
5
|
50
|
|
|
|
24
|
if ($check{_error}) { return "Error to convert degrees to locator."; } |
|
0
|
|
|
|
|
0
|
|
254
|
|
|
|
|
|
|
|
255
|
5
|
|
|
|
|
44
|
my $m = new Ham::Locator; |
256
|
5
|
|
|
|
|
58
|
$m->set_precision($locator_precision); |
257
|
5
|
|
|
|
|
108
|
$m->set_latlng($dec_coord{lat_1_dec}, $dec_coord{long_1_dec}); |
258
|
5
|
|
|
|
|
76
|
my $loc = $m->latlng2loc; |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
=head2 compass |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
Gets an integer with a decimal degree and returns a string with its |
264
|
|
|
|
|
|
|
equivalent value in a compass (North, East, ...). It uses a separation of 11.25 |
265
|
|
|
|
|
|
|
degrees for each position, 32 cardinal positions of total. |
266
|
|
|
|
|
|
|
Values range must be between 0 to 360 degrees. |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
my $compass = $foo->compass("-90.0"); # returns "W" (west) |
269
|
|
|
|
|
|
|
my $compass = $foo->compass("270.0"); # returns "W" (west) |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=cut |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub compass { |
274
|
3
|
|
|
3
|
1
|
457
|
my $self = shift; |
275
|
3
|
|
|
|
|
7
|
my $course = shift; |
276
|
3
|
|
|
|
|
16
|
my $pattern = qr/(\+?)(-?)\d{1,3}(\.?)(\d*)$/; |
277
|
3
|
|
|
|
|
6
|
my $error_msg = "Error value must be a integer between 0 to 360"; |
278
|
|
|
|
|
|
|
|
279
|
3
|
50
|
|
|
|
37
|
if ($course !~ $pattern) { |
280
|
0
|
|
|
|
|
0
|
return $error_msg; |
281
|
|
|
|
|
|
|
} else { |
282
|
3
|
50
|
33
|
|
|
36
|
if ($course < -360 or $course > 360) { return $error_msg; } |
|
0
|
|
|
|
|
0
|
|
283
|
3
|
|
|
|
|
33
|
my @rosa = ('NbE','NNE','NEbN','NE','NEbE','ENE','EbN','E','EbS','ESE','SEbE','SE','SEbS','SSE','SbE','S','SbW','SSW','SWbS','SW','SWbW','WSW','WbS','W','WbN','WNW','NWbW','NW','NWbN','NNW','NbW','N'); |
284
|
|
|
|
|
|
|
|
285
|
3
|
|
|
|
|
11
|
my $rosa_index = int((+$course / 11.25))-1; |
286
|
3
|
|
|
|
|
18
|
return $rosa[$rosa_index]; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=head2 dec2sexag |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
Gets an integer with a decimal degree value and returns a string with its |
293
|
|
|
|
|
|
|
equivalence to sexagesimal degree form. Only returns degrees and minutes. |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
=cut |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
sub dec2sexag{ |
298
|
7
|
|
|
7
|
1
|
499
|
my ($self, $course) = @_; |
299
|
7
|
|
|
|
|
50
|
my @degree_part = split(/\./, $course); |
300
|
7
|
|
|
|
|
30
|
my $decimal = (('0.'.$degree_part[1]) * 60); |
301
|
7
|
|
|
|
|
41
|
my $min = int((sprintf("%.2f",$decimal))); |
302
|
7
|
|
|
|
|
40
|
my $sexag = $degree_part[0].".".$min; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=head2 sexag2dec |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
Gets a hash with sexagesimal value (maximun four) and returns a hash with its |
308
|
|
|
|
|
|
|
decimal values. |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
Range of values are -90 to 90 for latitudes, and -180 to 180 for longitudes. |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
Values must be a pair, longitude and latitude. Two values for one point or |
313
|
|
|
|
|
|
|
four values (two pairs) for two points. |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
There is not mandatory send a complete hash (4 values), but you will receive a |
316
|
|
|
|
|
|
|
hash with the four. |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
You can use it like this: |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
my %coord = ( |
321
|
|
|
|
|
|
|
Long_1 => "41N23.30", |
322
|
|
|
|
|
|
|
Lat_1 => "2E11.10" |
323
|
|
|
|
|
|
|
); |
324
|
|
|
|
|
|
|
my %sexag = $foo->sexag2dec(%coord); |
325
|
|
|
|
|
|
|
foreach my $key (sort keys %sexag) { |
326
|
|
|
|
|
|
|
say $key." = ".$sexag{$key} if ($sexag{$key}); |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
The index send it, you will receive with '_dec' suffix, ie, you send |
330
|
|
|
|
|
|
|
'latitude' and receive 'latitude_dec' |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=cut |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
sub sexag2dec { |
335
|
9
|
|
|
9
|
1
|
1088
|
my $self = shift; |
336
|
9
|
|
|
|
|
29
|
my %coord = @_; |
337
|
|
|
|
|
|
|
|
338
|
9
|
|
|
|
|
20
|
my $error_msg_1 = "Error sexagesimal conversion. Out of range. (-90 to 90)"; |
339
|
9
|
|
|
|
|
18
|
my $error_msg_2 = "Error sexagesimal conversion. Out of range. (-180 to 180)"; |
340
|
|
|
|
|
|
|
|
341
|
9
|
|
|
|
|
40
|
my $grad_match = qr|(\d{1,3})([NSEOW+-\.])(\d{1,2})\.{0,1}(\d{0,2}){0,1}|i; |
342
|
9
|
|
|
|
|
42
|
my %coord_dec = ( |
343
|
|
|
|
|
|
|
lat_1_dec => '', |
344
|
|
|
|
|
|
|
lat_2_dec => '', |
345
|
|
|
|
|
|
|
long_1_dec => '', |
346
|
|
|
|
|
|
|
long_2_dec => '', |
347
|
|
|
|
|
|
|
); |
348
|
9
|
|
|
|
|
18
|
my $secs = undef; |
349
|
9
|
|
|
|
|
62
|
foreach my $key (sort keys %coord) { |
350
|
22
|
50
|
|
|
|
132
|
if ($4) {$secs = $4/3600;} else {$secs = 0} |
|
0
|
|
|
|
|
0
|
|
|
22
|
|
|
|
|
38
|
|
351
|
22
|
50
|
33
|
|
|
239
|
if ($key && ($coord{$key} =~ $grad_match)) { |
352
|
22
|
100
|
100
|
|
|
139
|
if ($2 eq 'S' || $2 eq 'W' || $2 eq '-') { |
|
|
|
66
|
|
|
|
|
353
|
10
|
|
|
|
|
50
|
$coord_dec{$key.'_dec'} = (-($1+(($3/60)+$secs))); |
354
|
10
|
50
|
66
|
|
|
86
|
if ($2 eq 'S' && $coord_dec{$key.'_dec'} < -90) { $coord_dec{$key.'_dec'} = $error_msg_1; } |
|
0
|
|
|
|
|
0
|
|
355
|
10
|
50
|
66
|
|
|
69
|
if ($2 eq 'W' && $coord_dec{$key.'_dec'} < -180) { $coord_dec{$key.'_dec'} = $error_msg_2; } |
|
0
|
|
|
|
|
0
|
|
356
|
|
|
|
|
|
|
} else { |
357
|
12
|
|
|
|
|
87
|
$coord_dec{$key.'_dec'} = ($1+(($3/60)+$secs)); |
358
|
12
|
50
|
66
|
|
|
76
|
if ($2 eq 'N' && $coord_dec{$key.'_dec'} > 90) { $coord_dec{$key.'_dec'} = $error_msg_1; } |
|
0
|
|
|
|
|
0
|
|
359
|
12
|
50
|
66
|
|
|
73
|
if ($2 eq 'E' && $coord_dec{$key.'_dec'} > 180) { $coord_dec{$key.'_dec'} = $error_msg_2; } |
|
0
|
|
|
|
|
0
|
|
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
} |
363
|
9
|
|
|
|
|
83
|
return %coord_dec; |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
=head2 cicle_sun |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
Gets three strings with latitude, longitude, in decimal degrees, and date, in |
369
|
|
|
|
|
|
|
'dd-mm-yyyy' format and returns a hash with Sunrise time, Sunset time and |
370
|
|
|
|
|
|
|
Midday time in hours and minutes format in Universal Time (UTC). |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
my %sun = $foo->cicle_sun($lat,$long,$date); |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
=cut |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
sub cicle_sun { |
377
|
5
|
|
|
5
|
1
|
17
|
my $self = shift; |
378
|
5
|
|
|
|
|
15
|
my ($Lat, $Long, $date, $origin_point) = @_; |
379
|
|
|
|
|
|
|
|
380
|
5
|
100
|
|
|
|
17
|
$origin_point = "" if (!$origin_point); |
381
|
5
|
50
|
|
|
|
21
|
$date = "00-00-0000" if ($date =~ /Error/); |
382
|
5
|
50
|
|
|
|
33
|
$Lat = 0 if ($Lat =~ /Error/); |
383
|
5
|
50
|
|
|
|
23
|
$Long = 0 if ($Long =~ /Error/); |
384
|
|
|
|
|
|
|
|
385
|
5
|
|
|
|
|
23
|
my @date_ = date_split($self, $date); |
386
|
5
|
|
|
|
|
11
|
my $day = $date_[0]; |
387
|
5
|
|
|
|
|
11
|
my $month = $date_[1]; |
388
|
5
|
|
|
|
|
8
|
my $year = $date_[2]; |
389
|
5
|
|
|
|
|
18
|
my $UT = '0'; |
390
|
|
|
|
|
|
|
|
391
|
5
|
50
|
|
|
|
15
|
if ($day =~ /Error/) { |
392
|
0
|
|
|
|
|
0
|
return my %solar_cycle = (_error => $day); |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
# Julian data |
397
|
5
|
|
|
|
|
25
|
my $GGG = 1; |
398
|
5
|
|
|
|
|
16
|
my $S = 1; |
399
|
|
|
|
|
|
|
|
400
|
5
|
50
|
|
|
|
18
|
if ($year <= 1585) { $GGG = 0; } |
|
0
|
|
|
|
|
0
|
|
401
|
5
|
|
|
|
|
25
|
my $JD = -1 * int(7 * (int(($month + 9) / 12 ) + $year) / 4); |
402
|
5
|
50
|
|
|
|
15
|
if (($month - 9) < 0) { $S = -1; } |
|
5
|
|
|
|
|
9
|
|
403
|
5
|
|
|
|
|
11
|
my $A = abs($month - 9); |
404
|
5
|
|
|
|
|
11
|
my $J1 = int($year + $S * int($A / 7)); |
405
|
5
|
|
|
|
|
14
|
$J1 = -1 * int((int($J1 / 100) + 1) * 3 / 4); |
406
|
5
|
|
|
|
|
13
|
$JD = $JD + int(275 * $month / 9) + $day + ($GGG * $J1); |
407
|
5
|
|
|
|
|
13
|
$JD = $JD + 1721027 + 2 * $GGG + 367 * $year - 0.5; |
408
|
5
|
|
|
|
|
10
|
my $J2 = $JD; |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
# Earth values |
411
|
5
|
|
|
|
|
8
|
my $RAD = 180 / pi; |
412
|
5
|
|
|
|
|
8
|
my $ET = 0.016718; |
413
|
5
|
|
|
|
|
17
|
my $VP = 8.22e-5; |
414
|
5
|
|
|
|
|
7
|
my $P = 4.93204; |
415
|
5
|
|
|
|
|
14
|
my $M0 = 2.12344; |
416
|
5
|
|
|
|
|
10
|
my $MN = 1.72019e-2; |
417
|
5
|
|
|
|
|
9
|
my $T0 = 2444000.5; |
418
|
5
|
|
|
|
|
8
|
$S = 2415020.5; |
419
|
5
|
|
|
|
|
14
|
$P = $P + ($J2 - $T0) * $VP / 100; |
420
|
5
|
|
|
|
|
37
|
my $AM = $M0 + $MN * ($J2 - $T0); |
421
|
5
|
|
|
|
|
26
|
$AM = $AM - 2 * pi * int($AM / (2 * pi)); |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
# Kepler equation for the Earth |
424
|
5
|
|
|
|
|
94
|
my $V = $AM + 2 * $ET * sin($AM) + 1.25 * $ET * $ET * sin(2 * $AM); |
425
|
5
|
50
|
|
|
|
23
|
if ($V < 0) { |
426
|
0
|
|
|
|
|
0
|
$V = 2 * pi + $V; |
427
|
|
|
|
|
|
|
} |
428
|
5
|
|
|
|
|
11
|
my $L = $P + $V; |
429
|
5
|
|
|
|
|
12
|
$L = $L - 2 * pi * int($L / (2 * pi)); |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
#AR and DEC calculus |
432
|
5
|
|
|
|
|
10
|
my $Z = ($J2 - 2415020.5) / 365.2422; |
433
|
5
|
|
|
|
|
13
|
my $OB = 23.452294 - (0.46845 * $Z + 0.00000059 * $Z * $Z) / 3600; |
434
|
5
|
|
|
|
|
9
|
$OB = $OB / $RAD; |
435
|
5
|
|
|
|
|
26
|
my $DC = asin(sin($OB) * sin($L)); |
436
|
5
|
|
|
|
|
89
|
my $AR = acos(cos($L) / cos($DC)); |
437
|
5
|
50
|
|
|
|
61
|
if ($L > pi) { |
438
|
0
|
|
|
|
|
0
|
$AR = 2 * pi - $AR; |
439
|
|
|
|
|
|
|
} |
440
|
5
|
|
|
|
|
9
|
$OB = $OB * $RAD; |
441
|
5
|
|
|
|
|
8
|
$L = $L * $RAD; |
442
|
5
|
|
|
|
|
11
|
$AR = $AR * 12 / pi; |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
# HH.MM to AR conversion |
445
|
5
|
|
|
|
|
9
|
my $H = int($AR); |
446
|
5
|
|
|
|
|
13
|
my $M = int(($AR - int($AR)) * 60); |
447
|
5
|
|
|
|
|
13
|
$S=(($AR - int($AR)) * 60 - $M) * 60; |
448
|
5
|
|
|
|
|
7
|
$DC = $DC * $RAD; |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
# Degrees conversion from DEC |
451
|
5
|
|
|
|
|
10
|
my $D = abs($DC); |
452
|
5
|
50
|
|
|
|
17
|
if ($DC > 0) { |
453
|
5
|
|
|
|
|
13
|
my $G1 = int($D); |
454
|
|
|
|
|
|
|
} else { |
455
|
0
|
|
|
|
|
0
|
my $G1 = (-1) * int($D); |
456
|
|
|
|
|
|
|
} |
457
|
5
|
|
|
|
|
21
|
my $M1 = int(($D - int($D)) * 60); |
458
|
5
|
|
|
|
|
21
|
my $S1 = (($D - int($D)) * 60 - $M1) * 60; |
459
|
5
|
50
|
|
|
|
23
|
if ($DC < 0) { |
460
|
0
|
|
|
|
|
0
|
$M1 = -$M1; |
461
|
0
|
|
|
|
|
0
|
$S1 = -$S1; |
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
# Time equation |
465
|
5
|
|
|
|
|
44
|
my $MR = 0.04301; |
466
|
5
|
|
|
|
|
12
|
my $F = 13750.987; |
467
|
5
|
|
|
|
|
20
|
my $C = 2 * $ET * $F * sin($AM) + 1.25 * $ET * $ET * $F * sin(2 * $AM); |
468
|
5
|
|
|
|
|
20
|
my $R = -$MR * $F * sin(2 * ($P + $AM)) + $MR * $MR * $F * sin(4 * ($P + $AM)) / 2; |
469
|
5
|
|
|
|
|
16
|
$ET = $C + $R; |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
# Semi-diurn arc calculus |
472
|
5
|
|
|
|
|
21
|
my $H0 = acos(-tan($Lat / $RAD) * tan($DC / $RAD)); |
473
|
5
|
|
|
|
|
173
|
$H0 = $H0 * $RAD; |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
# DEC variations |
476
|
5
|
|
|
|
|
24
|
my $VD = 0.9856 * sin($OB / $RAD) * cos($L / $RAD) / cos($DC / $RAD); |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
# Sun rise calculus |
479
|
5
|
|
|
|
|
14
|
my $VDOR = $VD * (-$H0 + 180) / 360; |
480
|
5
|
|
|
|
|
11
|
my $DCOR = $DC + $VDOR; |
481
|
5
|
|
|
|
|
12
|
my $HORTO = -acos(-tan($Lat / $RAD) * tan($DCOR / $RAD)); |
482
|
5
|
|
|
|
|
143
|
my $VHORTO = 5 / (6 * cos($Lat / $RAD) * cos($DCOR / $RAD) * sin($HORTO)); |
483
|
5
|
|
|
|
|
12
|
$HORTO = ($HORTO * $RAD + $VHORTO) / 15; |
484
|
5
|
|
|
|
|
16
|
my $TUORTO = $HORTO + $ET / 3600 - $Long / 15 + 12; |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
# Sun rise value conversion to HH.MM |
487
|
5
|
|
|
|
|
9
|
my $HOR = int($TUORTO); |
488
|
5
|
|
|
|
|
13
|
my $MOR = int(($TUORTO - $HOR) * 60 + 0.5); |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
# AZ calculation |
491
|
5
|
|
|
|
|
15
|
my $TUC = 12 + $ET / 3600 - $Long / 15; |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
# AZ value conversion to HH.MM |
494
|
5
|
|
|
|
|
22
|
my $HC = int($TUC); |
495
|
5
|
|
|
|
|
15
|
my $MC = int(($TUC - $HC) * 60 + 0.5); |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
# Sunset calculus |
498
|
5
|
|
|
|
|
23
|
my $VDOC = $VD * ($H0 + 180) / 360; |
499
|
5
|
|
|
|
|
12
|
my $DCOC = $DC + $VDOC; |
500
|
5
|
|
|
|
|
17
|
my $HOC = acos(-tan($Lat / $RAD) * tan($DCOC / $RAD)); |
501
|
5
|
|
|
|
|
147
|
my $VHOC = 5 / (6 * cos($Lat / $RAD) * cos($DCOC / $RAD) * sin($HOC)); |
502
|
5
|
|
|
|
|
10
|
$HOC = ($HOC * $RAD + $VHOC) / 15; |
503
|
5
|
|
|
|
|
14
|
my $TUOC = $HOC + $ET / 3600 - $Long / 15 + 12; |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
# Sunset conversion to HH.MM |
506
|
5
|
|
|
|
|
8
|
$HOC = int($TUOC); |
507
|
5
|
|
|
|
|
12
|
my $MOC = int(($TUOC - $HOC) * 60 + 0.5); |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
# Altitude of AZ |
510
|
5
|
|
|
|
|
13
|
my $HCUL = 90 - $Lat + ($DCOR + $DCOC) / 2; |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
# Degree conversion from altitude |
513
|
5
|
|
|
|
|
9
|
my $GCUL = int($HCUL); |
514
|
5
|
|
|
|
|
14
|
my $MCUL = int (($HCUL - $GCUL) * 60 + 0.5); |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
# AZ from Sunrise and Sunset |
517
|
5
|
|
|
|
|
27
|
my $ACOC = acos(-sin($DCOC / $RAD) / cos($Lat / $RAD)) * $RAD; |
518
|
5
|
|
|
|
|
39
|
my $ACOR = 360 - acos(-sin($DCOR / $RAD) / cos($Lat / $RAD)) * $RAD; |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
# AZ conversion to degrees |
521
|
5
|
|
|
|
|
37
|
my $GACOC = int($ACOC); |
522
|
5
|
|
|
|
|
14
|
my $MACOC = int(($ACOC - $GACOC) * 60 + 0.5); |
523
|
5
|
|
|
|
|
9
|
my $GACOR = int($ACOR); |
524
|
5
|
|
|
|
|
12
|
my $MACOR = int(($ACOR - $GACOR) * 60 + 0.5); |
525
|
|
|
|
|
|
|
|
526
|
5
|
|
|
|
|
18
|
my $sunrise = $HOR."h ".$MOR."m"; |
527
|
5
|
|
|
|
|
15
|
my $sunset = $HOC."h ".$MOC."m"; |
528
|
5
|
|
|
|
|
14
|
my $midday = $HC."h ".$MC."m"; |
529
|
|
|
|
|
|
|
|
530
|
5
|
|
|
|
|
17
|
my $k_sunrise = "sunrise".$origin_point; |
531
|
5
|
|
|
|
|
19
|
my $k_sunset = "sunset".$origin_point; |
532
|
5
|
|
|
|
|
9
|
my $k_midday = "midday".$origin_point; |
533
|
|
|
|
|
|
|
|
534
|
5
|
|
|
|
|
24
|
my %solar_cycle = ( |
535
|
|
|
|
|
|
|
$k_sunrise => $sunrise, |
536
|
|
|
|
|
|
|
$k_sunset => $sunset, |
537
|
|
|
|
|
|
|
$k_midday => $midday, |
538
|
|
|
|
|
|
|
); |
539
|
|
|
|
|
|
|
|
540
|
5
|
50
|
|
|
|
16
|
if ($day =~ /Error/) { |
541
|
0
|
|
|
|
|
0
|
return my %solar_cycle = (_error => $day); |
542
|
|
|
|
|
|
|
} |
543
|
5
|
50
|
33
|
|
|
39
|
if ($Lat == 0 || $Long == 0) { |
544
|
0
|
|
|
|
|
0
|
%solar_cycle = (_error => "Error sexagesimal conversion. Out of range."); |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
|
547
|
5
|
|
|
|
|
56
|
return %solar_cycle; |
548
|
|
|
|
|
|
|
} |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
=head2 date_split |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
Gets a string with date in format 'dd-mm-yyyy' and check it if value is a valid date. |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
Returns an array with the day, month and year ... or error message. |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
=cut |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
sub date_split { |
559
|
6
|
|
|
6
|
1
|
545
|
my ($self, $date) = @_; |
560
|
6
|
|
|
|
|
13
|
my @part_of_date; |
561
|
6
|
|
|
|
|
18
|
my $check = is_date($date); |
562
|
6
|
50
|
|
|
|
24
|
if ($check !~ /Error/) { |
563
|
6
|
|
|
|
|
31
|
return @part_of_date = split(/-/,$date); |
564
|
|
|
|
|
|
|
} else { |
565
|
0
|
|
|
|
|
0
|
return $part_of_date[0] = $check; |
566
|
|
|
|
|
|
|
} |
567
|
|
|
|
|
|
|
} |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
# --------------- |
570
|
|
|
|
|
|
|
# INTERNAL SUBS |
571
|
|
|
|
|
|
|
# --------------- |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
=head1 Internals subs |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
=head2 data_constructor |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
Internal function used by data_by_coordinates() and data_by_locator() to call the others functions and create a response. |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
=head2 NESW |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
Internal function to convert degrees to radians. |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
=head2 check_error |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
Internal function to check errors in data_by_coordinates() or data_by_locator(). |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
=head2 is_date |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
Internal function to check if a date is valid. |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
=cut |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
sub NESW { |
594
|
4
|
|
|
4
|
1
|
18
|
deg2rad($_[0]), deg2rad(90 - $_[1]) |
595
|
|
|
|
|
|
|
} |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
sub is_date { |
598
|
6
|
|
|
6
|
1
|
12
|
my $date = shift; |
599
|
6
|
|
|
|
|
38
|
my $pattern = qr/\d{1,2}(-)\d{1,2}(-)\d{4}/; |
600
|
|
|
|
|
|
|
|
601
|
6
|
50
|
|
|
|
57
|
if ($date !~ $pattern) { |
602
|
0
|
|
|
|
|
0
|
return "Error date format. Must be dd-mm-yyyy"; |
603
|
|
|
|
|
|
|
} else { |
604
|
6
|
|
|
|
|
26
|
my @part_of_date = split(/-/,$date); |
605
|
|
|
|
|
|
|
|
606
|
6
|
50
|
|
|
|
43
|
my $intDay = ($part_of_date[0] <= 9) ? sprintf("%02d", $part_of_date[0]) : sprintf("%2d", $part_of_date[0]); |
607
|
6
|
50
|
|
|
|
30
|
my $intMonth = ($part_of_date[1] <= 9) ? sprintf("%02d", $part_of_date[1]) : sprintf("%2d", $part_of_date[1]); |
608
|
6
|
|
|
|
|
14
|
my $intYear = $part_of_date[2]; |
609
|
|
|
|
|
|
|
|
610
|
6
|
|
|
|
|
63
|
my %array_month = ( |
611
|
|
|
|
|
|
|
'01' => 31, |
612
|
|
|
|
|
|
|
'02' => 0, |
613
|
|
|
|
|
|
|
'03' => 31, |
614
|
|
|
|
|
|
|
'04' => 30, |
615
|
|
|
|
|
|
|
'05' => 31, |
616
|
|
|
|
|
|
|
'06' => 30, |
617
|
|
|
|
|
|
|
'07' => 31, |
618
|
|
|
|
|
|
|
'08' => 31, |
619
|
|
|
|
|
|
|
'09' => 30, |
620
|
|
|
|
|
|
|
'10' => 31, |
621
|
|
|
|
|
|
|
'11' => 30, |
622
|
|
|
|
|
|
|
'12' => 31, |
623
|
|
|
|
|
|
|
); |
624
|
|
|
|
|
|
|
|
625
|
6
|
50
|
|
|
|
27
|
if ($intMonth > 12) { return "Error in date format. This must be a valid dd-mm-yyyy." } |
|
0
|
|
|
|
|
0
|
|
626
|
|
|
|
|
|
|
|
627
|
6
|
50
|
33
|
|
|
42
|
if ($array_month{$intMonth} != 0 && $part_of_date[0] <= $array_month{$intMonth}) { |
628
|
6
|
|
|
|
|
45
|
return 1; |
629
|
|
|
|
|
|
|
} |
630
|
|
|
|
|
|
|
|
631
|
0
|
0
|
|
|
|
0
|
if ($intMonth == 0) { |
632
|
0
|
0
|
0
|
|
|
0
|
if ($intDay > 0 && $intDay < 29) { |
|
|
0
|
|
|
|
|
|
633
|
0
|
|
|
|
|
0
|
return 1; |
634
|
|
|
|
|
|
|
} |
635
|
|
|
|
|
|
|
elsif ($intDay == 29) { |
636
|
0
|
0
|
0
|
|
|
0
|
if (($intYear % 4 == 0) && ($intYear % 100 != 0) || ($intYear % 400) == 0) { |
|
|
|
0
|
|
|
|
|
637
|
0
|
|
|
|
|
0
|
return 1; |
638
|
|
|
|
|
|
|
} |
639
|
|
|
|
|
|
|
} |
640
|
|
|
|
|
|
|
} |
641
|
|
|
|
|
|
|
|
642
|
0
|
|
|
|
|
0
|
return "Error in date format. This must be a valid dd-mm-yyyy."; |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
} |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
sub check_error { |
647
|
7
|
|
|
7
|
1
|
26
|
my %coord = @_; |
648
|
7
|
|
|
|
|
32
|
foreach my $key (sort keys %coord) { |
649
|
36
|
50
|
|
|
|
144
|
if ($coord{$key} =~ /Error/) { |
650
|
0
|
|
|
|
|
0
|
$coord{_error} = $coord{$key}; |
651
|
0
|
|
|
|
|
0
|
$coord{$key} = 0; |
652
|
|
|
|
|
|
|
} |
653
|
|
|
|
|
|
|
} |
654
|
7
|
|
|
|
|
39
|
return %coord; |
655
|
|
|
|
|
|
|
} |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
=head1 Cheking Errors |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
In functions that return only a string or an array, errors will detect to match /Error/ word. |
661
|
|
|
|
|
|
|
In complex functions, like data_by_coordinates, that responses with a hash, you check the '_error' index, i.e: |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
%data = $foo->data_by_locator($date,$locator_1,$locator_2); |
664
|
|
|
|
|
|
|
if (!$data{_error}) { |
665
|
|
|
|
|
|
|
foreach my $key (sort keys %data) { |
666
|
|
|
|
|
|
|
say $key.": ".$data{$key}; |
667
|
|
|
|
|
|
|
} |
668
|
|
|
|
|
|
|
} else { |
669
|
|
|
|
|
|
|
say $data{_error}; |
670
|
|
|
|
|
|
|
} |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
... or something like this :p |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
=cut |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
=head1 AUTHOR |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
CJUAN, C<< >> |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
=head1 BUGS |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through |
684
|
|
|
|
|
|
|
the web interface at L. I will be notified, and then you'll |
685
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes. |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
=head1 SUPPORT |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
perldoc Ham::Resources::Utils |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
You can also look for information at: |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
=over 4 |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker (report bugs here) |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
L |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
L |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
=item * CPAN Ratings |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
L |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
=item * Search CPAN |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
L |
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
=back |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
=head1 TODO |
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
=over 4 |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
=item * Add long path course and distances from point A to B |
724
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
=item * Add a function to calculate X and Y coordinates based on real coordinates for use it on a geographical projection (or Plate Carree) |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
=back |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
Copyright 2012-2018 CJUAN. |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
735
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published |
736
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License. |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
See http://dev.perl.org/licenses/ for more information. |
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
=cut |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
1; # End of Ham::Resources::Utils |