| | |
| | | import org.springframework.boot.context.event.ApplicationReadyEvent; |
| | | import org.springframework.context.event.EventListener; |
| | | import org.springframework.stereotype.Service; |
| | | import com.zy.acs.common.utils.News; |
| | | |
| | | import java.security.MessageDigest; |
| | | import java.security.NoSuchAlgorithmException; |
| | |
| | | stopWatch.start(); |
| | | this.initLaneData(); |
| | | stopWatch.stop(); |
| | | log.info("the rcs system calculated lane data which has spend {} millisecond......", stopWatch.getTime()); |
| | | News.info("the rcs system calculated lane data which has spend {} millisecond......", stopWatch.getTime()); |
| | | |
| | | if (!Cools.isEmpty(this.laneDtoList)) { |
| | | laneService.batchSaveByLaneDtoList(null, this.laneDtoList); |
| | |
| | | } |
| | | |
| | | private void initLaneData() { |
| | | log.info("the rcs system is starting to initialize lane data..."); |
| | | News.info("the rcs system is starting to initialize lane data..."); |
| | | |
| | | List<Code> codeList = codeService.list(new LambdaQueryWrapper<Code>().eq(Code::getStatus, StatusType.ENABLE.val)); |
| | | |
| | |
| | | |
| | | this.generateLaneHash(); |
| | | |
| | | log.info("the lane data initialization has been completed in rcs system."); |
| | | News.info("the lane data initialization has been completed in rcs system."); |
| | | } |
| | | |
| | | private void fillAdjacencyCodeMap(List<Code> codeList) { |
| | |
| | | } |
| | | |
| | | for (String codeData : codeDataList) { |
| | | if (this.adjacencyCodeMap.get(codeData).size() == 2 && !visited.contains(codeData)) { |
| | | if (this.adjacencyCodeMap.get(codeData).size() == 2 |
| | | && !visited.contains(codeData) |
| | | && !this.isTurnCorner(codeData)) { |
| | | // 检查是否为环路的一部分 |
| | | LaneDto laneDto = new LaneDto(); |
| | | this.dfsCalcForLoop(codeData, null, laneDto, visited); |
| | | this.laneDtoList.add(laneDto); |
| | | if (!Cools.isEmpty(laneDto.getCodes())) { |
| | | this.laneDtoList.add(laneDto); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | private void dfsCalcIncludingEnd(String start, String current, LaneDto laneDto, Set<String> visited) { |
| | | // 如果 current 本身是拐角(degree=2 且不共线),不应该进入 lane |
| | | if (this.isTurnCorner(current)) { |
| | | return; |
| | | } |
| | | |
| | | laneDto.getCodes().add(current); |
| | | visited.add(current); |
| | | |
| | |
| | | if (!visited.contains(neighbor)) { |
| | | int degree = this.adjacencyCodeMap.get(neighbor).size(); |
| | | if (degree == 2) { |
| | | // 下一跳如果是拐角:直接在拐角前终止,且不把拐角算进 lane |
| | | if (this.isTurnCorner(neighbor)) { |
| | | continue; |
| | | } |
| | | if (this.isSameDirection(current, neighbor, start)) { |
| | | this.dfsCalcIncludingEnd(current, neighbor, laneDto, visited); |
| | | } |
| | |
| | | } |
| | | |
| | | private void dfsCalcForLoop(String current, String parent, LaneDto laneDto, Set<String> visited) { |
| | | // 环路 lane:拐角点不算入 lane,并且在拐角前停止 |
| | | if (this.isTurnCorner(current)) { |
| | | return; |
| | | } |
| | | |
| | | laneDto.getCodes().add(current); |
| | | visited.add(current); |
| | | |
| | |
| | | if (!visited.contains(neighbor)) { |
| | | int degree = this.adjacencyCodeMap.get(neighbor).size(); |
| | | if (degree == 2) { |
| | | // 下一跳如果是拐角:在拐角前终止,不把拐角加入 lane,也不标 visited |
| | | if (this.isTurnCorner(neighbor)) { |
| | | continue; |
| | | } |
| | | if (this.isSameDirection(current, neighbor, parent)) { |
| | | this.dfsCalcForLoop(neighbor, current, laneDto, visited); |
| | | } |
| | |
| | | |
| | | // 设置角度差阈值为3度 |
| | | return angleDifference < Math.toRadians(3); |
| | | } |
| | | |
| | | private boolean isTurnCorner(String codeData) { |
| | | if (Cools.isEmpty(codeData)) { |
| | | return false; |
| | | } |
| | | List<String> neighbors = this.adjacencyCodeMap.get(codeData); |
| | | if (neighbors == null || neighbors.size() != 2) { |
| | | return false; |
| | | } |
| | | |
| | | String n1 = neighbors.get(0); |
| | | String n2 = neighbors.get(1); |
| | | |
| | | Code c1 = codeService.getCacheByData(n1); |
| | | Code c = codeService.getCacheByData(codeData); |
| | | Code c2 = codeService.getCacheByData(n2); |
| | | |
| | | // v1 = c - c1, v2 = c2 - c |
| | | double v1x = c.getX() - c1.getX(); |
| | | double v1y = c.getY() - c1.getY(); |
| | | double v2x = c2.getX() - c.getX(); |
| | | double v2y = c2.getY() - c.getY(); |
| | | |
| | | // 两个向量任一为零向量:不按拐角处理 |
| | | double len1 = Math.hypot(v1x, v1y); |
| | | double len2 = Math.hypot(v2x, v2y); |
| | | if (len1 == 0 || len2 == 0) { |
| | | return false; |
| | | } |
| | | |
| | | // 夹角 cos = dot / (|v1||v2|) |
| | | double dot = v1x * v2x + v1y * v2y; |
| | | double cos = dot / (len1 * len2); |
| | | |
| | | // 共线有两种: |
| | | // 1) 180°:cos ≈ -1(直线走廊) |
| | | // 2) 0°:cos ≈ +1(路线异常回头),一般也视为共线 |
| | | // 只要“不接近 ±1”,就说明不在一条线上 -> 拐角 |
| | | double eps = Math.cos(Math.toRadians(3)); // 3度容差 |
| | | boolean nearOpposite = cos <= -eps; // 接近 -1 |
| | | boolean nearSame = cos >= eps; // 接近 +1 |
| | | return !(nearOpposite || nearSame); |
| | | } |
| | | |
| | | /** |
| | |
| | | try { |
| | | md = MessageDigest.getInstance("SHA-256"); |
| | | } catch (NoSuchAlgorithmException e) { |
| | | log.error("generateDigest", e); |
| | | News.error("generateDigest", e); |
| | | throw new RuntimeException(e); |
| | | } |
| | | String combined = list.stream().sorted().collect(Collectors.joining(",")); |
| | |
| | | } |
| | | |
| | | public void generateLaneCodeIdx(Integer lev) { |
| | | log.info("There is initializing Lane CodeIdxMap......"); |
| | | News.info("There is initializing Lane CodeIdxMap......"); |
| | | if (Cools.isEmpty(this.laneDtoList)) { |
| | | return; |
| | | } |
| | |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |