- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
JTS Topology Suite(Java Topology Suite)是一个开源的Java软件库,它为欧几里得平面线性几何提供了一个对象模型以及一组基本的几何函数。
JTS 特性:https://locationtech.github.io/jts/jts-features.html
GitHub(JTS):https://github.com/locationtech/jts
JTS java doc:http://locationtech.github.io/jts/javadoc/overview-summary.html
GeoTools(JTS):https://docs.geotools.org/latest/userguide/library/jts/index.html
wikipedia(JTS):https://en.wikipedia.org/wiki/JTS_Topology_Suite
wikipedia(WKT):https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry
PostGIS 拓扑关系:https://postgis.net/docs/reference.html#idm15481
polygon 和 multipolygon 的区别:https://gis.stackexchange.com/questions/225368/understanding-difference-between-polygon-and-multipolygon-for-shapefiles-in-qgis/225373
几何类型 | WKT |
---|---|
Point | POINT (30 10) |
LineString | LINESTRING (30 10, 10 30, 40 40) |
Polygon | POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10),(20 30, 35 35, 30 20, 20 30)) |
Polygon-with-hole | POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10), (20 30, 35 35, 30 20, 20 30)) |
MultiPoint | MULTIPOINT ((10 40), (40 30), (20 20), (30 10)) |
MultiPoint | MULTIPOINT (10 40, 40 30, 20 20, 30 10) |
MultiLineString | MULTILINESTRING ((10 10, 20 20, 10 40),(40 40, 30 30, 40 20, 30 10)) |
MultiPolygon | MULTIPOLYGON (((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5))) |
MultiPolygon-with-hole | MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20))) |
GeometryCollection | GEOMETRYCOLLECTION (POINT (40 10), LINESTRING (10 10, 20 20, 10 40), POLYGON ((40 40, 20 45, 45 30, 40 40))) |
关键字 | 说明 | 参考 |
---|---|---|
equals (相等) | 如果两个几何在空间中包含相同的一组点,则返回 true | ST_Equals |
disjoint(不相交) | 如果两个几何在空间上不相交(它们没有共同点),则返回 true | ST_Disjoint |
intersects(相交) | 如果两个几何/地理在 2D 空间上相交(至少有一个共同点),则返回 true | ST_Intersects |
touches(接触) | 如果两个几何体至少有一个共同点,但它们的内部不相交,则返回 true | ST_Touches |
crosses(交叉) | 如果两个几何具有一些(但不是全部)共同的内部点,则返回 true | ST_Crosses |
within(内含) | 如果几何 A 完全在几何 B 内部,则返回 true | ST_Within |
contains (包含) | 当且仅当 B 的任何点都不在 A 的外部,并且 B 内部的至少一个点在 A 的内部时,才返回 true | ST_Contains |
overlaps(重叠) | 如果两个几何体相交并具有相同的维度,但彼此不完全包含,则返回 true | ST_Overlaps |
关键字 | 说明 | 参考 |
---|---|---|
buffer(缓冲区) | 返回一个几何图形,该几何图形涵盖距几何图形给定距离内的所有点 | ST_Buffer |
convexHull(凸壳) | 计算几何的凸壳 | ST_ConvexHull |
intersection(交集) | 返回表示几何 A 和 B 共享部分的几何 | ST_Intersection |
union(合并) | 返回表示输入几何的点集合并的几何 | ST_Union |
difference(差异) | 返回表示几何 A 中不与几何 B 相交的部分的几何 | ST_Difference |
symDifference(对称差异) | 返回表示几何 A 和 B 不相交部分的几何 | ST_SymDifference |
<!-- https://mvnrepository.com/artifact/org.locationtech.jts/jts-core -->
<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
<version>1.18.2</version>
</dependency>
package com.example;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;
import java.util.List;
import java.util.Map;
/**
* JTS 几何模型
* 几何类型:点( POINT )、多点( MULTIPOINT )
* 线( LINESTRING )、多线(MULTILINESTRING )
* 面(POLYGON )、多面(MULTIPOLYGON )
* 圆
* 创建方式:几何工厂 和 WKT
* */
public class JTSGeometryUtil {
// 几何工厂对象
private GeometryFactory geometryFactory = new GeometryFactory();
/**
* 获取点
* @param lng 经度
* @param lat 纬度
* */
public Point getPoint(Double lng, Double lat){
Coordinate coordinate = new Coordinate(lng, lat);
return geometryFactory.createPoint(coordinate);
}
/**
* 获取点,通过 WKT 创建
* @param lng 经度
* @param lat 纬度
* */
public Point getPointByWKT(Double lng, Double lat) throws ParseException {
StringBuilder wktSB = new StringBuilder();
// POINT(111 22)
wktSB.append("POINT").append("(").append( lng ).append(" ").append( lat ).append(")");
return (Point) createGeometry(wktSB.toString());
}
/**
* 获取多点
* @param coordinates 坐标集合
* */
public MultiPoint getMultiPoint(Coordinate [] coordinates){
return geometryFactory.createMultiPointFromCoords(coordinates);
}
/**
* 获取多点,通过 WKT 创建
* @param coordinates 坐标集合
* */
public MultiPoint getMultiPointByWKT(Coordinate [] coordinates) throws ParseException {
// MULTIPOINT(111 22 ,111 22)
String wktStr = createWktString("MULTIPOINT", coordinates);
return (MultiPoint) createGeometry(wktStr);
}
/**
* 获取线
* @param coordinates 坐标集合
* */
public LineString getLineString(Coordinate [] coordinates){
return geometryFactory.createLineString(coordinates);
}
/**
* 获取线,通过 WKT 创建
* @param coordinates 坐标集合
* */
public LineString getLineStringByWKT(Coordinate [] coordinates) throws ParseException {
String wktStr = createWktString("LINESTRING", coordinates);
return (LineString) createGeometry(wktStr);
}
/**
* 获取多线
* @param coordList 多个坐标集合
* */
public MultiLineString getMultiLineString(List<Coordinate []> coordList){
LineString [] lineStrings = new LineString[coordList.size()];
for(int m=0; m<coordList.size(); m++){
lineStrings[m] = getLineString(coordList.get(m));
}
return geometryFactory.createMultiLineString(lineStrings);
}
/**
* 获取多线,通过 WKT 创建
* @param coordList 多个坐标集合
* */
public MultiLineString getMultiLineStringByWKT(List<Coordinate []> coordList) throws ParseException {
String wktStr = createMultiWktString("MULTILINESTRING", coordList);
return (MultiLineString) createGeometry(wktStr);
}
/**
* 获取面
* @param coordinates 坐标集合
* */
public Polygon getPolygon(Coordinate [] coordinates){
return geometryFactory.createPolygon(coordinates);
}
/**
* 获面
* @param shellCoordinates 面边界坐标集合
* @param holeCoordList 多个孔洞坐标集合
* */
public Polygon getPolygon(Coordinate [] shellCoordinates, List<Coordinate []> holeCoordList){
LinearRing shell = geometryFactory.createLinearRing(shellCoordinates);
LinearRing[] holes = new LinearRing[holeCoordList.size()];
for(int m=0; m<holeCoordList.size(); m++){
Coordinate [] holeCoordinates = holeCoordList.get(m);
holes[m] = geometryFactory.createLinearRing(holeCoordinates);
}
return geometryFactory.createPolygon(shell, holes);
}
/**
* 获取面,通过 WKT 创建
* @param coordinates 坐标集合
* */
public Polygon getPolygonByWKT(Coordinate [] coordinates) throws ParseException {
String wktStr = createWktStringWithPolygon("POLYGON", coordinates, null);
return (Polygon) createGeometry(wktStr);
}
/**
* 获取面,通过 WKT 创建
* @param shellCoordinates 面边界坐标集合
* @param holeCoordList 多个孔洞坐标集合
* */
public Polygon getPolygonByWKT(Coordinate [] shellCoordinates, List<Coordinate []> holeCoordList) throws ParseException {
String wktStr = createWktStringWithPolygon("POLYGON", shellCoordinates, holeCoordList);
return (Polygon) createGeometry(wktStr);
}
/**
* 获取多面
* @param coordList 多个坐标集合
* */
public MultiPolygon getMultiPolygon(List<Coordinate []> coordList){
Polygon [] polygons = new Polygon[ coordList.size() ];
for(int i=0; i<coordList.size(); i++){
polygons[i] = geometryFactory.createPolygon(coordList.get(i));
}
return geometryFactory.createMultiPolygon(polygons);
}
/**
* 获多面
* @param coordinateMap 面边界和孔洞坐标集合
* */
public MultiPolygon getMultiPolygon(Map<Coordinate [], List<Coordinate []>> coordinateMap){
Polygon [] polygons = new Polygon[ coordinateMap.size() ];
int index = 0;
for(Map.Entry<Coordinate[], List<Coordinate[]>> item : coordinateMap.entrySet()){
LinearRing shell = geometryFactory.createLinearRing(item.getKey()); // 面边界
LinearRing[] holes = new LinearRing[item.getValue().size()]; // 孔洞
for(int m=0; m<item.getValue().size(); m++){
Coordinate [] holeCoordinates = item.getValue().get(m);
holes[m] = geometryFactory.createLinearRing(holeCoordinates);
}
polygons[index] = geometryFactory.createPolygon(shell, holes);
index++;
}
return geometryFactory.createMultiPolygon(polygons);
}
/**
* 获取多面
* @param coordList 多个坐标集合
* */
public MultiPolygon getMultiPolygonByWKT(List<Coordinate []> coordList) throws ParseException {
StringBuilder wktSB = new StringBuilder();
wktSB.append("MULTIPOLYGON").append("(");
int index = 0;
for(Coordinate [] coordinates : coordList){
if(index > 0) { wktSB.append(","); }
// 1. 处理面边界
wktSB.append("(");
wktSB.append("("); // 面边界start
wktSB.append(coordinatesToWktStr(coordinates));
wktSB.append(")"); // 面边界end
wktSB.append(")");
index++;
}
wktSB.append(")");
return (MultiPolygon) createGeometry(wktSB.toString());
}
/**
* 获多面
* @param coordinateMap 面边界和孔洞坐标集合
* */
public MultiPolygon getMultiPolygonByWKT(Map<Coordinate [], List<Coordinate []>> coordinateMap) throws ParseException {
StringBuilder wktSB = new StringBuilder();
wktSB.append("MULTIPOLYGON").append("(");
int index = 0;
for(Map.Entry<Coordinate[], List<Coordinate[]>> item : coordinateMap.entrySet()){
Coordinate [] shellCoordinates = item.getKey();
List<Coordinate []> holeCoordList = item.getValue();
if(index > 0) { wktSB.append(","); }
wktSB.append("(");
wktSB.append(coordinatesToWktStr(shellCoordinates, holeCoordList));
wktSB.append(")");
index++;
}
wktSB.append(")");
return (MultiPolygon) createGeometry(wktSB.toString());
}
/**
* 获取圆(无孔洞)
* @param lng 经度
* @param lat 纬度
* @param radius 半径
* */
public Polygon getCircle(double lng, double lat, final double radius) {
final int arcs = 32; // 弧线点数量
Coordinate coords[] = new Coordinate[ arcs + 1 ];
for (int i = 0; i < arcs; i++) { // 角度转弧度计算
double angle = ((double) i / (double) arcs) * Math.PI * 2.0;
double dx = Math.cos(angle) * radius;
double dy = Math.sin(angle) * radius;
coords[i] = new Coordinate((double) lng + dx, (double) lat + dy);
}
coords[arcs] = coords[0]; // 将第一个数据放在最后,形成闭环
LinearRing ring = geometryFactory.createLinearRing(coords); // 圆环线
Polygon polygon = geometryFactory.createPolygon(ring, null);
return polygon;
}
/**
* 通过 WKT 字符串创建几何对象
* @param wktStr wkt 字符串
* */
public Geometry createGeometry(String wktStr) throws ParseException {
WKTReader wktReader = new WKTReader(geometryFactory);
return wktReader.read(wktStr);
}
/**
* 根据几何类型和坐标集合,创建 WKT 字符串
* @param geomType 几何类型
* @param coordinates 坐标集合
* */
public String createWktString(String geomType, Coordinate [] coordinates){
StringBuilder wktSB = new StringBuilder();
wktSB.append(geomType).append("(");
wktSB.append(coordinatesToWktStr(coordinates));
wktSB.append(")");
return wktSB.toString();
}
/**
* 将坐标集合转换为 wkt 需要的字符串
* @param coordinates 坐标集合
* */
private String coordinatesToWktStr(Coordinate [] coordinates){
StringBuilder wktSB = new StringBuilder();
for(int i=0; i<coordinates.length; i++){
Coordinate coordinate = coordinates[i];
wktSB.append( coordinate.getX() ).append(" ").append( coordinate.getY() );
if(coordinates.length-1 != i){ wktSB.append(","); } // 最后一个坐标不需要加逗号
}
return wktSB.toString();
}
/**
* 将坐标集合转换为 wkt 需要的字符串
* */
private String coordinatesToWktStr(Coordinate [] shellCoordinates, List<Coordinate []> holeCoordList){
StringBuilder wktSB = new StringBuilder();
// 1. 处理面边界
wktSB.append("("); // 面边界start
wktSB.append(coordinatesToWktStr(shellCoordinates));
wktSB.append(")"); // 面边界end
// 2. 处理多个孔洞
if(holeCoordList != null && holeCoordList.size() > 0){
for(int n=0; n<holeCoordList.size(); n++){
Coordinate [] holeCoordinates = holeCoordList.get(n);
wktSB.append(",");
wktSB.append("("); // 面边界start
wktSB.append(coordinatesToWktStr(holeCoordinates));
wktSB.append(")"); // 面边界end
}
}
return wktSB.toString();
}
/**
* 根据几何类型和坐标集合,创建 WKT 字符串(多个几何图形)
* @param geomType 几何类型
* @param coordList 多个坐标集合
* */
public String createMultiWktString(String geomType, List<Coordinate []> coordList){
StringBuilder wktSB = new StringBuilder();
wktSB.append(geomType).append("(");
for(int m=0; m<coordList.size(); m++){
Coordinate [] coordinates = coordList.get(m);
wktSB.append("(");
for(int n=0; n<coordList.size(); n++){
Coordinate coordinate = coordinates[n];
wktSB.append( coordinate.getX() ).append(" ").append( coordinate.getY() );
if(coordinates.length-1 != n){ wktSB.append(","); } // 最后一个坐标不需要加逗号
}
wktSB.append(")");
if(coordList.size()-1 != m){ wktSB.append(","); } // 最后一个坐标不需要加逗号
}
wktSB.append(")");
return wktSB.toString();
}
/**
* 根据几何类型和坐标集合,创建 WKT 字符串
* @param geomType 几何类型
* @param shellCoordinates 面边界坐标集合
* @param holeCoordList 多个孔洞坐标集合
* */
public String createWktStringWithPolygon(String geomType, Coordinate [] shellCoordinates, List<Coordinate []> holeCoordList){
StringBuilder wktSB = new StringBuilder();
wktSB.append(geomType).append("(");
wktSB.append(coordinatesToWktStr(shellCoordinates, holeCoordList));
wktSB.append(")");
return wktSB.toString();
}
}
package com.example;
import org.locationtech.jts.geom.*;
public class App
{
public static void main( String[] args )
{
App app = new App();
// 拓扑关系 contains
app.doContains();
// 叠加分析 intersection
app.doIntersection();
}
private JTSGeometryUtil jtsGeometryUtil = new JTSGeometryUtil();
/**
* Contains 包含
* */
public void doContains(){
// 点
Point point = jtsGeometryUtil.getPoint(116.403406,39.93397);
// 面
Coordinate[] coordinates = new Coordinate[4];
coordinates[0] = new Coordinate(116.361725,39.95676); // 首尾坐标相同
coordinates[1] = new Coordinate(116.364887,39.908515);
coordinates[2] = new Coordinate(116.442501,39.909622);
coordinates[2] = new Coordinate(116.440488,39.955654);
coordinates[3] = new Coordinate(116.361725,39.95676); // 首尾坐标相同
Polygon polygon = jtsGeometryUtil.getPolygon(coordinates);
// 操作
boolean result = polygon.contains(point);
System.out.println(result);
}
/**
* Intersection 交叉分析
* */
public void doIntersection(){
// 线一
Coordinate [] coordinates1 = new Coordinate[2];
coordinates1[0] = new Coordinate(116.361725,39.95676);
coordinates1[1] = new Coordinate(116.442501,39.909622);
LineString lineString1 = jtsGeometryUtil.getLineString(coordinates1);
// 线二
Coordinate [] coordinates2 = new Coordinate[2];
coordinates2[0] = new Coordinate(116.364887,39.908515);
coordinates2[1] = new Coordinate(116.440488,39.955654);
LineString lineString2 = jtsGeometryUtil.getLineString(coordinates2);
// 操作
Geometry geometry = lineString1.intersection(lineString2);
System.out.println(geometry);
}
}
本文分享自华为云社区《大模型LLM之分布式训练》,作者: 码上开花_Lancer。 随着语言模型参数量和所需训练数据量的急速增长,单个机器上有限的资源已无法满足大语言模型训练的要求。需要设计分布式训
本文分享自华为云社区《五大基础算法--动态规划法》,作者: 大金(内蒙的)。 一、基本概念 动态规划法,和分治法极其相似。区别就是,在求解子问题时,会保存该子问题的解,后面的子问题求解时,可以直接拿来
pip install scp pip install pexpect 测试代码: import os import stat import paramiko # 用于调用scp命令 def s
我目前正在实现“ token ”REST 服务。 token 只是一个字符串,由一些参数构建而成,然后经过哈希处理并在一定时间后过期。 我想在我的 REST 服务中有一个可以验证 token 的端点,
打开软删除后,我在客户端上添加一条记录,推送,删除添加的记录推送,然后尝试使用与初始记录相同的主键添加新记录(然后推送),我得到一个异常(exception)。 EntityDomainManager
打开软删除后,我在客户端上添加一条记录,推送,删除添加的记录推送,然后尝试使用与初始记录相同的主键添加新记录(然后推送),我得到一个异常(exception)。 EntityDomainManager
我有一个应用程序,每 x 秒接收一次天气信息。我想将此数据保存到 XML 文件中。 我应该为每个天气通知创建一个新的 XML 文件,还是将每个通知附加到同一个 XML 文件中?我不确定 XML 标准的
我猜我们大多数人都必须在某个时候处理这个问题,所以我想我会问这个问题。 当您的 BLL 中有很多集合并且您发现自己一遍又一遍地编写相同的旧内联(匿名)谓词时,显然有必要进行封装,但实现封装的最佳方
我有一些 c# 代码已经运行了一段时间了..我不得不说,虽然我了解 OO 原则的基础知识,但显然有不止一种方法可以给猫剥皮(尽管我讨厌那个短语!)。 因此,我有一个基本抽象类作为基本数据服务类,如下所
我设计了一个 SQL 数据库系统(使用 Postgre),我有一个问题,即创建一个关系/引用的常见做法是什么,这种关系/引用即使在引用的对象被删除时也能持续存在。 比如有一个UserORM,还有Act
我们的目标是搜索用户输入的字符串并计算在其中找到多少元音。不幸的是我被困在这里,有什么帮助吗? def numVowels(s): vowels= "AEIOUaeiou" if s
我有一个适用于我的“items”int 数组的旋转函数。下面的代码完成了它,除了我不必要地传输值。我正在努力实现“就地”轮换。我的意思是 ptrs 会递增或递减,而不是从数组中获取值。我需要通过这种方
我有一个 json 存储在我的应用程序文档文件夹中,我需要在我的所有 View 中使用它。我正在加载 json 并将其添加到每个 View 中的 NSMutableArray。但现在我了解到,我可以将
我用 C++ 开始了一个项目。这种语言的内存管理对我来说是新的。 我过去常常使用 new () 创建对象,然后传递指针,虽然它可以工作,但调试起来很痛苦,人们看到代码时会用有趣的眼神看着我。我为它没有
已结束。 这个问题是 off-topic .它目前不接受答案。 想要改进这个问题? Update the question所以它是on-topic堆栈溢出。 关闭 10 年前。 Improve thi
保持类松散耦合是编写易于理解、修改和调试的代码的一个重要方面——我明白这一点。然而,作为一个新手,几乎任何时候我都会超越我所苦苦挣扎的最简单的例子。 我或多或少地了解如何将字符串、整数和简单数据类型封
我发现我需要编写大量重复代码,因为我无法从其他 Controller 调用函数。例如,这里新闻提要内容在我的代码中重复,我对一个 Controller 做一些特定的事情,然后需要像这样加载我的新闻提要
假设需要一种数字数据类型,其允许值在指定范围内。更具体地说,假设要定义一个整数类型,其最小值为0,最大值为5000。这种情况在很多情况下都会出现,例如在对数据库数据类型,XSD数据类型进行建模时。 在
假设我想循环整个数组来访问每个元素。使用 for 循环、for...in 循环或 for...of 循环是 JavaScript 开发人员的标准做法吗? 例如: var myArray = ["app
我有一个旧的 SL4/ria 应用程序,我希望用 Breeze 取代它。我有一个关于内存使用和缓存的问题。我的应用程序加载工作列表(一个典型的用户可以访问大约 1,000 个这些工作)。此外,还有很多
我是一名优秀的程序员,十分优秀!