微信搜索:“二十同学” 公众号,欢迎关注一条不一样的成长之路

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     MultiPointLineString     LinearRing  封闭的线条MultiLineString    多条线PolygonMultiPolygon         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 responseHttpResponse<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;}
}

geotools应用-JTS生产四叉树索引和R树索引相关推荐

  1. 基于R树索引的点面关系判断以及效率优化统计

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 在之前的博客中,我分别介绍了基于网格的空间索引(http:// ...

  2. MySQL 索引 :哈希索引、B+树索引、最左前缀匹配规则、全文索引

    文章目录 索引 什么是索引 索引优缺点与适用场景 常见的索引 哈希索引 自适应哈希索引 B+树索引 聚集索引 非聚集索引 使用方法 联合索引 最左前缀匹配规则 覆盖索引 全文索引 使用方法 索引 什么 ...

  3. MySQL 索引 :哈希索引、B+树索引、全文索引

    文章目录 索引 引言 常见的索引 哈希索引 自适应哈希索引 B+树索引 聚集索引 非聚集索引 使用方法 联合索引 最左前缀匹配规则 覆盖索引 全文索引 使用方法 索引 引言 为什么需要索引? 倘若不使 ...

  4. 轻松理解 MySQL InnoDB 索引、B+树索引、查询原理

    博主:爱码叔 个人博客站点: icodebook 公众号:爱码叔漫画软件设计(搜:爱码叔) 专注于软件设计与架构.技术管理.擅长用通俗易懂的语言讲解技术.对技术管理工作有自己的一定见解.文章会第一时间 ...

  5. Hash索引和B+树索引

    hash索引底层就是hash表,进行查找时,调用一次hash函数就可以获取到相应的键值,之后进行回表查询获得实际数据.B+树底层实现是多路平衡查找树.对于每一次的查询都是从根节点出发,查找到叶子节点方 ...

  6. 5.算法进阶——kafka消息查询(二分法)——稀疏索引与B+树索引的对比

    Kafka介绍 Kafka 是一款性能强大且相当常用的分布式消息队列,常常用于对流量进行消峰.解耦系统和异步处理部分逻辑以提高性能的场景. 在kafka中,所有的消息都以日志的形式存储.这种日志只允许 ...

  7. B+树与B树的区别、Hash索引与B+树索引的区别

    目录 B+ 树和 B 树的区别 B+树的结构 B树的结构 B+树索引与Hash索引的区别 B+ 树和 B 树的区别 1.b树(balance tree),B+树是B树的改进版 2.B+树非叶子节点仅用 ...

  8. 如何在vs中创建r树索引代码_线段树详解与实现

    此篇文章用于记录<玩转数据结构>课程的学习笔记 什么是线段树 线段树也被称为区间树,英文名为Segment Tree或者Interval tree,是一种高级的数据结构.这种数据结构更多出 ...

  9. 从数据库库索引说到空间数据索引

    要说空间索引,我们不得不先说一下数据库索引. 1. 数据库索引 1.1. 什么是数据库索引 索引是定义在table基础之上,有助于无需检查所有记录而快速定位所需记录的一种辅助存储结构,由一系列存储在磁 ...

最新文章

  1. KVM虚拟机添加虚拟磁盘
  2. iOS编程(双语版) - 视图 - 基本概念
  3. 构建高可用ZooKeeper集群(转载)
  4. 脚本大全_抖音文案大全2020励志:抖音最火励志搞笑句子,直接套用上热门
  5. 软件工程 speedsnail 冲刺3
  6. Docker 私有仓库最简便的搭建方法
  7. 云栖·追踪云原生|Serverless入围阿里云十大核心技术
  8. mysql 枚举类型 映射_model类中enum类型与数据库字段的映射
  9. android的oomkiller_Android Low memory killer
  10. 漫话:如何给女朋友解释什么是3PC?
  11. TCP/IP原理 (四) IP编址
  12. ASP.NET2.0服务器控件之自定义状态管理
  13. Android 与 JavaScript 相互调用桥梁 JSBridge
  14. OpenStack-Ocata版+CentOS7.6 云平台环境搭建 — 3.安装配置OpenStack认证服务(keystone)...
  15. Linux 使用 ffmpeg 开发
  16. matlab实现文本内容批量替换
  17. Snmp拓扑结构php,基于SNMP的网络拓扑结构生成
  18. GTX 1070Ti正式发布!iGame Vulcan X家族再添新成员
  19. Photoshop插件-charIDToTypeID-PIStringTerminology.h-不同值的解释及参考-脚本开发-PS插件
  20. Textpad 1.7下载

热门文章

  1. DeepMind重大突破:AI进化出大脑级导航能力,像动物一样会“抄小路”
  2. 最全Mac系统快捷键一览 学会了一秒变大神!
  3. java:1:错误:写入Hello时出错:Hello.class(拒绝访问)
  4. linux红帽分区安装教程,RedHat Linux 9.0 硬盘安装教程手把手全部详细教程
  5. Stata: VAR (向量自回归) 模型
  6. CGBitmapContextCreate函数
  7. C++描述 645.蛇形矩阵
  8. 关于找不到mfc120u.dll文件错误与0xc000007b错误的解决方案
  9. 【最终方法】百度移动适配 url校验不通过的解决方法,URL适配规则
  10. 广东阶段丰收成定局 国稻种芯·中国水稻节:肇庆鱼塘上首次