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