微信搜索:“二十同学” 公众号,欢迎关注一条不一样的成长之路
geotools介绍
geotools官网https://geotools.org/
Geotools是一个java类库,它提供了很多的标准类和方法来处理空间数据,同时这个类库是构建在OGC标准之上的,是OGC思想的一种实现。而OGC是国际标准,所以geotools将来必定会成为开源空间数据处理的主要工具,目前的大部分开源软件,如udig,geoserver等,对空间数据的处理都是由geotools来做支撑。而其他很多的web服务,命令行工具和桌面程序都可以由geotools来实现。
JTS介绍
JTS是加拿大的 Vivid Solutions 做的一套开放源码的 Java API。它提供了一套空间数据操作的核心算法,为在兼容OGC标准的空间对象模型中进行基础的几何操作提供2D空间谓词API。
JTS包结构:系(linearref包)、计算交点(noding包)、几何图形操作(operation包)、平面图(planargraph包)、多边形化(polygnize包)、精度(precision)、工具(util包)
1、JTS提供了如下的空间数据类型,还提供了读取各种空间描述文件(WTK等),线简化,空间操作(求交,计算距离,计算外包矩形等),建立空间索引等多种算法。
Point
MultiPoint
LineString
LinearRing 封闭的线条
MultiLineString 多条线
Polygon
MultiPolygon
GeometryCollection 包括点,线,面
里面最主要的几个类,GeometryFactory,Geometry,Envelope以及上面提到的几种常用数据类型。
Geometry类:所有的空间数据类型,点,线,面,多点,环,多边形等等都是继承自Geometry类的。
Envelope类:该类就是描述一个空间几何对象的外包矩形,由max_x,max_y,min_x,min_y组成。
2、支持接口
Coordinate(坐标)是用来存储坐标的轻便的类。它不同于点,点是Geometry的子类。不像模范Point的对象(包含额外的信息,例如一个信包,一个精确度模型和空间参考系统信息),Coordinate只包含纵座标值和存取方法。
Envelope(矩形)一个具体的类,包含一个最大和最小的x 值和y 值。
GeometryFactory提供一系列的有效方法用来构造来自Coordinate类的Geometry对象。支持接口
3、空间关系
空间关系主要是由九交模型来描述的,九交模型的讲解可以参考:九交模型的讲解
至于在JTS中的对应的关系,就是以下几种:
相等(Equals): | 几何形状拓扑上相等。 |
脱节(Disjoint): | 几何形状没有共有的点。 |
相交(Intersects): | 几何形状至少有一个共有点(区别于脱节) |
接触(Touches): | 几何形状有至少一个公共的边界点,但是没有内部点。 |
交叉(Crosses): | 几何形状共享一些但不是所有的内部点。 |
内含(Within): | 几何形状A的线都在几何形状B内部。 |
包含(Contains): | 几何形状B的线都在几何形状A内部(区别于内含) |
重叠(Overlaps): | 几何形状共享一部分但不是所有的公共点,而且相交处有他们自己相同的区域。 |
4、空间索引
四叉树索引,R树索引等。
对Geometry操作
import org.geotools.geometry.jts.JTSFactoryFinder;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
/**
* Class GeometryDemo.java
* Description Geometry 几何实体的创建,读取操作
*/
public class GeometryDemo {
private GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory( null );
/**
* create a point
* @return
*/
public Point createPoint(){
Coordinate coord = new Coordinate(109.013388, 32.715519);
Point point = geometryFactory.createPoint( coord );
return point;
}
/**
* create a rectangle(矩形)
* @return
*/
public Envelope createEnvelope(){
Envelope envelope = new Envelope(0,1,0,2);
return envelope;
}
/**
* create a point by WKT
* @return
* @throws ParseException
*/
public Point createPointByWKT() throws ParseException{
WKTReader reader = new WKTReader( geometryFactory );
Point point = (Point) reader.read("POINT (109.013388 32.715519)");
return point;
}
/**
* create multiPoint by wkt
* @return
*/
public MultiPoint createMulPointByWKT()throws ParseException{
WKTReader reader = new WKTReader( geometryFactory );
MultiPoint mpoint = (MultiPoint) reader.read("MULTIPOINT(109.013388 32.715519,119.32488 31.435678)");
return mpoint;
}
/**
*
* create a line
* @return
*/
public LineString createLine(){
Coordinate[] coords = new Coordinate[] {new Coordinate(2, 2), new Coordinate(2, 2)};
LineString line = geometryFactory.createLineString(coords);
return line;
}
/**
* create a line by WKT
* @return
* @throws ParseException
*/
public LineString createLineByWKT() throws ParseException{
WKTReader reader = new WKTReader( geometryFactory );
LineString line = (LineString) reader.read("LINESTRING(0 0, 2 0)");
return line;
}
/**
* create multiLine
* @return
*/
public MultiLineString createMLine(){
Coordinate[] coords1 = new Coordinate[] {new Coordinate(2, 2), new Coordinate(2, 2)};
LineString line1 = geometryFactory.createLineString(coords1);
Coordinate[] coords2 = new Coordinate[] {new Coordinate(2, 2), new Coordinate(2, 2)};
LineString line2 = geometryFactory.createLineString(coords2);
LineString[] lineStrings = new LineString[2];
lineStrings[0]= line1;
lineStrings[1] = line2;
MultiLineString ms = geometryFactory.createMultiLineString(lineStrings);
return ms;
}
/**
* create multiLine by WKT
* @return
* @throws ParseException
*/
public MultiLineString createMLineByWKT()throws ParseException{
WKTReader reader = new WKTReader( geometryFactory );
MultiLineString line = (MultiLineString) reader.read("MULTILINESTRING((0 0, 2 0),(1 1,2 2))");
return line;
}
/**
* create a polygon(多边形) by WKT
* @return
* @throws ParseException
*/
public Polygon createPolygonByWKT() throws ParseException{
WKTReader reader = new WKTReader( geometryFactory );
Polygon polygon = (Polygon) reader.read("POLYGON((20 10, 30 0, 40 10, 30 20, 20 10))");
return polygon;
}
/**
* create multi polygon by wkt
* @return
* @throws ParseException
*/
public MultiPolygon createMulPolygonByWKT() throws ParseException{
WKTReader reader = new WKTReader( geometryFactory );
MultiPolygon mpolygon = (MultiPolygon) reader.read("MULTIPOLYGON(((40 10, 30 0, 40 10, 30 20, 40 10),(30 10, 30 0, 40 10, 30 20, 30 10)))");
return mpolygon;
}
/**
* create GeometryCollection contain point or multiPoint or line or multiLine or polygon or multiPolygon
* @return
* @throws ParseException
*/
public GeometryCollection createGeoCollect() throws ParseException{
LineString line = createLine();
Polygon poly = createPolygonByWKT();
Geometry g1 = geometryFactory.createGeometry(line);
Geometry g2 = geometryFactory.createGeometry(poly);
Geometry[] garray = new Geometry[]{g1,g2};
GeometryCollection gc = geometryFactory.createGeometryCollection(garray);
return gc;
}
/**
* create a Circle 创建一个圆,圆心(x,y) 半径RADIUS
* @param x
* @param y
* @param RADIUS
* @return
*/
public Polygon createCircle(double x, double y, final double RADIUS){
final int SIDES = 32;//圆上面的点个数
Coordinate coords[] = new Coordinate[SIDES+1];
for( int i = 0; i < SIDES; i++){
double angle = ((double) i / (double) SIDES) * Math.PI * 2.0;
double dx = Math.cos( angle ) * RADIUS;
double dy = Math.sin( angle ) * RADIUS;
coords[i] = new Coordinate( (double) x + dx, (double) y + dy );
}
coords[SIDES] = coords[0];
LinearRing ring = geometryFactory.createLinearRing( coords );
Polygon polygon = geometryFactory.createPolygon( ring, null );
return polygon;
}
/**
* @param args
* @throws ParseException
*/
public static void main(String[] args) throws ParseException {
GeometryDemo gt = new GeometryDemo();
Polygon p = gt.createCircle(0, 1, 2);
//圆上所有的坐标(32个)
Coordinate coords[] = p.getCoordinates();
for(Coordinate coord:coords){
System.out.println(coord.x+","+coord.y);
}
Envelope envelope = gt.createEnvelope();
System.out.println(envelope.centre());
}
}
建立四叉树索引
public static void main(String[] args) {
//创建四叉树索引
Quadtree quatree = new Quadtree();
PointInfo info = new PointInfo();
quatree.insert(new Envelope(new Coordinate(11638937, 3992178)), info);
}
注:
quatree.insert(new Envelope(new Coordinate(11638937, 3992178)), info);
当中的Coordinate代表了一个只是包含经纬度的点(point)。在jts中,还有另外一个专门的对象表示点,就是point对象,但是这里我们只是想用经纬度来建立好节点之间的关系,故而只是采用了Coordinate。
而Envelope,这个对象其实代表的是一个矩形框。Envelope的构造函数中需要给出矩形的对角坐标。但是我们这里只是有一个点,所以,jts会把这一个单独的点也作为一个矩形。
这就是说明,jts中结点不是简单的point,而是一个矩形(Envelope),至于最后的info,则是表示点的其他描述信息。
jts目前只是支持二维,三维的z坐标永远是0。
Quatree 提供了三个搜索方法,分别如下:
public List query(Envelope searchEnv) {
/**
* the items that are matched are the items in quads which overlap the
* search envelope
*/
ArrayListVisitor visitor = new ArrayListVisitor();
query(searchEnv, visitor);
return visitor.getItems();
}
public void query(Envelope searchEnv, ItemVisitor visitor) {
/**
* the items that are matched are the items in quads which overlap the
* search envelope
*/
root.visit(searchEnv, visitor);
}
/**
* Return a list of all items in the Quadtree
*/
public List queryAll() {
List foundItems = new ArrayList();
root.addAllItems(foundItems);
return foundItems;
}
每个函数的含义分别表示搜索范围搜索,范围过滤搜索和全部搜索。范围搜索只要给出一个矩形框,然后传入即可。
List<PointInfo> points = quatree.query(new Envelope(new Coordinate(
11638937, 3992178)));
for (PointInfo pointInfo : points) {
// 结果只有一个点
System.out.println(pointInfo.getName());
}
// 调整经纬度,看周围有什么
System.out.println("只能够调整经纬度,来看周围有什么,相当于地图上的周边搜索的概念");
points = quatree.query(new Envelope(new Coordinate(11638937, 3991605),
new Coordinate(11639081, 3992178)));
for (PointInfo pointInfo : points) {
System.out.println(pointInfo.getName());
}
建立R数索引
package util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequences;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
import com.vividsolutions.jts.index.strtree.STRtree;
import config.GeoConfig;
import dao.QueryTrail;
import entity.CompareValue;
import entity.GPSPoint;
import entity.Grid;
import entity.Line;
import entity.Point;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.WebClient;
public class SpatialUtil {
static String result=new String();
public static void getPolygonofWuhan(String[] args) {
Vertx vertx = Vertx.vertx();
WebClient client = WebClient.create(vertx);
client.get(80, "restapi.amap.com",
"/v3/config/district?keywords=%E6%AD%A6%E6%B1%89&subdistrict=0&key=高德地图API申请的Token&extensions=all")
.send(ar -> {
if (ar.succeeded()) {
// Obtain response
HttpResponse<Buffer> response = ar.result();
result = response.bodyAsString();
JsonObject jo = new JsonObject(result);
result = jo.getJsonArray("districts").getJsonObject(0).getString("polyline");
GeometryFactory factory=new GeometryFactory();
String[] xyStrings=result.replace("|", ";").split(";");
List<Coordinate> list=new ArrayList<>();
for(String xy:xyStrings){
String[] s_arr=xy.split(",");
double[] d_xy=new double[2];
d_xy[0]=Double.parseDouble(s_arr[0]);
d_xy[1]=Double.parseDouble(s_arr[1]);
Coordinate coor=new Coordinate(d_xy[0], d_xy[1]);
list.add(coor);
}
Coordinate[] coor_arr=list.toArray(new Coordinate[0]);
MultiPoint multiPoint=factory.createMultiPoint(coor_arr);
Geometry env=multiPoint.getEnvelope();
Coordinate[] MBR=env.getCoordinates();
for(int i=0;i<MBR.length;i++){
System.out.println(MBR[i].x+","+MBR[i].y);
}
client.close();
vertx.close();
} else {
System.out.println("Something went wrong " + ar.cause().getMessage());
}
});
}
/**
* 计算两点的距离差在哪个阈值范围内
* @param pt1
* @param pt2
* @param config 阈值的设置
* @return
*/
public static CompareValue inTolerance(Point pt1,Point pt2,GeoConfig config){
double delta=Math.sqrt(Math.pow(pt1.getX()-pt2.getX(),2)+Math.pow(pt1.getY()-pt2.getY(), 2));
double max=config.getMaxGeoRange();
double min=config.getMinGeoRange();
if(delta<min){
return CompareValue.LT;
}else if(delta<=max&&delta>=min){
return CompareValue.IN;
}else{
return CompareValue.GT;
}
}
/**
* 建立网格
* @return
*/
public static HashMap<String,Grid> createGrids(){
HashMap<String,Grid> gridMap=new HashMap<>();
double left_top_x=Double.parseDouble(PropertiesUtil.getProperties("common", "left-top").split(",")[0]);
double left_top_y=Double.parseDouble(PropertiesUtil.getProperties("common", "left-top").split(",")[1]);
double right_bottom_x=Double.parseDouble(PropertiesUtil.getProperties("common", "right-bottom").split(",")[0]);
double right_bottom_y=Double.parseDouble(PropertiesUtil.getProperties("common", "right-bottom").split(",")[1]);
int rows=Integer.parseInt(PropertiesUtil.getProperties("common", "rows"));
int cols=Integer.parseInt(PropertiesUtil.getProperties("common", "cols"));
double interval_x=Double.parseDouble(ParseDataType.parseD2s((right_bottom_x-left_top_x)/(cols*1.0),6));
double interval_y=Double.parseDouble(ParseDataType.parseD2s((left_top_y-right_bottom_y)/(rows*1.0),6));
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
Grid grid=new Grid();
grid.setCol(cols);
grid.setRow(rows);
grid.setIndex(i*cols+j+1);
Point lefttop=new Point();
Point rightbottom=new Point();
lefttop.setX(left_top_x+j*interval_x);
lefttop.setY(left_top_y-i*interval_y);
if(j==cols-1){
rightbottom.setX(right_bottom_x);
}else{
rightbottom.setX(left_top_x+(j+1)*interval_x);
}
if(i==rows-1){
rightbottom.setY(right_bottom_y);
}else{
rightbottom.setY(left_top_y-(i+1)*interval_y);
}
grid.setLefttop(lefttop);
grid.setRightbottom(rightbottom);
gridMap.put(String.valueOf(grid.getRow())+"_"+String.valueOf(grid.getCol())+"_"+String.valueOf(grid.getIndex()),grid);
}
}
return gridMap;
}
/**
* 建立网格索引
*/
public static HashMap<String, Grid> createGridIndex(){
HashMap<String, Grid> gridmap=createGrids();
int cols=Integer.parseInt(PropertiesUtil.getProperties("common", "cols"));
int rows=Integer.parseInt(PropertiesUtil.getProperties("common", "rows"));
String rbPt_s=PropertiesUtil.getProperties("common", "right-bottom");
Point rbPt=new Point();
rbPt.setX(Double.parseDouble(rbPt_s.split(",")[0]));
rbPt.setY(Double.parseDouble(rbPt_s.split(",")[1]));
String ltPt_s=PropertiesUtil.getProperties("common", "left-top");
Point ltPt=new Point();
ltPt.setX(Double.parseDouble(ltPt_s.split(",")[0]));
ltPt.setY(Double.parseDouble(ltPt_s.split(",")[1]));
double range_x=rbPt.getX()-ltPt.getX();
double range_y=ltPt.getY()-rbPt.getY();
QueryTrail query=new QueryTrail();
HashMap<String, Line> map=query.getLine();
GeoConfig config=new GeoConfig();
config.setMaxGeoRange(Double.parseDouble(PropertiesUtil.getProperties("common", "maxGeoRange")));
config.setMinGeoRange(Double.parseDouble(PropertiesUtil.getProperties("common", "minGeoRange")));
GeometryFactory factory=new GeometryFactory();
for(Entry<String, Line> entry:map.entrySet()){
Line templine=entry.getValue().sort(true);
List<Line> list=templine.filter(config);
for(Line line:list){
List<GPSPoint> gpslist=line.getCoors();
List<Coordinate> coors=new ArrayList<>();
for(GPSPoint xy:gpslist){
double x=xy.getX();
double y=xy.getY();
Coordinate coor=new Coordinate(x, y);
coors.add(coor);
}
Coordinate[] coor_arr=coors.toArray(new Coordinate[0]);
if(coor_arr.length>1){
LineString l_s=factory.createLineString(coor_arr);
Envelope env=l_s.getEnvelopeInternal();
double max_x=env.getMaxX();
double min_x=env.getMinX();
double max_y=env.getMaxY();
double min_y=env.getMinY();
int max_j=(int)((max_x-ltPt.getX())/range_x*cols);
int max_i=(int)((ltPt.getY()-max_y)/range_y*rows);
int min_j=(int)((min_x-ltPt.getX())/range_x*cols);
int min_i=(int)((ltPt.getY()-min_y)/range_y*rows);
a:for(int i=max_i;i<=min_i;i++){
for(int j=min_j;j<=max_j;j++){
Grid grid=gridmap.get(String.valueOf(rows)+"_"+String.valueOf(cols)+"_"+String.valueOf(i*cols+j+1));
Coordinate[] coor_arr1=new Coordinate[5];
coor_arr1[0]=new Coordinate(grid.getLefttop().getX(), grid.getLefttop().getY());
coor_arr1[1]=new Coordinate(grid.getLefttop().getX(), grid.getRightbottom().getY());
coor_arr1[2]=new Coordinate(grid.getRightbottom().getX(), grid.getRightbottom().getY());
coor_arr1[3]=new Coordinate(grid.getRightbottom().getX(), grid.getLefttop().getY());
coor_arr1[4]=new Coordinate(grid.getLefttop().getX(), grid.getLefttop().getY());
CoordinateArraySequence seq=new CoordinateArraySequence(coor_arr1);
LinearRing ring = new LinearRing(seq, new GeometryFactory());
Polygon poly=new Polygon(ring, null, new GeometryFactory());
if(l_s.crosses(poly)||poly.covers(l_s)){
grid.addLine(line);
break a;
}
}
}
}else{
GPSPoint point=gpslist.get(0);
int j=(int)((point.getX()-ltPt.getX())/range_x*cols);
int i=(int)((ltPt.getY()-point.getY())/range_y*rows);
Grid grid=gridmap.get(String.valueOf(rows)+"_"+String.valueOf(cols)+"_"+String.valueOf(i*cols+j+1));
grid.addLine(line);
}
}
}
System.out.println("网格索引创建成功!");
return gridmap;
}
/**
* 建立R树索引
* @return
*/
public static STRtree createRtree(){
QueryTrail query=new QueryTrail();
HashMap<String, Line> map=query.getLine();
GeoConfig config=new GeoConfig();
config.setMaxGeoRange(Double.parseDouble(PropertiesUtil.getProperties("common", "maxGeoRange")));
config.setMinGeoRange(Double.parseDouble(PropertiesUtil.getProperties("common", "minGeoRange")));
STRtree tree=new STRtree();
for(Entry<String, Line> entry:map.entrySet()){
Line templine=entry.getValue().sort(true);
List<Line> list=templine.filter(config);
for(Line line:list){
GeometryFactory factory=new GeometryFactory();
List<Coordinate> coors=new ArrayList<>();
List<GPSPoint> gpslist=line.getCoors();
for(GPSPoint xy:gpslist){
double x=xy.getX();
double y=xy.getY();
Coordinate coor=new Coordinate(x, y);
coors.add(coor);
}
Coordinate[] coor_arr=coors.toArray(new Coordinate[0]);
if(coor_arr.length>1){
LineString lineStr=factory.createLineString(coor_arr);
Envelope env=lineStr.getEnvelopeInternal();
tree.insert(env, lineStr);
}else{
com.vividsolutions.jts.geom.Point point=factory.createPoint(coor_arr[0]);
Envelope env=point.getEnvelopeInternal();
tree.insert(env, point);
}
}
}
tree.build();
System.out.println("R树索引创建成功!");
return tree;
}
/**
* R树查询
* @param tree
* @param searchGeo
* @return
*/
public static List<Geometry> query(STRtree tree,Geometry searchGeo){
List <Geometry> result=new ArrayList<>();
@SuppressWarnings("rawtypes")
List list=tree.query(searchGeo.getEnvelopeInternal());
for(int i=0;i<list.size();i++){
Geometry lineStr=(Geometry)list.get(i);
if(lineStr.intersects(searchGeo)){
result.add(lineStr);
}
}
return result;
}
//根据两点生成矩形搜索框
public static Geometry generateSearchGeo(double left_top_x,double left_top_y,double right_bottom_x,double right_bottom_y){
Coordinate[] coors=new Coordinate[4];
coors[0]=new Coordinate(left_top_x, left_top_y);
coors[1]=new Coordinate(right_bottom_x, left_top_y);
coors[2]=new Coordinate(left_top_x, right_bottom_y);
coors[3]=new Coordinate(right_bottom_x, right_bottom_y);
LinearRing ring=new LinearRing(new CoordinateArraySequence(coors),new GeometryFactory());
return ring;
}
}
common.properties:
#两点间最大间隔(经纬度差值,目前按照江的宽度)
maxGeoRange=0.002
#maxGeoRange=0.012
#两点间最小间隔(经纬度差值,目前按照地图上一栋楼的宽度)
minGeoRange=0.0005
#minGeoRange=0.0017
#武汉市外包矩形的范围
#左上角
left-top=113.702282,31.36127
#左下角
left-bottom=113.702282,29.969079
#右上角
right-top=115.082574,31.36127
#右下角
right-bottom=115.082574,29.969079
#设定的网格的行数
rows=10
#设定的网格的列数
cols=10
#坐标保留小数点后几位
CoorAbs=10000
package entity;
import java.util.Date;
/**
* 点,描述点的位置,所属网格和所属线条
* @author KingWang
*
*/
public class GPSPoint extends Point{
private Date date=new Date();
private Grid grid=new Grid();
private Line line=new Line();
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Grid getGrid() {
return grid;
}
public void setGrid(Grid grid) {
this.grid = grid;
}
public Line getLine() {
return line;
}
public void setLine(Line line) {
this.line = line;
}
}
package entity;
import java.util.HashSet;
public class Grid {
private int index=0;
private int col=0;
private int row=0;
private Point lefttop=new Point();
private Point rightbottom=new Point();
private HashSet<Line> set=new HashSet<>();
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public int getCol() {
return col;
}
public void setCol(int col) {
this.col = col;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public Point getLefttop() {
return lefttop;
}
public void setLefttop(Point lefttop) {
this.lefttop = lefttop;
}
public Point getRightbottom() {
return rightbottom;
}
public void setRightbottom(Point rightbottom) {
this.rightbottom = rightbottom;
}
public HashSet<Line> getSet() {
return set;
}
public void setSet(HashSet<Line> set) {
this.set = set;
}
public void addLine(Line line){
this.set.add(line);
}
}
package entity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import config.GeoConfig;
import util.SpatialUtil;
/**
* 线,点串,描述整条轨迹
* @author KingWang
*
*/
public class Line {
/**
* 轨迹的id
*/
private String id="";
/**
* 按照顺序存储点轨迹
*/
private List<GPSPoint> coors=new ArrayList<>();
/**
* 经过的网格,按照轨迹顺序存储
*/
private List<Grid> grids=new ArrayList<>();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<GPSPoint> getCoors() {
return coors;
}
public void setCoors(List<GPSPoint> coors) {
this.coors = coors;
}
public List<Grid> getGrids() {
return grids;
}
public void setGrids(List<Grid> grids) {
this.grids = grids;
}
public void addPoint(GPSPoint p){
this.coors.add(p);
}
public void removePoint(int index){
this.coors.remove(index);
}
public Line sort(boolean isTimeAsc){
List<GPSPoint> list=this.getCoors();
Collections.sort(list, (point1,point2)->{
if(point1.getDate().after(point2.getDate())){
if(isTimeAsc){
return 1;
}else{
return -1;
}
}else{
if(isTimeAsc){
return -1;
}else{
return 1;
}
}
});
return this;
}
/**
* 对线坐标串进行粗处理,太密的点删掉,太远的点打断成两段
* @param config
* @return
*/
public List<Line> filter(GeoConfig config){
List<Line> resultList=new ArrayList<>();
List<GPSPoint> list=new CopyOnWriteArrayList<>(this.getCoors());
Point lastPt=new Point();
int i=0;
int lastCutIndex=0;
for(GPSPoint point:list){
if(i>0&&SpatialUtil.inTolerance(lastPt,point,config)==CompareValue.GT){
List<GPSPoint> list_temp=new ArrayList<>();
list_temp.addAll(list.subList(lastCutIndex, i));
Line line_temp=new Line();
line_temp.setCoors(list_temp);
line_temp.setId(String.valueOf(System.currentTimeMillis()+new Random().nextInt(10)));
resultList.add(line_temp);
lastCutIndex=i;
}else if(i>0&&SpatialUtil.inTolerance(lastPt, point, config)==CompareValue.LT){
list.remove(i);
i--;
}
lastPt=point;
i++;
}
if(lastCutIndex==i){
Line line_temp=new Line();
line_temp.setCoors(this.getCoors());
line_temp.setId(String.valueOf(System.currentTimeMillis()+new Random().nextInt(10)));
resultList.add(line_temp);
}else{
List<GPSPoint> list_temp=new ArrayList<>();
list_temp.addAll(list.subList(lastCutIndex, i));
Line line_temp=new Line();
line_temp.setCoors(list_temp);
line_temp.setId(String.valueOf(System.currentTimeMillis()+new Random().nextInt(10)));
resultList.add(line_temp);
}
return resultList;
}
}
package entity;
import config.GeoConfig;
/**
* 点,描述点的位置
* @author KingWang
*
*/
public class Point {
private double x=0.0;
private double y=0.0;
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
}