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