Oracle
Oracle Database 21c Express Edition Release 21.0.0.0.0
SELECT
sdo_inside(
sdo_geometry(
2001,
NULL,
SDO_POINT_TYPE(
118.439140,
31.385456,
NULL
),
NULL,
NULL
),
SDO_GEOMETRY(
2003,
NULL,
NULL,
sdo_elem_info_array(
1,
2003,
2
),
SDO_ORDINATE_ARRAY(
118.392992, 31.381136 ,
118.39694, 31.377399 ,
118.433933, 31.378169 ,
118.479852, 31.372599 ,
118.510322, 31.366883 ,
118.51663, 31.394503 ,
118.435605, 31.436145 ,
118.392992, 31.381136
)
)
)
FROM DUAL
;
Java
/**
* <p>
* 经纬度DTO
* </p>
*
* @author jpge
* @since 2024/04/28
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class GeoPoint implements Serializable {
private static final long serialVersionUID = 4815643503634826077L;
/**
* 经度
*/
private BigDecimal longitude;
/**
* 纬度
*/
private BigDecimal latitude;
}
/**
* 检查多边形是否包含了某点
*
* @param vertices 多边形顶点
* @param point 某点[非闭合多边形,即最开始点只会出现一次,最终点不为最开始点]
* @return 是否包含
*/
public boolean containsPointJava(GeoPoint point, List<GeoPoint> vertices) {
int verticesCount = vertices.size();
int nCross = 0;
for (int i = 0; i < verticesCount; ++i) {
GeoPoint p1 = vertices.get(i);
GeoPoint p2 = vertices.get((i + 1) % verticesCount);
// 求解 y=p.y 与 p1 p2 的交点
if (p1.getLatitude().equals(p2.getLatitude())) { // p1p2 与 y=p0.y平行
continue;
}
if (
point.getLatitude().compareTo(
p1.getLatitude().min(p2.getLatitude())
) < 0
) { // 交点在p1p2延长线上
continue;
}
if (
point.getLatitude().compareTo(
p1.getLatitude().max(p2.getLatitude())
) >= 0
) { // 交点在p1p2延长线上
continue;
}
// 求交点的 X 坐标
BigDecimal x =
(point.getLatitude().subtract(p1.getLatitude())
).multiply(p2.getLatitude().subtract(p1.getLatitude()))
.divide(
(p2.getLatitude().subtract(p1.getLatitude())
).add(p1.getLatitude()), RoundingMode.HALF_UP);
if (x.compareTo(point.getLatitude()) > 0) { // 只统计单边交点
nCross++;
}
}
// 单边交点为偶数,点在多边形之外
return (nCross % 2 == 1);
}
GeoTools
<!-- https://mvnrepository.com/artifact/org.geotools/gt-main -->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-main</artifactId>
<version>${geotools.version}</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/gt-main-24.0.jar</systemPath>
</dependency>
<!-- https://mvnrepository.com/artifact/org.geotools/gt-main -->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-metadata</artifactId>
<version>${geotools.version}</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/gt-metadata-24.7.jar</systemPath>
</dependency>
<!-- https://mvnrepository.com/artifact/org.geotools/gt-main -->
<dependency>
<groupId>org.locationtech</groupId>
<artifactId>jts-core</artifactId>
<version>1.16.0-RC1</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/jts-core-1.16.0-RC1.jar</systemPath>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
</plugins>
</build>
/**
* 判断点是否在范围内
*
* @param point 点
* @param radius 范围[非闭合多边形,即最开始点只会出现一次,最终点不为最开始点][方法内会处理为闭合多边形]
* @return 是否在范围内
*/
@Override
public boolean containsPointGeoTools(GeoPoint point, List<GeoPoint> radius) {
List<Coordinate> collect = radius.stream().map(
geoPoint -> new Coordinate(
geoPoint.getLongitude().doubleValue(),
geoPoint.getLatitude().doubleValue()
)
).collect(Collectors.toList());
collect.add(
new Coordinate(
radius.get(0).getLongitude().doubleValue(),
radius.get(0).getLatitude().doubleValue()
)
);
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
// 定义多边形的坐标序列,顺序很重要,需要按照顺时针或逆时针顺序给出
Coordinate[] coordinates = new Coordinate[collect.size()];
collect.toArray(coordinates);
LinearRing linearRing = geometryFactory.createLinearRing(coordinates);
Polygon polygon = geometryFactory.createPolygon(linearRing, null);
// 待判断的点
Coordinate pointToCheck = new Coordinate(
point.getLongitude().doubleValue(),
point.getLatitude().doubleValue()
);
// 判断点是否在多边形内
return polygon.contains(geometryFactory.createPoint(pointToCheck));
}