• 大量POI点展示的一种解决方案


    概述:

    不论是在Arcgis for js还是Openlayers中,当POI点比较多的时候,在前台页面的展示在效率上是一大问题。经过一段时间的研究,发现百度地图在这一问题上的处理思路比较好:将要展示的POI点在服务器端生成图片,页面只调用图片的话效率会比较高。本文讲述如何在java后台实现POI点在服务器端的实时生成以及在Openlayers2的展示。


    实现后效果:





    技术难点:

    要实现POI点在服务器端的生成,难点在与如何通过前台请求的参数计算出坐标点的屏幕坐标。为此参了网上的一篇文章解决了此问题,文章内容如下:

    地理坐标定义规则:X轴(代表经度)向右递增,Y轴(纬度)向上递增,就好比小学学过的平面坐标。向左、向下的规则。屏幕坐标定义规则:X轴向右递增,Y轴向下递增。
    可以看出,地理坐标和屏幕坐标的区别仅仅只是在于Y轴递增方向是相反的(这就是不同)。
    这里强调一点的就是为了保证精度,地理坐标的度*3600换算成秒,所有的取值用double来计算,最后的结果再转换成int。
    1 已知道屏幕的高(y)和宽(h),地理坐标区域的范围(maxLon,minLon,maxLat,minLat),这里我们知道了这些已知的参数。
    2 我们可以算出每像素所代表的经度和纬度(有人称这个为比例因子)。
    公式:scaleX = ((maxLon-minLon)*3600)/h ----------X轴上每像素代表的经度秒数;
    公式:scaleY = ((maxLat-minLat)*3600)/y ----------Y轴上每像素代表的纬度秒数;
    这两个比例因子就是两个坐标系之间的关系。
    3 很简单的一步了,那就是算出该地理坐标区域中的任何一点(lon,lat)在屏幕上的坐标了。
    公式:screenX = lon*3600/scaleX;---------屏幕坐标X轴坐标
    公式:screenY = lat*3600/scaleY; ---------屏幕坐标Y轴坐标
    还有最后一步,那就是我们要把该地理区域占满占个屏幕该怎么办呢?
    4 接着我们需要该地理区域占满占个屏幕该怎么办呢
    公式:minX = minLon*3600/scaleX;区域左边置最左端
    公式:minY = minLat*3600/scaleY; 区域上面置最上端
    5 当地地理范围区域占满整个屏幕时,我们需要用到第三步计算出来的 screenX和screenY两个参数,该区域中的任何一点的公式如下: 
    公式:X = screenX - minX = (lon - minLon)*3600/scaleX; 
    公式:Y = screenMaxLat - screenLat = (maxLat - lat)*3600/scaleY;
    6 总结:
    经纬度转屏幕坐标的最终公式如下:
    公式:X = (lon - minLon)*3600/scaleX; 
    公式:Y = (maxLat - lat)*3600/scaleY;
    接着我们由上面的公式可以推出屏幕坐标转经纬度坐标公式如下:
    公式:lon = X * scaleX/3600 + minLon;
    公式:lat = maxLat - y* scaleY/3600;


    编码实现:

    后台POI图片的实时生成用了一个servlet实现,前台调用用WMS来调用,具体代码如下:

    package com.lzugis.web;
    
    
    import javax.imageio.ImageIO;
    
    import java.awt.Color;
    import java.awt.Image;
    import java.awt.image.BufferedImage;
    import java.io.BufferedInputStream;
    import java.io.ByteArrayInputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * Servlet implementation class PoiServices
     */
    @WebServlet(description = "poi to wms", urlPatterns =  {"/map/poi"})
    public class PoiServices extends HttpServlet {
    	private static final long serialVersionUID = 1L;
           
        /**
         * @see javax.servlet.http.HttpServlet#HttpServlet()
         */
        public PoiServices() {
            super();
            // TODO Auto-generated constructor stub
        }
    
    	/**
    	 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
    	 */
    	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		this.doPost(request,response);
    	}
    
    	/**
    	 * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
    	 */
    	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub		
    		 String bbox= request.getParameter("BBOX");
    		 String width= request.getParameter("WIDTH");
    	     String height= request.getParameter("HEIGHT");
    	     int w = Integer.parseInt(width),
    	    	  h = Integer.parseInt(height);
    	     String[] extent = bbox.split(",");
    	     double xmin = Double.parseDouble(extent[0]),
    	    		 ymin = Double.parseDouble(extent[1]),
    	    		 xmax = Double.parseDouble(extent[2]),
    	    		 ymax = Double.parseDouble(extent[3]);
    	     double scalex = ((xmax-xmin)*3600)/w,
    	    		 scaley = ((ymax-ymin)*3600)/h;
    	     List<String> geoData = new ArrayList<String>();
    	     /*geoData.add("87.5758285931,43.7822116460");
    	     geoData.add("91.1629975040,29.7104204643");
    	     geoData.add("116.4575803581078,40.04054437977018");
    	     geoData.add("103.584297498,36.1190864503");*/ 
    	     geoData.add("116.294,39.9742"); 
    	     geoData.add("116.306,39.9754"); 
    	     ……
    	     
    	     BufferedImage image = new BufferedImage(w, h,BufferedImage.TYPE_INT_RGB);
    	     java.awt.Graphics2D g2d = image.createGraphics();
    	     image = g2d.getDeviceConfiguration().createCompatibleImage(w,h,
    	    	java.awt.Transparency.TRANSLUCENT);
    	     g2d.dispose();
    	     g2d = image.createGraphics();
    	     for(int i=0;i<geoData.size();i++){
    	    	 String lonLat = geoData.get(i).toString();
    	    	 String lon = lonLat.split(",")[0],
    	    			 lat = lonLat.split(",")[1];
    	    	 double x = Double.parseDouble(lon),
    	    			 y = Double.parseDouble(lat);
    	    	 double scrx = (x-xmin)*3600/scalex,
    	    			 scry = (ymax-y)*3600/scaley;
    	    	 Image img = ImageIO.read(new File("c:/icon.png"));
    	    	 g2d.drawImage(img, (int)scrx, (int)scry, null, null);
    	     }
    	     g2d.setStroke(new java.awt.BasicStroke(10));
    	     // 释放对象
    	     g2d.dispose();
    	     // 保存文件
    	     OutputStream os = response.getOutputStream();
    	     try {
    	    	 String poiimg = "c:/wms.png";
    	    	 ImageIO.write(image, "png", new File(poiimg));
    	         int count = 0;
    	         byte[] buffer = new byte[1024 * 1024];
                 InputStream inStream = new BufferedInputStream(new FileInputStream(poiimg));
    	         while ((count = inStream.read(buffer)) != -1){
    	             os.write(buffer, 0, count);
    	         }
    	         os.flush();	        
    	         inStream.close();
    	         os.close();
    	     }
    	     catch (IOException e) {
    	          e.printStackTrace();
    	     }
    	}
    }
    说明:

    此处用了北京市的地铁站点的数据作为测试数据。


    前台调用:

                    var poiurl = "http://localhost:8081/lzugis/map/poi";
                    var poilayer = new OpenLayers.Layer.WMS("poilayer",
                            poiurl,
                            {
                                layers: "",
                                transparent: true
                            }, {
                                opacity: 1,
                                singleTile: true
                            });
                    map.addLayer(poilayer);

    后续:

    作为POI,是需要有鼠标的事件的,这部分的内容正在研究中,后期会陆续更新。




  • 相关阅读:
    分类管理模块
    Java8新特性 集合的stream的map
    条件和分页查询
    工作常用系统汇总
    Dubbo简单环境搭建
    深入浅出 TCP/IP 协议栈
    非对称加密
    理解Cookie和Session机制
    jQuery学习
    数据库系列学习(六)-函数之数学函数
  • 原文地址:https://www.cnblogs.com/lzugis/p/6539786.html
Copyright © 2020-2023  润新知