Distance between cities

First of all I need to cite my sources:

The goal of my project was to find out which cities are nearby (within a user specified distance).
Of course users don’t know their city coordinate, so you will have to find out by yourself. To do so, I used the JEDI trick (Geocoding Belgium Postal Codes) which is:

      Downloading the csv of cities and zip code (available on the national mail site for Belgium, I don’t know for other countries)
      Writing a small piece of code to parse the csv and retrieve the right latitude and longitude via google geo service

I could have downloaded the file from the JEDI site but I really needed to do it by myself.

So the next thing to do is: finding the cities within an arbitrary distance.

This was based on the documentation I found on the movable-type math site.

All I did is translating the Javascript function to PHP functions:

    private function sphericalDistance($lat1,$lon1,$lat2,$lon2){
        $R = 6371.0; // km
        $d = acos(
                sin(deg2rad($lat1))*sin(deg2rad($lat2))
                + cos(deg2rad($lat1))*cos(deg2rad($lat2))
                * cos(deg2rad($lon2-$lon1))
             )
             * $R;
        return $d;
    }

    private function haversineDistance($lat1,$lon1,$lat2,$lon2){
        $R = 6371.0; // km
        $dLat = deg2rad($lat2-$lat1);
        $dLon = deg2rad($lon2-$lon1);
        $a = sin($dLat/2) * sin($dLat/2)
            + cos(deg2rad($lat1)) * cos(deg2rad($lat2))
            * sin($dLon/2) * sin($dLon/2);
        $c = 2.0 * atan2(sqrt($a), sqrt(1-$a));
        $d = $R * $c;
        return $d;
    }

    private function vincentyDistance($lat1,$lon1,$lat2,$lon2){
        $a = 6378137.0; $b = 6356752.3142;  $f = 1/298.257223563;  // WGS-84 ellipsiod
        $L = deg2rad($lon2-$lon1);
        $U1 = atan((1-$f) * tan(deg2rad($lat1)));
        $U2 = atan((1-$f) * tan(deg2rad($lat2)));
        $sinU1 = sin($U1);
        $cosU1 = cos($U1);
        $sinU2 = sin($U2);
        $cosU2 = cos($U2);
        $lambda = $L;
        $lambdaP = $L;
        $iterLimit = 100;
        do{
            $sinLambda = sin($lambda);
            $cosLambda = cos($lambda);
            $sinSigma = sqrt(($cosU2*$sinLambda) * ($cosU2*$sinLambda) +
                        ($cosU1*$sinU2-$sinU1*$cosU2*$cosLambda) * ($cosU1*$sinU2-$sinU1*$cosU2*$cosLambda));
            if($sinSigma==0) return 0;
            $cosSigma = $sinU1 * $sinU2 + $cosU1*$cosU2*$cosLambda;
            $sigma = atan2($sinSigma, $cosSigma);
            $sinAlpha = $cosU1 * $cosU2 * $sinLambda / $sinSigma;
            $cosSqAlpha = 1 - $sinAlpha*$sinAlpha;
            if($cosSqAlpha!=0){
                $cos2SigmaM = $cosSigma - 2*$sinU1*$sinU2/$cosSqAlpha;
            }else{
                $cos2SigmaM =0;
            }
            $C = $f/16*$cosSqAlpha*(4+$f*(4-3*$cosSqAlpha));
            $lambdaP = $lambda;
            $lambda = $L + (1-$C) * $f * $sinAlpha *
                    ($sigma + $C*$sinSigma*($cos2SigmaM+$C*$cosSigma*(-1+2*$cos2SigmaM*$cos2SigmaM)));
        }while(abs($lambda-$lambdaP) > 1e-12 && --$iterLimit>0);
        if($iterLimit == 0) return false; // formula failed to converge
        $uSq = $cosSqAlpha * ($a*$a - $b*$b) / ($b*$b);
        $A = 1 + $uSq/16384.0*(4096+$uSq*(-768+$uSq*(320-175*$uSq)));
        $B = $uSq/1024.0 * (256+$uSq*(-128+$uSq*(74-47*$uSq)));
        $deltaSigma = $B*$sinSigma*($cos2SigmaM+$B/4*($cosSigma*(-1+2*$cos2SigmaM*$cos2SigmaM)
                    - $B/6*$cos2SigmaM*(-3+4*$sinSigma*$sinSigma)*(-3+4*$cos2SigmaM*$cos2SigmaM)));
        $s = $b*$A*($sigma-$deltaSigma);
        return $s/1000.0;
    }

And that’s it…

So if you want the php serialized cities of Belgium with Zip, cityname, uppercase cityname, longitude,latitude.

I didn’t do a lot at all, just put every source together.

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>