
function bdccGeo(lat,lon)
{var theta=(lon*Math.PI/180.0);var rlat=bdccGeoGeocentricLatitude(lat*Math.PI/180.0);var c=Math.cos(rlat);this.x=c*Math.cos(theta);this.y=c*Math.sin(theta);this.z=Math.sin(rlat);}
bdccGeo.prototype=new bdccGeo();function bdccGeoGeocentricLatitude(geographicLatitude)
{var flattening=1.0/298.257223563;var f=(1.0-flattening)*(1.0-flattening);return Math.atan((Math.tan(geographicLatitude)*f));}
function bdccGeoGeographicLatitude(geocentricLatitude)
{var flattening=1.0/298.257223563;var f=(1.0-flattening)*(1.0-flattening);return Math.atan(Math.tan(geocentricLatitude)/f);}
function bdccGeoGetIntersection(geo1,geo2,geo3,geo4)
{var geoCross1=geo1.crossNormalize(geo2);var geoCross2=geo3.crossNormalize(geo4);return geoCross1.crossNormalize(geoCross2);}
function bdccGeoRadiansToMeters(rad)
{return rad*6378137.0;}
function bdccGeoMetersToRadians(m)
{return m/6378137.0;}
bdccGeo.prototype.getLatitudeRadians=function()
{return(bdccGeoGeographicLatitude(Math.atan2(this.z,Math.sqrt((this.x*this.x)+(this.y*this.y)))));}
bdccGeo.prototype.getLongitudeRadians=function()
{return(Math.atan2(this.y,this.x));}
bdccGeo.prototype.getLatitude=function()
{return this.getLatitudeRadians()*180.0/Math.PI;}
bdccGeo.prototype.getLongitude=function()
{return this.getLongitudeRadians()*180.0/Math.PI;}
bdccGeo.prototype.dot=function(b)
{return((this.x*b.x)+(this.y*b.y)+(this.z*b.z));}
bdccGeo.prototype.crossLength=function(b)
{var x=(this.y*b.z)-(this.z*b.y);var y=(this.z*b.x)-(this.x*b.z);var z=(this.x*b.y)-(this.y*b.x);return Math.sqrt((x*x)+(y*y)+(z*z));}
bdccGeo.prototype.scale=function(s)
{var r=new bdccGeo(0,0);r.x=this.x*s;r.y=this.y*s;r.z=this.z*s;return r;}
bdccGeo.prototype.crossNormalize=function(b)
{var x=(this.y*b.z)-(this.z*b.y);var y=(this.z*b.x)-(this.x*b.z);var z=(this.x*b.y)-(this.y*b.x);var L=Math.sqrt((x*x)+(y*y)+(z*z));var r=new bdccGeo(0,0);r.x=x/L;r.y=y/L;r.z=z/L;return r;}
bdccGeo.prototype.antipode=function()
{return this.scale(-1.0);}
bdccGeo.prototype.distance=function(v2)
{return Math.atan2(v2.crossLength(this),v2.dot(this));}
bdccGeo.prototype.distanceToLineSegMtrs=function(geo1,geo2)
{var p2=geo1.crossNormalize(geo2);var ip=bdccGeoGetIntersection(geo1,geo2,this,p2);var d=geo1.distance(geo2);var d1p=geo1.distance(ip);var d2p=geo2.distance(ip);if((d>=d1p)&&(d>=d2p))
return bdccGeoRadiansToMeters(this.distance(ip));else
{ip=ip.antipode();d1p=geo1.distance(ip);d2p=geo2.distance(ip);}
if((d>=d1p)&&(d>=d2p))
return bdccGeoRadiansToMeters(this.distance(ip));else
return bdccGeoRadiansToMeters(Math.min(geo1.distance(this),geo2.distance(this)));}
function bdccGeoDistanceToPolyMtrs(poly,point)
{var d=999999999;var i;var p=new bdccGeo(point.lat(),point.lng());for(i=0;i<(poly.getVertexCount()-1);i++)
{var p1=poly.getVertex(i);var l1=new bdccGeo(p1.lat(),p1.lng());var p2=poly.getVertex(i+1);var l2=new bdccGeo(p2.lat(),p2.lng());var dp=p.distanceToLineSegMtrs(l1,l2);if(dp<d)
d=dp;}
return d;}
function bdccGeoPointAtRangeAndBearing(point,distanceMeters,azimuthDegrees)
{var latr=point.lat()*Math.PI/180.0;var lonr=point.lng()*Math.PI/180.0;var coslat=Math.cos(latr);var sinlat=Math.sin(latr);var az=azimuthDegrees*Math.PI/180.0;var cosaz=Math.cos(az);var sinaz=Math.sin(az);var dr=distanceMeters/6378137.0;var sind=Math.sin(dr);var cosd=Math.cos(dr);return new GLatLng(Math.asin((sinlat*cosd)+(coslat*sind*cosaz))*180.0/Math.PI,(Math.atan2((sind*sinaz),(coslat*cosd)-(sinlat*sind*cosaz))+lonr)*180.0/Math.PI);}