java jts获取线上任意一点到起点的距离
近期项目要求计算某段公路上一辆车的运行轨迹,通过路上的设备实时获取车辆的经纬度信息并发送到后台接收。
抽象出来就是获取线上任意一点到起点的距离,按照一定每秒一次的频率去计算就获取该点的运动轨迹了。
主要通过使用jts的工具类来计算。
<dependency><groupId>com.vividsolutions</groupId><artifactId>jts</artifactId><version>1.13</version>
</dependency>
jts使用样例
jts官方API文档
期间需要将经纬度转换成平面坐标。这里使用墨卡托进行坐标转换。
具体参考了如下文章,本文就不再引用了直接使用其工具类。
墨卡托经纬度转换平面坐标
正文代码如下:
@Data
@NoArgsConstructor
public class ExtLine {private String wkt;//原始的线的wkt信息private JSONObject geojson;private Coordinate[] coordinates;//组成线的每个端点的信息(经纬度已转换成平面坐标)private LineString line;//经过墨卡托转换后的线的对象private Double[] distances;//保存每个节点距离起点的距离
}
/*** @param wkt 原始线的wkt信息 需要经过墨卡托转换* @return ExtLine* 通过wkt创建ExtLine 该类中包含了各个点位的距离起点信息* */public static ExtLine createExtLine(String wkt) throws ParseException {WKTReader reader = new WKTReader();LineString lineString = (LineString) reader.read(wkt);ExtLine extLine = new ExtLine();extLine.setWkt(wkt);Coordinate[] row = lineString.getCoordinates();Coordinate[] result = new Coordinate[row.length];Double[] distance = new Double[row.length];for (int i = 0; i < row.length; i++) {double lng = row[i].x;double lat = row[i].y;double rate = Math.cos(Math.toRadians(lat));//墨卡托转成平面坐标计算距离时会拉伸长度使得结果偏大,需要对结果乘以当前纬度的cos值Map<String, Double> tmp = new HashMap<>();tmp = CoordConverter.convertLL2MC(lng, lat);//经过墨卡托转换Coordinate coordinate = new Coordinate(tmp.get("x"), tmp.get("y"));result[i] = coordinate;if (i == 0) {//起点位置distance[0] = 0.0D;} else {//计算并保存每个节点距离起点的长度LineString tempLine = geometryFactory.createLineString(Arrays.copyOf(result,i+1));distance[i] = tempLine.getLength() * rate;}}extLine.setDistances(distance);extLine.setCoordinates(result);extLine.setLine(geometryFactory.createLineString(result));System.out.println(distance[row.length-1]);return extLine;}/*** @param extLine 将上一步的计算好距离的信息对象传入* @param wkt 某点的wkt信息* @return double 返回某条线上的起点到某点的距离* */public static double getDistance(ExtLine extLine,String wkt) throws ParseException {WKTReader reader = new WKTReader();Point point = (Point) reader.read(wkt);//获取某点的信息(不一定要在线上)Coordinate coordinate = point.getCoordinate();double lng = coordinate.x;double lat = coordinate.y;Map<String,Double> map = CoordConverter.convertLL2MC(lng,lat);//将经纬度转换成平面坐标Coordinate transCoordinate = new Coordinate(map.get("x"),map.get("y"));LineString lineString = extLine.getLine();LocationIndexedLine indexedLine = new LocationIndexedLine(lineString);LinearLocation linearLocation = indexedLine.indexOf(transCoordinate);int index = linearLocation.getSegmentIndex();//获取某点距离线上最近的节点的indexCoordinate[] coordinates = extLine.getCoordinates();Coordinate lastPoint = coordinates[index];System.out.println(index);LineString temp = geometryFactory.createLineString(new Coordinate[]{lastPoint,transCoordinate});//计算线上距离某点最近的点和某点的距离 double distance = temp.getLength()+extLine.getDistances()[index];//两者相加即所求距离return distance;}
代码的图片说明如下:
线由节点1,2,3,4,5组成,需要计算点6到起点的距离(非计算点1和点6的直线距离 这样误差太大了) 需要计算点1-4的距离 这个步骤在createExtLine时就完成了 后续只需传入ExtLine 和点6的wkt 计算点4和点6的距离 d1 最后把点1-4的距离d2 return d1+d2即可。
如何计算点6距离线上某个节点最近通过linearLocation.getSegmentIndex();即可得到最近的前一个节点。
第一次写博客感觉写的不是很清楚,希望对这方面有需求的朋友有所帮助吧。