<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">###########################
#      Match::GNS.pm      #
#      Version 1.01       #
#    (c) Ed Egan 2009     # 
###########################

package GNS;
no warnings 'redefine';
@ISA= qw (Common);
use strict;
use warnings;

#use Math::Complex qw(asin);
use Math::Trig qw(deg2rad pi great_circle_distance asin acos);

sub new {
    my $class = shift;
    my $self = bless {}, $class;
    $self-&gt;{GLOBALS}-&gt;{ISO9660}=uc(shift);
    $self-&gt;{DIR}=shift;
    $self-&gt;{GLOBALS}-&gt;{SOURCEFILE}="GNS-".$self-&gt;{GLOBALS}-&gt;{ISO9660}.".txt"; #"GNS-GB.txt";
    $self-&gt;Load($self-&gt;{DIR});
    return $self;
}

sub Load {
    my $self=shift;
    my $Dir=shift;
    my $reffile=$self-&gt;{GLOBALS}-&gt;{SOURCEFILE};
    my $reffilewithpath;
    if ($Dir) {$reffilewithpath="$Dir/$reffile";}
    else {$reffilewithpath=$reffile;}
    open (SOURCE,"$reffilewithpath") || die "Can not find the source file - Is it the correct dir?".$!;
    #The Load is robust to changes into the order of the columns and inclusion of new columns, but not to renamings
    undef my @header;
    my $headercol={};
    while (&lt;SOURCE&gt;) {
        chomp $_;
        if (!@header) {
            @header=split("\t",$_);
            for (my $i=0;$i&lt;=$#header;$i++) {$headercol-&gt;{$header[$i]}=$i;}
            next;
        }
        my @temp=split("\t",$_);
        #Ignore anything but NT = A,P,L
        if (!($temp[$headercol-&gt;{FC}] eq "A" || $temp[$headercol-&gt;{FC}] eq "P")) {next;}  #|| $temp[$headercol-&gt;{FC}] eq "L" #L is dropped for now
        $self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{UNI}]}-&gt;{RAWDATA}=\@temp;
        $self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{UNI}]}-&gt;{LAT}=$temp[$headercol-&gt;{LAT}];
        $self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{UNI}]}-&gt;{LONG}=$temp[$headercol-&gt;{LONG}];
        $self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{UNI}]}-&gt;{FC}=$temp[$headercol-&gt;{FC}];
        $self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{UNI}]}-&gt;{NT}=$temp[$headercol-&gt;{NT}];
        $self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{UNI}]}-&gt;{DSG}=$temp[$headercol-&gt;{DSG}];
        $self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{UNI}]}-&gt;{SHORT_FORM}=$temp[$headercol-&gt;{SHORT_FORM}];
        $self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{UNI}]}-&gt;{FULL_NAME_RAW}=$temp[$headercol-&gt;{FULL_NAME}];
        $self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{UNI}]}-&gt;{FULL_NAME_ND_RAW}=$temp[$headercol-&gt;{FULL_NAME_ND}];
        $self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{UNI}]}-&gt;{FULL_NAME}=$self-&gt;CleanString($self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{UNI}]}-&gt;{FULL_NAME_RAW});
        $self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{UNI}]}-&gt;{FULL_NAME_ND}=$self-&gt;CleanString($self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{UNI}]}-&gt;{FULL_NAME_ND_RAW});
    }
    $self-&gt;{COUNT_DATA}=scalar(keys(%{$self-&gt;{DATA}}));
    close (SOURCE);
    return $self;
}

sub GetCount {
    my $self=shift;
    my $var=shift;
    $var="COUNT_".$var;
    if (defined($self-&gt;{$var})) {return $self-&gt;{$var};}
    else {return "ERROR";}
}

sub Index {
    my $self=shift;
    foreach my $UNI (keys (%{$self-&gt;{DATA}})) {
        my $data=$self-&gt;{DATA}-&gt;{$UNI};
        if (defined($data-&gt;{SHORT_FORM}) &amp;&amp; $data-&gt;{SHORT_FORM} ne "") {$self-&gt;{INDEX_ALL}-&gt;{$data-&gt;{SHORT_FORM}}-&gt;{$UNI}=$data;}
        $self-&gt;{INDEX_ALL}-&gt;{$data-&gt;{FULL_NAME}}-&gt;{$UNI}=$data;
        $self-&gt;{INDEX_ALL}-&gt;{$data-&gt;{FULL_NAME_ND}}-&gt;{$UNI}=$data;
        if ($data-&gt;{FC} eq "A") {
            if (defined($data-&gt;{SHORT_FORM}) &amp;&amp; $data-&gt;{SHORT_FORM} ne "") {$self-&gt;{INDEX_A}-&gt;{$data-&gt;{SHORT_FORM}}-&gt;{$UNI}=$data;}
            $self-&gt;{INDEX_A}-&gt;{$data-&gt;{FULL_NAME}}-&gt;{$UNI}=$data;
            $self-&gt;{INDEX_A}-&gt;{$data-&gt;{FULL_NAME_ND}}-&gt;{$UNI}=$data;
        }
        elsif ($data-&gt;{FC} eq "P") {
            if (defined($data-&gt;{SHORT_FORM}) &amp;&amp; $data-&gt;{SHORT_FORM} ne "") {$self-&gt;{INDEX_P}-&gt;{$data-&gt;{SHORT_FORM}}-&gt;{$UNI}=$data;}
            $self-&gt;{INDEX_P}-&gt;{$data-&gt;{FULL_NAME}}-&gt;{$UNI}=$data;
            $self-&gt;{INDEX_P}-&gt;{$data-&gt;{FULL_NAME_ND}}-&gt;{$UNI}=$data;
        }
        #elsif ($data-&gt;{FC} eq "L") {
        #    if (defined($data-&gt;{SHORT_FORM}) &amp;&amp; $data-&gt;{SHORT_FORM} ne "") {$self-&gt;{INDEX_L}-&gt;{$data-&gt;{SHORT_FORM}}-&gt;{$UNI}=$data;}
        #    $self-&gt;{INDEX_L}-&gt;{$data-&gt;{FULL_NAME}}-&gt;{$UNI}=$data;
        #    $self-&gt;{INDEX_L}-&gt;{$data-&gt;{FULL_NAME_ND}}-&gt;{$UNI}=$data;
        #}
    }
    my @temp=keys(%{$self-&gt;{INDEX_ALL}});
    foreach (@temp) {$self-&gt;{NAME}-&gt;{$_}=1;}
    return $self;
}

sub GetIndexKeys {
    my $self=shift;
    my $IndexType="INDEX_".shift;
    return (keys(%{$self-&gt;{$IndexType}}));
}

sub GetLong {
    my $self=shift;
    my $PlaceName=shift;
    my $Letter=shift;
    my $Long=undef;
    if (!defined($self-&gt;{"INDEX_".$Letter}-&gt;{$PlaceName})) {
        return undef;
    }    
    elsif (scalar(keys(%{$self-&gt;{"INDEX_".$Letter}-&gt;{$PlaceName}})) &gt;=1) {
        my $UNI=$self-&gt;GetUNI($PlaceName,$Letter);
        $Long=$self-&gt;{"INDEX_".$Letter}-&gt;{$PlaceName}-&gt;{$UNI}-&gt;{LONG};
        return $Long;
    }
    elsif (scalar(keys(%{$self-&gt;{"INDEX_".$Letter}-&gt;{$PlaceName}})) ==0) {
        return undef;
    }
}

sub GetLat {
    my $self=shift;
    my $PlaceName=shift;
    my $Letter=shift;
    my $Lat=undef;
    if (!defined($self-&gt;{"INDEX_".$Letter}-&gt;{$PlaceName})) {
        return undef;
    }    
    elsif (scalar(keys(%{$self-&gt;{"INDEX_".$Letter}-&gt;{$PlaceName}})) &gt;=1) {
        my $UNI=$self-&gt;GetUNI($PlaceName,$Letter);
        $Lat=$self-&gt;{"INDEX_".$Letter}-&gt;{$PlaceName}-&gt;{$UNI}-&gt;{LAT};
        return $Lat;
    }
    elsif (scalar(keys(%{$self-&gt;{"INDEX_".$Letter}-&gt;{$PlaceName}})) ==0) {
        return undef;
    }
}

sub GetUNI {
    my $self=shift;
    my $PlaceName=shift;
    my $Letter=shift;
    if (!defined($self-&gt;{"INDEX_".$Letter}-&gt;{$PlaceName})) {return undef;}    
    elsif (scalar(keys(%{$self-&gt;{"INDEX_".$Letter}-&gt;{$PlaceName}})) &gt;=1) {
        my @UNIs=keys(%{$self-&gt;{"INDEX_".$Letter}-&gt;{$PlaceName}});
        return $UNIs[0];
    }
    elsif (scalar(keys(%{$self-&gt;{"INDEX_".$Letter}-&gt;{$PlaceName}})) ==0) {return undef;}
}

sub GetDist {
    my $self=shift;
    my ($Lat1,$Long1,$Lat2,$Long2)=@_;
    if (!defined($Lat1) || !defined($Long1) || !defined($Lat2) || !defined($Long2)) {return 99999999;} #A very big number
    my $Dist=0; 
    my $EarthRadiusKm=6367.45; #Note: This is the Geometric mean of the radius - see http://en.wikipedia.org/wiki/Haversine_formula
    my $pi=3.1415926535897932384626433832795; #From http://en.wikipedia.org/wiki/Pi
    my $RadsInADegree=$pi/180;
    my $HalfDiffLong=(($Long1*$RadsInADegree)-($Long2*$RadsInADegree))/2;
    my $HalfDiffLat=(($Lat1*$RadsInADegree)-($Lat2*$RadsInADegree))/2;
    my $RadLat1=($Lat1*$RadsInADegree); my $RadLat2=($Lat2*$RadsInADegree);
    my $Part=sin($HalfDiffLat)**2 + cos($RadLat1)*cos($RadLat2)*sin($HalfDiffLong)**2;
    my $Haversine=2*asin(sqrt($Part));
    $Dist=$Haversine*$EarthRadiusKm;
    return $Dist; 
}


1;

</pre></body></html>