吉安感知网项目-后端
xiebin
2026-01-06 d207a86cdf1ab52ef8cb7cd83bad8fceab8038cf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
package org.sxkj.common.geo.utils;
 
import org.sxkj.common.geo.entity.Feature;
import org.sxkj.common.geo.entity.FlyAreaParam;
import org.sxkj.common.geo.entity.GeoJson;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.sxkj.common.geo.entity.PointPOJO;
 
import java.io.File;
import java.io.IOException;
import java.util.*;
 
/**
 * 空间计算工具类
 */
public class GeoUtils {
    /**
     * 默认地球半径
     */
    private static double EARTH_RADIUS = 6371000;//赤道半径(单位m)
 
    /**
     * 转化为弧度(rad)
     */
    private static double rad(double d) {
        return d * Math.PI / 180.0;
    }
 
 
    /**
     * 计算中心经纬度与目标经纬度的距离(米)
     *
     * @param centerLon 中心精度
     * @param centerLat 中心纬度
     * @param targetLon 需要计算的精度
     * @param targetLat 需要计算的纬度
     * @return 米
     */
    public static double distance(double centerLon, double centerLat, double targetLon, double targetLat) {
 
        double jl_jd = 102834.74258026089786013677476285;// 每经度单位米;
        double jl_wd = 111712.69150641055729984301412873;// 每纬度单位米;
        double b = Math.abs((centerLat - targetLat) * jl_jd);
        double a = Math.abs((centerLon - targetLon) * jl_wd);
        return Math.sqrt((a * a + b * b));
    }
 
    /**
     * 根据多个点计算中心点
     * @param list
     * @return
     */
    public static PointPOJO getCenterPoint(List<PointPOJO> list) {
 
        int total = list.size();
        double X = 0, Y = 0, Z = 0;
 
        for (int i = 0; i < list.size(); i++) {
            PointPOJO point = list.get(i);
            double lat, lon, x, y, z;
            lon = point.getLon() * Math.PI / 180;
            lat = point.getLat() * Math.PI / 180;
            x = Math.cos(lat) * Math.cos(lon);
            y = Math.cos(lat) * Math.sin(lon);
            z = Math.sin(lat);
            X += x;
            Y += y;
            Z += z;
        }
 
 
        X = X / total;
        Y = Y / total;
        Z = Z / total;
        double Lon = Math.atan2(Y, X);
        double Hyp = Math.sqrt(X * X + Y * Y);
        double Lat = Math.atan2(Z, Hyp);
 
        PointPOJO centerPoint = new PointPOJO();
        centerPoint.setLon( Lon * 180 / Math.PI);
        centerPoint.setLat(Lat * 180 / Math.PI);
        return centerPoint;
    }
 
    /**
     * 获取点区域并按从近到远排序
     * @param flyAreaParam
     * @return
     */
    public static List<PointPOJO> caculatePointList(FlyAreaParam flyAreaParam){
        List<List<PointPOJO>> areaList = flyAreaParam.getAreaList();
        PointPOJO dockPoint = flyAreaParam.getDockPoint();
        Double radius = flyAreaParam.getRadius();
 
        List<PointPOJO> centerPointList = new ArrayList<>();
 
        //根据区域获取中心点
        areaList.forEach(area -> {
            PointPOJO centerPoint = GeoUtils.getCenterPoint(area);
            centerPointList.add(centerPoint);
        });
 
        //巡逻目标集合
        List<PointPOJO> targetList = new ArrayList<>();
        //获取所有中心点之后,
        centerPointList.forEach(centerPoint -> {
            //判断各个中心点和机场点的距离
            double distance = GeoUtils.distance(dockPoint.getLon(), dockPoint.getLat(), centerPoint.getLon(), centerPoint.getLat());
 
            //当距离小于半径时,添加到目标集合中
            if (distance <= radius) {
                centerPoint.setDistance(distance);
                targetList.add(centerPoint);
            }
        });
 
        //按距离从近到远排序
        targetList.sort(Comparator.comparing(PointPOJO::getDistance));
        return targetList;
    }
 
    /**
     * 根据geojson获取点区域并按从近到远排序
     * @param geoJson
     * @return
     */
    public static List<PointPOJO> caculatePointList(GeoJson geoJson,PointPOJO dockPoint,Double radius){
        List<Feature> features = geoJson.getFeatures();
 
        List<List<PointPOJO>> areaList = new ArrayList<>();
 
        features.forEach(feature -> {
            List<PointPOJO> list = new ArrayList<>();
            List<List<Double>> coordinates = feature.getGeometry().getCoordinates().get(0);
 
            coordinates.forEach(coordinate ->{
                PointPOJO pointPOJO = new PointPOJO();
 
                pointPOJO.setLon(coordinate.get(0));
                pointPOJO.setLat(coordinate.get(1));
 
                list.add(pointPOJO);
            });
            areaList.add(list);
        });
 
        FlyAreaParam flyAreaParam = new FlyAreaParam();
 
        flyAreaParam.setDockPoint(dockPoint);
        flyAreaParam.setRadius(radius);
        flyAreaParam.setAreaList(areaList);
 
        List<PointPOJO> pointPOJOS = caculatePointList(flyAreaParam);
 
        return pointPOJOS;
    }
 
    /**
     * 读取json文件
     * @param path
     * @return
     */
    public static GeoJson readJsonFile(String path){
 
        try {
            File file = new File(path);
            ObjectMapper objectMapper = new ObjectMapper();
 
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
 
            return objectMapper.readValue(file, GeoJson.class);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
 
    }
 
 
    /**
     * 根据起点经纬度、方向和距离计算目标点经纬度
     *
     * @param lat1     起点纬度(单位:度)
     * @param lon1     起点经度(单位:度)
     * @param bearing  方向角(单位:度,正北为0度,顺时针增加)
     *                 lat1:起点纬度(单位:度)。
     *
     * lon1:起点经度(单位:度)。
     *
     * bearing:方向角(单位:度,正北为0度,顺时针增加)。
     *
     * distance:距离(单位:米)
     * @param distance 距离(单位:米)
     * @return 目标点的经纬度数组,格式为 [纬度, 经度]
     */
    public static PointPOJO calculateDestination(double lat1, double lon1, double bearing, double distance) {
        // 将经纬度从度数转换为弧度
        double lat1Rad = Math.toRadians(lat1);
        double lon1Rad = Math.toRadians(lon1);
 
        // 将方向角从度数转换为弧度
        double bearingRad = Math.toRadians(bearing);
 
        // 计算目标点纬度
        double lat2Rad = Math.asin(Math.sin(lat1Rad) * Math.cos(distance / EARTH_RADIUS) +
            Math.cos(lat1Rad) * Math.sin(distance / EARTH_RADIUS) * Math.cos(bearingRad));
 
        // 计算目标点经度
        double lon2Rad = lon1Rad + Math.atan2(
            Math.sin(bearingRad) * Math.sin(distance / EARTH_RADIUS) * Math.cos(lat1Rad),
            Math.cos(distance / EARTH_RADIUS) - Math.sin(lat1Rad) * Math.sin(lat2Rad));
 
        // 将结果从弧度转换回度数
        double lat2 = Math.toDegrees(lat2Rad);
        double lon2 = Math.toDegrees(lon2Rad);
        PointPOJO pointPOJO=new PointPOJO();
        pointPOJO.setLat(lat2);
        pointPOJO.setLon(lon2);
        return pointPOJO;
    }
 
 
    /**
     * 方向与角度的关系
     */
    public static final Map<String, Double> DIRECTION_ANGLES = new HashMap<>();
 
    static {
        DIRECTION_ANGLES.put("北", 0.0);
        DIRECTION_ANGLES.put("东北", 45.0);
        DIRECTION_ANGLES.put("东", 90.0);
        DIRECTION_ANGLES.put("东南", 135.0);
        DIRECTION_ANGLES.put("南", 180.0);
        DIRECTION_ANGLES.put("西南", 225.0);
        DIRECTION_ANGLES.put("西", 270.0);
        DIRECTION_ANGLES.put("西北", 315.0);
    }
 
 
 
}