Skip to main content

No project description provided

Project description

🧠 地理空间感知系统(Geospatial Sense System)完整项目模板

📌 项目概述

本项目旨在构建一个地理空间感知系统,帮助智能体(如自动驾驶车辆、机器人、无人机等)感知和理解其周围的地理环境。该系统支持从多种数据源(包括手动输入、GeoJSON 文件、Shapefile 文件)加载地理数据,并提供路径规划、可视化、感知等功能。


🧱 一、总体架构设计

✅ 核心目标

  • 统一处理地理数据:POI、道路网络、坐标点。
  • 多数据源支持:支持 .geojson.shp 文件导入。
  • 自动节点合并:避免重复的 POI 节点。
  • 路径规划与分析:Dijkstra、A* 等算法。
  • 可视化能力:地图展示、路径高亮、热力图等。
  • 模块化结构:便于扩展、测试和维护。

📁 二、目录结构(推荐)

geospatial-awareness/
├── src/
│   └── gisense/
│       ├── core/                 # 核心类定义
│       │   ├── graph.py          # LocationGraph 主类
│       │   ├── exceptions.py     # 自定义异常类
│       │   └── observer.py       # 智能体观察者
│       ├── entities/             # 数据实体定义
│       │   ├── coordinate.py     # 经纬度封装
│       │   ├── poi.py            # POI 类
│       │   └── road.py           # Road 类
│       ├── io/                   # 输入输出模块
│       │   ├── geojson_reader.py # GeoJSON 解析
│       │   └── shapefile_reader.py # Shapefile 解析
│       ├── algorithms/           # 路径规划算法
│       │   ├── pathfinding.py    # Dijkstra/A*
│       │   └── perception.py     # 地理感知逻辑
│       ├── visualization/        # 可视化模块
│       │   └── map_visualizer.py # 路网/路径可视化
│       └── utils/                # 工具函数
│           ├── distance.py       # 距离计算
│           └── geometry.py       # 几何操作
├── tests/                        # 单元测试
├── docs/                         # 文档(Sphinx)
├── examples/                     # 使用示例脚本
├── pyproject.toml                # 构建配置文件
├── requirements.txt              # 第三方依赖
└── README.md                     # 项目说明文档

🧩 三、核心类与模块设计

1. LocationGraph(src/gisense/core/graph.py)

作为整个系统的主入口,负责管理 POI、Road、邻接表,并提供路径查找、数据导入、感知接口。

from typing import Dict, List, Optional
from gisense.entities.poi import POI
from gisense.entities.road import Road
from gisense.utils.geometry import CoordinateMatcher

class LocationGraph:
    def __init__(self):
        self.pois: Dict[str, POI] = {}
        self.roads: Dict[str, Road] = {}
        self.adjacency_list: Dict[str, Dict[str, str]] = {}
        self._coordinate_to_poi_id = CoordinateMatcher()  # 自动去重相同坐标的POI

    def add_poi(self, poi: POI) -> None:
        coord_key = (poi.coordinate.latitude, poi.coordinate.longitude)
        if coord_key in self._coordinate_to_poi_id:
            existing_id = self._coordinate_to_poi_id[coord_key]
            print(f"Coordinate conflict: '{poi.id}' merged with '{existing_id}'")
            return
        if poi.id in self.pois:
            raise ValueError(f"POI ID '{poi.id}' already exists")
        self.pois[poi.id] = poi
        self.adjacency_list[poi.id] = {}

    def add_road(self, road: Road) -> None:
        start_id = road.start_poi.id
        end_id = road.end_poi.id
        if start_id not in self.pois or end_id not in self.pois:
            raise ValueError("Start or End POI does not exist")
        self.roads[road.id] = road
        self.adjacency_list[start_id][end_id] = road.id
        if road.bidirectional:
            self.adjacency_list[end_id][start_id] = road.id

    def find_path(self, start_id: str, end_id: str) -> List[str]:
        # 调用 Dijkstra 或 A*
        from gisense.algorithms.pathfinding import dijkstra_shortest_path
        return dijkstra_shortest_path(self, start_id, end_id)

2. CoordinateMatcher(utils/geometry.py)

支持坐标匹配与自动去重。

from typing import Tuple, Dict

class CoordinateMatcher:
    def __init__(self, tolerance=1e-5):
        self.tolerance = tolerance
        self._map = {}  # {(lat, lon): poi_id}

    def __contains__(self, coord: Tuple[float, float]):
        for stored in self._map:
            if abs(stored[0] - coord[0]) < self.tolerance and \
               abs(stored[1] - coord[1]) < self.tolerance:
                return True
        return False

    def get_closest(self, coord: Tuple[float, float]) -> Optional[Tuple[float, float]]:
        for stored in self._map:
            if abs(stored[0] - coord[0]) < self.tolerance and \
               abs(stored[1] - coord[1]) < self.tolerance:
                return stored
        return None

    def add(self, coord: Tuple[float, float], poi_id: str):
        closest = self.get_closest(coord)
        if closest:
            return self._map[closest]
        self._map[coord] = poi_id
        return poi_id

3. ShapefileReader(io/shapefile_reader.py)

使用 geopandas 加载 .shp 文件并构建路网结构。

import geopandas as gpd
from shapely.geometry import LineString
from gisense.entities.poi import POI
from gisense.entities.road import Road
from gisense.entities.coordinate import Coordinate

class ShapefileReader:
    @staticmethod
    def read(shapefile_path: str) -> dict:
        gdf = gpd.read_file(shapefile_path)
        pois = []
        roads = []

        for _, row in gdf.iterrows():
            geom = row.geometry
            if isinstance(geom, LineString):
                coords = list(geom.coords)
                start_lon, start_lat = coords[0]
                end_lon, end_lat = coords[-1]

                start_poi = POI(
                    id=f"poi_{start_lat}_{start_lon}",
                    name="Node Start",
                    type="Intersection",
                    coordinate=Coordinate(start_lat, start_lon)
                )
                end_poi = POI(
                    id=f"poi_{end_lat}_{end_lon}",
                    name="Node End",
                    type="Intersection",
                    coordinate=Coordinate(end_lat, end_lon)
                )

                road = Road(
                    id=row.get('road_id', f"road_{len(roads)}"),
                    start_poi=start_poi,
                    end_poi=end_poi,
                    road_type=row.get('type', 'unknown'),
                    speed_limit=row.get('speed', 50),
                    bidirectional=True
                )
                pois.append(start_poi)
                pois.append(end_poi)
                roads.append(road)

        return {'pois': pois, 'roads': roads}

4. Observer(core/observer.py)

智能体观察者,可基于不同定位方式感知周围环境。

from typing import Union
from gisense.entities.poi import POI
from gisense.entities.coordinate import Coordinate
from gisense.core.graph import LocationGraph

class Observer:
    def __init__(self, position: Union[POI, Coordinate, str]):
        self.position = position

    def perceive(self, graph: LocationGraph):
        from gisense.algorithms.perception import perceive_surroundings
        return perceive_surroundings(graph, self.position)

5. perceive_surroundings(algorithms/perception.py)

from typing import Union
from gisense.core.graph import LocationGraph
from gisense.entities.poi import POI
from gisense.entities.coordinate import Coordinate

def perceive_surroundings(
    graph: LocationGraph,
    position: Union[POI, Coordinate, str]
):
    # 实现感知逻辑
    nearby_pois = graph.find_nearby_pois(position)
    nearby_roads = graph.find_nearby_roads(position)
    return {
        "nearby_pois": nearby_pois,
        "nearby_roads": nearby_roads
    }

📦 四、依赖管理(requirements.txt)

geopandas>=0.13.0
shapely>=2.0.0
pyproj>=3.6.0
matplotlib>=3.7.0
networkx>=3.0

🧪 五、使用示例(examples/example_usage.py)

from gisense.core.graph import LocationGraph
from gisense.io.shapefile_reader import ShapefileReader

graph = LocationGraph()

# 从 Shapefile 加载路网
result = ShapefileReader.read("data/roads.shp")
for poi in result['pois']:
    graph.add_poi(poi)
for road in result['roads']:
    graph.add_road(road)

# 查找路径
path = graph.find_path("poi_1", "poi_2")
print("Path:", path)

📘 六、文档生成(docs/)

使用 Sphinx + MyST Parser 支持 Markdown 编写 API 文档:

sphinx-quickstart
pip install sphinx myst-parser

🧪 七、测试框架(tests/)

使用 pytest 进行单元测试:

pytest tests/test_graph.py

✅ 八、总结

功能 实现方式
自动节点合并 使用 CoordinateMatcher 去重相同坐标的 POI
支持 GeoJSON 导入 GeoJsonReader 解析 FeatureCollection
支持 Shapefile 导入 ShapefileReader 使用 geopandas
路径规划 Dijkstra, A* 算法实现
观察者模型 Observer 抽象类感知周围信息
模块化设计 分为 core/io/entities/algorithms/visualization/utils

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gisense-0.0.1.tar.gz (47.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gisense-0.0.1-py3-none-any.whl (100.1 kB view details)

Uploaded Python 3

File details

Details for the file gisense-0.0.1.tar.gz.

File metadata

  • Download URL: gisense-0.0.1.tar.gz
  • Upload date:
  • Size: 47.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.1

File hashes

Hashes for gisense-0.0.1.tar.gz
Algorithm Hash digest
SHA256 a4a94d8bf722dd4b83cc756ed5fb29f7e14c9057fc13241bf570e99fb0e23e8d
MD5 cb04fa9a2bd73558364f0f76cb87a98f
BLAKE2b-256 baeeafc61b01f00710fba1c9625e5b9a305ff3a1cf880caa8e3dabf302cac844

See more details on using hashes here.

File details

Details for the file gisense-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: gisense-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 100.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.1

File hashes

Hashes for gisense-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 7da1518aa17955b8ddd9231f731f7e9b1f181bc1f7972f4b78f003bf3090633e
MD5 e6a0dc2be0d1623e390490e41ddf9847
BLAKE2b-256 cb54781dc16fa47880b8804d4e0f25fea0ddbff7cfa3a7acb96580321aceb76c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page