| | |
| | | } |
| | | |
| | | private List<NavigateNode> normalizeStationPath(List<NavigateNode> path) { |
| | | HashSet<Integer> stationIdSet = new HashSet<>(); |
| | | List<NavigateNode> filterList = new ArrayList<>(); |
| | | Integer lastStationId = null; |
| | | for (NavigateNode navigateNode : safeList(path)) { |
| | | if (navigateNode == null) { |
| | | continue; |
| | |
| | | continue; |
| | | } |
| | | Integer stationId = valueObject.getInteger("stationId"); |
| | | if (stationId == null || !stationIdSet.add(stationId)) { |
| | | if (stationId == null) { |
| | | continue; |
| | | } |
| | | // 仅压缩连续重复站点,保留环线重算场景下后续再次经过的同一站点。 |
| | | if (lastStationId != null && lastStationId.equals(stationId)) { |
| | | continue; |
| | | } |
| | | lastStationId = stationId; |
| | | NavigateNode clonedNode = navigateNode.clone(); |
| | | if (clonedNode == null) { |
| | | continue; |
| | |
| | | long lastSeenAt = System.currentTimeMillis(); |
| | | int segCursor = 0; |
| | | Integer lastCurrentStationId = null; |
| | | int lastMatchedPathIndex = -1; |
| | | boolean firstRun = true; |
| | | while (true) { |
| | | try { |
| | |
| | | break; |
| | | } |
| | | |
| | | int currentIndex = effectiveFullPath.indexOf(currentStation.getStationId()); |
| | | int currentIndex = resolveCurrentPathIndex( |
| | | effectiveFullPath, |
| | | currentStation.getStationId(), |
| | | lastMatchedPathIndex |
| | | ); |
| | | if (currentIndex < 0) { |
| | | Thread.sleep(500L); |
| | | firstRun = false; |
| | | continue; |
| | | } |
| | | lastMatchedPathIndex = currentIndex; |
| | | |
| | | int remaining = effectiveFullPath.size() - currentIndex - 1; |
| | | if (remaining <= 0) { |
| | |
| | | } |
| | | } |
| | | |
| | | private int resolveCurrentPathIndex(List<Integer> fullPathStationIds, |
| | | Integer currentStationId, |
| | | int lastMatchedPathIndex) { |
| | | if (fullPathStationIds == null || fullPathStationIds.isEmpty() || currentStationId == null) { |
| | | return -1; |
| | | } |
| | | if (lastMatchedPathIndex >= 0 |
| | | && lastMatchedPathIndex < fullPathStationIds.size() |
| | | && equalsInteger(currentStationId, fullPathStationIds.get(lastMatchedPathIndex))) { |
| | | return lastMatchedPathIndex; |
| | | } |
| | | |
| | | int nextIndex = findNextStationIndex(fullPathStationIds, currentStationId, Math.max(lastMatchedPathIndex + 1, 0)); |
| | | if (nextIndex >= 0) { |
| | | return nextIndex; |
| | | } |
| | | return findNextStationIndex(fullPathStationIds, currentStationId, 0); |
| | | } |
| | | |
| | | private int findNextStationIndex(List<Integer> path, Integer stationId, int fromIndex) { |
| | | if (path == null || path.isEmpty() || stationId == null) { |
| | | return -1; |
| | | } |
| | | int startIdx = Math.max(fromIndex, 0); |
| | | for (int i = startIdx; i < path.size(); i++) { |
| | | if (equalsInteger(stationId, path.get(i))) { |
| | | return i; |
| | | } |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | private boolean sendSegmentWithRetry(StationCommand command, |
| | | StationTaskTraceRegistry traceRegistry, |
| | | Integer traceVersion, |
| | |
| | | int total = path.size(); |
| | | List<Integer> segmentEndIndices = new ArrayList<>(); |
| | | if (liftTransferPath != null) { |
| | | int searchStartIdx = 0; |
| | | for (Integer liftTransferStationId : liftTransferPath) { |
| | | int endIndex = path.indexOf(liftTransferStationId); |
| | | int endIndex = findNextStationIndex(path, liftTransferStationId, searchStartIdx); |
| | | if (endIndex >= 0) { |
| | | searchStartIdx = endIndex + 1; |
| | | } |
| | | if (endIndex <= 0) { |
| | | continue; |
| | | } |
| | |
| | | return plan; |
| | | } |
| | | |
| | | private int findNextStationIndex(List<Integer> path, Integer stationId, int fromIndex) { |
| | | if (path == null || path.isEmpty() || stationId == null) { |
| | | return -1; |
| | | } |
| | | int startIdx = Math.max(fromIndex, 0); |
| | | for (int i = startIdx; i < path.size(); i++) { |
| | | if (stationId.equals(path.get(i))) { |
| | | return i; |
| | | } |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | private List<Integer> copyIntegerList(List<Integer> source) { |
| | | if (source == null) { |
| | | return new ArrayList<>(); |
| New file |
| | |
| | | package com.zy.common.utils; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.zy.common.model.NavigateNode; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.test.util.ReflectionTestUtils; |
| | | |
| | | import java.util.List; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.assertEquals; |
| | | |
| | | class NavigateUtilsTest { |
| | | |
| | | @Test |
| | | void normalizeStationPath_keepsLoopRevisitStationsWhileCompressingAdjacentDuplicates() { |
| | | NavigateUtils navigateUtils = new NavigateUtils(); |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | List<NavigateNode> normalizedPath = (List<NavigateNode>) ReflectionTestUtils.invokeMethod( |
| | | navigateUtils, |
| | | "normalizeStationPath", |
| | | List.of( |
| | | buildNode(121, 0, 0), |
| | | buildNode(121, 0, 1), |
| | | buildNode(124, 0, 2), |
| | | buildNode(186, 0, 3), |
| | | buildNode(189, 0, 4), |
| | | buildNode(121, 0, 5), |
| | | buildNode(124, 0, 6), |
| | | buildNode(124, 0, 7), |
| | | buildNode(125, 0, 8), |
| | | buildNode(127, 0, 9) |
| | | ) |
| | | ); |
| | | |
| | | List<Integer> stationIdList = normalizedPath.stream() |
| | | .map(node -> JSONObject.parseObject(node.getNodeValue()).getInteger("stationId")) |
| | | .collect(Collectors.toList()); |
| | | |
| | | assertEquals(List.of(121, 124, 186, 189, 121, 124, 125, 127), stationIdList); |
| | | } |
| | | |
| | | private NavigateNode buildNode(int stationId, int x, int y) { |
| | | NavigateNode node = new NavigateNode(x, y); |
| | | node.setNodeValue("{\"stationId\":" + stationId + "}"); |
| | | return node; |
| | | } |
| | | } |
| | |
| | | import org.springframework.context.ApplicationContext; |
| | | import org.springframework.test.util.ReflectionTestUtils; |
| | | |
| | | import java.util.List; |
| | | import java.util.function.Function; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.assertFalse; |
| | | import static org.junit.jupiter.api.Assertions.assertEquals; |
| | | import static org.mockito.ArgumentMatchers.any; |
| | | import static org.mockito.Mockito.mock; |
| | | import static org.mockito.Mockito.never; |
| | |
| | | class StationSegmentExecutorTest { |
| | | |
| | | @Test |
| | | void resolveCurrentPathIndex_prefersForwardOccurrenceForLoopRevisitStations() { |
| | | StationSegmentExecutor executor = new StationSegmentExecutor(new DeviceConfig(), mock(RedisUtil.class), command -> null); |
| | | |
| | | Integer second121Index = ReflectionTestUtils.invokeMethod( |
| | | executor, |
| | | "resolveCurrentPathIndex", |
| | | List.of(121, 124, 186, 189, 121, 124, 125, 127), |
| | | 121, |
| | | 3 |
| | | ); |
| | | Integer second124Index = ReflectionTestUtils.invokeMethod( |
| | | executor, |
| | | "resolveCurrentPathIndex", |
| | | List.of(121, 124, 186, 189, 121, 124, 125, 127), |
| | | 124, |
| | | 4 |
| | | ); |
| | | Integer same124Index = ReflectionTestUtils.invokeMethod( |
| | | executor, |
| | | "resolveCurrentPathIndex", |
| | | List.of(121, 124, 186, 189, 121, 124, 125, 127), |
| | | 124, |
| | | 5 |
| | | ); |
| | | |
| | | assertEquals(Integer.valueOf(4), second121Index); |
| | | assertEquals(Integer.valueOf(5), second124Index); |
| | | assertEquals(Integer.valueOf(5), same124Index); |
| | | } |
| | | |
| | | @Test |
| | | void sendSegmentWithRetry_skipsWhenRouteIsCancelPending() { |
| | | ApplicationContext applicationContext = mock(ApplicationContext.class); |
| | | StationMoveCoordinator coordinator = new StationMoveCoordinator(); |
| New file |
| | |
| | | package com.zy.core.thread.impl.station; |
| | | |
| | | import com.zy.core.enums.StationCommandType; |
| | | import com.zy.core.model.command.StationCommand; |
| | | import org.junit.jupiter.api.Test; |
| | | |
| | | import java.util.List; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.assertEquals; |
| | | import static org.junit.jupiter.api.Assertions.assertTrue; |
| | | |
| | | class StationSegmentPlannerTest { |
| | | |
| | | @Test |
| | | void buildPlan_usesLaterLiftTransferOccurrencesWhenLoopPathRevisitsStations() { |
| | | StationSegmentPlanner planner = new StationSegmentPlanner(); |
| | | |
| | | StationCommand original = new StationCommand(); |
| | | original.setTaskNo(11017); |
| | | original.setCommandType(StationCommandType.MOVE); |
| | | original.setStationId(121); |
| | | original.setTargetStaNo(127); |
| | | original.setNavigatePath(List.of(121, 124, 186, 189, 121, 124, 125, 127)); |
| | | original.setLiftTransferPath(List.of(121, 124, 186, 189, 121, 124, 127)); |
| | | |
| | | StationSegmentExecutionPlan plan = planner.buildPlan(original); |
| | | |
| | | assertEquals( |
| | | List.of( |
| | | List.of(121, 124), |
| | | List.of(124, 186), |
| | | List.of(186, 189), |
| | | List.of(189, 121), |
| | | List.of(121, 124), |
| | | List.of(124, 125, 127) |
| | | ), |
| | | plan.getSegmentCommands().stream() |
| | | .map(StationCommand::getNavigatePath) |
| | | .collect(Collectors.toList()) |
| | | ); |
| | | assertEquals(List.of(1, 2, 3, 4, 5, 6), |
| | | plan.getSegmentCommands().stream() |
| | | .map(StationCommand::getSegmentNo) |
| | | .collect(Collectors.toList())); |
| | | assertTrue(plan.getSegmentCommands().stream() |
| | | .allMatch(command -> Integer.valueOf(6).equals(command.getSegmentCount()))); |
| | | } |
| | | } |