java地图导出——添加经纬线
生活随笔
收集整理的這篇文章主要介紹了
java地图导出——添加经纬线
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
概述
前面的文章Node實現切片的拼接和地圖的導出和Java實現地圖的導出分別講述可如何在node和java中實現切片的拼接以及地圖的導出。本文,書接前文,實現java導出時經緯度的添加。
實現后效果
實現
完整的實現思路流程如下圖:
1. 根據切片參數計算分辨率組
static int TILE_SIZE = 256; static double GLOBAL_EXTENT = 20037508.34; static double[] resolutions = new double[19]; // 計算分辨率組 double res = (GLOBAL_EXTENT * 2) / TILE_SIZE; for (int i = 0; i < 19; i++) {resolutions[i] = res;res = res / 2; }2. 根據經緯度間隔計算經緯度組
static double interval[] = new double[]{10, 7.5}; static int lonNum = (int) (180 / interval[0]); static int latNum = (int) (90 / interval[1]); static double[] lonInterval = new double[lonNum]; static double[] latInterval = new double[latNum]; // 計算經緯線組 for (int i = 1; i < lonNum; i++) {lonInterval[i] = interval[0] * i; } for (int i = 1; i < latNum; i++) {latInterval[i] = interval[1] * i; }3. 根據出圖級別獲取當前級別分辨率和地理坐標轉屏幕坐標轉換函數
public static Integer[] getPixel(double[] coords) {// 獲取當前分辨率和轉換函數double res = resolutions[ZOOM];double originY = GLOBAL_EXTENT;double originX = -GLOBAL_EXTENT;double coordX = coords[0], coordY = coords[1];Integer x = (int) ((coordX - originX) / res);Integer y = (int) ((originY - coordY) / res);return new Integer[]{x, y}; }4. 根據出圖四至獲取切片行列號并拼圖
// 根據出圖四至獲取切片行列號 public static int[] getTileRowCol (double[] extent) {if(extent.length != 4) return new int[]{};double originX = -GLOBAL_EXTENT;double originY = GLOBAL_EXTENT;double res = resolutions[ZOOM] * TILE_SIZE;int xmin = (int) Math.floor((extent[0] - originX) / res)int xmax = (int) Math.ceil((extent[2] - originX) / res);int ymax = (int) Math.ceil((originY - extent[1]) / res);int ymin = (int) Math.floor((originY - extent[3]) / res)return new int[]{ xmin, xmax, ymin, ymax}; }// 獲取切片的行列號 int[] rowCol = getTileRowCol(extent); int xmin = rowCol[0]; int xmax = rowCol[1]; int ymin = rowCol[2]; int ymax = rowCol[3]; // 計算切片拼圖的大小 int width = (xmax - xmin) * TILE_SIZE; int height = (ymax - ymin) * TILE_SIZE; // 拼圖 try {BufferedImage tileImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);Graphics2D graphicsTile = tileImage.createGraphics();for (int i = xmin; i <= xmax ; i++) {for (int j = ymin; j <= ymax ; j++) {String destUrl = "http://webrd01.is.autonavi.com/appmaptile?x="+i+"&y="+j+"&z="+ZOOM+"&lang=zh_cn&size=1&scale=1&style=8";BufferedImage tile = getBufferedImageDestUrl(destUrl);int x = (i - xmin) * TILE_SIZE;int y = (j -ymin) * TILE_SIZE;graphicsTile.drawImage(tile, x, y, TILE_SIZE, TILE_SIZE, null);}} } catch (Exception e) {e.printStackTrace(); }5. 計算切片出圖大小和四至,疊加wms圖層
// 獲取切片的坐標范圍 public static double[] getTileExtent(Integer xmin, Integer xmax, Integer ymin, Integer ymax) {double res = resolutions[ZOOM] * TILE_SIZE;double originY = GLOBAL_EXTENT;double originX = -GLOBAL_EXTENT;double xminE = originX + (xmin * res);double xmaxE = originX + (xmax * res);double yminE = originY - (ymax * res);double ymaxE = originY - (ymin * res);return new double[] {xminE, yminE, xmaxE, ymaxE}; } // 計算切片拼圖的大小 int width = (xmax - xmin) * TILE_SIZE; int height = (ymax - ymin) * TILE_SIZE; // 疊加wms double[] tileExtent = getTileExtent(xmin, xmax, ymin, ymax); String extentStr = tileExtent[0] + "," + tileExtent[1] + "," +tileExtent[2] + "," +tileExtent[3]; String wmsUrl = "https://lzugis.cn/geoserver/lzugis/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&LAYERS=lzugis%3Achina&CRS=EPSG%3A3857&STYLES=&WIDTH="+width+"&HEIGHT="+height+"&BBOX="+extentStr; BufferedImage wms = getBufferedImageDestUrl(wmsUrl); graphicsTile.drawImage(wms, 0, 0, width, height, null);6. 根據轉換函數計算出圖大小和切片的偏移量,裁剪圖片
// 計算出圖范圍的寬高 Integer[] topLeft = getPixel(new double[]{extent[0], extent[3]}); //xmin, ymax Integer[] bottomRight = getPixel(new double[]{extent[2], extent[1]}); // xmax, ymin int widthE = (bottomRight[0] - topLeft[0]); int heightE = (bottomRight[1] - topLeft[1]); // 計算切片寬高和出圖寬高的差值 int deltX = (width - widthE) / 2; int deltY= (height - heightE) / 2; // 裁剪切片出圖,獲得出圖圖片 BufferedImage extentImage = tileImage.getSubimage(deltX,deltY,widthE,heightE);7. 根據出圖范圍計算經緯線并添加
// 向外擴30px,用于展示經緯線和標記 int offset = 30; int widthM = widthE + offset * 2; int heightM = heightE + offset * 2; BufferedImage mergeImage = new BufferedImage(widthM, heightM, BufferedImage.TYPE_INT_RGB); Graphics2D graphicsMerge = mergeImage.createGraphics(); graphicsMerge.setColor(Color.WHITE);//設置筆刷白色 graphicsMerge.fillRect(0,0,widthM,heightM);//填充整個屏幕 // 繪制出圖地圖 graphicsMerge.drawImage(extentImage, offset, offset, widthE, heightE, null);// 獲取經緯度 double[] minLonLat = webmactor2wgs84(extent[0], extent[1]); double[] maxLonLat = webmactor2wgs84(extent[2], extent[3]); int lonIndexMin = (int) Math.floor(minLonLat[0] / interval[0]); int lonIndexMax = (int) Math.ceil(maxLonLat[0] / interval[0]); int latIndexMin = (int) Math.floor(minLonLat[1] / interval[1]); int latIndexMax = (int) Math.ceil(maxLonLat[1] / interval[1]);double latMin= minLonLat[1], lonMin = minLonLat[0], latMax = maxLonLat[1], lonMax = maxLonLat[0]; Stroke solid = new BasicStroke(1); graphicsMerge.setStroke(solid); // 設置字體 Font font=new Font("Times New Roman",Font.PLAIN,14); graphicsMerge.setFont(font); // 抗鋸齒 graphicsMerge.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); FontMetrics fm = graphicsMerge.getFontMetrics(font);for (int i = lonIndexMin; i <= lonIndexMax ; i++) {String lon = String.valueOf((Double.valueOf(lonInterval[i] * 100).intValue()) / 100.0);double[] coords = wgs842webmactor(lonInterval[i], latMin);Integer[] pixel = getPixel(coords);// x1, int y1, int x2, int y2int x1 = pixel[0] - topLeftTile[0] + offset - deltX;int y1 = offset, y2 = heightE + offset;if(x1 > offset && x1 < widthE + offset){// 繪制豎直的經線和經度標注graphicsMerge.setColor(new Color(0, 144, 255));graphicsMerge.drawLine(x1, y1, x1, y2);// 計算文字長度,計算居中的x點坐標int textWidth = fm.stringWidth(lon) / 2;graphicsMerge.setColor(Color.BLACK);graphicsMerge.drawString(lon, x1 - textWidth, y1 - 10); // 上面的文字graphicsMerge.drawString(lon, x1 - textWidth, y2 + 20); // 下面的文字} } // 旋轉文字 AffineTransform affineTransform = new AffineTransform(); affineTransform.rotate(Math.toRadians(-90), 0, 0); Font rotatedFont = font.deriveFont(affineTransform); graphicsMerge.setFont(rotatedFont); for (int i = latIndexMin; i <= latIndexMax ; i++) {String lat = String.valueOf((Double.valueOf(latInterval[i] * 100).intValue()) / 100.0);double[] coords = wgs842webmactor(lonMin, latInterval[i]);Integer[] pixel = getPixel(coords);// x1, int y1, int x2, int y2int y1 = pixel[1] - topLeftTile[1] + offset - deltY;int x1 = offset, x2 = widthE + offset;if(y1 > offset && y1 < heightE + offset) {// 繪制豎直的經線graphicsMerge.setColor(new Color(0, 144, 255));graphicsMerge.drawLine(x1, y1, x2, y1);// 計算文字長度,計算居中的x點坐標int textWidth = fm.stringWidth(lat) / 2;graphicsMerge.setColor(Color.BLACK);graphicsMerge.drawString(lat, x1 - 10, y1 + textWidth); // 左面的文字graphicsMerge.drawString(lat, x2 + 20, y1 + textWidth); // 右面的文字} }8. 添加圖名、指北針等要素
// 添加地圖標題 String mapTitle = "中國地圖"; graphicsMerge.setColor(new Color(255,0,0,255)); graphicsMerge.setFont(new Font("微軟雅黑", Font.BOLD, 24)); int length = graphicsMerge.getFontMetrics(graphicsMerge.getFont()).charsWidth(mapTitle.toCharArray(), 0, mapTitle.length()); int posx = 45 + offset, posy = 60 + offset, offsetTxt = 15; graphicsMerge.drawString(mapTitle, posx, posy); graphicsMerge.setStroke(new BasicStroke(2.0f)); int x1 = posx - offsetTxt; int y1 = posy - offsetTxt - 18; int x2 = posx + length + offsetTxt; int y2 = posy + offsetTxt + 6; graphicsMerge.drawLine(x1, y1, x2, y1); graphicsMerge.drawLine(x2, y1, x2, y2); graphicsMerge.drawLine(x2, y2, x1, y2); graphicsMerge.drawLine(x1, y2, x1, y1);// 添加指北針 String base64 = "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"; int w = 50, h = 50, pos = widthE + offset - posx; graphicsMerge.drawImage(base64ToBufferedImage(base64), pos , posx, w, h, null);總結
從實現的功能上來說,其實是比較簡單的,但是簡單的功能背后涵蓋著很多復雜的webgis基礎相關的知識,如果對這些知識理解不深刻的話實現起來還是比較困難的。如果掌握了這些知識后,不論是java還是js還是pythoon,都可實現。本文只實現了基礎的地圖導出,添加比例尺、圖例等暫未實現。
總結
以上是生活随笔為你收集整理的java地图导出——添加经纬线的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: InstallShield安装与制作
- 下一篇: 希赛教育计算机网络基础,2020年9月网