TiandituDownload.java 10.1 KB
import utils.*;
import utils.Point;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.*;

public class TiandituDownload {

    // 级别
    int[] level = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};

    // 分辨率
    double[] res4490 = {
            1.40625,
            0.703125,
            0.3515625,
            0.17578125,
            0.087890625,
            0.0439453125,
            0.02197265625,
            0.010986328125,
            0.0054931640625,
            0.00274658203125,
            0.001373291015625,
            0.0006866455078125,
            0.00034332275390625,
            0.000171661376953125,
            8.58306884765629E-05,
            4.29153442382814E-05,
            2.14576721191407E-05,
            1.07288360595703E-05,
            5.36441802978515E-06,
            2.68220901489258E-06,
            1.34110450744629E-06
    };
    // 比例尺
    double[] scale4490 = {
            400000000,
            295497598.5708346,
            147748799.285417,
            73874399.6427087,
            36937199.8213544,
            18468599.9106772,
            9234299.95533859,
            4617149.97766929,
            2308574.98883465,
            1154287.49441732,
            577143.747208662,
            288571.873604331,
            144285.936802165,
            72142.9684010827,
            36071.4842005414,
            18035.7421002707,
            9017.87105013534,
            4508.93552506767,
            2254.467762533835,
            1127.2338812669175,
            563.61694063345875
    };

    double[] scale3857 = {
            295829355.45,
            147914677.73,
            73957338.86,
            36978669.43,
            18489334.72,
            9244667.36,
            4622333.68,
            2311166.84,
            1155583.42,
            577791.71,
            288895.85,
            144447.93,
            72223.96,
            36111.98,
            18055.99,
            9028,
            4514,
            2257};

    double[] res3857 = {
            0.70391441567318025,
            0.35195720784848739,
            0.1759786039123464,
            0.087989301956173202,
            0.043994650989983904,
            0.021997325494991952,
            0.010998662747495976,
            0.005499331373747988,
            0.002749665686873994,
            0.001374832843436997,
            0.00068741640982119352,
            0.00034370821680790179,
            0.00017185409650664589,
            8.5927048253322947e-005,
            4.2963524126661473e-005,
            2.1481773960635764e-005,
            1.0740886980317882e-005,
            5.3704434901589409e-006};

    // 最小级别
    int minLevel = 1;

    // 最大级别
    int maxLevel = 2;

    // 保存数据的sqlite文件路径
    String dbpath;

    // SQLite链接
    Connection conn = null;
    Statement stmt = null;

    public TiandituDownload() {

    }

    public TiandituDownload(String dbpath) {
        this.dbpath = dbpath;
    }

    /**
     * @param originPoint 坐标点
     * @param level       级别
     * @return 改点在该级别所属的地图瓦片行列号(4490)
     */
    private CalEnv calculateEnv4490(Point originPoint, int level) {
        int startX = (int) Math.floor((originPoint.getLng() + 180) / (256 * res4490[level]));
        int startY = (int) Math.floor((90 - originPoint.getLat()) / (256 * res4490[level]));
        if (startX < 0) startX = 0;
        if (startY < 0) startY = 0;

        return new CalEnv(startX, startY);
    }

    /**
     * @param minPoint 下载范围左下角坐标
     * @param maxPoint 下载范围右上角坐标
     * @param level    下载级别
     * @param type     下载数据类型
     * @param merge    数据与其注记是否融合
     */
    private void downloadSingLevelTiles(Point minPoint, Point maxPoint, int level, TianDiTuTiledMapServiceType type, boolean merge) {

        try {
            CalEnv startEnv = calculateEnv4490(minPoint, level);
            CalEnv stopEnv = calculateEnv4490(maxPoint, level);

            PreparedStatement preparedStatement;
            ResultSet rs;

            for (int i = startEnv.getStartCol(); i <= stopEnv.getStartCol(); i++) {
                for (int j = stopEnv.getStartRow(); j <= startEnv.getStartRow(); j++) {
                    boolean hasData = false;
                    try {
                        // 查询瓦片是否存在
                        String querySQL = "select * from " + type + " where TILELEVEL = " + level + " and TILECOL = " + i + " and TILEROW = " + j;
                        rs = stmt.executeQuery(querySQL);
                        while (rs.next()) {
                            hasData = true;
                        }
                        // 如果不存在则从网络获取
                        if (!hasData) {
                            String url = new TDTUrl(level, i, j, type).generatUrl();
                            // 获得地图瓦片数据流
                            byte[] img = getTile(url);
                            System.out.println("正在下载 " + url);

                            // 如果merge为true,则在下载img_c或vec_c时将其注记图片一并下载
                            if (merge) {
                                InputStream img_stream = new ByteArrayInputStream(img);
                                BufferedImage bImageFromConvert = ImageIO.read(img_stream);

                                String url2 = "";
                                if (type == TianDiTuTiledMapServiceType.IMG_C) {
                                    url2 = new TDTUrl(level, i, j, TianDiTuTiledMapServiceType.CIA_C).generatUrl();
                                } else {
                                    url2 = new TDTUrl(level, i, j, TianDiTuTiledMapServiceType.CVA_C).generatUrl();
                                }
                                byte[] img2 = getTile(url2);
                                InputStream img_stream2 = new ByteArrayInputStream(img2);
                                BufferedImage bImageFromConvert2 = ImageIO.read(img_stream2);
                                // 将两张图片拼凑为一张
                                Graphics g = bImageFromConvert.getGraphics();
                                g.drawImage(bImageFromConvert, 0, 0, null);
                                g.drawImage(bImageFromConvert2, 0, 0, null);

                                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                                ImageIO.write(bImageFromConvert, "jpg", baos);
                                baos.flush();
                                img = baos.toByteArray();
                                baos.close();
                            }
                            // 将数据写入sqlite
                            String insertSQL = "INSERT INTO " + type + "(TILELEVEL,TILECOL,TILEROW,TILEDATA) VALUES (?,?,?,?)";
                            preparedStatement = conn.prepareStatement(insertSQL);
                            preparedStatement.setInt(1, level);
                            preparedStatement.setInt(2, i);
                            preparedStatement.setInt(3, j);
                            preparedStatement.setBytes(4, img);
                            preparedStatement.execute();
                        }
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                }
                conn.commit();
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }


    /**
     * @param minPoint 下载范围左下角坐标
     * @param maxPoint 下载范围右上角坐标
     * @param minLevel 下载最小级别
     * @param maxLevel 下载最大级别
     * @param type     下载数据类型
     * @param merge    数据与其注记是否融合
     * @throws SQLException
     */
    public void Download(Point minPoint, Point maxPoint, int minLevel, int maxLevel, TianDiTuTiledMapServiceType type, boolean merge) throws SQLException {
        try {
            Class.forName("org.sqlite.JDBC");
            conn = DriverManager.getConnection("jdbc:sqlite:" + this.dbpath);
            conn.setAutoCommit(false);
            stmt = conn.createStatement();
            // 新建数据表
            String sql = "CREATE TABLE IF NOT EXISTS " + type +
                    "(TILELEVEL INT," +
                    "TILECOL INT," +
                    "TILEROW INT," +
                    "TILEDATA BLOB)";
            stmt.executeUpdate(sql);
            stmt.close();

            for (int m = minLevel; m <= maxLevel; m++) {
                this.downloadSingLevelTiles(minPoint, maxPoint, m, type, merge);
            }
            conn.close();
            System.out.println("下载完成");

        } catch (Exception e) {

        }
    }

    /**
     * 下载网络数据
     *
     * @param url
     * @return 图片数据流
     * @throws Exception
     */
    protected byte[] getTile(String url) throws Exception {
        byte[] result = null;
        try {
            // 如果没有就直接从web上读取
            ByteArrayOutputStream bos = new ByteArrayOutputStream();

            URL sjwurl = new URL(url);
            HttpURLConnection httpUrl = null;
            BufferedInputStream bis = null;
            byte[] buf = new byte[1024];

            httpUrl = (HttpURLConnection) sjwurl.openConnection();
            httpUrl.connect();
            bis = new BufferedInputStream(httpUrl.getInputStream());

            while (true) {
                int bytes_read = bis.read(buf);
                if (bytes_read > 0) {
                    bos.write(buf, 0, bytes_read);
                } else {
                    break;
                }
            }

            bis.close();
            httpUrl.disconnect();

            result = bos.toByteArray();
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return result;
    }
}