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

概述:

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

 

实现后效果:

 

技术难点:

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

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

 

编码实现:

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

 

  1. package com.lzugis.web;  
  2.   
  3.   
  4. import javax.imageio.ImageIO;  
  5.   
  6. import java.awt.Color;  
  7. import java.awt.Image;  
  8. import java.awt.image.BufferedImage;  
  9. import java.io.BufferedInputStream;  
  10. import java.io.ByteArrayInputStream;  
  11. import java.io.File;  
  12. import java.io.FileInputStream;  
  13. import java.io.IOException;  
  14. import java.io.InputStream;  
  15. import java.io.OutputStream;  
  16. import java.util.ArrayList;  
  17. import java.util.List;  
  18.   
  19. import javax.servlet.ServletException;  
  20. import javax.servlet.annotation.WebServlet;  
  21. import javax.servlet.http.HttpServlet;  
  22. import javax.servlet.http.HttpServletRequest;  
  23. import javax.servlet.http.HttpServletResponse;  
  24.   
  25. /** 
  26.  * Servlet implementation class PoiServices 
  27.  */  
  28. @WebServlet(description = "poi to wms", urlPatterns =  {"/map/poi"})  
  29. public class PoiServices extends HttpServlet {  
  30.     private static final long serialVersionUID = 1L;  
  31.          
  32.     /** 
  33.      * @see javax.servlet.http.HttpServlet#HttpServlet() 
  34.      */  
  35.     public PoiServices() {  
  36.         super();  
  37.         // TODO Auto-generated constructor stub  
  38.     }  
  39.   
  40.     /** 
  41.      * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) 
  42.      */  
  43.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  44.         // TODO Auto-generated method stub  
  45.         this.doPost(request,response);  
  46.     }  
  47.   
  48.     /** 
  49.      * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) 
  50.      */  
  51.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  52.         // TODO Auto-generated method stub        
  53.          String bbox= request.getParameter("BBOX");  
  54.          String width= request.getParameter("WIDTH");  
  55.          String height= request.getParameter("HEIGHT");  
  56.          int w = Integer.parseInt(width),  
  57.               h = Integer.parseInt(height);  
  58.          String[] extent = bbox.split(",");  
  59.          double xmin = Double.parseDouble(extent[0]),  
  60.                  ymin = Double.parseDouble(extent[1]),  
  61.                  xmax = Double.parseDouble(extent[2]),  
  62.                  ymax = Double.parseDouble(extent[3]);  
  63.          double scalex = ((xmax-xmin)*3600)/w,  
  64.                  scaley = ((ymax-ymin)*3600)/h;  
  65.          List<String> geoData = new ArrayList<String>();  
  66.          /*geoData.add("87.5758285931,43.7822116460"); 
  67.          geoData.add("91.1629975040,29.7104204643"); 
  68.          geoData.add("116.4575803581078,40.04054437977018"); 
  69.          geoData.add("103.584297498,36.1190864503");*/   
  70.          geoData.add("116.294,39.9742");   
  71.          geoData.add("116.306,39.9754");   
  72.          ……  
  73.            
  74.          BufferedImage image = new BufferedImage(w, h,BufferedImage.TYPE_INT_RGB);  
  75.          java.awt.Graphics2D g2d = image.createGraphics();  
  76.          image = g2d.getDeviceConfiguration().createCompatibleImage(w,h,  
  77.             java.awt.Transparency.TRANSLUCENT);  
  78.          g2d.dispose();  
  79.          g2d = image.createGraphics();  
  80.          for(int i=0;i<geoData.size();i++){  
  81.              String lonLat = geoData.get(i).toString();  
  82.              String lon = lonLat.split(",")[0],  
  83.                      lat = lonLat.split(",")[1];  
  84.              double x = Double.parseDouble(lon),  
  85.                      y = Double.parseDouble(lat);  
  86.              double scrx = (x-xmin)*3600/scalex,  
  87.                      scry = (ymax-y)*3600/scaley;  
  88.              Image img = ImageIO.read(new File("c:/icon.png"));  
  89.              g2d.drawImage(img, (int)scrx, (int)scry, null, null);  
  90.          }  
  91.          g2d.setStroke(new java.awt.BasicStroke(10));  
  92.          // 释放对象  
  93.          g2d.dispose();  
  94.          // 保存文件  
  95.          OutputStream os = response.getOutputStream();  
  96.          try {  
  97.              String poiimg = "c:/wms.png";  
  98.              ImageIO.write(image, "png", new File(poiimg));  
  99.              int count = 0;  
  100.              byte[] buffer = new byte[1024 * 1024];  
  101.              InputStream inStream = new BufferedInputStream(new FileInputStream(poiimg));  
  102.              while ((count = inStream.read(buffer)) != -1){  
  103.                  os.write(buffer, 0, count);  
  104.              }  
  105.              os.flush();              
  106.              inStream.close();  
  107.              os.close();  
  108.          }  
  109.          catch (IOException e) {  
  110.               e.printStackTrace();  
  111.          }  
  112.     }  
  113. }  

说明:

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

 

前台调用:

[javascript] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. var poiurl = "http://localhost:8081/lzugis/map/poi";  
  2. var poilayer = new OpenLayers.Layer.WMS("poilayer",  
  3.         poiurl,  
  4.         {  
  5.             layers: "",  
  6.             transparent: true  
  7.         }, {  
  8.             opacity: 1,  
  9.             singleTile: true  
  10.         });  
  11. map.addLayer(poilayer); 
posted @ 2016-07-18 15:07  韩慧兵  阅读(1242)  评论(0编辑  收藏  举报