Javascript 地图经度纬度之间的距离的算法(轉)
2012-01-12 12:39
447 查看
Calculatedistance,bearingandmorebetweenLatitude/Longitudepoints
Thispagepresentsavarietyofcalculationsforlatitude/longitudepoints,withtheformul?andcodefragmentsforimplementingthem.
Alltheseformul?areforcalculationsonthebasisofasphericalearth(ignoringellipsoidaleffects)–whichisaccurateenough
Entertheco-ordinatesintothetextboxestotryoutthecalculations.Avarietyofformatsareaccepted,principally:
Distance
Thisusesthe‘haversine’formulatocalculatethegreat-circledistancebetweentwopoints–thatis,theshortestdistanceovertheearth’ssurface–givingan‘as-the-crow-flies’distancebetweenthepoints(ignoringanyhills,ofcourse!).Haversineformula: | a=sin²(Δlat/2)+cos(lat1).cos(lat2).sin²(Δlong/2) c=2.atan2(√a,√(1−a)) d=R.c |
whereRisearth’sradius(meanradius=6,371km); notethatanglesneedtobeinradianstopasstotrigfunctions! | |
JavaScript: | varR=6371;//kmvardLat=(lat2-lat1).toRad();vardLon=(lon2-lon1).toRad();varlat1=lat1.toRad();varlat2=lat2.toRad();vara=Math.sin(dLat/2)*Math.sin(dLat/2)+Math.sin(dLon/2)*Math.sin(dLon/2)*Math.cos(lat1)*Math.cos(lat2);varc=2*Math.atan2(Math.sqrt(a),Math.sqrt(1-a));vard=R*c; |
SphericalLawofCosines
Infact,whenSinnottpublishedthehaversineformula,computationalprecisionwaslimited.Nowadays,JavaScript(andmostmoderncomputers&languages)useIEEE75464-bitfloating-pointnumbers,whichprovide15significantfiguresofprecision.Withthisprecision,thesimpleThismakesthesimplerlawofcosinesareasonable1-linealternativetothehaversineformulaformanypurposes.Thechoicemaybedrivenbycodingcontext,availabletrigfunctions(indifferentlanguages),etc.
Sphericallaw ofcosines: | d=acos(sin(lat1).sin(lat2)+cos(lat1).cos(lat2).cos(long2−long1)).R |
JavaScript: | varR=6371;//kmvard=Math.acos(Math.sin(lat1)*Math.sin(lat2)+Math.cos(lat1)*Math.cos(lat2)*Math.cos(lon2-lon1))*R; |
Excel: | =ACOS(SIN(lat1)*SIN(lat2)+COS(lat1)*COS(lat2)*COS(lon2-lon1))*6371 |
Equirectangularapproximation
Ifperformanceisanissueandaccuracylessimportant,forsmalldistancesx=Δlon.cos(lat) y=Δlat d=R.√x²+y² | |
JavaScript: | varx=(lon2-lon1)*Math.cos((lat1+lat2)/2);vary=(lat2-lat1);vard=Math.sqrt(x*x+y*y)*R; (lat/loninradians!) |
Bearing
Ingeneral,yourcurrentheadingwillvaryasyoufollowagreatcirclepath(orthodrome);thefinalheadingwilldifferfromtheinitialheadingbyvaryingdegreesaccordingtodistanceandlatitude(ifyouweretogofromsay35°N,45°E(Baghdad)to35°N,135°E(Osaka),youwouldstartonaheadingof60°andenduponaheadingof120°!).Thisformulaisfortheinitialbearing(sometimesreferredtoasforwardazimuth)whichiffollowedinastraightlinealongagreat-circlearcwilltakeyoufromthestartpointtotheendpoint:
Formula: | θ= | atan2( | sin(Δlong).cos(lat2), cos(lat1).sin(lat2)−sin(lat1).cos(lat2).cos(Δlong)) |
JavaScript: | vary=Math.sin(dLon)*Math.cos(lat2);varx=Math.cos(lat1)*Math.sin(lat2)-Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);varbrng=Math.atan2(y,x).toDeg(); | ||
Excel: | =ATAN2(COS(lat1)*SIN(lat2)-SIN(lat1)*COS(lat2)*COS(lon2-lon1), SIN(lon2-lon1)*COS(lat2)) *NotethatExcelreversestheargumentstoATAN2–seenotesbelow |
Forfinalbearing,simplytaketheinitialbearingfromtheendpointtothestartpointandreverseit(usingθ=(θ+180)%360).
Midpoint
Thisisthehalf-waypointalongagreatcirclepathbetweenthetwopoints.Formula: | Bx=cos(lat2).cos(Δlong) By=cos(lat2).sin(Δlong) latm=atan2(sin(lat1)+sin(lat2),√((cos(lat1)+Bx)²+By²)) lonm=lon1+atan2(By,cos(lat1)+Bx) |
JavaScript: | varBx=Math.cos(lat2)*Math.cos(dLon);varBy=Math.cos(lat2)*Math.sin(dLon);varlat3=Math.atan2(Math.sin(lat1)+Math.sin(lat2),Math.sqrt((Math.cos(lat1)+Bx)*(Math.cos(lat1)+Bx)+By*By));varlon3=lon1+Math.atan2(By,Math.cos(lat1)+Bx); |
Destinationpointgivendistanceandbearingfromstartpoint
Givenastartpoint,initialbearing,anddistance,thiswillcalculatethedestinationpointandfinalbearingtravellingalonga(shortestdistance)greatcirclearc.Formula: | lat2=asin(sin(lat1)*cos(d/R)+cos(lat1)*sin(d/R)*cos(θ)) |
lon2=lon1+atan2(sin(θ)*sin(d/R)*cos(lat1),cos(d/R)−sin(lat1)*sin(lat2)) | |
θisthebearing(inradians,clockwisefromnorth); d/Ristheangulardistance(inradians),wheredisthedistancetravelledandRistheearth’sradius | |
JavaScript: | varlat2=Math.asin(Math.sin(lat1)*Math.cos(d/R)+Math.cos(lat1)*Math.sin(d/R)*Math.cos(brng));varlon2=lon1+Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(lat1),Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2)); |
Excel: | lat2:=ASIN(SIN(lat1)*COS(d/R)+COS(lat1)*SIN(d/R)*COS(brng)) lon2:=lon1+ATAN2(COS(d/R)-SIN(lat1)*SIN(lat2),SIN(brng)*SIN(d/R)*COS(lat1)) |
Intersectionoftwopathsgivenstartpointsandbearings
Thisisarathermorecomplexcalculationthanmostothersonthispage,butI'vebeenaskedforitanumberoftimes.SeebelowfortheJavaScript.Formula: | d12=2.asin(√(sin²(Δlat/2)+cos(lat1).cos(lat2).sin²(Δlon/2))) φ1=acos(sin(lat2)−sin(lat1).cos(d12)/sin(d12).cos(lat1)) φ2=acos(sin(lat1)−sin(lat2).cos(d12)/sin(d12).cos(lat2)) ifsin(lon2−lon1)>0 θ12=φ1,θ21=2.π−φ2 else θ12=2.π−φ1,θ21=φ2 α1=(θ1−θ12+π)%2.π−π α2=(θ21−θ2+π)%2.π−π α1=|α1| α2=|α2| α3=acos(−cos(α1).cos(α2)+sin(α1).sin(α2).cos(d12)) d13=atan2(sin(d12).sin(α1).sin(α2),cos(α2)+cos(α1).cos(α3)) lat3=asin(sin(lat1).cos(d13)+cos(lat1).sin(d13).cos(θ1)) Δlon13=atan2(sin(θ1).sin(d13).cos(lat1),cos(d13)−sin(lat1).sin(lat3)) lon3=(lon1+Δlon13+π)%2.π−π |
where | lat1,lon1,θ1:1stpoint&bearing lat2,lon2,θ2:2ndpoint&bearing lat3,lon3:intersectionpoint %=mod,||=abs |
note– | ifsin(α1)=0andsin(α2)=0:infinitesolutions ifsin(α1).sin(α2)<0:ambiguoussolution thisformulationisnotalwayswell-conditionedformeridionalorequatoriallines |
Foreachpointφ,λ(lat=φ,lon=λ),wecandefineaunitvectorpointingtoitfromthecentreoftheearth:u{x,y,z}=[cosφ·cosλ,cosφ·sinλ,sinφ](takingx=0º,y=90º,z=north–notethattheseformulædependonconventionusedfordirectionsandhandedness)
Andforanygreatcircledefinedbytwopoints,wecandefineaunitvectorNnormaltotheplaneofthecircle:N(u1,u2)=(u1×u2)/||u1×u2||where×isthevectorcrossproduct,and||u||thenorm(lengthofthevector)
Thevectorrepresentingtheintersectionofthetwogreatcirclesisthenui=±N(N(u1,u2),N(u3,u4))
WecanthengetthelatitudeandlongitudeofPibyφ=atan2(uz,sqrt(ux²+uy²)),λ=atan2(uy,ux)
Theantipodalintersectionpointis(-φ,λ+π)
Cross-trackdistance
Here’sanewone:I’vesometimesbeenaskedaboutdistanceofapointfromagreat-circlepath(sometimescalledcrosstrackerror).Formula: | dxt=asin(sin(d13/R)*sin(θ13−θ12))*R |
where | d13isdistancefromstartpointtothirdpoint θ13is(initial)bearingfromstartpointtothirdpoint θ12is(initial)bearingfromstartpointtoendpoint Ristheearth’sradius |
JavaScript: | vardXt=Math.asin(Math.sin(d13/R)*Math.sin(brng13-brng12))*R; |
Thealong-trackdistance,fromthestartpointtotheclosestpointonthepathtothethirdpoint,is
Formula: | dat=acos(cos(d13/R)/cos(dxt/R))*R |
where | d13isdistancefromstartpointtothirdpoint dxtiscross-trackdistance Ristheearth’sradius |
JavaScript: | vardAt=Math.acos(Math.cos(d13/R)/Math.cos(dXt/R))*R; |
Closestpointtothepoles
And:‘Clairaut’sformula’willgiveyouthemaximumlatitudeofagreatcirclepath,givenabearingandlatitudeonthegreatcircle:Formula: | latmax=acos(abs(sin(θ)*cos(lat))) |
JavaScript: | varlatMax=Math.acos(Math.abs(Math.sin(brng)*Math.cos(lat))); |
Rhumblines
A‘rhumbline’(orloxodrome)isapathofconstantbearing,whichcrossesallmeridiansatthesameangle.Sailorsusedto(andsometimesstill)navigatealongrhumblinessinceitiseasiertofollowaconstantcompassbearingthantobecontinuallyadjustingthebearing,asisneededtofollowagreatcircle.RhumblinesarestraightlinesonaMercatorProjectionmap(alsohelpfulfornavigation).
Rhumblinesaregenerallylongerthangreat-circle(orthodrome)routes.Forinstance,LondontoNewYorkis4%longeralongarhumblinethanalongagreatcircle–importantforaviationfuel,butnotparticularlytosailingvessels.NewYorktoBeijing–closetothemostextremeexamplepossible(thoughnotsailable!)–is30%longeralongarhumbline.
Distance/bearing
Theseformulægivethedistanceand(constant)bearingbetweentwopoints.Formula: | Δφ=ln(tan(lat2/2+π/4)/tan(lat1/2+π/4)) | [=the‘stretched’latitudedifference] |
ifE:Wline, | q=cos(lat1) | |
otherwise, | q=Δlat/Δφ | |
d=√(Δlat²+q².Δlon²).R | [pythagoras] | |
θ=atan2(Δlon,Δφ) | ||
wherelnisnaturallog,Δlonistakingshortestroute(<180º),andRistheearth’sradius | ||
JavaScript: | vardPhi=Math.log(Math.tan(lat2/2+Math.PI/4)/Math.tan(lat1/2+Math.PI/4));varq=(!isNaN(dLat/dPhi))?dLat/dPhi:Math.cos(lat1);//E-WlinegivesdPhi=0 |
Destination
Givenastartpointandadistancedalongconstantbearingθ,thiswillcalculatethedestinationpoint.Ifyoumaintainaconstantbearingalongarhumbline,youwillgraduallyspiralintowardsoneofthepoles.Formula: | α=d/R(angulardistance) | |
lat2=lat1+α.cos(θ) | ||
Δφ=ln(tan(lat2/2+π/4)/tan(lat1/2+π/4)) | [=the‘stretched’latitudedifference] | |
ifE:Wline | q=cos(lat1) | |
otherwise | q=Δlat/Δφ | |
Δlon=α.sin(θ)/q | ||
lon2=(lon1+Δlon+π)%2.π−π | ||
wherelnisnaturallogand%ismodulo,Δlonistakingshortestroute(<180°),andRistheearth’sradius | ||
JavaScript: | vardLat=d*Math.cos(brng);varlat2=lat1+dLat;vardPhi=Math.log(Math.tan(lat2/2+Math.PI/4)/Math.tan(lat1/2+Math.PI/4));varq=(!isNaN(dLat/dPhi))?dLat/dPhi:Math.cos(lat1);//E-WlinegivesdPhi=0vardLon=d*Math.sin(brng)/q;//checkforsomedaftbuggergoingpastthepole,normaliselatitudeifsoif(Math.abs(lat2)>Math.PI/2)lat2=lat2>0?Math.PI-lat2:-(Math.PI-lat2); |
Mid-point
Thisformulaforcalculatingthe‘loxodromicmidpoint’,thepointhalf-wayalongarhumblinebetweentwopoints,isduetoRobertHillandCliveToothFormula: | latm=(lat1+lat2)/2 | |
f1=tan(π/4+lat1/2) | ||
f2=tan(π/4+lat2/2) | ||
fm=tan(π/4+latm/2) | ||
lonm=[(lon2−lon1).ln(fm)+lon1.ln(f2)−lon2.ln(f1)]/ln(f2/f1) | ||
wherelnisnaturallog | ||
JavaScript: | varlat3=(lat1+lat2)/2;varf1=Math.tan(Math.PI/4+lat1/2);varf2=Math.tan(Math.PI/4+lat2/2);varf3=Math.tan(Math.PI/4+lat3/2);varlon3=((lon2-lon1)*Math.log(f3)+lon1*Math.log(f2)-lon2*Math.log(f1))/Math.log(f2/f1); UsingthescriptsinwebpagesUsingthesescriptsinwebpageswouldbesomethinglikethefollowing: |
<scriptsrc="geo.js">/*Geodesyrepresentationconversions*/</script>
...
<form>
Lat1:<inputtype="text"name="lat1"id="lat1">Lon1:<inputtype="text"name="lon1"id="lon1">
Lat2:<inputtype="text"name="lat2"id="lat2">Lon2:<inputtype="text"name="lon2"id="lon2">
<buttononClick="varp1=newLatLon(Geo.parseDMS(f.lat1.value),Geo.parseDMS(f.lon1.value));
varp2=newLatLon(Geo.parseDMS(f.lat2.value),Geo.parseDMS(f.lon2.value));
alert(p1.distanceTo(p2));">Calculatedistance</button>
</form>
IfyouusejQuery,thecodecanbeseparatedfromtheHTML:
<scriptsrc="latlon.js">/*Latitude/Longitudeformulae*/</script>
<scriptsrc="geo.js">/*Geodesyrepresentationconversions*/</script>
<script>
$(document).ready(function(){
$('#calc-dist').click(function(){
varp1=newLatLon(Geo.parseDMS($('#lat1').val()),Geo.parseDMS($('#lon1').val()));
varp2=newLatLon(Geo.parseDMS($('#lat2').val()),Geo.parseDMS($('#lon2').val()));
$('#result-distance').html(p1.distanceTo(p2)+'km');
});
});
</script>
...
<form>
Lat1:<inputtype="text"name="lat1"id="lat1">Lon1:<inputtype="text"name="lon1"id="lon1">
Lat2:<inputtype="text"name="lat2"id="lat2">Lon2:<inputtype="text"name="lon2"id="lon2">
<buttonid="calc-dist">Calculatedistance</button>
<outputid="result-distance"></output>
</form>
--------------------------------------------------------------------------------
/*Latitude/longitudesphericalgeodesyformulae&scripts(c)ChrisVeness2002-2011*/
/*-www.movable-type.co.uk/scripts/latlong.html*/
/**/
/*Sampleusage:*/
/*varp1=newLatLon(51.5136,-0.0983);*/
/*varp2=newLatLon(51.4778,-0.0015);*/
/*vardist=p1.distanceTo(p2);//inkm*/
/*varbrng=p1.bearingTo(p2);//indegreesclockwisefromnorth*/
/*...etc*/
/*-----------------------------------------------*/
/*-----------------------------------------------*/
/*Notethatminimalerrorcheckingisperformedinthisexamplecode!*/
/*-----------------------------------------------*/
/**
*Createsapointontheearth'ssurfaceatthesuppliedlatitude/longitude
*
*@constructor
*@param{Number}lat:latitudeinnumericdegrees
*@param{Number}lon:longitudeinnumericdegrees
*@param{Number}[rad=6371]:radiusofearthifdifferentvalueisrequiredfromstandard6,371km
*/
functionLatLon(lat,lon,rad){
if(typeof(rad)=='undefined')rad=6371;//earth'smeanradiusinkm
//onlyacceptnumbersorvalidnumericstrings
this._lat=typeof(lat)=='number'?lat:typeof(lat)=='string'&&lat.trim()!=''?+lat:NaN;
this._lon=typeof(lon)=='number'?lon:typeof(lon)=='string'&&lon.trim()!=''?+lon:NaN;
this._radius=typeof(rad)=='number'?rad:typeof(rad)=='string'&&trim(lon)!=''?+rad:NaN;
}
/**
*Returnsthedistancefromthispointtothesuppliedpoint,inkm
*(usingHaversineformula)
*
*from:Haversineformula-R.W.Sinnott,"VirtuesoftheHaversine",
*SkyandTelescope,vol68,no2,1984
*
*@param{LatLon}point:Latitude/longitudeofdestinationpoint
*@param{Number}[precision=4]:noofsignificantdigitstouseforreturnedvalue
*@returns{Number}Distanceinkmbetweenthispointanddestinationpoint
*/
LatLon.prototype.distanceTo=function(point,precision){
//default4sigfigsreflectstypical0.3%accuracyofsphericalmodel
if(typeofprecision=='undefined')precision=4;
varR=this._radius;
varlat1=this._lat.toRad(),lon1=this._lon.toRad();
varlat2=point._lat.toRad(),lon2=point._lon.toRad();
vardLat=lat2-lat1;
vardLon=lon2-lon1;
vara=Math.sin(dLat/2)*Math.sin(dLat/2)+
Math.cos(lat1)*Math.cos(lat2)*
Math.sin(dLon/2)*Math.sin(dLon/2);
varc=2*Math.atan2(Math.sqrt(a),Math.sqrt(1-a));
vard=R*c;
returnd.toPrecisionFixed(precision);
}
/**
*Returnsthe(initial)bearingfromthispointtothesuppliedpoint,indegrees
*see
*@param{LatLon}point:Latitude/longitudeofdestinationpoint
*@returns{Number}InitialbearingindegreesfromNorth
*/
LatLon.prototype.bearingTo=function(point){
varlat1=this._lat.toRad(),lat2=point._lat.toRad();
vardLon=(point._lon-this._lon).toRad();
vary=Math.sin(dLon)*Math.cos(lat2);
varx=Math.cos(lat1)*Math.sin(lat2)-
Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
varbrng=Math.atan2(y,x);
return(brng.toDeg()+360)%360;
}
/**
*Returnsfinalbearingarrivingatsupplieddestinationpointfromthispoint;thefinalbearing
*willdifferfromtheinitialbearingbyvaryingdegreesaccordingtodistanceandlatitude
*
*@param{LatLon}point:Latitude/longitudeofdestinationpoint
*@returns{Number}FinalbearingindegreesfromNorth
*/
LatLon.prototype.finalBearingTo=function(point){
//getinitialbearingfromsuppliedpointbacktothispoint...
varlat1=point._lat.toRad(),lat2=this._lat.toRad();
vardLon=(this._lon-point._lon).toRad();
vary=Math.sin(dLon)*Math.cos(lat2);
varx=Math.cos(lat1)*Math.sin(lat2)-
Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
varbrng=Math.atan2(y,x);
//...&reverseitbyadding180°
return(brng.toDeg()+180)%360;
}
/**
*Returnsthemidpointbetweenthispointandthesuppliedpoint.
*see
*
*@param{LatLon}point:Latitude/longitudeofdestinationpoint
*@returns{LatLon}Midpointbetweenthispointandthesuppliedpoint
*/
LatLon.prototype.midpointTo=function(point){
lat1=this._lat.toRad(),lon1=this._lon.toRad();
lat2=point._lat.toRad();
vardLon=(point._lon-this._lon).toRad();
varBx=Math.cos(lat2)*Math.cos(dLon);
varBy=Math.cos(lat2)*Math.sin(dLon);
lat3=Math.atan2(Math.sin(lat1)+Math.sin(lat2),
Math.sqrt((Math.cos(lat1)+Bx)*(Math.cos(lat1)+Bx)+By*By));
lon3=lon1+Math.atan2(By,Math.cos(lat1)+Bx);
lon3=(lon3+3*Math.PI)%(2*Math.PI)-Math.PI;//normaliseto-180..+180º
returnnewLatLon(lat3.toDeg(),lon3.toDeg());
}
/**
*Returnsthedestinationpointfromthispointhavingtravelledthegivendistance(inkm)onthe
*giveninitialbearing(bearingmayvarybeforedestinationisreached)
*
*see
*@param{Number}brng:Initialbearingindegrees
*@param{Number}dist:Distanceinkm
*@returns{LatLon}Destinationpoint
*/
LatLon.prototype.destinationPoint=function(brng,dist){
dist=typeof(dist)=='number'?dist:typeof(dist)=='string'&&dist.trim()!=''?+dist:NaN;
dist=dist/this._radius;//convertdisttoangulardistanceinradians
brng=brng.toRad();//
varlat1=this._lat.toRad(),lon1=this._lon.toRad();
varlat2=Math.asin(Math.sin(lat1)*Math.cos(dist)+
Math.cos(lat1)*Math.sin(dist)*Math.cos(brng));
varlon2=lon1+Math.atan2(Math.sin(brng)*Math.sin(dist)*Math.cos(lat1),
Math.cos(dist)-Math.sin(lat1)*Math.sin(lat2));
lon2=(lon2+3*Math.PI)%(2*Math.PI)-Math.PI;//normaliseto-180..+180º
returnnewLatLon(lat2.toDeg(),lon2.toDeg());
}
/**
*Returnsthepointofintersectionoftwopathsdefinedbypointandbearing
*
*see
*@param{LatLon}p1:Firstpoint
*@param{Number}brng1:Initialbearingfromfirstpoint
*@param{LatLon}p2:Secondpoint
*@param{Number}brng2:Initialbearingfromsecondpoint
*@returns{LatLon}Destinationpoint(nullifnouniqueintersectiondefined)
*/
LatLon.intersection=function(p1,brng1,p2,brng2){
brng1=typeofbrng1=='number'?brng1:typeofbrng1=='string'&&trim(brng1)!=''?+brng1:NaN;
brng2=typeofbrng2=='number'?brng2:typeofbrng2=='string'&&trim(brng2)!=''?+brng2:NaN;
lat1=p1._lat.toRad(),lon1=p1._lon.toRad();
lat2=p2._lat.toRad(),lon2=p2._lon.toRad();
brng13=brng1.toRad(),brng23=brng2.toRad();
dLat=lat2-lat1,dLon=lon2-lon1;
dist12=2*Math.asin(Math.sqrt(Math.sin(dLat/2)*Math.sin(dLat/2)+
Math.cos(lat1)*Math.cos(lat2)*Math.sin(dLon/2)*Math.sin(dLon/2)));
if(dist12==0)returnnull;
//initial/finalbearingsbetweenpoints
brngA=Math.acos((Math.sin(lat2)-Math.sin(lat1)*Math.cos(dist12))/
(Math.sin(dist12)*Math.cos(lat1)));
if(isNaN(brngA))brngA=0;//protectagainstrounding
brngB=Math.acos((Math.sin(lat1)-Math.sin(lat2)*Math.cos(dist12))/
(Math.sin(dist12)*Math.cos(lat2)));
if(Math.sin(lon2-lon1)>0){
brng12=brngA;
brng21=2*Math.PI-brngB;
}else{
brng12=2*Math.PI-brngA;
brng21=brngB;
}
alpha1=(brng13-brng12+Math.PI)%(2*Math.PI)-Math.PI;//angle2-1-3
alpha2=(brng21-brng23+Math.PI)%(2*Math.PI)-Math.PI;//angle1-2-3
if(Math.sin(alpha1)==0&&Math.sin(alpha2)==0)returnnull;//infiniteintersections
if(Math.sin(alpha1)*Math.sin(alpha2)<0)returnnull;//ambiguousintersection
//alpha1=Math.abs(alpha1);
//alpha2=Math.abs(alpha2);
//...EdWilliamstakesabsofalpha1/alpha2,butseemstobreakcalculation?
alpha3=Math.acos(-Math.cos(alpha1)*Math.cos(alpha2)+
Math.sin(alpha1)*Math.sin(alpha2)*Math.cos(dist12));
dist13=Math.atan2(Math.sin(dist12)*Math.sin(alpha1)*Math.sin(alpha2),
Math.cos(alpha2)+Math.cos(alpha1)*Math.cos(alpha3))
lat3=Math.asin(Math.sin(lat1)*Math.cos(dist13)+
Math.cos(lat1)*Math.sin(dist13)*Math.cos(brng13));
dLon13=Math.atan2(Math.sin(brng13)*Math.sin(dist13)*Math.cos(lat1),
Math.cos(dist13)-Math.sin(lat1)*Math.sin(lat3));
lon3=lon1+dLon13;
lon3=(lon3+3*Math.PI)%(2*Math.PI)-Math.PI;//normaliseto-180..+180º
returnnewLatLon(lat3.toDeg(),lon3.toDeg());
}
/*-----------------------------------------------*/
/**
*Returnsthedistancefromthispointtothesuppliedpoint,inkm,travellingalongarhumbline
*
*see
*@param{LatLon}point:Latitude/longitudeofdestinationpoint
*@returns{Number}Distanceinkmbetweenthispointanddestinationpoint
*/
LatLon.prototype.rhumbDistanceTo=function(point){
varR=this._radius;
varlat1=this._lat.toRad(),lat2=point._lat.toRad();
vardLat=(point._lat-this._lat).toRad();
vardLon=Math.abs(point._lon-this._lon).toRad();
vardPhi=Math.log(Math.tan(lat2/2+Math.PI/4)/Math.tan(lat1/2+Math.PI/4));
varq=(!isNaN(dLat/dPhi))?dLat/dPhi:Math.cos(lat1);//E-WlinegivesdPhi=0
//ifdLonover180°takeshorterrhumbacross180°meridian:
if(dLon>Math.PI)dLon=2*Math.PI-dLon;
vardist=Math.sqrt(dLat*dLat+q*q*dLon*dLon)*R;
returndist.toPrecisionFixed(4);//4sigfigsreflectstypical0.3%accuracyofsphericalmodel
}
/**
*Returnsthebearingfromthispointtothesuppliedpointalongarhumbline,indegrees
*
*@param{LatLon}point:Latitude/longitudeofdestinationpoint
*@returns{Number}BearingindegreesfromNorth
*/
LatLon.prototype.rhumbBearingTo=function(point){
varlat1=this._lat.toRad(),lat2=point._lat.toRad();
vardLon=(point._lon-this._lon).toRad();
vardPhi=Math.log(Math.tan(lat2/2+Math.PI/4)/Math.tan(lat1/2+Math.PI/4));
if(Math.abs(dLon)>Math.PI)dLon=dLon>0?-(2*Math.PI-dLon):(2*Math.PI+dLon);
varbrng=Math.atan2(dLon,dPhi);
return(brng.toDeg()+360)%360;
}
/**
*Returnsthedestinationpointfromthispointhavingtravelledthegivendistance(inkm)onthe
*givenbearingalongarhumbline
*
*@param{Number}brng:BearingindegreesfromNorth
*@param{Number}dist:Distanceinkm
*@returns{LatLon}Destinationpoint
*/
LatLon.prototype.rhumbDestinationPoint=function(brng,dist){
varR=this._radius;
vard=parseFloat(dist)/R;//d=angulardistancecoveredonearth'ssurface
varlat1=this._lat.toRad(),lon1=this._lon.toRad();
brng=brng.toRad();
varlat2=lat1+d*Math.cos(brng);
vardLat=lat2-lat1;
vardPhi=Math.log(Math.tan(lat2/2+Math.PI/4)/Math.tan(lat1/2+Math.PI/4));
varq=(!isNaN(dLat/dPhi))?dLat/dPhi:Math.cos(lat1);//E-WlinegivesdPhi=0
vardLon=d*Math.sin(brng)/q;
//checkforsomedaftbuggergoingpastthepole
if(Math.abs(lat2)>Math.PI/2)lat2=lat2>0?Math.PI-lat2:-(Math.PI-lat2);
lon2=(lon1+dLon+3*Math.PI)%(2*Math.PI)-Math.PI;
returnnewLatLon(lat2.toDeg(),lon2.toDeg());
}
/*-----------------------------------------------*/
/**
*Returnsthelatitudeofthispoint;signednumericdegreesifnoformat,otherwiseformat&dp
*asperGeo.toLat()
*
*@param{String}[format]:Returnvalueas'd','dm','dms'
*@param{Number}[dp=0|2|4]:Noofdecimalplacestodisplay
*@returns{Number|String}Numericdegreesifnoformatspecified,otherwisedeg/min/sec
*
*@requiresGeo
*/
LatLon.prototype.lat=function(format,dp){
if(typeofformat=='undefined')returnthis._lat;
returnGeo.toLat(this._lat,format,dp);
}
/**
*Returnsthelongitudeofthispoint;signednumericdegreesifnoformat,otherwiseformat&dp
*asperGeo.toLon()
*
*@param{String}[format]:Returnvalueas'd','dm','dms'
*@param{Number}[dp=0|2|4]:Noofdecimalplacestodisplay
*@returns{Number|String}Numericdegreesifnoformatspecified,otherwisedeg/min/sec
*
*@requiresGeo
*/
LatLon.prototype.lon=function(format,dp){
if(typeofformat=='undefined')returnthis._lon;
returnGeo.toLon(this._lon,format,dp);
}
/**
*Returnsastringrepresentationofthispoint;formatanddpasperlat()/lon()
*
*@param{String}[format]:Returnvalueas'd','dm','dms'
*@param{Number}[dp=0|2|4]:Noofdecimalplacestodisplay
*@returns{String}Comma-separatedlatitude/longitude
*
*@requiresGeo
*/
LatLon.prototype.toString=function(format,dp){
if(typeofformat=='undefined')format='dms';
if(isNaN(this._lat)||isNaN(this._lon))return'-,-';
returnGeo.toLat(this._lat,format,dp)+','+Geo.toLon(this._lon,format,dp);
}
/*-----------------------------------------------*/
//----extendNumberobjectwithmethodsforconvertingdegrees/radians
/**Convertsnumericdegreestoradians*/
if(typeof(Number.prototype.toRad)==="undefined"){
Number.prototype.toRad=function(){
returnthis*Math.PI/180;
}
}
/**Convertsradianstonumeric(signed)degrees*/
if(typeof(Number.prototype.toDeg)==="undefined"){
Number.prototype.toDeg=function(){
returnthis*180/Math.PI;
}
}
/**
*Formatsthesignificantdigitsofanumber,usingonlyfixed-pointnotation(noexponential)
*
*@param{Number}precision:Numberofsignificantdigitstoappearinthereturnedstring
*@returns{String}Astringrepresentationofnumberwhichcontainsprecisionsignificantdigits
*/
if(typeof(Number.prototype.toPrecisionFixed)==="undefined"){
Number.prototype.toPrecisionFixed=function(precision){
if(isNaN(this))return'NaN';
varnumb=this<0?-this:this;//can'ttakelogof-venumber...
varsign=this<0?'-':'';
if(numb==0){//can'ttakelogofzero,justformatwithprecisionzeros
varn='0.';
while(precision--)n+='0';
returnn
}
varscale=Math.ceil(Math.log(numb)*Math.LOG10E);//noofdigitsbeforedecimal
varn=String(Math.round(numb*Math.pow(10,precision-scale)));
if(scale>0){//addtrailingzeros&insertdecimalasrequired
l=scale-n.length;
while(l-->0)n=n+'0';
if(scale<n.length)n=n.slice(0,scale)+'.'+n.slice(scale);
}else{//prefixdecimalandleadingzerosifrequired
while(scale++<0)n='0'+n;
n='0.'+n;
}
returnsign+n;
}
}
/**Trimswhitespacefromstring(q.v.blog.stevenlevithan.com/archives/faster-trim-javascript)*/
if(typeof(String.prototype.trim)==="undefined"){
String.prototype.trim=function(){
returnString(this).replace(/^\s\s*/,'').replace(/\s\s*$/,'');
}
}
/*-----------------------------------------------*/
/*Geodesyrepresentationconversionfunctions(c)ChrisVeness2002-2011*/
/*-www.movable-type.co.uk/scripts/latlong.html*/
/**/
/*Sampleusage:*/
/*varlat=Geo.parseDMS('51°28′40.12″N');*/
/*varlon=Geo.parseDMS('000°00′05.31″W');*/
/*varp1=newLatLon(lat,lon);*/
/*-----------------------------------------------*/
varGeo={};//Geonamespace,representingstaticclass
/**
*Parsesstringrepresentingdegrees/minutes/secondsintonumericdegrees
*
*Thisisveryflexibleonformats,allowingsigneddecimaldegrees,ordeg-min-secoptionally
*suffixedbycompassdirection(NSEW).Avarietyofseparatorsareaccepted(eg3º37'09"W)
*orfixed-widthformatwithoutseparators(eg0033709W).Secondsandminutesmaybeomitted.
*(Noteminimalvalidationisdone).
*
*@param{String|Number}dmsStr:Degreesordeg/min/secinvarietyofformats
*@returns{Number}Degreesasdecimalnumber
*@throws{TypeError}dmsStrisanobject,perhapsDOMobjectwithout.value?
*/
Geo.parseDMS=function(dmsStr){
if(typeofdeg=='object')thrownewTypeError('Geo.parseDMS-dmsStris[DOM?]object');
//checkforsigneddecimaldegreeswithoutNSEW,ifsoreturnitdirectly
if(typeofdmsStr==='number'&&isFinite(dmsStr))returnNumber(dmsStr);
//stripoffanysignorcompassdir'n&splitoutseparated/m/s
vardms=String(dmsStr).trim().replace(/^-/,'').replace(/[NSEW]$/i,'').split(/[^0-9.,]+/);
if(dms[dms.length-1]=='')dms.splice(dms.length-1);//fromtrailingsymbol
if(dms=='')returnNaN;
//andconverttodecimaldegrees...
switch(dms.length){
case3://interpret3-partresultasd/m/s
vardeg=dms[0]/1+dms[1]/60+dms[2]/3600;
break;
case2://interpret2-partresultasd/m
vardeg=dms[0]/1+dms[1]/60;
break;
case1://justd(possiblydecimal)ornon-separateddddmmss
vardeg=dms[0];
//checkforfixed-widthunseparatedformateg0033709W
//if(/[NS]/i.test(dmsStr))deg='0'+deg;//-normaliseN/Sto3-digitdegrees
//if(/[0-9]{7}/.test(deg))deg=deg.slice(0,3)/1+deg.slice(3,5)/60+deg.slice(5)/3600;
break;
default:
returnNaN;
}
if(/^-|[WS]$/i.test(dmsStr.trim()))deg=-deg;//take'-',westandsouthas-ve
returnNumber(deg);
}
/**
*Convertdecimaldegreestodeg/min/secformat
*-degree,prime,double-primesymbolsareadded,butsignisdiscarded,thoughnocompass
*directionisadded
*
*@private
*@param{Number}deg:Degrees
*@param{String}[format=dms]:Returnvalueas'd','dm','dms'
*@param{Number}[dp=0|2|4]:Noofdecimalplacestouse-default0fordms,2fordm,4ford
*@returns{String}degformattedasdeg/min/secsaccordingtospecifiedformat
*@throws{TypeError}degisanobject,perhapsDOMobjectwithout.value?
*/
Geo.toDMS=function(deg,format,dp){
if(typeofdeg=='object')thrownewTypeError('Geo.toDMS-degis[DOM?]object');
if(isNaN(deg))return'NaN';//giveuphereifwecan'tmakeanumberfromdeg
//defaultvalues
if(typeofformat=='undefined')format='dms';
if(typeofdp=='undefined'){
switch(format){
case'd':dp=4;break;
case'dm':dp=2;break;
case'dms':dp=0;break;
default:format='dms';dp=0;//beforgivingoninvalidformat
}
}
deg=Math.abs(deg);//(unsignedresultreadyforappendingcompassdir'n)
switch(format){
case'd':
d=deg.toFixed(dp);//rounddegrees
if(d<100)d='0'+d;//padwithleadingzeros
if(d<10)d='0'+d;
dms=d+'\u00B0';//addºsymbol
break;
case'dm':
varmin=(deg*60).toFixed(dp);//convertdegreestominutes&round
vard=Math.floor(min/60);//getcomponentdeg/min
varm=(min%60).toFixed(dp);//padwithtrailingzeros
if(d<100)d='0'+d;//padwithleadingzeros
if(d<10)d='0'+d;
if(m<10)m='0'+m;
dms=d+'\u00B0'+m+'\u2032';//addº,'symbols
break;
case'dms':
varsec=(deg*3600).toFixed(dp);//convertdegreestoseconds&round
vard=Math.floor(sec/3600);//getcomponentdeg/min/sec
varm=Math.floor(sec/60)%60;
vars=(sec%60).toFixed(dp);//padwithtrailingzeros
if(d<100)d='0'+d;//padwithleadingzeros
if(d<10)d='0'+d;
if(m<10)m='0'+m;
if(s<10)s='0'+s;
dms=d+'\u00B0'+m+'\u2032'+s+'\u2033';//addº,',"symbols
break;
}
returndms;
}
/**
*Convertnumericdegreestodeg/min/seclatitude(suffixedwithN/S)
*
*@param{Number}deg:Degrees
*@param{String}[format=dms]:Returnvalueas'd','dm','dms'
*@param{Number}[dp=0|2|4]:Noofdecimalplacestouse-default0fordms,2fordm,4ford
*@returns{String}Deg/min/seconds
*/
Geo.toLat=function(deg,format,dp){
varlat=Geo.toDMS(deg,format,dp);
returnlat==''?'':lat.slice(1)+(deg<0?'S':'N');//knockoffinitial'0'forlat!
}
/**
*Convertnumericdegreestodeg/min/seclongitude(suffixedwithE/W)
*
*@param{Number}deg:Degrees
*@param{String}[format=dms]:Returnvalueas'd','dm','dms'
*@param{Number}[dp=0|2|4]:Noofdecimalplacestouse-default0fordms,2fordm,4ford
*@returns{String}Deg/min/seconds
*/
Geo.toLon=function(deg,format,dp){
varlon=Geo.toDMS(deg,format,dp);
returnlon==''?'':lon+(deg<0?'W':'E');
}
/**
*Convertnumericdegreestodeg/min/secasabearing(0º..360º)
*
*@param{Number}deg:Degrees
*@param{String}[format=dms]:Returnvalueas'd','dm','dms'
*@param{Number}[dp=0|2|4]:Noofdecimalplacestouse-default0fordms,2fordm,4ford
*@returns{String}Deg/min/seconds
*/
Geo.toBrng=function(deg,format,dp){
deg=(Number(deg)+360)%360;//normalise-vevaluesto180º..360º
varbrng=Geo.toDMS(deg,format,dp);
returnbrng.replace('360','0');//justincaseroundingtookusupto360º!
}
/*-----------------------------------------------*/
综合可参考资料:
相关文章推荐
- 计算地球上两个坐标点(经度,纬度)之间距离sql函数
- 计算地球上两个坐标点(经度,纬度)之间距离sql函数
- 根据2个经纬度点,计算这2个经纬度点之间的距离(通过经度纬度得到距离)
- 根据2个经纬度点,计算这2个经纬度点之间的距离(通过经度纬度得到距离)
- 计算地球上两个坐标点(经度,纬度)之间距离sql函数
- Go语言计算两个经度和纬度之间距离的方法
- php计算两个坐标(经度,纬度)之间距离的方法
- 计算地球上两个坐标点(经度,纬度)之间距离sql函数
- java 计算经度纬度之间的距离
- 已知两点的经度和纬度,计算两点间的距离(php,javascript)
- 根据2个经纬度点,计算这2个经纬度点之间的距离(通过经度纬度得到距离)
- 根据2个经纬度点,计算这2个经纬度点之间的距离(通过经度纬度得到距离)
- 计算地图上两坐标点之间的距离
- 已知两点的经度、纬度,计算两点的距离
- 计算地图上两坐标点之间的距离
- java通过经纬度计算两个点的之间的距离的算法
- 地图上(百度地图)获取两个坐标之间的直线距离
- C语言实验:已知地球上两点的经度和纬度求其球面距离
- Java---(SpringBlade框架)后台从数据库读取所有点的经度和纬度,传输到前端显示在地图上
- JavaScript 实现的根据经纬度计算地球上两点之间的距离