最近项目原因需要用到克里金和等直线算法 ,在网上找了许久都不太满意,不是话说到一半就是 示例不正确,要不就是没库等等,捣鼓许久弄出来,把示例代码发出来分享一下。
首先了说明一下为什么要使用到克里金算法 因为气象方面很多气象站点零散的分布在地图各个位置,在这零散的位置上就可能会产生区域覆盖不完整的情况,这个时候就需要做插值覆盖。而等直线的意义跟插值业务一样,因为在地图上热力图的绘制需要大量格点数据来支撑绘制所以,就会出现在绘制热力图的时候光是下载格点数据都是很大的,这个取决于格点密度,密度越大那么数据量就会很大,在网络传输过程中光是下载这个数据都需要花费很多时间,更别说绘制了。所以等值线数据就尤为的重要。例如:
根据区域划分成勾勒出线的坐标,其内的值都是等值范围这样的数据就不会很多,当然等值范围越精确数据也会递增。
这次示例使用到的库wContour和geo,因为代码不复杂 加上代码也有注释,所以我就不细致解释下去了直接上demo
package kriginDemo.test;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.json.simple.JSONObject;
import com.alibaba.fastjson.JSON;
import krigingDemo.util.CommonMethod;
import krigingDemo.util.KrigingUtil;
import wContour.Contour;
import wContour.Interpolate;
import wContour.Global.Border;
import wContour.Global.PointD;
import wContour.Global.PolyLine;
import wContour.Global.Polygon;
public class Test {
/**
* 通过本地文件访问json并读取
*
* @param path:json文件路径
* @return:json文件的内容
*/
public static String readFile(String path) {
StringBuffer laststr = new StringBuffer();
File file = new File(path);// 打开文件
BufferedReader reader = null;
try {
FileInputStream in = new FileInputStream(file);
reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));// 读取文件
String tempString = null;
while ((tempString = reader.readLine()) != null) {
laststr = laststr.append(tempString);
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException el) {
}
}
}
return laststr.toString();
}
private static String getPolygonGeoJson(List<Polygon> cPolygonList) {
String geo = null;
String geometry = " { \"type\":\"Feature\",\"geometry\":";
String properties = ",\"properties\":{ \"hvalue\":";
String head = "{\"type\": \"FeatureCollection\"," + "\"features\": [";
String end = " ] }";
if (cPolygonList == null || cPolygonList.size() == 0) {
return null;
}
try {
for (Polygon pPolygon : cPolygonList) {
List<Object> ptsTotal = new ArrayList<Object>();
List<Object> pts = new ArrayList<Object>();
PolyLine pline = pPolygon.OutLine;
for (PointD ptD : pline.PointList) {
List<Double> pt = new ArrayList<Double>();
pt.add(ptD.X);
pt.add(ptD.Y);
pts.add(pt);
}
ptsTotal.add(pts);
if (pPolygon.HasHoles()) {
for (PolyLine cptLine : pPolygon.HoleLines) {
List<Object> cpts = new ArrayList<Object>();
for (PointD ccptD : cptLine.PointList) {
List<Double> pt = new ArrayList<Double>();
pt.add(ccptD.X);
pt.add(ccptD.Y);
cpts.add(pt);
}
if (cpts.size() > 0) {
ptsTotal.add(cpts);
}
}
}
JSONObject js = new JSONObject();
js.put("type", "Polygon");
js.put("coordinates", ptsTotal);
double hv = pPolygon.HighValue;
double lv = pPolygon.LowValue;
if (hv == lv) {
if (pPolygon.IsClockWise) {
if (!pPolygon.IsHighCenter) {
hv = hv - 0.1;
lv = lv - 0.1;
}
} else {
if (!pPolygon.IsHighCenter) {
hv = hv - 0.1;
lv = lv - 0.1;
}
}
} else {
if (!pPolygon.IsClockWise) {
lv = lv + 0.1;
} else {
if (pPolygon.IsHighCenter) {
hv = hv - 0.1;
}
}
}
geo = geometry + js.toString() + properties + hv
+ ", \"lvalue\":" + lv + "} }" + "," + geo;
}
if (geo.contains(",")) {
geo = geo.substring(0, geo.lastIndexOf(","));
}
geo = head + geo + end;
} catch (Exception e) {
e.printStackTrace();
return geo;
}
return geo;
}
public static void main(String[] args) {
//雅安样本数据
double[][] trainData = JSON.parseObject(readFile("G:\\t.json"), double[][].class);
KrigingUtil kriging = new KrigingUtil(KrigingUtil.SPHERICAL_MODEL, 0, 100);
kriging.train(trainData[2], trainData[0], trainData[1]);
//经度起点
double left = 101.91;
//经度结束点
double right =103.395;
//维度起点
double bottom = 28.845;
//维度结束点
double top = 30.935;
double[] bottomLeft = {left, bottom};
double[] topLeft = {left, top};
double[] topRight = {right, top};
double[] bottomRight = {right, bottom};
double[][][] polygons = {{bottomLeft, topLeft, topRight, bottomRight}};
//计算经纬度格点距离
double xWidth = Math.abs(right - left) / 297;
double yWidth = Math.abs(top - bottom) / 418;
//克里金插值
KrigingUtil.Grid grid = kriging.grid(polygons, xWidth, yWidth);
//等值线阈值
double[] dataInterval = new double[]{10,20,25,30,35};
//异常数据样本
double _undefData = -9999.0;
double[] _X = new double[420];
double[] _Y = new double[298];
Interpolate.createGridXY_Num(101.91,28.845,103.395,30.935, _X, _Y);
int[][] S1 = new int[grid.A.length][grid.A[0].length];
//绘线
List<Border> _borders = Contour.tracingBorders(grid.A, _X, _Y,S1, _undefData);
List<PolyLine> cPolylineList = new ArrayList<PolyLine>();
cPolylineList = Contour.tracingContourLines(grid.A, _X, _Y, dataInterval.length, dataInterval, _undefData, _borders, S1);// 生成等值线
cPolylineList = Contour.smoothLines(cPolylineList);// 平滑
List<Polygon> cPolygonList = new ArrayList<Polygon>();
cPolygonList = Contour.tracingPolygons(grid.A, cPolylineList,_borders, dataInterval);
String geojsonpogylon = getPolygonGeoJson(cPolygonList);
CommonMethod cm = new CommonMethod();
cm.append2File("G:\\data.json",geojsonpogylon);
}
}
double[][] trainData = JSON.parseObject(readFile("G:\\t.json"), double[][].class);
这个数据是我的样本数据
//计算经纬度格点距离
double xWidth = Math.abs(right - left) / 297;
double yWidth = Math.abs(top - bottom) / 418;
这个297和418 是我自己计算的值意思是从开始经纬度 和结束经纬度 以0.005为格点距离计算出来的数值
CommonMethod cm = new CommonMethod();
cm.append2File("G:\\data.json",geojsonpogylon);
最后将JSON 输出到文件 因为数据也是比较大的
最后可以将生成的等值线JSON 贴入这里来看看效果http://geojson.io/#map=8/29.893/102.651
来源:oschina
链接:https://my.oschina.net/umbrellall1/blog/4256500