feat(javaTest): compile routing map from full grid
This commit is contained in:
@@ -0,0 +1,128 @@
|
|||||||
|
package com.ft546.wcs.shadow.history.simulation;
|
||||||
|
|
||||||
|
import com.ft546.wcs.demo.model.Site;
|
||||||
|
import com.ft546.wcs.demo.traffic.GridMap;
|
||||||
|
import com.ft546.wcs.shadow.history.HistoricalMapCell;
|
||||||
|
import com.ft546.wcs.shadow.map.EffectiveTrafficMap;
|
||||||
|
import com.ft546.wcs.shadow.map.TrafficMapCompiler;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public final class HistoricalGridMapCompiler {
|
||||||
|
public CompiledHistoricalMap compile(List<HistoricalMapCell> cells) {
|
||||||
|
if (cells == null || cells.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("full map cells are required");
|
||||||
|
}
|
||||||
|
List<HistoricalMapCell> passable = new ArrayList<HistoricalMapCell>();
|
||||||
|
for (HistoricalMapCell cell : cells) {
|
||||||
|
if (cell.getValue() == 1 || cell.getValue() == 2) passable.add(cell);
|
||||||
|
}
|
||||||
|
Collections.sort(passable, Comparator.comparingInt(HistoricalMapCell::getZ)
|
||||||
|
.thenComparingInt(HistoricalMapCell::getY)
|
||||||
|
.thenComparingInt(HistoricalMapCell::getX)
|
||||||
|
.thenComparing(HistoricalMapCell::getSiteId));
|
||||||
|
|
||||||
|
GridMap gridMap = new GridMap();
|
||||||
|
Map<String, HistoricalMapCell> sites = new LinkedHashMap<String, HistoricalMapCell>();
|
||||||
|
Map<String, HistoricalMapCell> coordinates = new LinkedHashMap<String, HistoricalMapCell>();
|
||||||
|
for (HistoricalMapCell cell : passable) {
|
||||||
|
if (cell.getSiteId().trim().isEmpty() || sites.put(cell.getSiteId(), cell) != null) {
|
||||||
|
throw new IllegalArgumentException("passable site ids must be unique and nonblank");
|
||||||
|
}
|
||||||
|
if (coordinates.put(coordinate(cell.getX(), cell.getY(), cell.getZ()), cell) != null) {
|
||||||
|
throw new IllegalArgumentException("passable coordinates must be unique");
|
||||||
|
}
|
||||||
|
gridMap.addSite(new Site(cell.getSiteId(), cell.getZ(), cell.getX(), cell.getY(),
|
||||||
|
cell.getAxy().isEmpty() ? "OFFLINE" : cell.getAxy()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<TrafficMapCompiler.EdgeDefinition> trafficEdges =
|
||||||
|
new LinkedHashSet<TrafficMapCompiler.EdgeDefinition>();
|
||||||
|
for (HistoricalMapCell cell : passable) {
|
||||||
|
connectIfPresent(gridMap, trafficEdges, cell,
|
||||||
|
coordinates.get(coordinate(cell.getX() + 1, cell.getY(), cell.getZ())));
|
||||||
|
connectIfPresent(gridMap, trafficEdges, cell,
|
||||||
|
coordinates.get(coordinate(cell.getX(), cell.getY() + 1, cell.getZ())));
|
||||||
|
}
|
||||||
|
Set<String> nodeIds = new LinkedHashSet<String>(sites.keySet());
|
||||||
|
TrafficMapCompiler.MapDefinition definition = new TrafficMapCompiler.MapDefinition(
|
||||||
|
"FT546-FULL-GRID-SIM", 1L, "OFFLINE", true,
|
||||||
|
"full-grid-v1", "full-grid-v1", nodeIds, trafficEdges,
|
||||||
|
Collections.emptyMap(), Collections.emptySet(), Collections.emptySet());
|
||||||
|
EffectiveTrafficMap trafficMap = new TrafficMapCompiler().compile(definition);
|
||||||
|
return new CompiledHistoricalMap(gridMap, trafficMap, sites, components(gridMap));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connectIfPresent(GridMap map,
|
||||||
|
Set<TrafficMapCompiler.EdgeDefinition> trafficEdges,
|
||||||
|
HistoricalMapCell left, HistoricalMapCell right) {
|
||||||
|
if (right == null) return;
|
||||||
|
map.connect(left.getSiteId(), right.getSiteId());
|
||||||
|
trafficEdges.add(new TrafficMapCompiler.EdgeDefinition(
|
||||||
|
left.getSiteId(), right.getSiteId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Integer> components(GridMap map) {
|
||||||
|
Map<String, Integer> result = new LinkedHashMap<String, Integer>();
|
||||||
|
List<String> ids = new ArrayList<String>(map.getSites().keySet());
|
||||||
|
Collections.sort(ids);
|
||||||
|
int component = 0;
|
||||||
|
for (String start : ids) {
|
||||||
|
if (result.containsKey(start)) continue;
|
||||||
|
component++;
|
||||||
|
ArrayDeque<String> queue = new ArrayDeque<String>();
|
||||||
|
queue.add(start);
|
||||||
|
result.put(start, component);
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
String site = queue.removeFirst();
|
||||||
|
for (String neighbor : map.getNeighbors(site)) {
|
||||||
|
if (!result.containsKey(neighbor)) {
|
||||||
|
result.put(neighbor, component);
|
||||||
|
queue.addLast(neighbor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String coordinate(int x, int y, int z) {
|
||||||
|
return x + "," + y + "," + z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class CompiledHistoricalMap {
|
||||||
|
private final GridMap gridMap;
|
||||||
|
private final EffectiveTrafficMap trafficMap;
|
||||||
|
private final Map<String, HistoricalMapCell> passableSites;
|
||||||
|
private final Map<String, Integer> componentIds;
|
||||||
|
|
||||||
|
private CompiledHistoricalMap(GridMap gridMap, EffectiveTrafficMap trafficMap,
|
||||||
|
Map<String, HistoricalMapCell> passableSites,
|
||||||
|
Map<String, Integer> componentIds) {
|
||||||
|
this.gridMap = gridMap;
|
||||||
|
this.trafficMap = trafficMap;
|
||||||
|
this.passableSites = Collections.unmodifiableMap(
|
||||||
|
new LinkedHashMap<String, HistoricalMapCell>(passableSites));
|
||||||
|
this.componentIds = Collections.unmodifiableMap(
|
||||||
|
new LinkedHashMap<String, Integer>(componentIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
public GridMap getGridMap() { return gridMap; }
|
||||||
|
public EffectiveTrafficMap getTrafficMap() { return trafficMap; }
|
||||||
|
public Map<String, HistoricalMapCell> getPassableSites() { return passableSites; }
|
||||||
|
|
||||||
|
public int getComponentId(String siteId) {
|
||||||
|
Integer component = componentIds.get(siteId);
|
||||||
|
if (component == null) throw new IllegalArgumentException("unknown passable site " + siteId);
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.ft546.wcs.shadow.history.simulation;
|
||||||
|
|
||||||
|
import com.ft546.wcs.shadow.history.HistoricalMapCell;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class HistoricalGridMapCompilerTest {
|
||||||
|
@Test
|
||||||
|
void connectsOnlyPassableSameFloorManhattanNeighbors() {
|
||||||
|
HistoricalGridMapCompiler.CompiledHistoricalMap compiled =
|
||||||
|
new HistoricalGridMapCompiler().compile(Arrays.asList(
|
||||||
|
cell("A", 1, 1, 1, 1),
|
||||||
|
cell("B", 2, 1, 1, 2),
|
||||||
|
cell("BLOCK", 1, 2, 1, 0),
|
||||||
|
cell("DIAGONAL", 2, 2, 1, 1),
|
||||||
|
cell("UP", 1, 1, 2, 1)));
|
||||||
|
|
||||||
|
assertEquals(4, compiled.getGridMap().getSites().size());
|
||||||
|
assertFalse(compiled.getGridMap().getSites().containsKey("BLOCK"));
|
||||||
|
assertTrue(compiled.getGridMap().getNeighbors("A").contains("B"));
|
||||||
|
assertFalse(compiled.getGridMap().getNeighbors("A").contains("DIAGONAL"));
|
||||||
|
assertFalse(compiled.getGridMap().getNeighbors("A").contains("UP"));
|
||||||
|
assertEquals(2, compiled.getTrafficMap().getEdges().size());
|
||||||
|
assertEquals(compiled.getComponentId("A"), compiled.getComponentId("DIAGONAL"));
|
||||||
|
assertNotEquals(compiled.getComponentId("A"), compiled.getComponentId("UP"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private HistoricalMapCell cell(String id, int x, int y, int z, int value) {
|
||||||
|
return new HistoricalMapCell(id, x, y, z, value, x + "," + y,
|
||||||
|
"W", "AREA");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user