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

概述:

在上文“ 大量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>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏函数式编程语言及工具

PICE(5):MongoDBStreaming - gRPC -MGO Service

  我在前面提到过MongoDB不支持像SQL般字符式的操作指令,所以我们必须对所有的MongoDB操作指令建立protobuf类型才能支持MongoDB指令的...

1104
来自专栏LhWorld哥陪你聊算法

Hadoop源码篇--Reduce篇

Reduce文件会从Mapper任务中拉取很多小文件,小文件内部有序,但是整体是没序的,Reduce会合并小文件,然后套个归并算法,变成一个整体有序的文件。

2181
来自专栏土豆专栏

JavaWeb入门之Servlet小练习

在web.xml文件中设置两个WEB应用的初始化参数,username,password,创建一个html页面,定义两个请求字段并发送到一个Servlet中,对...

41812
来自专栏贾老师の博客

【笔记】ejoy2d —— shader

2073
来自专栏PPV课数据科学社区

【学习】七天搞定SAS(二):基本操作(判断、运算、基本函数)

SAS生成新变量 SAS支持基本的加减乘除,值得一提的是它的**代表指数,而不是^。 * Modify homegarden data set with ass...

4374
来自专栏鸿的学习笔记

写给开发者的机器学习指南(十二)

此代码加载DJI数据,并将其添加到已经包含我们自己的股票市场指数的图形上。但是,当我们执行这段代码时,结果如下。

1082
来自专栏cnblogs

Javascript的原型继承,说清楚

     一直以来对Javascript的原型、原型链、继承等东西都只是会用和了解,但没有深入去理解这门语言关于继承这方面的本质和特点。闲暇之余做的理解和总...

1749
来自专栏Flutter入门到实战

老司机带你重构Android的v4包的部分源码

版权声明:本文为博主原创文章,未经博主允许不得转载。https://www.jianshu.com/p/a08d754944c4

1821
来自专栏ml

Redis学习笔记二

  学习Redis添加Object时,由于Redis只能存取字符串String,对于其它数据类型形容:Int,long,double,Date等不提供支持,因而...

3339
来自专栏行者常至

java 获取 post参数

923

扫码关注云+社区