Javascript 将给定图片上的长/宽转换为像素x/y
我有一张莫斯科的城市地图。我们用一些艺术元素修改了谷歌地图图像,但GPS坐标和像素之间的关系保持不变 问题:如何将各种数据点的GPS坐标转换为图像中的像素坐标 理想情况下,我可以用Javascript实现这一点,但PHP也可以Javascript 将给定图片上的长/宽转换为像素x/y,javascript,google-maps,coordinates,google-static-maps,Javascript,Google Maps,Coordinates,Google Static Maps,我有一张莫斯科的城市地图。我们用一些艺术元素修改了谷歌地图图像,但GPS坐标和像素之间的关系保持不变 问题:如何将各种数据点的GPS坐标转换为图像中的像素坐标 理想情况下,我可以用Javascript实现这一点,但PHP也可以 我知道在小比例尺上(例如在城市比例尺上),制作简单(有必要了解什么地理坐标有一个图片角,然后分别了解OX和OY轴上图片地理坐标中一个像素的“价格”) 但在大尺度(国家尺度)上,一个像素的“价格”将不是一个常数,并且会有足够大的变化,上述方法无法应用 如何解决国家层面的问
我知道在小比例尺上(例如在城市比例尺上),制作简单(有必要了解什么地理坐标有一个图片角,然后分别了解OX和OY轴上图片地理坐标中一个像素的“价格”) 但在大尺度(国家尺度)上,一个像素的“价格”将不是一个常数,并且会有足够大的变化,上述方法无法应用 如何解决国家层面的问题
更新:
我不使用API谷歌地图,我只有:对象的地理坐标(它们来自谷歌地图),我的网站上还有一张简单的图片*。gif,其中我必须绘制一个与地理坐标相对应的点。如果假设每个像素位于同一区域,那么下面关于将距离转换为经度/纬度坐标的文章可能会对您有所帮助:
您需要公式将纬度和经度转换为直角坐标。有很多选择,每一个都会以不同的方式扭曲地图。Wolfram MathWorld有一个很好的收藏:
按照“另请参阅”链接进行操作。您可能会看到,它是从js移植到python的。您正在处理的转换与此有关,这就是如何将我们世界的球面转换为二维渲染的。有多种方法(投影)可以在二维曲面上渲染世界 如果您的地图只使用特定的投影(很流行),您应该能够找到方程式、一些示例代码和/或一些库(例如,一个墨卡托解-。如果不这样做,我相信您可以找到其他示例-。如果您的图像不是地图使用墨卡托投影,您需要确定它使用什么投影来找到正确的平移方程
如果您试图支持多个地图投影(您希望支持使用不同投影的多个不同地图),那么您肯定想使用类似的库,但我不确定您会在Javascript或PHP中找到什么。所有这些的关键是理解。正如其他人所指出的,造成扭曲的原因是球形(或更准确地说是椭圆形)地球投影到一个平面上的事实 为了实现目标,您首先必须了解有关数据的两件事:
// include the library
<script src="lib/proj4js-combined.js"></script> //adjust the path for your server
//or else use the compressed version
// creating source and destination Proj4js objects
// once initialized, these may be re-used as often as needed
var source = new Proj4js.Proj('EPSG:4326'); //source coordinates will be in Longitude/Latitude, WGS84
var dest = new Proj4js.Proj('EPSG:3785'); //destination coordinates in meters, global spherical mercators projection, see http://spatialreference.org/ref/epsg/3785/
// transforming point coordinates
var p = new Proj4js.Point(-76.0,45.0); //any object will do as long as it has 'x' and 'y' properties
Proj4js.transform(source, dest, p); //do the transformation. x and y are modified in place
//p.x and p.y are now EPSG:3785 in meters
//包含该库
//调整服务器的路径
//或者使用压缩版本
//创建源和目标Proj4js对象
//一旦初始化,它们可以根据需要重复使用
var source=new Proj4js.Proj('EPSG:4326');//源坐标将以经度/纬度WGS84表示
var dest=new Proj4js.Proj('EPSG:3785');//以米为单位的目标坐标,全局球形墨卡托投影,请参见http://spatialreference.org/ref/epsg/3785/
//转换点坐标
var p=new Proj4js.Point(-76.0,45.0);//任何对象只要具有“x”和“y”属性就可以
Proj4js.transform(source,dest,p);//执行转换。x和y被就地修改
//p、 x和p.y现在是EPSG:3785米
那么您想获取纬度/经度坐标,并找出该位置图像上的像素坐标
主GMap2类提供与显示地图上的像素和lat/long坐标之间的转换:
Gmap2.fromLatLngToContainerPixel(latlng)
例如:
var gmap2 = new GMap2(document.getElementById("map_canvas"));
var geocoder = new GClientGeocoder();
geocoder.getLatLng( "1600 Pennsylvania Avenue NW Washington, D.C. 20500",
function( latlng ) {
var pixel_coords = gmap2.fromLatLngToContainerPixel(latlng);
window.alert( "The White House is at pixel coordinates (" +
pixel_coodrs.x + ", " + pixel_coords.y + ") on the " +
"map image shown on this page." );
}
);
因此,假设您的地图图像是Google地图显示的屏幕抓取,那么这将为您提供该图像上正确的像素坐标(lat/long坐标)
如果你抓取瓷砖图像并自己将它们缝合在一起,事情会变得更加棘手,因为整个瓷砖集的区域将位于显示地图的区域之外
在这种情况下,需要使用左上图像平铺的左和顶部值作为从LatlNgtoContainerPixel(latlng:GLatLng)提供给您的坐标的偏移,从x坐标减去左坐标,从y坐标减去顶部坐标
GMap2.fromLatLngToDivPixel(latlng:GLatLng)
public class GoogleMapsAPIProjection
{
private readonly double PixelTileSize = 256d;
private readonly double DegreesToRadiansRatio = 180d / Math.PI;
private readonly double RadiansToDegreesRatio = Math.PI / 180d;
private readonly PointF PixelGlobeCenter;
private readonly double XPixelsToDegreesRatio;
private readonly double YPixelsToRadiansRatio;
public GoogleMapsAPIProjection(double zoomLevel)
{
var pixelGlobeSize = this.PixelTileSize * Math.Pow(2d, zoomLevel);
this.XPixelsToDegreesRatio = pixelGlobeSize / 360d;
this.YPixelsToRadiansRatio = pixelGlobeSize / (2d * Math.PI);
var halfPixelGlobeSize = Convert.ToSingle(pixelGlobeSize / 2d);
this.PixelGlobeCenter = new PointF(
halfPixelGlobeSize, halfPixelGlobeSize);
}
public PointF FromCoordinatesToPixel(PointF coordinates)
{
var x = Math.Round(this.PixelGlobeCenter.X
+ (coordinates.X * this.XPixelsToDegreesRatio));
var f = Math.Min(
Math.Max(
Math.Sin(coordinates.Y * RadiansToDegreesRatio),
-0.9999d),
0.9999d);
var y = Math.Round(this.PixelGlobeCenter.Y + .5d *
Math.Log((1d + f) / (1d - f)) * -this.YPixelsToRadiansRatio);
return new PointF(Convert.ToSingle(x), Convert.ToSingle(y));
}
public PointF FromPixelToCoordinates(PointF pixel)
{
var longitude = (pixel.X - this.PixelGlobeCenter.X) /
this.XPixelsToDegreesRatio;
var latitude = (2 * Math.Atan(Math.Exp(
(pixel.Y - this.PixelGlobeCenter.Y) / -this.YPixelsToRadiansRatio))
- Math.PI / 2) * DegreesToRadiansRatio;
return new PointF(
Convert.ToSingle(latitude),
Convert.ToSingle(longitude));
}
}
var map = new OpenLayers.Map({
div:"map-id",
allOverlays: true
});
var osm = new OpenLayers.Layer.OSM("OpenStreeMao");
var gmap = new OpenLayers.Layer.Google("Google Streets", {visibility: false});
map.addLayers([osm,gmap]);
var vectorLayer = new OpenLayers.Layer.Vector("IconLayer");
var lonlatObject = new OpenLayers.LonLat(24.938622,60.170421).transform(
new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()
);
console.log(lonlatObject);
var point = new OpenLayers.Geometry.Point(lonlatObject.lon, lonlatObject.lat);
console.log(point);
var point2 = new OpenLayers.Geometry.Point(lonlatObject.x, lonlatObject.y);
console.log(point2);
var feature = new OpenLayers.Feature.Vector(point, null, {
externalGraphic: "http://cdn1.iconfinder.com/data/icons/SUPERVISTA/networking/png/72/antenna.png",
graphicWidth: 72,
graphicHeight: 72,
fillOpacity: 1
});
vectorLayer.addFeatures(feature);
map.addLayer(vectorLayer);
map.setCenter(
new OpenLayers.LonLat(24.938622,60.170421).transform(
new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()
),
12);
map.addControl(new OpenLayers.Control.LayerSwitcher());
// Adapted from : http://blog.cppse.nl/x-y-to-lat-lon-for-google-maps
window.geo = {
glOffset: Math.pow(2,28), //268435456,
glRadius: Math.pow(2,28) / Math.PI,
a: Math.pow(2,28),
b: 85445659.4471,
c: 0.017453292519943,
d: 0.0000006705522537,
e: Math.E, //2.7182818284590452353602875,
p: Math.PI / 180,
lonToX: function(lon) {
return Math.round(this.glOffset + this.glRadius * lon * this.p);
},
XtoLon: function(x) {
return -180 + this.d * x;
},
latToY: function(lat) {
return Math.round(this.glOffset - this.glRadius *
Math.log((1 + Math.sin(lat * this.p)) /
(1 - Math.sin(lat * this.p))) / 2);
},
YtoLat: function(y) {
return Math.asin(Math.pow(this.e,(2*this.a/this.b - 2*y/this.b)) /
(Math.pow(this.e, (2*this.a/this.b - 2*y/this.b))+1) -
1/(Math.pow(this.e, (2*this.a/this.b - 2*y/this.b))+1)
) / this.c;
},
deltaLonPerDeltaX: function(deltaX, zoom) {
// 2^(7+zoom) pixels <---> 180 degrees
return deltaX * 180 / Math.pow(2, 7+zoom);
},
deltaLatPerDeltaY: function(deltaY, zoom, startLat) {
// more complex because of the curvature, we calculte it by difference
var startY = this.latToY(startLat),
endY = startY + deltaY * Math.pow(2, 28-7-zoom),
endLat = this.YtoLat(endY);
return ( endLat - startLat ); // = deltaLat
}
}