Commit 9ba97109ea03f955835e8e1bf8a0840329fa7953
1 parent
8cedaf34
1.加入导航点位信息接口(常规、绕改道)
Showing
3 changed files
with
661 additions
and
0 deletions
src/main/java/com/bsth/entity/Detour.java
0 → 100644
| 1 | +package com.bsth.entity; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
| 4 | +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
| 5 | +import org.hibernate.annotations.DynamicInsert; | ||
| 6 | +import org.hibernate.annotations.DynamicUpdate; | ||
| 7 | + | ||
| 8 | +import javax.persistence.*; | ||
| 9 | +import java.util.ArrayList; | ||
| 10 | +import java.util.List; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * 绕改道实体类 | ||
| 14 | + * 对应数据库表 bsth_c_detour | ||
| 15 | + */ | ||
| 16 | +@Entity | ||
| 17 | +@Table(name = "bsth_c_detour") | ||
| 18 | +@DynamicInsert | ||
| 19 | +@DynamicUpdate | ||
| 20 | +@JsonIgnoreProperties(ignoreUnknown = true) | ||
| 21 | +public class Detour { | ||
| 22 | + | ||
| 23 | + // 主键 | ||
| 24 | + @Id | ||
| 25 | + @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
| 26 | + @JsonIgnore | ||
| 27 | + private Integer id; | ||
| 28 | + | ||
| 29 | + // 线路 | ||
| 30 | + private Integer line; | ||
| 31 | + | ||
| 32 | + // 版本号 | ||
| 33 | + @JsonIgnore | ||
| 34 | + private Integer versions; | ||
| 35 | + | ||
| 36 | + // 上下行 | ||
| 37 | + private Integer direction; | ||
| 38 | + | ||
| 39 | + // 起点编码 | ||
| 40 | + @JsonIgnore | ||
| 41 | + private String startStationCode; | ||
| 42 | + | ||
| 43 | + @Transient | ||
| 44 | + private int startIdx; | ||
| 45 | + | ||
| 46 | + // 终点编码 | ||
| 47 | + @JsonIgnore | ||
| 48 | + private String terminalStationCode; | ||
| 49 | + | ||
| 50 | + @Transient | ||
| 51 | + private int terminalIdx; | ||
| 52 | + | ||
| 53 | + // 路段wgs84点位 | ||
| 54 | + @JsonIgnore | ||
| 55 | + private String points; | ||
| 56 | + | ||
| 57 | + public Integer getId() { | ||
| 58 | + return id; | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + public void setId(Integer id) { | ||
| 62 | + this.id = id; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + public Integer getLine() { | ||
| 66 | + return line; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + public void setLine(Integer line) { | ||
| 70 | + this.line = line; | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + public Integer getVersions() { | ||
| 74 | + return versions; | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + public void setVersions(Integer versions) { | ||
| 78 | + this.versions = versions; | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + public Integer getDirection() { | ||
| 82 | + return direction; | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + public void setDirection(Integer direction) { | ||
| 86 | + this.direction = direction; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + public String getStartStationCode() { | ||
| 90 | + return startStationCode; | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + public void setStartStationCode(String startStationCode) { | ||
| 94 | + this.startStationCode = startStationCode; | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + public int getStartIdx() { | ||
| 98 | + return startIdx; | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + public void setStartIdx(int startIdx) { | ||
| 102 | + this.startIdx = startIdx; | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + public String getTerminalStationCode() { | ||
| 106 | + return terminalStationCode; | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + public void setTerminalStationCode(String terminalStationCode) { | ||
| 110 | + this.terminalStationCode = terminalStationCode; | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + public int getTerminalIdx() { | ||
| 114 | + return terminalIdx; | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | + public void setTerminalIdx(int terminalIdx) { | ||
| 118 | + this.terminalIdx = terminalIdx; | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + public String getPoints() { | ||
| 122 | + return points; | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + public void setPoints(String points) { | ||
| 126 | + this.points = points; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + /** | ||
| 130 | + * 将 points 字段转换为 List<Point> 格式 | ||
| 131 | + * 第一个点位和最后一个点位的 isStation 为 true | ||
| 132 | + * @return List<Point> | ||
| 133 | + */ | ||
| 134 | + public List<Point> getList() { | ||
| 135 | + List<Point> pointList = new ArrayList<>(); | ||
| 136 | + if (points == null || points.isEmpty()) { | ||
| 137 | + return pointList; | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + // 按照逗号分割 points 字符串,得到每个点位的字符串 | ||
| 141 | + String[] pointStrings = points.split(","); | ||
| 142 | + int length = pointStrings.length; | ||
| 143 | + | ||
| 144 | + // 遍历每个点位字符串 | ||
| 145 | + for (int i = 0; i < length; i++) { | ||
| 146 | + String pointString = pointStrings[i].trim(); | ||
| 147 | + if (pointString.isEmpty()) { | ||
| 148 | + continue; | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + // 按照空格分割得到经度和纬度 | ||
| 152 | + String[] coords = pointString.split(" "); | ||
| 153 | + if (coords.length != 2) { | ||
| 154 | + continue; | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + try { | ||
| 158 | + // 创建 Point 对象,设置经纬度 | ||
| 159 | + Point point = new Point(); | ||
| 160 | + point.setLon(Double.parseDouble(coords[0])); | ||
| 161 | + point.setLat(Double.parseDouble(coords[1])); | ||
| 162 | + | ||
| 163 | + // 第一个点位和最后一个点位的 isStation 为 true | ||
| 164 | + if (i == 0 || i == length - 1) { | ||
| 165 | + point.setStation(true); | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + pointList.add(point); | ||
| 169 | + } catch (NumberFormatException e) { | ||
| 170 | + // 忽略格式错误的点位 | ||
| 171 | + } | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + return pointList; | ||
| 175 | + } | ||
| 176 | +} | ||
| 0 | \ No newline at end of file | 177 | \ No newline at end of file |
src/main/java/com/bsth/server_rs/base_info/navigation/NavigationRestService.java
0 → 100644
| 1 | +package com.bsth.server_rs.base_info.navigation; | ||
| 2 | + | ||
| 3 | +import com.bsth.entity.Detour; | ||
| 4 | +import com.bsth.entity.Point; | ||
| 5 | +import com.bsth.server_rs.base_info.section.buffer.LD_SectionBufferData; | ||
| 6 | +import com.bsth.server_rs.base_info.section.entity.LD_Section; | ||
| 7 | +import com.bsth.server_rs.base_info.section.entity.LD_SectionRoute; | ||
| 8 | +import com.bsth.server_rs.base_info.station.buffer.StationBufferData; | ||
| 9 | +import com.bsth.server_rs.base_info.station.entity.StationRotue; | ||
| 10 | +import com.bsth.util.GeoUtils; | ||
| 11 | +import org.springframework.beans.factory.InitializingBean; | ||
| 12 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 13 | +import org.springframework.jdbc.core.BeanPropertyRowMapper; | ||
| 14 | +import org.springframework.jdbc.core.JdbcTemplate; | ||
| 15 | +import org.springframework.scheduling.annotation.EnableScheduling; | ||
| 16 | +import org.springframework.scheduling.annotation.Scheduled; | ||
| 17 | +import org.springframework.stereotype.Component; | ||
| 18 | + | ||
| 19 | +import javax.ws.rs.GET; | ||
| 20 | +import javax.ws.rs.Path; | ||
| 21 | +import javax.ws.rs.PathParam; | ||
| 22 | +import javax.ws.rs.Produces; | ||
| 23 | +import javax.ws.rs.core.MediaType; | ||
| 24 | +import java.util.*; | ||
| 25 | +import java.util.concurrent.ConcurrentHashMap; | ||
| 26 | + | ||
| 27 | +@Component | ||
| 28 | +@Path("/navigation") | ||
| 29 | +@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) | ||
| 30 | +@EnableScheduling | ||
| 31 | +public class NavigationRestService implements InitializingBean { | ||
| 32 | + | ||
| 33 | + @Autowired | ||
| 34 | + private JdbcTemplate jdbcTemplate; | ||
| 35 | + | ||
| 36 | + @Autowired | ||
| 37 | + private LD_SectionBufferData ldSectionBufferData; | ||
| 38 | + | ||
| 39 | + private static Map<String, Integer> line2version = new ConcurrentHashMap<>(); | ||
| 40 | + | ||
| 41 | + @GET | ||
| 42 | + @Path("/version/reload") | ||
| 43 | + @Scheduled(cron = "0 0 * * * *") // 每小时执行一次 | ||
| 44 | + public void reload() { | ||
| 45 | + Map<String, Integer> line2versionMap = new ConcurrentHashMap<>(); | ||
| 46 | + List<Map<String, Object>> list = jdbcTemplate.queryForList("SELECT line_code,versions FROM `bsth_c_line_versions` where `status` = 1 and now() BETWEEN start_date and end_date"); | ||
| 47 | + for (Map<String, Object> map : list) { | ||
| 48 | + line2versionMap.put((String) map.get("line_code"), (Integer) map.get("versions")); | ||
| 49 | + } | ||
| 50 | + if (!line2versionMap.isEmpty()) { | ||
| 51 | + line2version = line2versionMap; | ||
| 52 | + } | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + /** | ||
| 56 | + * 获取线路正常路径的点位信息 | ||
| 57 | + * @param lineCode 线路编码 | ||
| 58 | + * @param direction 方向 | ||
| 59 | + * @return 包含线路编码、方向和点位信息的Map | ||
| 60 | + */ | ||
| 61 | + @GET | ||
| 62 | + @Path("/normal/{lineCode}/{direction}") | ||
| 63 | + public Map<String, Object> normal(@PathParam("lineCode") String lineCode, @PathParam("direction") int direction) { | ||
| 64 | + Map<String, Object> result = new LinkedHashMap<>(); | ||
| 65 | + result.put("lineCode", lineCode); | ||
| 66 | + result.put("direction", direction); | ||
| 67 | + | ||
| 68 | + // 获取路段数据 | ||
| 69 | + Map<String, Collection<LD_SectionRoute>> sectionRoutesMap = ldSectionBufferData.findByLineCode(lineCode); | ||
| 70 | + if (sectionRoutesMap.isEmpty()) { | ||
| 71 | + result.put("list", new ArrayList<Point>()); | ||
| 72 | + return result; | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + // 获取对应方向的路段路由 | ||
| 76 | + Collection<LD_SectionRoute> sectionRoutes = sectionRoutesMap.get(lineCode + "_" + direction); | ||
| 77 | + if (sectionRoutes == null || sectionRoutes.isEmpty()) { | ||
| 78 | + result.put("list", new ArrayList<Point>()); | ||
| 79 | + return result; | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + // 获取站点数据 | ||
| 83 | + Map<String, Collection<StationRotue>> stationRoutesMap = StationBufferData.findRouteByLineCode(lineCode); | ||
| 84 | + Collection<StationRotue> stationRoutes = stationRoutesMap.get(lineCode + "_" + direction); | ||
| 85 | + List<StationRotue> stationRotueList = stationRoutes != null ? new ArrayList<>(stationRoutes) : new ArrayList<StationRotue>(); | ||
| 86 | + | ||
| 87 | + // 创建点位信息列表 | ||
| 88 | + List<Point> points = new ArrayList<>(); | ||
| 89 | + | ||
| 90 | + // 建立路段到站点的映射 | ||
| 91 | + Map<String, StationRotue> sectionToStationMap = new HashMap<>(); | ||
| 92 | + | ||
| 93 | + // 遍历站点,为每个站点找最近的路段 | ||
| 94 | + for (StationRotue stationRotue : stationRotueList) { | ||
| 95 | + if (stationRotue.getStation() == null) { | ||
| 96 | + continue; | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + // 创建站点的点位 | ||
| 100 | + Point stationPoint = new Point(); | ||
| 101 | + stationPoint.setLon(stationRotue.getLon()); | ||
| 102 | + stationPoint.setLat(stationRotue.getLat()); | ||
| 103 | + | ||
| 104 | + // 查找站点最近的路段 | ||
| 105 | + LD_Section nearestSection = findNearestSection(stationRotue, sectionRoutes); | ||
| 106 | + if (nearestSection != null) { | ||
| 107 | + // 建立路段到站点的映射 | ||
| 108 | + sectionToStationMap.put(nearestSection.getSectionCode(), stationRotue); | ||
| 109 | + } | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + // 遍历路段,处理每个路段 | ||
| 113 | + for (LD_SectionRoute sectionRoute : sectionRoutes) { | ||
| 114 | + LD_Section section = sectionRoute.getSection(); | ||
| 115 | + if (section == null) { | ||
| 116 | + continue; | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + // 检查路段是否有对应的站点 | ||
| 120 | + StationRotue stationRotue = sectionToStationMap.get(section.getSectionCode()); | ||
| 121 | + | ||
| 122 | + // 创建点位信息 | ||
| 123 | + Point point = createPointFromSection(section, stationRotue); | ||
| 124 | + if (point != null) { | ||
| 125 | + points.add(point); | ||
| 126 | + } | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + result.put("list", points); | ||
| 130 | + return result; | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + /** | ||
| 134 | + * 查找站点最近的路段 | ||
| 135 | + * @param stationRotue 站点路由 | ||
| 136 | + * @param sectionRoutes 路段路由集合 | ||
| 137 | + * @return 最近的路段 | ||
| 138 | + */ | ||
| 139 | + private LD_Section findNearestSection(StationRotue stationRotue, Collection<LD_SectionRoute> sectionRoutes) { | ||
| 140 | + if (stationRotue == null || stationRotue.getStation() == null || sectionRoutes == null || sectionRoutes.isEmpty()) { | ||
| 141 | + return null; | ||
| 142 | + } | ||
| 143 | + | ||
| 144 | + // 创建站点的点位 | ||
| 145 | + Point stationPoint = new Point(); | ||
| 146 | + stationPoint.setLon(stationRotue.getLon()); | ||
| 147 | + stationPoint.setLat(stationRotue.getLat()); | ||
| 148 | + | ||
| 149 | + LD_Section nearestSection = null; | ||
| 150 | + double minDistance = Double.MAX_VALUE; | ||
| 151 | + | ||
| 152 | + // 遍历路段,找到最近的路段 | ||
| 153 | + for (LD_SectionRoute sectionRoute : sectionRoutes) { | ||
| 154 | + LD_Section section = sectionRoute.getSection(); | ||
| 155 | + if (section == null) { | ||
| 156 | + continue; | ||
| 157 | + } | ||
| 158 | + | ||
| 159 | + // 获取路段的所有坐标点 | ||
| 160 | + List<Point> sectionPointList = getSectionPoints(section); | ||
| 161 | + if (sectionPointList == null || sectionPointList.size() < 2) { | ||
| 162 | + continue; | ||
| 163 | + } | ||
| 164 | + | ||
| 165 | + // 计算站点到路段折线的最短距离 | ||
| 166 | + double sectionMinDistance = calculateMinDistanceToPolyline(stationPoint, sectionPointList); | ||
| 167 | + | ||
| 168 | + // 如果距离更小,更新最近路段 | ||
| 169 | + if (sectionMinDistance < minDistance) { | ||
| 170 | + minDistance = sectionMinDistance; | ||
| 171 | + nearestSection = section; | ||
| 172 | + } | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + // 直接返回最近的路段,不设置距离阈值 | ||
| 176 | + return nearestSection; | ||
| 177 | + } | ||
| 178 | + | ||
| 179 | + /** | ||
| 180 | + * 获取路段的所有坐标点 | ||
| 181 | + * @param section 路段 | ||
| 182 | + * @return 路段的所有坐标点 | ||
| 183 | + */ | ||
| 184 | + private List<Point> getSectionPoints(LD_Section section) { | ||
| 185 | + if (section == null || section.getGsectionVector() == null || section.getGsectionVector().isEmpty()) { | ||
| 186 | + return null; | ||
| 187 | + } | ||
| 188 | + | ||
| 189 | + List<Point> pointList = new ArrayList<>(); | ||
| 190 | + | ||
| 191 | + // 解析 WKT 格式的 LINESTRING | ||
| 192 | + String wkt = section.getGsectionVector(); | ||
| 193 | + | ||
| 194 | + // 移除 LINESTRING( 前缀和 ) 后缀 | ||
| 195 | + if (wkt.startsWith("LINESTRING(") && wkt.endsWith(")")) { | ||
| 196 | + String pointsStr = wkt.substring(10, wkt.length() - 1); | ||
| 197 | + | ||
| 198 | + // 按照逗号分割得到每个点位的字符串 | ||
| 199 | + String[] points = pointsStr.split(","); | ||
| 200 | + for (String pointStr : points) { | ||
| 201 | + String[] coords = pointStr.trim().split(" "); | ||
| 202 | + if (coords.length != 2) { | ||
| 203 | + continue; | ||
| 204 | + } | ||
| 205 | + | ||
| 206 | + try { | ||
| 207 | + Point point = new Point(); | ||
| 208 | + point.setLon(Double.parseDouble(coords[0])); | ||
| 209 | + point.setLat(Double.parseDouble(coords[1])); | ||
| 210 | + pointList.add(point); | ||
| 211 | + } catch (NumberFormatException e) { | ||
| 212 | + // 忽略格式错误的点位 | ||
| 213 | + } | ||
| 214 | + } | ||
| 215 | + } | ||
| 216 | + | ||
| 217 | + return pointList; | ||
| 218 | + } | ||
| 219 | + | ||
| 220 | + /** | ||
| 221 | + * 计算点到折线的最短距离 | ||
| 222 | + * @param point 点 | ||
| 223 | + * @param polyline 折线的坐标点列表 | ||
| 224 | + * @return 点到折线的最短距离 | ||
| 225 | + */ | ||
| 226 | + private double calculateMinDistanceToPolyline(Point point, List<Point> polyline) { | ||
| 227 | + if (point == null || polyline == null || polyline.size() < 2) { | ||
| 228 | + return Double.MAX_VALUE; | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + double minDistance = Double.MAX_VALUE; | ||
| 232 | + | ||
| 233 | + // 遍历折线的每一条线段,计算点到线段的距离 | ||
| 234 | + for (int i = 0; i < polyline.size() - 1; i++) { | ||
| 235 | + Point startPoint = polyline.get(i); | ||
| 236 | + Point endPoint = polyline.get(i + 1); | ||
| 237 | + | ||
| 238 | + // 计算点到线段的距离 | ||
| 239 | + double distance = GeoUtils.getDistanceFromLine(startPoint, endPoint, point); | ||
| 240 | + | ||
| 241 | + // 更新最短距离 | ||
| 242 | + if (distance < minDistance) { | ||
| 243 | + minDistance = distance; | ||
| 244 | + } | ||
| 245 | + } | ||
| 246 | + | ||
| 247 | + return minDistance; | ||
| 248 | + } | ||
| 249 | + | ||
| 250 | + /** | ||
| 251 | + * 获取路段的中间点 | ||
| 252 | + * @param section 路段 | ||
| 253 | + * @return 路段的中间点 | ||
| 254 | + */ | ||
| 255 | + private Point getSectionMidPoint(LD_Section section) { | ||
| 256 | + if (section == null || section.getGsectionVector() == null || section.getGsectionVector().isEmpty()) { | ||
| 257 | + return null; | ||
| 258 | + } | ||
| 259 | + | ||
| 260 | + // 获取路段的所有坐标点 | ||
| 261 | + List<Point> pointList = getSectionPoints(section); | ||
| 262 | + if (pointList == null || pointList.size() < 2) { | ||
| 263 | + return null; | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + // 计算折线的总长度 | ||
| 267 | + double totalLength = 0; | ||
| 268 | + List<Double> segmentLengths = new ArrayList<>(); | ||
| 269 | + | ||
| 270 | + for (int i = 0; i < pointList.size() - 1; i++) { | ||
| 271 | + Point startPoint = pointList.get(i); | ||
| 272 | + Point endPoint = pointList.get(i + 1); | ||
| 273 | + double length = GeoUtils.getDistance(startPoint, endPoint); | ||
| 274 | + totalLength += length; | ||
| 275 | + segmentLengths.add(length); | ||
| 276 | + } | ||
| 277 | + | ||
| 278 | + // 如果总长度为0,返回第一个点 | ||
| 279 | + if (totalLength <= 0) { | ||
| 280 | + return pointList.get(0); | ||
| 281 | + } | ||
| 282 | + | ||
| 283 | + // 找到距离起点为总长度一半的点 | ||
| 284 | + double halfLength = totalLength / 2; | ||
| 285 | + double currentLength = 0; | ||
| 286 | + | ||
| 287 | + for (int i = 0; i < segmentLengths.size(); i++) { | ||
| 288 | + double segmentLength = segmentLengths.get(i); | ||
| 289 | + if (currentLength + segmentLength >= halfLength) { | ||
| 290 | + // 找到包含中间点的线段 | ||
| 291 | + Point startPoint = pointList.get(i); | ||
| 292 | + Point endPoint = pointList.get(i + 1); | ||
| 293 | + | ||
| 294 | + // 计算中间点在线段上的位置 | ||
| 295 | + double ratio = (halfLength - currentLength) / segmentLength; | ||
| 296 | + double midLon = startPoint.getLon() + (endPoint.getLon() - startPoint.getLon()) * ratio; | ||
| 297 | + double midLat = startPoint.getLat() + (endPoint.getLat() - startPoint.getLat()) * ratio; | ||
| 298 | + | ||
| 299 | + // 创建中间点 | ||
| 300 | + Point midPoint = new Point(); | ||
| 301 | + midPoint.setLon(midLon); | ||
| 302 | + midPoint.setLat(midLat); | ||
| 303 | + | ||
| 304 | + return midPoint; | ||
| 305 | + } | ||
| 306 | + currentLength += segmentLength; | ||
| 307 | + } | ||
| 308 | + | ||
| 309 | + // 如果没有找到,返回最后一个点 | ||
| 310 | + return pointList.get(pointList.size() - 1); | ||
| 311 | + } | ||
| 312 | + | ||
| 313 | + /** | ||
| 314 | + * 根据路段和站点创建点位信息 | ||
| 315 | + * @param section 路段 | ||
| 316 | + * @param station 站点 | ||
| 317 | + * @return 点位信息 | ||
| 318 | + */ | ||
| 319 | + private Point createPointFromSection(LD_Section section, StationRotue station) { | ||
| 320 | + Point point = new Point(); | ||
| 321 | + | ||
| 322 | + if (station != null && station.getStation() != null) { | ||
| 323 | + // 如果有站点,使用站点的坐标 | ||
| 324 | + point.setLon(station.getLon()); | ||
| 325 | + point.setLat(station.getLat()); | ||
| 326 | + point.setStation(true); | ||
| 327 | + } else { | ||
| 328 | + // 否则使用路段的中间点坐标 | ||
| 329 | + Point midPoint = getSectionMidPoint(section); | ||
| 330 | + if (midPoint != null) { | ||
| 331 | + point.setLon(midPoint.getLon()); | ||
| 332 | + point.setLat(midPoint.getLat()); | ||
| 333 | + point.setStation(false); | ||
| 334 | + } else { | ||
| 335 | + return null; | ||
| 336 | + } | ||
| 337 | + } | ||
| 338 | + | ||
| 339 | + return point; | ||
| 340 | + } | ||
| 341 | + | ||
| 342 | + @GET | ||
| 343 | + @Path("/detour/{lineCode}/{direction}") | ||
| 344 | + public List<Detour> detour(@PathParam("lineCode") String lineCode, @PathParam("direction") int direction) { | ||
| 345 | + Integer version = line2version.get(lineCode); | ||
| 346 | + if (version == null) { | ||
| 347 | + version = 1; | ||
| 348 | + } | ||
| 349 | + List<Detour> detourList = jdbcTemplate.query("select * from bsth_c_detour where line = ? and versions = ? and direction = ?", new Object[]{ lineCode, version, direction }, BeanPropertyRowMapper.newInstance(Detour.class)); | ||
| 350 | + Map<String, Collection<StationRotue>> map = StationBufferData.findRouteByLineCode(lineCode); | ||
| 351 | + if (map.isEmpty()) { | ||
| 352 | + return new ArrayList<>(); | ||
| 353 | + } | ||
| 354 | + Collection<StationRotue> stationRotueCollection = map.get(String.format("%s_%d", lineCode, direction)); | ||
| 355 | + | ||
| 356 | + // 处理 detourList,将 startStationCode 和 terminalStationCode 替换为对应的索引值+1 | ||
| 357 | + processDetourStations(detourList, stationRotueCollection); | ||
| 358 | + | ||
| 359 | + // 过滤掉 terminalIdx 不大于 startIdx 的对象 | ||
| 360 | + List<Detour> filteredDetourList = new ArrayList<>(); | ||
| 361 | + for (Detour detour : detourList) { | ||
| 362 | + if (detour.getTerminalIdx() > detour.getStartIdx()) { | ||
| 363 | + filteredDetourList.add(detour); | ||
| 364 | + } | ||
| 365 | + } | ||
| 366 | + | ||
| 367 | + return filteredDetourList; | ||
| 368 | + } | ||
| 369 | + | ||
| 370 | + /** | ||
| 371 | + * 处理绕改道站点,将站点编码替换为对应的索引值+1 | ||
| 372 | + * @param detourList 绕改道列表 | ||
| 373 | + * @param stationRotueCollection 站点路由集合 | ||
| 374 | + */ | ||
| 375 | + private void processDetourStations(List<Detour> detourList, Collection<StationRotue> stationRotueCollection) { | ||
| 376 | + if (detourList == null || detourList.isEmpty() || stationRotueCollection == null || stationRotueCollection.isEmpty()) { | ||
| 377 | + return; | ||
| 378 | + } | ||
| 379 | + | ||
| 380 | + // 将 stationRotueCollection 转换为列表,以便获取索引 | ||
| 381 | + List<StationRotue> stationRotueList = new ArrayList<>(stationRotueCollection); | ||
| 382 | + | ||
| 383 | + // 遍历 detourList,处理每个绕改道对象 | ||
| 384 | + for (Detour detour : detourList) { | ||
| 385 | + String startStationCode = detour.getStartStationCode(); | ||
| 386 | + String terminalStationCode = detour.getTerminalStationCode(); | ||
| 387 | + | ||
| 388 | + // 查找起点站的索引 | ||
| 389 | + for (int i = 0; i < stationRotueList.size(); i++) { | ||
| 390 | + StationRotue stationRotue = stationRotueList.get(i); | ||
| 391 | + if (startStationCode != null && startStationCode.equals(stationRotue.getStationCode())) { | ||
| 392 | + detour.setStartIdx(i + 1); // 索引值+1 | ||
| 393 | + break; | ||
| 394 | + } | ||
| 395 | + } | ||
| 396 | + | ||
| 397 | + // 查找终点站的索引 | ||
| 398 | + for (int i = detour.getStartIdx(); i < stationRotueList.size(); i++) { | ||
| 399 | + StationRotue stationRotue = stationRotueList.get(i); | ||
| 400 | + if (terminalStationCode != null && terminalStationCode.equals(stationRotue.getStationCode())) { | ||
| 401 | + detour.setTerminalIdx(i + 1); // 索引值+1 | ||
| 402 | + break; | ||
| 403 | + } | ||
| 404 | + } | ||
| 405 | + } | ||
| 406 | + } | ||
| 407 | + | ||
| 408 | + @Override | ||
| 409 | + public void afterPropertiesSet() throws Exception { | ||
| 410 | + reload(); | ||
| 411 | + } | ||
| 412 | +} |
src/main/java/com/bsth/util/GeoUtils.java
0 → 100644
| 1 | +package com.bsth.util; | ||
| 2 | + | ||
| 3 | +import com.bsth.entity.Point; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * Created by panzhao on 2016/12/23. | ||
| 7 | + */ | ||
| 8 | +public class GeoUtils { | ||
| 9 | + | ||
| 10 | + private final static double EARTH_RADIUS = 6378137; | ||
| 11 | + | ||
| 12 | + public static double getDistance(Point p1, Point p2) { | ||
| 13 | + double lng1 = getLoop(p1.getLon(), -180, 180), lat1 = getRange( | ||
| 14 | + p1.getLat(), -74, 74); | ||
| 15 | + double lng2 = getLoop(p2.getLon(), -180, 180), lat2 = getRange( | ||
| 16 | + p2.getLat(), -74, 74); | ||
| 17 | + | ||
| 18 | + double x1, x2, y1, y2; | ||
| 19 | + x1 = degreeToRad(lng1); | ||
| 20 | + y1 = degreeToRad(lat1); | ||
| 21 | + x2 = degreeToRad(lng2); | ||
| 22 | + y2 = degreeToRad(lat2); | ||
| 23 | + return EARTH_RADIUS | ||
| 24 | + * Math.acos((Math.sin(y1) * Math.sin(y2) + Math.cos(y1) | ||
| 25 | + * Math.cos(y2) * Math.cos(x2 - x1))); | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + private static double getLoop(double v, double a, double b) { | ||
| 29 | + while (v > b) { | ||
| 30 | + v -= b - a; | ||
| 31 | + } | ||
| 32 | + while (v < a) { | ||
| 33 | + v += b - a; | ||
| 34 | + } | ||
| 35 | + return v; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + private static double getRange(double v, double a, double b) { | ||
| 39 | + v = Math.min(Math.max(v, a), b); | ||
| 40 | + return v; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + private static double degreeToRad(double degree) { | ||
| 44 | + return Math.PI * degree / 180; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * 计算点 到 线的距离 | ||
| 49 | + * @param line | ||
| 50 | + * @param p | ||
| 51 | + * @return | ||
| 52 | + */ | ||
| 53 | + public static double getDistanceFromLine(Point s, Point e, Point p){ | ||
| 54 | + double d1 = getDistance(s, p); | ||
| 55 | + double d2 = getDistance(p, e); | ||
| 56 | + double d3 = getDistance(s, e); | ||
| 57 | + double distance = 0; | ||
| 58 | + | ||
| 59 | + double alpha = Math.acos((d1*d1 + d3*d3 - d2*d2)/(2*d1*d3)); | ||
| 60 | + double beta = Math.acos((d2*d2 + d3*d3 - d1*d1)/(2*d2*d3)); | ||
| 61 | + | ||
| 62 | + if(alpha>Math.PI/2) { | ||
| 63 | + distance = d1; | ||
| 64 | + } | ||
| 65 | + else if(beta > Math.PI/2) { | ||
| 66 | + distance = d2; | ||
| 67 | + } | ||
| 68 | + else { | ||
| 69 | + distance = Math.sin(alpha) * d1; | ||
| 70 | + } | ||
| 71 | + return distance; | ||
| 72 | + } | ||
| 73 | +} |