java地图导出——添加经纬线
Posted 牛老师讲GIS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 y2
int 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 y2
int 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以上是关于java地图导出——添加经纬线的主要内容,如果未能解决你的问题,请参考以下文章