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

原创 2016年05月30日 19:43:12

概述:

在上文“ 大量POI点展示的一种解决方案”中,介绍了在在后台将POI生成图片在前台展示,文章中没有涉及到点的抽稀问题,也就是当点的数据量非常大的时候,这种展示方式还是会有一定的效率问题,在本文,书接上文,介绍一种点抽稀的算法,并结合上文,实现大量poi点的高效展示。


效果:






实现思路:

1、点抽稀与图片生成

package com.lzugis.web;

import java.awt.Color;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
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 java.util.Map;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.jdbc.core.JdbcTemplate;

import com.lzugis.db.SpringUtil;
import com.lzugis.web.Model.Pos;

/**
 * Servlet implementation class PoiServlet
 */
@WebServlet(description = "poi servlet", urlPatterns =  {"/poi"})
public class PoiServlet extends HttpServlet {
	private static final long serialVersionUID = 1L; 	
	private static double M_PI = Math.PI;
	//6378137赤道半径,一度对应赤道上的一米,20037508.342789244
	private static double Degree2Meter = M_PI * 6378137 / 180.0;
	
    /**
     * @see HttpServlet#HttpServlet()
     */
    public PoiServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		this.doPost(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, 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 z = Integer.parseInt(request.getParameter("z").toString());
	    String layer = request.getParameter("layer");
	    System.out.println(z+","+layer+","+bbox);
	    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;
	    //获取抽稀数据
	    double dis = 2000000/(z+1);
	    System.out.println(dis);
		List<Pos> fc = new ArrayList<Pos>();
        List<Pos> fcDel = new ArrayList<Pos>();
        double buf = dis/Degree2Meter;
		JdbcTemplate jdbcTemplate = (JdbcTemplate) SpringUtil.getBean("jdbcTemplate");
        String sqlQuery = "select * from "+layer+" where x>=? and x<=? and y>=? and y<=?";
        List<Map<String, Object>> list =  jdbcTemplate.queryForList(sqlQuery, new Object[]{xmin,xmax,ymin,ymax});
        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();
	    if(list.size()>20){
	        for(int i=0;i<list.size();i++){
	        	Map<String,Object> map = list.get(i);
	        	double x =  Double.parseDouble(map.get("x").toString());
	        	double y =  Double.parseDouble(map.get("y").toString());
	        	Pos pos = new Pos(x,y);
	        	pos.setBuffer(buf);
	        	if (fc.contains(pos)) {
	        		fcDel.add(pos);
	        	} 
	        	else {
	        		fc.add(pos);
	        		double scrx = (x-xmin)*3600/scalex,
	      	    			scry = (ymax-y)*3600/scaley;      	    	 
	      	    	g2d.setColor(Color.RED);
	      	    	Image img = ImageIO.read(new File("c:/icon.png"));
	      	    	g2d.drawImage(img, (int)scrx, (int)scry, null, null);
	        	}
	        }
	    }
	    else{
	    	for(int i=0;i<list.size();i++){
	        	Map<String,Object> map = list.get(i);
	        	double x =  Double.parseDouble(map.get("x").toString());
	        	double y =  Double.parseDouble(map.get("y").toString());
	        	Pos pos = new Pos(x,y);
	        	pos.setBuffer(buf);
	        	fc.add(pos);
        		double scrx = (x-xmin)*3600/scalex,
      	    			scry = (ymax-y)*3600/scaley;      	    	 
      	    	g2d.setColor(Color.RED);
      	    	Image img = ImageIO.read(new File("c:/icon.png"));
      	    	g2d.drawImage(img, (int)scrx, (int)scry, null, null);	        		
	        }
	    }
        System.out.println("共"+list.size()+"个点,其中:保留"+fc.size()+"个,删除"+fcDel.size()+"个");
        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();
	    }
	}
}
其中,Pos类如下:

package com.lzugis.web.Model;

public class Pos {
	public double x;
	public double y;

	private double buf;

	public Pos(double x, double y) {
		this.x = x;
		this.y = y;
	}

	public void setBuffer(double buf) {
		this.buf = buf;
	}

	public boolean equals(Object pt) {
		if (pt instanceof Pos)
			return (Math.abs(this.x - ((Pos) pt).x) <= buf && Math.abs(this.y
					- ((Pos) pt).y) <= buf);
		return false;
	}

	public int hashCode() {
		return Integer.valueOf(x + "" + y);
	}

}
2、扩展wms,在请求参数后添加zoom和layername

OpenLayers.Layer.PoiLayer = OpenLayers.Class(OpenLayers.Layer.Grid, {
    DEFAULT_PARAMS: { service: "WMS",
        version: "1.1.1",
        request: "GetMap",
        styles: "",
        format: "image/jpeg"
    },
    isBaseLayer: true,
    encodeBBOX: false,
    noMagic: false,
    yx: {},
    layer:"",
    initialize: function(name, url, params, options) {
        var newArguments = [];
        //uppercase params
        params = OpenLayers.Util.upperCaseObject(params);
        if (parseFloat(params.VERSION) >= 1.3 && !params.EXCEPTIONS) {
            params.EXCEPTIONS = "INIMAGE";
        }
        newArguments.push(name, url, params, options);
        OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
        OpenLayers.Util.applyDefaults(
            this.params,
            OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)
        );


        //layer is transparent        
        if (!this.noMagic && this.params.TRANSPARENT &&
            this.params.TRANSPARENT.toString().toLowerCase() == "true") {

            // unless explicitly set in options, make layer an overlay
            if ( (options == null) || (!options.isBaseLayer) ) {
                this.isBaseLayer = false;
            }

            // jpegs can never be transparent, so intelligently switch the 
            //  format, depending on the browser's capabilities
            if (this.params.FORMAT == "image/jpeg") {
                this.params.FORMAT = OpenLayers.Util.alphaHack() ? "image/gif"
                    : "image/png";
            }
        }

    },
    clone: function (obj) {

        if (obj == null) {
            obj = new OpenLayers.Layer.WMS(this.name,
                this.url,
                this.params,
                this.getOptions());
        }

        //get all additions from superclasses
        obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);

        // copy/set any non-init, non-simple values here

        return obj;
    },
    reverseAxisOrder: function() {
        var projCode = this.projection.getCode();
        return parseFloat(this.params.VERSION) >= 1.3 &&
            !!(this.yx[projCode] || OpenLayers.Projection.defaults[projCode].yx);
    },
    getURL: function (bounds) {
        bounds = this.adjustBounds(bounds);
        var imageSize = this.getImageSize();
        var newParams = {};
        // WMS 1.3 introduced axis order
        var reverseAxisOrder = this.reverseAxisOrder();
        newParams.BBOX = this.encodeBBOX ?
            bounds.toBBOX(null, reverseAxisOrder) :
            bounds.toArray(reverseAxisOrder);
        newParams.WIDTH = imageSize.w;
        newParams.HEIGHT = imageSize.h;
        var requestString = this.getFullRequestString(newParams);
        var zoom = this.map.getZoom();
        var layer = this.name;
        return requestString+"&z="+zoom+"&layer="+layer;
    },

    mergeNewParams:function(newParams) {
        var upperParams = OpenLayers.Util.upperCaseObject(newParams);
        var newArguments = [upperParams];
        return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,
            newArguments);
    },
    getFullRequestString:function(newParams, altUrl) {
        var mapProjection = this.map.getProjectionObject();
        var projectionCode = this.projection && this.projection.equals(mapProjection) ?
            this.projection.getCode() :
            mapProjection.getCode();
        var value = (projectionCode == "none") ? null : projectionCode;
        if (parseFloat(this.params.VERSION) >= 1.3) {
            this.params.CRS = value;
        } else {
            this.params.SRS = value;
        }

        if (typeof this.params.TRANSPARENT == "boolean") {
            newParams.TRANSPARENT = this.params.TRANSPARENT ? "TRUE" : "FALSE";
        }

        return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(
            this, arguments);
    },

    CLASS_NAME: "OpenLayers.Layer.PoiLayer"
});
3、前台调用并展示

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>openlayers map</title>
    <link rel="stylesheet" href="../../../plugin/OpenLayers-2.13.1/theme/default/style.css" type="text/css">
    <style>
        html, body, #map{
            padding:0;
            margin:0;
            height:100%;
            width:100%;
            overflow: hidden;
        }
        .tool{
            position: absolute;
            top:10pt;
            right: 10pt;
            padding: 5px;
            background: #fff;
            border: 1px solid #ff5500;
            z-index: 1000;
        }
    </style>
    <script src="../../../plugin/OpenLayers-2.13.1/OpenLayers.js"></script>
    <script src="extend/PoiLayer.js"></script>
    <script src="../../../plugin/jquery/jquery-1.8.3.js"></script>
    <script>
        var map;
        var tiled;
        OpenLayers.IMAGE_RELOAD_ATTEMPTS = 5;
        OpenLayers.DOTS_PER_INCH = 25.4 / 0.28;
        $(window).load(function() {
            var format = 'image/png';
            var bounds = new OpenLayers.Bounds(
                    73.45100463562233, 18.16324718764174,
                    134.97679764650596, 53.531943152223576
            );
            var options = {
                controls: [],
                maxExtent: bounds,
                maxResolution: 0.2403351289487642,
                projection: "EPSG:4326",
                units: 'degrees'
            };
            map = new OpenLayers.Map('map', options);
            var url = "http://localhost:8088/geoserver/lzugis/wms";
            tiled = new OpenLayers.Layer.WMS(
                    "Geoserver layers - Tiled",
                    url,
                    {
                        "LAYERS": 'lzugis:province',
                        "STYLES": '',
                        format: format
                    },
                    {
                        buffer: 0,
                        displayOutsideMaxExtent: true,
                        isBaseLayer: true,
                        yx : {'EPSG:4326' : true}
                    }
            );
            map.addLayers([tiled]);
            map.addControl(new OpenLayers.Control.Zoom());
            map.addControl(new OpenLayers.Control.Navigation());
            map.zoomToExtent(bounds);

            $("#addchart").on("click",function(){
                var poiurl = "http://localhost:8081/lzugis/poi";
                var wms = new OpenLayers.Layer.PoiLayer("county",
                        poiurl,
                        {
                            layers: "poi",
                            transparent: true
                        }, {
                            opacity: 1,
                            singleTile: true
                        });
                map.addLayers([wms]);
            });
        });
    </script>
</head>
<body>
<div id="map">
    <div class="tool">
        <button id="addchart">添加marker</button>
    </div>
</div>
<map name="marker" id="marker"></map>
</body>
</html>

传播GIS知识 | 交流GIS经验 | 分享GIS价值 | 专注GIS发展

技术博客

http://blog.csdn.net/gisshixisheng


在线教程

http://edu.csdn.net/course/detail/799

Github

https://github.com/lzugis/


联系方式

q       q:1004740957

e-mail:niujp08@qq.com

公众号:lzugis15

Q Q 群:452117357(webgis)
             337469080(Android)





版权声明:本文为LZUGIS原创文章,未经允许不得转载。 举报

相关文章推荐

点抽稀算法

对密集的点抽稀,保持点的均匀分布。 dis=1000; double degToMeter = Math.PI * 6378137 / 180.0;//6378137赤道半径,一度对应赤道上的一...

lzugis——Arcgis Server for JavaScript API之POI

lzugis——Arcgis Server for JavaScript API之POI

精选:深入理解 Docker 内部原理及网络配置

网络绝对是任何系统的核心,对于容器而言也是如此。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜像管理。然而,Docker的网络一直以来都比较薄弱,所以我们有必要深入了解Docker的网络知识,以满足更高的网络需求。

ArcGis点抽稀方法

1、如果我们用Arcgis打开一个点数据很多的文件,并对其进行标注的话,会显得很乱,而且无法获取有效的数据,为此我们需要随着比例尺的放大逐渐显示信息,点抽稀就是一个不错的选择; 2、选中...

大量POI的解决方案2

在前面的文章中,讲述了通过“抽稀+后台生成图片”的方式解决大量POI点展示的一种思路,后面看了tilestack的矢量切片方式,自己仔细思考了下,提出了本文大量POI点的展示解决方案。

曲线点抽稀算法-Python实现

何为抽稀 在处理矢量化数据时,记录中往往会有很多重复数据,对进一步数据处理带来诸多不便。多余的数据一方面浪费了较多的存储空间,另一方面造成所要表达的图形不光滑或不符合标准。因此要通过某种规则,在...

道格拉斯-普克 Douglas-Peuker抽稀算法

道格拉斯-普克抽稀算法,是用来对大量冗余的图形数据点进行压缩以提取必要的数据点。 该算法实现抽稀的过程是: 1)对曲线的首末点虚连一条直线,求曲线上所有点与直线的距离,并找出最大距离值dmax,用...

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

在上文“ 大量POI点展示的一种解决方案”中,介绍了在在后台将POI生成图片在前台展示,文章中没有涉及到点的抽稀问题,也就是当点的数据量非常大的时候,这种展示方式还是会有一定的效率问题,在本文,书接上...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)