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