DJ Howarth
DJ Howarth

Reputation: 582

Javascript & Google Maps Circle

Currently the formula I am using is below, but it is less accurate as the Vincenty formula, which you can find on this link: http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html

My question is, can someone help simplify the javascript code so i can implement it in my formula? I am trying to learn javascript but it is a bit beyond my capabilities.

ex = lat2 ey = lon2

Im thinking the easiest way would be to run through the code and do an array of 360 degrees to calculate the ex/ey coordinates.

<script type="text/javascript"> 

function drawCircle(point, radius, dir, addtoBounds) { 
var d2r = Math.PI / 180;   // degrees to radians 
var r2d = 180 / Math.PI;   // radians to degrees 
var earthsradius = 6378137;

   var points = 360; 

   // find the radius in lat/lon 
   var rlat = (radius / earthsradius) * r2d; 
   var rlng = rlat / Math.cos(point.lat() * d2r); 


   var extp = new Array(); 
   if (dir==1)  {var start=0;var end=points+1} // one extra here makes sure we connect the
   else     {var start=points+1;var end=0}
   for (var i=start; (dir==1 ? i < end : i > end); i=i+dir)  
   { 
    var theta = Math.PI * (i / (points/2));//i is number of points + 1 
var lat1=point.lat()*d2r;
var lon1=point.lng()*d2r;
var d=radius;
var R=earthsradius;

var ex = Math.asin( Math.sin(lat1)*Math.cos(d/R) + 
                Math.cos(lat1)*Math.sin(d/R)*Math.cos(theta));
var ey = lon1 + Math.atan2(Math.sin(theta)*Math.sin(d/R)*Math.cos(lat1), 
                 Math.cos(d/R)-Math.sin(lat1)*Math.sin(ex));
  extp.push(new google.maps.LatLng(ex*r2d, ey*r2d)); 
  if (addtoBounds) bounds.extend(extp[extp.length-1]);



   } 
   // alert(extp.length);
   return extp;


   }

Here is the direct formula converted to php. I am trying to put this code into the google maps code. The movable type link actually has this code in javascript, but since I know php much better, I converted it over to test it out, this works perfectly.

<?php 
 $lat1 = 29.10860062;
 $lon1 = -95.46209717;
 $a = 6378137;
 $b = 6356752.314245;
 $f = 1/298.257223563;  // WGS-84 ellipsoid params
 $brng = 32.8;


 $s = 1796884.48;
 $alpha1 = deg2rad($brng);
 $sinAlpha1 = sin($alpha1);
 $cosAlpha1 = cos($alpha1);
 $tanU1 = (1-$f) * tan(deg2rad($lat1));
 $cosU1 = 1 / sqrt((1 + pow($tanU1,2)));
 $sinU1 = $tanU1*$cosU1;
 $sigma1 = atan2($tanU1, $cosAlpha1);
 $sinAlpha = $cosU1 * $sinAlpha1;
 $cosSqAlpha = 1 - pow($sinAlpha,2);
 $uSq = $cosSqAlpha * (pow($a,2) - pow($b,2)) / (pow($b,2));
 $A = 1 + $uSq/16384*(4096+$uSq*(-768+$uSq*(320-175*$uSq)));
 $B = $uSq/1024 * (256+$uSq*(-128+$uSq*(74-47*$uSq)));
 $sigma = $s / ($b*$A);
 $sigmaP = 2*pi;

 $limit = 100; 
 $counter = 1;

 while ( $counter <= $limit ) {
 $cos2SigmaM = cos(2*$sigma1 + $sigma);
 $sinSigma = sin($sigma);
 $cosSigma = cos($sigma);
 $deltaSigma = $B*$sinSigma*($cos2SigmaM+$B/4*($cosSigma*(-1+2*pow($cos2SigmaM,2))-$B/6*$cos2SigmaM*(-3+4*pow($sinSigma,2))*(-3+4*pow($cos2SigmaM,2))));
 $sigmaP = $sigma;
 $sigma = $s / ($b*$A) + $deltaSigma;
$counter = $counter+1;
};

 $tmp = $sinU1*$sinSigma - $cosU1*$cosSigma*$cosAlpha1;
 $lat2 = atan2($sinU1*$cosSigma + $cosU1*$sinSigma*$cosAlpha1,(1-$f)*sqrt(pow($sinAlpha,2)+ pow($tmp,2)));
 $lambda = atan2($sinSigma*$sinAlpha1, $cosU1*$cosSigma - $sinU1*$sinSigma*$cosAlpha1);
 $C = $f/16*$cosSqAlpha*(4+$f*(4-3*$cosSqAlpha));
 $L = $lambda - (1-$C) * $f * $sinAlpha *($sigma + $C*$sinSigma*($cos2SigmaM+$C*$cosSigma*(-1+2*pow($cos2SigmaM,2))));

 if (deg2rad($lon1)+$L+(3*pi)<(2*pi)) {
 (  $lon2 = (deg2rad($lon1)+$L+(3*pi))-pi);
 } else {
 (  $lon2 = ((deg2rad($lon1)+$L+3*pi))%(2*pi))-pi;}

 $revAz = atan2($sinAlpha, -$tmp);  // final bearing, if required

?>

Upvotes: 2

Views: 737

Answers (1)

Bryan Weaver
Bryan Weaver

Reputation: 4473

Since the link you provided already provides the formula in javascript the hard part is complete, you can just copy it and call it rather than rewriting it into your function. Just remember to attribute the source. I removed the variables that were not being used. Also, I just hard coded 361 into the formula since you were just assigning it to a points variable. You can change this back if you are going to be passing the number of degrees into the formula. I separated the for loops, to me this is more readable, and I dont think the way you had before was working like you intended it. When working with degrees and radians I always wrap these conversions into functions since it improves readability. To do this I hooked them up to the Number object in JavaScript using prototype as seen here:

Number.prototype.toRad = function() {
   //'this' is the current number the function is acting on.  
   //e.g. 360.toRad() == 2PI radians
  return this * Math.PI / 180;
}

Number.prototype.toDeg = function() {
  return this * 180 / Math.PI;
}

Not too tough to understand, prototype allows you to extend objects in JavaScript, similar to inheritance in class based languages. There are plenty of resources online that can help clarify.

Here is the reworked drawCircle function:

function drawCircle(point, radius, dir, addtoBounds) {
    //best practice is to use [] rather then new Array(), 
    //both do the same thing.   
    var extp = [];
    if (dir == 1) {
        for (var i = 0; i < 361; i++) {
            //destVincenty function returns a object with 
            //lat, lon, and final bearing.     
            var destPoint = destVincenty(point.lat(), point.lng(), i, radius);

            //add new point 
            extp.push(new google.maps.LatLng(destPoint.lat, destPoint.lon));
            if (addtoBounds) bounds.extend(extp[extp.length - 1]);
        }
    }
    else {
        for (var i = 361; i > 0; i--) {    
            var destPoint = destVincenty(point.lat(), point.lng(), i, radius);
            extp.push(new google.maps.LatLng(destPoint.lat, destPoint.lon));
            if (addtoBounds) bounds.extend(extp[extp.length - 1]);
        }
    }

    return extp;
}

here is a fiddle of it working.

Upvotes: 2

Related Questions