偷懒了一个月,今天终于重新修改了mapeasy中的球平算法应用。
以前的mapeasy中使用 google map data的例子不能正确使用经纬度,现在终于可以了。
google map api中有个很有用的接口:GProjection,官方对这个接口的解释是:
This is the interface for map projections. A map projection instance is passed to the constructor of
GMapType
. This interface is implemented by the
class GMercatorProjection
, which is used by all predefined map types. You can implement this interface if you want to define map types with different map projections.
这个接口最大的作用,就是允许你使用自己的球平算法去投影地图,其中的fromPixelToLatLng()和fromPixelToLatLng()非常重要,他们表示了从经纬度和pixel之间的转换算法。
google做了一个默认的实现 GMercatorProjection,使用的是麦卡托算法,google map提供的地图数据,就是根据这个算法投影转换而来的。
如果你需要使用自己的投影地图,记得一定要自己实现GProjection接口。
google使用的麦卡托算法很有意思,它并没有把整个地球都投影出来,只能投影纬度在85度内的地图。也就是说,最北极和最南极的那部分(纬度85以上),在google地图中是找不到的:)
你可以运行一下这句代码:
alert(map.getCurrentMapType().getProjection().fromLatLngToPixel(
new
GLatLng(
85
,
0
),map.getZoom()));
你会发现,对应的Y坐标就是0了:)
如果运行:
alert(map.getCurrentMapType().getProjection().fromLatLngToPixel(
new
GLatLng(
90
,
0
),map.getZoom()));
那么,Y坐标将为负数:)
如果你只是希望使用google实现好的麦卡托算法,你还可以直接绕过GMap类,直接使用GMercatorProjection类:
var zoom=17;
var latLan=new GLatLng(85,180);
var gm = new GMercatorProjection(zoom + 1 );
var x = gm.fromLatLngToPixel(latLan,zoom).x;
var y = gm.fromLatLngToPixel(latLan,zoom).y;
var latLan=new GLatLng(85,180);
var gm = new GMercatorProjection(zoom + 1 );
var x = gm.fromLatLngToPixel(latLan,zoom).x;
var y = gm.fromLatLngToPixel(latLan,zoom).y;
而后,你就可以把得到的x,y转换成自己应用的坐标系中的坐标。例如,在我的mapeasy中,坐标系范围是x:[-180,180], y:[-90,90],因此我使用如下的代码进行坐标转换:
/**
* @param lat 经度
* @param lan 纬度
* @param zoom 放大比例
*/
function GoogleMapLatLan(lat,lan,zoom){
this .lat = lat;
this .lan = lan;
this .zoom = zoom;
}
GoogleMapLatLan.prototype.fromLatLngToMapEasyPoint = function(){
var latLan = new GLatLng( this .lat, this .lan);
var zoom = this .zoom;
var gm = new GMercatorProjection(zoom + 1 );
// merX,merY:根据google提供的Mercator算法算出来的Pixel的
var merX = gm.fromLatLngToPixel(latLan,zoom).x;
var merY = gm.fromLatLngToPixel(latLan,zoom).y;
// google使用的麦卡托投影法,并没有把整个地球投影出来,只是投影出纬度在85度以内的地球,也就是说,北纬85度的点,就是最北边的点。而最北极和最南极的那部分地图(纬度85以上),在google提供的地图中是找不到的:)
// 在zome=0时,如果地图的左上角的点对应的纬经度为:(85,-180),右下角对应的纬经度为(-85,180),此时,使用google提供的Mercator算法算出来的对应的坐标系 范围为:x[0,256],y[0,256],
// 坐标系的放大倍数
var scale = Math.pow( 2 ,zoom);
var merXMin = 0 ;
var merXMax = 256 * scale;
var merYCenter = 128 * scale;
// meX,meY:MapEasyPoint中的x,y
// MapEasy默认的坐标系范围为x:[-180,180],y:[-90,90],因此需要进行转换
var meX = ((merX - merXMin) - (merXMax - merXMin) / 2 ) * 180 / ((merXMax - merXMin) / 2 );
var meY = (merYCenter - merY) * 90 / merYCenter;
return new Point(meX,meY);
};
GoogleMapLatLan.prototype.getPoint = function(){
return this .fromLatLngToMapEasyPoint();
}
* @param lat 经度
* @param lan 纬度
* @param zoom 放大比例
*/
function GoogleMapLatLan(lat,lan,zoom){
this .lat = lat;
this .lan = lan;
this .zoom = zoom;
}
GoogleMapLatLan.prototype.fromLatLngToMapEasyPoint = function(){
var latLan = new GLatLng( this .lat, this .lan);
var zoom = this .zoom;
var gm = new GMercatorProjection(zoom + 1 );
// merX,merY:根据google提供的Mercator算法算出来的Pixel的
var merX = gm.fromLatLngToPixel(latLan,zoom).x;
var merY = gm.fromLatLngToPixel(latLan,zoom).y;
// google使用的麦卡托投影法,并没有把整个地球投影出来,只是投影出纬度在85度以内的地球,也就是说,北纬85度的点,就是最北边的点。而最北极和最南极的那部分地图(纬度85以上),在google提供的地图中是找不到的:)
// 在zome=0时,如果地图的左上角的点对应的纬经度为:(85,-180),右下角对应的纬经度为(-85,180),此时,使用google提供的Mercator算法算出来的对应的坐标系 范围为:x[0,256],y[0,256],
// 坐标系的放大倍数
var scale = Math.pow( 2 ,zoom);
var merXMin = 0 ;
var merXMax = 256 * scale;
var merYCenter = 128 * scale;
// meX,meY:MapEasyPoint中的x,y
// MapEasy默认的坐标系范围为x:[-180,180],y:[-90,90],因此需要进行转换
var meX = ((merX - merXMin) - (merXMax - merXMin) / 2 ) * 180 / ((merXMax - merXMin) / 2 );
var meY = (merYCenter - merY) * 90 / merYCenter;
return new Point(meX,meY);
};
GoogleMapLatLan.prototype.getPoint = function(){
return this .fromLatLngToMapEasyPoint();
}
这次写这段代码,才发现google中GLatLan类的distanceFrom( other)函数,实现了计算两个经纬坐标间距离(米为单位)的算法,简单试用了一下,还8错。
忘了交代 了,我参考的google map api的版本是maps2.48.api.js
btw:
今天还是偷懒,没有仔细研究GMercatorProjection的实现代码,留给team中有空的伙伴去研究吧。
这儿有个Mercator不错的说明: http://en.wikipedia.org/wiki/Mercator_projection
有兴趣的朋友可以来逛逛 http://mapeasy.sf.net。项目问题还好多,包括javascript的memory leakage至今也还没去解决。项目组的成员最近都好忙,也不知道有没有朋友有兴趣加入的。