Files
sunvpy-docs/docs/content/14-bian-li-xuan-ze-ji-dui-xiang.md

364 lines
16 KiB
Markdown
Raw Normal View History

2026-04-10 13:47:53 +08:00
遍历选择集对象是 SunvStation 自动化脚本中的核心操作,用于批量处理地理对象的属性和几何信息。通过遍历选择集,可以高效地读取、修改、验证或分析大量地理数据,实现数据质量检查、批量属性更新、统计分析等复杂业务逻辑。
## 选择集数据结构概述
SunvStation 的选择集由两个核心列表组成:`selGeoList` 存储点线面等几何对象,`selNoteList` 存储注记对象。这两个列表都是 `GeoBaseList` 类型,支持索引访问和迭代操作。选择集对象通过 `SSProcessManager` 类统一管理,该类通过 `SelectionMixin` 提供了完整的迭代 API。
```mermaid
flowchart TD
A[SSProcessManager] --> B[SelectionMixin]
B --> C[selGeoList<br/>点线面对象列表]
B --> D[selNoteList<br/>注记对象列表]
C --> E[GeoBaseList<br/>索引访问]
D --> E
E --> F[getSelGeoValue<br/>getSelNoteValue<br/>getSelGeoPoint]
E --> G[setSelGeoValue<br/>setSelNoteValue]
F --> H[属性读取循环]
G --> I[属性修改循环]
```
选择集对象通常通过两种方式构建:一是通过 `setSelectCondition``selectFilter` 基于条件过滤生成;二是通过 `updateSysSelection(0)` 从系统地图的选择集中同步。构建完成后,即可使用索引方式遍历处理每个对象。
Sources: [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L25-L46) [PySSProcess.py](PySSProcess.py#L53-L86)
## 核心迭代 API 方法
遍历选择集依赖于以下关键方法,这些方法提供了从对象数量统计到具体属性访问的完整功能链。
| 方法名称 | 参数说明 | 返回值 | 功能描述 |
|---------|---------|--------|---------|
| `getSelGeoCount()` | 无 | int | 获取选择集中点线面对象的数量 |
| `getSelNoteCount()` | 无 | int | 获取选择集中注记对象的数量 |
| `getSelGeoValue(index, fieldName)` | index: 对象索引, fieldName: 属性名称 | str | 获取指定几何对象的属性值 |
| `getSelNoteValue(index, fieldName)` | index: 对象索引, fieldName: 属性名称 | str | 获取指定注记对象的属性值 |
| `setSelGeoValue(index, fieldName, value)` | index: 对象索引, fieldName: 属性名称, value: 属性值 | None | 设置指定几何对象的属性值 |
| `setSelNoteValue(index, fieldName, value)` | index: 对象索引, fieldName: 属性名称, value: 属性值 | None | 设置指定注记对象的属性值 |
| `getSelGeoPoint(index, pointIndex)` | index: 对象索引, pointIndex: 点索引 | Point | 获取指定几何对象的坐标点 |
`index` 参数从 0 开始,最大值为对象数量减 1。属性名称包括以 `SSObj_` 开头的基本属性(如 `SSObj_Code``SSObj_Area`)、以 `<>` 括住的几何特性(如 `<Overlap>`)、以 `[]` 括住的扩展属性(如 `[建筑结构]`)。当索引越界时,`getSelGeoValue``getSelNoteValue` 返回空字符串,而 `setSelGeoValue``setSelNoteValue` 则直接返回不执行操作。
Sources: [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L204-L277) [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L279-L320) [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L322-L338) [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L340-L393)
## 基本遍历流程
遍历选择集对象遵循标准的索引循环模式。首先获取对象总数,然后使用 `for` 循环遍历每个索引,在每个迭代中读取或修改对象属性。
```mermaid
flowchart LR
A[开始] --> B[获取对象数量<br/>getSelGeoCount / getSelNoteCount]
B --> C[初始化循环索引 i = 0]
C --> D{i < 对象数量?}
D -->|是| E[访问对象属性<br/>getSelGeoValue / getSelNoteValue]
E --> F[执行业务逻辑]
F --> G[i++]
G --> D
D -->|否| H[结束]
```
**读取属性的基本模式**
```python
from sunvpy import SSProcess
# 遍历所有点线面对象
count = SSProcess.getSelGeoCount()
for i in range(count):
code = SSProcess.getSelGeoValue(i, "SSObj_Code")
layer = SSProcess.getSelGeoValue(i, "SSObj_LayerName")
obj_type = SSProcess.getSelGeoValue(i, "SSObj_Type")
print(f"对象 {i}: 编码={code}, 图层={layer}, 类型={obj_type}")
# 遍历所有注记对象
note_count = SSProcess.getSelNoteCount()
for i in range(note_count):
note_content = SSProcess.getSelNoteValue(i, "SSObj_FontString")
note_class = SSProcess.getSelNoteValue(i, "SSObj_FontClass")
print(f"注记 {i}: 内容={note_content}, 分类={note_class}")
```
**修改属性的基本模式**
```python
# 批量更新对象属性
count = SSProcess.getSelGeoCount()
for i in range(count):
# 批量修改为新的颜色
SSProcess.setSelGeoValue(i, "SSObj_Color", "255") # 红色
# 批量更新图层名称
SSProcess.setSelGeoValue(i, "SSObj_LayerName", "Updated_Layer")
# 批量修改对象名称
SSProcess.setSelGeoValue(i, "SSObj_Name", f"对象_{i}")
```
需要注意的是,修改属性后对象不会自动保存到数据库,需要调用保存方法才能持久化。对于 `SSObj_Code``SSObj_LayerName` 这两个特殊属性,系统会自动处理对象重新生成逻辑,确保数据一致性。
Sources: [PySSProcess.py](PySSProcess.py#L110-L138) [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L340-L393)
## 完整工作流示例
下面的示例展示了从构建选择集到遍历处理再到保存结果的完整流程,包括条件过滤、属性读取、属性修改和批量保存。
```mermaid
flowchart TD
A[清除旧选择集<br/>clearSelection] --> B[清除选择条件<br/>clearSelectCondition]
B --> C[设置选择条件<br/>setSelectCondition]
C --> D[执行过滤查询<br/>selectFilter]
D --> E[遍历几何对象<br/>for i in range<br/>getSelGeoCount]
E --> F[读取属性<br/>getSelGeoValue]
F --> G{是否满足条件?}
G -->|是| H[修改属性<br/>setSelGeoValue]
G -->|否| I[跳过]
H --> J[添加到保存列表<br/>addSelGeoToSaveGeoList]
I --> K{i < count?}
J --> K
K -->|是| E
K -->|否| L[批量保存到数据库<br/>saveBufferObjToDatabase]
L --> M[更新系统显示<br/>updateSysSelection]
```
**完整的批量处理脚本**
```python
from sunvpy import SSProcess
# 步骤 1: 清理旧选择集和条件
SSProcess.clearSelection()
SSProcess.clearSelectCondition()
# 步骤 2: 设置选择条件选择长度大于100的对象
SSProcess.setSelectCondition("SSObj_Length", ">", "100")
# 步骤 3: 执行过滤查询
SSProcess.selectFilter()
print(f"选择集包含 {SSProcess.getSelGeoCount()} 个对象")
# 步骤 4: 定义要读取和修改的字段
read_fields = [
"SSObj_ID", "SSObj_Code", "SSObj_LayerName", "SSObj_Type",
"SSObj_Length", "SSObj_Area", "SSObj_Color"
]
# 步骤 5: 遍历选择集,读取属性并批量修改
count = SSProcess.getSelGeoCount()
for i in range(count):
# 读取对象属性
obj_info = {}
for field in read_fields:
obj_info[field] = SSProcess.getSelGeoValue(i, field)
# 业务逻辑:根据对象类型进行不同处理
obj_type = obj_info["SSObj_Type"]
if obj_type == "AREA":
# 面对象:修改颜色并添加到保存列表
SSProcess.setSelGeoValue(i, "SSObj_Color", "16711680") # 蓝色
SSProcess.addSelGeoToSaveGeoList(i)
print(f"面对象 {obj_info['SSObj_ID']} 面积: {obj_info['SSObj_Area']}")
elif obj_type == "LINE":
# 线对象:修改线宽并添加到保存列表
SSProcess.setSelGeoValue(i, "SSObj_LineWidth", "3")
SSProcess.addSelGeoToSaveGeoList(i)
print(f"线对象 {obj_info['SSObj_ID']} 长度: {obj_info['SSObj_Length']}")
# 步骤 6: 批量保存修改到数据库
SSProcess.saveBufferObjToDatabase()
print("已保存所有修改的对象")
```
**代码对比:修改前后**
| 场景 | 修改前代码 | 修改后代码 | 变化说明 |
|------|-----------|-----------|---------|
| 单个对象属性读取 | `SSProcess.getSelGeoValue(0, "SSObj_Code")` | `SSProcess.getSelGeoValue(i, "SSObj_Code")` | 使用循环变量索引 |
| 固定属性修改 | `SSProcess.setSelGeoValue(0, "SSObj_Color", "255")` | `SSProcess.setSelGeoValue(i, "SSObj_Color", "255")` | 批量修改所有对象 |
| 无保存操作 | 修改属性后不保存 | `SSProcess.addSelGeoToSaveGeoList(i)``saveBufferObjToDatabase()` | 添加保存机制 |
Sources: [PySSProcess.py](PySSProcess.py#L94-L131) [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L566-L588) [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L131-L154)
## 坐标点遍历
对于几何对象,经常需要访问其坐标点信息。`getSelGeoPoint` 方法可以获取对象指定索引的坐标点,结合 `getPointSize` 可以遍历对象的所有坐标点。
```python
# 遍历所有对象的坐标点
count = SSProcess.getSelGeoCount()
for i in range(count):
geo_type = SSProcess.getSelGeoValue(i, "SSObj_Type")
# 只处理线对象和面对象
if geo_type in ["LINE", "AREA"]:
# 获取对象引用以查询点数量(需要直接访问 selGeoList
geo = SSProcess.selGeoList[i]
point_count = geo.getPointSize()
print(f"对象 {i} 包含 {point_count} 个坐标点:")
# 遍历所有坐标点
for j in range(point_count):
point = SSProcess.getSelGeoPoint(i, j)
if point:
x = point.x()
y = point.y()
z = point.z()
print(f" 点 {j}: ({x:.2f}, {y:.2f}, {z:.2f})")
```
这种模式常用于数据质量检查(如检查线对象是否有重复点)、坐标转换、几何计算等场景。需要注意的是,访问 `selGeoList``getPointSize` 是直接操作 C++ 对象,效率较高,但需要确保索引在有效范围内。
Sources: [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L322-L338)
## 扩展属性遍历
扩展属性是以 `[]` 括住的自定义属性,通常用于存储业务特定的扩展数据。遍历扩展属性需要先获取对象的字段列表,然后逐个读取或修改。
```python
# 遍历对象的扩展属性
count = SSProcess.getSelGeoCount()
for i in range(count):
# 获取对象的扩展属性字段和值
# 注意:这需要直接访问 curSelGeoFields 和 curSelGeoValues
geo = SSProcess.selGeoList[i]
SSProcess.curSelGeoFields.clear()
SSProcess.curSelGeoValues.clear()
SSProcess.map.getExtentAttr(geo, SSProcess.curSelGeoFields, SSProcess.curSelGeoValues)
print(f"对象 {i} 的扩展属性:")
# 遍历所有扩展属性
for j in range(SSProcess.curSelGeoFields.size()):
field_name = SSProcess.curSelGeoFields[j]
field_value = SSProcess.curSelGeoValues[j]
print(f" [{field_name}] = {field_value}")
# 读取特定扩展属性(使用标准 API
structure = SSProcess.getSelGeoValue(i, "[建筑结构]")
floors = SSProcess.getSelGeoValue(i, "[楼层数]")
if structure and floors:
# 修改扩展属性
SSProcess.setSelGeoValue(i, "[建筑结构], [楼层数]", "砖混, 6")
SSProcess.addSelGeoToSaveGeoList(i)
```
扩展属性支持批量读取和写入,使用逗号分隔多个字段名可以一次性获取或设置多个属性值。这种方式特别适合属性较多的业务对象,可以减少函数调用次数,提高处理效率。
Sources: [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L252-L274) [ObjBaseAttr.py](ObjBaseAttr.py#L13-L36)
## 最佳实践与注意事项
在遍历选择集对象时,遵循以下最佳实践可以提高代码质量和执行效率:
**性能优化建议**
| 场景 | 优化建议 | 效果说明 |
|------|---------|---------|
| 大批量对象处理 | 使用 `setSelGeoValue(i, -1, fieldName, value)` 一次性修改所有对象 | 减少 90% 的 API 调用次数 |
| 频繁属性访问 | 缓存常用属性值或字段索引 | 减少重复的字符串查找开销 |
| 进度反馈 | 启用进度条显示处理进度 | 提升用户体验,便于监控长时间任务 |
```python
# 优化示例:一次性修改所有对象的属性
SSProcess.setSelGeoValue(-1, "SSObj_Color", "255") # index=-1 表示所有对象
SSProcess.setSelGeoValue(-1, "SSObj_LayerName", "New_Layer")
# 进度条反馈
count = SSProcess.getSelGeoCount()
SSProcess.startProgress("正在处理选择集...", count)
for i in range(count):
# 处理逻辑
SSProcess.setSelGeoValue(i, "SSObj_Name", f"对象_{i}")
SSProcess.stepProgress(f"已处理 {i+1}/{count} 个对象")
SSProcess.closeProgress()
```
**常见陷阱与解决方案**
| 陷阱类型 | 问题描述 | 解决方案 |
|---------|---------|---------|
| 索引越界 | 使用超出范围的对象索引 | 在循环中使用 `range(getSelGeoCount())` 确保索引有效 |
| 未保存修改 | 修改属性后未调用保存方法 | 使用 `addSelGeoToSaveGeoList` 添加到保存列表后调用 `saveBufferObjToDatabase` |
| 属性名拼写错误 | 使用错误的属性名导致读取失败 | 参考 `setSelectCondition` 文档中的完整属性名列表 |
| 忽略注记对象 | 只处理 `selGeoList` 而忽略 `selNoteList` | 同时遍历 `selGeoList``selNoteList` 确保完整性 |
**错误处理示例**
```python
count = SSProcess.getSelGeoCount()
for i in range(count):
try:
code = SSProcess.getSelGeoValue(i, "SSObj_Code")
if not code:
print(f"警告: 对象 {i} 的编码为空,跳过处理")
continue
# 业务逻辑
SSProcess.setSelGeoValue(i, "SSObj_Name", f"对象_{code}")
SSProcess.addSelGeoToSaveGeoList(i)
except Exception as e:
print(f"错误: 处理对象 {i} 时发生异常: {e}")
# 继续处理下一个对象,不中断整个流程
continue
```
Sources: [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L340-L393) [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L356-L360) [ssprocess_mixins/progress_mixin.py](ssprocess_mixins/progress_mixin.py)
## 应用场景示例
**数据质量检查**
```python
# 检查所有线对象是否有最小长度
count = SSProcess.getSelGeoCount()
error_count = 0
for i in range(count):
obj_type = SSProcess.getSelGeoValue(i, "SSObj_Type")
if obj_type == "LINE":
length = float(SSProcess.getSelGeoValue(i, "SSObj_Length"))
if length < 5.0: # 最小长度阈值
obj_id = SSProcess.getSelGeoValue(i, "SSObj_ID")
print(f"错误: 线对象 {obj_id} 长度过短 ({length:.2f} 米)")
error_count += 1
print(f"检查完成,发现 {error_count} 个问题对象")
```
**批量属性标准化**
```python
# 将所有建筑对象的扩展属性标准化
count = SSProcess.getSelGeoCount()
for i in range(count):
obj_type = SSProcess.getSelGeoValue(i, "SSObj_Type")
if obj_type == "AREA":
structure = SSProcess.getSelGeoValue(i, "[建筑结构]")
floors = SSProcess.getSelGeoValue(i, "[楼层数]")
# 标准化建筑结构名称
structure_map = {
"砖混": "砖混结构",
"框架": "框架结构",
"钢结构": "钢结构"
}
if structure in structure_map:
SSProcess.setSelGeoValue(i, "[建筑结构]", structure_map[structure])
SSProcess.addSelGeoToSaveGeoList(i)
SSProcess.saveBufferObjToDatabase()
```
Sources: [PySSProcess.py](PySSProcess.py#L93-L116)
## 下一步学习
掌握了选择集遍历后,建议继续学习以下相关内容:
- **[获取地物属性值](15-huo-qu-di-wu-shu-xing-zhi)**:深入了解各类属性的访问方式和特殊属性的处理
- **[修改地物属性值](16-xiu-gai-di-wu-shu-xing-zhi)**:掌握属性修改的高级技巧和批量操作
- **[对象缓存机制](23-dui-xiang-huan-cun-ji-zhi)**:了解缓存机制如何优化批量操作性能
- **[批量保存到数据库](24-pi-liang-bao-cun-dao-shu-ju-ku)**:学习将修改持久化到数据库的完整流程
这些主题将帮助您构建更加完整和高效的地理数据处理自动化解决方案。