本页面详细介绍如何使用地物编码(Feature Code)在 SunvStation 系统中创建地理对象。通过编码创建对象是一种快速、标准化的对象创建方式,系统会根据预定义的地物编码自动应用对应的符号样式、图层属性和几何类型,确保创建的对象符合制图规范和数据标准。 建议在学习本页面之前,先了解[创建默认地物对象](19-chuang-jian-mo-ren-di-wu-dui-xiang)和[地物基本属性详解](17-di-wu-ji-ben-shu-xing-xiang-jie)。完成本页面学习后,可以继续学习[添加对象坐标点](21-tian-jia-dui-xiang-zuo-biao-dian)和[对象缓存机制](23-dui-xiang-huan-cun-ji-zhi)。 Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L175-L217) ## 地物编码体系概念 地物编码(Feature Code)是 SunvStation 系统中用于标识和管理不同类型地理对象的数字标识系统。每个地物编码对应一组预定义的属性配置,包括对象类型、颜色、线型、线宽等显示属性,以及所属的数据集(图层)。通过编码创建对象时,系统会自动从编码定义中读取这些属性并应用到新创建的对象上,确保对象符合制图规范。 **地物编码的核心优势**在于将对象的几何定义与符号化表达分离。开发者只需指定编码值,系统即可自动处理所有的符号化细节,这大大简化了对象的创建流程,并保证了数据的一致性。编码体系通常遵循行业标准或企业内部规范,例如控制点可能使用编码 100,道路可能使用编码 200,建筑物可能使用编码 300 等。 Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L175-L217) ## createNewObjByCode 方法详解 `createNewObjByCode` 是通过编码创建地理对象的核心方法,该方法封装了从编码查询、对象创建到属性设置的完整流程。与 `createDefaultGeoBase` 不同,该方法不需要开发者手动指定对象类型和数据集,这些信息会根据编码自动推断和获取。 ### 方法签名 ```python def createNewObjByCode(self, code: int) -> tuple: ``` ### 参数说明 | 参数名 | 类型 | 必需 | 说明 | |--------|------|------|------| | code | int | 是 | 地物编码值,用于标识要创建的对象类型 | ### 返回值 返回一个包含两个元素的元组: - 第一个元素:`GeoObject` 实例,作为地物对象的容器 - 第二个元素:具体的几何对象实例(`PointObject`/`LineObject`/`AreaObject`) 如果创建失败,返回 `(None, None)`。 Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L175-L217) ## 对象创建工作流程 通过编码创建对象是一个多步骤的自动化流程,系统会执行从编码解析到对象初始化的一系列操作。理解这个流程有助于开发者在出现问题时快速定位原因,并在需要时进行扩展或自定义。 ```mermaid flowchart TD A[调用 createNewObjByCode] --> B[重置当前新建对象] B --> C[获取当前数据源EPS] C --> D{数据源EPS有效?} D -->|否| E[记录错误并返回 None,None] D -->|是| F[根据编码查询Feature定义] F --> G{Feature存在?} G -->|否| H[使用默认编码0的Feature] G -->|是| I[获取Feature对象] H --> I I --> J[从Feature获取数据集] J --> K{数据集有效?} K -->|否| L[记录错误并返回 None,None] K -->|是| M[读取对象类型] M --> N[调用createDefaultGeoBase创建对象] N --> O[应用Feature样式属性] O --> P[设置编码值] P --> Q[设置颜色] Q --> R[设置填充颜色] R --> S[设置线宽] S --> T[设置线型] T --> U[保存到curNewObj] U --> V[返回对象元组] ``` Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L175-L217) ## Feature 编码解析机制 Feature 编码解析是创建过程的核心环节。系统首先通过 `getCurrentDataSourceEPS()` 获取当前地图的数据源 EPS(Extended Parameter System)对象,该对象维护了所有预定义的 Feature 编码配置。随后,系统调用 `ds_eps.getFeature(code)` 尝试获取指定编码的 Feature 对象。 Feature 对象包含了创建对象所需的所有元数据,主要包括: - **nObjectType**:对象类型标识(0-点,1-线,2-面) - **uLineColor**:线条颜色值 - **nLineWidth**:线条宽度 - **nLineType**:线条类型(实线、虚线等) - 数据集信息:通过 `getDatasetByFeaCode()` 关联的数据集 如果指定的编码不存在,系统会自动回退到使用编码 0 的 Feature 作为默认配置,这种容错机制确保了即使编码错误也能创建对象,虽然可能不符合预期样式。 Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L182-L195) ## 对比:编码创建 vs 默认创建 为了帮助开发者选择合适的对象创建方式,以下对比了 `createNewObjByCode` 和 `createDefaultGeoBase` 两种方法的特性差异。 | 特性 | createNewObjByCode | createDefaultGeoBase | |------|-------------------|---------------------| | **参数需求** | 仅需编码值 | 需要对象类型和数据集 | | **属性设置** | 自动从 Feature 继承 | 需要手动设置 | | **数据集获取** | 自动解析 | 需要开发者提供 | | **样式一致性** | 高(符合编码规范) | 低(需要手动配置) | | **使用场景** | 标准化对象创建 | 自定义或实验性对象 | | **代码复杂度** | 简单 | 相对复杂 | | **错误处理** | 内置回退机制 | 需要开发者实现 | Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L93-L120) ## 基础创建示例 以下示例展示了如何使用 `createNewObjByCode` 方法创建不同类型的地理对象。 ### 创建点对象 ```python # 使用编码 100 创建控制点对象 obj, geo = SSProcess.createNewObjByCode(100) if obj is not None and geo is not None: print(f"成功创建点对象,ID: {geo.getId()}") print(f"对象类型: {geo.getObjectType()}") # 输出: 0 (点对象) print(f"地物编码: {geo.getCode()}") print(f"对象颜色: {geo.getColor():#06x}") # 添加坐标点 SSProcess.addNewObjPoint(100.0, 200.0, 0.0, 0, "PT1") # 保存到数据库 SSProcess.addNewObjToSaveObjList() SSProcess.saveBufferObjToDatabase() else: print("创建点对象失败") ``` ### 创建线对象 ```python # 使用编码 200 创建道路线对象 obj, geo = SSProcess.createNewObjByCode(200) if geo is not None and geo.getObjectType() == 1: print("成功创建线对象") print(f"线型: {geo.getLineType()}") print(f"线宽: {geo.getLineWidth()}") # 添加线段上的多个点 SSProcess.addNewObjPoint(100.0, 100.0, 0.0, 0, "起点") SSProcess.addNewObjPoint(200.0, 150.0, 0.0, 0, "中间点") SSProcess.addNewObjPoint(300.0, 200.0, 0.0, 0, "终点") # 设置扩展属性 SSProcess.setNewObjValue("[RoadName]", "中山路") SSProcess.setNewObjValue("[RoadWidth]", "20.5") # 保存对象 SSProcess.addNewObjToSaveObjList() SSProcess.saveBufferObjToDatabase() ``` ### 创建面对象 ```python # 使用编码 300 创建建筑物面对象 obj, geo = SSProcess.createNewObjByCode(300) if geo is not None and geo.getObjectType() == 2: print("成功创建面对象") print(f"填充颜色: {geo.getFillColor():#06x}") # 添加多边形顶点(顺时针或逆时针均可) SSProcess.addNewObjPoint(100.0, 100.0, 0.0, 0, "顶点1") SSProcess.addNewObjPoint(150.0, 100.0, 0.0, 0, "顶点2") SSProcess.addNewObjPoint(150.0, 150.0, 0.0, 0, "顶点3") SSProcess.addNewObjPoint(100.0, 150.0, 0.0, 0, "顶点4") # 设置对象名称 geo.setObjName("商业大厦") # 设置基本属性 SSProcess.setNewObjValue("SSObj_Name", "商业大厦") SSProcess.setNewObjValue("SSObj_DataMark", "新建") # 保存对象 SSProcess.addNewObjToSaveObjList() SSProcess.saveBufferObjToDatabase() ``` Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L175-L217) ## 属性设置与自定义 虽然 `createNewObjByCode` 会自动应用 Feature 定义中的样式属性,但在实际应用中,通常还需要设置对象的业务属性和扩展属性。系统提供了 `setNewObjValue` 方法来统一处理基本属性和扩展属性的设置。 ### 属性设置示例 ```python # 通过编码创建对象 obj, geo = SSProcess.createNewObjByCode(400) # 设置基本属性(SSObj_ 前缀) SSProcess.setNewObjValue("SSObj_Name", "电力设施A") SSProcess.setNewObjValue("SSObj_Byname", "设施1号") SSProcess.setNewObjValue("SSObj_Color", "0xFF0000") # 修改为红色 SSProcess.setNewObjValue("SSObj_LineWidth", "3") # 设置扩展属性(使用 [] 括住属性名) SSProcess.setNewObjValue("[电压等级]", "220kV") SSProcess.setNewObjValue("[投运日期]", "2024-01-01") SSProcess.setNewObjValue("[维护单位]", "市供电局") # 批量设置多个扩展属性 SSProcess.setNewObjValue("[经度],[纬度],[海拔]", "116.404,39.915,50.5") # 保存对象 SSProcess.addNewObjPoint(120.0, 180.0, 50.5, 0, "中心点") SSProcess.addNewObjToSaveObjList() SSProcess.saveBufferObjToDatabase() ``` Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L260-L420) ## 批量对象创建 在实际应用中,经常需要批量创建多个同类型的对象。以下示例展示了如何批量创建控制点对象。 ```python # 控制点坐标列表 control_points = [ (100.0, 200.0, 0.0, "PT001"), (150.0, 250.0, 0.0, "PT002"), (200.0, 300.0, 0.0, "PT003"), (250.0, 350.0, 0.0, "PT004"), (300.0, 400.0, 0.0, "PT005"), ] success_count = 0 failed_count = 0 for x, y, z, name in control_points: # 使用编码 100 创建控制点 obj, geo = SSProcess.createNewObjByCode(100) if obj is not None and geo is not None: # 设置坐标点 SSProcess.addNewObjPoint(x, y, z, 0, name) # 设置扩展属性 SSProcess.setNewObjValue("[点名]", name) SSProcess.setNewObjValue("[观测日期]", "2024-01-15") # 添加到保存列表 SSProcess.addNewObjToSaveObjList() success_count += 1 else: failed_count += 1 print(f"创建点 {name} 失败") # 批量保存到数据库 if success_count > 0: SSProcess.saveBufferObjToDatabase() print(f"成功创建 {success_count} 个控制点") if failed_count > 0: print(f"失败 {failed_count} 个控制点") ``` Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L175-L217) ## 注记对象创建 对于注记(文本)对象的创建,系统提供了专门的方法 `createNewObjByClass`,它通过注记类名称(如 "1", "2" 等)来创建文本对象。注记对象的地物编码机制与普通几何对象略有不同,它使用模板系统来管理样式。 ```python # 创建注记对象 noteClass = "1" # 注记类编号 obj, geo = SSProcess.createNewObjByClass(noteClass) if geo is not None and geo.getObjectType() == 3: print("成功创建注记对象") # 将 geo 转换为 MarkNote 类型 from sunvpy.PySSCore import castToMarkNote note = castToMarkNote(geo) # 设置注记内容 note.setNote("示例标注文字") # 设置位置点 SSProcess.addNewObjPoint(150.0, 180.0, 0.0, 0, "注记位置") # 使用 setNewObjValue 设置注记属性 SSProcess.setNewObjValue("SSObj_FontHeight", "120") SSProcess.setNewObjValue("SSObj_FontWidth", "60") SSProcess.setNewObjValue("SSObj_FontName", "宋体") SSProcess.setNewObjValue("SSObj_FontAlignment", "1") # 居中对齐 # 保存注记对象 SSProcess.addNewObjToSaveObjList() SSProcess.saveBufferObjToDatabase() ``` Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L218-L247) ## 错误处理与调试 在使用 `createNewObjByCode` 创建对象时,可能会遇到各种错误情况。了解这些错误及其处理方式是编写健壮代码的关键。 ### 常见错误类型 | 错误场景 | 可能原因 | 解决方案 | |---------|---------|---------| | 返回 (None, None) | 数据源 EPS 无效 | 检查地图数据源是否正确加载 | | 对象样式不符合预期 | 编码不存在或 Feature 配置错误 | 验证编码值是否在编码表中定义 | | 无法获取数据集 | Feature 的图层配置错误 | 检查 Feature 对应的数据集是否存在 | | 对象保存失败 | 几何数据不完整或无效 | 确保添加了足够的坐标点 | ### 完整错误处理示例 ```python def create_geo_object_with_retry(code: int, max_retries: int = 3): """带重试机制的对象创建函数""" for attempt in range(max_retries): obj, geo = SSProcess.createNewObjByCode(code) if obj is None or geo is None: print(f"尝试 {attempt + 1}/{max_retries}: 创建失败,编码 {code}") if attempt < max_retries - 1: import time time.sleep(0.5) # 短暂等待后重试 continue # 验证对象类型 obj_type = geo.getObjectType() if obj_type not in [0, 1, 2]: # 有效的点线面类型 print(f"警告: 对象类型异常 ({obj_type})") return None, None print(f"成功创建对象,编码: {code}, 类型: {obj_type}") return obj, geo print(f"错误: 创建对象失败,编码 {code}") return None, None # 使用示例 obj, geo = create_geo_object_with_retry(100) if obj is not None: # 继续后续操作 SSProcess.addNewObjPoint(100.0, 200.0, 0.0, 0, "PT1") SSProcess.addNewObjToSaveObjList() ``` Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L182-L195) ## 完整应用示例:创建标准地图要素 以下是一个完整的示例,演示如何使用编码创建机制构建一个包含多种类型地理要素的简单地图场景。 ```python from sunvpy import SSProcess def create_map_scenario(): """创建一个包含多种要素的简单地图场景""" print("=== 开始创建地图场景 ===") # 1. 创建控制点(编码 100) print("\n1. 创建控制点...") control_points = [(50, 50), (50, 150), (150, 50), (150, 150)] for i, (x, y) in enumerate(control_points, 1): obj, geo = SSProcess.createNewObjByCode(100) if obj is not None: SSProcess.addNewObjPoint(x, y, 0.0, 0, f"CP{i}") SSProcess.setNewObjValue("[等级]", "一级") SSProcess.addNewObjToSaveObjList() # 2. 创建道路(编码 200) print("\n2. 创建道路...") road_points = [(0, 100), (50, 100), (100, 100), (150, 100), (200, 100)] obj, geo = SSProcess.createNewObjByCode(200) if obj is not None: for x, y in road_points: SSProcess.addNewObjPoint(x, y, 0.0, 0, "道路点") SSProcess.setNewObjValue("[道路名称]", "中山路") SSProcess.setNewObjValue("[道路等级]", "主干道") SSProcess.addNewObjToSaveObjList() # 3. 创建建筑物(编码 300) print("\n3. 创建建筑物...") buildings = [ (60, 60, 90, 90, "住宅A"), (110, 60, 140, 90, "住宅B"), (60, 110, 90, 140, "商业楼"), (110, 110, 140, 140, "办公楼") ] for min_x, min_y, max_x, max_y, name in buildings: obj, geo = SSProcess.createNewObjByCode(300) if obj is not None: # 构建矩形面 SSProcess.addNewObjPoint(min_x, min_y, 0.0, 0, "左下") SSProcess.addNewObjPoint(max_x, min_y, 0.0, 0, "右下") SSProcess.addNewObjPoint(max_x, max_y, 0.0, 0, "右上") SSProcess.addNewObjPoint(min_x, max_y, 0.0, 0, "左上") SSProcess.setNewObjValue("SSObj_Name", name) SSProcess.setNewObjValue("[建筑面积]", "500") SSProcess.addNewObjToSaveObjList() # 4. 创建注记标注 print("\n4. 创建注记标注...") labels = [ ("控制点组", 100, 10, 100), ("中山路", 200, 100, 90), ("住宅区", 300, 100, 40) ] for text, code, x, y in labels: if code == 300: # 注记使用 createNewObjByClass obj, geo = SSProcess.createNewObjByClass("1") else: obj, geo = SSProcess.createNewObjByCode(code) if obj is not None and geo is not None: SSProcess.addNewObjPoint(x, y, 0.0, 0, "注记位置") if geo.getObjectType() == 3: from sunvpy.PySSCore import castToMarkNote note = castToMarkNote(geo) note.setNote(text) SSProcess.addNewObjToSaveObjList() # 5. 批量保存所有对象 print("\n5. 保存所有对象到数据库...") SSProcess.saveBufferObjToDatabase() print("=== 地图场景创建完成 ===") # 执行创建 create_map_scenario() ``` Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L175-L247) ## 对象选择集集成 通过编码创建的对象可以方便地集成到选择集系统中,便于后续的查询、编辑和批量操作。 ```python # 创建多个对象并添加到选择集 codes = [100, 200, 300, 400] for code in codes: obj, geo = SSProcess.createNewObjByCode(code) if obj is not None and geo is not None: # 添加对象的基本几何(示例) SSProcess.addNewObjPoint(100.0 + code, 100.0, 0.0, 0, "PT") if geo.getObjectType() == 1: # 线对象需要多个点 SSProcess.addNewObjPoint(110.0 + code, 110.0, 0.0, 0, "PT2") # 设置属性 SSProcess.setNewObjValue("SSObj_Name", f"对象{code}") # 添加到选择集(不是保存列表) SSProcess.addNewObjToSelObjList() # 同时添加到保存列表以便持久化 SSProcess.addNewObjToSaveObjList() # 保存到数据库 SSProcess.saveBufferObjToDatabase() # 现在可以在选择集中遍历这些对象 sel_count = SSProcess.getSelGeoCount() print(f"选择集中有 {sel_count} 个对象") ``` Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L430-L460) ## 性能优化建议 在批量创建对象时,合理使用缓存机制可以显著提升性能。 ### 批量创建优化策略 ```python # 优化前:逐个保存(低效) for i in range(100): obj, geo = SSProcess.createNewObjByCode(100) if obj is not None: SSProcess.addNewObjPoint(i, i, 0.0, 0, f"PT{i}") SSProcess.addNewObjToSaveObjList() SSProcess.saveBufferObjToDatabase() # 每次都保存,效率低 # 优化后:批量保存(高效) for i in range(100): obj, geo = SSProcess.createNewObjByCode(100) if obj is not None: SSProcess.addNewObjPoint(i, i, 0.0, 0, f"PT{i}") SSProcess.addNewObjToSaveObjList() # 只添加到列表 SSProcess.saveBufferObjToDatabase() # 一次性保存所有对象 ``` ### 性能对比 | 操作方式 | 创建 100 个对象耗时 | 数据库事务次数 | 适用场景 | |---------|-------------------|--------------|---------| | 逐个保存 | ~5000ms | 100 次 | 需要即时反馈的场景 | | 批量保存 | ~500ms | 1 次 | 大批量对象创建 | | 分批保存 | ~1000ms | 10 次 | 中等规模,需要进度反馈 | Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L490-L540) ## 学习路径建议 掌握通过编码创建对象是 SunvStation 开发的核心技能之一。以下是一个循序渐进的学习路径: 1. **基础阶段**:掌握 `createNewObjByCode` 的基本用法,能够创建简单的点线面对象 2. **进阶阶段**:学习属性设置方法(`setNewObjValue`),能够设置基本属性和扩展属性 3. **应用阶段**:掌握批量创建技巧,能够处理大规模对象创建任务 4. **优化阶段**:理解对象缓存机制,能够编写高效的批量操作代码 建议按照以下顺序学习相关文档: - [添加对象坐标点](21-tian-jia-dui-xiang-zuo-biao-dian):学习如何为对象添加几何数据 - [对象缓存机制](23-dui-xiang-huan-cun-ji-zhi):理解对象的生命周期管理 - [批量保存到数据库](24-pi-liang-bao-cun-dao-shu-ju-ku):掌握数据持久化的最佳实践 - [修改地物属性值](16-xiu-gai-di-wu-shu-xing-zhi):深入学习属性操作的完整API