本页面将引导您编写第一个 SunvStation Python 脚本，从最基础的地物属性查询开始。通过实际案例，您将学习如何使用选择集过滤地物对象，并读取它们的属性信息。这是所有数据处理和编辑操作的基础起点。

## 脚本功能概览

我们的第一个脚本将实现以下完整流程：在当前地图中按照编码条件筛选地物对象，然后遍历选择集中的每个对象，读取并显示其核心属性信息。这个示例涵盖了脚本开发的四个核心环节——准备工作、筛选对象、遍历结果、输出信息。

Sources: [PySSProcess.py](PySSProcess.py#L110-L140)

## 完整工作流程

让我们先通过一个流程图理解整个脚本的数据流转过程，这有助于把握各步骤之间的逻辑关系：

```mermaid
flowchart LR
    A[初始化 SSProcess<br>获取工作空间与地图] --> B[清除旧选择集<br>clearSelection]
    B --> C[清除旧选择条件<br>clearSelectCondition]
    C --> D[设置筛选条件<br>setSelectCondition]
    D --> E[执行过滤查询<br>selectFilter]
    E --> F{选择集非空?}
    F -->|是| G[获取对象数量<br>getSelGeoCount]
    F -->|否| H[脚本结束]
    G --> I[循环遍历对象]
    I --> J[获取对象属性<br>getSelGeoValue]
    J --> K[输出属性信息]
    K --> L{还有对象?}
    L -->|是| I
    L -->|否| H
```

这个流程图展示了脚本的核心执行路径，其中每个节点对应一个关键的 API 调用。接下来的详细教程将逐步解析每个节点的具体实现。

Sources: [PySSProcess.py](PySSProcess.py#L110-L140)

## 步骤一：准备环境与初始化

在编写任何脚本之前，首先需要导入 sunvpy 模块中的核心类 `SSProcess`。这是一个全局单例对象，封装了工作空间、地图、选择集以及所有地物操作的核心功能。初始化完成后，`SSProcess` 会自动获取当前 SunvStation 系统的工作空间和活动地图实例，为后续操作做好准备。

```python
from sunvpy import SSProcess
```

这个简单的导入语句就完成了所有必要的准备工作。`SSProcess` 内部维护了 `WorkSpace`（工作空间）和 `ScaleMap`（比例尺地图）两个核心对象，以及 `GeoBaseList`（地物列表）、`SSearchHelper`（搜索助手）等辅助对象，共同构成了脚本运行的基础环境。

Sources: [PySSProcess.py](PySSProcess.py#L35-L70)

## 步骤二：清理选择集与条件

在开始新的查询之前，良好的习惯是清理之前可能残留的选择集和选择条件。这确保了脚本的执行结果不受上一次操作的影响，提高了脚本的可重复性和可靠性。

```python
SSProcess.clearSelection()      # 清除脚本选择集中的所有对象
SSProcess.clearSelectCondition() # 清除之前设置的选择条件
```

`clearSelection()` 会清空 `selGeoList`（点线面地物列表）和 `selNoteList`（注记对象列表），而 `clearSelectCondition()` 则会清空 `searchHelper` 中存储的过滤条件。这两个方法都是无参数的简单调用，为后续操作提供一个干净的开始状态。

Sources: [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L28-L50)

## 步骤三：设置选择条件

选择条件定义了我们要筛选地物的规则。SunvStation 支持三种类型的属性：基本属性、几何特性和扩展属性，它们通过不同的前缀标识符来区分。

### 条件类型说明

| 属性类型 | 前缀标识 | 示例 | 说明 |
|---------|---------|------|------|
| 基本属性 | `SSObj_` | `SSObj_Code` | 以 SSObj_ 开头的系统内置属性 |
| 几何特性 | `< >` | `<Overlap>` | 用尖括号括住的几何判断条件 |
| 扩展属性 | `[ ]` | `[JG]` | 用方括号括住的自定义扩展属性 |

### 操作符支持

系统提供了丰富的比较操作符，满足各种查询需求：

| 操作符 | 含义 | 示例 |
|--------|------|------|
| `==` | 等于 | `SSObj_Code == "3103013"` |
| `>` | 大于 | `SSObj_Length > "100"` |
| `<` | 小于 | `SSObj_Area < "500"` |
| `<>` | 不等于 | `SSObj_Type <> "NOTE"` |
| `LIKE` | 模糊匹配 | `SSObj_Name LIKE "%道路%"` |
| `NOT LIKE` | 不匹配 | `SSObj_Name NOT LIKE "%临时%"` |
| `CompareNoCase` | 忽略大小写比较 | `SSObj_Name CompareNoCase "MAIN"` |
| `Dec` | 小数位比较 | `SSObj_Area Dec 2` |

### 设置选择条件代码

在我们的第一个脚本中，我们将按照地物编码进行筛选：

```python
SSProcess.setSelectCondition("SSObj_Code", "==", "3103013")
```

这行代码会调用 `searchHelper.addCondition()` 方法，将条件添加到过滤条件列表中。地物编码 `3103013` 是一个具体的编码值，表示我们要筛选出编码为 3103013 的所有地物对象。

Sources: [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L52-L110)

## 步骤四：执行过滤查询

设置好选择条件后，需要调用 `selectFilter()` 方法来实际执行查询。这个方法会在当前数据源中查找符合所有设置条件的对象，并将它们添加到脚本选择集中。

```python
SSProcess.selectFilter()
```

`selectFilter()` 方法执行以下操作流程：

1. 调用 `searchHelper.getFilterObj()` 获取初步过滤的对象列表
2. 调用 `searchHelper.filterObj()` 进行精确过滤
3. 将过滤结果根据对象类型分别添加到 `selGeoList` 或 `selNoteList`
4. 在整个过程中显示进度条，提升用户体验

执行完成后，所有符合条件的对象都存储在 `SSProcess` 的内部选择集列表中，可以通过索引访问它们。

Sources: [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L112-L133)

## 步骤五：获取选择集对象数量

在遍历选择集之前，通常需要先了解查询到了多少对象，这有助于后续的逻辑判断和循环控制。

```python
geo_count = SSProcess.getSelGeoCount()
print(f"选择集中的点线面对象数量: {geo_count}")
```

`getSelGeoCount()` 方法返回 `selGeoList` 的长度，即当前选择集中的点、线、面对象总数。如果还有注记对象，可以使用 `getSelNoteCount()` 方法获取注记对象的数量。了解对象数量可以帮助我们判断查询结果是否符合预期，或者避免在空选择集上执行不必要的操作。

Sources: [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L152-L162)

## 步骤六：遍历选择集并读取属性

现在我们进入了脚本的核心部分——遍历选择集中的每个对象，并读取它们的属性值。这需要使用 `getSelGeoValue()` 方法，它接受两个参数：对象在选择集中的索引和属性名称。

### 常用地物属性速查表

| 属性名称 | 属性说明 | 数据类型 | 示例值 |
|---------|---------|---------|--------|
| `SSObj_ID` | 对象唯一标识 | 整数 | 1001 |
| `SSObj_Code` | 地物编码 | 整数 | 3103013 |
| `SSObj_LayerName` | 所在图层名 | 字符串 | "Default_A" |
| `SSObj_Type` | 对象类型 | 字符串 | "POINT", "LINE", "AREA", "NOTE" |
| `SSObj_Color` | 颜色值 | 整数 | 16777215 (白色) |
| `SSObj_LineType` | 线型 | 整数 | 1 |
| `SSObj_LineWidth` | 线宽 | 整数 | 2 |
| `SSObj_Name` | 对象名称 | 字符串 | "道路1" |
| `SSObj_Byname` | 对象别名 | 字符串 | "主路" |
| `SSObj_Area` | 面积 | 浮点数 | 1234.56 |
| `SSObj_Length` | 长度 | 浮点数 | 567.89 |
| `SSObj_PointCount` | 坐标点数量 | 整数 | 5 |
| `SSObj_X` | X坐标 | 浮点数 | 12345.67 |
| `SSObj_Y` | Y坐标 | 浮点数 | 54321.09 |

### 遍历代码示例

以下代码展示了如何遍历选择集的前10个对象，并读取它们的多个属性：

```python
# 定义要读取的属性列表
fields = [
    "SSObj_ID", "SSObj_Code", "SSObj_LayerName", "SSObj_Type", "SSObj_Color",
    "SSObj_LineType", "SSObj_LineWidth", "SSObj_Name", "SSObj_Byname",
    "SSObj_Area", "SSObj_Length", "SSObj_X", "SSObj_Y"
]

# 遍历选择集（最多显示前10个对象）
for i in range(min(10, geo_count)):
    print(f"第 {i} 个对象属性：")
    for field in fields:
        value = SSProcess.getSelGeoValue(i, field)
        print(f"  {field}: {value}")
    print("-" * 40)
```

`getSelGeoValue()` 方法内部会根据属性名的前缀判断属性类型：
- 如果属性名以 `[` 开头，则调用 `map.getExtentAttr()` 获取扩展属性
- 否则，调用 `objBaseAttr.getGeoValue()` 获取基本属性

这种设计使得属性读取接口对用户保持统一，而内部实现则根据属性类型自动适配。

Sources: [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L189-L261)

## 完整示例脚本

将上述所有步骤组合起来，我们就得到了一个完整可运行的第一个脚本：

```python
from sunvpy import SSProcess

# 1. 清理选择集和条件
SSProcess.clearSelection()
SSProcess.clearSelectCondition()

# 2. 设置筛选条件：按编码筛选
SSProcess.setSelectCondition("SSObj_Code", "==", "3103013")

# 3. 执行过滤查询
SSProcess.selectFilter()

# 4. 获取选择集对象数量
geo_count = SSProcess.getSelGeoCount()
print(f"选择集中的点线面对象数量: {geo_count}")

# 5. 定义要读取的属性列表
fields = [
    "SSObj_ID", "SSObj_Code", "SSObj_LayerName", "SSObj_Type", "SSObj_Color",
    "SSObj_LineType", "SSObj_LineWidth", "SSObj_Name", "SSObj_Byname",
    "SSObj_Area", "SSObj_Length", "SSObj_PointCount", "SSObj_X", "SSObj_Y"
]

# 6. 遍历选择集并读取属性
for i in range(min(10, geo_count)):
    print(f"第 {i} 个对象属性：")
    for field in fields:
        value = SSProcess.getSelGeoValue(i, field)
        print(f"  {field}: {value}")
    print("-" * 40)
```

运行这个脚本后，您将在控制台看到每个选中对象的详细属性信息，格式化输出为清晰的键值对形式，便于查看和调试。

Sources: [PySSProcess.py](PySSProcess.py#L110-L140)

## 脚本执行结果示例

假设我们的地图中有3个编码为3103013的地物对象，脚本执行后的输出可能如下：

```
选择集中的点线面对象数量: 3
第 0 个对象属性：
  SSObj_ID: 1001
  SSObj_Code: 3103013
  SSObj_LayerName: Default_A
  SSObj_Type: LINE
  SSObj_Color: 16777215
  SSObj_LineType: 1
  SSObj_LineWidth: 1
  SSObj_Name: 道路1
  SSObj_Byname: 主路
  SSObj_Area: 0.0
  SSObj_Length: 567.89
  SSObj_PointCount: 5
  SSObj_X: 12345.67
  SSObj_Y: 54321.09
----------------------------------------
第 1 个对象属性：
  SSObj_ID: 1002
  SSObj_Code: 3103013
  SSObj_LayerName: Default_A
  SSObj_Type: LINE
  SSObj_Color: 16777215
  SSObj_LineType: 1
  SSObj_LineWidth: 1
  SSObj_Name: 道路2
  SSObj_Byname: 支路
  SSObj_Area: 0.0
  SSObj_Length: 234.56
  SSObj_PointCount: 3
  SSObj_X: 13000.00
  SSObj_Y: 55000.00
----------------------------------------
第 2 个对象属性：
  SSObj_ID: 1003
  SSObj_Code: 3103013
  SSObj_LayerName: Default_A
  SSObj_Type: AREA
  SSObj_Color: 16711680
  SSObj_LineType: 2
  SSObj_LineWidth: 2
  SSObj_Name: 区域1
  SSObj_Byname: 核心区
  SSObj_Area: 1234.56
  SSObj_Length: 150.00
  SSObj_PointCount: 6
  SSObj_X: 12500.00
  SSObj_Y: 54500.00
----------------------------------------
```

从输出结果可以看出，我们成功查询到了3个符合条件的对象，包括2个线型对象和1个面对象，每个对象的属性都清晰地显示出来。

## 常见问题与解决方案

### 问题1：选择集为空

**现象**：运行脚本后显示"选择集中的点线面对象数量: 0"

**可能原因**：
- 指定的编码在当前地图中不存在
- 当前数据源中没有符合条件的对象
- 选择条件设置不正确

**解决方案**：尝试使用更宽泛的条件，例如按图层筛选：

```python
SSProcess.setSelectCondition("SSObj_LayerName", "==", "Default_A")
```

或者不设置任何条件，查询所有对象：

```python
# 不调用 setSelectCondition，直接执行 selectFilter
SSProcess.selectFilter()
```

### 问题2：属性值为空

**现象**：某些属性显示为空字符串

**可能原因**：
- 该属性对于当前对象类型不适用（例如，点对象的 `SSObj_Area` 总是为 0）
- 扩展属性 `[ ]` 在当前对象上不存在

**解决方案**：根据对象类型选择合适的属性。例如，对于线对象，查询 `SSObj_Length`；对于面对象，查询 `SSObj_Area`。

### 问题3：扩展属性无法读取

**现象**：使用 `[扩展属性名]` 格式读取时返回空值

**可能原因**：
- 扩展属性名称拼写错误
- 当前对象没有该扩展属性

**解决方案**：先查询对象的扩展属性列表：

```python
# 获取对象的扩展属性字段名
SSProcess.curSelGeoFields.clear()
SSProcess.curSelGeoValues.clear()
SSProcess.map.getExtentAttr(geo, SSProcess.curSelGeoFields, SSProcess.curSelGeoValues)

# 打印所有扩展属性
for i in range(SSProcess.curSelGeoFields.size()):
    print(f"{SSProcess.curSelGeoFields[i]}: {SSProcess.curSelGeoValues[i]}")
```

Sources: [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L189-L261)

## 架构原理补充说明

### SSProcess 的内部结构

`SSProcessManager` 类采用了**Mixin 设计模式**，将不同功能模块分离到独立的 Mixin 类中，然后通过多重继承组合成一个功能完整的管理器：

```mermaid
classDiagram
    class SSProcessManager {
        -workspace: WorkSpace
        -map: ScaleMap
        -selGeoList: GeoBaseList
        -selNoteList: GeoBaseList
        -searchHelper: SSearchHelper
        +clearSelection()
        +clearSelectCondition()
        +setSelectCondition()
        +selectFilter()
        +getSelGeoCount()
        +getSelGeoValue()
    }
    
    class SelectionMixin {
        +clearSelection()
        +clearSelectCondition()
        +setSelectCondition()
        +selectFilter()
        +getSelGeoCount()
        +getSelGeoValue()
    }
    
    class GeoEditMixin {
        +createGeo()
        +deleteGeo()
        +updateGeo()
    }
    
    class ProjectMixin {
        +getWorkspace()
        +getMap()
    }
    
    class LogMixin {
        +log()
        +logger
    }
    
    class ProgressMixin {
        +startProgress()
        +stepProgress()
        +closeProgress()
    }

    SSProcessManager --|> SelectionMixin
    SSProcessManager --|> GeoEditMixin
    SSProcessManager --|> ProjectMixin
    SSProcessManager --|> LogMixin
    SSProcessManager --|> ProgressMixin
```

这种架构设计的优势在于：
- **关注点分离**：每个 Mixin 只负责一个特定的功能领域
- **代码复用**：不同功能的代码可以独立维护和测试
- **扩展性强**：新增功能只需添加新的 Mixin 类
- **清晰的职责边界**：便于理解和使用

Sources: [PySSProcess.py](PySSProcess.py#L35-L70)

### 属性读取机制

SunvStation 支持三种属性类型，它们在底层有不同的存储和访问机制：

```mermaid
flowchart LR
    A[getSelGeoValue 调用] --> B{属性名前缀判断}
    B -->|基本属性| C[调用 objBaseAttr.getGeoValue]
    B -->|几何特性| D[调用 searchHelper 几何判断]
    B -->|扩展属性| E[调用 map.getExtentAttr]
    
    C --> F[返回基本属性值]
    D --> G[返回几何特性结果]
    E --> H[返回扩展属性值]
    
    F --> I[统一返回字符串]
    G --> I
    H --> I
```

基本属性存储在 C++ 对象的内部结构中，通过 `ObjBaseAttr` 类的索引机制快速访问；扩展属性存储在数据库或附加结构中，通过地图接口动态获取；几何特性则是实时计算的判断结果。

Sources: [ObjBaseAttr.py](ObjBaseAttr.py#L1-L50)

## 下一步学习建议

掌握了第一个脚本的基本流程后，您可以根据自己的学习需求选择接下来的学习路径：

### 继续深入选择集与查询

如果您想了解更多选择集操作和高级查询技巧，建议阅读：

- **[使用 SSProcess 管理选择集](4-shi-yong-ssprocess-guan-li-xuan-ze-ji)** - 学习更复杂的选择集管理方法
- **[设置选择条件](12-she-zhi-xuan-ze-tiao-jian)** - 深入了解多条件组合查询
- **[遍历选择集对象](14-bian-li-xuan-ze-ji-dui-xiang)** - 掌握高效的遍历技巧

### 学习地物属性操作

如果您想学习如何修改地物属性，建议阅读：

- **[获取地物属性值](15-huo-qu-di-wu-shu-xing-zhi)** - 了解更多属性获取细节
- **[修改地物属性值](16-xiu-gai-di-wu-shu-xing-zhi)** - 学习如何批量修改属性
- **[地物基本属性详解](17-di-wu-ji-ben-shu-xing-xiang-jie)** - 查看所有可用属性的完整列表

### 探索高级功能

如果您已经掌握了基础知识，可以尝试更高级的功能：

- **[运行内置示例脚本](5-yun-xing-nei-zhi-shi-li-jiao-ben)** - 查看更多实际应用案例
- **[SunvStation 系统架构](6-sunvstation-xi-tong-jia-gou)** - 理解系统的整体设计原理

无论选择哪条路径，都建议您在实际项目中多练习，通过编写不同的脚本加深对 SunvStation Python API 的理解。每个页面都提供了详细的示例代码和源文件引用，可以作为您学习的参考手册。