Java各坐标系之间的转换(高斯、WGS84经纬度、Web墨卡托、瓦片坐标)

本文整理了一些地理坐标系之间的转换(Java代码)

pom依赖

        <dependency>
            <groupId>com.vividsolutions</groupId>
            <artifactId>jts</artifactId>
            <version>1.13</version>
        </dependency>

        <dependency>
            <groupId>org.osgeo</groupId>
            <artifactId>proj4j</artifactId>
            <version>0.1.0</version>
        </dependency>

坐标转换工具类

package com.mytest.algorithm.geometry;

import com.mytest.algorithm.model.Pixel;
import com.mytest.algorithm.model.Tile;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import org.osgeo.proj4j.BasicCoordinateTransform;
import org.osgeo.proj4j.CRSFactory;
import org.osgeo.proj4j.CoordinateReferenceSystem;
import org.osgeo.proj4j.ProjCoordinate;

/*************************************
 *Class Name:GeoTransform
 *Description:<坐标转换工具类>
 *@since 1.0.0
 *************************************/
public class GeoTransform {
    /**
     * 赤道半径
     */
    private final static double EarthRadius = 6378137.0;
    /**
     * 地球周长
     */
    private final static double EarthPerimeter = 2 * Math.PI * EarthRadius;
    /**
     * 瓦片大小,默认256
     */
    private final static int tileSize = 256;
    /**
     * 初始像素分辨率.
     */
    private final static double initialResolution = EarthPerimeter / tileSize;
    /**
     * 坐标原点
     */
    private final static Coordinate origin = new Coordinate(-EarthPerimeter / 2.0, EarthPerimeter / 2.0);

    private final static BasicCoordinateTransform transform1;
    private final static BasicCoordinateTransform transform2;
    private final static CRSFactory crsFactory = new CRSFactory();
    private final static CoordinateReferenceSystem WGS84CRS = crsFactory.createFromName("EPSG:4326");
    private final static CoordinateReferenceSystem WebMercatorCRS = crsFactory.createFromName("EPSG:3857");

    static {
        transform1 = new BasicCoordinateTransform(WGS84CRS, WebMercatorCRS);
        transform2 = new BasicCoordinateTransform(WebMercatorCRS, WGS84CRS);
    }

    /**
     * 缩放级别换算地图分辨率
     *
     * @param zoom 级别
     */
    public double zoomToResolution(int zoom) {
        return initialResolution / Math.pow(2, zoom);
    }

    /**
     * 经纬度转墨卡托
     *
     * @param pt 经纬度坐标
     * @return 墨卡托坐标
     */
    public Coordinate geographic2Mercator(Coordinate pt) {

        synchronized (transform1) {
            ProjCoordinate pt1 = new ProjCoordinate(pt.x, pt.y);
            ProjCoordinate pt2 = new ProjCoordinate();
            transform1.transform(pt1, pt2);
            return new Coordinate(pt2.x, pt2.y);
        }
    }

    /**
     * 墨卡托转经纬度
     *
     * @param pt 墨卡托坐标
     * @return 经纬度坐标
     */
    public Coordinate mercator2Geographic(Coordinate pt) {

        synchronized (transform2) {
            ProjCoordinate pt1 = new ProjCoordinate(pt.x, pt.y);
            ProjCoordinate pt2 = new ProjCoordinate();
            transform2.transform(pt1, pt2);
            return new Coordinate(pt2.x, pt2.y);
        }
    }

    /**
     * 高斯转经纬度
     *
     * @param pt 高斯坐标
     * @param d  度带号(3度带)
     * @return 经纬度坐标
     */
    public Coordinate gk2Geographic(Coordinate pt, int d) {
        synchronized (crsFactory) {
            CoordinateReferenceSystem GKCRS = crsFactory.createFromParameters("WGS84", String.format("+proj=tmerc +lat_0=0 +lon_0=%d +k=1 +x_0=500000 +y_0=0 +ellps=WGS84 +units=m +no_defs", d * 3));
            BasicCoordinateTransform transform = new BasicCoordinateTransform(GKCRS, WGS84CRS);
            ProjCoordinate pt1 = new ProjCoordinate(pt.x, pt.y);
            ProjCoordinate pt2 = new ProjCoordinate();
            transform.transform(pt1, pt2);
            return new Coordinate(pt2.x, pt2.y);
        }
    }

    /**
     * 经纬度转高斯
     *
     * @param pt 经纬度坐标
     * @return 高斯坐标
     */
    public Coordinate geographic2GK(Coordinate pt) {
        synchronized (crsFactory) {
            int d = (int) Math.floor((pt.y + 1.5) / 3);
            CoordinateReferenceSystem GKCRS = crsFactory.createFromParameters("WGS84", String.format("+proj=tmerc +lat_0=0 +lon_0=%d +k=1 +x_0=500000 +y_0=0 +ellps=WGS84 +units=m +no_defs", d * 3));
            BasicCoordinateTransform transform = new BasicCoordinateTransform(WGS84CRS, GKCRS);
            ProjCoordinate pt1 = new ProjCoordinate(pt.x, pt.y);
            ProjCoordinate pt2 = new ProjCoordinate();
            transform.transform(pt1, pt2);
            return new Coordinate(pt2.x, pt2.y);
        }
    }

    /**
     * 高斯转web墨卡托
     *
     * @param pt 高斯坐标
     * @param d  度带好(3度带)
     * @return 墨卡托坐标
     */
    public Coordinate gk2Mercator(Coordinate pt, int d) {
        synchronized (crsFactory) {
            CoordinateReferenceSystem GKCRS = crsFactory.createFromParameters("WGS84", String.format("+proj=tmerc +lat_0=0 +lon_0=%d +k=1 +x_0=500000 +y_0=0 +ellps=WGS84 +units=m +no_defs", d * 3));
            BasicCoordinateTransform transform = new BasicCoordinateTransform(GKCRS, WebMercatorCRS);
            ProjCoordinate pt1 = new ProjCoordinate(pt.x, pt.y);
            ProjCoordinate pt2 = new ProjCoordinate();
            transform.transform(pt1, pt2);
            return new Coordinate(pt2.x, pt2.y);
        }
    }

    /**
     * 墨卡托转像素
     *
     * @param pt   墨卡托坐标
     * @param zoom 缩放级别
     * @return 像素坐标
     */
    public Pixel mercator2Pixel(Coordinate pt, int zoom) {
        double res = zoomToResolution(zoom);
        Double px = (pt.x - origin.x) / res;
        Double py = -(pt.y - origin.y) / res;
        //System.out.println(px+","+py);
        //fixme 精度向下取整
        return new Pixel((long) Math.floor(px), (long) Math.floor(py));
    }

    /**
     * 像素转墨卡托
     *
     * @param pixel 像素坐标
     * @param zoom  缩放级别
     * @return 墨卡托坐标
     */
    public Coordinate pixel2Mercator(Pixel pixel, int zoom) {
        double res = zoomToResolution(zoom);
        double x = pixel.getX() * res + origin.x;
        double y = origin.y - pixel.getY() * res;
        return new Coordinate(x, y);
    }

    /**
     * 像素坐标所在瓦片
     *
     * @param pixel 像素坐标
     * @return 瓦片坐标
     */
    public Tile pixelAtTile(Pixel pixel) {
        long tileX = pixel.getX() / tileSize;
        long tileY = pixel.getY() / tileSize;
        return new Tile(tileX, tileY);
    }

    /**
     * 像素转瓦片内像素
     *
     * @param pixel 像素坐标
     * @param tile  瓦片坐标
     * @return 瓦片内像素坐标
     */
    public Pixel pixel2Tile(Pixel pixel, Tile tile) {
        long pX = pixel.getX() - tile.getX() * tileSize;
        long pY = pixel.getY() - tile.getY() * tileSize;
        return new Pixel(pX, pY);
    }

    /**
     * 瓦片内像素转像素
     *
     * @param p    瓦片内像素坐标
     * @param tile 瓦片坐标
     * @return 像素坐标
     */
    public Pixel tile2Pixel(Pixel p, Tile tile) {
        long pixelX = p.getX() + tile.getX() * tileSize;
        long pixelY = p.getY() + tile.getY() * tileSize;
        return new Pixel(pixelX, pixelY);
    }

    /**
     * 墨卡托转瓦片内像素
     *
     * @param pt   墨卡托坐标
     * @param tile 瓦片坐标
     * @param zoom 缩放级别
     * @return 瓦片内像素坐标
     */
    public Pixel mercator2Tile(Coordinate pt, Tile tile, int zoom) {
        Pixel p = mercator2Pixel(pt, zoom);
        Pixel pixel = pixel2Tile(p, tile);
        return pixel;
    }

    /**
     * 经纬度转像素
     *
     * @param pt   经纬度坐标
     * @param zoom 缩放级别
     * @return 像素坐标
     */
    public Pixel geographic2Pixel(Coordinate pt, int zoom) {
        Coordinate mpt = geographic2Mercator(pt);
        Pixel pixel = mercator2Pixel(mpt, zoom);
        return pixel;
    }

    /**
     * 经纬度转瓦片内像素
     *
     * @param pt   经纬度坐标
     * @param tile 瓦片坐标
     * @param zoom 缩放级别
     * @return 瓦片内像素坐标
     */
    public Pixel geographic2Tile(Coordinate pt, Tile tile, int zoom) {
        Pixel pixel = geographic2Pixel(pt, zoom);
        Pixel p = this.pixel2Tile(pixel, tile);
        return p;
    }

    /**
     * 像素转经纬度
     *
     * @param pixel 像素坐标
     * @param zoom  缩放级别
     * @return 经纬度坐标
     */
    public Coordinate pixel2Geographic(Pixel pixel, int zoom) {
        Coordinate mpt = pixel2Mercator(pixel, zoom);
        Coordinate lonlat = this.mercator2Geographic(mpt);
        return lonlat;
    }

    /**
     * Tile坐标转换为所在的Tile的矩形
     *
     * @param tile 瓦片坐标
     * @return 矩形
     */
    public Envelope tile2Envelope(Tile tile) {
        long px = tile.getX() * tileSize;
        long py = tile.getY() * tileSize;
        Pixel pixel1 = new Pixel(px, py + 256);//左下
        Pixel pixel2 = new Pixel(px + 256, py);//右上
        Coordinate sw = pixel2Geographic(pixel1, tile.getZ());
        Coordinate ne = pixel2Geographic(pixel2, tile.getZ());
        return new Envelope(sw, ne);
    }

    /**
     * 瓦片坐标转换为QuadKey四叉树键值
     *
     * @param tile 瓦片坐标
     * @return String QuadKey四叉树键值
     */
    public String tile2QuadKey(Tile tile) {
        long tileX = tile.getX();
        long tileY = tile.getY();
        StringBuilder quadKey = new StringBuilder();
        for (int i = tile.getZ(); i > 0; i--) {
            char digit = '0';
            int mask = 1 << (i - 1);
            if ((tileX & mask) != 0) {
                digit++;
            }
            if ((tileY & mask) != 0) {
                digit++;
                digit++;
            }
            quadKey.append(digit);
        }
        return quadKey.toString();
    }

    /**
     * QuadKey四叉树键值转换为瓦片坐标
     *
     * @param quadKey QuadKey四叉树键值
     * @return 瓦片坐标
     */
    public Tile quadKey2Tile(String quadKey) {
        long tileX = 0;
        long tileY = 0;
        int levelOfDetail = quadKey.length();

        for (int i = levelOfDetail; i > 0; i--) {
            int mask = 1 << (i - 1);
            switch (quadKey.charAt(levelOfDetail - i)) {
                case '0':
                    break;
                case '1':
                    tileX |= mask;
                    break;
                case '2':
                    tileY |= mask;
                    break;
                case '3':
                    tileX |= mask;
                    tileY |= mask;
                    break;

                //default:throw new ArgumentException("Invalid QuadKey digit sequence.");
            }
        }
        return new Tile(tileX, tileY, levelOfDetail);
    }

}

Pixel类

import lombok.Data;

/**
 *
 * 屏幕像素坐标类,该类为基础类(单位:像素)。
 * 像素坐标系(Pixel Coordinates)单位。
 * 以左上角为原点(0,0),向右向下为正方向。
 * @version	1.0
 * @author 
 */
@Data
public class Pixel {
    /**
     * 横向像素
     */
    long x;
    /**
     * 纵向像素
     */
    long y;

    /**
     * 根据给定参数构造Pixel的新实例
     * @param x 横向像素
     * @param y 纵向像素
     */
    public Pixel(long x, long y){
        this.x=x;
        this.y=y;
    }
}

Tile类

import lombok.Getter;
import lombok.Setter;

/**
 *
 * 瓦片类,该类为基础类(单位:块)。
 * 地图瓦片坐标系(Tile Coordinates)单位。
 * 瓦片坐标系以左上角为原点(0, 0),到右下角(2 ^ 图像级别 - 1, 2 ^ 图像级别 - 1)为止。
 * @version	1.0
 * @author 
 */
@Getter
@Setter
public class Tile{
    /**
     * 横向瓦片数
     */
    long x;
    /**
     * 纵向瓦片数
     */
    long y;
    /**
     * 级别
     */
    int z;

    public Tile(){
    }

    /**
     * 根据给定参数构造Tile的新实例
     * @param x 横向瓦片数
     * @param y 纵向瓦片数
     */
    public Tile(long x, long y){
        this.x=x;
        this.y=y;
    }
    /**
     * 根据给定参数构造Tile的新实例
     * @param x 横向瓦片数
     * @param y 纵向瓦片数
     * @param z 级别
     */
    public Tile(long x, long y, int z){
        this.x=x;
        this.y=y;
        this.z=z;
    }

    @Override
    public String toString(){
        return "Tile("+x+","+y+","+z+")";
    }
}

over!

  • 9
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
WSG84(World Geodetic System 1984)和CGCS2000(中国大地坐标系统2000)是两种常用的地理坐标系。在Java中将WSG84转换为CGCS2000可以通过使用坐标转换库来实现。 首先,我们需要确定所使用的坐标转换库。Java中有许多开源的坐标转换库可以使用,例如Geotools和Proj4j。这里以使用Geotools为例进行说明。 在使用Geotools进行坐标转换之前,我们需要先导入相关的库文件。可以在Maven项目中的pom.xml文件中添加以下依赖项: ```xml <dependency> <groupId>org.geotools</groupId> <artifactId>gt-epsg-hsql</artifactId> <version>24.1</version> </dependency> ``` 接下来,我们可以使用以下代码将WSG84坐标转换为CGCS2000坐标: ```java import org.geotools.geometry.DirectPosition2D; import org.geotools.referencing.CRS; import org.opengis.referencing.FactoryException; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.crs.CoordinateReferenceSystem; public class CoordinateConversion { public static void main(String[] args) { // 输入的坐标点(WSG84) double longitude = 116.3975; double latitude = 39.9085; // 设置源坐标系(WSG84) CoordinateReferenceSystem sourceCRS; try { sourceCRS = CRS.decode("EPSG:4326"); } catch (NoSuchAuthorityCodeException | FactoryException e) { e.printStackTrace(); return; } // 设置目标坐标系(CGCS2000) CoordinateReferenceSystem targetCRS; try { targetCRS = CRS.decode("EPSG:4490"); } catch (NoSuchAuthorityCodeException | FactoryException e) { e.printStackTrace(); return; } // 创建源坐标点 DirectPosition2D sourcePosition = new DirectPosition2D(sourceCRS, longitude, latitude); // 坐标转换 try { DirectPosition2D targetPosition = (DirectPosition2D) CRS.transform(sourcePosition, targetCRS); double targetLongitude = targetPosition.x; double targetLatitude = targetPosition.y; System.out.println("转换后的坐标(CGCS2000):"); System.out.println("经度:" + targetLongitude); System.out.println("纬度:" + targetLatitude); } catch (Exception e) { e.printStackTrace(); } } } ``` 上述代码中,首先设置源坐标系为WSG84(EPSG:4326)和目标坐标系为CGCS2000(EPSG:4490),然后创建源坐标点并利用`CRS.transform()`方法进行坐标转换。 运行上述代码后,将输出转换后的CGCS2000坐标,包括经度和纬度。 需要注意的是,WSG84和CGCS2000的坐标系定义可能因使用的地理坐标转换库而有所不同,可以根据实际情况进行相应的调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值