- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
项目需求,需要很多的空间几何计算,例如:点、线、面之间的距离、面积、长度、相交、最短距离点等,由于相关文档是真的缺乏,墙内墙外看了大量的博客和文档收集和验证了很久。现将结论和知识点整理发出来。
地理坐标系(Geographic coordinate system),是以经纬度为地图的存储单位。很明显地理坐标系是球面坐标系统。我们要将地球上的数字化信息存放到球面坐标系统上,如何进行操作呢?地球是一个不规则的椭球,如何将数据信息以科学的方法存放到椭球上?这必然要求
我们找到这样的一个椭球体。这样的椭球体具有特点:可以量化计算的。具有长半轴,短
半轴,偏心率。以下几行便是Krasovsky_1940椭球及其相应参数。
Spheroid: Krasovsky_1940
Semimajor Axis: 6378245.000000000000000000
Semiminor Axis: 6356863.018773047300000000
Inverse Flattening(扁率): 298.300000000000010000
然而有了这个椭球体以后还不够,还需要一个大地基准面将这个椭球定位。在坐标系统描
述中,可以看到有这么一行:
Datum: D_Beijing_1954
表示,大地基准面是D_Beijing_1954。
投影坐标系统,实质上便是平面坐标系统,其地图单位通常为米。
投影的意义:将球面坐标转化为平面坐标的过程便称为投影。
地理坐标系右下角显示Degrees(度)表示经纬度;投影显示的是Meters(米)
平常看到的WGS84、高德、百度坐标系都是地理坐标系,当我们需要计算距离、面积、长度时需要用投影坐标系
利用一定数学法则把地球表面转换到平面上的理论和方法称为地图投影。由于地球表面是一个不可展平的曲面,所以运用任何数学方法进行投影转换都会产生误差和变形,为按照不同的需求缩小误差,就产生了各种投影方式,如圆柱投影、圆锥投影、等角投影、等面积投影、切投影、割投影等。
一种正轴等角切圆柱投影。
WGS84坐标系
地球坐标系,国际上通用的坐标系。设备一般包含GPS芯片或者北斗芯片获取的经纬度为WGS84地理坐标系。
GCJ02坐标系
火星坐标系,是由中国国家测绘局制订的地理信息系统的坐标系统。由WGS84坐标系经加密后的坐标系。
BD09坐标系
百度地图使用坐标系,GCJ02坐标系经加密后的坐标系。
转换方法
国际通用的转换做法:
百度的做法:
需要2个依赖库,这里要注意org.geotool
库的下载源。
<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-epsg-hsql</artifactId>
<version>22-RC</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-main</artifactId>
<version>22-RC</version>
</dependency>
<repositories>
<repository>
<id>geotools</id>
<name>geotools</name>
<url>http://maven.icm.edu.pl/artifactory/repo/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
转换代码示例
// WGS84(一般项目中常用的是CSR:84和EPSG:4326)
CoordinateReferenceSystem sourceCRS = CRS.decode("CRS:84");
// Pseudo-Mercator(墨卡托投影)
CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:3857");
MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS, false);
Geometry geometryMercator = JTS.transform(geometry, transform);
// 面积、周长
System.out.println(geometryMercator.getArea());
System.out.println(geometryMercator.getLength());
JTS包下的Geometry等类其实是代表的空间几何,它所提供的几何计算只是单纯的值计算,而我们提到的根据GIS经纬度等获取面积周长等其实是需要放到对应坐标系中才有意义。
墨卡托坐标
EPSG:3857
坐标系。投影坐标系,EPSG:3857 的数据一般是这种的。[12914838.35,4814529.9]
,看上去相对数值较大。不利于存储,比较占内存。
WGS-84:是国际标准,GPS坐标(Google Earth使用、或者GPS模块)
EPSG:4326 的数据一般是这种的。[22.37,114.05]
。利于存储,可读性高
// 2437 GCJ-02:中国坐标偏移标准,Google Map、高德、腾讯使用
另一种方式,之后研究
https://blog.csdn.net/u010410697/article/details/110003422
Geotools是一个java类库,它提供了很多的标准类和方法来处理空间数据,同时这个类库是构建在OGC标准之上的,是OGC思想的一种实现。而OGC是国际标准,所以geotools将来必定会成为开源空间数据处理的主要工具,目前的大部分开源软件,如udig,geoserver等,对空间数据的处理都是由geotools来做支撑。而其他很多的web服务,命令行工具和桌面程序都可以由geotools来实现。
中文文档:https://max.book118.com/html/2019/0624/6154225215002041.shtm
工具包+相关文档下载:https://download.csdn.net/download/abu935009066/16208250
JTS(Java Topology Suite) Java拓扑套件,是Java的处理地理数据的API,它提供以下功能:
JTS支持一套完整的二元谓词操作。二元谓词方法将两个几何图形作为参数,返回一个布尔值来表示几何图形是否有指定的空间关系。它支持的空间关系有:相等(equals)、分离(disjoint)、相交(intersect)、相接(touches)、交叉(crosses)、包含于(within)、包含(contains)、覆盖/覆盖于(overlaps)。同时,也支持一般的关系(relate)操作符。relate可以被用来确定维度扩展的九交模型(DE-9IM),它可以完全的描述两个几何图形的关系。
https://locationtech.github.io/jts/
https://github.com/locationtech/jts
maven仓库
看了下vividsolutions于2015年就停在更新了,好像在哪儿看过,jts由vividsolutions变为的locationtech,一个爹 应该是。选locationtech这个就完事了
JTS提供了以下空间数据类型:
多数的空间数据模型都是遵从这个的。
private GeometryFactory geometryFactory = new GeometryFactory();
ByCoordinate坐标
Coordinate coord = new Coordinate(109.013388, 32.715519);
Point point = geometryFactory.createPoint( coord );
ByWKT
WKTReader reader = new WKTReader( geometryFactory );
Point point = (Point) reader.read("POINT (109.013388 32.715519)");
WKTReader reader = new WKTReader( geometryFactory );
MultiPoint mpoint = (MultiPoint) reader.read("MULTIPOINT(109.013388 32.715519,119.32488 31.435678)");
Coordinate[] coords = new Coordinate[] {new Coordinate(2, 2), new Coordinate(2, 2)};
LineString line = geometryFactory.createLineString(coords);
// wkt
WKTReader reader = new WKTReader( geometryFactory );
LineString line = (LineString) reader.read("LINESTRING(0 0, 2 0)");
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);
// wkt
WKTReader reader = new WKTReader( geometryFactory );
MultiLineString line = (MultiLineString) reader.read("MULTILINESTRING((0 0, 2 0),(1 1,2 2))");
LinearRing lr = new GeometryFactory().createLinearRing(new Coordinate[]{new Coordinate(0, 0), new Coordinate(0, 10), new Coordinate(10, 10), new Coordinate(10, 0), new Coordinate(0, 0)});
WKTReader reader = new WKTReader( geometryFactory );
Polygon polygon = (Polygon) reader.read("POLYGON((20 10, 30 0, 40 10, 30 20, 20 10))");
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)))");
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);
关系 | 解释 |
---|---|
相等(Equals): | 几何形状拓扑上相等。 |
不相交(Disjoint): | 几何形状没有共有的点。 |
相交(Intersects): | 几何形状至少有一个共有点(区别于脱节) |
接触(Touches): | 几何形状有至少一个公共的边界点,但是没有内部点。 |
交叉(Crosses): | 几何形状共享一些但不是所有的内部点。 |
内含(Within): | 几何形状A的线都在几何形状B内部。 |
包含(Contains): | 几何形状B的线都在几何形状A内部(区别于内含) |
重叠(Overlaps): | 几何形状共享一部分但不是所有的公共点,而且相交处有他们自己相同的区域。 |
举例相交,其他类似
/**
* 至少一个公共点(相交)
* @return
* @throws ParseException
*/
public boolean intersectsGeo() throws ParseException{
WKTReader reader = new WKTReader( geometryFactory );
LineString geometry1 = (LineString) reader.read("LINESTRING(0 0, 2 0, 5 0)");
LineString geometry2 = (LineString) reader.read("LINESTRING(0 0, 0 2)");
Geometry interPoint = geometry1.intersection(geometry2);//相交点
System.out.println(interPoint.toText());//输出 POINT (0 0)
return geometry1.intersects(geometry2);
}
JTS支持基本的空间分析方法。空间分析方法使用一个或两个几何图形作为参数,返回一个新构造的几何图形。
分析 | 解释 |
---|---|
缓冲区分析(Buffer) | 包含所有的点在一个指定距离内的多边形和多多边形 |
凸壳分析(ConvexHull) | 包含几何形体的所有点的最小凸壳多边形(外包多边形) |
交叉分析(Intersection) | A∩B 交叉操作就是多边形AB中所有共同点的集合 |
联合分析(Union) | AUB AB的联合操作就是AB所有点的集合 |
差异分析(Difference) | (A-A∩B) AB形状的差异分析就是A里有B里没有的所有点的集合 |
对称差异分析(SymDifference) | (AUB-A∩B) AB形状的对称差异分析就是位于A中或者B中但不同时在AB中的所有点的集合 |
// WGS84(一般项目中常用的是CRS:84和EPSG:4326)
CoordinateReferenceSystem sourceCRS = CRS.decode("CRS:84");
// Pseudo-Mercator(墨卡托投影)
CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:3857");
MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS, false);
GeometryFactory GeometryFactory = new GeometryFactory();
Coordinate k96 = new Coordinate(117.41722, 31.975379);
Coordinate k97 = new Coordinate(117.426387, 31.970712);
Geometry line = JTS.transform(GeometryFactory.createLineString(new Coordinate[]{k96, k97}), transform);
//double rate1 = Math.cos(Math.toRadians(k96.y)); 距离短的话乘以这个就行, 大概为: 0.8482973000510488
double rate = Math.cos((Math.toRadians(k96.y) + Math.toRadians(k97.y)) / 2.000000);//距离长的话用这个
System.out.println("rate: " + rate);
// 面积、周长
System.out.println(line.getArea());// 面积未验证是乘以 rate 还是其平方
System.out.println(line.getLength() * rate);
Coordinate tmp = new Coordinate(117.417145, 31.975465);
Geometry point = JTS.transform(GeometryFactory.createPoint(tmp), transform);
System.out.println(point.distance(line) * rate);
工具包+相关文档下载:https://download.csdn.net/download/abu935009066/16208250
偶然间发现可以使用jts中的工具可视化我们的WKT数据。
需要java环境
GeometryFactory gf = JTSFactoryFinder.getGeometryFactory(null);
WKTReader reader = new WKTReader(gf);
Geometry line2 = reader.read("LINESTRING(0 0, 10 0, 10 10, 20 10)");
Coordinate c = new Coordinate(5, 5);
PointPairDistance ppd = new PointPairDistance();
DistanceToPoint.computeDistance(line2, c, ppd);
System.out.println(ppd.getDistance());
for (Coordinate cc : ppd.getCoordinates()) {
System.out.println(cc);
}
// create ring: P1(0,0) - P2(0,10) - P3(10,10) - P4(0,10)
LinearRing lr = new GeometryFactory().createLinearRing(new Coordinate[]{new Coordinate(0,0), new Coordinate(0,10), new Coordinate(10,10), new Coordinate(10,0), new Coordinate(0,0)});
// create line: P5(5, -1) - P6(5, 11) -> crossing the ring vertically in the middle
LineString ls = new GeometryFactory().createLineString(new Coordinate[]{new Coordinate(5,-1), new Coordinate(5,11)});
// calculate intersection points
Geometry intersectionPoints = lr.intersection(ls);
// simple output of points
for(Coordinate c : intersectionPoints.getCoordinates()){
System.out.println(c.toString());
}
创建一个包含在设定距离内的所有点的面或多面(想要圆,但是没有。。。):
geometry = point
Geometry buffer = geometry.buffer( 2.0 ); // note distance is in same units as geometry
已知:起点、终点、道路
求解:其在道路上的子轨迹
GeometryFactory GeometryFactory = new GeometryFactory();
WKTReader reader = new WKTReader(GeometryFactory);
Geometry geom = reader.read("LINESTRING(0 0, 10 0, 10 10, 20 10)");
LocationIndexedLine lil = new LocationIndexedLine(geom);
LinearLocation start = lil.indexOf(new Coordinate(8, 5));
LinearLocation end = lil.indexOf(new Coordinate(17, 10));
Geometry result = lil.extractLine(start, end);
System.out.println(result.toText());
// 结果
LINESTRING (10 5, 10 10, 17 10)
已知:道路、在道路的距离
求解:到起点坐标距离的点
public static Coordinate lengthOnLineString2(Geometry roadLine, double length) {
LocationIndexedLine locationIndexedLine = new LocationIndexedLine(roadLine);
LinearLocation linearLocation = LengthLocationMap.getLocation(roadLine, length);
Coordinate result = locationIndexedLine.extractPoint(linearLocation);
return result;
}
参考:
我正在编写一个具有以下签名的 Java 方法。 void Logger(Method method, Object[] args); 如果一个方法(例如 ABC() )调用此方法 Logger,它应该
我是 Java 新手。 我的问题是我的 Java 程序找不到我试图用作的图像文件一个 JButton。 (目前这段代码什么也没做,因为我只是得到了想要的外观第一的)。这是我的主课 代码: packag
好的,今天我在接受采访,我已经编写 Java 代码多年了。采访中说“Java 垃圾收集是一个棘手的问题,我有几个 friend 一直在努力弄清楚。你在这方面做得怎么样?”。她是想骗我吗?还是我的一生都
我的 friend 给了我一个谜语让我解开。它是这样的: There are 100 people. Each one of them, in his turn, does the following
如果我将使用 Java 5 代码的应用程序编译成字节码,生成的 .class 文件是否能够在 Java 1.4 下运行? 如果后者可以工作并且我正在尝试在我的 Java 1.4 应用程序中使用 Jav
有关于why Java doesn't support unsigned types的问题以及一些关于处理无符号类型的问题。我做了一些搜索,似乎 Scala 也不支持无符号数据类型。限制是Java和S
我只是想知道在一个 java 版本中生成的字节码是否可以在其他 java 版本上运行 最佳答案 通常,字节码无需修改即可在 较新 版本的 Java 上运行。它不会在旧版本上运行,除非您使用特殊参数 (
我有一个关于在命令提示符下执行 java 程序的基本问题。 在某些机器上我们需要指定 -cp 。 (类路径)同时执行java程序 (test为java文件名与.class文件存在于同一目录下) jav
我已经阅读 StackOverflow 有一段时间了,现在我才鼓起勇气提出问题。我今年 20 岁,目前在我的家乡(罗马尼亚克卢日-纳波卡)就读 IT 大学。足以介绍:D。 基本上,我有一家提供簿记应用
我有 public JSONObject parseXML(String xml) { JSONObject jsonObject = XML.toJSONObject(xml); r
我已经在 Java 中实现了带有动态类型的简单解释语言。不幸的是我遇到了以下问题。测试时如下代码: def main() { def ks = Map[[1, 2]].keySet()
一直提示输入 1 到 10 的数字 - 结果应将 st、rd、th 和 nd 添加到数字中。编写一个程序,提示用户输入 1 到 10 之间的任意整数,然后以序数形式显示该整数并附加后缀。 public
我有这个 DownloadFile.java 并按预期下载该文件: import java.io.*; import java.net.URL; public class DownloadFile {
我想在 GUI 上添加延迟。我放置了 2 个 for 循环,然后重新绘制了一个标签,但这 2 个 for 循环一个接一个地执行,并且标签被重新绘制到最后一个。 我能做什么? for(int i=0;
我正在对对象 Student 的列表项进行一些测试,但是我更喜欢在 java 类对象中创建硬编码列表,然后从那里提取数据,而不是连接到数据库并在结果集中选择记录。然而,自从我这样做以来已经很长时间了,
我知道对象创建分为三个部分: 声明 实例化 初始化 classA{} classB extends classA{} classA obj = new classB(1,1); 实例化 它必须使用
我有兴趣使用 GPRS 构建车辆跟踪系统。但是,我有一些问题要问以前做过此操作的人: GPRS 是最好的技术吗?人们意识到任何问题吗? 我计划使用 Java/Java EE - 有更好的技术吗? 如果
我可以通过递归方法反转数组,例如:数组={1,2,3,4,5} 数组结果={5,4,3,2,1}但我的结果是相同的数组,我不知道为什么,请帮助我。 public class Recursion { p
有这样的标准方式吗? 包括 Java源代码-测试代码- Ant 或 Maven联合单元持续集成(可能是巡航控制)ClearCase 版本控制工具部署到应用服务器 最后我希望有一个自动构建和集成环境。
我什至不知道这是否可能,我非常怀疑它是否可能,但如果可以,您能告诉我怎么做吗?我只是想知道如何从打印机打印一些文本。 有什么想法吗? 最佳答案 这里有更简单的事情。 import javax.swin
我是一名优秀的程序员,十分优秀!