【GeoTools】shp文件坐标转换

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wk1134314305/article/details/77918445

前言:GeoTools是一个开源的GIS开发工具,可以用来arcsde的开发,gis相关的文件转换读写,JTS等空间计算方法。

GeoTools is an open source (LGPL) Java code library which provides standards compliant methods for the manipulation of geospatial data, for example to implement Geographic Information Systems (GIS). The GeoTools library implements Open Geospatial Consortium (OGC) specifications as they are developed.
其主要功能如下:
http://docs.geotools.org/stable/userguide/

GeoTools官网:
http://geotools.org/

本文主要介绍怎么对shp文件读写和坐标转换,而且本文主要介绍的是对线、点的shp文件转换(坐标转换)。

因为笔者拿到的数据是WGS84坐标系下的数据,因此需要对数据进行转换,而我们国家的电子地图大多都是GCJ02(该坐标系经过了国测局某种加密算法进行计算的),因此会出现一定程度的偏差。像现在有开源的地图OSM,他们提供的数据是WGS84坐标系下的数据。因此我们需要转换坐标系才可以将数据展示在国内的地图厂商的电子地图上。那么怎么转换这种数据呢?

代码如下:

ReadFile.java

package com.kingwang.transfer;

import java.io.File;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFinder;
import org.geotools.data.FeatureSource;
import org.geotools.data.FeatureWriter;
import org.geotools.data.FileDataStoreFactorySpi;
import org.geotools.data.Transaction;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.Point;

public class ReadFile {
    //转换线,多线和点shp文件(只是转换shp中的坐标,由WGS84坐标转换为火星坐标系)
    public static void tranferWGS84toMars(String srcshppath,String destshppath) throws Exception{
        File file = new File(srcshppath);
        Map<String, Object> map = new HashMap<>();
        map.put("url", file.toURI().toURL());

        DataStore srcdata = DataStoreFinder.getDataStore(map);
        ((ShapefileDataStore) srcdata).setCharset(Charset.forName("GBK"));//国内的计算机默认编码格式为GBK,所以如果不进行设置的话,就会出现乱码的现象
        String typeName = srcdata.getTypeNames()[0];

        FeatureSource<SimpleFeatureType, SimpleFeature> source = srcdata
                .getFeatureSource(typeName);
        Filter filter = Filter.INCLUDE; // ECQL.toFilter("BBOX(THE_GEOM, 10,20,30,40)")

        FeatureCollection<SimpleFeatureType, SimpleFeature> collection = source.getFeatures(filter);
      //创建目标shape文件对象  
        Map<String, Serializable> params = new HashMap<String, Serializable>();  
        FileDataStoreFactorySpi factory = new ShapefileDataStoreFactory();  
        params.put(ShapefileDataStoreFactory.URLP.key, new File(destshppath).toURI().toURL());  
        ShapefileDataStore ds = (ShapefileDataStore) factory.createNewDataStore(params);  
        ((ShapefileDataStore) ds).setCharset(Charset.forName("GBK"));
        // 设置属性  
        SimpleFeatureSource fs = srcdata.getFeatureSource(srcdata.getTypeNames()[0]);  
        //下面这行还有其他写法,根据源shape文件的simpleFeatureType可以不用retype,而直接用fs.getSchema设置  
        ds.createSchema(SimpleFeatureTypeBuilder.retype(fs.getSchema(), DefaultGeographicCRS.WGS84));  

        //设置writer  
        FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);
        try (FeatureIterator<SimpleFeature> features = collection.features()) {
            while (features.hasNext()) {
                SimpleFeature feature = features.next();
                List<Object> list=feature.getAttributes();
                Object obj=list.get(0);
                if(obj instanceof LineString||obj instanceof MultiLineString){
                    Geometry line=((Geometry) obj);
                    int parts=line.getNumGeometries();
                    for(int i=0;i<parts;i++){
                        LineString l=(LineString)line.getGeometryN(i);
                        for(int j=0,num=l.getNumPoints();j<num;j++){
                            Coordinate coor=l.getCoordinateN(j);
                            double[] xy=WGS_Encrypt.WGS2Mars(coor.y,coor.x);
                            Coordinate newcoor=new Coordinate(xy[1],xy[0]);
                            coor.setCoordinate(newcoor);
                        }
                    }
                }else if(obj instanceof Point){
                    Point pt=(Point)obj;
                    Coordinate coor=pt.getCoordinate();
                    double[] xy=WGS_Encrypt.WGS2Mars(coor.y,coor.x);
                    coor.setCoordinate(new Coordinate(xy[1], xy[0]));
                }
                SimpleFeature fNew = writer.next();
                fNew.setAttributes(feature.getAttributes());  
                writer.write();
            }
        }
        writer.close();
        ds.dispose();  
        srcdata.dispose(); 
    }

    public static void main(String[] args) throws Exception {
        tranferWGS84toMars("C:\\Users\\KingWang\\Desktop\\最新数据\\空间数据\\道路.shp","C:\\Users\\KingWang\\Desktop\\dest\\道路.shp");
        tranferWGS84toMars("C:\\Users\\KingWang\\Desktop\\最新数据\\空间数据\\路段.shp","C:\\Users\\KingWang\\Desktop\\dest\\路段.shp");
        tranferWGS84toMars("C:\\Users\\KingWang\\Desktop\\最新数据\\空间数据\\路口.shp","C:\\Users\\KingWang\\Desktop\\dest\\路口.shp");
    }
}

各种坐标系的转换:

WGS_Encrypt.java

package com.kingwang.transfer;

public class WGS_Encrypt {
    private static double pi = 3.14159265358979324;
    private static double a = 6378245.0;
    private static double ee = 0.00669342162296594323;
    private static double x_pi = 3.14159265358979324 * 3000.0 / 180.0;

    public static  Boolean outofChina(double lat, double lon)
    {
        if (lon < 72.004 || lon > 137.8374)
            return true;
        if (lat < 0.8293 || lat > 55.8271)
            return true;
        return false;
    }

    private static double transformLat(double x, double y)
    {
        double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
        return ret;
    }

    private static double transformLon(double x, double y)
    {
        double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0;
        return ret;  
    }

    /// <summary>
    /// 地球坐标转换为火星坐标(GCJ02)
    /// </summary>
    /// <param name="wglat">地球纬度坐标</param>30 y
    /// <param name="wglon">地球经度坐标</param>114 x
    /// <param name="mglat">火星纬度坐标</param>
    /// <param name="mglon">火星经度坐标</param>
    public static double[]  WGS2Mars(double wgLat, double wgLon)
    {
        double[] result= new double[2];
        double mgLat=0;
        double mgLon=0;
        if (outofChina(wgLat, wgLon))
        {
            mgLat = wgLat;
            mgLon = wgLon;
            return result;
        }
        double dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
        double dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
        double radLat = wgLat / 180.0 * pi;
        double magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        double sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
        dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
        mgLat = wgLat + dLat;
        mgLon = wgLon + dLon;

        result[0]=mgLat;
        result[1]=mgLon;
        return result;
    }

    /// <summary>
    /// 火星坐标(GCJ02)转换为百度坐标(BD09)
    /// </summary>
    /// <param name="mg_Lat">火星纬度坐标</param>
    /// <param name="mg_lon">火星经度坐标</param>
    /// <param name="bd_Lat">百度纬度坐标</param>
    /// <param name="bd_Lon">百度经度坐标</param>
    public static double[] Mars2BD(double mg_Lat, double mg_lon)
    {
        double[] result= new double[2];
        double bd_Lat;
        double bd_Lon;
        double x = mg_lon, y = mg_Lat;
        double z = Math.sqrt(x*x + y*y) + 0.00002*Math.sin(y*x_pi);
        double theta = Math.atan2(y, x) + 0.000003*Math.cos(x*x_pi);
        bd_Lon = z*Math.cos(theta) + 0.0065;
        bd_Lat = z*Math.sin(theta) + 0.006;

        result[0]=bd_Lat;
        result[1]=bd_Lon;
        return result;
    }

    /// <summary>
    /// 火星坐标转为WGS84坐标
    /// </summary>
    /// <param name="gcj_Lon">火星坐标经度</param>
    /// <param name="gcj_Lat">火星坐标纬度</param>
    /// <param name="wgs_Lon">WGS经度</param>
    /// <param name="wgs_Lat">WGS纬度</param>
    public static double[]  GCJ2WGS(double gcj_Lat, double gcj_Lon)
    {
        double[] result= new double[2];
        double wgs_Lon;
        double wgs_Lat;
        double inter_Lon;
        double inter_Lat;
        double[] inters=WGS2Mars(gcj_Lat,gcj_Lon);
        inter_Lat=inters[0];
        inter_Lon=inters[1];
        wgs_Lon = gcj_Lon*2 - inter_Lon;
        wgs_Lat = gcj_Lat*2 - inter_Lat;
        result[0]=wgs_Lat;
        result[1]=wgs_Lon;
        return result;
    }

    /// <summary>
    /// 地球坐标转换为百度坐标(BD09)
    /// </summary>
    /// <param name="wg_lat">地球纬度坐标</param>
    /// <param name="wg_lon">地球经度坐标</param>
    /// <param name="bd_lat">百度纬度坐标</param>
    /// <param name="bd_lon">百度经度坐标</param>
    public static double[] WGS2BD(double wg_lat, double wg_lon)
    {
        double[] result= new double[2];
        double[] mgs=WGS2Mars(wg_lat, wg_lon);
        double[] bds=Mars2BD(mgs[0], mgs[1]);
        result[0]=bds[0];
        result[1]=bds[1];
        return result;
    }

    /// <summary>
    /// 百度坐标转为火星坐标
    /// </summary>
    /// <param name="bd_lat"></param>
    /// <param name="bd_lon"></param>
    /// <param name="mg_lat"></param>
    /// <param name="mg_lon"></param>
    public static double[] BD2Mars(double bd_lat, double bd_lon)
    {
        double[] result= new double[2];
        double x = bd_lon - 0.0065, y = bd_lat - 0.006;
        double z = Math.sqrt(x*x + y*y) - 0.00002*Math.sin(y*x_pi);
        double theta = Math.atan2(y, x) - 0.000003*Math.cos(x*x_pi);
        double mg_lon = z*Math.cos(theta);
        double mg_lat = z*Math.sin(theta);
        result[0]=mg_lat;
        result[1]=mg_lon;
        return result;
    }
}

猜你喜欢

转载自blog.csdn.net/wk1134314305/article/details/77918445