Files
sunvpy-docs/docs/content/18-kuo-zhan-shu-xing-yu-zi-ding-yi-shu-xing.md
2026-04-10 13:47:53 +08:00

24 KiB
Raw Blame History

本页专门讲解 SunvStation 中扩展属性与自定义属性的使用方法。扩展属性是存储在对象扩展属性表中的用户自定义字段,用于满足业务特定的数据管理需求。通过扩展属性,开发者可以在不修改系统架构的前提下,为地物对象添加任意的业务信息,如建筑结构、施工状态、维护记录等。

扩展属性体系架构

扩展属性与系统基本属性SSObj_不同它采用灵活的键值对存储机制允许开发者根据业务需求动态定义属性名称和值。理解这个架构有助于正确使用扩展属性功能。

flowchart TB
    A[扩展属性体系] --> B[存储机制<br/>MemoData StringArray]
    A --> C[访问语法<br/>方括号包裹]
    A --> D[应用场景<br/>业务特定信息]
    
    B --> B1[Fields: 属性名数组]
    B --> B2[Values: 属性值数组]
    B1 --> B3[getMemoData/setMemoData]
    B2 --> B3
    
    C --> C1[单个属性: #91属性名#92]
    C --> C2[多个属性: #91属性1#92,#91属性2#92,...]
    
    D --> D1[建筑管理: 结构, 层数, 面积]
    D --> D2[道路管理: 宽度, 材质, 等级]
    D --> D3[设施管理: 状态, 维护日期, 责任人]

扩展属性的核心优势在于其灵活性和可扩展性。与固定的系统属性不同,扩展属性可以根据项目需求随时添加新的字段,无需修改数据库结构或系统代码。这种设计使得 SunvStation 能够适应各种专业领域的需求。

Sources: ObjBaseAttr.py, ssprocess_mixins/selection_mixin.py

扩展属性命名与语法规则

扩展属性使用特定的命名约定,以区别于系统基本属性和几何特性。掌握这些规则是正确使用扩展属性的前提。

属性类型 命名格式 示例 存储位置 适用场景
扩展属性 [属性名] [建筑结构][施工状态] 对象扩展属性表 用户自定义业务字段
基本属性 SSObj_属性名 SSObj_CodeSSObj_Name 对象内部属性 系统预定义固有属性
几何特性 <属性名> <Area><Length> 几何计算结果 拓扑和几何判断

单个属性访问

访问单个扩展属性时,使用方括号包裹属性名:

# 获取扩展属性值
structure = SSProcess.getSelGeoValue(0, "[建筑结构]")
print(f"建筑结构: {structure}")

# 设置扩展属性值
SSProcess.setSelGeoValue(0, "[建筑结构]", "钢筋混凝土")

多个属性访问

使用逗号分隔可以一次性访问或设置多个扩展属性:

# 获取多个扩展属性(逗号分隔属性名)
combined_value = SSProcess.getSelGeoValue(0, "[建筑结构],[层数],[建成年份]")
# 返回格式: "钢筋混凝土,18,2020"
print(combined_value)

# 设置多个扩展属性(逗号分隔属性名和值)
SSProcess.setSelGeoValue(0, "[建筑结构],[层数],[建成年份]", "钢结构,25,2015")

注意:设置多个属性时,属性名和值的数量必须一一对应,否则操作不会执行。

Sources: ssprocess_mixins/selection_mixin.py, ssprocess_mixins/geo_edit_mixin.py

读取扩展属性

读取扩展属性主要通过 getSelGeoValue()getSelNoteValue() 方法实现。这两个方法会自动识别方括号语法,从对象的扩展属性表中提取对应的值。

读取几何对象扩展属性

from sunvpy import SSProcess

# 清除并设置选择条件
SSProcess.clearSelection()
SSProcess.clearSelectCondition()
SSProcess.setSelectCondition("SSObj_Code", "==", "100")  # 选择建筑物
SSProcess.selectFilter()

if SSProcess.getSelGeoCount() > 0:
    # 读取单个扩展属性
    structure = SSProcess.getSelGeoValue(0, "[建筑结构]")
    floors = SSProcess.getSelGeoValue(0, "[层数]")
    
    print(f"建筑结构: {structure}")
    print(f"楼层数: {floors}")
    
    # 读取多个扩展属性
    combined = SSProcess.getSelGeoValue(0, "[建筑结构],[层数],[建筑面积]")
    if combined:
        parts = combined.split(',')
        print(f"完整信息: 结构={parts[0]}, 层数={parts[1]}, 面积={parts[2]}")

读取注记对象扩展属性

注记对象同样支持扩展属性,使用 getSelNoteValue() 方法:

from sunvpy import SSProcess

# 选择注记对象
SSProcess.clearSelection()
SSProcess.setSelectCondition("SSObj_Type", "==", "NOTE")
SSProcess.setSelectCondition("[注记分类]", "==", "道路标注")
SSProcess.selectFilter()

if SSProcess.getSelNoteCount() > 0:
    # 读取注记扩展属性
    category = SSProcess.getSelNoteValue(0, "[注记分类]")
    priority = SSProcess.getSelNoteValue(0, "[显示优先级]")
    
    print(f"注记分类: {category}")
    print(f"显示优先级: {priority}")

扩展属性读取流程

flowchart TD
    A[调用 getSelGeoValue/getSelNoteValue] --> B{字段名以 '&#91' 开头?}
    B -->|否| C[按基本属性处理<br/>调用 getGeoValue]
    B -->|是| D[扩展属性路径]
    
    D --> E[调用 map.getExtentAttr<br/>获取 Fields 和 Values]
    E --> F{字段名包含逗号?}
    
    F -->|否| G[查找单个字段索引]
    G --> H[返回对应值或空字符串]
    
    F -->|是| I[分割多个字段名]
    I --> J[逐个查找并收集值]
    J --> K[拼接并返回逗号分隔的值]

注意事项:如果指定的扩展属性不存在,方法会返回空字符串。建议在关键操作前进行有效性检查。

Sources: ssprocess_mixins/selection_mixin.py

设置扩展属性

设置扩展属性可以通过 setSelGeoValue()setSelNoteValue()(针对已有对象)和 setNewObjValue()(针对新建对象)实现。设置操作会修改对象在内存中的扩展属性表,但需要显式保存才能持久化到数据库。

修改已有对象的扩展属性

from sunvpy import SSProcess

# 1. 选择目标对象
SSProcess.clearSelection()
SSProcess.clearSelectCondition()
SSProcess.setSelectCondition("SSObj_Code", "==", "100")
SSProcess.selectFilter()

# 2. 修改单个对象的扩展属性
if SSProcess.getSelGeoCount() > 0:
    SSProcess.setSelGeoValue(0, "[建筑结构]", "砖混结构")
    SSProcess.setSelGeoValue(0, "[层数]", "6")
    SSProcess.setSelGeoValue(0, "[建成年份]", "2008")
    
    # 添加到保存列表
    SSProcess.addSelGeoToSaveGeoList(0)
    
    # 保存到数据库
    SSProcess.saveBufferObjToDatabase()
    SSProcess.updateRequest()

批量修改扩展属性

将索引设置为 -1 可以一次性修改选择集中所有对象的扩展属性:

from sunvpy import SSProcess

# 1. 选择多个对象
SSProcess.clearSelection()
SSProcess.setSelectCondition("SSObj_Code", "==", "100")
SSProcess.selectFilter()

count = SSProcess.getSelGeoCount()
print(f"选中 {count} 个对象")

if count > 0:
    # 2. 批量修改扩展属性
    SSProcess.setSelGeoValue(-1, "[维护状态]", "待维护")
    SSProcess.setSelGeoValue(-1, "[检查日期]", "2024-01-15")
    SSProcess.setSelGeoValue(-1, "[责任部门]", "市政管理处")
    
    # 3. 将所有对象添加到保存列表
    for i in range(count):
        SSProcess.addSelGeoToSaveGeoList(i)
    
    # 4. 批量保存
    SSProcess.saveBufferObjToDatabase()
    SSProcess.updateRequest()
    
    print("批量更新完成")

设置多个扩展属性

使用逗号分隔可以一次性设置多个扩展属性:

# 单个对象设置多个属性
SSProcess.setSelGeoValue(0, "[建筑结构],[层数],[建筑面积],[建筑功能]", 
                          "框架结构,15,8500,商业")

# 批量设置多个属性
SSProcess.setSelGeoValue(-1, "[维护状态],[检查日期],[责任人]", 
                          "维护中,2024-01-20,张工")

重要提示:设置多个属性时,属性名和值的数量必须严格一致。如果数量不匹配,整个操作将不会执行。

Sources: ssprocess_mixins/selection_mixin.py, ObjBaseAttr.py

为新建对象设置扩展属性

在创建新对象时,可以使用 setNewObjValue() 方法设置扩展属性。这种方式适用于需要预先定义扩展属性的场景。

完整的新建对象流程

from sunvpy import SSProcess

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

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

# 3. 添加坐标点(闭合多边形)
SSProcess.addNewObjPoint(123456.789, 3456789.123, 50.0, 0, "")
SSProcess.addNewObjPoint(123500.000, 3456800.000, 50.0, 0, "")
SSProcess.addNewObjPoint(123500.000, 3456700.000, 50.0, 0, "")
SSProcess.addNewObjPoint(123456.789, 3456789.123, 50.0, 0, "")

# 4. 设置单个扩展属性
SSProcess.setNewObjValue("[建筑高度]", "45.5")
SSProcess.setNewObjValue("[建筑面积]", "3200")
SSProcess.setNewObjValue("[建筑功能]", "办公")
SSProcess.setNewObjValue("[消防等级]", "一级")

# 5. 或一次性设置多个扩展属性
SSProcess.setNewObjValue("[建设年份],[设计单位],[施工单位]", 
                        "2023,XX设计院,XX建筑公司")

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

print("新对象创建完成,扩展属性已设置")

新建对象扩展属性设置机制

flowchart TD
    A[调用 setNewObjValue] --> B{字段名以 '&#91' 开头?}
    B -->|否| C[按基本属性处理]
    B -->|是| D[扩展属性处理]
    
    D --> E[调用 geo.getMemoData<br/>获取现有 Fields 和 Values]
    E --> F{字段名包含逗号?}
    
    F -->|否| G[查找字段索引]
    G --> H{索引 >= 0?}
    H -->|是| I[更新现有值]
    H -->|否| J[添加新字段和值]
    
    F -->|是| K[分割多个字段名和值]
    K --> L[逐个处理每个字段]
    L --> M{字段已存在?}
    M -->|是| I
    M -->|否| J
    
    I --> N[调用 geo.setMemoData<br/>保存扩展属性表]
    J --> N

Sources: ssprocess_mixins/geo_edit_mixin.py

在选择条件中使用扩展属性

扩展属性可以用于选择条件过滤,实现基于业务属性的查询。在 setSelectCondition() 中使用扩展属性语法,可以快速筛选出符合业务规则的对象。

基于扩展属性的选择

from sunvpy import SSProcess

# 1. 清除之前的选择条件
SSProcess.clearSelection()
SSProcess.clearSelectCondition()

# 2. 设置基于扩展属性的选择条件
# 等值匹配
SSProcess.setSelectCondition("[建筑结构]", "==", "钢筋混凝土")

# 模糊匹配
SSProcess.setSelectCondition("[建筑功能]", "LIKE", "%办公%")

# 数值比较
SSProcess.setSelectCondition("[层数]", ">", "10")

# 执行过滤
SSProcess.selectFilter()

# 3. 处理选择集
count = SSProcess.getSelGeoCount()
print(f"找到 {count} 个符合条件的对象")

if count > 0:
    # 批量更新维护状态
    SSProcess.setSelGeoValue(-1, "[维护状态]", "已检查")
    
    for i in range(count):
        SSProcess.addSelGeoToSaveGeoList(i)
    
    SSProcess.saveBufferObjToDatabase()
    SSProcess.updateRequest()

复合选择条件

# 多条件组合查询
SSProcess.clearSelection()
SSProcess.clearSelectCondition()

# 条件1建筑结构为钢筋混凝土
SSProcess.setSelectCondition("[建筑结构]", "==", "钢筋混凝土")

# 条件2层数大于15
SSProcess.setSelectCondition("[层数]", ">", "15")

# 条件3维护状态为"待维护"
SSProcess.setSelectCondition("[维护状态]", "==", "待维护")

# 条件4基本属性编码
SSProcess.setSelectCondition("SSObj_Code", "==", "100")

# 执行过滤
SSProcess.selectFilter()

print(f"找到 {SSProcess.getSelGeoCount()} 个高层待维护建筑")

支持的操作符

扩展属性在选择条件中支持多种操作符:

操作符 说明 示例 适用数据类型
== 等于 "[建筑结构]" == "钢筋混凝土" 所有类型
<> 不等于 "[维护状态]" <> "已废弃" 所有类型
> 大于 "[层数]" > "10" 数值类型
< 小于 "[建造年份]" < "2000" 数值类型
LIKE 模糊匹配 "[建筑功能]" LIKE "%办公%" 字符串类型
NOT LIKE 不匹配 "[备注]" NOT LIKE "暂缓%" 字符串类型
CompareNoCase 不区分大小写 "[负责人]" CompareNoCase "张三" 字符串类型

注意:扩展属性的值在比较时作为字符串处理,数值比较需要确保值的格式正确。

Sources: ssprocess_mixins/selection_mixin.py

扩展属性应用场景与最佳实践

典型应用场景

建筑物管理

# 建筑物相关扩展属性
building_attrs = {
    "[建筑结构]": "框架结构",
    "[层数]": "12",
    "[地下层数]": "2",
    "[建筑面积]": "8500",
    "[建筑功能]": "商业",
    "[消防等级]": "一级",
    "[建成年份]": "2018",
    "[维护状态]": "正常",
    "[最后检查日期]": "2024-01-10"
}

道路设施管理

# 道路相关扩展属性
road_attrs = {
    "[路面宽度]": "12.5",
    "[路面材料]": "沥青混凝土",
    "[道路等级]": "主干道",
    "[设计时速]": "60",
    "[车行道数]": "4",
    "[施工状态]": "已竣工",
    "[维护周期]": "12"
}

市政设施管理

# 市政设施相关扩展属性
facility_attrs = {
    "[设施类型]": "路灯",
    "[功率]": "150W",
    "[安装日期]": "2022-06-15",
    "[维护责任人]": "张工",
    "[使用状态]": "正常",
    "[检查周期]": "30"
}

最佳实践

1. 命名规范

使用清晰、一致的扩展属性命名规范:

# 推荐的命名方式
# 业务类别 + 属性名称
"[建筑结构]", "[建筑高度]"  # 建筑类
"[路面宽度]", "[道路等级]"  # 道路类
"[设施类型]", "[安装日期]"  # 设施类

# 避免的命名方式
"[结构]", "[高度]"           # 太简短,容易混淆
"[结构信息]", "[高度信息]"   # 包含冗余的"信息"

2. 数据类型一致性

保持扩展属性值的数据类型一致性:

# 数值类型统一使用数字字符串
SSProcess.setSelGeoValue(0, "[层数]", "12")       # 正确
SSProcess.setSelGeoValue(0, "[层数]", "十二")     # 错误,无法进行数值比较

# 日期类型使用统一格式
SSProcess.setSelGeoValue(0, "[检查日期]", "2024-01-15")  # 正确
SSProcess.setSelGeoValue(0, "[检查日期]", "2024年1月15日")  # 错误,排序不便

3. 属性数量控制

避免为对象添加过多的扩展属性:

# 不推荐:属性过多
SSProcess.setSelGeoValue(0, "[属性1],[属性2],...,[属性50]", "值1,值2,...,值50")

# 推荐:只保留业务必需的核心属性
SSProcess.setSelGeoValue(0, "[建筑结构],[层数],[建筑功能]", "框架结构,12,办公")

4. 属性值验证

设置扩展属性前进行值的有效性检查:

def validate_building_structure(value):
    valid_structures = ["砖混结构", "框架结构", "钢结构", "钢筋混凝土"]
    return value in valid_structures

structure = "框架结构"
if validate_building_structure(structure):
    SSProcess.setSelGeoValue(0, "[建筑结构]", structure)
else:
    print(f"无效的建筑结构: {structure}")

5. 批量操作优化

在处理大量对象时,优先使用批量操作:

# 不推荐:逐个处理
for i in range(SSProcess.getSelGeoCount()):
    SSProcess.setSelGeoValue(i, "[维护状态]", "已检查")
    SSProcess.addSelGeoToSaveGeoList(i)

# 推荐:批量设置后统一添加
SSProcess.setSelGeoValue(-1, "[维护状态]", "已检查")
for i in range(SSProcess.getSelGeoCount()):
    SSProcess.addSelGeoToSaveGeoList(i)

Sources: ssprocess_mixins/selection_mixin.py, ssprocess_mixins/geo_edit_mixin.py

常见问题与故障排除

问题1扩展属性读取返回空字符串

症状:调用 getSelGeoValue() 读取扩展属性时返回空字符串。

可能原因

  • 指定的扩展属性不存在
  • 对象没有设置过该扩展属性
  • 属性名拼写错误(区分大小写)

解决方案

# 检查属性是否存在
value = SSProcess.getSelGeoValue(0, "[建筑结构]")
if not value:
    print("属性不存在或为空")
    
# 验证属性名拼写(区分大小写)
# "[建筑结构]" ≠ "[建筑结构]" ≠ "[建筑结构]"

问题2批量设置多个属性失败

症状:使用逗号分隔设置多个属性时,操作不生效。

可能原因

  • 属性名和值的数量不匹配
  • 属性名或值中包含逗号

解决方案

# 检查数量匹配
attrs = "[建筑结构],[层数],[建筑功能]"
values = "框架结构,12,办公"

if len(attrs.split(',')) == len(values.split(',')):
    SSProcess.setSelGeoValue(0, attrs, values)
else:
    print("属性名和值的数量不匹配")

# 如果值中包含逗号,转义或分别设置
SSProcess.setSelGeoValue(0, "[备注]", "包含,逗号的文本")

问题3基于扩展属性的选择无结果

症状:使用 setSelectCondition() 设置扩展属性条件后,选择集为空。

可能原因

  • 选择条件语法错误
  • 扩展属性值的数据类型不匹配
  • 使用了不支持的操作符

解决方案

# 验证选择条件
SSProcess.clearSelection()
SSProcess.clearSelectCondition()

# 确保使用正确的语法
SSProcess.setSelectCondition("[建筑结构]", "==", "钢筋混凝土")  # 正确
# SSProcess.setSelectCondition("建筑结构", "==", "钢筋混凝土") # 错误,缺少方括号

# 数值比较时确保值是数字字符串
SSProcess.setSelectCondition("[层数]", ">", "10")     # 正确
# SSProcess.setSelectCondition("[层数]", ">", "十层") # 错误

SSProcess.selectFilter()
print(f"找到 {SSProcess.getSelGeoCount()} 个对象")

问题4修改后的扩展属性未保存

症状:调用 setSelGeoValue() 修改扩展属性后,刷新地图或重启系统,修改丢失。

可能原因

  • 未调用保存方法
  • 保存列表添加失败

解决方案

# 必须的保存流程
SSProcess.setSelGeoValue(0, "[维护状态]", "已检查")
SSProcess.addSelGeoToSaveGeoList(0)       # 添加到保存列表
SSProcess.saveBufferObjToDatabase()      # 保存到数据库
SSProcess.updateRequest()                # 刷新显示

Sources: ssprocess_mixins/selection_mixin.py, ssprocess_mixins/geo_edit_mixin.py

完整示例:建筑物维护管理系统

下面的示例展示了如何使用扩展属性构建一个完整的建筑物维护管理系统。

from sunvpy import SSProcess

def building_maintenance_system():
    """建筑物维护管理系统示例"""
    
    print("=== 建筑物维护管理系统 ===\n")
    
    # 1. 查找所有待维护的高层建筑
    print("1. 查找待维护的高层建筑...")
    SSProcess.clearSelection()
    SSProcess.clearSelectCondition()
    SSProcess.setSelectCondition("SSObj_Code", "==", "100")        # 建筑物编码
    SSProcess.setSelectCondition("[建筑结构]", "==", "钢筋混凝土")
    SSProcess.setSelectCondition("[层数]", ">", "15")
    SSProcess.setSelectCondition("[维护状态]", "==", "待维护")
    SSProcess.selectFilter()
    
    count = SSProcess.getSelGeoCount()
    print(f"   找到 {count} 个符合条件的建筑\n")
    
    if count == 0:
        print("没有需要维护的建筑物")
        return
    
    # 2. 显示待维护建筑物列表
    print("2. 待维护建筑物列表:")
    print("-" * 80)
    print(f"{'序号':<6}{'名称':<20}{'层数':<8}{'建筑结构':<12}{'建筑面积':<10}")
    print("-" * 80)
    
    for i in range(count):
        name = SSProcess.getSelGeoValue(i, "SSObj_Name")
        floors = SSProcess.getSelGeoValue(i, "[层数]")
        structure = SSProcess.getSelGeoValue(i, "[建筑结构]")
        area = SSProcess.getSelGeoValue(i, "[建筑面积]")
        print(f"{i:<6}{name:<20}{floors:<8}{structure:<12}{area:<10}")
    
    print()
    
    # 3. 批量更新维护信息
    print("3. 更新维护信息...")
    import datetime
    today = datetime.datetime.now().strftime("%Y-%m-%d")
    
    SSProcess.setSelGeoValue(-1, "[维护状态]", "维护中")
    SSProcess.setSelGeoValue(-1, "[开始维护日期]", today)
    SSProcess.setSelGeoValue(-1, "[维护责任人]", "张工程师")
    SSProcess.setSelGeoValue(-1, "[维护内容]", "外墙清洗和设备检查")
    
    # 4. 保存修改
    print("4. 保存修改到数据库...")
    for i in range(count):
        SSProcess.addSelGeoToSaveGeoList(i)
    
    SSProcess.saveBufferObjToDatabase()
    SSProcess.updateRequest()
    
    print(f"   已更新 {count} 个建筑物的维护状态\n")
    
    # 5. 生成维护报告
    print("5. 维护报告摘要:")
    print("-" * 80)
    
    # 按建筑结构统计
    structure_stats = {}
    for i in range(count):
        structure = SSProcess.getSelGeoValue(i, "[建筑结构]")
        structure_stats[structure] = structure_stats.get(structure, 0) + 1
    
    print("按建筑结构分类:")
    for structure, num in structure_stats.items():
        print(f"   - {structure}: {num} 栋")
    
    print()
    
    # 按楼层数统计
    print("按楼层数分类:")
    high_rise = 0
    mid_rise = 0
    for i in range(count):
        floors = int(SSProcess.getSelGeoValue(i, "[层数]"))
        if floors > 20:
            high_rise += 1
        elif floors > 10:
            mid_rise += 1
    
    print(f"   - 高层建筑(>20层: {high_rise} 栋")
    print(f"   - 中高层建筑11-20层: {mid_rise} 栋")
    
    print()
    print("=== 维护管理操作完成 ===")

# 执行维护管理系统
if __name__ == "__main__":
    building_maintenance_system()

示例输出

=== 建筑物维护管理系统 ===

1. 查找待维护的高层建筑...
   找到 5 个符合条件的建筑

2. 待维护建筑物列表:
--------------------------------------------------------------------------------
序号   名称                层数    建筑结构      面积      
--------------------------------------------------------------------------------
0      金融大厦A座        32      钢筋混凝土    15000     
1      科技研发中心        25      钢筋混凝土    12000     
2      商业综合体B区       28      钢筋混凝土    18000     
3      写字楼C座           22      钢筋混凝土    9500      
4      商务中心大楼        18      钢筋混凝土    8500      

3. 更新维护信息...
4. 保存修改到数据库...
   已更新 5 个建筑物的维护状态

5. 维护报告摘要:
--------------------------------------------------------------------------------
按建筑结构分类:
   - 钢筋混凝土: 5 栋

按楼层数分类:
   - 高层建筑(>20层: 4 栋
   - 中高层建筑11-20层: 1 栋

=== 维护管理操作完成 ===

Sources: ssprocess_mixins/selection_mixin.py, ssprocess_mixins/geo_edit_mixin.py

下一步学习

掌握扩展属性后,您可以继续探索以下相关主题:

通过系统学习这些内容,您将能够充分利用 SunvStation 的属性管理功能,构建高效的地理数据管理应用。