微信搜索:“二十同学” 公众号,欢迎关注一条不一样的成长之路
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。
Point MultiPoint LineString LinearRing 封闭的线条 MultiLineString 多条线 Polygon MultiPolygon GeometryCollection 包括点,线,面
里面最主要的几个类,GeometryFactory,Geometry,Envelope以及上面提到的几种常用数据类型。
Geometry类:所有的空间数据类型,点,线,面,多点,环,多边形等等都是继承自Geometry类的。
Envelope类:该类就是描述一个空间几何对象的外包矩形,由max_x,max_y,min_x,min_y组成。
3、空间关系
空间关系主要是由九交模型来描述的,九交模型的讲解可以参考:九交模型的讲解
至于在JTS中的对应的关系,就是以下几种:
|
相等(Equals): |
几何形状拓扑上相等。 |
|
脱节(Disjoint): |
几何形状没有共有的点。 |
|
相交(Intersects): |
几何形状至少有一个共有点(区别于脱节) |
|
接触(Touches): |
几何形状有至少一个公共的边界点,但是没有内部点。 |
|
交叉(Crosses): |
几何形状共享一些但不是所有的内部点。 |
|
内含(Within): |
几何形状A的线都在几何形状B内部。 |
|
包含(Contains): |
几何形状B的线都在几何形状A内部(区别于内含) |
|
重叠(Overlaps): |
几何形状共享一部分但不是所有的公共点,而且相交处有他们自己相同的区域。 |
对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.); 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.)"); 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.,119.32488 31.)"); 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(, )), info); }
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
points = quatree.query(new Envelope(new Coordinate( , ))); for (PointInfo pointInfo : points) { // 结果只有一个点 System.out.println(pointInfo.getName()); } // 调整经纬度,看周围有什么 System.out.println("只能够调整经纬度,来看周围有什么,相当于地图上的周边搜索的概念"); points = quatree.query(new Envelope(new Coordinate(, ), new Coordinate(, ))); 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
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
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
=min){ return CompareValue.IN; }else{ return CompareValue.GT; } } / * 建立网格 * @return */ public static HashMap
createGrids(){ HashMap
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
createGridIndex(){ HashMap
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
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
entry:map.entrySet()){ Line templine=entry.getValue().sort(true); List
list=templine.filter(config); for(Line line:list){ List
gpslist=line.getCoors(); List
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
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
entry:map.entrySet()){ Line templine=entry.getValue().sort(true); List
list=templine.filter(config); for(Line line:list){ GeometryFactory factory=new GeometryFactory(); List
coors=new ArrayList<>(); List
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
query(STRtree tree,Geometry searchGeo){ List
result=new ArrayList<>(); @SuppressWarnings("rawtypes") List list=tree.query(searchGeo.getEnvelopeInternal()); for(int i=0;i
common.properties:
#两点间最大间隔(经纬度差值,目前按照江的宽度) maxGeoRange=0.002 #maxGeoRange=0.012 #两点间最小间隔(经纬度差值,目前按照地图上一栋楼的宽度) minGeoRange=0.0005 #minGeoRange=0.0017 #武汉市外包矩形的范围 #左上角 left-top=113.,31.36127 #左下角 left-bottom=113.,29. #右上角 right-top=115.082574,31.36127 #右下角 right-bottom=115.082574,29. #设定的网格的行数 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
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
getSet() { return set; } public void setSet(HashSet
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
coors=new ArrayList<>(); / * 经过的网格,按照轨迹顺序存储 */ private List
grids=new ArrayList<>(); public String getId() { return id; } public void setId(String id) { this.id = id; } public List
getCoors() { return coors; } public void setCoors(List
coors) { this.coors = coors; } public List
getGrids() { return grids; } public void setGrids(List
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
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
filter(GeoConfig config){ List
resultList=new ArrayList<>(); List
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
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
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; } }
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/220347.html原文链接:https://javaforall.net
