西宁最好网站建设公司,软件仓库,ps网站头部,电影网站设计说明书场景
Java中使用JTS对空间几何计算(读取WKT、距离、点在面内、长度、面积、相交等)#xff1a;
Java中使用JTS对空间几何计算(读取WKT、距离、点在面内、长度、面积、相交等)_jts-core_霸道流氓气质的博客-CSDN博客
JavaGeoTools实现WKT数据根据EPSG编码进行坐标系转换
Java中使用JTS对空间几何计算(读取WKT、距离、点在面内、长度、面积、相交等)_jts-core_霸道流氓气质的博客-CSDN博客
JavaGeoTools实现WKT数据根据EPSG编码进行坐标系转换
JavaGeoTools实现WKT数据根据EPSG编码进行坐标系转换_霸道流氓气质的博客-CSDN博客
基于gis的业务场景中需要在地图中录入区域数据的wkt数据然后根据某个坐标点判断是属于哪个区域
以及距离所属区域中最近的端点的方位角比如坐标点位于某区域东南方向100米。
注
博客霸道流氓气质_C#,架构之路,SpringBoot-CSDN博客
实现
1、参考上面引入jts的依赖。
首先数据库中存储的所有线的WKT数据为 其中region_name为线的名称region_wkt为线的wkt字符串。
首先从数据库中读取所有的wkt字符串数据并转换为map类型数据方便处理以及赋值线的名称到linestring的userData字段。 ListLineString regionList new ArrayList();MapString, ListLineString regionMap new HashMap();//读取录入的区域位置信息RegionManagement param RegionManagement.builder().deleteFlag(false).build();ListRegionManagement regionManagements regionManagementMapper.selectList(param);for (RegionManagement regionManagement : regionManagements) {LineString lineString readWKT(regionManagement.getRegionWKT());RegionDTO regionDTO JSON.parseObject(JSON.toJSONString(regionManagement), RegionDTO.class);regionDTO.setUpdateTime(regionManagement.getUpdateTime().toString());lineString.setUserData(regionDTO);regionList.add(lineString);}//将区域list流处理为map方便快速查找MapString, ListRegionManagement collect regionManagements.stream().collect(Collectors.groupingBy(RegionManagement::getRegionName));for (String name : collect.keySet()) {ListLineString tmp new ArrayList();collect.get(name).forEach(item - tmp.add(readWKT(item.getRegionWKT())));regionMap.put(name, tmp);}
这里的RegionManagement用来读取数据库中存储的wkt字符串等数据实现为
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;Data
NoArgsConstructor
AllArgsConstructor
Builder
public class RegionManagement {private Long id;private String regionName;private String regionWKT;// 0 false ; 1 trueprivate boolean deleteFlag;JsonFormat(pattern yyyy-MM-dd HH:mm:ss)private Date updateTime;}
调用读取wkt字符串并转换为jts的LineString对象的方法readWKT实现为 //读取wkt数据为LineStringpublic LineString readWKT(String regionWKT){GeometryFactory fact new GeometryFactory();WKTReader reader new WKTReader(fact);LineString geometry1 null;try {geometry1 (LineString) reader.read(regionWKT);} catch (ParseException e) {e.printStackTrace();}return geometry1;}
中间获取所需要的数据的RegionDTO的实现为
import lombok.Data;Data
public class RegionDTO {private Long id;private String regionName;private String updateTime;
}
2、将要判断方位的坐标值声明为Point2D对象 //目标点位Point2D.Double carPoint new Point2D.Double(36582834.745, 4259820.7951);
3、获取距离目标点位最近的线 //获取离目标点位最近的线LineString lineString findNearestLine(carPoint, 10D, regionList);
这里调用的findNearestLine方法的实现 //查找最近的线jts工具做线的缓冲区扩展宽度为10public LineString findNearestLine(java.awt.geom.Point2D.Double point, Double FuzzyLookupRange, ListLineString lineStringList) {Point a createPoint(point.getX(), point.getY());return lineStringList.parallelStream().filter((lineString) - lineString.buffer(FuzzyLookupRange).contains(a)).min((o1, o2) - {Double ax o1.distance(a);Double axx o2.distance(a);return ax.compareTo(axx);}).orElse(null);}
这里调用了createPoint用来创建point对象 //根据坐标x y创建点对象public static Point createPoint(Double x, Double y) {GeometryFactory a JTSFactoryFinder.getGeometryFactory();return a.createPoint(new Coordinate(x, y));}
然后使用lineString.buffer方法对线做缓冲区扩展宽度为10即将线向外扩充成类似区域的概念判断点是否在扩充后
的区域内如果有多个区域则取距离最小的一个。
LineString.buffer方法的使用可参考
Geometry (JTS Topology Suite 1.13 API) - Javadoc Extreme)
Computes a buffer area around this geometry having the given width. The buffer of a Geometry is the Minkowski sum or difference of the geometry
with a disc of radius abs(distance).
Mathematically-exact buffer area boundaries can contain circular arcs.
To represent these arcs using linear geometry they must be approximated with line segments.
The buffer geometry is constructed using 8 segments per quadrant to approximate the circular arcs. The end cap style is CAP_ROUND.
The buffer operation always returns a polygonal result. The negative or zero-distance buffer of lines and points is always an empty Polygon. This is also the result for the buffers of degenerate (zero-area) polygons.
直译
计算具有给定宽度的几何体周围的缓冲区。几何体的缓冲区是具有半径为abs距离的圆盘的几何体的Minkowski和或差。
数学上精确的缓冲区边界可以包含圆弧。要使用线性几何图形表示这些圆弧必须使用线段对其进行近似。
缓冲区几何结构使用每个象限8个线段来近似圆弧。端盖样式为cap_ROUND。
缓冲区操作总是返回多边形结果。直线和点的负或零距离缓冲区始终为空多边形。
这也是退化零面积多边形缓冲区的结果。 然后获取距离最近的线的名称并输出 //获取离目标点位最近的线LineString lineString findNearestLine(carPoint, 10D, regionList);String regionName 区域位置为空;if (lineString ! null) {RegionDTO userData (RegionDTO) lineString.getUserData();regionName userData.getRegionName();}System.out.println(regionName);
4、获取坐标点相对于该线的方位角 String azimuth;if (!regionName.equals(区域位置为空)) {ListLineString lineStringList regionMap.get(regionName);LineString closeLine;if (lineStringList.size() 1) {closeLine findNearestLine(carPoint, 10D, lineStringList);} else {closeLine lineStringList.get(0);}//获取线的两个端点Point startPoint closeLine.getStartPoint();Point endPoint closeLine.getEndPoint();//获取点位到两个端点的距离double startDistance startPoint.distance(createPoint(carPoint.getX(), carPoint.getY()));double endDistance endPoint.distance(createPoint(carPoint.getX(), carPoint.getY()));//获取较近的点作为参考点判断方位距离if (startDistance endDistance) {//获取方位角azimuth regionName DirectionUtil.getAzimuth(startPoint.getX(), startPoint.getY(), carPoint.getX(), carPoint.getY()) 方向路口 BigDecimal.valueOf(startDistance).intValue() 米;} else {azimuth regionName DirectionUtil.getAzimuth(endPoint.getX(), endPoint.getY(), carPoint.getX(), carPoint.getY()) 方向路口 BigDecimal.valueOf(endDistance).intValue() 米;}} else {azimuth [ carPoint.getX() , carPoint.getY() ];}System.out.println(azimuth);
其中获取方位角的工具类DirectionUtil.getAzimuth实现
import org.locationtech.jts.geom.LineSegment;public class DirectionUtil {/*** 笛卡尔坐标系*/enum DirectionEnum {DUE_EAST(正东, 0 || 360),DUE_NORTHEAST(东北, 45),DUE_NORTH(正北, 90),NORTH_NORTHWEST(西北, 90theta135),DUE_WEST(正西, 180),WEST_SOUTHWEST(西南, 180theta225),DUE_SOUTH(正南, 270),DUE_SOUTHEAST(东南, 315);private String direction;private String describe;DirectionEnum(String direction, String describe) {this.direction direction;this.describe describe;}public String getDirection() {return direction;}public void setDirection(String direction) {this.direction direction;}public String getDescribe() {return describe;}public void setDescribe(String describe) {this.describe describe;}}/*** 获取方位角** param x1 观测点x* param y1 观测点y* param x2 目标点x* param y2 目标点y* return 返回距离观测点的方位角*/public static String getAzimuth(double x1, double y1, double x2, double y2) {LineSegment lineSegment new LineSegment(x1, y1, x2, y2);double angle1 lineSegment.angle();double angle Math.toDegrees(lineSegment.angle());if (angle 0) {angle angle 360;}if ((0 angle angle 12.5) || (347.5 angle angle 360)) {return DirectionEnum.DUE_EAST.getDirection();} else if (12.5 angle angle 77.5) {return DirectionEnum.DUE_NORTHEAST.getDirection();} else if (77.5 angle angle 102.5) {return DirectionEnum.DUE_NORTH.getDirection();} else if (102.5 angle angle 167.5) {return DirectionEnum.NORTH_NORTHWEST.getDirection();} else if (167.5 angle angle 192.5) {return DirectionEnum.DUE_WEST.getDirection();} else if (192.5 angle angle 257.5) {return DirectionEnum.WEST_SOUTHWEST.getDirection();} else if (257.5 angle angle 282.5) {return DirectionEnum.DUE_SOUTH.getDirection();} else if (282.5 angle angle 347.5) {return DirectionEnum.WEST_SOUTHWEST.getDirection();} else {return ERROR;}}
}
逻辑就是对比目标点到线的两个端点的距离取较近的进行判断然后做方位角判断。
运行效果测试