文章目录
- 前言
- 一、通过bigmap软件生成坐标信息csv
- 二、Java实现
- 1.CSV分隔
- 2.计算
- 2.1 读取gps_data.csv
- 2.2 读取piles.csv
- 2.3 进行线性插值
- 2.4 返回值实体
- 2.5 根据GPS坐标计算距离工具
- 2.6 根据GPS坐标读取桩号
- 2.7 根据桩号读取GPS坐标(根据距离计算,找到最近的桩号)
前言
本文核心功能: 1.通过GPS坐标获取对应的桩号 2.通过桩号获取对应的GPS坐标
一、通过bigmap软件生成坐标信息csv
对于不规则曲线的公路,使用线性插值来计算桩号的经纬度仍然是可行的,但我们需要确保插值的精度更高。这通常意味着需要更多的GPS点来覆盖整个公路,确保每段路都有足够的数据点以进行准确的插值。
软件:
官方教程地址:链接
重点:比如需要计算的是一条蜿蜒曲折的公路,需要在软件内,沿着公路走向描点连线;注意公路起点(桩号K0+000)
示例:
间隔距离:间隔距离越小,倒时候转换时就越精确(如下图,如果设置为100米,则整条线等分为100米一段),保存为CSV文件
导出的csv示例(50米等分):
二、Java实现
1.CSV分隔
将bigemap导出的csv文件分成两份
第一份:gps_data.csv
包含经纬度和距离信息
第二份:piles.csv
包含桩号名称和对应的距离信息
2.计算
2.1 读取gps_data.csv
/**
* 该函数用于从指定文件路径读取GPS数据,并将每行数据转换为GPSPointConvert对象后存入列表返回。具体步骤如下:
* 通过BufferedReader逐行读取文件内容;
* 每行数据以逗号分割,提取纬度、经度和距离信息;
* 将提取的数据创建成GPSPointConvert对象并添加到列表中;
* 最终返回包含所有GPS点的列表
* @param filePath
* @return
* @throws IOException
*/
private static List<GPSPointConvert> readGPSData(String filePath) throws IOException {
List<GPSPointConvert> gpsData = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = br.readLine()) != null) {
String[] parts = line.split(",");
double latitude = Double.parseDouble(parts[0]);
double longitude = Double.parseDouble(parts[1]);
double distance = Double.parseDouble(parts[2]);
gpsData.add(new GPSPointConvert(latitude, longitude, distance));
}
}
return gpsData;
}
2.2 读取piles.csv
/**
* 该函数用于从指定的文件中读取数据并转换为PileConvert对象列表。具体步骤如下:
* 创建一个空的PileConverts列表。
* 使用BufferedReader读取指定的文件。
* 循环读取文件的每一行,直到没有内容为止。
* 将每一行用逗号分割成两部分。
* 第一部分作为名称,第二部分解析为double类型的距离。
* 创建一个新的PileConvert对象,传入名称和距离作为参数。
* 将新对象添加到PileConverts列表中。
* 返回PileConverts列表
* @param filePath
* @return
* @throws IOException
*/
private static List<PileConvert> readPileConvertData(String filePath) throws IOException {
List<PileConvert> PileConverts = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = br.readLine()) != null) {
String[] parts = line.split(",");
String name = parts[0];
double distance = Double.parseDouble(parts[1]);
PileConverts.add(new PileConvert(name, distance));
}
}
return PileConverts;
}
2.3 进行线性插值
/**
* 该函数用于根据给定的桩点距离,在GPS数据点间进行线性插值以确定桩点的实际经纬度位置。具体步骤如下:
* 遍历每个桩点PileConvert;
* 查找最近的两个GPS点p1和p2,使得p1到p2的距离覆盖目标桩点距离;
* 计算插值比例ratio;
* 利用ratio插值计算出桩点的纬度latitude和经度longitude;
* 创建新的GPSPointConvert对象并添加到结果列表中。
* @param gpsData
* @param PileConverts
* @return
*/
private static List<GPSPointConvert> interpolatePileConvertPositions(List<GPSPointConvert> gpsData, List<PileConvert> PileConverts) {
List<GPSPointConvert> PileConvertPositions = new ArrayList<>();
int currentIndex = 0;
for (PileConvert PileConvert : PileConverts) {
double targetDistance = PileConvert.getDistance();
while (currentIndex < gpsData.size() - 1 && gpsData.get(currentIndex + 1).getDistance() < targetDistance) {
currentIndex++;
}
if (currentIndex >= gpsData.size() - 1) {
break;
}
GPSPointConvert p1 = gpsData.get(currentIndex);
GPSPointConvert p2 = gpsData.get(currentIndex + 1);
double ratio = (targetDistance - p1.getDistance()) / (p2.getDistance() - p1.getDistance());
double latitude = p1.getLatitude() + ratio * (p2.getLatitude() - p1.getLatitude());
double longitude = p1.getLongitude() + ratio * (p2.getLongitude() - p1.getLongitude());
PileConvertPositions.add(new GPSPointConvert(latitude,longitude,targetDistance));
}
return PileConvertPositions;
}
2.4 返回值实体
import lombok.Data;
import java.io.Serializable;
/**
* gps桩号转换-GPS
*/
@Data
public class GPSPointConvert implements Serializable {
private static final long serialVersionUID = 1L;
private Double latitude;
private Double longitude;
private Double distance;
public GPSPointConvert(double latitude, double longitude, double targetDistance) {
this.latitude = latitude;
this.longitude = longitude;
this.distance = targetDistance;
}
}
import lombok.Data;
import java.io.Serializable;
/**
* gps桩号转换-桩号
*/
@Data
public class PileConvert implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private Double distance;
public PileConvert(String name, double distance) {
this.name = name;
this.distance = distance;
}
}
2.5 根据GPS坐标计算距离工具
import java.text.DecimalFormat;
/**
*
* @描 述: 高德地图对应经纬度计算距离
*/
public class LocationUtils {
// 地球赤道半径
private static double EARTH_RADIUS = 6378.137;
private static double rad(double d) {
return d * Math.PI / 180.0;
}
/**
* @描述 经纬度获取距离
* @参数 [lat1, lng1, lat2, lng2]
* @返回值 double 米
**/
public static double getDistance(double lat1, double lng1, double lat2,
double lng2) {
double radLat1 = rad(lat1);
double radLat2 = rad(lat2);
double a = radLat1 - radLat2;
double b = rad(lng1) - rad(lng2);
double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
+ Math.cos(radLat1) * Math.cos(radLat2)
* Math.pow(Math.sin(b / 2), 2)));
s = s * EARTH_RADIUS;
s = Math.round(s * 10000d) / 10000d;
//保留三位小数
DecimalFormat df = new DecimalFormat("0.000");
String format = df.format(s * 1000);
return Double.parseDouble(format);
}
/**
* 获取两个经纬度的中心
* @param args
*/
public static double[] getCenter(double lat1, double lng1, double lat2,
double lng2) {
double[] center = new double[2];
center[0] = (lat1 + lat2) / 2;
center[1] = (lng1 + lng2) / 2;
return center;
}
// public static void main(String[] args) {
//
// double distance = getDistance(43.819579, 82.586068,
// 29.35, 106.33);
// System.out.println("距离" + distance + "千米");
// }
}
2.6 根据GPS坐标读取桩号
/**
* 根据桩号读取GPS坐标
* @param pileName 桩号 格式:K00+000
*/
public String getPileConvert(String pileName) throws IOException {
// 读取GPS轨迹数据
List<GPSPointConvert> gpsData = readGPSData("gps_data.csv");
// 读取桩号数据
List<PileConvert> PileConverts = readPileConvertData("piles.csv");
// 插值计算桩号位置
List<GPSPointConvert> PileConvertPositions = interpolatePileConvertPositions(gpsData, PileConverts);
String result="";
// 输出经纬度
double distanceResult =99999;
for (int i = 0; i < PileConvertPositions.size(); i++) {
PileConvert pileConvert = PileConverts.get(i);
String name = pileConvert.getName().replace("K","");
String[] split = name.split("\\+");
//循环值
double v = Double.parseDouble(split[0])*1000+Double.parseDouble(split[1]);
String[] split1 = pileName.replace("K","").split(" ");
//等待被判断的值
double v1 = Double.parseDouble(split1[0])*1000+Double.parseDouble(split1[1]);
//计算绝对差值
double distance = Math.abs(v - v1);
if(distance<distanceResult){
distanceResult=distance;
result=PileConvertPositions.get(i).getLatitude()+","+PileConvertPositions.get(i).getLongitude();
}
}
return result;
}
2.7 根据桩号读取GPS坐标(根据距离计算,找到最近的桩号)
/**
* 根据GPS坐标读取桩号
*/
public String getPileConvert(GPSPointConvert gpsPointConvert) throws IOException {
// 读取GPS轨迹数据
List<GPSPointConvert> gpsData = readGPSData("gps_data.csv");
// 读取桩号数据
List<PileConvert> PileConverts = readPileConvertData("piles.csv");
// 插值计算桩号位置
List<GPSPointConvert> PileConvertPositions = interpolatePileConvertPositions(gpsData, PileConverts);
// 查询距离最近的桩点
double distanceResult =99999;
String result="";
for (int i = 0; i < PileConvertPositions.size(); i++) {
GPSPointConvert gPSPointConvert = PileConvertPositions.get(i);
double longitude = gpsPointConvert.getLongitude();
double latitude = gpsPointConvert.getLatitude();
//找到距离最近的桩点
Double longitude1 = gPSPointConvert.getLongitude();
Double latitude1 = gPSPointConvert.getLatitude();
double distance = LocationUtils.getDistance(latitude, longitude, latitude1, longitude1);
if(distance<distanceResult){
distanceResult=distance;
result=PileConverts.get(i).getName();
}
}
return result;
}