| package com.ruoyi.utils.tube; | 
|   | 
| import com.ruoyi.alarmpoints.tube.domain.ArdTubesDetails; | 
| import com.ruoyi.common.utils.StringUtils; | 
| import lombok.extern.slf4j.Slf4j; | 
| import org.gavaghan.geodesy.Ellipsoid; | 
| import org.gavaghan.geodesy.GeodeticCalculator; | 
| import org.gavaghan.geodesy.GlobalCoordinates; | 
| 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 | 
|         GeoPoint pointA = new GeoPoint(124.939903268, 46.684520056, 143.3 - 0.73); | 
|         GeoPoint pointB = new GeoPoint(124.94034787826001, 46.68444909044429, 144.12232823014708); | 
|         GeoPoint pointC = new GeoPoint(124.940552075, 46.684416498, 144.5 - 0.81); | 
|   | 
|         double distance = getDistance(pointA, pointC); | 
|         double diffAC = pointA.getAltitude() - pointC.getAltitude(); | 
|         log.info("AC总距离:" + distance + " AC高度差:" + diffAC); | 
|         double distance1 = getDistance(pointA, pointB); | 
|         double diffAB = pointA.getAltitude() - pointB.getAltitude(); | 
|         log.info("AB距离:" + distance1 + " AB高度差:" + diffAB); | 
|         double distance2 = getDistance(pointB, pointC); | 
|         double diffBC = pointB.getAltitude() - pointC.getAltitude(); | 
|         log.info("BC距离:" + distance2 + " BC高度差:" + diffBC); | 
|         // 计算斜率 | 
|         double slope1 = (pointB.getLatitude() - pointA.getLatitude()) / (pointB.getLongitude() - pointA.getLongitude()); | 
|         double slope2 = (pointC.getLatitude() - pointB.getLatitude()) / (pointC.getLongitude() - pointB.getLongitude()); | 
|   | 
|         // 设置斜率差值的阈值 | 
|         double threshold = 0.000001; | 
|   | 
|         // 检查斜率是否相等 | 
|         if (Math.abs(slope1 - slope2) < threshold) { | 
|             log.debug("这三个点共线"); | 
|         } else { | 
|             log.debug("这三个点不共线"); | 
|         } | 
|     } | 
|   | 
|     /** | 
|      *  计算坐标 | 
|      * | 
|      *  刘苏义 | 
|      *  2023/6/8 14:38 | 
|      */ | 
|     public static GeoPoint CalculateCoordinates(List<ArdTubesDetails> ardTubesDetails, Integer alarmPointDistance) { | 
|             try { | 
|                 if(StringUtils.isNull(alarmPointDistance)) | 
|                 { | 
|                     log.debug("报警点距离为空,无法计算坐标"); | 
|                     return null; | 
|                 } | 
|                 Comparator<ArdTubesDetails> comparator = Comparator.comparingInt(person -> Integer.parseInt(person.getInflectionPointNumber())); // 使用Collections.sort方法进行排序 | 
|                 Collections.sort(ardTubesDetails, comparator); | 
|                 GeoPoint point0 = new GeoPoint(ardTubesDetails.get(0).getLongitude(), ardTubesDetails.get(0).getLatitude(), ardTubesDetails.get(0).getAltitude() - ardTubesDetails.get(0).getDepth()); | 
|                 TreeMap<Integer, Double> distanceMap = new TreeMap<>(); | 
|                 TreeMap<Integer, Object> tubeMap = new TreeMap<>(); | 
|                 double distance = 0.0; | 
|                 for (ArdTubesDetails atd : ardTubesDetails) { | 
|                     GeoPoint point = new GeoPoint(atd.getLongitude(), atd.getLatitude(), atd.getAltitude() - atd.getDepth()); | 
|                     distance += getDistance(point, point0); | 
|                     distanceMap.put(Integer.parseInt(atd.getInflectionPointNumber()), distance); | 
|                     tubeMap.put(Integer.parseInt(atd.getInflectionPointNumber()), atd); | 
|                     point0 = point; | 
|                 } | 
|                 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; | 
|     } | 
|   | 
|     /** | 
|      * 根据经纬度,计算两点间的距离 | 
|      * | 
|      * @param GeoPoint pa 第一个点 | 
|      * @param GeoPoint  pb 第二个点 | 
|      * @return 返回距离 单位米 | 
|      */ | 
|     public static GeodeticCalculator geodeticCalculator = new GeodeticCalculator(); | 
|     public static double getDistance(GeoPoint pa, GeoPoint pb) { | 
|         GlobalCoordinates source = new GlobalCoordinates(pa.getLatitude(), pa.getLongitude()); | 
|         GlobalCoordinates target = new GlobalCoordinates(pb.getLatitude(), pb.getLongitude()); | 
|         double distance = geodeticCalculator.calculateGeodeticCurve(Ellipsoid.WGS84, source, target).getEllipsoidalDistance(); | 
|         double res = Math.sqrt(Math.pow(pa.getAltitude() - pb.getAltitude(), 2) + Math.pow(distance, 2)); | 
|         return res; | 
|     } | 
| } |