package com.ruoyi.utils.tube; import com.ruoyi.alarmpoints.tube.domain.ArdTubesDetails; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.TreeMap; /** * @ClassName TubeTools * @Description: 管线计算工具 * @Author 刘苏义 * @Date 2023/6/6 19:29 * @Version 1.0 */ @Service @Slf4j public class TubeTools { public static void main(String[] args) { // 假设给定的三个坐标点 A、B、C double x1 = 124.939903268; double y1 = 46.684520056; double x2 = 124.94049634327537; double y2 = 46.68442539350505; double x3 = 124.940552075; double y3 = 46.684416498; double distance = getDistance(x1, y1, x3, y3); log.debug("总距离:" + distance); double distance1 = getDistance(x1, y1, x2, y2); log.debug("距离起点距离:" + distance1); double distance2 = getDistance(x2, y2, x3, y3); log.debug("距离终点距离:" + distance2); // 计算斜率 double slope1 = (y2 - y1) / (x2 - x1); double slope2 = (y3 - y2) / (x3 - x2); // 设置斜率差值的阈值 double threshold = 0.000001; // 检查斜率是否相等 if (Math.abs(slope1 - slope2) < threshold) { log.debug("这三个点共线"); } else { log.debug("这三个点不共线"); } } /** * @描述 计算坐标 * @参数 [ardTubesDetails, alarmPointDistance] * @返回值 void * @创建人 刘苏义 * @创建时间 2023/6/8 14:38 * @修改人和其它信息 */ public static GeoPoint CalculateCoordinates(List ardTubesDetails, Integer alarmPointDistance) { try { Comparator comparator = Comparator.comparingInt(person -> Integer.parseInt(person.getInflectionPointNumber())); // 使用Collections.sort方法进行排序 Collections.sort(ardTubesDetails, comparator); double x = ardTubesDetails.get(0).getLongitude(); double y = ardTubesDetails.get(0).getLatitude(); TreeMap distanceMap = new TreeMap<>(); TreeMap tubeMap = new TreeMap<>(); double distance = 0.0; for (ArdTubesDetails atd : ardTubesDetails) { distance += getDistance(x, y, atd.getLongitude(), atd.getLatitude()); distanceMap.put(Integer.parseInt(atd.getInflectionPointNumber()), distance); tubeMap.put(Integer.parseInt(atd.getInflectionPointNumber()), atd); x = atd.getLongitude(); y = atd.getLatitude(); } Integer num = 0; double tempDistance = 0.0; while (tempDistance < alarmPointDistance) { num++; tempDistance = distanceMap.get(num); } log.debug("报警点在拐点" + (num - 1) + "-" + num + "之间,总距离" + (tempDistance - distanceMap.get(num - 1))); ArdTubesDetails point1 = (ArdTubesDetails) tubeMap.get(num - 1); double x0 = point1.getLongitude(); double y0 = point1.getLatitude(); double z0 = point1.getAltitude(); ArdTubesDetails point2 = (ArdTubesDetails) tubeMap.get(num); double x1 = point2.getLongitude(); double y1 = point2.getLatitude(); double z1 = point2.getAltitude(); /*计算报警点坐标*/ double d = alarmPointDistance - distanceMap.get(num - 1); GeoPoint aPoint = new GeoPoint(x0, y0, z0); GeoPoint bPoint = new GeoPoint(x1, y1, z1); GeoPoint geoPoint = caculateRawGeoPoint(aPoint, bPoint, d); double height = interpolateHeight(aPoint, bPoint, geoPoint); geoPoint.setAltitude(height); log.debug("计算结果:" + geoPoint); return geoPoint; } catch (Exception ex) { log.error("管线报警点坐标计算异常:"+ex.getMessage()); return null; } } // 线性插值计算任意点的高度 private static double interpolateHeight(GeoPoint startPoint, GeoPoint endPoint, GeoPoint alarmPoint) { double startX = startPoint.getLongitude(); double startY = startPoint.getLatitude(); double startZ = startPoint.getAltitude(); double endX = endPoint.getLongitude(); double endY = endPoint.getLatitude(); double endZ = endPoint.getAltitude(); // 目标点的坐标 double targetX = alarmPoint.getLongitude(); double targetY = alarmPoint.getLatitude(); double distance = Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2)); double targetDistance = Math.sqrt(Math.pow(targetX - startX, 2) + Math.pow(targetY - startY, 2)); double t = targetDistance / distance; double targetHeight = startZ + t * (endZ - startZ); return targetHeight; } /** * 已知WGS84坐标系 A 点,B点, X 在AB 弧线上, 且是最短的这条, AX距离已知,求X点坐标. * * @param aPoint * @param bPoint * @param distance_ax_in_meter * @return */ private static GeoPoint caculateRawGeoPoint(GeoPoint aPoint, GeoPoint bPoint, double distance_ax_in_meter) { MyLatLng a = new MyLatLng(aPoint.getLongitude(), aPoint.getLatitude()); MyLatLng b = new MyLatLng(bPoint.getLongitude(), bPoint.getLatitude()); double angle = getAngle(a, b); //double angle = GisUtil.getNorthAngle(a.getM_Longitude(),a.getM_Latitude(), b.getM_Longitude(),b.getM_Latitude()); MyLatLng x = getMyLatLng(a, distance_ax_in_meter / 1000.0, angle); GeoPoint xPoint = new GeoPoint(x.m_Longitude, x.m_Latitude, 0.0); return xPoint; } /** * 求B点经纬度 * * @param A 已知点的经纬度, * @param distanceInKM AB两地的距离 单位km * @param angle AB连线与正北方向的夹角(0~360) * @return B点的经纬度 */ private static MyLatLng getMyLatLng(MyLatLng A, double distanceInKM, double angle) { double dx = distanceInKM * 1000 * Math.sin(Math.toRadians(angle)); double dy = distanceInKM * 1000 * Math.cos(Math.toRadians(angle)); double bjd = (dx / A.Ed + A.m_RadLo) * 180. / Math.PI; double bwd = (dy / A.Ec + A.m_RadLa) * 180. / Math.PI; return new MyLatLng(bjd, bwd); } /** * 获取AB连线与正北方向的角度 * * @param A A点的经纬度 * @param B B点的经纬度 * @return AB连线与正北方向的角度(0~360) */ private static double getAngle(MyLatLng A, MyLatLng B) { double dx = (B.m_RadLo - A.m_RadLo) * A.Ed; double dy = (B.m_RadLa - A.m_RadLa) * A.Ec; double angle = 0.0; angle = Math.atan(Math.abs(dx / dy)) * 180. / Math.PI; double dLo = B.m_Longitude - A.m_Longitude; double dLa = B.m_Latitude - A.m_Latitude; if (dLo > 0 && dLa <= 0) { angle = (90. - angle) + 90; } else if (dLo <= 0 && dLa < 0) { angle = angle + 180.; } else if (dLo < 0 && dLa >= 0) { angle = (90. - angle) + 270; } return angle; } private static final double EARTH_RADIUS = 6378.137; // 6378.137为地球半径(单位:千米) /** * 根据经纬度,计算两点间的距离 * * @param longitude1 第一个点的经度 * @param latitude1 第一个点的纬度 * @param longitude2 第二个点的经度 * @param latitude2 第二个点的纬度 * @return 返回距离 单位千米 */ private static double getDistance(double longitude1, double latitude1, double longitude2, double latitude2) { // 纬度 double lat1 = Math.toRadians(latitude1); double lat2 = Math.toRadians(latitude2); // 经度 double lng1 = Math.toRadians(longitude1); double lng2 = Math.toRadians(longitude2); // 纬度之差 double a = lat1 - lat2; // 经度之差 double b = lng1 - lng2; // 计算两点距离的公式 double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(b / 2), 2))); // 弧长乘地球半径, 返回单位: 千米 s = s * EARTH_RADIUS; //System.out.println("距离"+s); return s * 1000; } }