1.1 用到的技术栈
1.2 实现思路
// 定义栅格网格参数private static final double CELL_SIZE_DEGREES = 0.005;private static int gridWidth = 0;//格子高度 index + 1private static int gridHeight = 0;//格子宽度// 1. 读取GeoJSON文件File geoJsonFile = new File("C:/aaa/src/main/resources/" + "map.geojson");SimpleFeatureCollection features = readGeoJson(geoJsonFile);// 2. 获取边界范围Envelope envelope = getEnvelope(features);// 3. 创建栅格网格GridCell[][] grid = createGrid(envelope);// 4. 将GeoJSON要素栅格化rasterizeFeatures(features, grid, envelope);// 5. 构建图结构SimpleWeightedGraph<GridCell, DefaultWeightedEdge> graph = buildGraph(grid);// 6. 定义起点和终点 new GridCell[gridHeight][gridWidth];GridCell start = grid[2][2]; // 左下角GridCell end = grid[gridHeight -1][gridWidth - 1]; // 右上角// 7. 运行A*算法AStarShortestPath<GridCell, DefaultWeightedEdge> aStar = new AStarShortestPath<>(graph, new ManhattanDistance());GraphPath<GridCell, DefaultWeightedEdge> path = aStar.getPath(start, end);// 8. 输出结果if (path != null) {System.out.println("找到路径,长度: " + path.getLength());for (GridCell cell : path.getVertexList()) {System.out.println("[" + cell.centerX + ", " + cell.centerY + "],");}} else {System.out.println("未找到路径");}}
// 读取GeoJSON文件private static SimpleFeatureCollection readGeoJson(File file) throws IOException {FeatureJSON fjson = new FeatureJSON();try (FileInputStream in = new FileInputStream(file)) {return (SimpleFeatureCollection) fjson.readFeatureCollection(in);}}
// 创建栅格网格private static GridCell[][] createGrid(Envelope envelope) {double minLon = envelope.getMinX() - CELL_SIZE_DEGREES * 1.5;double minLat = envelope.getMinY() - CELL_SIZE_DEGREES * 1.5;double maxLon = envelope.getMaxX() + CELL_SIZE_DEGREES * 1.5;double maxLat = envelope.getMaxY() + CELL_SIZE_DEGREES * 1.5;gridWidth = (int) Math.ceil((maxLon - minLon) / CELL_SIZE_DEGREES);gridHeight = (int) Math.ceil((maxLat - minLat) / CELL_SIZE_DEGREES);GridCell[][] grid = new GridCell[gridHeight][gridWidth];for (int y = 0; y < gridHeight; y++) {for (int x = 0; x < gridWidth; x++) {// 3. 计算当前单元格的左下角坐标 (minX, minY)// 3. 计算当前单元格的左下角坐标 (minX, minY)double currentCellMinX = minLon + x * CELL_SIZE_DEGREES;double currentCellMinY = minLat + y * CELL_SIZE_DEGREES;// 4. 计算当前单元格的右上角坐标 (maxX, maxY)double currentCellMaxX = currentCellMinX + CELL_SIZE_DEGREES;double currentCellMaxY = currentCellMinY + CELL_SIZE_DEGREES;// 5. 计算当前单元格的中心点坐标double centerX = currentCellMinX + CELL_SIZE_DEGREES / 2.0;double centerY = currentCellMinY + CELL_SIZE_DEGREES / 2.0;grid[y][x] = new GridCell(x, y,centerX,centerY);}}return grid;}// 网格单元类static class GridCell {final int x, y; // 网格坐标final double centerX, centerY; // 地理坐标boolean isObstacle = false;GridCell(int x, int y, double centerX, double centerY) {this.x = x;this.y = y;this.centerX = centerX;this.centerY = centerY;}@Overridepublic String toString() {return "Cell(" + x + "," + y + ")" + "lonlat(" + centerX + "," + centerY + ")" ;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;GridCell gridCell = (GridCell) o;return x == gridCell.x && y == gridCell.y;}@Overridepublic int hashCode() {return 31 * x + y;}}
// 栅格化要素private static void rasterizeFeatures(SimpleFeatureCollection features, GridCell[][] grid, Envelope envelope)throws FactoryException, TransformException {try (SimpleFeatureIterator it = features.features()) {while (it.hasNext()) {SimpleFeature feature = it.next();Geometry geom = (Geometry) feature.getDefaultGeometry();// 检查每个网格单元是否与几何图形相交for (int y = 0; y < gridHeight; y++) {for (int x = 0; x < gridWidth; x++) {GridCell cell = grid[y][x];GeometryFactory geometryFactory = new GeometryFactory();// 定义矩形的边界 (minX, minY) 到 (maxX, maxY)double minX = cell.centerX - CELL_SIZE_DEGREES / 2;double minY = cell.centerY - CELL_SIZE_DEGREES / 2;double maxX = cell.centerX + CELL_SIZE_DEGREES / 2;double maxY = cell.centerY + CELL_SIZE_DEGREES / 2;// 2. 定义矩形的顶点坐标 (按顺时针或逆时针顺序,最后一个点与第一个点相同)Coordinate[] coords = new Coordinate[] {new Coordinate(minX, minY), // 左下new Coordinate(maxX, minY), // 右下new Coordinate(maxX, maxY), // 右上new Coordinate(minX, maxY), // 左上new Coordinate(minX, minY) // 回到左下,闭合环};// 3. (可选,如果你需要更复杂的序列,这里直接用Coordinate数组)// CoordinateSequence coordinateSequence = geometryFactory.getCoordinateSequenceFactory().create(coords);// 4. 创建 LinearRing (外部边界)LinearRing shell = geometryFactory.createLinearRing(coords);// 5. 创建 Polygon (矩形)// 第二个参数是内孔的 LinearRing 数组,对于简单矩形,通常是空的Polygon rectangle = geometryFactory.createPolygon(shell, null);// Point point = new GeometryFactory().createPoint(new Coordinate(cell.centerX, cell.centerY));if (geom.intersects(rectangle)) {cell.isObstacle = true;}}}}}}
// 构建图结构private static SimpleWeightedGraph<GridCell, DefaultWeightedEdge> buildGraph(GridCell[][] grid) {SimpleWeightedGraph<GridCell, DefaultWeightedEdge> graph =new SimpleWeightedGraph<>(DefaultWeightedEdge.class);// 添加所有顶点for (int y = 0; y < gridHeight; y++) {for (int x = 0; x < gridWidth; x++) {if (!grid[y][x].isObstacle) {graph.addVertex(grid[y][x]);}}}// 添加边(8连通)for (int y = 0; y < gridHeight; y++) {for (int x = 0; x < gridWidth; x++) {if (grid[y][x].isObstacle) continue;// 检查8个相邻方向for (int dy = -1; dy <= 1; dy++) {for (int dx = -1; dx <= 1; dx++) {if (dx == 0 && dy == 0) continue; // 跳过自身int nx = x + dx;int ny = y + dy;if (nx >= 0 && nx < gridWidth && ny >= 0 && ny < gridHeight) {if (!grid[ny][nx].isObstacle && graph.containsVertex(grid[ny][nx])) {DefaultWeightedEdge edge = graph.addEdge(grid[y][x], grid[ny][nx]);if (edge != null) {// 对角线距离为√2,直线距离为1double weight = (dx != 0 && dy != 0) ? Math.sqrt(2) : 1.0;graph.setEdgeWeight(edge, weight);}}}}}}}return graph;}
public static class ManhattanDistance implements AStarAdmissibleHeuristic<GridCell> {@Overridepublic double getCostEstimate(GridCell source, GridCell target) {double dx = Math.abs(source.x - target.x);double dy = Math.abs(source.y - target.y);return dx + dy;// double dx = source.centerX - target.centerX;
// double dy = source.centerY - target.centerY;
// return Math.sqrt(dx * dx + dy * dy);}}
