地图经纬度与地图切片像素坐标换算类
地图经纬度与地图切片像素坐标换算类
具体代码如下
/*** 高德地图栅格切片经纬度转换工具类** @author houxg* @Description 地图栅格切片经纬度工具类,适用于高德,Google Map,OSM* @date 2025/7/20 12:05**/
public class MapTileLnglatTransform {/** Created by CntChen 2016.04.30* 参考资料:http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames* 适用地图:高德,Google Map,OSM*///最大最小地图层级double levelMax;double levelMin;public double Math_sinh(double x) {return (Math.exp(x) - Math.exp(-x)) / 2;}/*** 构造函数** @param levelRange_max 最大地图层级* @param LevelRange_min 最小地图层级*/public MapTileLnglatTransform(double levelRange_max, double LevelRange_min) {this.levelMax = levelRange_max;this.levelMin = LevelRange_min;}/** 某一瓦片等级下瓦片地图X轴(Y轴)上的瓦片数目*/public double getMapSize(double level) {return Math.pow(2, level);}/** 分辨率,表示水平方向上一个像素点代表的真实距离(m)*/public double getResolution(double latitude, double level) {double resolution = 6378137.0 * 2 * Math.PI * Math.cos(latitude) / 256 / this.getMapSize(level);return resolution;}/** 经度转瓦片X坐标* @param longitude 经度* @param level 缩放级别 **/public double lngToTileX(double longitude, double level) {double x = (longitude + 180) / 360;double tileX = Math.floor(x * this.getMapSize(level));/*** 限定边界值, 解决 longitude=180 时边界值错误* latitude 应该没问题, 因为 latitude 不会取到 90/-90*/tileX = Math.min(tileX, Math.pow(2, level) - 1);return tileX;}/*** 纬度转瓦片Y** @param latitude 纬度* @param level 地图级别* @return 瓦片Y*/public double latToTileY(double latitude, double level) {double lat_rad = latitude * Math.PI / 180;double y = (1 - Math.log(Math.tan(lat_rad) + 1 / Math.cos(lat_rad)) / Math.PI) / 2;double tileY = Math.floor(y * this.getMapSize(level));// 代替性算法,使用了一些三角变化,其实完全等价//let sinLatitude = Math.sin(latitude * Math.PI / 180);//let y = 0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);//let tileY = Math.floor(y * this._getMapSize(level));return tileY;}/** 从经纬度获取某一级别瓦片坐标编号*/public double[] lnglatToTile(double longitude, double latitude, double level) {double tileX = this.lngToTileX(longitude, level);double tileY = this.latToTileY(latitude, level);return new double[]{tileX, tileY};}/** 从经纬度获取某一级别像素坐标编号* @param {double} longitude 经度* @param {double} latitude 纬度* @param {double} level 级别* @return {double} pixelX 切片X坐标编号*/public double lngToPixelX(double longitude, double level) {double x = (longitude + 180) / 360;double pixelX = Math.floor(x * this.getMapSize(level) * 256 % 256);return pixelX;}/*** 经纬度转切片Y坐标编号** @param latitude 纬度* @param level 地图级别* @return pixelY 切片Y坐标编号*/public double latToPixelY(double latitude, double level) {double sinLatitude = Math.sin(latitude * Math.PI / 180);double y = 0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);double pixelY = Math.floor(y * this.getMapSize(level) * 256 % 256);return pixelY;}/** 从经纬度获取点在某一级别瓦片中的像素坐标*/public double[] lnglatToPixel(double longitude, double latitude, double level) {double pixelX = this.lngToPixelX(longitude, level);double pixelY = this.latToPixelY(latitude, level);return new double[]{pixelX, pixelY};}/*** 从像素坐标获取经纬度** @param pixelX 像素坐标X* @param tileX 瓦片坐标X* @param level 瓦片级别* @return 经度*/public double pixelXTolng(double pixelX, double tileX, double level) {double pixelXToTileAddition = pixelX / 256.0;double longitude = (tileX + pixelXToTileAddition) / this.getMapSize(level) * 360 - 180;return longitude;}/*** 瓦片像素坐标Y转纬度** @param pixelY 瓦片像素坐标Y* @param tileY 瓦片坐标Y* @param level 瓦片级别* @return 纬度*/public double pixelYToLat(double pixelY, double tileY, double level) {double pixelYToTileAddition = pixelY / 256.0;double latitude = Math.atan(Math_sinh(Math.PI * (1 - 2 * (tileY + pixelYToTileAddition) / this.getMapSize(level)))) * 180.0 / Math.PI;return latitude;}/** 从某一瓦片的某一像素点到经纬度*//*** 从某一瓦片的某一像素点到经纬度** @param pixelX 瓦片内像素点X坐标* @param pixelY 瓦片内像素点Y坐标* @param tileX 瓦片X坐标* @param tileY 瓦片Y坐标* @param level 瓦片等级* @return [经度, 纬度]*/public double[] pixelToLnglat(double pixelX, double pixelY, double tileX, double tileY, double level) {double lng = this.pixelXTolng(pixelX, tileX, level);double lat = this.pixelYToLat(pixelY, tileY, level);return new double[]{lng, lat};}/*** 测试类** @param args*/public static void main(String[] args) {System.out.println("请输入经纬度,测试开始");if (args.length < 2) {System.out.println("请输入经纬度");return;}double longitude = Double.parseDouble(args[0]);double latitude = Double.parseDouble(args[1]);int zoomIndex = 17;MapTileLnglatTransform mapTransformUtil = new MapTileLnglatTransform(18, 3);double[] tile = mapTransformUtil.lnglatToTile(longitude, latitude, zoomIndex);System.out.printf("longitude:%s,latitude:%s,zoom:%s---", longitude, latitude, zoomIndex);System.out.println("result:");System.out.printf("tileX:%s,tileY:%s---", tile[0], tile[1]);System.out.println("请输入经纬度,测试完成");}}