修改地物属性值是 SunvStation Python API 中最核心的数据操作功能之一。本页将系统性地介绍如何通过脚本修改地物的基本属性、扩展属性以及几何属性，并确保修改内容正确保存到数据库。

## 属性修改架构概览

地物属性修改涉及三个核心层次：**新建对象属性设置**、**选择集对象属性修改**和**批量保存机制**。理解这个架构对于正确使用 API 至关重要。

```mermaid
flowchart TB
    A[开始属性修改] --> B{修改场景}
    B --> C[新建对象]
    B --> D[选择集对象]
    B --> E[批量修改]
    
    C --> C1[createDefaultGeoBase<br/>创建对象]
    C1 --> C2[setNewObjValue<br/>设置属性]
    C2 --> C3[addNewObjToSaveObjList<br/>添加到保存列表]
    
    D --> D1[遍历选择集对象]
    D1 --> D2{属性类型}
    D2 --> D3[SSObj_Code/LayerName<br/>特殊处理]
    D2 --> D4[基本属性<br/>setGeoValue]
    D2 --> D5[扩展属性<br/>setMemoData]
    D3 --> D6[addSelGeoToSaveGeoList<br/>添加到保存列表]
    D4 --> D6
    D5 --> D6
    
    E --> E1[setSelGeoValue -1<br/>批量设置]
    E1 --> E2[addSelGeoToSaveGeoList -1<br/>批量添加]
    
    C3 --> F[saveBufferObjToDatabase<br/>保存到数据库]
    D6 --> F
    E2 --> F
    F --> G[updateRequest<br/>刷新地图显示]
    G --> H[完成]
```

## 属性类型与命名规范

SunvStation 支持三种不同类型的属性，每种类型使用特定的命名前缀和语法规则。

| 属性类型 | 命名格式 | 示例 | 说明 |
|---------|---------|------|------|
| **基本属性** | `SSObj_` 开头 | `SSObj_Code`, `SSObj_Name`, `SSObj_Color` | 系统预定义的固有属性 |
| **扩展属性** | `[属性名]` 格式 | `[建筑类型]`, `[施工状态]` | 用户自定义的扩展字段 |
| **几何属性** | `<属性名>` 格式 | `<Area>`, `<Length>`, `<X(0)>` | 对象的几何特性和坐标信息 |

### 基本属性分类

**通用属性**：涵盖对象的标识、图层和图形表现。这包括对象 ID、编码、图层名称、颜色、线型和线宽等关键属性。

**几何属性**：涉及对象的坐标、几何尺寸和拓扑特征。包括坐标点（X, Y, Z）、面积、长度、边界框等几何信息。

**注记属性**：专门针对文本标注的样式和格式。包括字体宽度、高度、名称、内容、对齐方式和角度等详细属性。

**时间与状态**：记录对象的创建和修改时间，以及对象的状态标记。

Sources: [ObjBaseAttr.py](ObjBaseAttr.py#L9-L79)

## 修改新建对象的属性

当通过 `createDefaultGeoBase()` 或 `createNewObjByCode()` 创建新地物对象后，可以使用 `setNewObjValue()` 方法设置其属性。这种方法适用于单次创建并立即设置属性的场景。

### 基本属性设置

```python
# 创建编码为 100 的线对象
obj, geo = ssp.createNewObjByCode(100)

# 设置基本属性
ssp.setNewObjValue("SSObj_Name", "主干道")
ssp.setNewObjValue("SSObj_Color", "16711680")      # RGB 红色
ssp.setNewObjValue("SSObj_LineWidth", "2")
ssp.setNewObjValue("SSObj_Angle", "45.0")
```

### 扩展属性设置

扩展属性使用方括号 `[]` 包裹属性名，可以同时设置多个属性：

```python
# 设置单个扩展属性
ssp.setNewObjValue("[建筑类型]", "住宅楼")
ssp.setNewObjValue("[建成年份]", "2020")

# 同时设置多个扩展属性（用逗号分隔）
ssp.setNewObjValue("[建筑类型],[建成年份],[楼层数]", "商业楼,2021,18")
```

### 注记属性设置

对于注记对象，支持专门的字体属性：

```python
# 创建注记对象
obj, note = ssp.createNewObjByClass("1")  # 分类号为1的注记

# 设置注记属性
ssp.setNewObjValue("SSObj_FontString", "示例文字")
ssp.setNewObjValue("SSObj_FontHeight", "300")
ssp.setNewObjValue("SSObj_FontWidth", "200")
ssp.setNewObjValue("SSObj_FontName", "SimSun")
ssp.setNewObjValue("SSObj_FontAlignment", "1")  # 对齐方式
```

完成属性设置后，需要将新对象添加到保存列表并持久化：

```python
ssp.addNewObjToSaveObjList()
ssp.saveBufferObjToDatabase()
ssp.updateRequest()
```

Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L106-L266)

## 修改选择集中对象的属性

对于已经存在于地图上的对象，需要先通过选择集过滤获取目标对象，然后使用 `setSelGeoValue()` 或 `setSelNoteValue()` 修改属性。

### 选择集对象属性修改流程

```mermaid
flowchart LR
    A[设置选择条件] --> B[执行过滤查询]
    B --> C[遍历选择集]
    C --> D[修改对象属性]
    D --> E[添加到保存列表]
    E --> F[保存到数据库]
    F --> G[刷新显示]
```

### 修改单个对象的属性

通过指定索引值修改选择集中特定对象的属性：

```python
# 清除并设置选择条件
ssp.clearSelection()
ssp.clearSelectCondition()
ssp.setSelectCondition("SSObj_Code", "==", "100")
ssp.selectFilter()

# 修改选择集中第0个对象的属性
ssp.setSelGeoValue(0, "SSObj_Name", "修改后的名称")
ssp.setSelGeoValue(0, "SSObj_Color", "255")      # 设置颜色号
ssp.setSelGeoValue(0, "[施工状态]", "已完成")

# 将修改后的对象添加到保存列表
ssp.addSelGeoToSaveGeoList(0)

# 批量保存到数据库
ssp.saveBufferObjToDatabase()
ssp.updateRequest()
```

### 批量修改选择集对象的属性

将索引值设为 `-1` 可以一次性修改选择集中的所有对象：

```python
# 获取所有编码为 100 的对象
ssp.clearSelection()
ssp.setSelectCondition("SSObj_Code", "==", "100")
ssp.selectFilter()

print(f"当前选择集对象数量: {ssp.getSelGeoCount()}")

# 批量修改所有选择集对象的属性
ssp.setSelGeoValue(-1, "SSObj_Color", "255")       # 统一颜色
ssp.setSelGeoValue(-1, "SSObj_LineWidth", "3")     # 统一线宽
ssp.setSelGeoValue(-1, "[更新时间]", "2024-01-15")

# 批量添加到保存列表
for i in range(ssp.getSelGeoCount()):
    ssp.addSelGeoToSaveGeoList(i)

# 保存并刷新
ssp.saveBufferObjToDatabase()
ssp.updateRequest()
```

### 修改注记对象的属性

对于注记对象，使用 `setSelNoteValue()` 方法：

```python
# 清除并设置注记选择条件
ssp.clearSelection()
ssp.setSelectCondition("SSObj_Type", "==", "NOTE")
ssp.setSelectCondition("[注记分类]", "==", "道路注记")
ssp.selectFilter()

# 批量修改注记属性
ssp.setSelNoteValue(-1, "SSObj_FontHeight", "250")
ssp.setSelNoteValue(-1, "SSObj_FontWeight", "700")   # 粗体
ssp.setSelNoteValue(-1, "SSObj_FontColor", "16777215")  # 白色

# 添加到保存列表
for i in range(ssp.getSelNoteCount()):
    ssp.addSelNoteToSaveNoteList(i)

# 保存
ssp.saveBufferObjToDatabase()
ssp.updateRequest()
```

Sources: [ssprocess_mixins/selection_mixin.py](ssprocess_mixins/selection_mixin.py#L310-L411)

## 特殊属性处理

某些属性的修改涉及对象重建或特殊逻辑，需要特别注意。

### 编码属性（SSObj_Code）修改

修改对象编码会触发对象重新创建，需要通过数据源重新获取特性信息：

```python
# 修改单个对象的编码
ssp.setSelGeoValue(0, "SSObj_Code", "200")

# 注意：此操作会自动处理对象重建
# 无需手动管理新旧对象的替换
```

### 图层属性（SSObj_LayerName）修改

将对象移动到不同图层涉及完整的对象克隆和数据集切换：

```python
# 将选择集中的对象移动到"建筑"图层
ssp.setSelGeoValue(0, "SSObj_LayerName", "建筑")

# 系统会自动：
# 1. 克隆原始对象
# 2. 保留扩展属性
# 3. 删除旧对象
# 4. 在新图层创建新对象
```

### 点坐标修改（SSObj_X, SSObj_Y, SSObj_Z）

修改坐标点需要指定点的索引：

```python
# 修改第一个点的坐标
ssp.setSelGeoValue(0, "SSObj_X(0)", "123456.789")
ssp.setSelGeoValue(0, "SSObj_Y(0)", "3456789.123")
ssp.setSelGeoValue(0, "SSObj_Z(0)", "100.5")

# 修改第二个点的坐标
ssp.setSelGeoValue(0, "SSObj_X(1)", "123500.000")
ssp.setSelGeoValue(0, "SSObj_Y(1)", "3456800.000")
```

### 点名称与类型修改（SSObj_PointName, SSObj_PointType）

```python
# 修改点名称
ssp.setSelGeoValue(0, "SSObj_PointName(0)", "起点")
ssp.setSelGeoValue(0, "SSObj_PointName(1)", "终点")

# 修改点类型（需要指定点索引）
ssp.setSelGeoValue(0, "SSObj_PointType(0)", "1")
```

Sources: [ObjBaseAttr.py](ObjBaseAttr.py#L495-L550)

## 颜色属性设置详解

SunvStation 支持三种颜色表示方式，系统会自动识别并转换：

| 颜色表示方式 | 格式示例 | 说明 |
|------------|---------|------|
| **颜色号方式** | `COLORNO(1)` | 使用系统颜色索引，推荐方式 |
| **RGB方式** | `RGB(255,0,0)` | 直接指定红绿蓝分量 |
| **颜色值方式** | `16711680` | 24位RGB颜色值（0x00FF0000 = 红） |

```python
# 三种等价的红色设置方式
ssp.setSelGeoValue(0, "SSObj_Color", "COLORNO(1)")     # 颜色号方式
ssp.setSelGeoValue(0, "SSObj_Color", "RGB(255,0,0)")   # RGB方式
ssp.setSelGeoValue(0, "SSObj_Color", "16711680")       # 颜色值方式（红色）
```

Sources: [ObjBaseAttr.py](ObjBaseAttr.py#L413-L419)

## 完整示例：批量更新道路属性

下面的示例展示了完整的属性修改工作流程：选择所有道路对象，更新其颜色、线宽和扩展属性，然后保存到数据库。

```python
# 1. 清除并初始化选择集
ssp.clearSelection()
ssp.clearSelectCondition()

# 2. 设置选择条件：选择编码为 200 的道路对象
ssp.setSelectCondition("SSObj_Code", "==", "200")
ssp.selectFilter()

geo_count = ssp.getSelGeoCount()
print(f"选中对象数量: {geo_count}")

if geo_count > 0:
    # 3. 批量修改基本属性
    ssp.setSelGeoValue(-1, "SSObj_Color", "COLORNO(5)")       # 统一颜色
    ssp.setSelGeoValue(-1, "SSObj_LineWidth", "4")           # 统一线宽
    ssp.setSelGeoValue(-1, "SSObj_DataMark", "已更新")       # 数据标记
    
    # 4. 批量修改扩展属性
    ssp.setSelGeoValue(-1, "[路面宽度]", "12.5")
    ssp.setSelGeoValue(-1, "[铺装类型]", "沥青混凝土")
    ssp.setSelGeoValue(-1, "[维护日期]", "2024-01-10")
    
    # 5. 将所有修改后的对象添加到保存列表
    for i in range(geo_count):
        ssp.addSelGeoToSaveGeoList(i)
    
    # 6. 保存到数据库并刷新显示
    ssp.saveBufferObjToDatabase()
    ssp.updateRequest()
    
    print("属性更新完成！")
else:
    print("未找到符合条件的对象")
```

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

## 完整示例：创建并设置新对象

```python
# 1. 创建编码为 101 的建筑物对象
obj, geo = ssp.createNewObjByCode(101)

# 2. 设置基本属性
ssp.setNewObjValue("SSObj_Name", "新建建筑A栋")
ssp.setNewObjValue("SSObj_Color", "COLORNO(3)")
ssp.setNewObjValue("SSObj_LayerName", "建筑物")

# 3. 添加坐标点
ssp.addNewObjPoint(123456.789, 3456789.123, 50.0, 0, "")
ssp.addNewObjPoint(123500.000, 3456800.000, 50.0, 0, "")
ssp.addNewObjPoint(123500.000, 3456700.000, 50.0, 0, "")
ssp.addNewObjPoint(123456.789, 3456789.123, 50.0, 0, "")

# 4. 设置扩展属性
ssp.setNewObjValue("[建筑高度]", "45.5")
ssp.setNewObjValue("[建筑面积]", "3200")
ssp.setNewObjValue("[建筑功能]", "办公")

# 5. 添加到保存列表并持久化
ssp.addNewObjToSaveObjList()
ssp.saveBufferObjToDatabase()
ssp.updateRequest()

print("新对象创建完成并已保存！")
```

Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L106-L411)

## 注意事项与最佳实践

### 属性修改注意事项

1. **数据类型匹配**：确保属性值的数据类型与属性定义一致，数值属性使用数字字符串，文本属性使用字符串
2. **编码和图层**：修改 `SSObj_Code` 和 `SSObj_LayerName` 会触发对象重建，确保目标编码和图层存在
3. **批量操作**：修改大量对象时，使用 `-1` 索引进行批量操作可以提高性能
4. **扩展属性**：使用逗号分隔可以一次设置多个扩展属性，但确保属性数量和值数量匹配

### 保存机制

**重要**：属性修改后必须显式调用保存方法，否则修改仅在内存中生效，不会持久化到数据库：

```python
# 单个对象保存
ssp.addSelGeoToSaveGeoList(index)  # index 为具体索引或 -1（全部）
ssp.saveBufferObjToDatabase()

# 新对象保存
ssp.addNewObjToSaveObjList()
ssp.saveBufferObjToDatabase()
```

### 错误处理

属性修改操作通常会静默失败，建议在关键操作后检查结果：

```python
# 修改属性前检查对象是否存在
if ssp.getSelGeoCount() > 0:
    # 执行修改
    ssp.setSelGeoValue(0, "SSObj_Color", "255")
    ssp.addSelGeoToSaveGeoList(0)
else:
    print("选择集为空，无法执行修改")
```

## 进阶操作：通过对象ID直接修改属性

对于已知对象 ID 的情况，可以通过 `getObjectAttr()` 和 `setSelGeoValue()` 组合使用：

```python
# 通过对象 ID 直接获取属性
obj_id = 12345
attr_value = ssp.getObjectAttr(obj_id, "SSObj_Name")
print(f"当前名称: {attr_value}")

# 先选择该对象，再修改属性
ssp.clearSelection()
ssp.setSelectCondition("SSObj_ID", "==", str(obj_id))
ssp.selectFilter()

if ssp.getSelGeoCount() > 0:
    ssp.setSelGeoValue(0, "SSObj_Name", "修改后的名称")
    ssp.addSelGeoToSaveGeoList(0)
    ssp.saveBufferObjToDatabase()
```

Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L570-L600)

## 下一步学习

掌握属性修改后，建议继续学习以下相关主题：

- **[地物基本属性详解](17-di-wu-ji-ben-shu-xing-xiang-jie)** - 深入了解每种基本属性的含义和用途
- **[扩展属性与自定义属性](18-kuo-zhan-shu-xing-yu-zi-ding-yi-shu-xing)** - 学习如何创建和管理扩展属性系统
- **[批量保存到数据库](24-pi-liang-bao-cun-dao-shu-ju-ku)** - 了解批量保存的内部机制和性能优化
- **[撤销标记管理](25-che-xiao-biao-ji-guan-li)** - 学习如何实现属性修改的撤销功能