Location: PHPKode > scripts > geodistance > thinkphp-geodistance-a767b50/v2/vincenty.distance.xml
<?xml version="1.0" encoding="UTF-8"?>
<table xmlns="http://query.yahooapis.com/v1/schema/table.xsd">
  <meta>
    <sampleQuery>SELCT * from {table} WHERE place1="paris" and place2="london"</sampleQuery>
    <author>Adrian Statescu</author>
    <documentationURL>http://thinkphp.ro/apps/php-hacks/distance/</documentationURL>  
    <description>Gives you the distance of two places on earth in miles or kilometers.</description>
  </meta>
  <bindings>
    <select itemPath="" produces="XML">
      <inputs>
        <key id='place1' type='xs:string' paramType='variable' required="true" />
        <key id='place2' type='xs:string' paramType='variable' required="true" />
      </inputs>
      <execute><![CDATA[
         default xml namespace = "http://where.yahooapis.com/v1/schema.rng";
         var out = '';
         var res1 = y.query('select * from geo.places(1) where text="'+place1+'"').results;
         var res2 = y.query('select * from geo.places(1) where text="'+place2+'"').results;
         var lat1 = res1.place.centroid.latitude;
         var lon1 = res1.place.centroid.longitude;
         var lat2 = res2.place.centroid.latitude;
         var lon2 = res2.place.centroid.longitude;
         var d = distVincenty(lat1,lon1,lat2,lon2);

          /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
          /* Vincenty Inverse Solution of Geodesics on the Ellipsoid (c) Chris Veness 2002-2010             */
          /*                                                                                                */
          /* from: Vincenty inverse formula - T Vincenty, "Direct and Inverse Solutions of Geodesics on the */
          /*       Ellipsoid with application of nested equations", Survey Review, vol XXII no 176, 1975    */
          /*       http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf                                             */
          /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

          /**
           * Calculates geodetic distance between two points specified by latitude/longitude using 
           * Vincenty inverse formula for ellipsoids
           *
           * @param   {Number} lat1, lon1: first point in decimal degrees
           * @param   {Number} lat2, lon2: second point in decimal degrees
           * @returns (Number} distance in metres between points
           */
          function distVincenty(lat1, lon1, lat2, lon2) {
            var a = 6378137, b = 6356752.3142,  f = 1/298.257223563;  // WGS-84 ellipsoid params
            var L = (lon2-lon1) * Math.PI / 180;
            var U1 = Math.atan((1-f) * Math.tan(lat1 * Math.PI / 180));
            var U2 = Math.atan((1-f) * Math.tan(lat2 * Math.PI / 180));
            var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
            var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);

            var lambda = L, lambdaP, iterLimit = 100;
            do {
              var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda);
              var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) + 
                (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
              if (sinSigma==0) return 0;  // co-incident points
              var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
              var sigma = Math.atan2(sinSigma, cosSigma);
              var sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
              var cosSqAlpha = 1 - sinAlpha*sinAlpha;
              var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
              if (isNaN(cos2SigmaM)) cos2SigmaM = 0;  // equatorial line: cosSqAlpha=0 (6)
              var 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 (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0);

            if (iterLimit==0) return NaN  // formula failed to converge

            var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
            var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
            var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
            var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
              B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
            var s = b*A*(sigma-deltaSigma);

            s = s.toFixed(3); // round to 1mm precision
            return s;
          }

          /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */


             var d = d / 1000;
             var miles = Math.round(d/1.609344); 
             var kilometers = Math.round(d); 
             response.object = <distance>
             <miles>{miles}</miles> 
             <kilometers>{kilometers}</kilometers> 
             {res1.place}{res2.place}
             </distance>
      ]]></execute>
    </select>
  </bindings>
</table>
Return current item: geodistance