SunvStation 地理信息系统采用分层架构设计，其中工作空间与地图是理解整个系统的核心概念。本页将详细阐述这两个核心组件的职责、相互关系以及在 Python 脚本中的使用方式。掌握这些概念是高效使用 sunvpy 库进行二次开发的基础。

## 系统架构概览

SunvStation 系统采用单例模式的工作空间作为顶级容器，管理所有地图实例和系统资源。工作空间通过 `getInstance()` 方法获取全局唯一实例，确保整个应用程序共享同一资源上下文。地图对象则表示特定比例尺的地理数据视图，包含图层、地物、数据源等子组件。

```mermaid
graph TB
    subgraph "应用程序级别"
        WS[WorkSpace 工作空间<br/>单例实例]
    end
    
    subgraph "地图级别"
        SM1[ScaleMap 地图1<br/>比例尺1:500]
        SM2[ScaleMap 地图2<br/>比例尺1:1000]
    end
    
    subgraph "SM1 组件"
        L1[图层1]
        L2[图层2]
        DS1[数据源EPS]
    end
    
    subgraph "SM2 组件"
        L3[图层3]
        L4[图层4]
        DS2[数据源EPS]
    end
    
    subgraph "Python 脚本"
        PSS[SSProcessManager<br/>SSProcess全局实例]
    end
    
    PSS --> |WorkSpace.getInstance| WS
    PSS --> |getCurrentScaleMap| SM1
    WS --> |管理多个| SM1
    WS --> |管理多个| SM2
    SM1 --> |包含| L1
    SM1 --> |包含| L2
    SM1 --> |引用| DS1
    SM2 --> |包含| L3
    SM2 --> |包含| L4
    SM2 --> |引用| DS2
```

上图展示了系统的核心架构。工作空间作为顶级容器，管理所有地图实例。每个地图对象包含一组图层和关联的数据源。Python 脚本通过 `SSProcess` 全局实例访问工作空间和当前地图，实现与系统资源的交互。

Sources: [PySSProcess.py](PySSProcess.py#L30-L60)

## 工作空间

工作空间是 SunvStation 系统的全局单例对象，负责管理整个应用程序的资源和上下文。它提供统一的入口点来访问当前活动的地图、配置信息和系统路径。

### 核心特性

工作空间采用单例设计模式，确保整个应用程序中只有一个工作空间实例。这种设计有以下优势：

- **资源统一管理**：所有地图实例和共享资源由工作空间统一分配和协调
- **全局状态一致性**：确保不同模块访问的系统状态保持一致
- **生命周期控制**：工作空间控制整个应用程序的生命周期，包括资源的创建和销毁

### 获取工作空间实例

在 Python 脚本中，通过 `WorkSpace.getInstance()` 方法获取工作空间实例。`SSProcessManager` 在初始化时会自动获取工作空间实例并存储为成员变量 `self.workspace`。

Sources: [PySSProcess.py](PySSProcess.py#L42-L43)

### 主要职责

工作空间的核心职责包括：

- **地图管理**：维护所有打开的地图实例，提供获取当前活动地图的接口
- **资源协调**：协调地图之间的资源共享和互斥访问
- **全局配置**：存储和管理全局配置信息
- **系统路径**：提供系统级路径信息（配置路径、模板路径、脚本路径等）

### 便捷访问方法

`ProjectMixin` 提供了便捷方法 `getWorkspace()` 来获取工作空间实例：

Sources: [ssprocess_mixins/project_mixin.py](ssprocess_mixins/project_mixin.py#L36-L43)

## 地图

地图对象（`ScaleMap`）表示特定比例尺的地理数据视图，是工作空间中最核心的可视化和编辑单元。每个地图包含一组图层、地物对象和关联的数据源。

### 地图对象定义

`ScaleMap` 类定义在 `PySSMap` 模块中，通过 SWIG 从 C++ 封装而来。它是地图数据的主要容器和管理者。

Sources: [PySSMap.py](PySSMap.py#L303-L330)

### 地图组成结构

地图由以下核心组件构成：

| 组件类型 | 职责 | Python 类型 |
|---------|------|-----------|
| 图层 | 组织和管理地物对象，控制可见性和锁定状态 | Layer |
| 数据源 | 存储地物数据的底层存储（EPS 数据库） | DataSource |
| 地物对象 | 点、线、面等地理要素 | GeoObject |
| 选择集 | 当前选中的地物集合 | GeoBaseList |
| 符号表 | 要素编码和符号样式定义 | FeatureList |

### 图层管理

图层是地图中组织地物的逻辑单元。每个图层对应特定的数据类型（点、线、面、注记），可以独立控制其可见性和编辑锁定状态。

#### 图层操作 API

| 方法 | 功能描述 |
|-----|---------|
| `getLayerSize()` | 获取图层数量 |
| `getLayerName(index)` | 获取指定索引的图层名称 |
| `setLayerVisible(layerName, status)` | 设置图层可见性 |
| `isLayerVisible(layerName)` | 检查图层是否可见 |
| `setLayerLock(layerName, status)` | 设置图层锁定状态 |
| `isLayerLock(layerName)` | 检查图层是否锁定 |

Sources: [PySSMap.py](PySSMap.py#L355-L430)

#### 便捷访问方法

`ProjectMixin` 提供了简化的图层访问接口：

Sources: [ssprocess_mixins/project_mixin.py](ssprocess_mixins/project_mixin.py#L180-L198)

### 数据源管理

数据源是存储地物数据的底层存储，通常是 EPS 格式的数据库。地图可以加载多个数据源，每个数据源包含多个数据集。

| 方法 | 功能描述 |
|-----|---------|
| `getCurrentDataSource()` | 获取当前激活的数据源 |
| `setCurrentDataSource(dataSource)` | 设置当前数据源 |
| `unloadDataSource(dataSource)` | 卸载指定的数据源 |
| `getDataSourceSet(dataSourceSet)` | 获取所有可见图层使用的数据源集合 |

Sources: [PySSMap.py](PySSMap.py#L445-L480)

### 地物搜索与检索

地图提供了强大的地物搜索功能，支持多种搜索条件：

| 方法 | 功能描述 |
|-----|---------|
| `searchObject(objList, ...)` | 根据编码、矩形范围、点位置等条件搜索地物 |
| `searchMarkNote(geoList, ...)` | 搜索注记对象 |
| `getNearObject(point, range, ...)` | 获取指定点附近的地物或注记 |
| `getObjectSize(objType)` | 获取指定类型的地物个数 |

Sources: [PySSMap.py](PySSMap.py#L650-L1000)

### 撤销与重做

地图内置了完整的撤销/重做机制，所有可撤销操作都会被记录在命令栈中。

| 方法 | 功能描述 |
|-----|---------|
| `pushUndoMark(action)` | 创建撤销标记，用于分组多个操作 |
| `undo(step=1)` | 执行撤销操作，step 指定步数 |
| `redo(step=1)` | 执行重做操作 |
| `getUndoStackSize()` | 获取撤销栈的大小 |
| `getRedoStackSize()` | 获取重做栈的大小 |

Sources: [PySSMap.py](PySSMap.py#L1565-L1610)

## 工作空间与地图的关系

工作空间和地图之间的关系是整体与部分的关系。工作空间作为全局容器，可以管理多个地图实例，但通常只有一个当前活动的地图。

### 访问当前地图

通过工作空间的 `getCurrentScaleMap()` 方法获取当前活动的地图实例。在 `SSProcessManager` 初始化时，会自动获取当前地图并存储为成员变量 `self.map`。

Sources: [PySSProcess.py](PySSProcess.py#L42-L43)

### 地图切换

当用户切换地图时（例如从不同比例尺的地图视图切换），工作空间会更新当前活动的地图引用。Python 脚本可以通过以下方式获取最新的当前地图：

```python
# 方法1：直接使用 SSProcess 的 map 成员
current_map = SSProcess.map

# 方法2：通过工作空间获取
current_map = SSProcess.workspace.getCurrentScaleMap()

# 方法3：使用便捷方法
current_map = SSProcess.getCurrentMap()
```

Sources: [ssprocess_mixins/project_mixin.py](ssprocess_mixins/project_mixin.py#L45-L50)

## 系统路径管理

工作空间和相关组件提供了获取系统路径的接口，这些路径对于脚本操作文件和配置非常重要。

### 路径类型表

| 模式 | 路径类型 | 说明 |
|-----|---------|------|
| 0 | 配置路径 | 存放系统配置文件 |
| 1 | 模板路径 | 存放模板文件 |
| 2 | Comm 路径 | 公共资源路径 |
| 3 | Script 路径 | 脚本文件路径 |
| 4 | SSTemp 路径 | 临时文件路径 |
| 5 | 工程文件路径 | 当前工程所在目录 |
| 6 | 系统目录 | Windows 系统目录或 Unix /usr |
| 7/8 | 工作台面目录 | 用户工作台面目录 |

Sources: [ssprocess_mixins/project_mixin.py](ssprocess_mixins/project_mixin.py#L52-L80)

### 使用示例

```python
# 获取脚本路径
script_path = SSProcess.getSysPathName(3)

# 获取当前工程文件所在目录
project_dir = SSProcess.getSysPathName(5)

# 获取配置路径
config_path = SSProcess.getSysPathName(0)
```

## 符号表管理

地图使用符号表来定义地物的显示样式和要素编码。符号表包括要素代码表、符号脚本表和注记模板表。

| 方法 | 功能描述 |
|-----|---------|
| `getFeatureCodeTB()` | 获取当前要素代码表名称 |
| `getSymbolScriptTB()` | 获取当前符号表名称 |
| `getNoteTemplateTB()` | 获取当前注记模板表名称 |
| `setFeatureCodeTB(codeTB, symbolTB)` | 设置要素代码表和符号表 |
| `setNoteTemplateTB(templateTB)` | 设置注记模板表 |

Sources: [ssprocess_mixins/project_mixin.py](ssprocess_mixins/project_mixin.py#L200-L267)

## 地图图幅管理

地图图幅是地图的一个逻辑划分单位，用于组织和管理地图的分幅显示。`ProjectMixin` 提供了图幅相关操作：

| 方法 | 功能描述 |
|-----|---------|
| `createMapFrame()` | 创建当前地图的图幅列表 |
| `getMapFrameCount()` | 获取图幅数量 |
| `getMapFrameCenterPoint(index)` | 获取指定图幅的中心点坐标 |
| `setCurMapFrame(x, y)` | 设置当前图幅 |
| `getCurMapFrame()` | 获取当前图幅的编号 |
| `getMapFrameNumber(x, y)` | 获取指定坐标所在的图幅号 |
| `freeMapFrame()` | 释放图幅资源 |

Sources: [ssprocess_mixins/project_mixin.py](ssprocess_mixins/project_mixin.py#L122-L178)

## 最佳实践

在使用工作空间和地图时，遵循以下最佳实践可以编写更健壮和高效的代码：

### 1. 始终检查空引用

访问地图或工作空间对象前，检查是否为 None：

```python
current_map = SSProcess.getCurrentMap()
if current_map is None:
    print("当前没有打开的地图")
    return
```

### 2. 使用便捷方法优先

`ProjectMixin` 提供的便捷方法已经处理了常见的边界情况，优先使用这些方法而不是直接访问底层对象。

### 3. 批量操作使用撤销标记

执行批量修改操作前，先创建撤销标记：

```python
SSProcess.pushUndoMark("批量属性修改")
# 执行批量操作...
```

### 4. 及时释放资源

对于创建的临时资源（如图幅列表），使用完毕后及时释放：

```python
try:
    SSProcess.createMapFrame()
    # 处理图幅...
finally:
    SSProcess.freeMapFrame()
```

### 5. 尊重图层锁定状态

修改地物前检查图层是否锁定：

```python
layer_name = "DLG"
if not SSProcess.map.isLayerLock(layer_name):
    # 执行修改操作
    pass
else:
    print(f"图层 {layer_name} 已锁定，无法编辑")
```

## 与其他文档的关联

理解工作空间与地图概念后，可以继续深入学习以下主题：

- **选择集与查询**：[清除与初始化选择集](11-qing-chu-yu-chu-shi-hua-xuan-ze-ji) 了解如何在地图中查询和选择地物
- **地理对象编辑**：[创建默认地物对象](19-chuang-jian-mo-ren-di-wu-dui-xiang) 学习如何在工作空间和地图中创建地物
- **项目与工作流**：[获取工作空间信息](34-huo-qu-gong-zuo-kong-jian-xin-xi) 探索更多工作空间信息获取方法
- **Mixin 设计模式**：[Mixin 设计模式](9-mixin-she-ji-mo-shi) 理解 ProjectMixin 等模块的设计理念

通过掌握工作空间与地图的核心概念，您将能够更高效地使用 sunvpy 库进行二次开发，构建功能强大的地理信息处理脚本。