geotools应用-JTS生产四叉树索引和R树索引

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

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;
    }
}

 

已标记关键词 清除标记
表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符 “速评一下”
©️2020 CSDN 皮肤主题: 点我我会动 设计师:上身试试 返回首页