Generated: Tue Feb 2 17:54:40 2010 from geturl.pl 2008/01/26 51.3 KB.
#!/perl -w # NAME: geturl.pl # AIM: Get the text from a URL page ... # 22/01/2008 - geoff mclane # references # see from : http://aviationweather.gov/static/help/taf-decode.php - see html/taf-decode.htm # from : http://mbev.net/wikka/METARSandTAFS # KJAX 020256Z 02003KT 10SM TSRA OVC01OCB SCT100 BKN130 18/17 A2996 # METAR's will always be published in the same order: see: html/METARSandTAFS.htm # see from : http://www.nws.noaa.gov/oso/oso1/oso12/document/guide.shtml # also from : http://www.faa.gov/about/office_org/field_offices/fsdo/orl/local_more/media/ppt/metar.ppt # from : http://www.srh.noaa.gov/srh/cwwd/msd/note6.html # from : http://www.wunderground.com/metarFAQ.asp # from : http://www.nws.noaa.gov/oso/oso1/oso12/overview.htm # from : http://www.flyingineurope.be/metar_taf_decode.htm # from : http://www.alaska.faa.gov/fai/afss/metar%20taf/metcont.htm # from : http://www.geocities.com/CapeCanaveral/Lab/6799/metarpg.htm # from : http://www.alaska.faa.gov/fai/afss/metar%20taf/sametar1.htm # from : http://weather.cod.edu/notes/metar.html use strict; use warnings; use Socket; use LWP::Simple; require 'logfile.pl' or die "Unable to load logfile.pl ...\n"; # log file stuff my ($LF); my $pgmname = $0; if ($pgmname =~ /\w{1}:\\.*/) { my @tmpsp = split(/\\/,$pgmname); $pgmname = $tmpsp[-1]; } my $outfile = "temp.$pgmname.txt"; open_log($outfile); prt( "$0 ... Hello, World ...\n" ); my $minkey = 16; # apt.dat.gz CODES - see http://x-plane.org/home/robinp/Apt810.htm for DETAILS my $aln = '1'; # airport line my $rln = '10'; # runways/taxiways line my $sealn = '16'; # Seaplane base header data. my $heliln = '17'; # Heliport header data. my $twrln = '14'; # Tower view location. my $rampln = '15'; # Ramp startup position(s) my $bcnln = '18'; # Airport light beacons my $wsln = '19'; # windsock my $minatc = '50'; my $twrfrq = '54'; # like 12210 TWR my $appfrq = '55'; # like 11970 ROTTERDAM APP my $maxatc = '56'; my $lastln = '99'; # end of file my @aptlist = (); my $aptcnt = 0; my @taflist = (); # This NEEDS to be adjusted to YOUR particular default location of these files. my $FGROOT = (exists $ENV{FG_ROOT}) ? $ENV{FG_ROOT} : "C:/FGCVS/FlightGear/data"; my $APTFILE = "$FGROOT/Airports/apt.dat.gz"; # the airports data file my $NAVFILE = "$FGROOT/Navaids/nav.dat.gz"; # the NAV, NDB, etc. data file my $testurl = 'http://weather.noaa.gov/pub/data/forecasts/taf/stations/LFPO.TXT'; my $testurl2 = 'http://weather.noaa.gov/pub/data/forecasts/taf/stations/XS50.TXT'; my $testtaf = 'KSFO 231456Z 03009KT 10SM FEW009 OVC020 06/04 A2999 RMK AO2 RAB25E33 SLP156 P0000 60003 T00610039 55000'; my $testtaf2 = '2008/01/09 04:09 NZWD TAF 090303 15022G32KT 0400 -SN BLSN OVC007 650079 520005 QNH2910INS GRID32022G32KT BECMG 1214 16017KT 1600 -SN BLSN BKN008 OVC012 620089 QNH2908INS GRID33017KT BECMG 1719 16015KT 3200 -SN SCT010 BKN010 OVC025 610159 QNH2912INS GRID33015KT BECMG 2301 16020KT 1200 -SN BLSN BKN008 OVC010 620089 510005 QNH2915INS GRID33020KT'; my $acttaf = ''; my @warnings = (); my $cannedtaf = 'taf200825.txt'; ##load_airport_file($APTFILE); $aptcnt = scalar @aptlist; prt( "Got $aptcnt airports loaded ...\n" ); for (my $i = 1; $i <= $aptcnt; $i++) { show_airport($i); } ###fetch_url( $testurl ); if (open TF, "<$cannedtaf") { @taflist = <TF>; close TF; } else { push(@taflist, $testtaf2); } foreach my $taf (@taflist) { chomp $taf; show_taf($taf); } foreach my $warn (@warnings) { prt( "$warn\n" ); } close_log($outfile,1); exit(0); sub fetch_url { my ($url) = shift; prt( "Fetching: $url\n" ); my $txt = get($url); if ($txt && length($txt)) { prt( "$txt\n" ); # the TEXT - something like # 2008/01/22 11:00 # TAF LFPO 221100Z 221818 20006KT 9999 SCT025 SCT040 # BECMG 1820 6000 SCT004 # TEMPO 2002 2000 BR BKN003 # TEMPO 0408 -RADZ BKN006 # BECMG 0810 BKN012 # BECMG 1214 BKN018 my $taftxt = $txt; $taftxt =~ s/\n/ /gm; $taftxt = trim_all($taftxt); prt( "$taftxt\n" ); # 2008/01/22 11:00 TAF LFPO 221100Z 221818 20006KT 9999 SCT025 SCT040 BECMG 1820 6000 SCT004 TEMPO 2002 2000 BR BKN003 TEMPO 0408 -RADZ BKN006 BECMG 0810 BKN012 BECMG 1214 BKN018 # 2008/01/22 17:00 TAF LFPO 221700Z 230024 20005KT 9999 SCT040 BECMG 0002 4000 BR BKN040 TEMPO 0205 2500 BR SCT006 BECMG 0810 19012KT BECMG 1416 BKN025 push(@taflist,$taftxt); } else { prt( "FAILED to get URL $url ...\n" ); } } sub show_taf { my ($taftxt) = shift; prt( "\nDECODE: $taftxt\n" ); my %metar = decode_metar($taftxt); my $msg = ''; foreach my $key (keys %metar) { my $hash = $metar{$key}; #if (($key eq 'wind')||($key eq 'visibility')) { # ||($key eq 'clouds')) { $msg = "$key "; $msg .= '.' while (length($msg) < $minkey); $msg .= ': '; if (ref($hash) eq "HASH") { my $mg = ''; foreach my $k (keys %{$hash}) { my $v = ${%{$hash}}{$k}; $mg .= ', ' if length($mg); $mg .= "$k=$v"; } $msg .= $mg; } else { $msg .= $metar{$key}; } prt( "$msg\n" ); } } sub number_format { my ($num, $len) = @_; my $rnum = $num; if ($len == 0) { $rnum = int($num); } else { my $val = 10; my $n = $len - 1; while ($n) { $val = $val * 10; $n--; } $rnum = (int($num * $val)) / $val; } return $rnum; } sub get_descriptor { my ($desc) = shift; # '(MI|PR|BC|DR|BL|SH|TS|FZ)?' = Descriptor if ($desc eq 'MI') { return 'MI (Shallow)'; } elsif ($desc eq 'BC') { return 'BC (Patches)'; } elsif ($desc eq 'PR') { return 'PR (Partial)'; } elsif ($desc eq 'TS') { return 'TS (Thunderstorm)'; } elsif ($desc eq 'BL') { return 'BL (Blowing)'; } elsif ($desc eq 'SH') { return 'SH (Showers)'; } elsif ($desc eq 'DR') { return 'DR (Drifting)'; } elsif ($desc eq 'FZ') { return 'FZ (Freezing)'; } return "$desc (CHECKME)"; } sub get_obscuration { my ($obs) = shift; if ($obs eq 'BR') { return 'BR (Mist >= 5/8SM)'; } elsif ($obs eq 'FG') { return 'FG (Fog < 5/8SM)'; } elsif ($obs eq 'FU') { return 'FU (Smoke)'; } elsif ($obs eq 'VA') { return 'VA (Volcanic Ash)'; } elsif ($obs eq 'SA') { return 'SA (Sand)'; } elsif ($obs eq 'HZ') { return 'HZ (Haze)'; } elsif ($obs eq 'PY') { return 'PY (Spray)'; } elsif ($obs eq 'DU') { return 'DU (Widespread dust)'; } ###return "$obs (CHECKME)"; return get_precipitation($obs); } sub get_precipitation { my ($prc) = shift; if ($prc eq 'DZ') { return 'DZ (Drizzle)'; } elsif ($prc eq 'RA') { return 'RA (Rain)'; } elsif ($prc eq 'SN') { return 'SN (Snow)'; } elsif ($prc eq 'SG') { return 'SG (Snow grains)'; } elsif ($prc eq 'IC') { return 'IC (Ice crystals)'; } elsif ($prc eq 'PL') { return 'PL (Ice pellets)'; } elsif ($prc eq 'GR') { return 'GR (Hail)'; } elsif ($prc eq 'GS') { return 'GS (Small hail/snow pellets)'; } elsif ($prc eq 'UP') { return 'UP (Unknown precipitation in automated observations)'; } return "$prc (CHECKME)"; } sub get_other { my ($oth) = shift; if ($oth eq 'SQ') { return 'SQ (Squall)'; } elsif ($oth eq 'SS') { return 'SS (Sandstorm)'; } elsif ($oth eq 'DS') { return 'DS (Duststorm)'; } elsif ($oth eq 'PO') { return 'PO (Well developed)'; } elsif ($oth eq 'FC') { return 'FC (Funnel cloud)'; } elsif ($oth eq '+FC') { return '+FC (tornado/waterspout)'; } ### ??? dust/sand whirls return "$oth (CHECKME)"; } sub prtw { my ($mg, $tf) = @_; if ($tf ne $acttaf) { $acttaf = $tf; push(@warnings,$tf); } prt($mg); chomp $mg; push(@warnings,$mg); } sub decode_metar { my ($tt) = shift; my ($part, $ppart, $had_dc, $msg); my ($v1,$v2,$v3,$v4,$v5,$v6, $tr, $tmpn, $tmptr); my @parts = split(/\s/, $tt); my $num_parts = scalar @parts; my %decoded_metar = (); $decoded_metar{'remarks'} = ''; $part = ''; $had_dc = 0; $msg = ''; for (my $i = 0; $i < $num_parts; $i++) { $ppart = $part; $part = $parts[$i]; $had_dc = 0; # no DECODE yet # if (ereg('RMK|AFT|TEMPO|BECMG|INTER', $part)) #if ($part =~ /(RMK|AFT|TEMPO|BECMG|INTER)/) { if (($part =~ /(RMK|AFT|TEMPO|BECMG|INTER)/)||($part eq 'BEC')||($part =~ /^BEC([0-9]{2,4})/) ) { $msg = "$part - The rest of the METAR is either a remark or temporary information. We keep the remark."; $decoded_metar{'remarks'} = $part; $i++; for ( ; $i < $num_parts; $i++) { $part = $parts[$i]; $decoded_metar{'remarks'} .= ' '.$part; } $decoded_metar{'remarks'} = trim_all($decoded_metar{'remarks'}); $had_dc = 1; last; } elsif (($part eq 'METAR')||($part eq 'SPECI')||($part eq 'TAF')) { $msg = "$part - Type of Report: METAR, SPECI, TAF"; $decoded_metar{'type'} = $part; $had_dc = 1; ###} elsif ($part eq 'AMD') { } elsif ($part =~ /^AMD(.*)$/) { $msg = "$part - Qualifier of report."; $v1 = $1; $tr = 'qualifier'; $tmptr = $tr; $tmpn = 0; while (defined $decoded_metar{$tmptr}) { $tmpn++; $tmptr = $tr.$tmpn; } if ($v1 && length($v1)) { $decoded_metar{$tmptr} = "Amendment $v1"; # $tr = 'qualifier'; } else { $decoded_metar{$tmptr} = 'Amended'; } $had_dc = 1; } elsif ($part =~ /^CAVOK(=)?/) { $msg = "$part - indicates Ceiling And Visibility OKay"; # (no cloud below 5000 feet, a visibility of 6 Statute Miles or more and # no precipitation, thunderstorms, shallow fog, or low drifting snow) # = indicates the end of the METAR report $v1 = $1; if ($v1 && length($v1)) { $decoded_metar{'end-report'} = $part.' (Clear, no cloud 5000 feet, vis 6 miles+, no rain ...)'; last; } else { $decoded_metar{'indication'} = $part.' (Clear, no cloud 5000 feet, vis 6 miles+, no rain ...)'; } $had_dc = 1; } elsif ($part =~ /^[A-Z]{4,5}$/) { $msg = "$part - Station Identifier."; # $decoded_metar{'icao'} = $part; $v1 = $part; $tr = 'icao'; $tmptr = $tr; $tmpn = 0; while (defined $decoded_metar{$tmptr}) { $tmpn++; $tmptr = $tr.$tmpn; } $decoded_metar{$tmptr} = $v1; $had_dc = 1; } elsif ($part =~ /([0-9]{2})([0-9]{2})([0-9]{2})Z/) { $msg = "$part - DATE, HOUR, MINUTES Z."; $decoded_metar{'time'}{'day'} = $1; $decoded_metar{'time'}{'hour'} = $2; $decoded_metar{'time'}{'mins'} = $3; if (($i + 1) < $num_parts) { $part = $parts[$i+1]; if ($part =~ /([0-9]{2})([0-9]{2})([0-9]{2})/) { $decoded_metar{'time2'}{'day'} = $1; ##$decoded_metar{'time2'}{'hour'} = $2; ##$decoded_metar{'time2'}{'mins'} = $3; $decoded_metar{'time2'}{'begin-hour'} = $2; $decoded_metar{'time2'}{'end-hour'} = $3; $i++; } } $had_dc = 1; } elsif ($part =~ /([0-9]{4})\/([0-9]{2})\/([0-9]{2})/) { $msg = "$part - got a DATE YYYY/MM/DD"; $decoded_metar{'record_date'}{'year'} = $1; $decoded_metar{'record_date'}{'month'} = $2; $decoded_metar{'record_date'}{'day'} = $3; if (($i + 1) < $num_parts) { $part = $parts[$i+1]; if ($part =~ /([0-9]{2}):([0-9]{2})/) { $decoded_metar{'record_date'}{'hour'} = $1; $decoded_metar{'record_date'}{'minutes'} = $2; $i++; $msg .= ", plus $part - HOUR, MINUTES"; } } $had_dc = 1; } elsif ($part =~ /(AUTO|COR|RTD|CC[A-Z]|RR[A-Z])/ ) { $msg = "$part - Report Modifier: AUTO, COR, CCx or RRx"; $v1 = $1; $decoded_metar{'report_mod'} = $v1; $had_dc = 1; } elsif ($part =~ /([0-9]{3}|VRB)([0-9]{2,3})G?([0-9]{2,3})?(KT|MPS|KMH)/) { $msg = "$part - Wind Group"; # Wind Group = 20006KT # Examples: # 18010KT - Wind one eight zero at one zero knots # 35012G20KT - Wind three five zero at one two gust two zero knots # 00000KT - Wind calm # VRB16G28KT - Wind variable at one six gust two eight knots $v1 = $1; # direction, or VRB = variable $v2 = $2; # wind speed $v3 = $3; # gusts, if any $v4 = $4; # units $tr = 'wind'; $tmptr = $tr; $tmpn = 0; while (defined $decoded_metar{$tmptr}) { $tmpn++; $tmptr = $tr.$tmpn; } $decoded_metar{$tmptr}{'deg'} = $v1; # $tmptr = 'wind'.[nn] if ($v2 == 0) { $decoded_metar{$tmptr}{'knots'} = 0; $decoded_metar{$tmptr}{'meters_per_second'} = 0; $decoded_metar{$tmptr}{'miles_per_hour'} = 0; } else { if ($v4 eq 'KT') { $decoded_metar{$tmptr}{'knots'} = $v2; # The windspeed measured in meters per second, rounded to one decimal place # $meterspersec = number_format($value * 0.5144, 1); $decoded_metar{$tmptr}{'meters_per_second'} = number_format( ($v2 * 0.5144), 1 ); # The windspeed measured in miles per hour, rounded to one decimal place $decoded_metar{$tmptr}{'miles_per_hour'} = number_format( ($v2 * 1.1508), 1 ); } elsif ($v4 eq 'MPS') { # The windspeed measured in meters per second */ $decoded_metar{$tmptr}{'meters_per_second'} = number_format( $v2, 1 ); # The windspeed measured in knots, rounded to one decimal place $decoded_metar{$tmptr}{'knots'} = number_format($v2 / 0.5144, 1); # The windspeed measured in miles per hour, rounded to one decimal place $decoded_metar{$tmptr}{'miles_per_hour'} = number_format($v2 / 0.5144 * 1.1508, 1); } elsif ($v4 eq 'KMH') { # The windspeed measured in kilometers per hour $decoded_metar{$tmptr}{'meters_per_second'} = number_format($v2 * 1000 / 3600, 1); $decoded_metar{$tmptr}{'knots'} = number_format($v2 * 1000 / 3600 / 0.5144, 1); # The windspeed measured in miles per hour, rounded to one decimal place $decoded_metar{$tmptr}{'miles_per_hour'} = number_format($decoded_metar{'wind'}{'knots'} * 1.1508, 1); } else { $decoded_metar{$tmptr}{'knots'} = "$v2 (KTS assumed!)"; } } $had_dc = 1; } elsif ($part =~ /^([0-9]{3})V([0-9]{3})$/) { # !empty($decoded_metar['wind'])) { $msg = "$part - Variable wind-direction"; $decoded_metar{'wind'}{'var_beg'} = $1; $decoded_metar{'wind'}{'var_end'} = $2; $had_dc = 1; } elsif ($part =~ /^([0-9]{4})([NS]?[EW]?)$/) { $msg = "$part - Visibility in meters (4 digits only)."; $v1 = $1; if ($v1 eq '0000') { $decoded_metar{'visibility'}{'prefix'} = -1; $decoded_metar{'visibility'}{'meter'} = 50; $decoded_metar{'visibility'}{'km'} = 0.05; $decoded_metar{'visibility'}{'ft'} = 164; $decoded_metar{'visibility'}{'mile'} = 0.031; } elsif ($v1 eq '9999') { # elseif ($regs[1] == '9999') # Special high value $decoded_metar{'visibility'}{'prefix'} = 1; $decoded_metar{'visibility'}{'meter'} = 10000; $decoded_metar{'visibility'}{'km'} = 10; $decoded_metar{'visibility'}{'ft'} = 32800; $decoded_metar{'visibility'}{'mile'} = 6.2; } else { # Normal visibility, returned in both small and large units. $decoded_metar{'visibility'}{'prefix'} = 0; $decoded_metar{'visibility'}{'km'} = number_format($v1 / 1000, 1); $decoded_metar{'visibility'}{'meter'} = number_format($v1, 1); $decoded_metar{'visibility'}{'ft'} = number_format($v1 * 3.28084, 1); $decoded_metar{'visibility'}{'mile'} = number_format($v1 / 1609.344, 1); } $had_dc = 1; } elsif ($part =~ /^(VC)?(-|\+)?(MI|PR|BC|DR|BL|SH|TS|FZ)?((DZ|RA|SN|SG|IC|PL|GR|GS|UP)+)?(BR|FG|FU|VA|DU|SA|HZ|PY)?(PO|SQ|FC|SS)?$/ ) { # } elseif (ereg('^(VC)?' . /* Proximity */ # '(-|\+)?' . /* Intensity */ # '(MI|PR|BC|DR|BL|SH|TS|FZ)?' . /* Descriptor */ # '((DZ|RA|SN|SG|IC|PL|GR|GS|UP)+)?' . /* Precipitation */ # '(BR|FG|FU|VA|DU|SA|HZ|PY)?' . /* Obscuration */ # '(PO|SQ|FC|SS)?$', /* Other */ $msg = "$part - Weather."; $v1 = $1; $v2 = $2; $v3 = $3; $v4 = $4; $v5 = $5; $v6 = $6; $tr = 'weather'; $tmptr = $tr; $tmpn = 0; while (defined $decoded_metar{$tmptr}) { $tmpn++; $tmptr = $tr.$tmpn; } # $decoded_metar{'weather'}{'proximity'} = $v1 if ($v1 && length($v1)); if ($v1 && length($v1)) { if ($v1 eq 'VC') { $decoded_metar{$tmptr}{'proximity'} = 'outside aerodrome (5-10km)'; # 'weather'.[nn] } else { $decoded_metar{$tmptr}{'proximity'} = 'outside aerodrome (5-10km) $v1 CHECKME'; } } else { $decoded_metar{$tmptr}{'proximity'} = 'at aerodrome'; } ###$decoded_metar{'weather'}{'intensity'} = $v2 if ($v2 && length($v2)); if ($v2 && length($v2)) { if ($v2 eq '-') { $decoded_metar{$tmptr}{'intensity'} = 'light (-)'; } elsif ($v2 eq '+') { $decoded_metar{$tmptr}{'intensity'} = 'heavy (+)'; } else { $decoded_metar{$tmptr}{'intensity'} = 'unknown ($v2) CHECKME'; } } else { # no sign $decoded_metar{$tmptr}{'intensity'} = 'moderate (no sign)'; } $decoded_metar{$tmptr}{'decriptor'} = get_descriptor($v3) if ($v3 && length($v3)); $decoded_metar{$tmptr}{'precipitation'} = get_precipitation($v4) if ($v4 && length($v4)); $decoded_metar{$tmptr}{'obscuration'} = get_obscuration($v5) if ($v5 && length($v5)); $decoded_metar{$tmptr}{'other'} = get_other($v6) if ($v6 && length($v6)); $had_dc = 1; # ================================================================================ } elsif (($part eq 'SKC') || ($part eq 'CLR') || ($part eq 'NSC')) { $msg = "$part - Cloud-group."; #$decoded_metar{'clouds'}{'condition'} = $part; $decoded_metar{'conditions'} = $part.' (Clear)'; $had_dc = 1; ###} elsif ($part =~ /^(VV|FEW|SCT|BKN|OVC)([0-9]{3}|\/\/\/)(CB|TCU)?$/ ) { } elsif ($part =~ /^(VV|FEW|SCT|BKN|OVC)([0-9]{2,3}|\/\/\/)(CB|TCU)?$/ ) { $msg = "$part - We have found (another) a cloud-layer-group."; $v1 = $1; $v2 = $2; $v3 = $3; $tr = 'clouds'; $tmptr = $tr; $tmpn = 0; while (defined $decoded_metar{$tmptr}) { $tmpn++; $tmptr = $tr.$tmpn; } if ($v2 eq '000') { # if ($regs[2] == '000') # '000' is a special height. $decoded_metar{$tmptr}{'ft'} = 100; # $tr = 'clouds'.[nn] $decoded_metar{$tmptr}{'meter'} = 30; $decoded_metar{$tmptr}{'prefix'} = -1; #/* Less than */ } elsif ($v2 eq '///') { # '///' means height nil $decoded_metar{$tmptr}{'ft'} = 'nil'; $decoded_metar{$tmptr}{'meter'} = 'nil'; } else { $decoded_metar{$tmptr}{'ft'} = $v2 * 100; $decoded_metar{$tmptr}{'meter'} = int($v2 * 30.48); } $decoded_metar{$tmptr}{'cond'} = $v3 if ($v3 && length($v3)); $had_dc = 1; ################################################################ } elsif ($part =~ /^(M?[0-9]{2})\/(M?[0-9]{2}|\/\/)?$/) { $msg = "$part - Temperature/Dew Point Group."; # eg 12/08-Temperature and Dewpoint # 12 represents the temperature in Celcius # 08 represents the dewpoint in Celcius # If the temperature or dewpoint falls below 0 # there will be an "M" before it (i.e. 03/M02). "M" means minus. $v1 = $1; $v2 = $2; $v3 = ''; if ($v1 && length($v1) && (substr($v1,0,1) eq 'M')) { $v3 = '-'; } $decoded_metar{'temperature'}{'temp_c'} = $v3.int($v1); $decoded_metar{'temperature'}{'temp_f'} = $v3.int( ($v1 * (9/5)) + 32 ); # The dewpoint could be missing, this is indicated by the # second group being empty at most places, but in the UK they # use '//' instead of the missing temperature... */ $v3 = ''; if ($v2 && length($v2) && (substr($v2,0,1) eq 'M')) { $v3 = '-'; } if (length($v2) && ($v2 ne '//')) { $decoded_metar{'temperature'}{'dew_c'} = $v3.int($v2); $decoded_metar{'temperature'}{'dew_f'} = $v3.int(($v2 * (9/5)) + 32).'M-'; } $had_dc = 1; } elsif ($part =~ /A([0-9]{4})/) { $msg = "$part - Altimeter."; # The pressure measured in inHg. $v1 = $1; $tr = 'altimeter'; $tmptr = $tr; $tmpn = 0; while (defined $decoded_metar{$tmptr}) { $tmpn++; $tmptr = $tr.$tmpn; } $decoded_metar{$tmptr}{'inhg'} = number_format($v1/100, 2); # $tmptr = 'altimeter'.[nn] # The pressure measured in mmHg, hPa and atm */ $decoded_metar{$tmptr}{'mmhg'} = number_format($v1 * 0.254, 1); $decoded_metar{$tmptr}{'hpa'} = int($v1 * 0.33864); $decoded_metar{$tmptr}{'atm'} = number_format(($v1 * 3.3421e-4), 3); $msg .= " ($tmptr)"; $had_dc = 1; } elsif ( $part =~ /^Q([0-9]{4})/ ) { $msg = "$part - Q Altimeter."; $v1 = $1; $tr = 'altimeter'; $tmptr = $tr; $tmpn = 0; while (defined $decoded_metar{$tmptr}) { $tmpn++; $tmptr = $tr.$tmpn; } # The specification doesn't say anything about # the Qxxxx-form, but it's in the METARs. # /* The pressure measured in hPa */ $decoded_metar{$tmptr}{'hpa'} = int($v1); # $tmptr = 'altimeter'.[nn] # /* The pressure measured in mmHg, inHg and atm */ $decoded_metar{$tmptr}{'mmhg'} = number_format($v1 * 0.75006, 1); $decoded_metar{$tmptr}{'inhg'} = number_format($v1 * 0.02953, 2); $decoded_metar{$tmptr}{'atm'} = number_format($v1 * 9.8692e-4, 3); $msg .= " ($tmptr)"; $had_dc = 1; } elsif ( $part =~ /^QNH([0-9]{4})INS/ ) { $msg = "$part - QNH Altimeter."; $v1 = $1; $tr = 'altimeter'; $tmptr = $tr; $tmpn = 0; while (defined $decoded_metar{$tmptr}) { $tmpn++; $tmptr = $tr.$tmpn; } $decoded_metar{$tmptr}{'inhg'} = number_format($v1 / 100, 2); # $tmptr = 'altimeter'.[nn] $decoded_metar{$tmptr}{'mmhg'} = number_format($v1 * 0.254, 2); # 100 inch to mm $decoded_metar{$tmptr}{'hpa'} = number_format($v1 * 0.338639, 2); $decoded_metar{$tmptr}{'atm'} = number_format(($v1 * 3.3421e-4), 3); $msg .= " ($tmptr)"; $had_dc = 1; } elsif ($part =~ /^T([0-9]{4})([0-9]{4})/ ) { prtw("WARNING:1: [$part] NOT YET HANDLED!\n", $tt ); # * Temperature/Dew Point Group, coded to tenth of degree Celsius. # $this->store_temp($regs[1] / 10, # $decoded_metar['temperature']['temp_c'], # $decoded_metar['temperature']['temp_f']); # $this->store_temp($regs[2] / 10, # $decoded_metar['temperature']['dew_c'], # $decoded_metar['temperature']['dew_f']); } elsif ($part =~ /^T([0-9]{4}$)/) { prtw("WARNING:2: [$part] NOT YET HANDLED!\n", $tt ); # $this->store_temp($regs[1], # $decoded_metar['temperature']['temp_c'], # $decoded_metar['temperature']['temp_f']); } elsif ($part =~ /^1([0-9]{4}$)/) { prtw("WARNING:3: [$part] NOT YET HANDLED!\n", $tt ); # * 6 hour maximum temperature Celsius, coded to tenth of degree # $this->store_temp($regs[1] / 10, # $decoded_metar['temp_min_max']['max6h_c'], # $decoded_metar['temp_min_max']['max6h_f']); } elsif ($part =~ /^2([0-9]{4}$)/) { prtw("WARNING:4: [$part] NOT YET HANDLED!\n", $tt ); # * 6 hour minimum temperature Celsius, coded to tenth of degree # $this->store_temp($regs[1] / 10, # $decoded_metar['temp_min_max']['min6h_c'], # $decoded_metar['temp_min_max']['min6h_f']); } elsif ($part =~ /^4([0-9]{4})([0-9]{4})$/) { prtw("WARNING:5: [$part] NOT YET HANDLED!\n", $tt ); # * 24 hour maximum and minimum temperature Celsius, coded to # * tenth of degree # $this->store_temp($regs[1] / 10, # $decoded_metar['temp_min_max']['max24h_c'], # $decoded_metar['temp_min_max']['max24h_f']); # $this->store_temp($regs[2] / 10, # $decoded_metar['temp_min_max']['min24h_c'], # $decoded_metar['temp_min_max']['min24h_f']); } elsif ($part =~ /^P([0-9]{4})/) { prtw("WARNING:6: [$part] NOT YET HANDLED!\n", $tt ); # * Precipitation during last hour in hundredths of an inch # if ($regs[1] == '0000') { # $decoded_metar['precipitation']['in'] = -1; # $decoded_metar['precipitation']['mm'] = -1; # } else { # $decoded_metar['precipitation']['in'] = # number_format($regs[1]/100, 2); # $decoded_metar['precipitation']['mm'] = # number_format($regs[1]*0.254, 2); # } } elsif ($part =~ /^6([0-9]{4})/) { $msg = "$part - Precipitation during last 3 or 6 hours in hundredths of an inch."; $v1 = $1; $tr = 'precititation'; $tmptr = $tr; $tmpn = 0; while (defined $decoded_metar{$tmptr}) { $tmpn++; $tmptr = $tr.$tmpn; } if ($v1 eq '0000') { $decoded_metar{$tmptr}{'in_6h'} = -1; $decoded_metar{$tmptr}{'mm_6h'} = -1; } else { $decoded_metar{$tmptr}{'in_6h'} = number_format($v1/100, 2); $decoded_metar{$tmptr}{'mm_6h'} = number_format($v1*0.254, 2); } $msg .= " ($tmptr)"; $had_dc = 1; } elsif ($part =~ /^7([0-9]{4})/ ) { prtw("WARNING:8: [$part] NOT YET HANDLED!\n", $tt ); # * Precipitation during last 24 hours in hundredths of an inch. # if ($regs[1] == '0000') { # $decoded_metar['precipitation']['in_24h'] = -1; # $decoded_metar['precipitation']['mm_24h'] = -1; # } else { # $decoded_metar['precipitation']['in_24h'] = # number_format($regs[1]/100, 2, '.', ''); # $decoded_metar['precipitation']['mm_24h'] = # number_format($regs[1]*0.254, 2, '.', ''); # } } elsif ($part =~ /^4\/([0-9]{3})/) { prtw("WARNING:9: [$part] NOT YET HANDLED!\n", $tt ); # * Snow depth in inches # if ($regs[1] == '0000') { # $decoded_metar['precipitation']['snow_in'] = -1; # $decoded_metar['precipitation']['snow_mm'] = -1; # } else { # $decoded_metar['precipitation']['snow_in'] = $regs[1] * 1; # $decoded_metar['precipitation']['snow_mm'] = round($regs[1] * 25.4); # } } elsif ($part =~ /^PROB([0-9]{1,2})/) { $msg = "$part - Probability."; # PROB40 2022 Probability. The probability of a weather event occurring is given in percent # along with the 2-digit Zulu hour start and end of the event. $v1 = $1; $decoded_metar{'probability'}{'percent'} = $v1; if (($i + 1) < $num_parts) { $part = $parts[$i+1]; if ($part =~ /^([0-9]{2})([0-9]{2})$/) { $v1 = $1; $v2 = $2; $decoded_metar{'probability'}{'start'} = $v1; $decoded_metar{'probability'}{'end'} = $v2; $msg .= " (Bgn=$v1, End=$v2)"; $i++; } } $had_dc = 1; } elsif ($part =~ /^M?(([0-9]?)[ ]?([0-9])(\/?)([0-9]*))SM$/ ) { # Examples: # 1/2SM - Visibility one-half statute mile # 2 1/4SM - Visibility two and one-quarter statute miles # 5SM - Visibility five statute miles # P6SM - Visibility more than six statute miles $v1 = $1; $v2 = $2; $v3 = $3; $v4 = $4; prtw("WARNING:10: [$part] NOT YET HANDLED! v1=[$v1] v2=[$v2] v3=[$v3] v4=[$v4] \n", $tt ); } elsif ($part =~ /([0-9]{2})([0-9]{2})([0-9]{2})/) { $v1 = $1; $v2 = $2; $v3 = $3; $tr = 'time-range'; $tmptr = $tr; $tmpn = 0; while (defined $decoded_metar{$tmptr}) { $tmpn++; $tmptr = $tr.$tmpn; } $decoded_metar{$tmptr}{'day'} = $v1; $decoded_metar{$tmptr}{'begin-hour'} = $v2; $decoded_metar{$tmptr}{'end-hour'} = $v3; } elsif ($part =~ /^FM([0-9]{2})([0-9]{2})/) { # eg FM1930 = FroM and 2-digit hour and 2-digit minute # beginning time: indicates significant change. # Each FM starts on a new line, indented 5 spaces. $v1 = $1; $v2 = $2; $tr = 'time-range'; $tmptr = $tr; $tmpn = 0; while (defined $decoded_metar{$tmptr}) { $tmpn++; $tmptr = $tr.$tmpn; } $decoded_metar{$tmptr}{'begin-hour'} = $v1; $decoded_metar{$tmptr}{'begin-mins'} = $v2; } elsif ($part =~ /^FM([0-9]{2})$/) { # eg FM19 = FroM and 2-digit hour assume 00 minute # beginning time: indicates significant change. # Each FM starts on a new line, indented 5 spaces. $v1 = $1; $v2 = '00'; $tr = 'time-range'; $tmptr = $tr; $tmpn = 0; while (defined $decoded_metar{$tmptr}) { $tmpn++; $tmptr = $tr.$tmpn; } $decoded_metar{$tmptr}{'begin-hour'} = $v1; $decoded_metar{$tmptr}{'begin-mins'} = $v2; } else { # } else { # * If we couldn't match the group, we assume that it was a remark. # $decoded_metar['remarks'] .= ' ' . $part; # } # } prtw("WARNING:ELSE: [$part] NO CASE FOR THIS!\n", $tt ); if (defined $decoded_metar{'UNDECODED'}) { $decoded_metar{'UNDECODED'} .= ' '.$part; } else { $decoded_metar{'UNDECODED'} = $part; } } } return %decoded_metar; } # function decode_metar($index=false) { # /* initialization */ # $temp_visibility_miles = ''; # $decoded_metar['remarks'] = ''; # $decoded_metar['location'] = $this->get_location(); # # /* Make sure we got the metar */ # $tmp_metar = $this->get_metar(); # # /* Setup other variables */ # if ($index===false) { /* We are getting the current METAR */ # $decoded_metar['metar'] = $tmp_metar; # $decoded_metar['time'] = $this->metar_time; # } # else { # if ($this->metar_arch===false) { /* error */ # return false; # } # $tmp_metar = $this->metar_arch[$index]['metar']; # $decoded_metar['metar'] = $tmp_metar; # $decoded_metar['time'] = $this->metar_arch[$index]['time']; # } # # /* We parse the METAR */ # $parts = explode(' ', $tmp_metar); # $num_parts = count($parts); # # for ($i = 0; $i < $num_parts; $i++) { # $part = $parts[$i]; # # if (ereg('RMK|AFT|TEMPO|BECMG|INTER', $part)) { # /* The rest of the METAR is either a remark or temporary # * information. We keep the remark. # */ # for($j=$i;$j<$num_parts; $j++) # $decoded_metar['remarks'] .= ' ' . $parts[$j]; # $decoded_metar['remarks'] = trim($decoded_metar['remarks']); # break; # } elseif ($part == 'METAR') { # /* # * Type of Report: METAR # */ # $decoded_metar['type'] = 'METAR'; # } elseif ($part == 'SPECI') { # /* # * Type of Report: SPECI # */ # $decoded_metar['type'] = 'SPECI'; # } elseif (ereg('^[A-Z]{4}$', $part) && # empty($decoded_metar['icao'])) { # /* # * Station Identifier # */ # $decoded_metar['icao'] = $part; #// } elseif (ereg('([0-9]{2})([0-9]{2})([0-9]{2})Z', $part, $regs)) { #// /* #// * Date and Time of Report. #// * #// * We return a standard Unix UTC/GMT timestamp suitable for #// * gmdate(). #// * #// * If you experience incorrect timestamps but cannot set the #// * clock, then you can set $this->properties['offset'] to be #// * the offset in hours to add. For example, if your times #// * generated are 1 hour too early (so METARs appear an hour #// * older than they are), set $this->properties['offset'] to be #// * +1 in your defaults.php file. #// */ # #// if ($regs[1] > gmdate('j')) { #// /* The day is greather that the current day of month => the #// * report is from last month. #// */ #// $month = gmdate('n') - 1; #// } else { #// $month = gmdate('n'); #// } # #// $decoded_metar['time'] = #// gmmktime($regs[2] + $this->properties['offset'], #// $regs[3], 0, $month, $regs[1], gmdate('Y')); # # # } elseif (ereg('(AUTO|COR|RTD|CC[A-Z]|RR[A-Z])', $part, $regs)) { # /* # * Report Modifier: AUTO, COR, CCx or RRx # */ # $decoded_metar['report_mod'] = $regs[1]; # } elseif (ereg('([0-9]{3}|VRB)([0-9]{2,3})G?([0-9]{2,3})?(KT|MPS|KMH)', $part, $regs)) { # # /* Wind Group */ # # $decoded_metar['wind']['deg'] = $regs[1]; # # $this->store_speed($regs[2], # $regs[4], # $decoded_metar['wind']['knots'], # $decoded_metar['wind']['meters_per_second'], # $decoded_metar['wind']['miles_per_hour']); # # if (!empty($regs[3])) { # # /* We have a report with information about the gust. # * First we have the gust measured in knots. # */ # $this->store_speed($regs[3], # $regs[4], # $decoded_metar['wind']['gust_knots'], # $decoded_metar['wind']['gust_meters_per_second'], # $decoded_metar['wind']['gust_miles_per_hour']); # } # } elseif (ereg('^([0-9]{3})V([0-9]{3})$', $part, $regs) && # !empty($decoded_metar['wind'])) { # # /* # * Variable wind-direction # */ # $decoded_metar['wind']['var_beg'] = $regs[1]; # $decoded_metar['wind']['var_end'] = $regs[2]; # } elseif (ereg('^([0-9]{4})([NS]?[EW]?)$', $part, $regs)) { # /* # * Visibility in meters (4 digits only) # */ # unset($group); # # if ($regs[1] == '0000') { # /* Special low value */ # # $group['prefix'] = -1; /* Less than */ # $group['meter'] = 50; # $group['km'] = 0.05; # $group['ft'] = 164; # $group['miles'] = 0.031; # } elseif ($regs[1] == '9999') { # /* Special high value */ # $group['prefix'] = 1; # $group['meter'] = 10000; # $group['km'] = 10; # $group['ft'] = 32800; # $group['miles'] = 6.2; # } else { # /* Normal visibility, returned in both small and large units. */ # $group['prefix'] = 0; # $group['km'] = number_format($regs[1]/1000, 1); # $group['miles'] = number_format($regs[1]/1609.344, 1); # $group['meter'] = $regs[1] * 1; # $group['ft'] = round($regs[1] * 3.28084); # } # if (!empty($regs[2])) { # $group['deg'] = $regs[2]; # } # $decoded_metar['visibility'][] = $group; # # } elseif (ereg('^[0-9]$', $part)) { # /* # * Temp Visibility Group, single digit followed by space. # */ # $temp_visibility_miles = $part; # } elseif (ereg('^M?(([0-9]?)[ ]?([0-9])(/?)([0-9]*))SM$', # $temp_visibility_miles . ' ' . $part, $regs)) { # /* # * Visibility Group # */ # unset($group); # # if ($regs[4] == '/') { # $vis_miles = $regs[2] + $regs[3]/$regs[5]; # } else { # $vis_miles = $regs[1]; # } # if ($regs[0][0] == 'M') { # /* Prefix - less than */ # $group['prefix'] = -1; # } else { # $group['prefix'] = 0; # } # # /* The visibility measured in miles */ # $group['miles'] = number_format($vis_miles, 1); # # /* The visibility measured in feet */ # $group['ft'] = round($vis_miles * 5280, 1); # # /* The visibility measured in kilometers */ # $group['km'] = number_format($vis_miles * 1.6093, 1); # # /* The visibility measured in meters */ # $group['meter'] = round($vis_miles * 1609.3); # # $decoded_metar['visibility'][] = $group; # } elseif ($part == 'CAVOK') { # /* CAVOK is used when the visibility is greater than 10 # * kilometers, the lowest cloud-base is at 5000 feet or more # * and there is no significant weather. # */ # unset($group); # $group['prefix'] = 1; # $group['km'] = 10; # $group['meter'] = 10000; # $group['miles'] = 6.2; # $group['ft'] = 32800; # $decoded_metar['visibility'][] = $group; # $decoded_metar['clouds'][]['condition'] = 'CAVOK'; # # } elseif (ereg('^R([0-9]{2})([RLC]?)/([MP]?)([0-9]{4})' . # '([DNU]?)V?(P?)([0-9]{4})?([DNU]?)$', $part, $regs)) { # /* Runway-group */ # unset($group); # $group['nr'] = $regs[1]; # if (!empty($regs[2])) { # $group['approach'] = $regs[2]; # } # # if (!empty($regs[7])) { # /* We have both min and max visibility since $regs[7] holds # * the max visibility. # */ # if (!empty($regs[5])) { # /* $regs[5] is tendency for min visibility. */ # $group['min_tendency'] = $regs[5]; # } # # if (!empty($regs[8])) { # /* $regs[8] is tendency for max visibility. */ # $group['max_tendency'] = $regs[8]; # } # # if ($regs[3] == 'M') { # /* Less than. */ # $group['min_prefix'] = -1; # } # $group['min_meter'] = $regs[4] * 1; # $group['min_ft'] = round($regs[4] * 3.2808); # # if ($regs[6] == 'P') { # /* Greater than. */ # $group['max_prefix'] = 1; # } # $group['max_meter'] = $regs[7] * 1; # $group['max_ft'] = round($regs[7] * 3.2808); # # } else { # /* We only have a single visibility. */ # # if (!empty($regs[5])) { # /* $regs[5] holds the tendency for visibility. */ # $group['tendency'] = $regs[5]; # } # # if ($regs[3] == 'M') { # /* Less than. */ # $group['prefix'] = -1; # } elseif ($regs[3] == 'P') { # /* Greater than. */ # $group['prefix'] = 1; # } # $group['meter'] = $regs[4] * 1; # $group['ft'] = round($regs[4] * 3.2808); # } # $decoded_metar['runway'][] = $group; # # } elseif (ereg('^(VC)?' . /* Proximity */ # '(-|\+)?' . /* Intensity */ # '(MI|PR|BC|DR|BL|SH|TS|FZ)?' . /* Descriptor */ # '((DZ|RA|SN|SG|IC|PL|GR|GS|UP)+)?' . /* Precipitation */ # '(BR|FG|FU|VA|DU|SA|HZ|PY)?' . /* Obscuration */ # '(PO|SQ|FC|SS)?$', /* Other */ # $part, $regs)) { # /* # * Current weather-group. # */ # $decoded_metar['weather'][] = # array('proximity' => $regs[1], # 'intensity' => $regs[2], # 'descriptor' => $regs[3], # 'precipitation' => $regs[4], # 'obscuration' => $regs[6], # 'other' => $regs[7]); # # } elseif ($part == 'SKC' || $part == 'CLR') { # /* Cloud-group */ # $decoded_metar['clouds'][]['condition'] = $part; # # } elseif (ereg('^(VV|FEW|SCT|BKN|OVC)([0-9]{3}|///)' . # '(CB|TCU)?$', $part, $regs)) { # /* We have found (another) a cloud-layer-group. */ # unset($group); # # $group['condition'] = $regs[1]; # if (!empty($regs[3])) { # $group['cumulus'] = $regs[3]; # } # if ($regs[2] == '000') { # /* '000' is a special height. */ # $group['ft'] = 100; # $group['meter'] = 30; # $group['prefix'] = -1; /* Less than */ # } elseif ($regs[2] == '///') { # /* '///' means height nil */ # $group['ft'] = 'nil'; # $group['meter'] = 'nil'; # } else { # $group['ft'] = $regs[2] *100; # $group['meter'] = round($regs[2] * 30.48); # } # $decoded_metar['clouds'][] = $group; # # } elseif (ereg('^(M?[0-9]{2})/(M?[0-9]{2}|//)?$', $part, $regs)) { # /* # * Temperature/Dew Point Group. # */ # $decoded_metar['temperature']['temp_c'] = # round(strtr($regs[1], 'M', '-')); # $decoded_metar['temperature']['temp_f'] = # round(strtr($regs[1], 'M', '-') * (9/5) + 32); # # /* The dewpoint could be missing, this is indicated by the # * second group being empty at most places, but in the UK they # * use '//' instead of the missing temperature... */ # if (!empty($regs[2]) && $regs[2] != '//') { # $decoded_metar['temperature']['dew_c'] = # round(strtr($regs[2], 'M', '-')); # $decoded_metar['temperature']['dew_f'] = # round(strtr($regs[2], 'M', '-') * (9/5) + 32); # } # } elseif (ereg('A([0-9]{4})', $part, $regs)) { # /* # * Altimeter. # * The pressure measured in inHg. # */ # $decoded_metar['altimeter']['inhg'] = # number_format($regs[1]/100, 2); # # /* The pressure measured in mmHg, hPa and atm */ # $decoded_metar['altimeter']['mmhg'] = # number_format($regs[1] * 0.254, 1, '.', ''); # $decoded_metar['altimeter']['hpa'] = # round($regs[1] * 0.33864); # $decoded_metar['altimeter']['atm'] = # number_format($regs[1] * 3.3421e-4, 3, '.', ''); # } elseif (ereg('Q([0-9]{4})', $part, $regs)) { # /* # * Altimeter. # * The specification doesn't say anything about # * the Qxxxx-form, but it's in the METARs. # */ # # /* The pressure measured in hPa */ # $decoded_metar['altimeter']['hpa'] = round($regs[1]); # # /* The pressure measured in mmHg, inHg and atm */ # $decoded_metar['altimeter']['mmhg'] = # number_format($regs[1] * 0.75006, 1, '.', ''); # $decoded_metar['altimeter']['inhg'] = # number_format($regs[1] * 0.02953, 2); # $decoded_metar['altimeter']['atm'] = # number_format($regs[1] * 9.8692e-4, 3, '.', ''); # } elseif (ereg('^T([0-9]{4})([0-9]{4})', $part, $regs)) { # # /* # * Temperature/Dew Point Group, coded to tenth of degree Celsius. # */ # $this->store_temp($regs[1] / 10, # $decoded_metar['temperature']['temp_c'], # $decoded_metar['temperature']['temp_f']); # $this->store_temp($regs[2] / 10, # $decoded_metar['temperature']['dew_c'], # $decoded_metar['temperature']['dew_f']); # } elseif (ereg('^T([0-9]{4}$)', $part, $regs)) { # $this->store_temp($regs[1], # $decoded_metar['temperature']['temp_c'], # $decoded_metar['temperature']['temp_f']); # } elseif (ereg('^1([0-9]{4}$)', $part, $regs)) { # # /* # * 6 hour maximum temperature Celsius, coded to tenth of degree # */ # $this->store_temp($regs[1] / 10, # $decoded_metar['temp_min_max']['max6h_c'], # $decoded_metar['temp_min_max']['max6h_f']); # } elseif (ereg('^2([0-9]{4}$)', $part, $regs)) { # # /* # * 6 hour minimum temperature Celsius, coded to tenth of degree # */ # $this->store_temp($regs[1] / 10, # $decoded_metar['temp_min_max']['min6h_c'], # $decoded_metar['temp_min_max']['min6h_f']); # } elseif (ereg('^4([0-9]{4})([0-9]{4})$', $part, $regs)) { # # /* # * 24 hour maximum and minimum temperature Celsius, coded to # * tenth of degree # */ # $this->store_temp($regs[1] / 10, # $decoded_metar['temp_min_max']['max24h_c'], # $decoded_metar['temp_min_max']['max24h_f']); # $this->store_temp($regs[2] / 10, # $decoded_metar['temp_min_max']['min24h_c'], # $decoded_metar['temp_min_max']['min24h_f']); # } elseif (ereg('^P([0-9]{4})', $part, $regs)) { # # /* # * Precipitation during last hour in hundredths of an inch # */ # if ($regs[1] == '0000') { # $decoded_metar['precipitation']['in'] = -1; # $decoded_metar['precipitation']['mm'] = -1; # } else { # $decoded_metar['precipitation']['in'] = # number_format($regs[1]/100, 2); # $decoded_metar['precipitation']['mm'] = # number_format($regs[1]*0.254, 2); # } # } elseif (ereg('^6([0-9]{4})', $part, $regs)) { # # /* # * Precipitation during last 3 or 6 hours in hundredths of an # * inch. # */ # if ($regs[1] == '0000') { # $decoded_metar['precipitation']['in_6h'] = -1; # $decoded_metar['precipitation']['mm_6h'] = -1; # } else { # $decoded_metar['precipitation']['in_6h'] = # number_format($regs[1]/100, 2); # $decoded_metar['precipitation']['mm_6h'] = # number_format($regs[1]*0.254, 2); # } # } elseif (ereg('^7([0-9]{4})', $part, $regs)) { # # /* # * Precipitation during last 24 hours in hundredths of an inch. # */ # if ($regs[1] == '0000') { # $decoded_metar['precipitation']['in_24h'] = -1; # $decoded_metar['precipitation']['mm_24h'] = -1; # } else { # $decoded_metar['precipitation']['in_24h'] = # number_format($regs[1]/100, 2, '.', ''); # $decoded_metar['precipitation']['mm_24h'] = # number_format($regs[1]*0.254, 2, '.', ''); # } # } elseif (ereg('^4/([0-9]{3})', $part, $regs)) { # # /* # * Snow depth in inches # */ # if ($regs[1] == '0000') { # $decoded_metar['precipitation']['snow_in'] = -1; # $decoded_metar['precipitation']['snow_mm'] = -1; # } else { # $decoded_metar['precipitation']['snow_in'] = $regs[1] * 1; # $decoded_metar['precipitation']['snow_mm'] = round($regs[1] * 25.4); # } # } else { # # /* # * If we couldn't match the group, we assume that it was a # * remark. # */ # $decoded_metar['remarks'] .= ' ' . $part; # } # } # # /* # * Relative humidity # */ # if (!empty($decoded_metar['temperature']['temp_c']) && # !empty($decoded_metar['temperature']['dew_c'])) { # # $decoded_metar['rel_humidity'] = # number_format(pow(10, (1779.75 * ($decoded_metar['temperature']['dew_c'] - # $decoded_metar['temperature']['temp_c']) # / ((237.3 + $decoded_metar['temperature']['dew_c']) * # (237.3 + $decoded_metar['temperature']['temp_c'])) # + 2)), 1); # } # # # /* # * Compute windchill if temp < 40f and windspeed > 3 mph # */ # if (!empty($decoded_metar['temperature']['temp_f']) && # $decoded_metar['temperature']['temp_f'] <= 40 && # !empty($decoded_metar['wind']['miles_per_hour']) && # $decoded_metar['wind']['miles_per_hour'] > 3) { # $decoded_metar['windchill']['windchill_f'] = # number_format(35.74 + 0.6215*$decoded_metar['temperature']['temp_f'] # - 35.75*pow((float)$decoded_metar['wind']['miles_per_hour'], 0.16) # + 0.4275*$decoded_metar['temperature']['temp_f'] * # pow((float)$decoded_metar['wind']['miles_per_hour'], 0.16)); # $decoded_metar['windchill']['windchill_c'] = # number_format(13.112 + 0.6215*$decoded_metar['temperature']['temp_c'] # - 13.37*pow(($decoded_metar['wind']['miles_per_hour']/1.609), 0.16) # + 0.3965*$decoded_metar['temperature']['temp_c'] * # pow(($decoded_metar['wind']['miles_per_hour']/1.609), 0.16)); # } # # /* # * Compute heat index if temp > 70F # */ # if (!empty($decoded_metar['temperature']['temp_f']) && # $decoded_metar['temperature']['temp_f'] > 70 && # !empty($decoded_metar['rel_humidity'])) { # $decoded_metar['heatindex']['heatindex_f'] = # number_format(-42.379 # + 2.04901523 * $decoded_metar['temperature']['temp_f'] # + 10.1433312 * $decoded_metar['rel_humidity'] # - 0.22475541 * $decoded_metar['temperature']['temp_f'] # * $decoded_metar['rel_humidity'] # - 0.00683783 * $decoded_metar['temperature']['temp_f'] # * $decoded_metar['temperature']['temp_f'] # - 0.05481717 * $decoded_metar['rel_humidity'] # * $decoded_metar['rel_humidity'] # + 0.00122874 * $decoded_metar['temperature']['temp_f'] # * $decoded_metar['temperature']['temp_f'] # * $decoded_metar['rel_humidity'] # + 0.00085282 * $decoded_metar['temperature']['temp_f'] # * $decoded_metar['rel_humidity'] # * $decoded_metar['rel_humidity'] # - 0.00000199 * $decoded_metar['temperature']['temp_f'] # * $decoded_metar['temperature']['temp_f'] # * $decoded_metar['rel_humidity'] # * $decoded_metar['rel_humidity']); # $decoded_metar['heatindex']['heatindex_c'] = # number_format(($decoded_metar['heatindex']['heatindex_f'] - 32) / 1.8); # } # # /* # * Compute the humidity index # */ # if (!empty($decoded_metar['rel_humidity'])) { # $e = (6.112 * pow(10, 7.5 * $decoded_metar['temperature']['temp_c'] # / (237.7 + $decoded_metar['temperature']['temp_c'])) # * $decoded_metar['rel_humidity'] / 100) - 10; # $decoded_metar['humidex']['humidex_c'] = # number_format($decoded_metar['temperature']['temp_c'] + 5/9 * $e, 1); # $decoded_metar['humidex']['humidex_f'] = # number_format($decoded_metar['humidex']['humidex_c'] * 9/5 + 32, 1); # } # # # /* Finally we store our decoded METAR in $this->decoded_metar so # * that other methods can use it. # */ # if ($index===false) $this->decoded_metar = $decoded_metar; # else $this->decoded_metar_arch[$index] = $decoded_metar; # # return $decoded_metar; # } sub load_airport_file { my ($aptdat) = shift; # = $APTFILE; my ($line, $alat, $alon, $icao, $name, $rlat, $rlon); my (@arr, @arr2); prt("\nLoading $aptdat file ...\n"); mydie("ERROR: Can NOT locate $aptdat ...$!...\n") if ( !( -f $aptdat) ); ###open IF, "<$aptdat" or mydie("OOPS, failed to open [$aptdat] ... check name and location ...\n"); open IF, "gzip -d -c $aptdat|" or mydie( "ERROR: CAN NOT OPEN $aptdat...$!...\n" ); my @lines = <IF>; close IF; my $cnt = scalar @lines; prt( "Processing $cnt lines ...\n" ); my $apt = ''; my $rwycnt = 0; my $glat = 0; my $glon = 0; my $totaptcnt = 0; # count another AIRPORT foreach $line (@lines) { $line = trim_all($line); ###prt("$line\n"); @arr = split(/ /,$line); if ($line =~ /^$aln\s+/) { # start with '1' if (length($apt) && ($rwycnt > 0)) { $alat = $glat / $rwycnt; $alon = $glon / $rwycnt; @arr2 = split(/ /,$apt); $icao = $arr2[4]; $name = join(' ', splice(@arr2,5)); push(@aptlist, [$icao, $name, $alat, $alon]); } $apt = $line; $rwycnt = 0; $glat = 0; $glon = 0; $totaptcnt++; # count another AIRPORT } elsif ($line =~ /^$rln\s+/) { $rlat = $arr[1]; $rlon = $arr[2]; ###prt( "$line [$rlat, $rlon]\n" ); $glat += $rlat; $glon += $rlon; $rwycnt++; } elsif ($line =~ /^$lastln\s?/) { # 99, followed by space, count 0 or more ... prt( "Reached END OF FILE ... \n" ); last; } } if (length($apt) && ($rwycnt > 0)) { $alat = $glat / $rwycnt; $alon = $glon / $rwycnt; @arr2 = split(/ /,$apt); $icao = $arr2[4]; $name = join(' ', splice(@arr2,5)); push(@aptlist, [$icao, $name, $alat, $alon]); } } sub get_fix_len { my ($d) = shift; my $stg = sprintf("%03.7f", $d); my @arr = split(/\./,$stg); if (scalar @arr == 2) { $arr[0] = ' '.$arr[0] while ( length($arr[0]) < 4 ); $stg = $arr[0].'.'.$arr[1]; } return $stg; } sub show_airport { my ($off) = shift; # push(@aptlist, [$icao, $name, $alat, $alon]); my $cnt = scalar @aptlist; if (($off > 0) && ($off <= $cnt)) { $off--; # back up to logical my $icao = $aptlist[$off][0]; $icao .= ' ' while (length($icao) < 4); my $name = $aptlist[$off][1]; my $alat = $aptlist[$off][2]; my $alon = $aptlist[$off][3]; my $slat = get_fix_len($alat); my $slon = get_fix_len($alon); prt( "$icao $slat $slon $name\n" ); } } # eof