Files
sunvpy-docs/docs/content/42-di-li-dui-xiang-lei-xing-ding-yi.md
2026-04-10 13:47:53 +08:00

622 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
地理对象类型定义是 SunvStation 系统中地理数据模型的核心组成部分。系统采用面向对象的设计模式,通过类继承体系和类型标识来管理不同形态的地理要素。理解这些类型定义及其相互关系,是进行地理数据处理、空间分析和可视化的基础。
本页面将系统性地介绍地理对象的类型体系、类结构、属性机制以及相关的类型识别和转换方法。建议在学习本页面之前,先了解 [SunvStation 系统架构](6-sunvstation-xi-tong-jia-gou) 和 [C++ 扩展模块与 Python 接口](10-c-kuo-zhan-mo-kuai-yu-python-jie-kou)。完成本页面学习后,可以继续学习 [创建默认地物对象](19-chuang-jian-mo-ren-di-wu-dui-xiang) 和 [地物基本属性详解](17-di-wu-ji-ben-shu-xing-xiang-jie)。
Sources: [PySSCore.py](PySSCore.py#L2600-L3200)
## 地理对象类型体系
SunvStation 系统定义了四种基础地理对象类型,每种类型对应不同的几何形态和应用场景。这些类型通过整数标识符进行区分,并与特定的几何类相对应。类型体系的设计遵循简单、明确、可扩展的原则,为地理数据的存储、查询和展示提供了统一的抽象层次。
### 四种基础类型
| 类型标识 | 类型名称 | 几何类 | 典型应用场景 | 几何特征 |
|---------|---------|--------|------------|---------|
| 0 | 点对象 | PointObject | 控制点、界碑、建筑物中心点、测量点 | 零维几何,由单个坐标点定义 |
| 1 | 线对象 | LineObject | 道路、管线、河流中心线、边界线 | 一维几何,由有序坐标点序列定义 |
| 2 | 面对象 | AreaObject | 建筑物轮廓、湖泊、行政区划、地块 | 二维几何,由闭合坐标环定义 |
| 3 | 注记对象 | MarkNote | 文字标注、地名说明、图例说明 | 特殊对象,结合文本与定位点 |
### 类型标识的作用
类型标识是系统内部识别对象类型的核心机制,其作用体现在以下几个方面:
- **对象创建**`createDefaultGeoBase(obj_type, dataset)` 方法通过类型标识决定创建具体的几何对象实例
- **类型判断**`getObjectType()` 方法返回当前对象的类型标识,用于运行时类型识别
- **数据查询**:查询条件中可以通过类型标识过滤特定类型的地理对象
- **符号化渲染**:系统根据对象类型应用不同的符号化规则和渲染策略
Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L93-L120)
## 类继承架构
地理对象类型体系基于面向对象的继承架构设计,通过基类和派生类的层次结构实现代码复用和多态性。理解这个架构有助于掌握各类地理对象的共性和特性,以及如何正确使用它们提供的方法和属性。
### 继承层次结构
```mermaid
classDiagram
GeoBase <|-- PointObject
GeoBase <|-- LineObject
GeoBase <|-- AreaObject
GeoBase <|-- MarkNote
class GeoBase {
<<抽象基类>>
+getId() int
+setId(id)
+getCode() int
+setCode(code)
+getColor() int
+setColor(color)
+getObjectType() int
+getArea(haveSign) float
+getPerimeter() float
+setStatus(flag, status)
+getStatus(status) bool
}
class PointObject {
+getObjectType() int
+getScaleX/Y/Z() float
+setScaleX/Y/Z(scale)
+rotate(point, vct)
}
class LineObject {
+getObjectType() int
+getPerimeter() float
+getArea(haveSign) float
+setLineThickness(thickness)
+getLineThickness() float
}
class AreaObject {
+getObjectType() int
+getArea(haveSign) float
+getPerimeter() float
+getLoops() PointArray
}
class MarkNote {
+getObjectType() int
+setNote(note)
+getNote() string
+setFontHeight(height)
+setFontWidth(width)
+setAlignment(alignment)
+setNoteClass(number)
}
```
### GeoBase 基类
`GeoBase` 是所有地理对象的抽象基类,定义了所有地理对象共有的属性和方法。基类的设计遵循"提取共性、隔离差异"的原则,将通用的功能集中在基类中实现,而将特定类型的几何操作委托给派生类。
**核心属性**
- **ID**:对象的唯一标识符(`getId()`/`setId()`
- **Code**:地物编码,关联符号定义(`getCode()`/`setCode()`
- **Color**:颜色值(`getColor()`/`setColor()`
- **LineType/LineWidth**:线型和线宽(`getLineType()`/`setLineType()`, `getLineWidth()`/`setLineWidth()`
- **Status**:对象状态标志(`setStatus()`/`getStatus()`
**核心方法**
- `getObjectType()`:获取对象类型标识(返回 0、1、2 或 3
- `getArea()`:计算面积(仅 AreaObject 和 LineObject 返回有效值)
- `getPerimeter()`:计算周长(仅 AreaObject 和 LineObject 返回有效值)
Sources: [PySSCore.py](PySSCore.py#L2000-L2800)
### 派生类特性
各派生类在继承基类功能的基础上,针对特定的几何类型提供了专门的属性和方法:
**PointObject点对象**
- 支持三维缩放变换(`setScaleX/Y/Z()`
- 提供旋转功能(`rotate()`
- 主要用于表示离散的地理位置或标记点
**LineObject线对象**
- 继承面积计算方法(可用于计算线性要素的缓冲区面积)
- 提供线厚度设置(`setLineThickness()`
- 由一系列有序坐标点构成,表示连续的地理要素
**AreaObject面对象**
- 提供面积和周长的精确计算
- 支持多环结构(通过 `getLoops()` 获取)
- 由闭合坐标环构成,表示有界区域
**MarkNote注记对象**
- 继承自 GeoBase 但具有独特的属性体系
- 提供文本内容管理(`setNote()`/`getNote()`
- 支持字体属性设置(高度、宽度、对齐方式等)
- 提供注记类关联(`setNoteClass()`
Sources: [PySSCore.py](PySSCore.py#L2800-L3000)
## GeoObject 容器对象
`GeoObject` 是地理对象的容器类与具体的几何对象PointObject、LineObject、AreaObject、MarkNote协同工作形成完整的地物对象体系。理解容器对象与几何对象的关系对于正确创建、管理和操作地物对象至关重要。
### 容器与几何对象的分离设计
SunvStation 系统采用容器对象与几何对象分离的设计模式,每个地理地物由两个核心组件构成:
- **GeoObject 容器**:负责数据集关联、对象 ID 管理、属性存储和事务控制
- **几何对象GeoBase 派生类)**:负责几何数据存储、空间计算和图形属性
这种分离设计的优势在于:
- **关注点分离**:数据管理与几何计算职责清晰
- **灵活组合**:同一容器可以承载不同类型的几何对象
- **事务支持**:容器提供统一的事务管理接口
### GeoObject 核心功能
```mermaid
flowchart LR
subgraph GeoObject容器
A[数据集引用]
B[唯一ID管理]
C[属性存储]
D[事务控制]
end
subgraph 几何对象
E[PointObject]
F[LineObject]
G[AreaObject]
H[MarkNote]
end
A --> E
A --> F
A --> G
A --> H
C --> E
C --> F
C --> G
C --> H
```
**数据集关联**GeoObject 维护到数据集的引用,确保对象与数据库表的正确映射
**唯一 ID 管理**:通过 `generateUniqueId()` 生成全局唯一的对象标识符
**属性管理**:提供属性和图形信息的统一访问接口(`getAttribute()`/`getGraphicInfo()`
**几何对象绑定**:通过 `setGeoBase()`/`getGeoBase()` 方法管理几何对象的关联
Sources: [PySSCore.py](PySSCore.py#L900-L1000)
## 类型识别与转换机制
系统提供了完整的类型识别和转换机制,支持运行时类型判断和安全地类型转换。这些机制在处理异构对象集合、实现多态操作和类型安全访问时发挥关键作用。
### getObjectType() 类型识别方法
所有地理对象都实现了 `getObjectType()` 方法,该方法返回对象的类型标识符。这是运行时类型判断的主要方式:
```python
# 示例:判断对象类型
geo = getGeoObject() # 获取一个地理对象
obj_type = geo.getObjectType()
if obj_type == 0:
print("这是一个点对象")
elif obj_type == 1:
print("这是一个线对象")
elif obj_type == 2:
print("这是一个面对象")
elif obj_type == 3:
print("这是一个注记对象")
```
### 类型转换函数
系统提供了一组类型转换函数,用于在 `GeoBase` 基类指针和具体类型指针之间进行安全转换:
| 转换函数 | 目标类型 | 转换条件 | 失败返回 |
|---------|---------|---------|---------|
| `castToPointObject(geo)` | PointObject | 对象类型为 0 | None |
| `castToLineObject(geo)` | LineObject | 对象类型为 1 | None |
| `castToAreaObject(geo)` | AreaObject | 对象类型为 2 | None |
| `castToMarkNote(geo)` | MarkNote | 对象类型为 3 | None |
**转换示例**
```python
# 安全的类型转换
from sunvpy.PySSCore import castToLineObject, castToMarkNote
def processObject(geo):
obj_type = geo.getObjectType()
if obj_type == 1:
# 转换为线对象并访问线特有方法
line = castToLineObject(geo)
if line is not None:
thickness = line.getLineThickness()
print(f"线对象厚度: {thickness}")
elif obj_type == 3:
# 转换为注记对象并访问注记特有方法
note = castToMarkNote(geo)
if note is not None:
text = note.getNote()
print(f"注记内容: {text}")
```
### 类型转换的工作原理
类型转换函数在 C++ 层面实现,采用动态类型检查机制:
```mermaid
sequenceDiagram
participant Py as Python代码
participant SWIG as SWIG接口
participant Cpp as C++实现
Py->>SWIG: castToLineObject(geo)
SWIG->>Cpp: 调用转换函数
Cpp->>Cpp: 检查对象类型
alt 类型匹配 (getObjectType() == 1)
Cpp->>Cpp: 执行类型转换
Cpp->>SWIG: 返回 LineObject 指针
SWIG->>Py: 返回 Python 对象
else 类型不匹配
Cpp->>SWIG: 返回 NULL
SWIG->>Py: 返回 None
end
```
Sources: [PySSCore.py](PySSCore.py#L3000-L3100)
## 地理对象列表类型
为了高效管理大量同类型地理对象,系统为每种地理对象类型提供了专用的列表容器。这些列表容器继承自标准模板库的 vector 容器,提供了丰富的集合操作接口。
### 列表类型体系
| 列表类型 | 元素类型 | 典型用途 | 特殊方法 |
|---------|---------|---------|---------|
| `PointObjectList` | PointObject | 控制点集合、测量点集 | 通用列表方法 |
| `LineObjectList` | LineObject | 道路网络、管线系统 | 通用列表方法 |
| `AreaObjectList` | AreaObject | 建筑物群、地块集合 | 通用列表方法 |
| `MarkNoteList` | MarkNote | 标注集合、图例列表 | 通用列表方法 |
| `GeoBaseList` | GeoBase | 混合类型对象集合 | 通用列表方法 |
### 列表通用方法
所有列表容器都提供以下核心方法:
**基本操作**
- `size()`:获取元素数量
- `empty()`:判断是否为空
- `clear()`:清空列表
- `append(x)`:在尾部添加元素
- `pop()`:移除并返回尾部元素
**访问操作**
- `front()`:访问首元素
- `back()`:访问尾元素
- `__getitem__(index)`:索引访问(支持负索引)
- `iterator()`:获取迭代器(支持 Python 迭代协议)
**修改操作**
- `insert(index, x)`:在指定位置插入元素
- `erase(index)`:删除指定位置元素
- `resize(n)`:调整列表大小
**列表操作**
- `swap(other)`:交换两个列表内容
- `assign(n, x)`:用 n 个 x 填充列表
### 类型转换列表
系统还提供了列表类型的转换函数,用于在不同列表类型之间进行转换:
- `castToMarkNoteList(geos)`:将 `GeoBaseList` 转换为 `MarkNoteList`
- `castToGeoBaseList(geos)`:将 `MarkNoteList` 转换为 `GeoBaseList`
这些转换函数在处理混合类型对象集合时非常有用,例如在选择集操作中。
**示例**
```python
from sunvpy.PySSCore import GeoBaseList, MarkNoteList, castToMarkNoteList
# 创建通用列表
geo_list = GeoBaseList()
# 添加不同类型的对象
geo_list.append(point_obj) # 添加点对象
geo_list.append(line_obj) # 添加线对象
geo_list.append(note_obj) # 添加注记对象
# 转换为注记列表(仅提取注记对象)
note_list = castToMarkNoteList(geo_list)
print(f"注记对象数量: {note_list.size()}")
# 遍历注记列表
for i in range(note_list.size()):
note = note_list[i]
print(f"注记内容: {note.getNote()}")
```
Sources: [PySSCore.py](PySSCore.py#L3100-L3400)
## 属性系统与地物基本属性
地理对象的属性系统通过 `ObjBaseAttr` 类进行统一管理,该类定义了所有地物对象支持的基本属性名称和索引。属性系统为地物对象的元数据管理提供了标准化的接口,确保了属性访问的一致性和可扩展性。
### ObjBaseAttr 类结构
`ObjBaseAttr` 类采用注册表模式,维护属性名称到索引的映射关系:
```python
class ObjBaseAttr:
def __init__(self):
self.valueNames = [] # 属性名称列表(自动排序)
# 注册所有属性名(去前缀 SSObj_按升序排列
attr_names = [
# 点属性
"SSObj_PointName", "SSObj_PointCount", "SSObj_PointType",
"SSObj_X", "SSObj_Y", "SSObj_Z",
# 通用属性
"SSObj_Code", "SSObj_Byname", "SSObj_LayerName",
"SSObj_Color", "SSObj_LineType", "SSObj_LineWidth",
"SSObj_ID", "SSObj_GroupID", "SSObj_Name", "SSObj_Type",
"SSObj_Status", "SSObj_DataMark", "SSObj_RelationID",
"SSObj_CreateTime", "SSObj_ModifyTime",
# ... 更多属性
]
```
### 属性分类体系
属性按照功能和用途分为多个类别,每类属性对应不同的应用场景和操作需求:
**几何属性**
- 点坐标:`SSObj_X`, `SSObj_Y`, `SSObj_Z`
- 点信息:`SSObj_PointName`, `SSObj_PointCount`, `SSObj_PointType`
- 几何参量:`SSObj_Area`, `SSObj_Length`, `SSObj_3DLength`
- 边界框:`SSObj_minX`, `SSObj_minY`, `SSObj_maxX`, `SSObj_maxY`
**显示属性**
- 颜色:`SSObj_Color`(前景色)、`SSObj_Area`(填充色)
- 线型:`SSObj_LineType`(线型样式)、`SSObj_LineWidth`(线宽)
- 变换:`SSObj_Angle`(旋转角度)、`SSObj_ScaleX/Y/XY`(缩放)
**数据属性**
- 标识:`SSObj_Code`(地物编码)、`SSObj_ID`(对象 ID`SSObj_Name`(对象名称)
- 分组:`SSObj_GroupID`(分组 ID`SSObj_LayerName`(图层名称)
- 时间:`SSObj_CreateTime`(创建时间)、`SSObj_ModifyTime`(修改时间)
**注记属性**(仅 MarkNote 对象):
- 字体:`SSObj_FontName`, `SSObj_FontHeight`, `SSObj_FontWidth`
- 对齐:`SSObj_FontAlignment`, `SSObj_FontPosType`
- 方向:`SSObj_FontDirection`, `SSObj_FontWordAngle`, `SSObj_FontStringAngle`
- 样式:`SSObj_FontWeight`, `SSObj_FontItalicAngle`, `SSObj_FontUnderLine`
### 属性索引机制
`ObjBaseAttr` 提供了属性名称到索引的映射功能,支持高效的属性访问:
**核心方法**
- `get_value_index(field: str) -> int`:根据属性名获取索引(去除 SSObj_ 前缀)
- `get_value_index_param(field: str) -> tuple`:解析带参数的属性名,返回索引和参数
- `getGeoValue(map, geo, field) -> str`:获取地理对象的属性值
**索引规则**
- 属性名自动去除 `SSObj_` 前缀并转换为小写
- 支持带参数的属性名(如 `SSObj_Code(param)`
- 属性名列表自动按升序排列,确保索引稳定性
**使用示例**
```python
from sunvpy.ObjBaseAttr import ObjBaseAttr
attr_mgr = ObjBaseAttr()
# 获取属性索引
code_idx = attr_mgr.get_value_index("SSObj_Code")
name_idx = attr_mgr.get_value_index("SSObj_Name")
color_idx = attr_mgr.get_value_index("color") # 不需要前缀
print(f"Code 索引: {code_idx}")
print(f"Name 索引: {name_idx}")
print(f"Color 索引: {color_idx}")
# 获取对象属性值
value = attr_mgr.getGeoValue(map, geo, "SSObj_Area")
print(f"面积: {value}")
```
Sources: [ObjBaseAttr.py](ObjBaseAttr.py#L1-L200)
## 对象类型与属性的关系
不同类型的地理对象在属性支持上存在差异,理解这些差异有助于正确地设置和访问对象属性。某些属性是所有类型通用的,而某些属性仅对特定类型有效。
### 通用属性 vs 特定类型属性
**所有地理对象共有的属性**
- `SSObj_Code`:地物编码
- `SSObj_ID`:对象唯一标识
- `SSObj_Name`:对象名称
- `SSObj_Color`:颜色
- `SSObj_LineType`:线型
- `SSObj_LineWidth`:线宽
- `SSObj_Status`:对象状态
- `SSObj_CreateTime` / `SSObj_ModifyTime`:时间戳
**仅 PointObject 支持的属性**
- 点坐标属性:`SSObj_X`, `SSObj_Y`, `SSObj_Z`
- 点信息:`SSObj_PointName`, `SSObj_PointCount`, `SSObj_PointType`
**仅 LineObject 和 AreaObject 支持的属性**
- 几何参量:`SSObj_Length`, `SSObj_3DLength`, `SSObj_Area`
- 边界框:`SSObj_minX`, `SSObj_minY`, `SSObj_maxX`, `SSObj_maxY`
**仅 AreaObject 支持的属性**
- 椭球面积:`SSObj_EllipsoidArea1`, `SSObj_EllipsoidArea2`
- 面积标注:`SSObj_DrawAreaLabelStatus`, `SSObj_AreaLabelX`, `SSObj_AreaLabelY`
**仅 MarkNote 支持的属性**
- 所有以 `SSObj_Font` 开头的字体相关属性
- `SSObj_FontClass`:注记类
- `SSObj_FontString`:注记文本内容
### 属性有效性判断
系统提供了多种方式来判断属性的有效性:
**基于对象类型的判断**
```python
def isValidAttribute(geo, attr_name):
"""判断属性是否对当前对象类型有效"""
obj_type = geo.getObjectType()
attr_name_lower = attr_name.lower().replace('ssobj_', '')
# 点对象专用属性
if attr_name_lower in ['x', 'y', 'z', 'pointname', 'pointcount', 'pointtype']:
return obj_type == 0
# 线对象和面对象的几何属性
if attr_name_lower in ['length', '3dlength']:
return obj_type in [1, 2]
# 面对象专用属性
if attr_name_lower in ['ellipsoidarea1', 'ellipsoidarea2', 'arealabelx', 'arealabely']:
return obj_type == 2
# 注记对象专用属性
if attr_name_lower.startswith('font'):
return obj_type == 3
# 通用属性
return True
```
**基于返回值的判断**
```python
# 几何属性仅在特定对象类型返回有效值
area = geo.getArea()
if area > 0.0:
print(f"对象面积为: {area}") # 仅 AreaObject 和 LineObject 有有效面积
perimeter = geo.getPerimeter()
if perimeter > 0.0:
print(f"对象周长为: {perimeter}") # 仅 AreaObject 和 LineObject 有有效周长
```
Sources: [PySSCore.py](PySSCore.py#L2600-L2800)
## 总结与最佳实践
地理对象类型定义是 SunvStation 系统地理数据模型的基础,掌握这些概念对于开发高效的地理数据处理脚本至关重要。以下是本页面介绍的核心要点和实际开发中的最佳实践建议。
### 核心概念回顾
1. **四种基础类型**0、线1、面2、注记3每种类型对应特定的几何类和应用场景
2. **继承架构**:所有地理对象继承自 `GeoBase` 基类,共享通用属性和方法,同时提供类型特定的功能
3. **容器分离**`GeoObject` 作为容器管理数据和事务,几何对象负责几何计算和属性存储
4. **类型识别**:通过 `getObjectType()` 方法进行运行时类型判断,使用类型转换函数进行安全类型转换
5. **属性系统**`ObjBaseAttr` 统一管理所有地物属性,支持标准化的属性访问机制
### 类型识别与处理最佳实践
**使用 `getObjectType()` 进行类型判断**
```python
# 推荐:显式类型检查
def processGeoObject(geo):
obj_type = geo.getObjectType()
if obj_type == 0:
processPoint(geo)
elif obj_type == 1:
processLine(geo)
elif obj_type == 2:
processArea(geo)
elif obj_type == 3:
processNote(geo)
else:
print(f"未知对象类型: {obj_type}")
```
**使用类型转换函数安全访问类型特定方法**
```python
# 推荐:安全转换后访问
def printObjectDetails(geo):
if geo.getObjectType() == 1:
line = castToLineObject(geo)
if line is not None:
print(f"线厚度: {line.getLineThickness()}")
if geo.getObjectType() == 3:
note = castToMarkNote(geo)
if note is not None:
print(f"注记: {note.getNote()}")
```
### 属性访问最佳实践
**使用 `ObjBaseAttr` 统一管理属性索引**
```python
# 推荐:使用属性管理器
attr_mgr = ObjBaseAttr()
code_idx = attr_mgr.get_value_index("Code")
# 访问属性
code_value = geo.getAttribute(code_idx)
```
**根据对象类型选择有效属性**
```python
# 推荐:判断属性有效性后再访问
def safeGetArea(geo):
if geo.getObjectType() in [1, 2]: # 线对象和面对象
area = geo.getArea()
return area if area > 0 else 0.0
else:
return 0.0 # 点对象和注记对象无面积
```
### 创建对象时的类型选择
**根据应用场景选择合适的对象类型**
```python
# 推荐:明确类型选择
def createFeature(feature_type, coordinates):
if feature_type == 'control_point':
obj, geo = createDefaultGeoBase(0, dataset) # 点对象
elif feature_type == 'road':
obj, geo = createDefaultGeoBase(1, dataset) # 线对象
elif feature_type == 'building':
obj, geo = createDefaultGeoBase(2, dataset) # 面对象
elif feature_type == 'label':
obj, geo = createDefaultGeoBase(3, dataset) # 注记对象
```
### 后续学习建议
完成本页面学习后,建议继续深入以下相关主题:
- **对象创建**:学习 [创建默认地物对象](19-chuang-jian-mo-ren-di-wu-dui-xiang) 和 [通过编码创建对象](20-tong-guo-bian-ma-chuang-jian-dui-xiang)
- **属性管理**:学习 [地物基本属性详解](17-di-wu-ji-ben-shu-xing-xiang-jie) 和 [获取地物属性值](15-huo-qu-di-wu-shu-xing-zhi)
- **类型转换**:学习 [SSProcessManager 完整 API](40-ssprocessmanager-wan-zheng-api) 中的类型相关方法
- **高级操作**:学习 [坐标转换工具](44-zuo-biao-zhuan-huan-gong-ju) 中的几何转换功能