This commit is contained in:
coco
2026-07-03 16:05:30 +08:00
commit df489d5640
1101 changed files with 779140 additions and 0 deletions
@@ -0,0 +1,382 @@
# Main模块
<cite>
**本文引用的文件**
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp)
- [Global.cpp](file://cpp/Main/Global.cpp)
- [GeoMative.h](file://h/GeoMative.h)
- [DevManager.h](file://h/DevManager.h)
- [TdManager.h](file://h/TdManager.h)
- [ProManager.h](file://h/ProManager.h)
- [ExecManager.h](file://h/ExecManager.h)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
## 引言
本文件聚焦于GeomativeStudio项目的Main模块,系统性阐述CGeoMativeApp作为MFC应用程序主类的职责与实现,包括:
- 应用程序初始化流程(InitInstance)与生命周期管理(ExitInstance
- 全局变量与全局函数的定义与作用域
- 各管理器(m_pDevManager、m_pProManager、m_pTdManager、m_pExecManager、m_pSptManager、m_pIOManager)的创建与依赖关系
- 通过AfxGetApp()全局函数访问应用程序实例并在不同模块间传递调用模式
## 项目结构
Main模块位于cpp/Main目录,包含两个关键文件:
- GeoMative.cppMFC应用主类CGeoMativeApp的实现,涵盖初始化、消息处理、退出清理等
- Global.cpp:全局变量、全局函数与跨模块共享的数据结构定义
```mermaid
graph TB
subgraph "Main模块"
A["GeoMative.cpp<br/>CGeoMativeApp实现"]
B["Global.cpp<br/>全局变量/函数"]
H["GeoMative.h<br/>CGeoMativeApp声明"]
end
subgraph "管理器模块"
D["DevManager.h"]
T["TdManager.h"]
P["ProManager.h"]
E["ExecManager.h"]
end
A --> H
A --> D
A --> T
A --> P
A --> E
B --> A
```
图表来源
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L1-L120)
- [Global.cpp](file://cpp/Main/Global.cpp#L1-L60)
- [GeoMative.h](file://h/GeoMative.h#L115-L182)
- [DevManager.h](file://h/DevManager.h#L1-L69)
- [TdManager.h](file://h/TdManager.h#L1-L109)
- [ProManager.h](file://h/ProManager.h#L1-L77)
- [ExecManager.h](file://h/ExecManager.h#L1-L42)
章节来源
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L1-L120)
- [Global.cpp](file://cpp/Main/Global.cpp#L1-L60)
- [GeoMative.h](file://h/GeoMative.h#L115-L182)
## 核心组件
- CGeoMativeApp:MFC应用主类,负责应用初始化、主窗口创建、资源加载、全局对象创建、网络与数据库初始化、线程与定时器管理、退出清理等
- 全局变量与函数:集中定义跨模块使用的全局状态、工具函数、线程入口与回调等
- 管理器集合:设备、项目、测试数据、执行、脚本、IO等管理器,由CGeoMativeApp统一创建与协调
章节来源
- [GeoMative.h](file://h/GeoMative.h#L115-L182)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L139-L210)
- [Global.cpp](file://cpp/Main/Global.cpp#L20-L70)
## 架构总览
CGeoMativeApp作为应用入口,承担以下职责:
- 初始化MFC环境、OLE、控件容器、3D控件支持
- 设置工作目录、创建缓存目录、加载主框架窗口
- 建立数据库连接(ADO/ADOX)、初始化日志、诊断信息、跨孔配置
- 创建各管理器实例并注入数据库连接
- 读取配置(config.ini)、语言切换、用户登录、网络连接与心跳
- 启动扫描线程、系统时间线程、定时器
- 在退出时释放所有资源与线程
```mermaid
classDiagram
class CGeoMativeApp {
+InitInstance() bool
+ExitInstance() int
+PreTranslateMessage(pMsg) bool
+OnFileExit() void
+OnHelpAbout() void
+GetDBPasswordInfo() void
+GetPasswordPtr(map) void
+GetDevPassword(name, info) void
+OnCfgTerrain() void
+GetCfgUrl() bool
+Get2dDataExpStyle() int
-InitalDiagnosisInfo() void
-SetDBAttributeUpdateInfo() void
-ProcConPtrCloseExpect() void
-ParserSigCrossHole(index) bool
-GeCrossHoleCfg() bool
+m_pDevManager : CDevManager*
+m_pProManager : CProManager*
+m_pTdManager : CTdManager*
+m_pExecManager : CExecManager*
+m_pSptManager : CSptManager*
+m_pIOManager : CIOManager*
+m_pConnection : _ConnectionPtr
+m_pCatalog : _CatalogPtr
+m_NetWorkOper : CNetWorkOper
+m_uiUserID : UINT32
+m_ucIsMultiChannel : EN_CHANNEL_INFO
+m_mapCrossHole : map
}
class CDevManager
class CProManager
class CTdManager
class CExecManager
class CSptManager
class CIOManager
CGeoMativeApp --> CDevManager : "创建并持有"
CGeoMativeApp --> CProManager : "创建并持有"
CGeoMativeApp --> CTdManager : "创建并持有"
CGeoMativeApp --> CExecManager : "创建并持有"
CGeoMativeApp --> CSptManager : "创建并持有"
CGeoMativeApp --> CIOManager : "创建并持有"
```
图表来源
- [GeoMative.h](file://h/GeoMative.h#L115-L182)
- [DevManager.h](file://h/DevManager.h#L1-L69)
- [TdManager.h](file://h/TdManager.h#L1-L109)
- [ProManager.h](file://h/ProManager.h#L1-L77)
- [ExecManager.h](file://h/ExecManager.h#L1-L42)
## 详细组件分析
### CGeoMativeApp类与生命周期管理
- 构造与析构
- 构造函数初始化各管理器指针为空,清理计数器与路径等成员
- 析构函数负责释放数据库连接、主窗口、各管理器实例、菜单/加速键资源、COM/临界区等
- 初始化(InitInstance
- OLE初始化、控件容器启用、3D控件支持
- 设置注册表键、设置当前工作目录、创建CACHE目录结构
- 加载主框架窗口、显示最大化、初始化COM、清空跨孔配置映射
- 建立数据库连接(ADO/ADOX),设置锁数量上限
- 初始化网络(WSAStartup)、日志、诊断信息、跨孔配置
- 密码验证(数据库密码、几何密码)、系统时间线程、数据库升级
- 创建各管理器实例(Dev/Pro/Td/Exec/Spt/IO),读取config.ini配置(传输方式、用户ID、多通道、语言、时区等)
- 在线模式:登录对话框、心跳定时器、网络连接、设备通知注册、工作线程启动
- 离线/USB模式:设备扫描线程、设备链接初始化、MAC地址生成、扫描线程
- 资源清理与菜单刷新
- 退出(ExitInstance
- 注销网络回调、释放主窗口、管理器、关闭数据库连接、释放ADO/ADOX、停止扫描线程、反初始化COM、删除临界区、调用基类退出
```mermaid
sequenceDiagram
participant App as "CGeoMativeApp"
participant Frame as "主框架窗口"
participant DB as "数据库(ADO/ADOX)"
participant Net as "网络(CNetWorkOper)"
participant Th as "线程(扫描/系统时间)"
App->>App : 构造函数初始化
App->>App : InitInstance()
App->>App : OLE/控件容器初始化
App->>Frame : 创建并加载主框架
App->>App : 设置工作目录/CACHE目录
App->>DB : 建立连接/设置锁上限
App->>App : 日志/诊断/跨孔配置初始化
App->>App : 密码验证/系统时间线程
App->>App : 数据库升级
App->>App : 创建管理器实例
App->>App : 读取config.ini/语言切换
alt 在线模式
App->>Net : 初始化/连接/心跳/注册通知
else 离线/USB模式
App->>Th : 启动扫描线程
end
App-->>Frame : 显示并更新窗口
App->>App : ExitInstance()
App->>Th : 释放线程/临界区/COM
App->>DB : 关闭连接/释放ADO/ADOX
App->>Frame : 释放主窗口
App-->>App : 返回基类ExitInstance
```
图表来源
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L139-L210)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L211-L420)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L421-L642)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L644-L737)
章节来源
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L139-L210)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L211-L420)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L421-L642)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L644-L737)
### 全局变量与全局函数的作用
- 全局变量
- 系统语言、UI偏移、传输模式、UI语言、系统时间、扫描标志、MAC地址、设备序列号、PLC/设备ID、时区、在线传输开关、任务状态、时间戳等
- 设备链接表(aDevLinkTable[256])、扫描临界区(g_ScanTabSection)、系统时间(g_sysCurTime
- 全局函数
- 列表排序比较函数(ListStrCompare、SptListStrCompare
- 消息泵辅助(DoEvent
- 延迟与事件循环(TransDelay
- 字符串处理(SplitterString、StatStringCount、GetSubStringInHeadAndTail
- 数学与信号处理(多项式拟合、积分、二分法求根)
- 状态文本与编码转换(GetGRStatus、GetGrCodeText、U2G/G2U
- 时间转换(Tm2GmtStr/Tm2LocalStr、Str2GmtTm/Str2LocalTm
- 网络序转换(tcp_htonf/tcp_ntohf
- 在线任务状态文本(OnLineLocalTaskState/OnLineTask
- 测试失败原因文本(GetTestFailedReason
- 设备枚举(DeviceEnumCommPort
- 扫描线程入口(DevLinkScanThreadFunction
- 系统时间线程入口(GetSysTimeFunction
- 错误钩子(CBTHookProc
这些全局变量与函数贯穿于设备扫描、网络通信、UI交互、数据处理等模块,确保模块间共享状态与工具能力。
章节来源
- [Global.cpp](file://cpp/Main/Global.cpp#L20-L120)
- [Global.cpp](file://cpp/Main/Global.cpp#L120-L320)
- [Global.cpp](file://cpp/Main/Global.cpp#L320-L600)
- [Global.cpp](file://cpp/Main/Global.cpp#L600-L1000)
- [Global.cpp](file://cpp/Main/Global.cpp#L1000-L1539)
### 管理器创建与依赖关系
- 管理器创建顺序与注入
- 数据库连接(m_pConnection)与目录(m_pCatalog)在InitInstance中建立
- 管理器构造函数均接收_connection指针,确保所有管理器共享同一数据库上下文
- 管理器职责概览
- CDevManager:设备发现、在线/离线设备管理、远程设备集合维护
- CProManager:工程/测区管理、DMS树构建与同步、默认测区创建
- CTdManager:测试数据导入/导出、在线同步、2D/3D转换
- CExecManager:测试执行流程控制(2D/CE电阻率测试)
- CSptManager:脚本管理(2D/3D/CE
- CIOManagerIO与外部接口(含数据库与Catalog)
- 依赖关系
- CGeoMativeApp持有各管理器指针,负责创建与销毁
- 各管理器内部持有_connection指针,避免重复连接
- 网络层(CNetWorkOper)与扫描线程(DevLinkScanThreadFunction)通过CGeoMativeApp间接协作
```mermaid
flowchart TD
Start(["InitInstance入口"]) --> DBInit["建立数据库连接<br/>ADO/ADOX"]
DBInit --> CreateMgrs["创建管理器实例<br/>Dev/Pro/Td/Exec/Spt/IO"]
CreateMgrs --> ConfigRead["读取config.ini<br/>传输方式/用户ID/语言/时区"]
ConfigRead --> OnlineCheck{"在线模式?"}
OnlineCheck --> |是| NetInit["网络初始化/连接/心跳/注册"]
OnlineCheck --> |否| ScanThread["启动扫描线程"]
NetInit --> SysTime["启动系统时间线程"]
ScanThread --> SysTime
SysTime --> Done(["初始化完成"])
```
图表来源
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L421-L642)
- [DevManager.h](file://h/DevManager.h#L1-L69)
- [ProManager.h](file://h/ProManager.h#L1-L77)
- [TdManager.h](file://h/TdManager.h#L1-L109)
- [ExecManager.h](file://h/ExecManager.h#L1-L42)
章节来源
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L421-L642)
- [DevManager.h](file://h/DevManager.h#L1-L69)
- [ProManager.h](file://h/ProManager.h#L1-L77)
- [TdManager.h](file://h/TdManager.h#L1-L109)
- [ExecManager.h](file://h/ExecManager.h#L1-L42)
### AfxGetApp()的应用与模块间调用模式
- theApp全局实例
- Global.cpp中声明并定义CGeoMativeApp theApp,供全工程使用
- 各模块通过extern声明theApp,从而在任意位置访问CGeoMativeApp实例
- AfxGetApp()调用模式
- 在扫描线程入口DevLinkScanThreadFunction中,通过AfxGetApp()->GetMainWnd()向主窗口发送WM_NEWLINK/WM_DETECT_LINE消息
- 在线任务状态文本函数OnLineLocalTaskState/OnLineTask中,根据UI语言选择中文或英文提示
- 调用链示意
```mermaid
sequenceDiagram
participant Thread as "扫描线程"
participant App as "CGeoMativeApp"
participant MainWnd as "主窗口"
participant Handlers as "消息处理器"
Thread->>App : AfxGetApp()
App-->>Thread : 返回theApp实例
Thread->>App : GetMainWnd()
App-->>Thread : 返回主窗口指针
Thread->>MainWnd : SendMessage(WM_NEWLINK/WM_DETECT_LINE)
MainWnd->>Handlers : 分发消息并处理
```
图表来源
- [Global.cpp](file://cpp/Main/Global.cpp#L1000-L1166)
- [Global.cpp](file://cpp/Main/Global.cpp#L20-L30)
章节来源
- [Global.cpp](file://cpp/Main/Global.cpp#L20-L30)
- [Global.cpp](file://cpp/Main/Global.cpp#L1000-L1166)
## 依赖关系分析
- 组件耦合
- CGeoMativeApp与各管理器之间为“聚合”关系,通过指针持有,便于解耦与独立扩展
- 管理器之间无直接依赖,通过CGeoMativeApp协调,降低环状依赖风险
- 外部依赖
- 数据库:ADO/ADOX连接与事务
- 网络:CNetWorkOper封装的网络操作与线程
- 系统服务:COM初始化/反初始化、线程与临界区、文件系统(CACHE目录)
- 潜在循环依赖
- 通过全局theApp与AfxGetApp()访问主类,避免了管理器对主类的直接包含,降低循环依赖概率
```mermaid
graph LR
App["CGeoMativeApp"] --> DevMgr["CDevManager"]
App --> ProMgr["CProManager"]
App --> TdMgr["CTdManager"]
App --> ExecMgr["CExecManager"]
App --> SptMgr["CSptManager"]
App --> IOMgr["CIOManager"]
App --> Net["CNetWorkOper"]
App --> DB["ADO/ADOX 连接"]
```
图表来源
- [GeoMative.h](file://h/GeoMative.h#L115-L182)
- [DevManager.h](file://h/DevManager.h#L1-L69)
- [ProManager.h](file://h/ProManager.h#L1-L77)
- [TdManager.h](file://h/TdManager.h#L1-L109)
- [ExecManager.h](file://h/ExecManager.h#L1-L42)
章节来源
- [GeoMative.h](file://h/GeoMative.h#L115-L182)
- [DevManager.h](file://h/DevManager.h#L1-L69)
- [ProManager.h](file://h/ProManager.h#L1-L77)
- [TdManager.h](file://h/TdManager.h#L1-L109)
- [ExecManager.h](file://h/ExecManager.h#L1-L42)
## 性能考量
- 数据库连接与锁
- 初始化时设置最大锁数量,避免高并发下的锁竞争
- 线程与临界区
- 设备扫描线程与系统时间线程分离,扫描线程使用临界区保护共享表
- 网络与心跳
- 在线模式下启用心跳定时器与网络工作线程,需注意线程安全与异常恢复
- 文件系统
- 启动阶段创建CACHE目录与子目录,避免运行期频繁创建导致的性能抖动
[本节为通用指导,无需具体文件分析]
## 故障排查指南
- 数据库连接失败
- 现象:InitInstance中捕获_com_error并提示连接失败
- 排查:确认ACCDB路径、密码、Jet OLEDB驱动安装情况
- 网络初始化失败
- 现象:WSAStartup失败或网络连接失败
- 排查:检查IP/端口配置、防火墙、网络连通性
- 扫描线程创建失败
- 现象:创建扫描线程失败或无法发现设备
- 排查:检查传输模式、USB/GD设备状态、权限与驱动
- 退出异常
- 现象:ExitInstance中关闭连接抛出异常
- 排查:查看错误钩子与日志,确保线程安全关闭与资源释放顺序
章节来源
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L293-L310)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L311-L320)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L578-L622)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L644-L737)
- [Global.cpp](file://cpp/Main/Global.cpp#L1168-L1181)
## 结论
CGeoMativeApp作为GeomativeStudio的主入口,承担了完整的应用生命周期管理职责。通过清晰的初始化流程、严格的资源管理与模块化设计,实现了数据库、网络、设备扫描、UI交互等功能的有序协同。全局变量与函数为跨模块共享提供了基础,而theApp/AfxGetApp()的使用模式确保了模块间松耦合与可维护性。建议在后续演进中持续关注线程安全、异常恢复与性能优化,以提升整体稳定性与用户体验。
@@ -0,0 +1,419 @@
# DevManager
<cite>
**本文档中引用的文件**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [DevManager.h](file://h/DevManager.h)
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
- [DetcGD10Dev.h](file://h/DetcGD10Dev.h)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
- [Device.h](file://h/Device.h)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp)
- [SComPort.h](file://h/SComPort.h)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp)
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp)
- [checkupdate.h](file://h/checkupdate.h)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
</cite>
## 目录
1. [介绍](#介绍)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 介绍
DevManager模块是Geomative Studio系统中的核心组件,负责管理与GD10设备的连接、状态监控、参数配置和固件升级。该模块通过串口与GD10设备通信,使用DetcGD10Dev类进行设备检测,以及Device类对设备状态进行封装。DevManager与其他管理器(如ProManager、TdManager)协同工作,确保设备连接成功后能够同步项目信息和测量数据。本文档将详细说明DevManager的职责和实现,提供设备连接失败、通信超时等常见问题的解决方案,并分析其与其他管理器的数据交互流程。
## 项目结构
DevManager模块位于`cpp/Managers/`目录下,主要由`DevManager.cpp``DevManager.h`文件组成。该模块依赖于`Operator`目录下的`DetcGD10Dev.cpp``Device.cpp`文件,以及`Tools`目录下的`SComPort.cpp``GD10OperCmd.cpp`文件。`DetcGD10Dev`类负责检测GD10设备的连接状态,`Device`类封装了设备的状态和操作,`SComPort`类提供了串口通信功能,而`GD10OperCmd`类则处理与GD10设备的命令交互。
```mermaid
graph TD
subgraph "Managers"
DevManager[DevManager.cpp/h]
ProManager[ProManager.cpp/h]
TdManager[TdManager.cpp/h]
end
subgraph "Operator"
DetcGD10Dev[DetcGD10Dev.cpp/h]
Device[Device.cpp/h]
end
subgraph "Tools"
SComPort[SComPort.cpp/h]
GD10OperCmd[GD10OperCmd.cpp/h]
checkupdate[checkupdate.cpp/h]
end
DevManager --> DetcGD10Dev
DevManager --> Device
DevManager --> SComPort
DevManager --> GD10OperCmd
DevManager --> ProManager
DevManager --> TdManager
```
**图源**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L1-L661)
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L1-L189)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L1-L3893)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L1-L1199)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L1-L1213)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1-L2054)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L1-L6839)
## 核心组件
DevManager模块的核心组件包括`CDevManager`类、`CDetcGD10Dev`类和`CDevice`类。`CDevManager`类负责管理设备的生命周期,包括设备的添加、删除、状态更新等操作。`CDetcGD10Dev`类用于检测GD10设备的连接状态,`CDevice`类则封装了设备的状态和操作。
**组件源**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L1-L661)
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L1-L189)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L1-L3893)
## 架构概述
DevManager模块的架构设计遵循分层原则,将设备管理、通信、状态监控等功能分离。`CDevManager`类作为顶层管理器,负责协调各个子组件的工作。`CDetcGD10Dev`类负责设备检测,`CDevice`类负责设备状态的封装和操作,`SComPort`类提供串口通信功能,`GD10OperCmd`类处理与GD10设备的命令交互。
```mermaid
classDiagram
class CDevManager {
+InitialDevLinkList()
+AddDevice(CDevice* const pDev)
+DeleteDevice(DWORD dwHandle)
+GetDeviceByID(DWORD dwDevID)
+GetDevice(DWORD dwHandle)
+GetDevice(CString szDevSN)
+GetRegisterDevice(CString szDevSN, bool &bIsRegister)
+GetOLDevList(CPtrArray *pOLDevList)
+GetFLDevList(CPtrArray* pFLDevList)
+UpdateDevInfo(STSynDevParam stDevParam, BYTE bRemoteDeveTyp)
+SetDeviceHandle(CDevice* const pDev)
+DeleteObjInMem(DWORD dwHandle)
+DeleteObjInMem(CString szDevSN)
+AddObjInMem(CString szDevSN)
+AddOfflineObjInMem(CString szDevSN)
+DeleteDevice(CString strDev)
+AddRemoteDevice(STSigRemoteDev stDevice)
+DeleteRemoteDevice(STSigRemoteDev stDevice)
+GetRemoteDeviceInfo()
}
class CDetcGD10Dev {
+GetInstance()
+DetectGD10Dev()
+GetGD10DevAddr()
+IsGD10DevConnect()
+FindUsbDevice(CString strDevName)
+CompareDriverName(CString strDriName, CString strDriverAddr)
+PrintLog(CString strLog)
}
class CDevice {
+CDevice(DWORD dwID, _ConnectionPtr& pConnection)
+~CDevice()
+Reset()
+ShowFLDetailInfo(CListCtrl &devDetailList)
+ShowOLDetailInfo(CListCtrl& devDetailList)
+ShowGRInfo(CListCtrl& devGRList)
+ShowACInfo(CListCtrl& devDetailList)
+ShowCableHeadInfoDlg()
+ReceiveFile(const CString &szLocFilePath, const CString& szHostFileName, int nRetryCnt)
+SendFile(const CString &szHostFilePath, const CString &szLocFilePath, const CString& szLocFileName)
+ExecuteOrder(CString strOrder, CString strSign, CString *pStrResult, int nRepeatCnt, int nPollCnt)
+ExecuteSignleOrder(CString f_szOrder, CString f_szSign, CString *f_szResult, int nCmdPollCnt)
+ModifyTimeWindow()
+LockDevice()
+GetSynInfo()
+GetDevInfo()
+GetGRInfo()
+GetPoleCount()
+Register()
+Unregister()
+ModifyParameter()
+TestGRForPerPole(int iSN, CStringArray& strResArray)
+TestGRForAllPole()
+SetState(UINT uState)
+SetID(DWORD dwID)
+PrintLog(CString& strLog)
+IsExistOtherUserData()
+CheckGD10Password(CString strGD10Password)
+EndTransfer()
}
class CSComPort {
+OpenComm(CString szComName)
+CloseComm()
+SendDataDirectly(char *pDataBuff, int iDataSize)
+ReceiveDataDirectly(char *pDataBuff, int* iDataSize)
+ZmodemReceiveDataDirectly(char *pDataBuff, int *iDataSize)
+ZmodemSendDataDirectly(char *pDataBuff, int iDataSize)
+ExecuteOrder(CString strOrder, CString strSign, CString *pStrResult, int nRepeatCnt)
+ExecuteSignleOrder(CString f_szOrder, CString f_szSign, CString *f_szResult)
+ExecuteNoResOrder(CString f_szOrder)
+ClearCommReceiveBuff()
+ClearCommSendBuff()
+SetScanBreakSign(BOOL bIsScanBreak)
+DetectLine()
+SetOwnerWnd(HWND hOwnerWnd)
+SetCommID(long lCommID)
+SComPortDetectBreakThreadFun(LPVOID pParam)
+FindComName(CStringArray* pStringArray)
}
class CGD10OperCmd {
+GetInstance()
+project_add(const char *mac, const char *projectcn)
+AddProjectInLocalHost(const char *pProjectCN)
+AddProjectInMacXml(const char* pMac, const char *pProjectCN)
+project_del(const char *mac, const char *projectcn)
+project_rename(const char *mac, const char *old_projectcn, const char *new_projectcn)
+tz_add(const char *mac, const char *projectcn, const char *tzcn)
+tz_del(const char *mac, const char *projectcn, const char *tzcn)
+tz_rename(const char *mac, const char *projectcn, const char *old_tzcn, const char *new_tzcn)
+task_add(const char *mac, const char *projectcn, const char *tzcn, const char *taskcn)
+task_del(const char *mac, const char *projectcn, const char *tzcn, const char *taskcn)
+task_rename(const char *mac, const char *projectcn, const char *tzcn, const char *old_taskcn, const char *new_taskcn)
+sync_project(const char *mac, const char *projectcn)
+sync_tz(const char *mac, const char *projectcn, const char *tzcn)
+sync_task(const char *mac, const char *projectcn, const char *tzcn, const char *taskcn)
+sync_all(const char *mac)
+get_project_list(const char *mac, CStringArray &project_list)
+get_tz_list(const char *mac, const char *projectcn, CStringArray &tz_list)
+get_task_list(const char *mac, const char *projectcn, const char *tzcn, CStringArray &task_list)
+get_sync_status(const char *mac, const char *projectcn, const char *tzcn, const char *taskcn)
+get_device_info(const char *mac, STSynDevParam &dev_info)
+get_gr_info(const char *mac, CStringArray &gr_info)
+get_ac_info(const char *mac, CStringArray &ac_info)
+get_cable_head_info(const char *mac, CStringArray &cable_head_info)
+get_time_info(const char *mac, SYSTEMTIME &time_info)
+set_time_info(const char *mac, SYSTEMTIME &time_info)
+get_parameter_info(const char *mac, STParameterInfo &param_info)
+set_parameter_info(const char *mac, STParameterInfo &param_info)
+get_firmware_version(const char *mac, CString &version)
+upgrade_firmware(const char *mac, const char *firmware_path)
+reset_device(const char *mac)
+lock_device(const char *mac)
+unlock_device(const char *mac)
+get_battery_info(const char *mac, float &battery_vol, int &battery_alarm)
+get_signal_info(const char *mac, int &signal_strength)
+get_network_info(const char *mac, CString &network_status)
+get_storage_info(const char *mac, int &total_space, int &used_space)
+get_temperature_info(const char *mac, float &temperature)
+get_humidity_info(const char *mac, float &humidity)
+get_pressure_info(const char *mac, float &pressure)
+get_gps_info(const char *mac, double &latitude, double &longitude, double &altitude)
+get_accelerometer_info(const char *mac, float &x, float &y, float &z)
+get_gyroscope_info(const char *mac, float &x, float &y, float &z)
+get_magnetometer_info(const char *mac, float &x, float &y, float &z)
+get_barometer_info(const char *mac, float &pressure)
+get_light_sensor_info(const char *mac, float &light_level)
+get_proximity_sensor_info(const char *mac, float &proximity)
+get_ambient_temperature_info(const char *mac, float &temperature)
+get_relative_humidity_info(const char *mac, float &humidity)
+get_air_quality_info(const char *mac, int &air_quality)
+get_noise_level_info(const char *mac, float &noise_level)
+get_vibration_info(const char *mac, float &vibration)
+get_motion_info(const char *mac, float &motion)
+get_orientation_info(const char *mac, float &orientation)
+get_rotation_info(const char *mac, float &rotation)
+get_acceleration_info(const char *mac, float &acceleration)
+get_velocity_info(const char *mac, float &velocity)
+get_distance_info(const char *mac, float &distance)
+get_speed_info(const char *mac, float &speed)
+get_direction_info(const char *mac, float &direction)
+get_altitude_info(const char *mac, float &altitude)
+get_pressure_info(const char *mac, float &pressure)
+get_temperature_info(const char *mac, float &temperature)
+get_humidity_info(const char *mac, float &humidity)
+get_light_level_info(const char *mac, float &light_level)
+get_proximity_info(const char *mac, float &proximity)
+get_ambient_temperature_info(const char *mac, float &temperature)
+get_relative_humidity_info(const char *mac, float &humidity)
+get_air_quality_info(const char *mac, int &air_quality)
+get_noise_level_info(const char *mac, float &noise_level)
+get_vibration_info(const char *mac, float &vibration)
+get_motion_info(const char *mac, float &motion)
+get_orientation_info(const char *mac, float &orientation)
+get_rotation_info(const char *mac, float &rotation)
+get_acceleration_info(const char *mac, float &acceleration)
+get_velocity_info(const char *mac, float &velocity)
+get_distance_info(const char *mac, float &distance)
+get_speed_info(const char *mac, float &speed)
+get_direction_info(const char *mac, float &direction)
+get_altitude_info(const char *mac, float &altitude)
}
CDevManager --> CDetcGD10Dev
CDevManager --> CDevice
CDevManager --> CSComPort
CDevManager --> CGD10OperCmd
CDevice --> CSComPort
CDevice --> CGD10OperCmd
```
**图源**
- [DevManager.h](file://h/DevManager.h#L1-L69)
- [DetcGD10Dev.h](file://h/DetcGD10Dev.h#L1-L38)
- [Device.h](file://h/Device.h#L1-L128)
- [SComPort.h](file://h/SComPort.h#L1-L74)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L1-L1213)
## 详细组件分析
### DevManager分析
`CDevManager`类是设备管理的核心,负责管理所有设备的生命周期。它通过`InitialDevLinkList`方法初始化设备列表,从数据库中读取设备信息并创建`CDevice`对象。`AddDevice`方法用于添加新设备,`DeleteDevice`方法用于删除设备。`GetDeviceByID``GetDevice``GetDevice`方法用于根据不同的标识符获取设备对象。`GetOLDevList``GetFLDevList`方法分别获取在线和离线设备列表。`UpdateDevInfo`方法用于更新设备信息,`SetDeviceHandle`方法用于设置设备句柄。
#### 设备初始化和状态轮询
设备初始化和状态轮询是DevManager模块的重要功能。设备初始化通过`InitialDevLinkList`方法完成,该方法从数据库中读取设备信息并创建`CDevice`对象。状态轮询通过`GetOLDevList``GetFLDevList`方法实现,定期检查设备的连接状态并更新设备列表。
```mermaid
sequenceDiagram
participant DevManager as "DevManager"
participant Database as "数据库"
participant Device as "Device"
DevManager->>Database : 查询设备信息
Database-->>DevManager : 返回设备信息
DevManager->>Device : 创建CDevice对象
Device-->>DevManager : 返回设备对象
DevManager->>DevManager : 更新设备列表
```
**图源**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L160-L201)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L486-L590)
### DetcGD10Dev分析
`CDetcGD10Dev`类负责检测GD10设备的连接状态。`DetectGD10Dev`方法通过调用`FindUsbDevice`方法查找USB设备,`GetGD10DevAddr`方法返回设备的地址,`IsGD10DevConnect`方法返回设备是否已连接。
#### 设备检测流程
设备检测流程通过`DetectGD10Dev`方法实现,该方法首先清空设备地址,然后调用`FindUsbDevice`方法查找USB设备。如果找到设备,`m_strDevAddr`将被设置为设备地址,`m_bGD10DevIsCon`将被设置为`true`
```mermaid
flowchart TD
Start([开始]) --> DetectDevice["DetectGD10Dev()"]
DetectDevice --> ClearAddr["清空设备地址"]
ClearAddr --> FindDevice["FindUsbDevice(strDevName)"]
FindDevice --> CheckResult{"找到设备?"}
CheckResult --> |是| SetAddr["设置设备地址"]
SetAddr --> SetConnected["设置连接状态为true"]
SetConnected --> End([结束])
CheckResult --> |否| SetDisconnected["设置连接状态为false"]
SetDisconnected --> End
```
**图源**
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L61-L68)
### Device分析
`CDevice`类封装了设备的状态和操作。`CDevice`类的构造函数接收设备ID和数据库连接指针,初始化设备对象。`Reset`方法用于重置设备,`ShowFLDetailInfo``ShowOLDetailInfo`方法用于显示设备的详细信息,`ShowGRInfo``ShowACInfo`方法用于显示接地电阻和视极化率信息。`ReceiveFile``SendFile`方法用于文件传输,`ExecuteOrder``ExecuteSignleOrder`方法用于执行命令。
#### 文件传输流程
文件传输流程通过`ReceiveFile``SendFile`方法实现。`ReceiveFile`方法接收文件,`SendFile`方法发送文件。文件传输过程中,`CProgressDlg`对话框用于显示传输进度。
```mermaid
sequenceDiagram
participant Device as "Device"
participant ProgressDlg as "CProgressDlg"
participant SComPort as "SComPort"
Device->>ProgressDlg : 创建CProgressDlg对象
ProgressDlg->>Device : 返回对话框对象
Device->>ProgressDlg : 设置设备、传输类型、文件路径
ProgressDlg->>Device : 显示对话框
Device->>SComPort : 发送文件传输命令
SComPort-->>Device : 返回传输结果
Device->>ProgressDlg : 更新传输进度
ProgressDlg-->>Device : 传输完成
Device->>ProgressDlg : 销毁对话框对象
```
**图源**
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L682-L725)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L59-L66)
### 与其他管理器的数据交互
DevManager模块与其他管理器(如ProManager、TdManager)协同工作,确保设备连接成功后能够同步项目信息和测量数据。`ProManager`类负责管理项目信息,`TdManager`类负责管理测量数据。
#### 项目信息同步
项目信息同步通过`ProManager`类的`ShowProList`方法实现。当设备连接成功后,`ProManager`会从数据库中读取项目信息,并将其同步到设备上。
```mermaid
sequenceDiagram
participant DevManager as "DevManager"
participant ProManager as "ProManager"
participant Database as "数据库"
DevManager->>ProManager : 请求项目列表
ProManager->>Database : 查询项目信息
Database-->>ProManager : 返回项目信息
ProManager-->>DevManager : 返回项目列表
DevManager->>Device : 同步项目信息
```
**图源**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L184-L200)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L592-L642)
#### 测量数据同步
测量数据同步通过`TdManager`类的`ShowTdListByProject`方法实现。当设备连接成功后,`TdManager`会从数据库中读取测量数据,并将其同步到设备上。
```mermaid
sequenceDiagram
participant DevManager as "DevManager"
participant TdManager as "TdManager"
participant Database as "数据库"
DevManager->>TdManager : 请求测量数据列表
TdManager->>Database : 查询测量数据信息
Database-->>TdManager : 返回测量数据信息
TdManager-->>DevManager : 返回测量数据列表
DevManager->>Device : 同步测量数据
```
**图源**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L81-L200)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L592-L642)
## 依赖分析
DevManager模块依赖于多个其他模块,包括`DetcGD10Dev``Device``SComPort``GD10OperCmd``ProManager``TdManager`。这些模块共同协作,确保设备管理功能的正常运行。
```mermaid
graph TD
DevManager[DevManager] --> DetcGD10Dev[DetcGD10Dev]
DevManager --> Device[Device]
DevManager --> SComPort[SComPort]
DevManager --> GD10OperCmd[GD10OperCmd]
DevManager --> ProManager[ProManager]
DevManager --> TdManager[TdManager]
DetcGD10Dev --> SComPort
Device --> SComPort
Device --> GD10OperCmd
ProManager --> Database[(数据库)]
TdManager --> Database
```
**图源**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L1-L661)
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L1-L189)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L1-L3893)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L1-L1199)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L1-L1213)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1-L2054)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L1-L6839)
## 性能考虑
DevManager模块在设计时考虑了性能优化。例如,`InitialDevLinkList`方法在初始化设备列表时,会从数据库中批量读取设备信息,减少数据库查询次数。`GetOLDevList``GetFLDevList`方法在获取设备列表时,会缓存设备信息,减少重复查询。此外,`CDevice`类的`ExecuteOrder``ExecuteSignleOrder`方法支持重试机制,确保命令执行的可靠性。
## 故障排除指南
### 设备连接失败
设备连接失败可能是由于USB线缆问题、设备驱动问题或设备未正确连接。解决方法包括检查USB线缆、重新安装设备驱动、重新连接设备。
### 通信超时
通信超时可能是由于串口配置错误、设备响应慢或网络问题。解决方法包括检查串口配置、增加超时时间、检查网络连接。
### 文件传输失败
文件传输失败可能是由于文件路径错误、存储空间不足或设备忙。解决方法包括检查文件路径、清理存储空间、等待设备空闲。
**组件源**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L383-L433)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L682-L725)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L127-L187)
## 结论
DevManager模块是Geomative Studio系统中的核心组件,负责管理与GD10设备的连接、状态监控、参数配置和固件升级。通过详细的分析,我们了解了DevManager模块的职责和实现,包括设备初始化、状态轮询、文件传输、与其他管理器的数据交互等。此外,我们还提供了设备连接失败、通信超时等常见问题的解决方案。DevManager模块的设计考虑了性能优化,确保了系统的高效运行。未来的工作可以进一步优化设备管理功能,提高系统的稳定性和用户体验。
@@ -0,0 +1,278 @@
# IOManager
<cite>
**本文档引用的文件**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [IOManager.h](file://h/IOManager.h)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [DataOperator.h](file://h/DataOperator.h)
- [excel.cpp](file://cpp/Tools/excel.cpp)
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
- [OperTxtFile.h](file://h/OperTxtFile.h)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
- [OperUrfFile.h](file://h/OperUrfFile.h)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 简介
IOManager模块是Geomative Studio项目中的核心组件,负责处理数据的导入导出功能。该模块支持多种文件格式,包括Excel、CSV、TXT和URF等,能够协调DataOperator进行数据格式转换,并利用excel.cpp、OperTxtFile.cpp、OperUrfFile.cpp等工具类实现具体的文件读写操作。此外,IOManager还负责文件传输过程中的进度监控和错误处理机制,确保数据传输的可靠性和完整性。
## 项目结构
IOManager模块位于`cpp/Managers/`目录下,主要由`IOManager.cpp``IOManager.h`两个文件组成。该模块依赖于`DataOperator`类进行数据操作,并通过`excel.cpp``OperTxtFile.cpp``OperUrfFile.cpp`等工具类实现具体的文件读写功能。`DataOperator`类位于`cpp/Operator/`目录下,而工具类则位于`cpp/Tools/`目录下。
```mermaid
graph TD
subgraph "IOManager模块"
IOManager[IOManager]
DataOperator[DataOperator]
end
subgraph "工具类"
Excel[excel.cpp]
OperTxtFile[OperTxtFile.cpp]
OperUrfFile[OperUrfFile.cpp]
end
IOManager --> DataOperator
DataOperator --> Excel
DataOperator --> OperTxtFile
DataOperator --> OperUrfFile
```
**Diagram sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [excel.cpp](file://cpp/Tools/excel.cpp)
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [IOManager.h](file://h/IOManager.h)
## 核心组件
IOManager模块的核心功能包括数据的导入导出、格式转换、文件读写以及进度监控和错误处理。该模块通过调用`DataOperator`类的方法来执行具体的数据操作,并利用`excel.cpp``OperTxtFile.cpp``OperUrfFile.cpp`等工具类来实现不同格式的文件读写。
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
## 架构概述
IOManager模块的架构设计遵循了分层原则,将数据操作与文件读写分离,提高了代码的可维护性和可扩展性。`IOManager`类负责协调整个数据导入导出流程,`DataOperator`类负责具体的数据操作,而`excel.cpp``OperTxtFile.cpp``OperUrfFile.cpp`等工具类则负责具体的文件读写操作。
```mermaid
graph TD
IOManager[IOManager] --> DataOperator[DataOperator]
DataOperator --> Excel[excel.cpp]
DataOperator --> OperTxtFile[OperTxtFile.cpp]
DataOperator --> OperUrfFile[OperUrfFile.cpp]
```
**Diagram sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [excel.cpp](file://cpp/Tools/excel.cpp)
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
## 详细组件分析
### IOManager分析
`IOManager`类的主要职责是协调数据的导入导出流程。它通过调用`DataOperator`类的方法来执行具体的数据操作,并利用`excel.cpp``OperTxtFile.cpp``OperUrfFile.cpp`等工具类来实现不同格式的文件读写。
#### 类图
```mermaid
classDiagram
class IOManager {
+Export()
+Import()
-CreateExpDatabase()
-ExportDataToAccdbFile()
-ImportProjectToDB()
-ImportTzToDB()
-ImportSptToDB()
-ImportRspTdToDB()
-ImportIpspTdToDB()
}
class DataOperator {
+ExportRsp2DTdToExcel()
+ExportRsp2DTdToCSV()
+ExportRsp2DTdToUrf()
+ExportRsp2DTdToTxt()
+ExportRspCETdToExcel()
+ExportRspCETdToCSV()
+ExportRspCETdToUrf()
+ExportRspCETdToTxt()
+ExportIpCETdToExcel()
+ExportIpCETdToCSV()
+ExportIpCETdToTxt()
+ExportIp2DTdToExcel()
+ExportIp2DTdToCSV()
+ExportIp2DTdToTxt()
+ExportSPCETdToExcel()
+ExportSPCETdToCSV()
+ExportSPCETdToTxt()
+ExportSP2DTdToExcel()
+ExportSP2DTdToCSV()
+ExportSP2DTdToTxt()
}
class excel {
+_Application
+_Workbook
+_Worksheet
}
class OperTxtFile {
+OpenFileforWrite()
+CloseFile()
+SetParamWidth()
+WriteFileContent()
+WriteEmptyRow()
}
class OperUrfFile {
+OpenUrfFileForWrite()
+WriteUrfHeadInfo()
+Write3DUrfHeadInfo()
+WriteUrfPoleInfo()
+WriteUrfDataInfo()
+CloseFile()
+WriteElecByWenSch()
+WriteElecByWenSch_AMN()
+WriteElecByWenSch_MNB()
+WriteElecByWenSch_AM()
+WriteElecByCrossHole()
+WriteElecByCrossHoleGeomative()
+WriteElecByCrossHoleGeomativeAM()
+WriteElecByAR()
+WriteUrfPoleInfo()
}
IOManager --> DataOperator
DataOperator --> excel
DataOperator --> OperTxtFile
DataOperator --> OperUrfFile
```
**Diagram sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [excel.cpp](file://cpp/Tools/excel.cpp)
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [IOManager.h](file://h/IOManager.h)
### DataOperator分析
`DataOperator`类负责具体的数据操作,包括数据的导出和导入。它提供了多种方法来导出不同格式的数据,如Excel、CSV、TXT和URF等。
#### 序列图
```mermaid
sequenceDiagram
participant IOManager as "IOManager"
participant DataOperator as "DataOperator"
participant Excel as "excel.cpp"
participant OperTxtFile as "OperTxtFile.cpp"
participant OperUrfFile as "OperUrfFile.cpp"
IOManager->>DataOperator : ExportRsp2DTdToExcel()
DataOperator->>Excel : SaveTdToExcelFile()
Excel-->>DataOperator : 返回结果
DataOperator-->>IOManager : 返回结果
IOManager->>DataOperator : ExportRsp2DTdToCSV()
DataOperator->>DataOperator : SaveTdToCsvFile()
DataOperator-->>IOManager : 返回结果
IOManager->>DataOperator : ExportRsp2DTdToUrf()
DataOperator->>OperUrfFile : ExportDataToUrf()
OperUrfFile-->>DataOperator : 返回结果
DataOperator-->>IOManager : 返回结果
IOManager->>DataOperator : ExportRsp2DTdToTxt()
DataOperator->>OperTxtFile : ExportResDataToTxt()
OperTxtFile-->>DataOperator : 返回结果
DataOperator-->>IOManager : 返回结果
```
**Diagram sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [excel.cpp](file://cpp/Tools/excel.cpp)
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
**Section sources**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [DataOperator.h](file://h/DataOperator.h)
### 工具类分析
`excel.cpp``OperTxtFile.cpp``OperUrfFile.cpp`等工具类负责具体的文件读写操作。这些类提供了丰富的API来支持不同格式的文件读写。
#### 流程图
```mermaid
flowchart TD
Start([开始]) --> ValidateInput["验证输入参数"]
ValidateInput --> InputValid{"输入有效?"}
InputValid --> |否| ReturnError["返回错误响应"]
InputValid --> |是| CheckCache["检查缓存"]
CheckCache --> CacheHit{"缓存命中?"}
CacheHit --> |是| ReturnCache["返回缓存数据"]
CacheHit --> |否| QueryDB["查询数据库"]
QueryDB --> DBResult{"查询成功?"}
DBResult --> |否| HandleError["处理数据库错误"]
DBResult --> |是| ProcessData["处理原始数据"]
ProcessData --> UpdateCache["更新缓存"]
UpdateCache --> ReturnResult["返回处理结果"]
HandleError --> ReturnError
ReturnCache --> End([结束])
ReturnResult --> End
ReturnError --> End
```
**Diagram sources**
- [excel.cpp](file://cpp/Tools/excel.cpp)
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
**Section sources**
- [excel.cpp](file://cpp/Tools/excel.cpp)
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
## 依赖分析
IOManager模块依赖于`DataOperator`类进行数据操作,并通过`excel.cpp``OperTxtFile.cpp``OperUrfFile.cpp`等工具类实现具体的文件读写操作。这些依赖关系确保了模块的高内聚和低耦合,提高了代码的可维护性和可扩展性。
```mermaid
graph TD
IOManager[IOManager] --> DataOperator[DataOperator]
DataOperator --> Excel[excel.cpp]
DataOperator --> OperTxtFile[OperTxtFile.cpp]
DataOperator --> OperUrfFile[OperUrfFile.cpp]
```
**Diagram sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [excel.cpp](file://cpp/Tools/excel.cpp)
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
## 性能考虑
IOManager模块在设计时充分考虑了性能因素。通过使用高效的文件读写操作和缓存机制,确保了数据传输的高效性。此外,模块还支持批量导出功能,进一步提高了数据处理的效率。
## 故障排除指南
在使用IOManager模块时,可能会遇到文件编码错误或格式不兼容的问题。为了解决这些问题,建议检查文件的编码格式,并确保文件格式与目标系统兼容。如果问题仍然存在,可以尝试使用不同的文件格式或编码方式。
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
## 结论
IOManager模块是Geomative Studio项目中的关键组件,负责处理数据的导入导出功能。通过协调`DataOperator`类和利用`excel.cpp``OperTxtFile.cpp``OperUrfFile.cpp`等工具类,该模块实现了对多种文件格式的支持,并确保了数据传输的可靠性和完整性。未来的工作可以进一步优化性能,提高用户体验。
@@ -0,0 +1,84 @@
# Managers模块
<cite>
**Referenced Files in This Document**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [ExecManager.cpp](file://cpp/Managers/ExecManager.cpp)
- [PasswordMng.cpp](file://cpp/Managers/PasswordMng.cpp)
- [TestManager.cpp](file://cpp/Managers/TestManager.cpp)
</cite>
## 目录
1. [DevManager职责与实现](#devmanager职责与实现)
2. [ProManager职责与实现](#promanager职责与实现)
3. [SptManager职责与实现](#sptmanager职责与实现)
4. [TdManager职责与实现](#tdmanager职责与实现)
5. [IOManager职责与实现](#iomanager职责与实现)
6. [ExecManager职责与实现](#execmanager职责与实现)
7. [PasswordMng职责与实现](#passwordmng职责与实现)
8. [TestManager职责与实现](#testmanager职责与实现)
9. [管理器间协作示例](#管理器间协作示例)
## DevManager职责与实现
DevManager模块负责设备连接管理、状态监控和固件升级。该管理器通过`CDevManager`类实现,主要功能包括设备的添加、删除、状态更新和在线/离线设备列表的管理。它维护一个设备链表`m_devLinkList`,用于存储和管理所有设备对象。当设备连接时,DevManager会通过`AddDevice`方法将设备信息写入数据库,并在内存中创建设备对象。设备的状态(在线、离线)通过`m_uState`字段进行跟踪,状态更新通过`UpdateDevInfo`方法实现,该方法会将设备的硬件版本、软件版本、电池电压等信息同步到数据库中。对于固件升级,虽然具体实现未在代码中直接体现,但通过设备通信机制,可以实现固件的远程更新。
**Section sources**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L24-#L642)
## ProManager职责与实现
ProManager模块负责项目创建、测区管理和任务配置。该管理器通过`CProManager`类实现,提供了创建、显示和管理项目、测区和任务的接口。`CreateProjectInDB`方法用于在数据库中创建新项目,包括项目名称、描述、位置等信息,并确保项目名称的唯一性。`CreateProjectInDev`方法则负责将项目信息同步到设备端,通过生成XML文件并传输到设备的SD卡目录下。对于测区管理,`InsertDefaultTzToProject`方法会在项目创建时自动添加一个默认测区。任务配置方面,ProManager通过`ShowTzList``ShowProList`等方法提供项目和测区的列表显示功能,支持用户进行任务的配置和选择。
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L32-#L707)
## SptManager职责与实现
SptManager模块负责生成和管理2D/3D/跨孔测量脚本。该管理器通过`CSptManager`类实现,支持多种测量模式的脚本创建。`Create2DSConInDB`方法用于在数据库中创建二维测量脚本,包括脚本名称、电极数量、通道数等参数,并将脚本记录写入`script2d`表。对于跨孔测量,`CreateCESConInDB`方法实现了1D跨孔脚本的创建,支持自定义的测量参数。SptManager还维护了一个介质链表`m_medLinkList`,用于存储不同测量模式对应的介质对象,如`CMediumA``CMediumB`等,这些介质对象定义了具体的测量几何配置。脚本的生成过程涉及用户界面交互,通过`COpCreateSptDlg`等对话框收集用户输入,并最终将配置信息持久化到数据库。
**Section sources**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L74-#L800)
## TdManager职责与实现
TdManager模块负责测试数据的采集、存储和分析。该管理器通过`CTdManager`类实现,提供了测试数据的列表显示、数据采集和存储功能。`ShowTdListByProject``ShowTdListByTz`方法用于根据项目或测区显示相关的测试数据列表,支持多种测试类型(如2D电阻率、IP等)。测试数据的存储通过`CTdManager`与数据库的交互实现,将测量结果写入`td``rspcon``ipspcon`等数据表中。对于数据分析,TdManager提供了数据导出功能,可以将测试数据导出为Access数据库文件,便于后续处理。此外,该管理器还负责管理测试数据的元信息,如测量时间、天气条件、操作人员等。
**Section sources**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L57-#L800)
## IOManager职责与实现
IOManager模块负责数据导入导出功能,支持Excel、CSV、TXT、URF格式。该管理器通过`CIOManager`类实现,提供了`Export``Import`两个主要方法。`Export`方法允许用户将项目、测区和测试数据导出为Access数据库文件(.accdb),通过`CreateExpDatabase`方法创建目标数据库,并使用`ExportDataToAccdbFile`方法将数据写入。`Import`方法则从Access文件中读取数据,并将其导入到本地数据库中,支持项目、测区、脚本和测试数据的完整导入。虽然代码中主要实现了Access格式的导入导出,但通过扩展`OperTxtFile``OperUrfFile`等工具类,可以支持其他格式如TXT和URF。对于Excel和CSV格式,系统可能通过外部库或工具进行转换。
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L23-#L800)
## ExecManager职责与实现
ExecManager模块负责任务执行流程的管理。该管理器通过`CExecManager`类实现,协调测试任务的执行。`Exec2DRSPTest`方法是执行2D电阻率测量的核心,它首先通过`Save2DRSPSetInfo`方法保存测试设置,然后将配置文件发送到设备端,最后初始化测量过程。任务执行流程包括:1) 用户在界面设置测量参数;2) ExecManager生成配置文件并发送到设备;3) 设备接收指令并开始测量;4) 测量数据实时回传并存储。`InitialMeasure`方法负责与设备通信,发送`meas_add`等命令来启动测量。整个流程通过非模态对话框`COpExec2DRSPTestDlg`进行监控,确保用户可以实时查看测量状态。
**Section sources**
- [ExecManager.cpp](file://cpp/Managers/ExecManager.cpp#L49-#L613)
## PasswordMng职责与实现
PasswordMng模块负责密码管理机制。该管理器通过`CPasswordMng`类实现,提供密码的创建、修改和删除功能。密码信息存储在数据库的`password_info`表中,包含设备类型、设备名称和密码字段。`OperatePassword`方法根据操作类型(创建、修改、删除)生成相应的SQL语句,并执行数据库事务。对于GD-10设备,该管理器还通过串口命令与设备通信,使用`check_password`命令验证旧密码,并使用`set_param("password,...")`命令在设备端设置新密码,确保数据库和设备端的密码同步。密码的输入通过对话框界面完成,`OnOK`方法负责验证用户输入,确保新密码与确认密码一致,并调用`VerifyPassword`方法检查密码格式(必须由字母和数字组成)。
**Section sources**
- [PasswordMng.cpp](file://cpp/Managers/PasswordMng.cpp#L21-#L623)
## TestManager职责与实现
TestManager模块负责测试任务的调度。该管理器通过`CTestManager`类实现,目前代码中仅包含构造函数和析构函数的定义,具体实现细节未在提供的文件中体现。根据命名和模块化设计原则,TestManager可能负责管理测试任务队列、调度任务执行顺序、处理任务间的依赖关系以及监控任务执行状态。它可能与其他管理器(如ExecManager、TdManager)协同工作,确保测试任务能够按照预定计划高效执行。
**Section sources**
- [TestManager.cpp](file://cpp/Managers/TestManager.cpp#L18-#L27)
## 管理器间协作示例
各个管理器之间通过紧密协作实现完整的测量工作流。例如,当用户创建一个新项目时,ProManager首先在数据库中创建项目记录,然后触发SptManager生成默认的测量脚本。项目创建完成后,如果设备已连接,DevManager会检测到设备在线状态,并通知ProManager将项目数据同步到设备。ProManager调用`CreateProjectInDev`方法,生成项目配置文件并通过DevManager的设备对象发送到设备端。当用户开始执行测量任务时,ExecManager从ProManager获取项目和测区信息,从SptManager获取测量脚本,配置测试参数后,通过DevManager与设备通信,启动测量。测量过程中,TdManager负责接收和存储从设备传回的数据。整个流程体现了各管理器职责分明又相互协作的设计理念。
@@ -0,0 +1,216 @@
# ProManager
<cite>
**本文档引用的文件**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [ProManager.h](file://h/ProManager.h)
- [Project.cpp](file://cpp/ProblemZone/Project.cpp)
- [Project.h](file://h/Project.h)
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp)
- [TestingZone.h](file://h/TestingZone.h)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [SptManager.h](file://h/SptManager.h)
</cite>
## 目录
1. [简介](#简介)
2. [项目生命周期管理](#项目生命周期管理)
3. [测区管理机制](#测区管理机制)
4. [数据持久化流程](#数据持久化流程)
5. [与SptManager的协调](#与sptmanager的协调)
6. [恢复策略](#恢复策略)
7. [代码示例](#代码示例)
8. [结论](#结论)
## 简介
ProManager模块是Geomative Studio软件的核心组件之一,负责管理项目的整个生命周期。该模块提供了创建、打开、保存和关闭项目的基本功能,同时管理与项目相关的测区(TestingZone)和任务包配置。ProManager通过协调数据库和XML缓存文件之间的数据同步,确保项目数据的完整性和一致性。此外,它还与SptManager模块紧密协作,生成与项目关联的测量脚本。
**Section sources**
- [ProManager.h](file://h/ProManager.h#L30-L64)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L32-L37)
## 项目生命周期管理
ProManager模块实现了完整的项目生命周期管理功能,包括项目创建、打开、保存和关闭操作。当用户创建新项目时,ProManager首先通过`CreateProjectInDB`方法在数据库中创建项目记录,然后通过`CreateProjectInDev`方法在设备上创建相应的项目结构。项目创建过程中,系统会自动生成一个唯一的项目编号(CN),并创建一个默认的测区。
项目打开操作通过`LoadProjectFromDev`方法实现,该方法从设备加载项目数据并同步到本地数据库。项目保存操作则通过将内存中的项目数据序列化为XML格式并保存到缓存文件中来实现。项目关闭时,ProManager会清理内存中的项目对象,释放相关资源。
```mermaid
flowchart TD
Start([开始]) --> CreateProject["创建项目"]
CreateProject --> CheckExist["检查项目名称是否存在"]
CheckExist --> |存在| ShowError["显示错误信息"]
CheckExist --> |不存在| InsertDB["在数据库插入记录"]
InsertDB --> GenerateCN["生成项目编号"]
GenerateCN --> CreateDefaultTz["创建默认测区"]
CreateDefaultTz --> CreateDev["在设备创建项目"]
CreateDev --> SaveXML["保存project.xml"]
SaveXML --> End([结束])
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L249-L317)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L343-L483)
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L249-L317)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L343-L483)
- [Project.cpp](file://cpp/ProblemZone/Project.cpp#L19-L50)
## 测区管理机制
测区(TestingZone)是项目中的重要组成部分,用于组织和管理测量任务。ProManager通过`CreateTzInDB``CreateTzInDev`方法实现测区的创建。每个测区都有一个类型属性(TZtype),用于区分不同类型的测量任务,如1D VES、2D ERI或3D ERT。
测区配置逻辑包括设置测区名称、描述、位置和创建日期等基本信息。ProManager通过`ShowTzList`方法显示指定项目下的所有测区列表,用户可以通过界面操作选择和管理测区。当创建新测区时,系统会自动为其分配一个唯一的测区编号(CN),并在数据库和设备上同步创建相应的结构。
```mermaid
classDiagram
class CProManager {
+ShowTzList(dwProHandle, tzList)
+CreateTzInDB(dwID, dwPrID)
+CreateTzInDev(dwID, pDev)
+DeleteTzInDB(dwID)
+DeleteTzInDev(szPrCN, szTzCN, pDev)
}
class CTestingZone {
+m_szTZname
+m_szCDate
+m_szDesc
+m_szLocation
+m_szCN
+m_szTZtype
}
CProManager --> CTestingZone : "创建"
CProManager --> CTestingZone : "管理"
```
**Diagram sources**
- [ProManager.h](file://h/ProManager.h#L53-L58)
- [TestingZone.h](file://h/TestingZone.h#L14-L30)
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L53-L92)
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp#L18-L44)
- [TestingZone.h](file://h/TestingZone.h#L14-L30)
## 数据持久化流程
ProManager模块采用混合持久化策略,将项目数据存储在数据库和XML缓存文件中。核心项目数据(如项目名称、描述、位置等)存储在Access数据库的project表中,而项目结构和配置信息则以XML格式存储在CACHE目录下的project.xml文件中。
数据持久化流程如下:当项目创建或修改时,ProManager首先更新数据库中的记录,然后生成或更新project.xml文件。XML文件包含项目的基本信息、测区列表和配置参数。系统使用CMarkup类来处理XML文件的读写操作。项目数据在内存、数据库和XML文件之间保持同步,确保数据的一致性和完整性。
```mermaid
flowchart LR
Memory[内存对象] --> Database[(数据库)]
Memory --> XML[project.xml]
Database --> Memory
XML --> Memory
subgraph "数据流"
Database
XML
Memory
end
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L398-L426)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1746-L1863)
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L398-L426)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1746-L1863)
- [Project.h](file://h/Project.h#L16-L38)
## 与SptManager的协调
ProManager与SptManager模块紧密协作,共同完成项目相关的测量脚本管理。当需要为项目生成测量脚本时,ProManager会调用SptManager的相关方法。SptManager负责具体的脚本创建、编辑和验证逻辑,而ProManager则负责提供项目上下文和持久化支持。
这种协作关系体现在项目创建后的脚本生成流程中:ProManager首先创建项目结构,然后通知SptManager为该项目生成相应的测量脚本。脚本数据存储在独立的数据库表中,但与项目数据通过外键关联。这种设计实现了功能分离,同时保持了数据的完整性。
```mermaid
sequenceDiagram
participant User as "用户"
participant ProManager as "ProManager"
participant SptManager as "SptManager"
participant Database as "数据库"
User->>ProManager : 创建新项目
ProManager->>Database : 插入项目记录
ProManager->>SptManager : 请求生成脚本
SptManager->>SptManager : 创建脚本配置
SptManager->>Database : 保存脚本数据
SptManager-->>ProManager : 脚本创建完成
ProManager-->>User : 项目创建成功
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L343-L483)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L257-L487)
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L343-L483)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L257-L487)
- [SptManager.h](file://h/SptManager.h#L30-L48)
## 恢复策略
ProManager模块实现了多种恢复策略,以应对项目文件损坏或版本不兼容的情况。当检测到project.xml文件损坏时,系统可以从数据库中重建XML文件。恢复流程首先验证数据库中的项目记录完整性,然后重新生成XML文件结构。
对于版本不兼容问题,ProManager采用向后兼容的设计原则。新版本的软件可以读取旧版本创建的项目文件,系统会自动进行必要的数据转换和升级。在极端情况下,如果项目数据无法恢复,系统会创建一个新的空白项目,并尝试从备份中恢复尽可能多的数据。
```mermaid
flowchart TD
Start([开始]) --> CheckXML["检查project.xml"]
CheckXML --> |有效| LoadNormal["正常加载"]
CheckXML --> |无效| CheckDB["检查数据库"]
CheckDB --> |完整| RebuildXML["重建XML文件"]
CheckDB --> |不完整| CreateNew["创建新项目"]
RebuildXML --> Validate["验证数据"]
Validate --> |成功| LoadRebuilt["加载重建文件"]
Validate --> |失败| CreateNew
CreateNew --> Initialize["初始化新项目"]
Initialize --> End([结束])
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1746-L1863)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1865-L1999)
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1746-L1863)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1865-L1999)
## 代码示例
以下代码示例展示了项目创建和测区配置的核心方法调用。`CreateProjectInDB`方法处理数据库层面的项目创建,而`CreateProjectInDev`方法负责在设备上创建项目结构。测区配置通过`InsertDefaultTzToProject`方法实现,该方法为新项目创建一个默认的测区。
```mermaid
flowchart TD
A["CreateProjectInDB"] --> B["显示创建对话框"]
B --> C["验证项目名称"]
C --> |已存在| D["显示错误信息"]
C --> |不存在| E["生成项目编号"]
E --> F["插入数据库记录"]
F --> G["创建默认测区"]
G --> H["返回成功状态"]
I["CreateProjectInDev"] --> J["获取项目信息"]
J --> K["创建本地目录"]
K --> L["生成project.xml"]
L --> M["发送到设备"]
M --> |成功| N["更新同步状态"]
M --> |失败| O["清理并返回错误"]
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L249-L317)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L343-L483)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L319-L341)
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L249-L317)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L343-L483)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L319-L341)
## 结论
ProManager模块作为Geomative Studio项目管理的核心,实现了完整的项目生命周期管理功能。通过精心设计的架构,该模块有效地协调了数据库存储和XML文件缓存,确保了项目数据的持久性和一致性。其与SptManager模块的协作机制,为测量脚本的生成和管理提供了坚实的基础。完善的恢复策略进一步增强了系统的可靠性和用户体验。
@@ -0,0 +1,222 @@
# SptManager
<cite>
**本文档引用的文件**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [SptManager.h](file://h/SptManager.h)
- [Script2D.cpp](file://cpp/ProblemZone/Script2D.cpp)
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp)
- [ScriptCE.cpp](file://cpp/ProblemZone/ScriptCE.cpp)
- [Script.h](file://h/Script.h)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [testzone.xml](file://CACHE/testzone.xml)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 引言
SptManager模块是Geomative Studio软件中的核心组件,负责生成和管理各种测量脚本(包括2D、3D和跨孔测量)。该模块根据ProManager中定义的项目和测区信息,调用Script2D、Script3D、ScriptCE等具体类来生成符合测量协议的脚本数据。SptManager不仅处理脚本的创建和验证,还负责脚本的存储(如testzone.xml)和导出流程。本文档将深入分析SptManager的职责和实现,提供脚本生成失败或逻辑错误的排查方法,并通过代码示例展示从测区参数到最终脚本数据的转换过程。
## 项目结构
SptManager模块位于`cpp/Managers/`目录下,其主要功能是通过调用不同类型的脚本类(如Script2D、Script3D、ScriptCE)来生成测量脚本。这些脚本类位于`cpp/ProblemZone/`目录下,每个类负责特定类型的测量脚本生成。SptManager还与ProManager模块紧密协作,获取项目和测区信息,确保生成的脚本符合实际测量需求。
```mermaid
graph TB
subgraph "核心模块"
SptManager[SptManager]
ProManager[ProManager]
end
subgraph "脚本生成类"
Script2D[Script2D]
Script3D[Script3D]
ScriptCE[ScriptCE]
end
SptManager --> ProManager
SptManager --> Script2D
SptManager --> Script3D
SptManager --> ScriptCE
```
**图表来源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L1-L3589)
- [Script2D.cpp](file://cpp/ProblemZone/Script2D.cpp#L1-L237)
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp#L1-L221)
- [ScriptCE.cpp](file://cpp/ProblemZone/ScriptCE.cpp#L1-L146)
**章节来源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L1-L3589)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1-L2054)
## 核心组件
SptManager的核心功能包括脚本的创建、验证、存储和导出。它通过`Create2DSConInDB``CreateCESConInDB`等方法创建不同类型的测量脚本,并将这些脚本存储在数据库中。SptManager还负责将脚本导出到设备,并从设备加载脚本。
**章节来源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L257-L800)
- [Script2D.cpp](file://cpp/ProblemZone/Script2D.cpp#L1-L237)
## 架构概述
SptManager的架构设计遵循模块化原则,通过继承和多态机制实现不同类型的脚本生成。CScript类作为基类,定义了所有脚本的通用接口,而CScript2D、CScript3D、CScriptCE等派生类则实现了特定类型的脚本生成逻辑。SptManager通过`GetScript`方法根据句柄动态创建相应的脚本对象,实现了灵活的脚本管理。
```mermaid
classDiagram
class CScript {
+DWORD m_dwID
+_ConnectionPtr m_pConnection
+int m_iAR
+int m_iEAmount
+CScript(DWORD dwID, _ConnectionPtr& pConnection)
+~CScript()
+virtual bool ShowSptDetailInfo(CListCtrl &sptDetailList)
+virtual bool ShowChannelList(CListCtrl &sptChannelList)
+virtual bool ShowSptConInfo(CListCtrl &sptConList)
+virtual void AdjustRecListColumn(int iAR, CListCtrl& sptConListInfo)
}
class CScript2D {
+CScript2D(DWORD dwID, _ConnectionPtr& pConnection)
+~CScript2D()
+bool ShowSptDetailInfo(CListCtrl &sptDetailList)
+bool ShowChannelList(CListCtrl &sptChannelList)
+bool ShowSptConInfo(CListCtrl &sptConList)
+void AdjustRecListColumn(int iAR, CListCtrl& sptConListInfo)
}
class CScript3D {
+CScript3D(DWORD dwID, _ConnectionPtr& pConnection)
+~CScript3D()
+bool ShowSptDetailInfo(CListCtrl &sptDetailList)
+bool ShowChannelList(CListCtrl &sptChannelList)
+bool ShowSptConInfo(CListCtrl &sptConList)
+void AdjustRecListColumn(int iAR, CListCtrl& sptConListInfo)
}
class CScriptCE {
+CScriptCE(DWORD dwID, _ConnectionPtr& pConnection)
+~CScriptCE()
+bool ShowSptDetailInfo(CListCtrl &sptDetailList)
+bool ShowChannelList(CListCtrl &sptChannelList)
+bool ShowSptConInfo(CListCtrl &sptConList)
}
CScript <|-- CScript2D
CScript <|-- CScript3D
CScript <|-- CScriptCE
```
**图表来源**
- [Script.h](file://h/Script.h)
- [Script2D.cpp](file://cpp/ProblemZone/Script2D.cpp#L1-L237)
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp#L1-L221)
- [ScriptCE.cpp](file://cpp/ProblemZone/ScriptCE.cpp#L1-L146)
## 详细组件分析
### SptManager分析
SptManager模块的主要职责是协调脚本的生成和管理。它通过`Create2DSConInDB`方法创建2D测量脚本,通过`CreateCESConInDB`方法创建跨孔测量脚本。这些方法首先通过对话框获取用户输入的脚本参数,然后在数据库中创建相应的记录。
#### 脚本创建流程
```mermaid
sequenceDiagram
participant 用户 as "用户"
participant SptManager as "SptManager"
participant 数据库 as "数据库"
用户->>SptManager : 请求创建2D脚本
SptManager->>SptManager : 显示创建对话框
SptManager->>用户 : 获取脚本参数
SptManager->>数据库 : 检查脚本名称是否已存在
alt 脚本名称已存在
数据库-->>SptManager : 返回存在
SptManager-->>用户 : 显示错误消息
else 脚本名称不存在
数据库-->>SptManager : 返回不存在
SptManager->>数据库 : 插入scon记录
SptManager->>数据库 : 插入channel记录
SptManager->>数据库 : 插入script2d记录
数据库-->>SptManager : 确认插入成功
SptManager-->>用户 : 显示成功消息
end
```
**图表来源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L257-L800)
#### 脚本验证与存储
SptManager在创建脚本时会进行严格的验证,确保脚本名称的唯一性。如果脚本名称已存在,系统会提示用户并取消创建操作。脚本数据存储在数据库的`scon``channel``script2d`表中,其中`scon`表存储脚本的基本信息,`channel`表存储通道信息,`script2d`表存储具体的测量点数据。
**章节来源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L334-L351)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L363-L380)
### Script2D分析
Script2D类负责生成2D测量脚本。它继承自CScript类,并实现了特定于2D测量的逻辑。Script2D的主要功能包括显示脚本详细信息、显示通道列表和显示脚本配置信息。
#### 显示脚本详细信息
```mermaid
flowchart TD
Start([开始]) --> GetSConData["从scon表获取数据"]
GetSConData --> CheckRecordCount{"记录数 > 0?"}
CheckRecordCount --> |是| SetDetailInfo["设置详细信息"]
CheckRecordCount --> |否| End([结束])
SetDetailInfo --> End
```
**图表来源**
- [Script2D.cpp](file://cpp/ProblemZone/Script2D.cpp#L28-L71)
#### 显示通道列表
Script2D通过查询`channel``medium`表来获取通道信息,并将其显示在列表控件中。每个通道的装置类型编号(AR)也会被获取并存储。
**章节来源**
- [Script2D.cpp](file://cpp/ProblemZone/Script2D.cpp#L74-L109)
### Script3D分析
Script3D类负责生成3D测量脚本。它的实现与Script2D类似,但针对3D测量的特点进行了优化。Script3D同样实现了显示脚本详细信息、显示通道列表和显示脚本配置信息的功能。
**章节来源**
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp#L28-L151)
### ScriptCE分析
ScriptCE类负责生成跨孔测量脚本。它继承自CScript类,并实现了特定于跨孔测量的逻辑。ScriptCE的主要功能包括显示脚本配置信息、显示脚本详细信息和显示通道列表。
**章节来源**
- [ScriptCE.cpp](file://cpp/ProblemZone/ScriptCE.cpp#L28-L146)
## 依赖分析
SptManager模块依赖于多个其他模块和类,包括ProManager、Script2D、Script3D、ScriptCE等。这些依赖关系确保了SptManager能够获取项目和测区信息,并生成符合实际测量需求的脚本。
```mermaid
graph TD
SptManager --> ProManager
SptManager --> Script2D
SptManager --> Script3D
SptManager --> ScriptCE
SptManager --> CMarkup
SptManager --> _ConnectionPtr
```
**图表来源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L1-L3589)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1-L2054)
## 性能考虑
SptManager在处理大量脚本数据时需要考虑性能问题。为了避免数据库操作的性能瓶颈,SptManager采用了事务处理机制,确保脚本创建的原子性。此外,SptManager还通过缓存机制减少对数据库的频繁访问,提高整体性能。
## 故障排除指南
当脚本生成失败或出现逻辑错误时,可以按照以下步骤进行排查:
1. **检查脚本名称**:确保脚本名称在数据库中是唯一的,避免名称冲突。
2. **验证数据库连接**:确保数据库连接正常,能够正确执行SQL语句。
3. **检查参数输入**:确认用户输入的脚本参数是否正确,特别是电极数量、通道数量等关键参数。
4. **查看日志文件**:检查系统日志文件,查找可能的错误信息或异常堆栈。
**章节来源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L334-L351)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L488-L498)
## 结论
SptManager模块是Geomative Studio软件中不可或缺的一部分,负责生成和管理各种测量脚本。通过深入分析SptManager的职责和实现,我们可以更好地理解其工作原理,并在实际应用中更有效地使用和维护该模块。未来的工作可以进一步优化SptManager的性能,提高脚本生成的效率和可靠性。
@@ -0,0 +1,513 @@
# TdManager
<cite>
**本文档引用的文件**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
- [TdManager.h](file://h/TdManager.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [TaskDataOper.h](file://h/TaskDataOper.h)
- [TdRecord.cpp](file://cpp/ProblemZone/TdRecord.cpp)
- [TdRecord.h](file://h/TdRecord.h)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp)
- [TestingData.h](file://h/TestingData.h)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
10. [附录](#附录)(如有必要)
## 简介
TdManager模块是GeomativeStudio软件中负责测试数据采集、存储和管理的核心组件。该模块主要负责接收来自设备或文件的原始测量数据,通过TaskDataOper进行处理,并将结果持久化到TdRecord和TestingData对象中。它在测试数据与项目、脚本的关联机制中起着关键作用,确保数据的完整性和一致性。本文档将详细介绍TdManager模块的职责和实现,包括数据解析错误或存储失败的解决方案,并提供代码示例展示数据接收和记录的核心流程。
## 项目结构
GeomativeStudio项目的结构清晰,主要分为以下几个部分:
- **CACHE**: 存储缓存文件,如`project.xml``testzone.xml`
- **DB**: 包含数据库相关的文件,如`数据库字段修改记录.txt`
- **Install**: 包含安装文件和配置文件,如`config.ini``version_info.txt`
- **LOG**: 存储日志文件,如`upg_geo_filetrans_log.txt`
- **Release**: 包含发布版本的文件,如`config.ini``msado15.tlh`
- **cpp**: 源代码目录,包含多个子目录,如`Managers``Operator``ProblemZone`等。
- **h**: 头文件目录,包含与源代码对应的头文件。
- **res**: 资源文件目录,包含资源文件如`GeoMative.rc2`
- **tools**: 工具脚本目录,包含批处理文件如`IAP-GD10.bat`
```mermaid
graph TD
subgraph "根目录"
CACHE["CACHE"]
DB["DB"]
Install["Install"]
LOG["LOG"]
Release["Release"]
cpp["cpp"]
h["h"]
res["res"]
tools["tools"]
end
subgraph "cpp"
Managers["Managers"]
Operator["Operator"]
ProblemZone["ProblemZone"]
end
subgraph "Managers"
TdManager["TdManager.cpp"]
TaskDataOper["TaskDataOper.cpp"]
end
subgraph "ProblemZone"
TdRecord["TdRecord.cpp"]
TestingData["TestingData.cpp"]
end
subgraph "h"
TdManagerH["TdManager.h"]
TaskDataOperH["TaskDataOper.h"]
TdRecordH["TdRecord.h"]
TestingDataH["TestingData.h"]
end
TdManager --> TdManagerH
TaskDataOper --> TaskDataOperH
TdRecord --> TdRecordH
TestingData --> TestingDataH
```
**图表来源**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L1-L800)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L800)
- [TdRecord.cpp](file://cpp/ProblemZone/TdRecord.cpp#L1-L325)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L1-L800)
**章节来源**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L1-L800)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L800)
- [TdRecord.cpp](file://cpp/ProblemZone/TdRecord.cpp#L1-L325)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L1-L800)
## 核心组件
TdManager模块的核心组件包括`TdManager``TaskDataOper``TdRecord``TestingData`。这些组件协同工作,确保测试数据的高效采集、处理和存储。
**章节来源**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L1-L800)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L800)
- [TdRecord.cpp](file://cpp/ProblemZone/TdRecord.cpp#L1-L325)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L1-L800)
## 架构概述
TdManager模块的架构设计旨在实现高效的数据管理和处理。模块通过`TdManager`类接收来自设备或文件的原始测量数据,然后通过`TaskDataOper`类进行数据处理,最终将结果持久化到`TdRecord``TestingData`对象中。这种设计确保了数据的完整性和一致性,同时提供了灵活的数据处理和存储机制。
```mermaid
graph TD
subgraph "数据采集"
Device["设备"]
File["文件"]
end
subgraph "数据处理"
TdManager["TdManager"]
TaskDataOper["TaskDataOper"]
end
subgraph "数据存储"
TdRecord["TdRecord"]
TestingData["TestingData"]
end
Device --> TdManager
File --> TdManager
TdManager --> TaskDataOper
TaskDataOper --> TdRecord
TaskDataOper --> TestingData
```
**图表来源**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L1-L800)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L800)
- [TdRecord.cpp](file://cpp/ProblemZone/TdRecord.cpp#L1-L325)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L1-L800)
## 详细组件分析
### TdManager 分析
`TdManager`类是测试数据管理的核心,负责接收和处理来自设备或文件的原始测量数据。它通过`ImportTdHeadToDB``Import2DTdOrgToDB``ImportCETdOrgToDB`等方法将数据导入数据库,并通过`UploadCETdFromDev``Upload2DTdFromDev`等方法从设备上载数据。
#### 类图
```mermaid
classDiagram
class CTdManager {
+void DeleteSPCETd(DWORD dwID)
+void DeleteSP3DTd(DWORD dwID)
+void DeleteSP2DTd(DWORD dwID)
+void DeleteRsp3DTd(DWORD dwID)
+void DeleteIpsp3DTd(DWORD dwID)
+BOOL CheckTdExist(CString szPrCN, CString szTzCN, CString szTdCN, CDevice* const pDev, DWORD *TdId)
+BOOL OnlineCheckTdExist(CString szTdID, CString szDevSN, DWORD *TdId)
+BOOL OnlineCheckElecInfoExist(CString strTdID, CString szDevSN)
+DWORD ImportTdHeadToDB(DWORD dwTzID, CString szHeadFile, CDevice* const pDev, DWORD* pExTdID = NULL)
+BOOL Import2DTdOrgToDB(DWORD dwTdID, CString szOrgFile, CDevice* const pDev)
+BOOL ImportCETdOrgToDB(DWORD dwTdID, CString szOrgFile, CDevice* const pDev)
+BOOL Import3DTdOrgToDB(DWORD dwTdID, CString szOrgFile, CDevice* const pDev)
+BOOL Import2DTdConToDB(DWORD dwTdID, CString szDatFile, CDevice* const pDev, int* pTSN=NULL)
+BOOL ImportCETdConToDB(DWORD dwTdID, CString szDatFile, CDevice* const pDev)
+BOOL Import3DTdConToDB(DWORD dwTdID, CString szDatFile, CDevice* const pDev, int* pTSN = NULL)
+BOOL Import2DGRToDB(DWORD dwTdID, CString szGRFile, CDevice* const pDev)
+BOOL Import3DGRToDB(DWORD dwTdID, CString szGRFile, CDevice* const pDev)
+BOOL ImportCETGRToDB(DWORD dwTdID, CString szGRFile)
+BOOL UploadCETdFromDev(CString szPrCN, CString szTzCN, CString szTdCN, CString strSubTdCN, CDevice* const pDev)
+BOOL Upload2DTdFromDev(CString szPrCN, CString szTzCN, CString szTdCN, CString strSubTdCN, CDevice* const pDev)
+BOOL Upload3DTdFromDev(CString szPrCN, CString szTzCN, CString szTdCN, CString strSubTdCN, CDevice* const pDev)
+BOOL UploadWellTdFromDev(CString szPrCN, CString szTzCN, CString szTdCN, CString strSubTdCN, CDevice* const pDev)
+BOOL DeleteTdInDev(CString szPrCN, CString szTzCN, CString szTdCN, CDevice* const pDev)
+BOOL InitialTDListByTzForSyn(CListCtrl &tdList, CString szDeSN, CString szTzCN)
+BOOL InitialTDListByProForSyn(CListCtrl &tdList, CString szDeSN, CString szPrCN)
+BOOL InitialTDListByOnLineForSyn(CListCtrl &tdList, CString szDeSN, UINT32 &uiTotNum)
+BOOL InitialDevListByOnLineForSyn(CListCtrl &tdList, CString szDeSN, STSynDevParam *ptLocalDevParam)
+BOOL InitialCableListByOnLineForSyn(CListCtrl &tdList, CString szDeSN, STRemCableCallInfo *ptLocalCableInfo)
+BOOL OnlineSevTDListSynToDB(STRemTaskArg *tTaskArg, CString szDeSN)
+DWORD OnLineImportTdHeadToDB(STRemTaskArg *tTaskArg, CString szDevSN)
+BOOL Convert2DTo3D(DWORD dwTzHandle)
+void DeleteObjInMem(DWORD dwHandle)
+void DeleteRspCETd(DWORD dwID)
+void DeleteIpspCETd(DWORD dwID)
+void DeleteRsp2DTd(DWORD dwID)
+void DeleteIpsp2DTd(DWORD dwID)
+CTestingData* GetTestingData(DWORD dwHandle)
+bool ShowTdListByTz(DWORD dwTzHandle, CListCtrl& tdList)
+bool ShowTd2DListByTz(DWORD dwTzHandle, int iEAmount, float fEDistance, int iAR, CListCtrl& tdList)
+bool ShowTdListByDev(DWORD dwDevHandle, CListCtrl& tdList)
+bool ImportTdSpecAttr(const CStringArray& strAttrArray, int iDataType, DWORD dwChID, int iTSN)
+bool ShowTdListByProject(DWORD dwProHandle, CListCtrl& tdList)
+void GetTaskAttr(DWORD dwHandle, DWORD& dwTdID, int& iStyle)
+CTdManager(_ConnectionPtr& pConnection)
+virtual ~CTdManager()
+CHandleProcessor m_handleProcessor
-CLinkList<CTestingData*> m_tdLinkList
-_ConnectionPtr m_pConnection
-FILE *m_pFile
-CString m_log
-BOOL InitialTd2DTo3DDlg(COpTd2DTo3DDlg *pOpTd2DTo3DDlg)
}
```
**图表来源**
- [TdManager.h](file://h/TdManager.h#L1-L109)
### TaskDataOper 分析
`TaskDataOper`类负责处理测试数据,包括创建任务、查询任务信息、更新任务数据等。它通过`Create1DTask``Create2DTask``Create3DTask`等方法创建不同类型的任务,并通过`QueryTdDataByElec`等方法查询任务数据。
#### 类图
```mermaid
classDiagram
class CTaskDataOper {
+CTaskDataOper()
+virtual ~CTaskDataOper()
+CString CreateTaskCN(int iTestType)
+int Create1DTask(const ST1DTaskParam& stTaskParam, CString strTaskCN)
+int Create2DTask(const ST2DTaskParam& stTaskParam, CString strTaskCN)
+int Create3DTask(const ST3DTaskParam& stTaskParam, CString strTaskCN)
+void QuerySptByAR(int iAR, std : : vector<STQuerySptInfo>& vtQuerySptRes, int iSptType)
+void QuerySptRectByARandSCname(int iAR, CString strSCname, CString& vtQuerySptRes, CString& strPoleStep, CString& strPoleDistance, CString& strLineDirection, BYTE& ucSptType)
+void QueryMediumInfo(int iSptType, std : : vector<STQueryMediumInfo>& vtQueryAR)
+void QueryCmInfo(CString strCName, std : : vector<STQueryCMInfo>& vtQueryCM)
+bool DeleteTask(int iTaskID)
+bool DeleteTaskArray(std : : vector<int> vtTaskID)
+bool DeleteTaskArray(std : : vector<CString> vtTaskID)
+bool Query2DSptInfo(int iSptID, int &iMinLayer, int &iMaxLayer)
+bool QuerySptElecTpMount(int iSptID, int &iEAmount, int &iTpMount)
+bool QueryTdBasicInfo(int iTaskID, STQueryTaskBasicInfo* pTaskBasicInfo, CString strTaskCN=_T(""))
+bool UpdateGrData(int iTaskID, const char* pData, int iSptType, int iAddedVal = 0)
+bool InsertGrData(int iTaskID, WORD wGrNum, const char* pData, int iSptType=1)
+bool InsertCoordinatesData(CString strTaskID, WORD wGrNum, const char* pData, float fMaxWellDepth, int iSptType = 1)
+bool DeleteGrInfo(int iTaskID, WORD wElecID, BYTE ucDelFlag)
+bool DeleteTdDataInfo(BYTE ucTdType, int iTaskID, WORD wTSN, BYTE ucDelFlag)
+bool OpenTdData(int iTaskID, BYTE ucTdType, WORD wStartTSN = 0, WORD wMaxChannel = 1)
+void CloseTdData()
+int QueryNextTdBasicData(std : : vector<STSigSndDataInfo>& vtTestData)
+bool QueryTdSigBasicData(int iTaskID, BYTE ucTdType, WORD wTSN, LPSTSigSndDataInfo pMeasuBasicReq)
+bool UpdateTdBasicData(BYTE ucTdType, BYTE ucTestType, int iTdChannelID, int iTsn, LPSTMeasuBasicDataRes pMeasuBasicData, void *pAttachData)
+bool UpdateTdBasicData(BYTE ucTdType, BYTE ucTestType, int iTdChannelID, int iTsn, LPSTMeasuBasicDataResEx pMeasuBasicData, void *pAttachData)
+bool OnlineDownloadRes2DData(BYTE ucTdType, STTaskDataRes *ptTaskData, DWORD dwChID)
+bool OnlineUploadRes2DTask(DWORD dwChID)
+bool OnlineUploadRes2DArg(DWORD dwChID, STQueryTaskBasicInfo stQueryTdInfo)
+bool OnlineUploadRes2DRg(DWORD dwChID, STQueryTaskBasicInfo stQueryTdInfo)
+bool OnlineUploadRes2DData(DWORD dwChID, STQueryTaskBasicInfo stQueryTdInfo)
+bool UploadElecCoordinatesInfo(DWORD dwTdID, STQueryTaskBasicInfo stQueryTdInfo)
+int GetCurSelTdTestType()
+bool QueryTdDataFromTsn(int iTaskID, BYTE ucTdType, WORD wStartTSN, int iCnt, std : : vector<STTaskDetailBasicData>& vtRes)
+bool QueryTdDataByElec(int iSptID, BYTE ucTdType, int iStartElec, int iEndElec, std : : vector<STTaskDetailBasicData>& vtRes)
+bool QueryElecMaxWellDepthByCN(CString strScriptCN, BYTE ucTdType, STElecCoordinatesInfoHead& stElecInfoHead)
+bool QueryElecCoordinatesDataByCN(CString strScriptCN, BYTE ucTdType, WORD wStartTSN, int iCnt, std : : vector<STElecCoordinatesInfoBody>& vtRes)
+void QueryTdAttrToCtrl(CListCtrl& listAttr, int iTaskID)
+void QueryTdDataToCtrl(CListCtrl& listData, int iTaskID, int iSptType, int iTestType)
+void QueryOnLineTdAttrToCtrl(CListCtrl& listAttr, STTaskListItem taskItem, STRemTaskArg *pstTaskArg)
+bool QueryOnLineTdAttrFromSev(STRemTaskTable stTaskTable, STRemTaskArg *pstTaskArg)
+bool QueryOnLineTdRgFromSev(STRemTaskArg stTaskArg, char *pRg)
+bool QueryOnLineElecInfoFromSev(STRemTaskArg stTaskArg, char* pElecInfo)
+bool QueryOnLineTdDataFromSev(STRemTaskArg stTaskArg, UINT32 uiStartPoint, UINT32 uiEndPoint, char *pData)
+void QueryOnLineTdDataToCtrl(STRemTaskArg stTaskArg, std : : vector<STTaskDetailBasicData>& vtData)
+void InitialTaskTreeCtrl(CTreeCtrl& taskTree, int iSptType)
+void InitOnLineTaskTreeCtrl(CTreeCtrl& taskTree, int iSptType, std : : map<CString, STRemTaskTable> mapTaskList, HWND hWnd)
+void QueryTimerTaskValiad(std : : vector<STTimerTask>& vtTimerTask, const SYSTEMTIME &sysCurTime)
+int GetDefaultTzID()
+bool DeleteTimerTask(const std : : vector<int>& vtTask)
+bool DeleteTimerTask(UINT32 uiTDID)
+void QueryTdBrowseInfo(std : : vector<STTdBrowseInfo>& vtTdBrowseInfo, bool bIsQueryTimerTd=false)
+void QueryTdBrowseInfo(std : : vector<STTdBrowseInfo>& vtTdBrowseInfo, int iSptType, int iType, bool bIsQueryTimerTd=false)
+bool AddTimerTask(int iTaskID, CString strTaskName, CString strTime, CString strPlcID)
+bool InsertPlcStatusData(const STRemPlcDataInfo* pRemPlcData)
+bool QueryPlcStatusData(std : : vector<STPlcStatusInfo>& vtPlcStatus)
+void DeleteOldPlcStatusData()
+bool QueryTaskPacketAttr(int& iLoopTime, int& iInterval, CString& strPlcID)
+bool QueryTaskPacketInfo(std : : vector<STTdBrowseInfo>& vtTdBrowseInfo)
+bool InsertTaskPacketInfo(const std : : vector<STTdBrowseInfo>& vtTdBrowseInfo, const STTaskPacketAttr& stAttr)
+bool CreateSigTaskByAuto(const STTdBrowseInfo& stBasicTask, CString strTime, STTdBrowseInfo& stNewTask)
+bool CreateTaskPacket(const std : : vector<STTdBrowseInfo>& vtBasicTaskPacket, CString strSysTime, std : : vector<STTdBrowseInfo>& vtNewTaskPacket)
+int QueryARByTdID(DWORD dwTdID)
+void AdjustParam()
+void SetCurrentTimeRange(time_t tStartTime, time_t tEndTime)
+unsigned int m_uiDevID
-CGUCodeCreator m_guCodeCreator
-_RecordsetPtr m_pRecTdData
-BYTE m_iTdType
-int m_iTestType
-WORD m_wMaxChannel
-time_t m_tStartTime
-time_t m_tEndTime
}
```
**图表来源**
- [TaskDataOper.h](file://h/TaskDataOper.h#L1-L448)
### TdRecord 分析
`TdRecord`类负责处理测试数据的记录,包括加载原始数据、显示原始数据曲线等。它通过`LoadCEOrgData``Load2DOrgData``Load3DOrgData`等方法加载不同类型的原始数据,并通过`DisplayRawDataSplines`方法显示原始数据曲线。
#### 类图
```mermaid
classDiagram
class CTdRecord {
+CTdRecord(_ConnectionPtr& pConnection)
+virtual ~CTdRecord()
+DWORD m_dwChID
+int m_iTsn
+int m_iN
+float m_fK
+float m_fI
+float m_fV
+float m_fR0
+float m_fSP
+CString m_Datetime
+CStringArray m_saVRawData
+CStringArray m_saIRawData
+_ConnectionPtr m_pConnection
+float GetMaxAbsV()
+virtual void DisplayRawDataSplines()
+virtual BOOL LoadOrgData()
+virtual float ConvertVOrgData(float fVOrgData)
-float m_fMaxAbsV
-BOOL LoadCEOrgData()
-BOOL Load2DOrgData()
-BOOL Load3DOrgData()
}
```
**图表来源**
- [TdRecord.h](file://h/TdRecord.h#L1-L47)
### TestingData 分析
`TestingData`类负责处理测试数据的高级功能,包括显示测试数据列表、保存数据为不同格式的文件等。它通过`ShowConList``ShowConListByPage`等方法显示测试数据列表,并通过`SaveTdToExcelFile``SaveTdToRes2DFile`等方法保存数据为不同格式的文件。
#### 类图
```mermaid
classDiagram
class CTestingData {
+virtual void UpdataTopography(int f_disType, int f_start, CListCtrl &f_list)
+BOOL ExcuteSql(CString f_sql)
+virtual void GetTimeWindowList(CListCtrl &f_list)
+virtual BOOL ShowTimeWindow(CListCtrl &tdConList, int iTsn)
+void GetORGCStringToArray(CString f_SrcString, CStringArray *f_array)
+void FreeWindowsTime()
+double GetPeriod()
+bool GetTimeWindowInfo(std : : vector<STSigTWInfo>& vtTWInfo)
+void CreateWindowsTime()
+virtual bool CalculateTimeWindows(struct _WinTimeList f_winTimeList, CStringArray *v_orgData, int f_TRwave, int f_Tcycle, int f_Sample, int f_interation, int f_industrial)
+virtual bool CalculateTWInfo(CStringArray *v_orgData, int nFrenquence)
+virtual BOOL DisplayIpCurveGraph()
+CDevice* m_pDevice
+DWORD m_dwID
+CString m_szTdName
+CString m_szTdCN
+CString m_szTLocation
+CString m_szPrCN
+CString m_szTzName
+CString m_szTzCN
+DWORD m_dwTzID
+DWORD m_dwSCID
+CString m_szSCCN
+CString m_szSName
+int m_iSType
+int m_iTType
+int m_iTMode
+int m_iEAmount
+int m_iTPAmount
+int m_iCHAmount
+int m_iN
+int m_iTRWave
+int m_iTRFrequency
+int m_iIFrequency
+int m_iSAFrequency
+int m_iCLayout
+float m_fESpace
+CString m_szEDistance
+int m_iWeather
+int m_iWDIR
+float m_fTemperature
+float m_fHeight
+float m_fHumidity
+float m_fTRPeriod
+CString m_szCDate
+CString m_szCTime
+CString m_szTDate
+CString m_szTTime
+int m_iRCamount
+int m_iRDirection
+int m_iCRtime
+CString m_szPM
+CString m_szOP
+CString m_szQA
+virtual bool ShowGrList(CListCtrl &tdGrList)
+virtual bool ShowConList(CListCtrl &tdConList)
+virtual bool ShowConListByPage(CListCtrl &tdConList, int iSType = 2)
+virtual bool ShowDetailInfo(CListCtrl &tdDetailList)
+virtual BOOL SaveTdToExcelFile(CString f_szFileName)
+virtual BOOL SaveTdToResCEFile(CString f_szFileName)
+virtual BOOL SaveTdToRes2DFile(CString f_szFileName)
+virtual BOOL SaveTdToRes3DFile(CString f_szFileName)
+virtual BOOL SaveTdToCsvFile(CString f_szFileName)
+virtual bool ExportIP2DDataToDat(CString strFile)
+virtual bool ExportIP3DToDatFile(CString strFile)
+virtual BOOL ExportIPDataToTxt(CString strFileName)
+virtual BOOL ExportResDataToTxt(CString strFileName)
+virtual BOOL ExportSpDataToTxt(CString strFileName)
+virtual BOOL Export2dDataToTxtBySort(CString strFileName, int iSortMethod)
+virtual BOOL ExportDataToUrf(CString strFileName)
+void SetCustToCrossHole(bool bFlag)
+virtual BOOL DisplayGraph()
+virtual BOOL DisplayTPSplinesGraph(int iTSN)
+virtual BOOL LoadData(CLinkList<CMedium*>& m_medLinkList)
+inline int CalcuCrossHolePoleID(int iOrgPoleID, int iHoleID, int iHoleFlag, int iMidEamount)
+CTestingData(DWORD dwID, _ConnectionPtr& pConnection)
+virtual ~CTestingData()
+CPtrList m_tdChaList
+_WaveCount *m_waveCount
-_ConnectionPtr m_pConnection
-CHandleProcessor m_handleProcessor
-double GetCycle(int f_type)
-BOOL SaveOrgDataToDB(DWORD dwTdID)
-BOOL SaveGRDataToDB(DWORD dwTdID)
-bool m_bIsCustomToCrossHole
-int GetSample(int f_nindustrial, int f_type)
-double adc_integral(int *adc_buf, int length)
-double adc_average(int *adc_buf, int length)
-CString GetWaveNum(int f_waveType)
-void TransfToDouble(double* f_buff, CStringArray f_szArray)
-double adc_calculate(double offset, double coefficient, double adc)
}
```
**图表来源**
- [TestingData.h](file://h/TestingData.h#L1-L276)
**章节来源**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L1-L800)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L800)
- [TdRecord.cpp](file://cpp/ProblemZone/TdRecord.cpp#L1-L325)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L1-L800)
## 依赖分析
TdManager模块依赖于多个其他模块和库,包括`HandleProcessor``LinkList``TestingData``CtrlProtocolDef`等。这些依赖关系确保了模块的完整性和功能性。
```mermaid
graph TD
TdManager --> HandleProcessor
TdManager --> LinkList
TdManager --> TestingData
TdManager --> CtrlProtocolDef
TaskDataOper --> GUCodeCreator
TaskDataOper --> CtrlProtocolDef
TdRecord --> TestingData
TestingData --> Device
TestingData --> Medium
```
**图表来源**
- [TdManager.h](file://h/TdManager.h#L1-L109)
- [TaskDataOper.h](file://h/TaskDataOper.h#L1-L448)
- [TdRecord.h](file://h/TdRecord.h#L1-L47)
- [TestingData.h](file://h/TestingData.h#L1-L276)
**章节来源**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L1-L800)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L800)
- [TdRecord.cpp](file://cpp/ProblemZone/TdRecord.cpp#L1-L325)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L1-L800)
## 性能考虑
TdManager模块在设计时考虑了性能优化,特别是在数据处理和存储方面。通过使用高效的数据库操作和数据结构,模块能够快速处理大量测试数据。此外,模块还提供了多种数据导出格式,以满足不同用户的需求。
## 故障排除指南
### 数据解析错误
当遇到数据解析错误时,可以检查以下几点:
- 确认数据文件的格式是否正确。
- 检查数据文件是否损坏。
- 确认数据文件的编码是否正确。
### 存储失败
当遇到存储失败时,可以检查以下几点:
- 确认数据库连接是否正常。
- 检查数据库是否有足够的存储空间。
- 确认数据库表结构是否正确。
**章节来源**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L1-L800)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L800)
- [TdRecord.cpp](file://cpp/ProblemZone/TdRecord.cpp#L1-L325)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L1-L800)
## 结论
TdManager模块是GeomativeStudio软件中不可或缺的一部分,负责测试数据的采集、处理和存储。通过详细的分析,我们了解了模块的职责和实现,以及其在测试数据与项目、脚本的关联机制中的作用。模块的设计考虑了性能优化和错误处理,确保了数据的完整性和一致性。希望本文档能帮助开发者更好地理解和使用TdManager模块。
## 附录
### 代码示例
以下是一个简单的代码示例,展示如何使用`TdManager`类接收和记录测试数据:
```cpp
// 创建TdManager实例
CTdManager tdManager(connection);
// 从设备上载1D数据
CString prCN = _T("Project1");
CString tzCN = _T("Zone1");
CString tdCN = _T("Test1");
CString subTdCN = _T("");
CDevice* pDev = new CDevice();
BOOL result = tdManager.UploadCETdFromDev(prCN, tzCN, tdCN, subTdCN, pDev);
if (result) {
// 数据上载成功
AfxMessageBox(_T("数据上载成功"));
} else {
// 数据上载失败
AfxMessageBox(_T("数据上载失败"));
}
// 清理资源
delete pDev;
```
**章节来源**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L1-L800)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L800)
- [TdRecord.cpp](file://cpp/ProblemZone/TdRecord.cpp#L1-L325)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L1-L800)
@@ -0,0 +1,511 @@
# DataOperator
<cite>
**本文档引用的文件**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [DataOperator.h](file://h/DataOperator.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [TaskDataOper.h](file://h/TaskDataOper.h)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
- [TdManager.h](file://h/TdManager.h)
- [TestingData.h](file://h/TestingData.h)
- [excel.cpp](file://cpp/Tools/excel.cpp)
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 引言
DataOperator模块是GeomativeStudio软件中负责数据读写、处理与管理的核心组件。该模块主要负责与TdManager协同工作,实现测试数据的加载、保存和格式转换,支持Excel、CSV、TXT、URF等多种导出格式。通过TaskDataOper类,实现了任务数据的操作流程,包括数据序列化、反序列化及内存管理策略。DataOperator模块在实际业务场景中,如从设备读取原始测量数据并持久化到项目文件中的完整流程,展现了其强大的数据处理能力。此外,该模块还深入分析了与ADO数据库交互的实现机制,包括记录集操作和异常处理,确保了数据操作的稳定性和可靠性。
## 项目结构
GeomativeStudio项目结构清晰,主要分为CACHE、DB、Install、LOG、Release、cpp、h、res、tools等目录。其中,cpp目录下的Operator子目录包含了DataOperator和TaskDataOper等核心操作类的实现文件,Managers目录下的TdManager.cpp文件则负责测试数据的管理。h目录下的头文件定义了各个类的接口和数据结构,为模块间的协同工作提供了基础。整个项目结构体现了模块化设计的思想,便于维护和扩展。
```mermaid
graph TD
subgraph "核心模块"
DataOperator[DataOperator.cpp]
TaskDataOper[TaskDataOper.cpp]
TdManager[TdManager.cpp]
end
subgraph "工具类"
Excel[excel.cpp]
OperTxtFile[OperTxtFile.cpp]
OperUrfFile[OperUrfFile.cpp]
end
subgraph "头文件"
DataOperatorH[DataOperator.h]
TaskDataOperH[TaskDataOper.h]
TdManagerH[TdManager.h]
TestingDataH[TestingData.h]
end
DataOperator --> TdManager
DataOperator --> TaskDataOper
TaskDataOper --> TdManager
DataOperator --> Excel
DataOperator --> OperTxtFile
DataOperator --> OperUrfFile
DataOperatorH --> DataOperator
TaskDataOperH --> TaskDataOper
TdManagerH --> TdManager
TestingDataH --> TdManager
```
**图源**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
- [excel.cpp](file://cpp/Tools/excel.cpp)
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
**节源**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
## 核心组件
DataOperator模块的核心组件包括DataOperator类、TaskDataOper类和TdManager类。DataOperator类负责数据的读写和管理,通过与TdManager类的协同工作,实现了测试数据的加载、保存和格式转换。TaskDataOper类则专注于任务数据的操作流程,包括数据的序列化、反序列化及内存管理策略。这些核心组件共同构成了DataOperator模块的基础,确保了数据处理的高效性和可靠性。
**节源**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
## 架构概述
DataOperator模块的架构设计充分考虑了模块化和可扩展性。通过定义清晰的接口和数据结构,实现了各组件间的松耦合。DataOperator类作为数据操作的入口,通过调用TaskDataOper类和TdManager类的方法,完成具体的数据处理任务。这种设计不仅提高了代码的可读性和可维护性,还便于后续的功能扩展和性能优化。
```mermaid
classDiagram
class DataOperator {
+_ConnectionPtr m_pConnection
+CStateProcessor m_stateProcessor
+CHandleProcessor m_handleProcessor
+InitialNavDataView(CNavDataView* pNavDataView)
+ShowProjectInfo(DWORD dwProHandle, CView *pAppDataView)
+ShowTzInfo(DWORD dwTzHandle, CView *pAppDataView)
+ShowRsp3DTdInfo(DWORD dwTdHandle, CView *pAppDataView)
+ShowRsp2DTdInfo(DWORD dwTdHandle, CView *pAppDataView)
+ShowRspCETdInfo(DWORD dwTdHandle, CView* pAppDataView)
+LoadRspCERecordbyPage(DWORD dwTdHandle, CView *pAppDataView, int iSType)
+LoadRsp2dRecordbyPage(DWORD dwTdHandle, CView *pAppDataView, int iSType)
+LoadRsp3dRecordbyPage(DWORD dwTdHandle, CView *pAppDataView, int iSType)
+ShowIps2DpTdInfo(DWORD dwTdHandle, CView *pAppDataView)
+ShowIps3DpTdInfo(DWORD dwTdHandle, CView *pAppDataView)
+ShowIpsCEpTdInfo(DWORD dwTdHandle, CView *pAppDataView)
+LoadIpspCERecordbyPage(DWORD dwTdHandle, CView *pAppDataView, int iSType)
+LoadIpsp2dRecordbyPage(DWORD dwTdHandle, CView *pAppDataView, int iSType)
+LoadIpsp3dRecordbyPage(DWORD dwTdHandle, CView *pAppDataView, int iSType)
+CreateProjectInDB(CNavDataView* pNavDataView)
+DeleteProjectInDB(CNavDataView* pNavDataView)
+DeleteTzInDB(CNavDataView* pNavDataView)
+Convert2DTo3D(CNavDataView* pNavDataView)
+Delete3DRecord(CNavDataView *pNavDataView, int iTSN)
+Delete1DRecord(CNavDataView *pNavDataView, int iTSN)
+Delete2DRecord(CNavDataView *pNavDataView, int iTSN)
+DeleteSPCETdInDB(DWORD dwTdID)
+DeleteSP2DTdInDB(DWORD dwTdID)
+DeleteSP3DTdInDB(DWORD dwTdID)
+DeleteRspCETdInDB(DWORD dwTdID)
+DeleteRsp2DTdInDB(DWORD dwTdID)
+DeleteRsp3DTdInDB(DWORD dwTdID)
+DeleteIpspCETdInDB(DWORD dwTdID)
+DeleteIpsp2DTdInDB(DWORD dwTdID)
+DeleteIpsp3DTdInDB(DWORD dwTdID)
+DisplayRsp2DTdGraph(CNavDataView *pNavDataView)
+DisplayRsp3DTdGraph(CNavDataView *pNavDataView)
+DisplayRspCETdGraph(CNavDataView *pNavDataView)
+DisplayTPSplinesGraph(CNavDataView *pNavDataView, int iTSN)
+ExportIpCETdToExcel(CNavDataView *pNavDataView, CString f_szFileName)
+ExportIp2DTdToExcel(CNavDataView *pNavDataView, CString f_szFileName)
+ExportIp3DTdToExcel(CNavDataView *pNavDataView, CString f_szFileName)
+ExportIpCETdToCSV(CNavDataView *pNavDataView, CString f_szFileName)
+ExportIp2DTdToCSV(CNavDataView *pNavDataView, CString f_szFileName)
+ExportIp3DTdToCSV(CNavDataView *pNavDataView, CString f_szFileName)
+ExportIpSpCETdToDAT(CNavDataView *pNavDataView, CString f_szFileName)
+ExportIP2DToTxt(CNavDataView *pNavDataView, CString f_szFileName)
+ExportIP3DToTxt(CNavDataView *pNavDataView, CString f_szFileName)
+ExportIP1DToTxt(CNavDataView *pNavDataView, CString f_szFileName)
+ExportSPCETdToExcel(CNavDataView *pNavDataView, CString f_szFileName)
+ExportSP2DTdToExcel(CNavDataView *pNavDataView, CString f_szFileName)
+ExportSP3DTdToExcel(CNavDataView *pNavDataView, CString f_szFileName)
+ExportSPCETdToCSV(CNavDataView *pNavDataView, CString f_szFileName)
+ExportSP2DTdToCSV(CNavDataView *pNavDataView, CString f_szFileName)
+ExportSP3DTdToCSV(CNavDataView *pNavDataView, CString f_szFileName)
+ExportSPCETdToTxt(CNavDataView *pNavDataView, CString f_szFileName)
+ExportSP2DTdToTxt(CNavDataView *pNavDataView, CString f_szFileName)
+ExportSP3DTdToTxt(CNavDataView *pNavDataView, CString f_szFileName)
+ExportRsp1DTdToTxt(CNavDataView *pNavDataView, CString f_szFileName)
+ExportRsp2DTdToTxt(CNavDataView *pNavDataView, CString f_szFileName)
+ExportRsp3DTdToTxt(CNavDataView *pNavDataView, CString f_szFileName)
+ExportRspCETdToDAT(CNavDataView *pNavDataView, CString f_szFileName)
+ExportRsp2DTdToDAT(CNavDataView *pNavDataView, CString f_szFileName)
+ExportRsp3DTdToDAT(CNavDataView *pNavDataView, CString f_szFileName)
+ExportRspCETdToExcel(CNavDataView *pNavDataView, CString f_szFileName)
+ExportRsp2DTdToExcel(CNavDataView *pNavDataView, CString f_szFileName)
+ExportRsp3DTdToExcel(CNavDataView *pNavDataView, CString f_szFileName)
+ExportRspCETdToCSV(CNavDataView *pNavDataView, CString f_szFileName)
+ExportRsp2DTdToCSV(CNavDataView *pNavDataView, CString f_szFileName)
+ExportRsp3DTdToCSV(CNavDataView *pNavDataView, CString f_szFileName)
+ExportRsp2DTdToUrf(CNavDataView *pNavDataView, CString f_szFileName)
+ExportRsp3DTdToUrf(CNavDataView *pNavDataView, CString f_szFileName)
+Delete1DElectrodeRecord(CNavDataView *pNavDataView, const std : : vector<float>* pvtDelElecID)
+Delete2DElectrodeRecord(CNavDataView *pNavDataView, const std : : vector<float>* pvtDelElecID)
+Delete3DElectrodeRecord(CNavDataView *pNavDataView, const std : : vector<float>* pvtDelElecID)
+ExportTdRecFile(CNavDataView *pNavData)
+ExportTdOrgFile(CNavDataView *pNavData)
+SaveRecFileToLocal(CString strRecFile, CString strDstFile,int iTaskType)
+QueryTaskARInDB(DWORD dwTdHandle)
}
class TaskDataOper {
+_RecordsetPtr m_pRecTdData
+bool m_bIsOpenTdData
+BYTE m_iTdType
+int m_iTestType
+WORD m_wMaxChannel
+time_t m_tStartTime
+time_t m_tEndTime
+CGUCodeCreator m_guCodeCreator
+GetDefaultTzID()
+Create1DTask(const ST1DTaskParam& stTaskParam,CString strTaskCN)
+Create2DTask(const ST2DTaskParam& stTaskParam, CString strTaskCN)
+Create3DTask(const ST3DTaskParam& stTaskParam, CString strTaskCN)
+QuerySptByAR(int iAR, std : : vector<STQuerySptInfo>& vtQuerySptRes, int iSptType)
+QuerySptRectByARandSCname(int iAR, CString strSCname, CString& vtQuerySptRes, CString& strPoleStep, CString& strPoleDistance, CString& strLineDirection, BYTE& ucSptType)
+QueryMediumInfo(int iSptType, std : : vector<STQueryMediumInfo>& vtQueryAR)
+QueryCmInfo(CString strCName, std : : vector<STQueryCMInfo>& vtQueryCM)
+DeleteTask(int iTaskID)
+DeleteTaskArray(std : : vector<int> vtTaskID)
+DeleteTaskArray(std : : vector<CString> vtTaskID)
+Query2DSptInfo(int iSptID, int &iMinLayer,int &iMaxLayer)
+QuerySptElecTpMount(int iSptID, int &iEAmount, int &iTpMount)
+QueryTdBasicInfo(int iTaskID, STQueryTaskBasicInfo* pTaskBasicInfo,CString strTaskCN=_T(""))
+UpdateGrData(int iTaskID, const char* pData,int iSptType,int iAddedVal = 0)
+InsertGrData(int iTaskID, WORD wGrNum, const char* pData, int iSptType=1)
+InsertCoordinatesData(CString strTaskID, WORD wGrNum, const char* pData,float fMaxWellDepth, int iSptType = 1)
+DeleteGrInfo(int iTaskID, WORD wElecID, BYTE ucDelFlag)
+DeleteTdDataInfo(BYTE ucTdType, int iTaskID, WORD wTSN, BYTE ucDelFlag)
+OpenTdData(int iTaskID, BYTE ucTdType, WORD wStartTSN = 0, WORD wMaxChannel = 1)
+CloseTdData()
+QueryNextTdBasicData(std : : vector<STSigSndDataInfo>& vtTestData)
+QueryTdSigBasicData(int iTaskID, BYTE ucTdType, WORD wTSN, LPSTSigSndDataInfo pMeasuBasicReq)
+UpdateTdBasicData(BYTE ucTdType, BYTE ucTestType,int iTdChannelID, int iTsn, LPSTMeasuBasicDataRes pMeasuBasicData,void *pAttachData)
+UpdateTdBasicData(BYTE ucTdType, BYTE ucTestType, int iTdChannelID, int iTsn, LPSTMeasuBasicDataResEx pMeasuBasicData, void *pAttachData)
+OnlineDownloadRes2DData(BYTE ucTdType, STTaskDataRes *ptTaskData, DWORD dwChID)
+OnlineUploadRes2DTask(DWORD dwChID)
+OnlineUploadRes2DArg(DWORD dwChID, STQueryTaskBasicInfo stQueryTdInfo)
+OnlineUploadRes2DRg(DWORD dwChID, STQueryTaskBasicInfo stQueryTdInfo)
+OnlineUploadRes2DData(DWORD dwChID, STQueryTaskBasicInfo stQueryTdInfo)
+UploadElecCoordinatesInfo(DWORD dwTdID, STQueryTaskBasicInfo stQueryTdInfo)
+QueryTdDataFromTsn(int iTaskID, BYTE ucTdType, WORD wStartTSN, int iCnt, std : : vector<STTaskDetailBasicData>& vtRes)
+QueryTdDataByElec(int iSptID, BYTE ucTdType, int iStartElec, int iEndElec, std : : vector<STTaskDetailBasicData>& vtRes)
+QueryElecMaxWellDepthByCN(CString strScriptCN, BYTE ucTdType, STElecCoordinatesInfoHead& stElecInfoHead)
+QueryElecCoordinatesDataByCN(CString strScriptCN, BYTE ucTdType, WORD wStartTSN, int iCnt, std : : vector<STElecCoordinatesInfoBody>& vtRes)
+QueryTdAttrToCtrl(CListCtrl& listAttr, int iTaskID)
+QueryTdDataToCtrl(CListCtrl& listData, int iTaskID, int iSptType, int iTestType)
+QueryOnLineTdAttrToCtrl(CListCtrl& listAttr, STTaskListItem taskItem, STRemTaskArg *pstTaskArg)
+QueryOnLineTdAttrFromSev(STRemTaskTable stTaskTable, STRemTaskArg *pstTaskArg)
+QueryOnLineTdRgFromSev(STRemTaskArg stTaskArg, char *pRg)
+QueryOnLineElecInfoFromSev(STRemTaskArg stTaskArg, char* pElecInfo)
+QueryOnLineTdDataFromSev(STRemTaskArg stTaskArg, UINT32 uiStartPoint, UINT32 uiEndPoint, char *pData)
+QueryOnLineTdDataToCtrl(STRemTaskArg stTaskArg, std : : vector<STTaskDetailBasicData>& vtData)
+InitialTaskTreeCtrl(CTreeCtrl& taskTree,int iSptType)
+InitOnLineTaskTreeCtrl(CTreeCtrl& taskTree, int iSptType, std : : map<CString, STRemTaskTable> mapTaskList, HWND hWnd)
+QueryTimerTaskValiad(std : : vector<STTimerTask>& vtTimerTask, const SYSTEMTIME &sysCurTime)
+DeleteTimerTask(const std : : vector<int>& vtTask)
+DeleteTimerTask(UINT32 uiTDID)
+QueryTdBrowseInfo(std : : vector<STTdBrowseInfo>& vtTdBrowseInfo, bool bIsQueryTimerTd=false)
+QueryTdBrowseInfo(std : : vector<STTdBrowseInfo>& vtTdBrowseInfo, int iSptType, int iType ,bool bIsQueryTimerTd=false)
+AddTimerTask(int iTaskID, CString strTaskName, CString strTime,CString strPlcID)
+InsertPlcStatusData(const STRemPlcDataInfo* pRemPlcData)
+QueryPlcStatusData(std : : vector<STPlcStatusInfo>& vtPlcStatus)
+DeleteOldPlcStatusData()
+QueryTaskPacketAttr(int& iLoopTime, int& iInterval, CString& strPlcID)
+QueryTaskPacketInfo(std : : vector<STTdBrowseInfo>& vtTdBrowseInfo)
+InsertTaskPacketInfo(const std : : vector<STTdBrowseInfo>& vtTdBrowseInfo, const STTaskPacketAttr& stAttr)
+CreateSigTaskByAuto(const STTdBrowseInfo& stBasicTask, CString strTime, STTdBrowseInfo& stNewTask)
+CreateTaskPacket(const std : : vector<STTdBrowseInfo>& vtBasicTaskPacket, CString strSysTime, std : : vector<STTdBrowseInfo>& vtNewTaskPacket)
+QueryARByTdID(DWORD dwTdID)
+AdjustParam()
+SetCurrentTimeRange(time_t tStartTime, time_t tEndTime)
+unsigned int m_uiDevID
}
class TdManager {
+CLinkList<CTestingData*> m_tdLinkList
+_ConnectionPtr m_pConnection
+FILE *m_pFile
+CString m_log
+DeleteSPCETd(DWORD dwID)
+DeleteSP3DTd(DWORD dwID)
+DeleteSP2DTd(DWORD dwID)
+DeleteRsp3DTd(DWORD dwID)
+DeleteIpsp3DTd(DWORD dwID)
+CheckTdExist(CString szPrCN, CString szTzCN, CString szTdCN, CDevice* const pDev,DWORD *TdId)
+OnlineCheckTdExist(CString szTdID, CString szDevSN, DWORD *TdId)
+OnlineCheckElecInfoExist(CString strTdID, CString szDevSN)
+ImportTdHeadToDB(DWORD dwTzID, CString szHeadFile, CDevice* const pDev,DWORD* pExTdID = NULL)
+Import2DTdOrgToDB(DWORD dwTdID, CString szOrgFile, CDevice* const pDev)
+ImportCETdOrgToDB(DWORD dwTdID, CString szOrgFile, CDevice* const pDev)
+Import3DTdOrgToDB(DWORD dwTdID, CString szOrgFile, CDevice* const pDev)
+Import2DTdConToDB(DWORD dwTdID, CString szDatFile, CDevice* const pDev, int* pTSN=NULL)
+ImportCETdConToDB(DWORD dwTdID, CString szDatFile, CDevice* const pDev)
+Import3DTdConToDB(DWORD dwTdID, CString szDatFile, CDevice* const pDev, int* pTSN = NULL)
+Import2DGRToDB(DWORD dwTdID, CString szGRFile, CDevice* const pDev)
+Import3DGRToDB(DWORD dwTdID, CString szGRFile)
+ImportCETGRToDB(DWORD dwTdID, CString szGRFile)
+UploadCETdFromDev(CString szPrCN, CString szTzCN, CString szTdCN, CString strSubTdCN, CDevice* const pDev)
+Upload2DTdFromDev(CString szPrCN, CString szTzCN, CString szTdCN, CString strSubTdCN, CDevice* const pDev)
+Upload3DTdFromDev(CString szPrCN, CString szTzCN, CString szTdCN, CString strSubTdCN, CDevice* const pDev)
+UploadWellTdFromDev(CString szPrCN, CString szTzCN, CString szTdCN, CString strSubTdCN, CDevice* const pDev)
+DeleteTdInDev(CString szPrCN, CString szTzCN, CString szTdCN, CDevice* const pDev)
+InitialTDListByTzForSyn(CListCtrl &tdList, CString szDeSN, CString szTzCN)
+InitialTDListByProForSyn(CListCtrl &tdList, CString szDeSN, CString szPrCN)
+InitialTDListByOnLineForSyn(CListCtrl &tdList, CString szDeSN, UINT32 &uiTotNum)
+InitialDevListByOnLineForSyn(CListCtrl &tdList, CString szDeSN,STSynDevParam *ptLocalDevParam)
+InitialCableListByOnLineForSyn(CListCtrl &tdList, CString szDeSN, STRemCableCallInfo *ptLocalCableInfo)
+OnlineSevTDListSynToDB(STRemTaskArg *tTaskArg, CString szDeSN)
+OnLineImportTdHeadToDB(STRemTaskArg *tTaskArg, CString szDevSN)
+Convert2DTo3D(DWORD dwTzHandle)
+DeleteObjInMem(DWORD dwHandle)
+DeleteRspCETd(DWORD dwID)
+DeleteIpspCETd(DWORD dwID)
+DeleteRsp2DTd(DWORD dwID)
+DeleteIpsp2DTd(DWORD dwID)
+GetTestingData(DWORD dwHandle)
+ShowTdListByTz(DWORD dwTzHandle, CListCtrl& tdList)
+ShowTd2DListByTz(DWORD dwTzHandle, int iEAmount, float fEDistance, int iAR, CListCtrl& tdList)
+ShowTdListByDev(DWORD dwDevHandle, CListCtrl& tdList)
+ImportTdSpecAttr(const CStringArray& strAttrArray, int iDataType, DWORD dwChID,int iTSN)
+ShowTdListByProject(DWORD dwProHandle, CListCtrl& tdList)
+GetTaskAttr(DWORD dwHandle, DWORD& dwTdID, int& iStyle)
}
class CTestingData {
+CDevice* m_pDevice
+DWORD m_dwID
+CString m_szTdName
+CString m_szTdCN
+CString m_szTLocation
+CString m_szPrCN
+CString m_szTzName
+CString m_szTzCN
+DWORD m_dwTzID
+DWORD m_dwSCID
+CString m_szSCCN
+CString m_szSName
+int m_iSType
+int m_iTType
+int m_iTMode
+int m_iEAmount
+int m_iTPAmount
+int m_iCHAmount
+int m_iN
+int m_iTRWave
+int m_iTRFrequency
+int m_iIFrequency
+int m_iSAFrequency
+int m_iCLayout
+float m_fEspace
+float m_fEdistance
+CString m_strRect
+CString m_strValidElec
+CString m_strValildLayer
+int m_iStartElec
+int m_iEndElec
+int m_iStartLayer
+int m_iEndLayer
+int m_iRollCnt
+int m_iSkipCable
+int m_iAR
+int m_iTxWave
+int m_iTxPeriod
+int m_iSAInterval
+int m_iWeather
+int m_iWDIR
+float m_fTemperature
+float m_fHeight
+float m_fHumidity
+CString m_strCdate
+CString m_strCtime
+CString m_strTdate
+CString m_strTtime
+int m_iRdirection
+int m_iCRtime
+CString m_strPM
+CString m_strOP
+CString m_strQA
+int m_iTestGRFlag
+int m_iLineDirection
+int m_iCreateTime
+int m_iSTime
+int m_iETime
+int m_iTTimer
+int m_iTdStatus
+int m_iDesn
+int m_iStacking
+int m_iTestPeriod
+int m_iCableLayout
+int m_iSAInterval
+int m_iEamount
+int m_iTestPeriod
+int m_iCableLayout
+int m_iStartElec
+int m_iEndElec
+int m_iStacking
+int m_iTxWave
+int m_iTxPeriod
+int m_iSAInterval
+int m_iEAmount
+float m_fEspace
+float m_fHoleSpace
+unsigned int m_uiDevID
+unsigned int m_uiTimerTime
+BYTE m_ucOrgFlg
+BYTE m_ucTestGRFlag
+UpdataTopography(int f_disType ,int f_start,CListCtrl &f_list)
+ExcuteSql(CString f_sql)
+GetTimeWindowList(CListCtrl &f_list)
+ShowTimeWindow(CListCtrl &tdConList, int iTsn)
+GetORGCStringToArray(CString f_SrcString, CStringArray *f_array)
+FreeWindowsTime()
+GetPeriod()
+GetTimeWindowInfo(std : : vector<STSigTWInfo>& vtTWInfo)
+CreateWindowsTime()
+CalculateTimeWindows(struct _WinTimeList f_winTimeList, CStringArray *v_orgData, int f_TRwave, int f_Tcycle, int f_Sample, int f_interation, int f_industrial)
+CalculateTWInfo(CStringArray *v_orgData, int nFrenquence)
+DisplayIpCurveGraph()
}
DataOperator --> TdManager
DataOperator --> TaskDataOper
TaskDataOper --> TdManager
DataOperator --> CTestingData
TaskDataOper --> CTestingData
TdManager --> CTestingData
```
**图源**
- [DataOperator.h](file://h/DataOperator.h)
- [TaskDataOper.h](file://h/TaskDataOper.h)
- [TdManager.h](file://h/TdManager.h)
- [TestingData.h](file://h/TestingData.h)
**节源**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
## 详细组件分析
### DataOperator类分析
DataOperator类是数据操作的核心,负责与数据库的交互,实现数据的读取、写入和管理。通过调用TdManager类的方法,DataOperator能够获取和更新测试数据,并通过TaskDataOper类处理任务数据的序列化和反序列化。DataOperator还支持多种数据格式的导出,包括Excel、CSV、TXT和URF,满足了不同用户的需求。
#### 数据读写与管理
DataOperator通过ADO数据库接口与数据库进行交互,实现了数据的高效读写。在数据读取过程中,DataOperator首先通过SQL查询获取数据记录集,然后将记录集中的数据转换为应用程序内部的数据结构。在数据写入过程中,DataOperator将应用程序内部的数据结构转换为SQL语句,通过执行SQL语句将数据持久化到数据库中。这一过程确保了数据的一致性和完整性。
```mermaid
flowchart TD
Start([开始]) --> CheckConnection["检查数据库连接"]
CheckConnection --> |连接正常| QueryData["执行SQL查询"]
CheckConnection --> |连接异常| HandleError["处理异常"]
QueryData --> ProcessData["处理查询结果"]
ProcessData --> ConvertData["转换为内部数据结构"]
ConvertData --> End([结束])
HandleError --> End
```
**图源**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
**节源**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
#### 与TdManager的协同工作
DataOperator与TdManager的协同工作是实现数据管理的关键。TdManager负责测试数据的加载、保存和格式转换,而DataOperator则负责与数据库的交互。当需要加载测试数据时,DataOperator调用TdManager的相应方法,TdManager从数据库中读取数据并返回给DataOperator。当需要保存测试数据时,DataOperator将数据传递给TdManagerTdManager将数据写入数据库。这种协同工作模式确保了数据操作的高效性和可靠性。
```mermaid
sequenceDiagram
participant DataOperator
participant TdManager
participant Database
DataOperator->>TdManager : 请求加载测试数据
TdManager->>Database : 执行SQL查询
Database-->>TdManager : 返回查询结果
TdManager-->>DataOperator : 返回测试数据
DataOperator->>TdManager : 请求保存测试数据
TdManager->>Database : 执行SQL插入
Database-->>TdManager : 确认保存成功
TdManager-->>DataOperator : 确认保存成功
```
**图源**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
**节源**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
### TaskDataOper类分析
TaskDataOper类专注于任务数据的操作流程,包括数据的序列化、反序列化及内存管理策略。通过定义一系列方法,TaskDataOper实现了任务数据的高效处理,确保了数据操作的稳定性和可靠性。
#### 任务数据操作流程
TaskDataOper类通过定义一系列方法,实现了任务数据的序列化、反序列化及内存管理。在数据序列化过程中,TaskDataOper将应用程序内部的数据结构转换为适合存储的格式,如JSON或XML。在数据反序列化过程中,TaskDataOper将存储的格式转换回应用程序内部的数据结构。内存管理策略则确保了数据在内存中的高效使用,避免了内存泄漏和性能下降。
```mermaid
flowchart TD
Start([开始]) --> SerializeData["序列化数据"]
SerializeData --> StoreData["存储数据"]
StoreData --> DeserializeData["反序列化数据"]
DeserializeData --> UseData["使用数据"]
UseData --> ManageMemory["管理内存"]
ManageMemory --> End([结束])
```
**图源**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
**节源**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
## 依赖关系分析
DataOperator模块的依赖关系清晰,主要依赖于TdManager和TaskDataOper两个模块。TdManager负责测试数据的管理,而TaskDataOper负责任务数据的操作。DataOperator通过调用这两个模块的方法,实现了数据的读写和管理。此外,DataOperator还依赖于ADO数据库接口,用于与数据库的交互。这种依赖关系确保了模块间的松耦合,提高了代码的可维护性和可扩展性。
```mermaid
graph TD
DataOperator --> TdManager
DataOperator --> TaskDataOper
DataOperator --> ADO[ADO数据库接口]
TdManager --> ADO
TaskDataOper --> ADO
```
**图源**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
**节源**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
## 性能考虑
在设计DataOperator模块时,充分考虑了性能优化。通过批量处理和缓存机制,提高了数据操作的效率。批量处理减少了数据库交互的次数,降低了网络延迟和数据库负载。缓存机制则减少了对数据库的频繁访问,提高了数据读取的速度。此外,通过优化SQL查询语句和索引,进一步提升了数据操作的性能。
## 故障排除指南
### 数据丢失
数据丢失可能是由于数据库连接异常或数据写入失败导致的。在遇到数据丢失问题时,首先检查数据库连接是否正常,然后检查数据写入的日志,确认是否有写入失败的记录。如果发现写入失败,可以尝试重新执行写入操作,或检查数据库的存储空间是否充足。
### 格式不兼容
格式不兼容问题通常出现在数据导出时。在导出数据时,确保选择正确的导出格式,并检查导出文件的编码是否与目标系统兼容。如果遇到格式不兼容问题,可以尝试使用不同的导出工具或转换工具,将数据转换为兼容的格式。
## 结论
DataOperator模块是GeomativeStudio软件中不可或缺的一部分,通过与TdManager和TaskDataOper模块的协同工作,实现了高效的数据读写、处理与管理。该模块不仅支持多种数据格式的导出,还通过批量处理和缓存机制,提高了数据操作的性能。在实际应用中,DataOperator模块展现了其强大的数据处理能力和稳定性,为用户提供了可靠的数据管理解决方案。
@@ -0,0 +1,378 @@
# DeviceOperator
<cite>
**本文引用的文件**
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
- [DetcGD10Dev.h](file://h/DetcGD10Dev.h)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp)
- [DevOperator.h](file://h/DevOperator.h)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp)
- [GD10OperCmd.h](file://h/GD10OperCmd.h)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
- [Device.h](file://h/Device.h)
- [DevManager.h](file://h/DevManager.h)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文围绕 DeviceOperator 模块,系统阐述 GD10 设备的检测、连接、参数配置与状态监控的实现细节。重点覆盖:
- DetcGD10Dev 如何通过 USB 可移动盘符识别 GD10/GD20 主机并建立“逻辑连接”(挂载路径)。
- DevOperator 如何封装底层指令下发与响应解析,协调 DevManager 完成设备初始化、参数修改、升级流程与状态展示。
- GD10OperCmd 命令协议封装,用于在主机侧模拟对 GD 设备内部文件系统的操作。
- 异常处理与调试方法,安全与权限控制,以及性能优化建议(连接池、异步通信)。
## 项目结构
DeviceOperator 涉及的关键文件与职责如下:
- DetcGD10Dev:设备检测与挂载路径管理,提供“已连接”状态与设备路径。
- DevOperator:设备操作入口,负责树形视图初始化、参数修改、升级流程、权限校验与日志记录。
- GD10OperCmd:命令协议封装,负责在主机侧对 GD 设备内部 XML/文件进行增删改查。
- Device:设备抽象,封装串口命令执行、文件收发、参数读取与状态维护。
- DevManager:设备生命周期与远程设备集合管理。
```mermaid
graph TB
subgraph "设备检测层"
DGD["DetcGD10Dev<br/>检测GD10/GD20设备"]
end
subgraph "设备操作层"
DOp["DevOperator<br/>设备操作入口"]
GOC["GD10OperCmd<br/>命令协议封装"]
end
subgraph "设备抽象层"
Dev["CDevice<br/>串口命令/文件收发"]
DM["DevManager<br/>设备管理"]
end
DGD --> DOp
DOp --> Dev
DOp --> DM
GOC --> DGD
GOC --> Dev
```
图表来源
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L1-L189)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1-L200)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L1-L120)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L1-L120)
- [DevManager.h](file://h/DevManager.h#L1-L69)
章节来源
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L1-L189)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1-L200)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L1-L120)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L1-L120)
- [DevManager.h](file://h/DevManager.h#L1-L69)
## 核心组件
- DetcGD10Dev:单例,负责扫描可移动盘符,匹配 GD10/GD20 设备卷标,记录设备路径与连接状态;提供日志输出能力。
- DevOperator:封装设备树初始化、参数修改、升级流程、权限校验与日志记录;与 DevManager 协作完成设备注册/注销与状态展示。
- GD10OperCmd:命令封装,提供工程/测区/脚本/任务的增删改查与参数设置;在主机侧对 GD 内部 XML 文件进行操作。
- CDevice:设备抽象,封装串口命令执行、文件收发、参数读取、状态维护与日志记录;提供“执行命令带轮询”的超时控制。
- DevManager:维护在线/离线设备列表、远程设备集合、设备句柄映射与设备对象生命周期。
章节来源
- [DetcGD10Dev.h](file://h/DetcGD10Dev.h#L1-L38)
- [DevOperator.h](file://h/DevOperator.h#L1-L59)
- [GD10OperCmd.h](file://h/GD10OperCmd.h#L1-L55)
- [Device.h](file://h/Device.h#L1-L128)
- [DevManager.h](file://h/DevManager.h#L1-L69)
## 架构总览
DeviceOperator 的整体交互流程如下:
- 设备检测:DetcGD10Dev 扫描可移动盘符,匹配 GD 设备卷标,返回挂载路径并更新连接状态。
- 设备操作:DevOperator 依据选择的设备项,调用 DevManager 获取设备对象,执行参数修改、升级、权限校验等操作。
- 命令封装:GD10OperCmd 在主机侧对 GD 内部 XML/文件进行增删改查,确保 GD 设备侧数据一致性。
- 设备抽象:CDevice 封装串口命令执行与文件传输,提供超时控制与日志记录。
```mermaid
sequenceDiagram
participant UI as "界面"
participant DO as "DevOperator"
participant DM as "DevManager"
participant D as "CDevice"
participant GD as "GD10OperCmd"
participant DET as "DetcGD10Dev"
UI->>DO : 选择设备项
DO->>DM : GetDeviceByID/GetDevice
DM-->>DO : 返回设备对象
alt 参数修改
DO->>D : ModifyParameter()
D-->>DO : 成功/失败
else 升级流程
DO->>DO : StartDeviceUpgrade()
DO->>D : 执行升级命令/文件传输
D-->>DO : 结果
end
alt 需要主机侧操作
DO->>GD : 调用命令封装
GD->>DET : 读取设备路径
GD-->>DO : 成功/失败
end
```
图表来源
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L384-L433)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1139-L1262)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L51-L105)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L1-L120)
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L1-L80)
## 详细组件分析
### DetcGD10DevGD10/GD20 设备检测与连接
- 功能要点
- 单例模式,提供 IsGD10DevConnect 与 GetGD10DevAddr 接口。
- 通过扫描 GetLogicalDriveStrings 返回的可移动盘符,匹配 GD10/GD20 卷标或特定路径特征,确定设备挂载路径。
- 提供 CompareDriverName 通过 GetVolumeInformation 获取卷标名进行比对。
- 日志输出到 detect_gd20_log.txt,便于调试设备检测问题。
- 关键流程
- DetectGD10Dev:根据应用多通道配置选择 GD20 或 GD10 设备名,调用 FindUsbDevice 获取路径并更新连接状态。
- FindUsbDevice:遍历可移动盘符,尝试匹配卷标或特定目录特征,返回第一个匹配路径。
- CompareDriverName:读取卷标名并与期望名称比较,返回布尔结果。
- 异常与调试
- 若打开日志失败,弹出提示;若扫描失败,返回空路径。
- 建议:在 UI 层显示检测进度与失败原因,避免静默失败。
```mermaid
flowchart TD
Start(["开始检测"]) --> Scan["扫描可移动盘符"]
Scan --> Match{"匹配GD10/GD20卷标?"}
Match --> |是| Found["返回设备路径"]
Match --> |否| Next["继续扫描下一个盘符"]
Next --> Scan
Found --> Update["更新连接状态与路径"]
Update --> Log["写入检测日志"]
Log --> End(["结束"])
```
图表来源
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L61-L175)
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L177-L189)
章节来源
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L1-L189)
- [DetcGD10Dev.h](file://h/DetcGD10Dev.h#L1-L38)
### DevOperator:设备操作入口与与 DevManager 协作
- 功能要点
- 初始化导航设备视图,填充在线/离线/新设备树节点,绑定设备句柄与状态图标。
- 设备升级:创建升级线程,调用 StartDeviceUpgrade,处理升级结果与提示。
- 参数修改:调用设备对象 ModifyParameter 并刷新详情列表。
- 注册/注销:调用设备对象 Register/Unregister,更新树节点与状态。
- 权限校验:GD10 密码校验与数据库密码存储,支持二次确认与日志记录。
- 与 DevManager 协作
- 通过 GetDeviceByID/GetDevice 获取设备对象。
- 添加/删除设备对象,更新树节点与状态。
- 异常与调试
- 创建线程失败、解析设备信息失败等场景均弹出提示并返回失败码。
- 建议:在 UI 中显示升级进度条与错误码,便于定位问题。
```mermaid
sequenceDiagram
participant UI as "界面"
participant DO as "DevOperator"
participant DM as "DevManager"
participant D as "CDevice"
UI->>DO : 点击“注册新设备”
DO->>DM : GetDevice(szDevSN)
DM-->>DO : 返回设备对象
DO->>D : Register()
alt 成功
DO->>DM : AddDevice(pDev)
DO->>DO : 刷新树节点与状态
else 失败
DO-->>UI : 返回失败
end
```
图表来源
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1139-L1262)
- [DevManager.h](file://h/DevManager.h#L1-L69)
章节来源
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1-L200)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1139-L1262)
- [DevOperator.h](file://h/DevOperator.h#L1-L59)
- [DevManager.h](file://h/DevManager.h#L1-L69)
### GD10OperCmd:命令协议封装与主机侧操作
- 功能要点
- 工程/测区/脚本/任务的增删改查,参数设置,用户注销等。
- 通过 DetcGD10Dev 获取 GD 设备挂载路径,直接对 SD 卡内 XML/文件进行操作。
- 对 XML 文件的读取、查找、新增/删除元素、保存等操作均有错误日志记录。
- 关键接口
- project_add/project_delete/testzone_add/testzone_delete/script_add/script_delete/meas_delete/set_param/unregister_user/loadDeviceMarkDataFromGD。
- 安全与日志
- 所有关键操作均记录日志,便于审计与回溯。
- 在非 USB 传输模式下会拒绝执行命令,防止误操作。
```mermaid
classDiagram
class CGD10OperCmd {
+GetInstance()
+project_add(mac, projectcn)
+project_delete(mac, projectcn)
+testzone_add(projectcn, testzonecn, type)
+testzone_delete(projectcn, testzonecn)
+script_add(scriptcn, scriptname, mediumid)
+script_delete(scriptcn)
+meas_delete(projectcn, testzonecn, measuringcn)
+set_param(strParam)
+unregister_user(mac)
+loadDeviceMarkDataFromGD()
-AddProjectInLocalHost()
-AddProjectInMacXml()
-DelProjectInLocalHost()
-DelProjectInMacXml()
-DeleteTaskInTz()
-DeleteTaskFile()
}
class CDetcGD10Dev {
+GetInstance()
+IsGD10DevConnect()
+GetGD10DevAddr()
+DetectGD10Dev()
}
CGD10OperCmd --> CDetcGD10Dev : "使用设备路径"
```
图表来源
- [GD10OperCmd.h](file://h/GD10OperCmd.h#L1-L55)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L1-L120)
- [DetcGD10Dev.h](file://h/DetcGD10Dev.h#L1-L38)
章节来源
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L1-L200)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L800-L1213)
- [GD10OperCmd.h](file://h/GD10OperCmd.h#L1-L55)
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L1-L80)
### CDevice:串口命令执行与文件传输
- 功能要点
- ExecuteOrder/ExecuteSignleOrder:向 GD 设备发送命令并等待特定标志,内置轮询与超时控制。
- SendFile/ReceiveFile:文件上传/下载,支持重试与错误处理。
- GetSynInfo/GetGRInfo/ShowGRInfo/ShowACInfo:数据同步与结果显示。
- Register/Unregister/ModifyParameter/ShowCableHeadInfoDlg:设备注册、参数修改与界面交互。
- 超时与重试
- 默认轮询次数与间隔可配置,避免长时间阻塞。
- 文件传输失败自动重试,提升鲁棒性。
- 日志与状态
- 统一的日志输出接口,便于问题定位。
- 设备状态(在线/离线/新)与图标映射。
```mermaid
flowchart TD
Enter(["进入命令执行"]) --> Clear["清空收发缓冲"]
Clear --> Send["发送命令字符串"]
Send --> Poll["轮询等待标志"]
Poll --> Timeout{"超时/成功?"}
Timeout --> |成功| Parse["解析响应"]
Timeout --> |超时| Retry{"是否重试?"}
Retry --> |是| Send
Retry --> |否| Fail["返回失败"]
Parse --> Done(["返回成功"])
```
图表来源
- [Device.h](file://h/Device.h#L1-L128)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L1-L120)
章节来源
- [Device.h](file://h/Device.h#L1-L128)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L1-L200)
### DevManager:设备生命周期与远程设备管理
- 功能要点
- 在线/离线设备列表获取与管理。
- 远程设备集合(STSigRemoteDev)的增删与查询。
- 设备对象的添加/删除与句柄映射。
- 与 DevOperator 协作
- DevOperator 通过 DevManager 获取设备对象并执行操作。
- 更新远程设备集合,驱动 UI 列表刷新。
章节来源
- [DevManager.h](file://h/DevManager.h#L1-L69)
## 依赖关系分析
- DetcGD10Dev 与 GD10OperCmdGD10OperCmd 在执行前依赖 DetcGD10Dev 的连接状态与设备路径。
- DevOperator 与 DevManager/CDeviceDevOperator 通过 DevManager 获取设备对象,再调用 CDevice 的命令与文件操作。
- GD10OperCmd 与 DetcGD10DevGD10OperCmd 通过 DetcGD10Dev 的单例获取设备挂载路径,直接对 SD 卡内文件进行操作。
- CDevice 与 GD10OperCmd:两者均面向 GD 设备,前者侧重命令与文件传输,后者侧重主机侧对 GD 内部数据结构的维护。
```mermaid
graph LR
DGD["DetcGD10Dev"] --> GOC["GD10OperCmd"]
DOp["DevOperator"] --> DM["DevManager"]
DOp --> Dev["CDevice"]
GOC --> DGD
Dev --> DM
```
图表来源
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L1-L80)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L1-L120)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1-L200)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L1-L120)
- [DevManager.h](file://h/DevManager.h#L1-L69)
## 性能考量
- 连接池与并发
- 建议为串口通信引入连接池,避免频繁打开/关闭串口导致的握手延迟。
- 对于文件传输与升级流程,采用分块传输与进度回调,减少 UI 卡顿。
- 异步通信
- 将长耗时操作(如升级、文件传输)放入后台线程,主线程仅负责 UI 更新与状态提示。
- 使用事件/消息队列传递结果,避免阻塞 UI 线程。
- 超时与重试策略
- 命令轮询与文件传输应设置合理的超时阈值与重试次数,避免无限等待。
- 对网络不稳定或设备繁忙的情况,增加退避重试与降速策略。
- 缓存与预热
- 对设备参数与常用配置进行缓存,减少重复查询。
- 在设备连接后预热串口与文件传输通道,降低首次操作延迟。
## 故障排查指南
- 设备未检测到
- 检查 DetcGD10Dev 的 DetectGD10Dev 是否返回有效路径;确认卷标名与设备类型匹配。
- 查看 detect_gd20_log.txt 与 device_log.txt 的错误日志。
- 升级失败
- 确认 StartDeviceUpgrade 返回码与提示信息;检查升级包完整性与版本匹配。
- 若 GD10OperCmd 报告文件写入失败,检查 SD 卡空间与权限。
- 命令执行超时
- 调整 CDevice 的轮询次数与间隔;检查串口波特率与线缆质量。
- 对于复杂命令,拆分为多个小命令并增加中间态检查。
- 权限校验失败
- 确认 GD10 密码输入正确;检查数据库中密码记录是否更新成功。
- 若多次失败,建议清理缓存并重新输入。
- 文件传输失败
- 检查 SD 卡路径是否存在;确认文件名大小写与扩展名一致。
- 增加重试次数与断点续传机制。
章节来源
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L177-L189)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L1-L120)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1517-L1599)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L1-L120)
## 结论
DeviceOperator 模块通过 DetcGD10Dev 的设备检测、DevOperator 的操作编排、GD10OperCmd 的命令封装与 CDevice 的底层通信,形成了完整的 GD10 设备管理闭环。模块具备良好的日志记录与异常处理能力,建议进一步引入连接池、异步通信与缓存机制,以提升性能与用户体验。
## 附录
- 安全性建议
- 权限验证:GD10 密码校验与数据库存储,避免未授权访问。
- 操作审计:所有关键操作均写入日志,便于追踪与回溯。
- 输入校验:对命令参数与文件路径进行严格校验,防止注入与越权。
- 性能优化清单
- 串口连接池与复用。
- 异步升级与文件传输。
- 超时与重试策略优化。
- UI 进度反馈与中断机制。
@@ -0,0 +1,225 @@
# ExecutionOperator
<cite>
**本文档中引用的文件**
- [ExecOperator.cpp](file://cpp/Operator/ExecOperator.cpp)
- [ExecOperator.h](file://h/ExecOperator.h)
- [ExecManager.cpp](file://cpp/Managers/ExecManager.cpp)
- [ExecManager.h](file://h/ExecManager.h)
- [DialMeasureData.cpp](file://cpp/Views/DialMeasureData.cpp)
- [DialMeasureData.h](file://h/DialMeasureData.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [TaskDataOper.h](file://h/TaskDataOper.h)
- [DialOfflineDeviceTaskManager.cpp](file://cpp/Views/DialOfflineDeviceTaskManager.cpp)
- [DialOfflineDeviceTaskManager.h](file://h/DialOfflineDeviceTaskManager.h)
</cite>
## 目录
1. [引言](#引言)
2. [ExecutionOperator职责与实现](#executionoperator职责与实现)
3. [与ExecManager的协作机制](#与execmanager的协作机制)
4. [用户交互事件处理流程](#用户交互事件处理流程)
5. [异常情况恢复策略](#异常情况恢复策略)
6. [性能监控指标与优化建议](#性能监控指标与优化建议)
7. [离线模式执行任务的实现细节](#离线模式执行任务的实现细节)
8. [结论](#结论)
## 引言
ExecutionOperator是Geomative Studio系统中负责测量任务执行过程的核心组件。它协调设备、脚本和数据管理组件,完成测量任务的启动、暂停、恢复和终止。本文档详细阐述了ExecutionOperator的职责与实现,说明其如何与ExecManager协作管理任务状态机、实时数据采集和进度反馈,并结合UI组件(如DialMeasureData)说明用户交互事件的处理流程。此外,文档还提供了任务执行过程中异常情况的恢复策略、性能监控指标与优化建议,以及支持离线模式执行任务的实现细节。
## ExecutionOperator职责与实现
ExecutionOperator的主要职责是协调设备、脚本和数据管理组件,完成测量任务的启动、暂停、恢复和终止。它通过ExecManager与底层设备进行通信,确保测量任务的顺利执行。
ExecutionOperator的实现主要集中在`ExecOperator.cpp``ExecOperator.h`文件中。`CExecOperator`类的构造函数接受一个数据库连接指针,用于与数据库进行交互。`ExecRSPTest`方法是执行电阻率测试的入口点,它创建并初始化`COpExec2DRSPTestSetDlg`对话框,然后根据用户选择的测试类型调用ExecManager的相应方法。
```mermaid
classDiagram
class CExecOperator {
+CExecOperator(_ConnectionPtr& pConnection)
+~CExecOperator()
+ExecRSPTest()
+InitialExec2DRSPTestDlg(COpExec2DRSPTestSetDlg* pOpExec2DRSPTestSetDlg)
}
class COpExec2DRSPTestSetDlg {
+Create()
+ShowWindow()
+RunModalLoop()
+DestroyWindow()
}
CExecOperator --> COpExec2DRSPTestSetDlg : "创建并初始化"
```
**Diagram sources**
- [ExecOperator.cpp](file://cpp/Operator/ExecOperator.cpp#L26-L72)
- [ExecOperator.h](file://h/ExecOperator.h#L23-L26)
**Section sources**
- [ExecOperator.cpp](file://cpp/Operator/ExecOperator.cpp#L1-L72)
- [ExecOperator.h](file://h/ExecOperator.h#L1-L37)
## 与ExecManager的协作机制
ExecutionOperator与ExecManager紧密协作,共同完成测量任务的管理。ExecManager负责具体的任务执行逻辑,包括初始化测量、发送测量命令和处理测量结果。
`CExecManager`类提供了`Exec2DRSPTest``ExecCERSPTest`方法,分别用于执行2D和1D电阻率测试。这些方法首先创建相应的测量数据对象(`CRsp2DTd``CRspCETd`),然后调用`Save2DRSPSetInfo``SaveCERSPSetInfo`方法将测量设置信息保存到对象中。接着,将测量头信息保存到文件,并通过设备的`SendFile`方法将文件发送到主机。最后,调用`InitialMeasure`方法初始化测量,并创建相应的测量对话框(`COpExec2DRSPTestDlg``COpExecCERSPTestDlg`)来显示测量进度。
```mermaid
sequenceDiagram
participant ExecutionOperator
participant ExecManager
participant Device
participant MeasurementDialog
ExecutionOperator->>ExecManager : Exec2DRSPTest()
ExecManager->>ExecManager : 创建CRsp2DTd对象
ExecManager->>ExecManager : 保存测量设置信息
ExecManager->>ExecManager : 保存头信息到文件
ExecManager->>Device : SendFile()
Device-->>ExecManager : 文件发送成功
ExecManager->>ExecManager : InitialMeasure()
ExecManager->>MeasurementDialog : 创建并显示对话框
MeasurementDialog-->>ExecManager : 测量完成
ExecManager-->>ExecutionOperator : 返回结果
```
**Diagram sources**
- [ExecManager.cpp](file://cpp/Managers/ExecManager.cpp#L483-L548)
- [ExecManager.h](file://h/ExecManager.h#L26-L27)
**Section sources**
- [ExecManager.cpp](file://cpp/Managers/ExecManager.cpp#L483-L548)
- [ExecManager.h](file://h/ExecManager.h#L26-L27)
## 用户交互事件处理流程
用户交互事件的处理主要由`DialMeasureData`类负责。该类处理用户在测量界面上的各种操作,如启动测量、暂停测量、从当前位置继续测量等。
`CDialMeasureData`类的`OnMeasureAll`方法处理“启动测量”按钮的点击事件。它首先检查是否已经下载了测量配置,如果没有,则调用`OnMeasureDownloadMeasuCfg`方法下载配置。然后,更新任务的测试日期和时间,并根据测量类型打开相应的数据表。最后,设置按钮状态,准备开始测量。
```mermaid
flowchart TD
Start([开始测量]) --> CheckDownload{"已下载配置?"}
CheckDownload --> |否| Download[下载测量配置]
Download --> UpdateTime[更新测试日期和时间]
CheckDownload --> |是| UpdateTime
UpdateTime --> OpenTable{"测量类型"}
OpenTable --> |数据| OpenData[打开数据表]
OpenTable --> |接地电阻| ClearGR[清除接地电阻信息]
OpenData --> SetStatus[设置按钮状态]
ClearGR --> SetStatus
SetStatus --> End([准备测量])
```
**Diagram sources**
- [DialMeasureData.cpp](file://cpp/Views/DialMeasureData.cpp#L378-L497)
- [DialMeasureData.h](file://h/DialMeasureData.h#L61-L64)
**Section sources**
- [DialMeasureData.cpp](file://cpp/Views/DialMeasureData.cpp#L378-L497)
- [DialMeasureData.h](file://h/DialMeasureData.h#L61-L64)
## 异常情况恢复策略
在测量过程中,可能会遇到各种异常情况,如设备断开、数据校验失败等。系统提供了一系列恢复策略来应对这些异常。
当设备断开时,系统会尝试重新连接设备。如果重新连接失败,会显示错误消息并终止测量。对于数据校验失败的情况,系统会记录错误日志,并尝试重新发送数据包。如果多次尝试后仍然失败,会终止测量并提示用户检查设备连接。
```mermaid
stateDiagram-v2
[*] --> Idle
Idle --> Measuring : "启动测量"
Measuring --> DeviceDisconnected : "设备断开"
Measuring --> DataValidationFailed : "数据校验失败"
DeviceDisconnected --> Reconnect : "尝试重新连接"
Reconnect --> Measuring : "连接成功"
Reconnect --> Error : "连接失败"
DataValidationFailed --> Retry : "重新发送"
Retry --> Measuring : "发送成功"
Retry --> Error : "重试次数超限"
Error --> Idle : "终止测量"
Measuring --> Completed : "测量完成"
Completed --> Idle : "结束"
```
**Diagram sources**
- [DialMeasureData.cpp](file://cpp/Views/DialMeasureData.cpp#L928-L1100)
- [DialMeasureData.h](file://h/DialMeasureData.h#L80-L81)
**Section sources**
- [DialMeasureData.cpp](file://cpp/Views/DialMeasureData.cpp#L928-L1100)
- [DialMeasureData.h](file://h/DialMeasureData.h#L80-L81)
## 性能监控指标与优化建议
系统提供了多种性能监控指标,包括采样频率、响应延迟等。这些指标可以帮助用户评估测量过程的性能,并进行相应的优化。
采样频率是指每秒采集的数据点数,它直接影响测量的精度和速度。响应延迟是指从发送测量命令到接收到测量结果的时间间隔,它反映了系统的实时性。
为了优化性能,建议采取以下措施:
1. 使用高速通信接口,如USB或以太网,以减少通信延迟。
2. 优化数据处理算法,减少CPU占用率。
3. 使用高效的数据库查询语句,减少数据访问时间。
4. 定期维护设备,确保设备处于最佳工作状态。
```mermaid
erDiagram
MEASUREMENT ||--o{ PERFORMANCE_METRICS : "包含"
PERFORMANCE_METRICS {
float sampling_frequency
float response_latency
float cpu_usage
float memory_usage
}
OPTIMIZATION_STRATEGIES ||--o{ PERFORMANCE_METRICS : "优化"
OPTIMIZATION_STRATEGIES {
string high_speed_interface
string optimized_algorithm
string efficient_query
string regular_maintenance
}
```
**Diagram sources**
- [DialMeasureData.cpp](file://cpp/Views/DialMeasureData.cpp#L948-L954)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L4314-L4332)
**Section sources**
- [DialMeasureData.cpp](file://cpp/Views/DialMeasureData.cpp#L948-L954)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L4314-L4332)
## 离线模式执行任务的实现细节
系统支持离线模式执行任务,允许用户在没有网络连接的情况下进行测量。离线模式的实现主要依赖于`DialOfflineDeviceTaskManager`类。
在离线模式下,测量数据首先保存在本地数据库中。当网络连接恢复后,用户可以手动上传数据到服务器。`CDialOfflineDeviceTaskManager`类提供了创建、删除、上传和管理离线任务的功能。
```mermaid
classDiagram
class CDialOfflineDeviceTaskManager {
+OnButtonCreateTask()
+OnButtonDelTask()
+OnButtonMeasureTask()
+OnBtnDataDownload()
+OnBtnCreateTimerTask()
+OnBtnManageTimerTask()
}
class CTaskDataOper {
+Create1DTask()
+Create2DTask()
+Create3DTask()
+DeleteTaskArray()
+InsertPlcStatusData()
}
CDialOfflineDeviceTaskManager --> CTaskDataOper : "使用"
```
**Diagram sources**
- [DialOfflineDeviceTaskManager.cpp](file://cpp/Views/DialOfflineDeviceTaskManager.cpp#L323-L325)
- [TaskDataOper.h](file://h/TaskDataOper.h#L344-L346)
**Section sources**
- [DialOfflineDeviceTaskManager.cpp](file://cpp/Views/DialOfflineDeviceTaskManager.cpp#L323-L325)
- [TaskDataOper.h](file://h/TaskDataOper.h#L344-L346)
## 结论
ExecutionOperator是Geomative Studio系统中测量任务执行的核心组件。它通过与ExecManager的紧密协作,实现了测量任务的启动、暂停、恢复和终止。系统提供了完善的用户交互事件处理流程、异常情况恢复策略、性能监控指标与优化建议,以及支持离线模式执行任务的实现细节。这些功能共同确保了测量任务的高效、可靠执行。
@@ -0,0 +1,168 @@
# Operator模块
<cite>
**Referenced Files in This Document**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [DataOperator.h](file://h/DataOperator.h)
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
- [DetcGD10Dev.h](file://h/DetcGD10Dev.h)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp)
- [DevOperator.h](file://h/DevOperator.h)
- [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp)
- [SptOperator.h](file://h/SptOperator.h)
- [ExecOperator.cpp](file://cpp/Operator/ExecOperator.cpp)
- [ExecOperator.h](file://h/ExecOperator.h)
- [SynOperator.cpp](file://cpp/Operator/SynOperator.cpp)
- [SynOperator.h](file://h/SynOperator.h)
- [InputPasswordDial.cpp](file://cpp/Operator/InputPasswordDial.cpp)
- [InputPasswordDial.h](file://h/InputPasswordDial.h)
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp)
- [DialCustomSptInput.h](file://h/DialCustomSptInput.h)
- [UpdateDataBase.cpp](file://cpp/Operator/UpdateDataBase.cpp)
- [UpdateDataBase.h](file://h/UpdateDataBase.h)
</cite>
## 目录
1. [DataOperator数据操作器](#dataoperator数据操作器)
2. [DetcGD10Dev设备检测器](#detcgd10dev设备检测器)
3. [DevOperator设备操作器](#devoperator设备操作器)
4. [SptOperator脚本操作器](#sptoperator脚本操作器)
5. [ExecOperator执行操作器](#execoperator执行操作器)
6. [SynOperator同步操作器](#synoperator同步操作器)
7. [对话框操作器](#对话框操作器)
8. [UpdateDataBase数据库升级器](#updatedatabase数据库升级器)
9. [操作器与管理器调用关系](#操作器与管理器调用关系)
## DataOperator数据操作器
DataOperator类负责处理应用程序中的数据读写操作,主要功能包括初始化导航数据视图、显示各类测试数据信息以及在数据库中创建和删除项目。该操作器通过ADO数据库连接与后端数据库进行交互,使用`_ConnectionPtr`对象管理数据库连接。
`InitialNavDataView`方法负责初始化导航数据视图,通过查询数据库中的项目(project)、测区(tz)和测试任务(td)表,构建树形结构的数据视图。该方法首先获取项目信息,然后为每个项目获取其下属的测区,最后为每个测区获取其包含的测试任务。在构建树形结构时,使用`CHandleProcessor`生成唯一句柄,并通过`CStateProcessor`设置节点状态图像。
数据展示功能通过一系列`ShowXxxInfo`方法实现,如`ShowProjectInfo``ShowTzInfo``ShowRsp3DTdInfo`等。这些方法通过调用管理器对象(如`theApp.m_pProManager``theApp.m_pTdManager`)获取相应的数据对象,并调用其`ShowDetailInfo``ShowConList`等方法将数据显示在相应的视图控件中。
数据库操作方面,`CreateProjectInDB`方法在数据库中创建新项目,通过事务处理确保数据一致性。该方法首先调用`ProManager``CreateProjectInDB`方法在数据库中创建项目记录,然后更新导航视图以反映新创建的项目。类似地,`DeleteProjectInDB`方法用于删除项目及其相关数据。
**Section sources**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp#L241-L486)
- [DataOperator.h](file://h/DataOperator.h#L96-L171)
## DetcGD10Dev设备检测器
DetcGD10Dev类负责检测GD10设备的连接状态,采用单例模式实现,确保在整个应用程序中只有一个实例存在。该类通过USB设备枚举机制检测特定名称的可移动驱动器来识别GD10设备。
`DetectGD10Dev`方法是设备检测的核心,它调用`FindUsbDevice`方法搜索系统中的USB设备。搜索过程首先获取系统中所有逻辑驱动器,然后遍历这些驱动器,识别类型为`DRIVE_REMOVABLE`(可移动驱动器)的设备。对于每个可移动驱动器,通过`CompareDriverName`方法验证其卷标名称是否匹配预期的设备名称("GD10"或"GD20")。
`CompareDriverName`方法不仅检查卷标名称,还提供了备用检测机制。当卷标名称不匹配时,会检查驱动器根目录下是否存在"\SD\equipment"目录,这种设计提高了设备识别的可靠性,避免了因卷标名称修改导致的识别失败。
设备检测结果通过`m_bGD10DevIsCon`布尔变量和`m_strDevAddr`字符串变量存储,分别表示设备是否连接和设备的驱动器路径。检测过程中的日志信息通过`PrintLog`方法写入"log\detect_gd20_log.txt"文件,便于问题排查和调试。
**Section sources**
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L61-L68)
- [DetcGD10Dev.h](file://h/DetcGD10Dev.h#L22-L24)
## DevOperator设备操作器
DevOperator类负责执行与设备相关的各种操作,包括初始化设备导航视图、显示设备信息、设备升级和参数修改等。该操作器管理在线和离线设备的显示,通过树形结构组织设备信息。
`InitialNavDevView`方法构建设备导航视图的树形结构,分为在线设备和离线设备两大分支。在线设备进一步分为已注册设备和新发现设备。该方法通过`DevManager`获取设备列表,并根据设备状态(在线、离线、新设备)将其添加到相应的树节点中。设备信息的显示使用`m_handleProcessor`生成的句柄进行标识。
设备信息展示功能通过`ShowFLDeviceInfo``ShowOLDeviceInfo`方法实现,分别用于显示离线和在线设备的详细信息。这些方法调用`DevManager`获取设备对象,并调用其`ShowFLDetailInfo``ShowOLDetailInfo`等方法将设备参数、接地电阻信息等数据显示在相应的视图控件中。
设备管理功能包括`DevieUpgrade`(设备升级)、`ModifyDeviceParameter`(修改设备参数)和`ShowCableHeadDlg`(显示电缆头对话框)等。设备升级操作通过创建独立线程执行,避免阻塞用户界面。`RefreshGRRec``RefreshAllGRRec`方法用于刷新设备的接地电阻记录,通过与设备通信获取最新的接地电阻测量数据。
**Section sources**
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L60-L331)
- [DevOperator.h](file://h/DevOperator.h#L23-L47)
## SptOperator脚本操作器
SptOperator类负责处理脚本相关的操作,包括初始化脚本导航视图、显示脚本信息以及在数据库中创建和管理脚本。该操作器支持一维(CE)、二维(2D)和三维(3D)三种类型的脚本。
`InitialNavExecView`方法初始化脚本导航视图,依次调用`InitialNavExecCEDlg``InitialNavExec2DDlg``InitialNavExec3DDlg`方法初始化不同类型脚本的对话框。这些初始化方法通过查询数据库中的`scon`表获取已存在的脚本列表,并将其显示在相应的列表控件中。
脚本信息展示通过`ShowCEScriptConInfo``Show2DScriptConInfo``Show3DScriptConInfo`方法实现。这些方法首先通过`SptManager`获取脚本对象,然后调用其`ShowSptDetailInfo``ShowChannelList``ShowSptConInfo`方法将脚本的详细信息、通道列表和测量序列数据显示在相应的视图控件中。
脚本管理功能包括`Create2DSConInDB``Create3DSConInDB``CreateCESConInDB`等方法,用于在数据库中创建新的脚本。创建成功后,通过`AddSConItemToSConList`方法将新脚本添加到相应的列表控件中。`Export2DSConInDB``Export3DSConInDB`方法支持将脚本导出为文本文件。
**Section sources**
- [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp#L43-L791)
- [SptOperator.h](file://h/SptOperator.h#L33-L45)
## ExecOperator执行操作器
ExecOperator类负责执行测量任务,主要功能是启动电阻率测试。`ExecRSPTest`方法是执行测量任务的核心,它创建并显示`COpExec2DRSPTestSetDlg`对话框,让用户配置测试参数。
`InitialExec2DRSPTestSetDlg`方法初始化测试设置对话框,填充各种参数选项。该方法查询数据库中的`cm`表获取参数的可选值,如电极排列方式(`Clayout`)、发射频率(`Trfrequency`)、采样频率(`SAfrequency50`)等。这些参数根据当前语言设置进行本地化显示。
当用户完成参数配置并确认后,`ExecRSPTest`方法根据用户选择的标签页(一维或二维)调用`ExecManager`的相应方法执行测试。对于一维测试,调用`ExecCERSPTest`;对于二维测试,调用`Exec2DRSPTest`。测试执行完成后,对话框被销毁。
**Section sources**
- [ExecOperator.cpp](file://cpp/Operator/ExecOperator.cpp#L37-L213)
- [ExecOperator.h](file://h/ExecOperator.h#L26-L27)
## SynOperator同步操作器
SynOperator类负责处理同步操作,主要功能是启动同步对话框。`Syn`方法创建并显示`COpSynDlg`对话框,允许用户选择要同步的设备。
`InitialSynDlg`方法初始化同步对话框,通过`DevManager`获取在线设备列表,并将设备序列号添加到设备选择下拉框中。该方法只显示状态为"在线"而非"新设备"的设备,确保用户只能选择已注册的设备进行同步。
同步操作本身在`COpSynDlg`对话框中实现,`SynOperator`主要负责对话框的初始化和显示。当用户完成同步设置并确认后,同步过程开始;如果用户取消操作,则对话框被销毁。
**Section sources**
- [SynOperator.cpp](file://cpp/Operator/SynOperator.cpp#L32-L81)
- [SynOperator.h](file://h/SynOperator.h#L17-L18)
## 对话框操作器
### InputPasswordDial密码输入对话框
InputPasswordDial类实现密码输入对话框,用于用户身份验证。该对话框支持两种验证模式:直接验证和GD10验证,通过`m_bIsDirectVerify`标志区分。
`OnOK`方法处理用户确认操作,首先验证输入的密码是否为空,然后根据验证模式检查密码是否正确。在直接验证模式下,将输入密码与预设的Geomative密码进行比较;在GD10验证模式下,跳过密码检查。密码验证通过后,调用基类的`OnOK`方法关闭对话框。
`OnInitDialog`方法初始化对话框,根据验证模式设置窗口标题和提示信息。如果处于直接验证模式但未设置密码,则显示错误消息并拒绝初始化。`OnCancel`方法处理用户取消操作,显示确认对话框询问用户是否确实要放弃输入密码。
**Section sources**
- [InputPasswordDial.cpp](file://cpp/Operator/InputPasswordDial.cpp#L47-L108)
- [InputPasswordDial.h](file://h/InputPasswordDial.h#L38-L40)
### DialCustomSptInput自定义脚本输入对话框
DialCustomSptInput类实现自定义脚本输入对话框,允许用户手动输入或从Excel文件导入脚本参数。该对话框支持两种K值计算模式:手动输入和自动计算。
`OnButtonAddList`方法处理添加脚本行操作,首先验证输入的有效性,然后计算K值(如果处于自动计算模式),最后将参数添加到列表控件中。`CheckInputIsValid`方法验证所有输入字段,确保A、B、M、N、层数和迭代数为正整数或-1,K值为有效浮点数。
`CalculateK`方法在自动计算模式下根据A、B、M、N电极位置计算几何因子K。计算公式基于电极间距离的倒数差,考虑了无穷远电极(用-1表示)的特殊情况。`OnButtonImport`方法支持从Excel文件导入脚本数据,使用COM接口与Excel应用程序交互,读取指定工作表中的数据。
**Section sources**
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp#L78-L757)
- [DialCustomSptInput.h](file://h/DialCustomSptInput.h#L48-L56)
## UpdateDataBase数据库升级器
UpdateDataBase类负责处理数据库升级,通过解析XML配置文件执行数据库结构的变更。该类在应用程序启动时检查当前数据库版本,并根据需要执行升级操作。
`ParserUpdateDBXml`方法解析"updates\database_modify.xml"文件,查找与当前软件版本匹配的升级记录。该方法首先验证当前版本与XML文件中声明的版本是否一致,然后查找前一版本的升级信息。`GetDBUpdatesInfo`方法解析具体的数据库变更指令,包括创建表、删除表和修改表结构。
数据库操作通过`AddDBTable``DeleteDBTable``ModifyDBTable`方法实现。`AddDBTable`方法根据`STTableInfo`结构中的信息生成CREATE TABLE SQL语句,包括列定义、主键、索引和外键约束。`ModifyDBTable`方法处理表结构修改,支持添加列、删除列和修改列属性。
`UpdateDBInfo`方法是数据库升级的入口点,按顺序执行所有收集的数据库变更操作。升级完成后,调用`WriteVersionToDB`方法更新数据库中的版本信息,确保下次启动时不会重复执行已应用的升级。
**Section sources**
- [UpdateDataBase.cpp](file://cpp/Operator/UpdateDataBase.cpp#L432-L873)
- [UpdateDataBase.h](file://h/UpdateDataBase.h#L76-L97)
## 操作器与管理器调用关系
操作器与管理器之间存在紧密的调用关系,操作器作为管理器功能的前端接口,将用户操作转化为对管理器的具体调用。这种设计模式实现了关注点分离,操作器负责用户界面交互,管理器负责核心业务逻辑。
以SptManager调用SptOperator为例,当用户在脚本管理界面创建新脚本时,SptManager的`Create2DSConInDB`方法被调用。该方法执行核心的脚本创建逻辑,包括在数据库中插入记录和在内存中创建脚本对象。创建成功后,控制权返回给SptOperator,由其调用`AddSConItemToSConList`方法更新用户界面,将新脚本显示在列表中。
类似地,DevOperator在设备升级操作中调用DevManager的功能。`DevieUpgrade`方法首先获取选中的设备句柄,然后通过`DevManager``GetDeviceByID`方法获取设备对象。升级操作在独立线程中执行,调用`StartDeviceUpgrade`函数,该函数最终会调用DevManager中的设备通信和固件更新逻辑。
这种调用关系体现了典型的MVCModel-View-Controller)模式,其中管理器扮演Model角色,负责数据和业务逻辑;操作器扮演Controller角色,处理用户输入并协调Model和View;视图类(如各种CView派生类)则负责数据显示。通过这种分层架构,系统实现了良好的模块化和可维护性。
**Section sources**
- [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp#L497-L522)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L385-L433)
@@ -0,0 +1,253 @@
# ScriptOperator
<cite>
**本文档中引用的文件**
- [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [Script.cpp](file://cpp/ProblemZone/Script.cpp)
- [Script2D.cpp](file://cpp/ProblemZone/Script2D.cpp)
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp)
- [ScriptCE.cpp](file://cpp/ProblemZone/ScriptCE.cpp)
- [SptManager.h](file://h/SptManager.h)
- [SptOperator.h](file://h/SptOperator.h)
- [Script.h](file://h/Script.h)
- [Script2D.h](file://h/Script2D.h)
- [Script3D.h](file://h/Script3D.h)
- [ScriptCE.h](file://h/ScriptCE.h)
- [Medium.h](file://h/Medium.h)
- [MediumBasicWenAndSch.h](file://h/MediumBasicWenAndSch.h)
- [MediumStrongWenAndSch.h](file://h/MediumStrongWenAndSch.h)
- [MediumCrossHoleGeomative.h](file://h/MediumCrossHoleGeomative.h)
- [MediumCustom2D.h](file://h/MediumCustom2D.h)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 引言
ScriptOperator是Geomative Studio软件中负责脚本生成与管理的核心组件,主要处理2D、3D及跨孔测量脚本的创建、编辑和导出功能。该组件与SptManager协同工作,根据用户配置生成相应的测量脚本,包括电极排列计算、测量序列生成和脚本验证逻辑。ScriptOperator支持多种测量模式,如温纳法、施伦贝尔格法等,并提供脚本格式的内部结构说明和性能优化策略。
## 项目结构
Geomative Studio项目包含多个目录,其中与ScriptOperator相关的文件主要位于`cpp/Operator``cpp/Managers`目录下。`cpp/Operator`目录包含SptOperator.cpp,负责脚本操作的具体实现;`cpp/Managers`目录包含SptManager.cpp,负责脚本的管理和协调。此外,`cpp/ProblemZone`目录包含各种脚本类的实现文件,如Script2D.cpp、Script3D.cpp等。
```mermaid
graph TD
subgraph "核心组件"
SptOperator["SptOperator.cpp"]
SptManager["SptManager.cpp"]
end
subgraph "脚本实现"
Script2D["Script2D.cpp"]
Script3D["Script3D.cpp"]
ScriptCE["ScriptCE.cpp"]
end
subgraph "介质类"
Medium["Medium.h"]
MediumBasic["MediumBasicWenAndSch.h"]
MediumStrong["MediumStrongWenAndSch.h"]
MediumCrossHole["MediumCrossHoleGeomative.h"]
MediumCustom["MediumCustom2D.h"]
end
SptOperator --> SptManager
SptManager --> Script2D
SptManager --> Script3D
SptManager --> ScriptCE
Script2D --> MediumBasic
Script2D --> MediumStrong
Script3D --> MediumCrossHole
ScriptCE --> MediumCustom
```
**图源**
- [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [Script2D.cpp](file://cpp/ProblemZone/Script2D.cpp)
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp)
- [ScriptCE.cpp](file://cpp/ProblemZone/ScriptCE.cpp)
- [Medium.h](file://h/Medium.h)
- [MediumBasicWenAndSch.h](file://h/MediumBasicWenAndSch.h)
- [MediumStrongWenAndSch.h](file://h/MediumStrongWenAndSch.h)
- [MediumCrossHoleGeomative.h](file://h/MediumCrossHoleGeomative.h)
- [MediumCustom2D.h](file://h/MediumCustom2D.h)
**节源**
- [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
## 核心组件
ScriptOperator的核心功能包括创建、删除和导出2D、3D及跨孔测量脚本。通过与SptManager的交互,ScriptOperator能够根据用户配置生成相应的脚本,并处理脚本生成过程中的常见错误,如电极冲突和参数越界。SptManager负责管理脚本的生命周期,包括脚本的创建、编辑和导出。
**节源**
- [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
## 架构概述
ScriptOperator与SptManager之间的调用关系如下图所示。SptOperator负责用户界面的交互,接收用户输入并调用SptManager的方法来创建、删除和导出脚本。SptManager则负责具体的脚本生成逻辑,包括电极排列计算、测量序列生成和脚本验证。
```mermaid
sequenceDiagram
participant 用户 as "用户"
participant SptOperator as "SptOperator"
participant SptManager as "SptManager"
participant 脚本类 as "脚本类"
用户->>SptOperator : 创建新脚本
SptOperator->>SptManager : 调用Create2DSConInDB
SptManager->>脚本类 : 生成脚本
脚本类-->>SptManager : 返回脚本ID
SptManager-->>SptOperator : 返回执行结果
SptOperator-->>用户 : 显示结果
用户->>SptOperator : 编辑现有脚本
SptOperator->>SptManager : 调用EditScript
SptManager->>脚本类 : 修改脚本
脚本类-->>SptManager : 返回修改结果
SptManager-->>SptOperator : 返回执行结果
SptOperator-->>用户 : 显示结果
用户->>SptOperator : 导出脚本
SptOperator->>SptManager : 调用Export2DSConInDB
SptManager->>脚本类 : 导出脚本
脚本类-->>SptManager : 返回导出结果
SptManager-->>SptOperator : 返回执行结果
SptOperator-->>用户 : 显示结果
```
**图源**
- [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
**节源**
- [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
## 详细组件分析
### ScriptOperator分析
ScriptOperator的主要职责是处理用户界面的交互,接收用户输入并调用SptManager的方法来执行具体的操作。例如,当用户创建新脚本时,SptOperator会调用SptManager的Create2DSConInDB方法来生成脚本。
```mermaid
classDiagram
class CSptOperator {
+InitialNavExecView(CNavSptView* pNavExecView)
+ShowCEScriptConInfo(DWORD dwSptHandle, CView* pAppExecView)
+Show2DScriptConInfo(DWORD dwSptHandle, CView* pAppExecView)
+Show3DScriptConInfo(DWORD dwSptHandle, CView* pAppExecView)
+Create2DSConInDB(CNavSptView* pNavExecView)
+Delete2DSConInDB(CNavSptView* pNavExecView)
+Export2DSConInDB(CNavSptView* pNavExecView)
+CreateCESConInDB(CNavSptView* pNavExecView)
+DeleteCESConInDB(CNavSptView* pNavExecView)
+Create3DSConInDB(CNavSptView* pNavExecView)
+Delete3DSConInDB(CNavSptView* pNavExecView)
}
class CSptManager {
+Create2DSConInDB(DWORD& dwSConID)
+Delete2DSConInDB(DWORD dwSConID)
+Export2DSConInDB(DWORD dwSConID, CString strSptFilePath)
+CreateCESConInDB(DWORD& dwSConID)
+DeleteCESConInDB(DWORD dwSConID)
+Create3DSConInDB(DWORD dwSConID[128])
+Delete3DSConInDB(DWORD dwSConID)
}
CSptOperator --> CSptManager : "调用"
```
**图源**
- [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
**节源**
- [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
### 脚本生成逻辑分析
脚本生成过程中,SptManager会根据用户选择的测量模式(如温纳法、施伦贝尔格法等)生成相应的电极排列和测量序列。不同的测量模式有不同的实现类,如MediumBasicWenAndSch、MediumStrongWenAndSch等。
```mermaid
flowchart TD
Start([开始]) --> 选择测量模式
选择测量模式 --> 生成电极排列
生成电极排列 --> 生成测量序列
生成测量序列 --> 验证脚本
验证脚本 --> 保存脚本
保存脚本 --> 结束([结束])
验证脚本 --> |电极冲突| 处理错误
验证脚本 --> |参数越界| 处理错误
处理错误 --> 重新生成
重新生成 --> 生成电极排列
```
**图源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [MediumBasicWenAndSch.h](file://h/MediumBasicWenAndSch.h)
- [MediumStrongWenAndSch.h](file://h/MediumStrongWenAndSch.h)
- [MediumCrossHoleGeomative.h](file://h/MediumCrossHoleGeomative.h)
- [MediumCustom2D.h](file://h/MediumCustom2D.h)
**节源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [MediumBasicWenAndSch.h](file://h/MediumBasicWenAndSch.h)
- [MediumStrongWenAndSch.h](file://h/MediumStrongWenAndSch.h)
- [MediumCrossHoleGeomative.h](file://h/MediumCrossHoleGeomative.h)
- [MediumCustom2D.h](file://h/MediumCustom2D.h)
## 依赖关系分析
ScriptOperator依赖于SptManager来执行具体的脚本生成逻辑,而SptManager又依赖于各种脚本类和介质类来生成具体的测量脚本。这种分层架构使得各个组件之间的职责清晰,便于维护和扩展。
```mermaid
graph TD
SptOperator --> SptManager
SptManager --> Script2D
SptManager --> Script3D
SptManager --> ScriptCE
Script2D --> MediumBasic
Script2D --> MediumStrong
Script3D --> MediumCrossHole
ScriptCE --> MediumCustom
```
**图源**
- [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [Script2D.cpp](file://cpp/ProblemZone/Script2D.cpp)
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp)
- [ScriptCE.cpp](file://cpp/ProblemZone/ScriptCE.cpp)
- [MediumBasicWenAndSch.h](file://h/MediumBasicWenAndSch.h)
- [MediumStrongWenAndSch.h](file://h/MediumStrongWenAndSch.h)
- [MediumCrossHoleGeomative.h](file://h/MediumCrossHoleGeomative.h)
- [MediumCustom2D.h](file://h/MediumCustom2D.h)
**节源**
- [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
## 性能考虑
为了提高脚本生成的性能,SptManager采用了缓存机制来存储常用的计算结果。例如,电极排列和测量序列的计算结果会被缓存,以避免重复计算。此外,SptManager还支持多线程操作,可以在后台线程中执行耗时的计算任务,从而提高用户体验。
**节源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
## 故障排除指南
在脚本生成过程中,可能会遇到电极冲突和参数越界等常见错误。SptManager提供了相应的错误处理机制,可以在生成脚本时检测并处理这些错误。例如,当检测到电极冲突时,SptManager会提示用户重新配置电极排列。
**节源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
## 结论
ScriptOperator是Geomative Studio中负责脚本生成与管理的核心组件,通过与SptManager的协同工作,能够根据用户配置生成2D、3D及跨孔测量脚本。该组件支持多种测量模式,并提供了脚本格式的内部结构说明和性能优化策略。通过合理的架构设计和错误处理机制,ScriptOperator能够高效地生成和管理测量脚本,满足用户的需求。
@@ -0,0 +1,299 @@
# SynchronizationOperator
<cite>
**本文档中引用的文件**
- [SynOperator.cpp](file://cpp/Operator/SynOperator.cpp)
- [SynOperator.h](file://h/SynOperator.h)
- [opsyndlg.cpp](file://cpp/Views/opsyndlg.cpp)
- [opsyndlg.h](file://h/opsyndlg.h)
- [opsyntddlg.cpp](file://cpp/Views/opsyntddlg.cpp)
- [opsyntddlg.h](file://h/opsyntddlg.h)
- [opsynsptdlg.cpp](file://cpp/Views/opsynsptdlg.cpp)
- [opsynsptdlg.h](file://h/opsynsptdlg.h)
- [OperMediumPt.cpp](file://cpp/Operator/OperMediumPt.cpp)
- [OperMediumPt.h](file://h/OperMediumPt.h)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 简介
SynchronizationOperatorSynOperator)是GeomativeStudio软件中的一个核心组件,负责协调多个设备或模块之间的同步操作。该组件主要处理设备同步、数据同步和状态同步,确保测量过程的同步性。通过与同步对话框(opsyndlg)的交互,用户可以配置同步参数并接收状态反馈。本文档将深入探讨SynOperator的实现机制,包括其如何协调时间基准和操作序列,以及与OperMediumPt类结合进行介质点同步计算的算法逻辑。同时,文档还将提供同步失败、时钟漂移等常见问题的诊断方法和解决方案,并评估同步精度和网络延迟对同步性能的影响。
## 项目结构
GeomativeStudio项目的结构清晰地组织了各个功能模块。核心的同步功能主要位于`cpp/Operator`目录下的`SynOperator.cpp``SynOperator.h`文件中。同步对话框的实现则分布在`cpp/Views`目录下的`opsyndlg.cpp``opsyntddlg.cpp``opsynsptdlg.cpp`文件中。此外,设备管理和项目管理的相关逻辑分别在`cpp/Managers`目录下的`DevManager.cpp``ProManager.cpp`文件中实现。脚本管理器的功能则由`SptManager.cpp`文件提供。这些文件共同构成了SynchronizationOperator的技术基础。
```mermaid
graph TD
subgraph "核心组件"
SynOperator[SynOperator.cpp]
OperMediumPt[OperMediumPt.cpp]
end
subgraph "视图组件"
opsyndlg[opsyndlg.cpp]
opsyntddlg[opsyntddlg.cpp]
opsynsptdlg[opsynsptdlg.cpp]
end
subgraph "管理器"
DevManager[DevManager.cpp]
ProManager[ProManager.cpp]
SptManager[SptManager.cpp]
end
SynOperator --> opsyndlg
opsyndlg --> opsyntddlg
opsyndlg --> opsynsptdlg
SynOperator --> OperMediumPt
opsyndlg --> DevManager
opsyndlg --> ProManager
opsyntddlg --> ProManager
opsynsptdlg --> SptManager
```
**图表来源**
- [SynOperator.cpp](file://cpp/Operator/SynOperator.cpp)
- [opsyndlg.cpp](file://cpp/Views/opsyndlg.cpp)
- [opsyntddlg.cpp](file://cpp/Views/opsyntddlg.cpp)
- [opsynsptdlg.cpp](file://cpp/Views/opsynsptdlg.cpp)
- [OperMediumPt.cpp](file://cpp/Operator/OperMediumPt.cpp)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
**章节来源**
- [SynOperator.cpp](file://cpp/Operator/SynOperator.cpp)
- [opsyndlg.cpp](file://cpp/Views/opsyndlg.cpp)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
## 核心组件
SynchronizationOperator的核心功能包括设备同步、数据同步和状态同步。它通过调用`Syn()`方法启动同步过程,该方法创建并初始化同步对话框`COpSynDlg`,然后显示该对话框以供用户进行配置。`InitialSynDlg`方法用于初始化同步对话框,从设备管理器中获取已连接的设备列表,并将其添加到对话框的设备选择下拉列表中。整个同步过程依赖于与设备管理器、项目管理器和脚本管理器的紧密协作,确保所有相关数据和配置都能正确同步。
**章节来源**
- [SynOperator.cpp](file://cpp/Operator/SynOperator.cpp#L32-L55)
- [SynOperator.h](file://h/SynOperator.h#L17-L18)
## 架构概述
SynchronizationOperator的架构设计旨在实现高效且可靠的同步操作。其主要组件包括`CSynOperator`类,负责协调同步流程;`COpSynDlg`类,提供用户界面以配置同步参数;以及`COpSynTDDlg``COpSynSptDlg`类,分别处理测试数据和脚本的同步。这些组件通过事件驱动的方式进行通信,确保用户操作能够及时反映到同步过程中。此外,`CSynOperator`还利用`CStateProcessor``CHandleProcessor`来处理状态变化和句柄生成,进一步增强了系统的稳定性和可维护性。
```mermaid
classDiagram
class CSynOperator {
+Syn()
+InitialSynDlg(COpSynDlg* pOpSynDlg)
-_ConnectionPtr m_pConnection
-CStateProcessor m_stateProcessor
-CHandleProcessor m_handleProcessor
}
class COpSynDlg {
+OnInitDialog()
+OnSelchangeOpSynTab()
+OnSelchangeTdDesn()
-COpSynTDDlg m_opSynTDDlg
-COpSynSptDlg m_opSynSptDlg
-CDevice* m_pDev
-_ConnectionPtr m_pConnection
}
class COpSynTDDlg {
+OnInitDialog()
+OnSelchangedTreeSynDms()
+OnItemchangedListSynTd()
+OnTdSel()
+OnTdRemove()
+OnCreate()
+OnDmsDel()
+OnTdDel()
+OnTdUpload()
-CListCtrl m_tdList
-CListCtrl m_selTdList
-CTreeCtrl m_dmsTree
-CDevice* m_pDev
}
class COpSynSptDlg {
+OnInitDialog()
+OnSptDownload()
+OnSptUpload()
+OnSptDel()
-CListCtrl m_locSptList
-CListCtrl m_hostSptList
-CDevice* m_pDev
-int m_iSelSCID
}
CSynOperator --> COpSynDlg : "创建并初始化"
COpSynDlg --> COpSynTDDlg : "包含"
COpSynDlg --> COpSynSptDlg : "包含"
COpSynTDDlg --> ProManager : "调用"
COpSynSptDlg --> SptManager : "调用"
```
**图表来源**
- [SynOperator.h](file://h/SynOperator.h#L13-L24)
- [opsyndlg.h](file://h/opsyndlg.h#L19-L62)
- [opsyntddlg.h](file://h/opsyntddlg.h#L15-L61)
- [opsynsptdlg.h](file://h/opsynsptdlg.h#L13-L58)
## 详细组件分析
### SynOperator分析
`CSynOperator`类是同步操作的核心,其主要职责是启动和管理同步流程。`Syn()`方法通过创建`COpSynDlg`实例并调用其`RunModalLoop`方法来启动非模态窗口的模态循环,从而允许用户在不阻塞主程序的情况下进行同步配置。`InitialSynDlg`方法负责初始化同步对话框,从设备管理器中获取当前连接的设备列表,并将这些设备的信息填充到对话框的设备选择下拉列表中。这一过程确保了用户能够看到所有可用的设备,并选择需要同步的目标设备。
#### 对象导向组件:
```mermaid
classDiagram
class CSynOperator {
+Syn()
+InitialSynDlg(COpSynDlg* pOpSynDlg)
-_ConnectionPtr m_pConnection
-CStateProcessor m_stateProcessor
-CHandleProcessor m_handleProcessor
}
class COpSynDlg {
+OnInitDialog()
+OnSelchangeOpSynTab()
+OnSelchangeTdDesn()
-COpSynTDDlg m_opSynTDDlg
-COpSynSptDlg m_opSynSptDlg
-CDevice* m_pDev
-_ConnectionPtr m_pConnection
}
CSynOperator --> COpSynDlg : "创建并初始化"
```
**图表来源**
- [SynOperator.h](file://h/SynOperator.h#L13-L24)
- [opsyndlg.h](file://h/opsyndlg.h#L19-L62)
**章节来源**
- [SynOperator.cpp](file://cpp/Operator/SynOperator.cpp#L21-L55)
- [SynOperator.h](file://h/SynOperator.h#L13-L24)
### OperMediumPt分析
`COperMediumPt`类负责处理介质点的同步计算,特别是在不同类型的测量装置中进行深度排序。`InitiSortInfo`方法根据指定的方法初始化排序信息,而`AddSortPtInfo`方法则用于添加具体的排序点信息。`GetUniSptXPos`方法计算统一测点的位置,这是通过分析四个电极的位置(A、B、M、N)来完成的。对于不同类型的装置(如四级、三级、二级装置),该方法采用不同的算法来计算测点位置,确保结果的准确性。`GetFirstSortID``GetNextSortID`方法则用于遍历排序后的测点列表,提供有序的访问接口。
#### 对象导向组件:
```mermaid
classDiagram
class COperMediumPt {
+COperMediumPt(int iAR)
+~COperMediumPt()
+InitiSortInfo(int iMethod)
+AddSortPtInfo(int iA, int iB, int iM, int iN, int iLayer, int iIndex)
+GetUniSptXPos(int iA, int iB, int iM, int iN)
+GetFirstSortID(int iMethod)
+GetNextSortID()
-int m_iAR
-std : : map<STDepthSortKey, int> m_mapDepthSort
-std : : map<STDepthSortKey, int> : : iterator m_iterSortDepth
}
class STDepthSortKey {
+float fXPos
+int iLayer
+operator < (const STDepthSortKey& Obj) const
}
COperMediumPt --> STDepthSortKey : "使用"
```
**图表来源**
- [OperMediumPt.h](file://h/OperMediumPt.h#L39-L58)
- [OperMediumPt.cpp](file://cpp/Operator/OperMediumPt.cpp#L18-L137)
**章节来源**
- [OperMediumPt.cpp](file://cpp/Operator/OperMediumPt.cpp#L18-L137)
- [OperMediumPt.h](file://h/OperMediumPt.h#L39-L58)
### 同步对话框交互流程
同步对话框(`COpSynDlg`)提供了用户与SynchronizationOperator交互的界面。当用户选择同步操作时,`CSynOperator`会创建`COpSynDlg`实例并显示它。`OnInitDialog`方法初始化对话框,设置标签文本和控件布局。`OnSelchangeOpSynTab`方法处理标签页切换事件,根据用户选择的不同标签页(测试数据或脚本)显示相应的子对话框。`OnSelchangeTdDesn`方法在用户选择不同的设备时更新测试数据和脚本列表,确保用户能够看到与所选设备相关的所有信息。
#### API/服务组件:
```mermaid
sequenceDiagram
participant User as "用户"
participant SynOperator as "CSynOperator"
participant OpSynDlg as "COpSynDlg"
participant OpSynTDDlg as "COpSynTDDlg"
participant OpSynSptDlg as "COpSynSptDlg"
participant ProManager as "CProManager"
participant SptManager as "CSptManager"
User->>SynOperator : 调用Syn()
SynOperator->>OpSynDlg : 创建并初始化
OpSynDlg->>OpSynDlg : OnInitDialog()
OpSynDlg->>OpSynTDDlg : 显示
OpSynDlg->>OpSynSptDlg : 隐藏
User->>OpSynDlg : 切换标签页
OpSynDlg->>OpSynDlg : OnSelchangeOpSynTab()
OpSynDlg->>OpSynTDDlg : 隐藏
OpSynDlg->>OpSynSptDlg : 显示
User->>OpSynDlg : 选择设备
OpSynDlg->>OpSynDlg : OnSelchangeTdDesn()
OpSynDlg->>ProManager : 获取测试数据
ProManager-->>OpSynDlg : 返回测试数据
OpSynDlg->>SptManager : 获取脚本
SptManager-->>OpSynDlg : 返回脚本
```
**图表来源**
- [opsyndlg.cpp](file://cpp/Views/opsyndlg.cpp#L30-L237)
- [opsyntddlg.cpp](file://cpp/Views/opsyntddlg.cpp#L43-L200)
- [opsynsptdlg.cpp](file://cpp/Views/opsynsptdlg.cpp#L38-L200)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L53-L93)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L30-L53)
**章节来源**
- [opsyndlg.cpp](file://cpp/Views/opsyndlg.cpp#L30-L237)
- [opsyntddlg.cpp](file://cpp/Views/opsyntddlg.cpp#L43-L200)
- [opsynsptdlg.cpp](file://cpp/Views/opsynsptdlg.cpp#L38-L200)
## 依赖分析
SynchronizationOperator的实现依赖于多个关键组件,包括设备管理器(`CDevManager`)、项目管理器(`CProManager`)和脚本管理器(`CSptManager`)。`CDevManager`负责管理所有连接的设备,提供设备列表和状态信息。`CProManager`管理项目和测试区域的数据,确保同步过程中能够正确识别和处理相关的测试数据。`CSptManager`则负责脚本的创建、删除和同步,确保设备上的脚本与本地数据库保持一致。这些组件之间的依赖关系通过接口调用和数据传递来实现,形成了一个紧密协作的系统。
```mermaid
graph TD
SynOperator[CSynOperator] --> OpSynDlg[COpSynDlg]
OpSynDlg --> OpSynTDDlg[COpSynTDDlg]
OpSynDlg --> OpSynSptDlg[COpSynSptDlg]
OpSynTDDlg --> ProManager[CProManager]
OpSynSptDlg --> SptManager[CSptManager]
OpSynDlg --> DevManager[CDevManager]
ProManager --> Database[(数据库)]
SptManager --> Database
DevManager --> Database
```
**图表来源**
- [SynOperator.h](file://h/SynOperator.h#L13-L24)
- [opsyndlg.h](file://h/opsyndlg.h#L19-L62)
- [opsyntddlg.h](file://h/opsyntddlg.h#L15-L61)
- [opsynsptdlg.h](file://h/opsynsptdlg.h#L13-L58)
- [DevManager.h](file://h/DevManager.h#L22-L54)
- [ProManager.h](file://h/ProManager.h#L32-L64)
- [SptManager.h](file://h/SptManager.h#L27-L85)
**章节来源**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L24-L46)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L32-L51)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L74-L83)
## 性能考虑
SynchronizationOperator在设计时充分考虑了性能因素。首先,通过使用非模态窗口的模态循环,避免了阻塞主程序的执行,提高了用户体验。其次,同步过程中采用了批量操作,减少了与数据库和设备的交互次数,从而降低了网络延迟的影响。此外,`COperMediumPt`类中的算法优化确保了介质点位置计算的高效性,即使在处理大量数据时也能保持良好的性能表现。为了进一步优化同步稳定性,建议在高网络延迟环境下使用更长的超时设置,并定期检查设备状态以确保同步过程的顺利进行。
## 故障排除指南
在使用SynchronizationOperator时,可能会遇到同步失败或时钟漂移等问题。对于同步失败,首先应检查设备连接状态和网络状况,确保设备能够正常通信。如果问题仍然存在,可以尝试重新启动设备或软件,有时这能解决临时的通信故障。对于时钟漂移问题,建议定期校准设备时钟,并在同步配置中启用时钟同步功能。此外,查看日志文件可以帮助定位具体的问题原因,例如通过分析`Device.cpp`中的日志输出,可以了解同步过程中具体的错误信息。
**章节来源**
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L1779-L1908)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L595-L637)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L2696-L2739)
## 结论
SynchronizationOperator是GeomativeStudio软件中实现设备、数据和状态同步的关键组件。通过深入分析其架构和实现机制,我们可以看到它如何有效地协调多个设备或模块的时间基准和操作序列,确保测量过程的同步性。结合`OperMediumPt`类的介质点同步计算算法,SynchronizationOperator不仅提供了强大的同步功能,还保证了计算的准确性和效率。通过与同步对话框的交互,用户可以方便地配置同步参数并监控同步状态。针对常见的同步问题,文档提供了详细的诊断方法和解决方案,帮助用户快速解决问题。总体而言,SynchronizationOperator的设计充分考虑了性能和稳定性,为用户提供了一个可靠且高效的同步解决方案。
@@ -0,0 +1,305 @@
# Device数据模型
<cite>
**本文档引用的文件**
- [Device.h](file://h/Device.h)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
- [DevManager.h](file://h/DevManager.h)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
- [SComPort.h](file://h/SComPort.h)
- [config.ini](file://Install/Geomative Studio/config.ini)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 引言
本项目GeomativeStudio是一个用于地质勘探设备管理的应用程序,其核心功能围绕设备管理展开。系统通过Device类来封装和管理各种设备(如GD10)的属性和行为,包括设备型号、固件版本、通信端口、设备状态及硬件参数配置等。Device类通过DevManager进行统一管理,并与底层驱动(如stmcdc.inf)和通信协议(CtrlProtocolDef.h)交互。设备检测逻辑在DetcGD10Dev.cpp中实现,负责识别设备并进行状态轮询。设备参数的持久化存储与config.ini文件联动,确保配置信息的持久性。在设备热插拔和通信异常时,系统具备相应的错误处理策略,保证了系统的稳定性和可靠性。
## 项目结构
项目结构清晰地组织了各个模块,便于维护和扩展。核心代码位于`cpp`目录下,分为多个子目录,如`Managers``Operator``ProblemZone`等,分别处理不同的业务逻辑。头文件位于`h`目录下,定义了类和结构体。安装文件和配置文件位于`Install`目录下,其中`config.ini`文件用于存储用户配置信息。日志文件位于`LOG`目录下,记录系统运行时的信息。数据库相关文件位于`DB`目录下,管理设备和任务数据。
```mermaid
graph TD
subgraph "核心代码"
A[cpp] --> B[Managers]
A --> C[Operator]
A --> D[ProblemZone]
end
subgraph "头文件"
E[h] --> F[Device.h]
E --> G[DevManager.h]
E --> H[CtrlProtocolDef.h]
end
subgraph "资源文件"
I[Install] --> J[config.ini]
I --> K[stmcdc.inf]
end
subgraph "日志"
L[LOG] --> M[detect_gd20_log.txt]
end
A --> E
A --> I
A --> L
```
**Diagram sources**
- [Device.h](file://h/Device.h)
- [DevManager.h](file://h/DevManager.h)
- [config.ini](file://Install/Geomative Studio/config.ini)
**Section sources**
- [Device.h](file://h/Device.h)
- [DevManager.h](file://h/DevManager.h)
- [config.ini](file://Install/Geomative Studio/config.ini)
## 核心组件
Device类是设备管理的核心,封装了设备的各种属性和方法。它通过DevManager进行统一管理,实现了设备的注册、注销、参数修改等功能。Device类还负责与底层驱动和通信协议交互,确保设备的正常运行。
**Section sources**
- [Device.h](file://h/Device.h)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
## 架构概述
系统架构采用分层设计,上层为UI层,中间为业务逻辑层,底层为设备驱动层。DevManager作为业务逻辑层的核心,负责管理所有设备实例。Device类通过SComPort类与设备进行通信,使用Zmodem协议进行文件传输。CtrlProtocolDef.h定义了通信协议,确保数据的正确传输。
```mermaid
graph TD
A[UI层] --> B[业务逻辑层]
B --> C[设备驱动层]
B --> D[DevManager]
D --> E[Device]
E --> F[SComPort]
F --> G[设备]
H[CtrlProtocolDef.h] --> F
```
**Diagram sources**
- [DevManager.h](file://h/DevManager.h)
- [Device.h](file://h/Device.h)
- [SComPort.h](file://h/SComPort.h)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
## 详细组件分析
### Device类分析
Device类封装了设备的各种属性,如设备型号(GD10)、固件版本、通信端口(串口/USB)、设备状态(在线/离线/故障)及硬件参数配置。通过GetDevInfo方法,可以从设备获取这些信息并更新到数据库中。
#### 类图
```mermaid
classDiagram
class CDevice {
+DWORD m_dwID
+UINT m_uState
+UINT m_uType
+BYTE m_ucDevType
+CSComPort m_sComPort
+CString m_szDevSN
+CString m_szDevName
+CString m_szModelNO
+CString m_szMDate
+CString m_szHWV
+CString m_szSWV
+CString m_szMBatch
+CString m_szMacAddress
+_ConnectionPtr m_pConnection
+FILE* m_pLogFile
+CDevice(DWORD dwID, _ConnectionPtr& pConnection)
+~CDevice()
+void SetState(UINT uState)
+void SetID(DWORD dwID)
+BOOL Reset()
+BOOL GetDevInfo()
+BOOL GetGRInfo()
+bool ShowFLDetailInfo(CListCtrl& devDetailList)
+bool ShowOLDetailInfo(CListCtrl& devDetailList)
+bool ShowGRInfo(CListCtrl& devGRList)
+bool ShowACInfo(CListCtrl& devDetailList)
+BOOL ModifyParameter()
+BOOL ShowCableHeadInfoDlg()
+BOOL IsTheNumofPoleChanged()
+BOOL TestGRForPerPole(int iSN, CStringArray& strResArray)
+BOOL TestGRForAllPole()
+void PrintLog(CString& strLog)
+int IsExistOtherUserData()
+int CheckGD10Password(CString strGD10Password)
+BOOL EndTransfer()
+UINT32 GetXmlMaxTestPoint(int iSubIndex, CString strPrCN, CString strTzCN, CString strXmlFile)
}
class CSComPort {
+HANDLE m_hCom
+HWND m_hOwnerWnd
+long m_lCommID
+CString m_szComName
+DCB m_dcbBlock
+FILE* m_Log
+CSComPort()
+CSComPort(HWND hOwnerWnd, long lCommID)
+~CSComPort()
+BOOL OpenComm(CString szComName)
+void CloseComm()
+BOOL SendDataDirectly(char* pDataBuff, int iDataSize)
+BOOL ReceiveDataDirectly(char* pDataBuff, int* iDataSize)
+BOOL ZmodemReceiveDataDirectly(char* pDataBuff, int* iDataSize)
+BOOL ZmodemSendDataDirectly(char* pDataBuff, int iDataSize)
+void ClearCommReceiveBuff()
+void ClearCommSendBuff()
+BOOL ExecuteOrder(CString strOrder, CString strSign, CString* pStrResult, int nRepeatCnt=3)
+BOOL ExecuteSignleOrder(CString f_szOrder, CString f_szSign, CString* f_szResult)
+BOOL ExecuteNoResOrder(CString f_szOrder)
}
CDevice --> CSComPort : "uses"
```
**Diagram sources**
- [Device.h](file://h/Device.h)
- [SComPort.h](file://h/SComPort.h)
**Section sources**
- [Device.h](file://h/Device.h)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
### DevManager类分析
DevManager类负责管理所有设备实例,提供设备的增删改查功能。它通过m_devLinkList链表存储设备实例,并通过m_handleProcessor生成设备句柄。
#### 类图
```mermaid
classDiagram
class CDevManager {
+CLinkList<CDevice*> m_devLinkList
+_ConnectionPtr m_pConnection
+std : : set<STSigRemoteDev> m_setRemoteDev
+CHandleProcessor m_handleProcessor
+CDevManager(_ConnectionPtr& pConnection)
+~CDevManager()
+CDevice* GetDeviceByID(DWORD dwDevID)
+CDevice* GetDevice(DWORD dwHandle)
+CDevice* GetDevice(CString szDevSN)
+void InitialDevLinkList()
+BOOL AddDevice(CDevice* const pDev)
+void DeleteObjInMem(DWORD dwHandle)
+void DeleteObjInMem(CString szDevSN)
+void AddObjInMem(CString szDevSN)
+void AddOfflineObjInMem(CString szDevSN)
+BOOL DeleteDevice(DWORD dwHandle)
+BOOL DeleteDevice(CString strDev)
+BOOL GetOLDevList(CPtrArray* pOLDevList)
+BOOL GetFLDevList(CPtrArray* pFLDevList)
+void UpdateDevInfo(STSynDevParam stDevParam, BYTE bRemoteDeveTyp)
+BOOL SetDeviceHandle(CDevice* const pDev)
+CDevice* GetRegisterDevice(CString szDevSN, bool& bIsRegister)
+void DeleteRemoteDevice(STSigRemoteDev stDevice)
+void AddRemoteDevice(STSigRemoteDev stDevice)
+std : : set<STSigRemoteDev> GetRemoteDeviceInfo()
}
class CDevice {
+DWORD m_dwID
+UINT m_uState
+UINT m_uType
+BYTE m_ucDevType
+CSComPort m_sComPort
+CString m_szDevSN
+CString m_szDevName
+CString m_szModelNO
+CString m_szMDate
+CString m_szHWV
+CString m_szSWV
+CString m_szMBatch
+CString m_szMacAddress
+_ConnectionPtr m_pConnection
+FILE* m_pLogFile
}
CDevManager --> CDevice : "manages"
```
**Diagram sources**
- [DevManager.h](file://h/DevManager.h)
- [Device.h](file://h/Device.h)
**Section sources**
- [DevManager.h](file://h/DevManager.h)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
### DetcGD10Dev类分析
DetcGD10Dev类负责检测GD10设备,通过USB接口查找设备并建立连接。它使用FindUsbDevice方法遍历所有可移动驱动器,通过卷标名或特定目录结构来识别设备。
#### 序列图
```mermaid
sequenceDiagram
participant User as "用户"
participant DetcGD10Dev as "CDetcGD10Dev"
participant System as "系统"
User->>DetcGD10Dev : DetectGD10Dev()
DetcGD10Dev->>System : GetLogicalDriveStrings()
System-->>DetcGD10Dev : 驱动器列表
loop 每个驱动器
DetcGD10Dev->>System : GetDriveType()
alt 可移动驱动器
DetcGD10Dev->>System : GetVolumeInformation()
System-->>DetcGD10Dev : 卷标名
alt 卷标名匹配
DetcGD10Dev-->>User : 找到设备
break
else 目录结构匹配
DetcGD10Dev->>System : _stat()
System-->>DetcGD10Dev : 目录存在
DetcGD10Dev-->>User : 找到设备
break
end
end
end
alt 未找到设备
DetcGD10Dev-->>User : 未找到设备
end
```
**Diagram sources**
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
**Section sources**
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
## 依赖分析
系统依赖于多个外部组件,包括数据库连接、串口通信、文件操作等。DevManager依赖于Device类,Device类依赖于SComPort类进行通信,SComPort类依赖于Windows API进行串口操作。此外,系统还依赖于Zmodem协议进行文件传输。
```mermaid
graph TD
A[DevManager] --> B[Device]
B --> C[SComPort]
C --> D[Windows API]
B --> E[Zmodem]
A --> F[数据库]
G[DetcGD10Dev] --> H[Windows API]
```
**Diagram sources**
- [DevManager.h](file://h/DevManager.h)
- [Device.h](file://h/Device.h)
- [SComPort.h](file://h/SComPort.h)
**Section sources**
- [DevManager.h](file://h/DevManager.h)
- [Device.h](file://h/Device.h)
- [SComPort.h](file://h/SComPort.h)
## 性能考虑
系统在设计时考虑了性能优化,如使用链表存储设备实例,减少内存分配开销;使用异步通信避免阻塞主线程;使用缓存减少数据库查询次数。此外,系统还实现了错误重试机制,提高通信的可靠性。
## 故障排除指南
当设备无法连接时,首先检查USB线缆是否连接正常,设备是否上电。然后检查设备的卷标名是否正确,或是否存在特定目录结构。如果问题仍然存在,可以查看日志文件detect_gd20_log.txt,获取详细的错误信息。对于通信异常,可以尝试重启设备或重新插拔USB线缆。
**Section sources**
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
- [Install/Geomative Studio/LOG/detect_gd20_log.txt](file://Install/Geomative Studio/LOG/detect_gd20_log.txt)
## 结论
通过深入分析Device类及其相关组件,我们了解了GeomativeStudio项目中设备管理的核心机制。Device类通过封装设备属性和方法,实现了对设备的全面管理。DevManager类提供了统一的管理接口,确保了设备实例的一致性和完整性。DetcGD10Dev类实现了设备检测功能,保证了设备的自动识别和连接。整个系统设计合理,层次分明,具有良好的可维护性和扩展性。
@@ -0,0 +1,249 @@
# Medium测量模型
<cite>
**本文档引用的文件**
- [Medium.cpp](file://cpp\ProblemZone\Medium.cpp)
- [MediumA.cpp](file://cpp\ProblemZone\MediumA.cpp)
- [MediumB.cpp](file://cpp\ProblemZone\MediumB.cpp)
- [MediumC.cpp](file://cpp\ProblemZone\MediumC.cpp)
- [MediumD.cpp](file://cpp\ProblemZone\MediumD.cpp)
- [MediumCrossHoleGeomative.cpp](file://cpp\ProblemZone\MediumCrossHoleGeomative.cpp)
- [MediumCustom2D.cpp](file://cpp\ProblemZone\MediumCustom2D.cpp)
- [MediumZ.cpp](file://cpp\ProblemZone\MediumZ.cpp)
- [MediumY.cpp](file://cpp\ProblemZone\MediumY.cpp)
- [MediumX.cpp](file://cpp\ProblemZone\MediumX.cpp)
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig2DMainDlg.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [核心Medium类架构](#核心medium类架构)
3. [标准电极排列模型](#标准电极排列模型)
- [温纳α装置 (MediumA)](#温纳α装置-mediuma)
- [温纳β装置 (MediumB)](#温纳β装置-mediumb)
- [温纳γ装置 (MediumC)](#温纳γ装置-mediumc)
- [施伦贝谢装置 (MediumD)](#施伦贝谢装置-mediumd)
4. [特殊测量模型](#特殊测量模型)
- [跨孔测量模型 (MediumCrossHoleGeomative)](#跨孔测量模型-mediumcrossholegeomative)
- [自定义2D模型 (MediumCustom2D)](#自定义2d模型-mediumcustom2d)
5. [高级与遗留模型](#高级与遗留模型)
- [通用脚本模型 (MediumX, MediumY, MediumZ)](#通用脚本模型-mediumx-mediumy-mediumz)
6. [用户界面与配置](#用户界面与配置)
7. [模型选择决策树](#模型选择决策树)
8. [结论](#结论)
## 引言
Medium系列类是Geomative Studio软件中实现地球物理电阻率测量模型的核心组件。这些类通过继承自基类`CMedium`,为各种电极排列方式和测量方法提供了具体的实现。本文档系统地介绍了从`MediumA``MediumZ`的系列类,详细说明了它们所对应的电极排列方式,如`MediumA`代表温纳α装置,`MediumB`代表温纳β装置,`MediumCrossHoleGeomative`支持跨孔测量等。文档将深入分析各模型在电极间距计算、供电-测量电极组合逻辑、数据采集序列生成等方面的实现差异,并结合配置界面说明用户如何选择和参数化特定的测量模型。
## 核心Medium类架构
`CMedium`是所有测量模型的抽象基类,定义了测量脚本生成、测点定位和数据管理的通用接口。所有具体的测量模型,如`CMediumA``CMediumB`等,都继承自此类,并重写其核心方法以实现特定的测量逻辑。
```mermaid
classDiagram
class CMedium {
+int m_iAR
+int m_iStartPole
+int m_iEndPole
+float m_fEOffsetR
+float m_fLOffsetR
+map<int, int> m_mapUniversalLayer
+CalculateTdPtLoc()
+SetValidPoleInfo()
+GeneralUniSptInfo()
+ReSortPoint()
+AddSptToUniLayer()
+QuerySptLayerFromUni()
+GetUniSptXPos()
}
class CMediumA {
+GenerateSptRecElecVal()
+CalculateSptKVal()
+CalculateSptLevel()
+CalculateSptPtLoc()
}
class CMediumB {
+GenerateSptRecElecVal()
+CalculateSptKVal()
+CalculateSptLevel()
+CalculateSptPtLoc()
}
class CMediumC {
+GenerateSptRecElecVal()
+CalculateSptKVal()
+CalculateSptLevel()
+CalculateSptPtLoc()
}
class CMediumD {
+int m_iParamIma
+int m_iParamImn
+SetParamVal()
+GenerateSptRecElecVal()
+CalculateSptKVal()
+CalculateSptLevel()
+CalculateSptPtLoc()
}
class CMediumCrossHoleGeomative {
+float m_fSeprate
+GenerateSptRecElecVal()
+CalculateCESptKVal()
+CalculateSptPtLoc()
+GenSptRecLevel()
}
class CMediumCustom2D {
+GenerateSptRecElecVal()
}
CMedium <|-- CMediumA
CMedium <|-- CMediumB
CMedium <|-- CMediumC
CMedium <|-- CMediumD
CMedium <|-- CMediumCrossHoleGeomative
CMedium <|-- CMediumCustom2D
```
**图源**
- [Medium.cpp](file://cpp\ProblemZone\Medium.cpp#L11-L657)
- [MediumA.cpp](file://cpp\ProblemZone\MediumA.cpp#L19-L239)
- [MediumB.cpp](file://cpp\ProblemZone\MediumB.cpp#L19-L237)
- [MediumC.cpp](file://cpp\ProblemZone\MediumC.cpp#L19-L240)
- [MediumD.cpp](file://cpp\ProblemZone\MediumD.cpp#L19-L362)
- [MediumCrossHoleGeomative.cpp](file://cpp\ProblemZone\MediumCrossHoleGeomative.cpp#L19-L148)
- [MediumCustom2D.cpp](file://cpp\ProblemZone\MediumCustom2D.cpp#L19-L228)
**节源**
- [Medium.cpp](file://cpp\ProblemZone\Medium.cpp#L11-L657)
## 标准电极排列模型
标准电极排列模型是地球物理勘探中最常用的几种方法,它们在`MediumA``MediumD`类中实现。
### 温纳α装置 (MediumA)
`CMediumA`类实现了温纳α(Wenner Alpha)装置,这是一种对称四极排列,其中供电电极(A, B)和测量电极(M, N)等间距排列,且M、N位于A、B的中点。
`GenerateSptRecElecVal`方法中,该类通过一个双重循环生成测点序列。外层循环遍历测量电极M的位置,内层循环则通过移动供电电极A来生成同一层内的所有测点。其电极间距计算遵循公式:`AB = 3 * MN`,且MN间距随层数增加而增大。
```mermaid
flowchart TD
Start["开始生成温纳α测点"] --> Init["初始化参数 iEAmount, iMaxSpace"]
Init --> OuterLoop["外层循环: iMMVal = 2 to iEAmount-2"]
OuterLoop --> CalcSpace["计算当前间距 iSpace"]
CalcSpace --> InnerLoop["内层循环: 移动A电极"]
InnerLoop --> CreatePoint["创建CSptRecord: A, B, M, N"]
CreatePoint --> SetK["计算K值: k = 2π * (N-M)"]
SetK --> SetLevel["计算层数: Level = N - M"]
SetLevel --> AddToArray["将测点加入pSptRecArray"]
AddToArray --> CheckInner["内层循环结束?"]
CheckInner --> |否| InnerLoop
CheckInner --> |是| CheckOuter["外层循环结束?"]
CheckOuter --> |否| OuterLoop
CheckOuter --> |是| End["返回测点总数和最大层数"]
```
**图源**
- [MediumA.cpp](file://cpp\ProblemZone\MediumA.cpp#L30-L167)
**节源**
- [MediumA.cpp](file://cpp\ProblemZone\MediumA.cpp#L30-L167)
### 温纳β装置 (MediumB)
`CMediumB`类实现了温纳β(Wenner Beta)装置。与α装置不同,β装置的供电电极B和测量电极M是相邻的。
`GenerateSptRecElecVal`方法的逻辑与`MediumA`非常相似,主要区别在于电极的赋值顺序和K值的计算。在β装置中,K值的计算公式为 `k = 6π * (N-M)`,这反映了其不同的几何因子。
**节源**
- [MediumB.cpp](file://cpp\ProblemZone\MediumB.cpp#L30-L167)
### 温纳γ装置 (MediumC)
`CMediumC`类实现了温纳γ(Wenner Gamma)装置。在这种排列中,两个测量电极M和N位于一个供电电极A的同一侧。
该类的`GenerateSptRecElecVal`方法同样采用双重循环结构,但其电极组合逻辑和K值计算(`k = 3π * (M-A)`)与α和β装置有显著不同,体现了γ装置的独特性。
**节源**
- [MediumC.cpp](file://cpp\ProblemZone\MediumC.cpp#L30-L168)
### 施伦贝谢装置 (MediumD)
`CMediumD`类实现了施伦贝谢(Schlumberger)装置,这是一种非对称排列,其中测量电极MN间距固定,而供电电极AB间距随测量深度增加而扩大。
该模型的实现更为复杂,因为它引入了可配置的参数`m_iParamIma``m_iParamImn`,分别代表AM和MN的最大间距倍数。`SetParamVal`方法允许从外部设置这些参数。`GenerateSptRecElecVal`方法中的三重循环结构(`for (a = 1; a <= m_iParamIma; a++)`)用于生成不同MN间距的测点,这与标准温纳装置的单一间距不同。
**节源**
- [MediumD.cpp](file://cpp\ProblemZone\MediumD.cpp#L32-L279)
## 特殊测量模型
除了标准的地面测量模型,系统还支持更复杂的特殊测量场景。
### 跨孔测量模型 (MediumCrossHoleGeomative)
`CMediumCrossHoleGeomative`类专门用于跨孔(Cross-Hole)电阻率成像。这种模型涉及两个或多个钻孔中的电极,极大地增加了测量的复杂性。
该类的`GenerateSptRecElecVal`方法实现了一种特定的跨孔测量方案:电极按特定顺序排列(1-12从下到上,13-24从上到下),并遵循“C1P1 = C2P2”的规则。其核心逻辑是一个`while(TRUE)`循环,通过逐层增加测量深度(`iLayer++`)并控制C1/P1和C2/P2的移动来生成所有测点。K值的计算使用了更复杂的公式 `k = π / (1/AM - 1/sqrt(AM² + AB²))`,考虑了电极间的垂直和水平距离。
**节源**
- [MediumCrossHoleGeomative.cpp](file://cpp\ProblemZone\MediumCrossHoleGeomative.cpp#L47-L111)
### 自定义2D模型 (MediumCustom2D)
`CMediumCustom2D`类为用户提供了最大的灵活性,允许用户手动输入任意的电极组合(A, B, M, N)、K值、叠加次数(N)和层数。
该类的`GenerateSptRecElecVal`方法会弹出一个对话框`CDialCustomSptInput`,让用户输入所有测点的详细信息。程序会逐行读取用户输入,并创建`CSptRecord`对象。此外,它还支持多通道模式,会根据A、B、M的值对测点进行排序,以避免重复。
**节源**
- [MediumCustom2D.cpp](file://cpp\ProblemZone\MediumCustom2D.cpp#L28-L228)
## 高级与遗留模型
系统中还包含一些更高级或为兼容性而保留的模型。
### 通用脚本模型 (MediumX, MediumY, MediumZ)
`MediumX``MediumY``MediumZ`这三个类代表了基于外部脚本引擎的通用测量模型。它们不直接在C++代码中生成测点,而是通过调用底层的`scr_*`函数(如`scr_create`, `scr_generate`)来操作一个脚本引擎。
这些类的`GenerateSptRecElecVal`方法非常简单,主要是遍历由脚本引擎生成的测点列表(`scr_get_points`),并将每个点的A、B、M、N、K值复制到`CSptRecord`对象中。`MediumZ``MediumY``MediumX`分别对应“WennerAlfa”、“Schlumberger”和“Dipole-Dipole”等不同的脚本名称,这表明它们是通过配置不同的脚本来实现不同测量方法的。
**节源**
- [MediumZ.cpp](file://cpp\ProblemZone\MediumZ.cpp#L28-L61)
- [MediumY.cpp](file://cpp\ProblemZone\MediumY.cpp#L29-L62)
- [MediumX.cpp](file://cpp\ProblemZone\MediumX.cpp#L27-L60)
## 用户界面与配置
用户通过`CCrossHoleConfig2DMainDlg`等配置对话框来选择和参数化测量模型。例如,在跨孔配置界面中,用户可以在“参数”选项卡中选择测量类型(`GetMediumType`),并输入脚本名称、时间间隔等信息。
当用户点击“创建”按钮时,`OnBnClickedBtnCreate`方法会被调用。该方法首先获取用户选择的测量类型和参数,然后调用`TwoBoreholeGenerateScript`等函数来生成具体的测量脚本。最终,`SaveTestPointToDB`方法会将生成的测点信息(A, B, M, N, K值等)写入数据库的`script2d`表中,完成整个配置流程。
**节源**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig2DMainDlg.cpp#L734-L780)
## 模型选择决策树
为了帮助用户根据地质条件和勘探目标选择合适的Medium类型,以下提供一个决策树:
```mermaid
flowchart TD
Start["开始选择测量模型"] --> Q1["勘探目标是二维剖面吗?"]
Q1 --> |是| Q2["需要标准对称排列吗?"]
Q1 --> |否| Q3["是跨孔测量吗?"]
Q2 --> |是| Q4["需要最大探测深度?"]
Q2 --> |否| Q5["需要高横向分辨率?"]
Q3 --> |是| Recommend["推荐: MediumCrossHoleGeomative"]
Q3 --> |否| Q6["需要完全自定义电极组合?"]
Q4 --> |是| RecommendA["推荐: MediumA (温纳α)"]
Q4 --> |否| Q7["需要快速测量?"]
Q5 --> |是| RecommendD["推荐: MediumD (施伦贝谢)"]
Q5 --> |否| RecommendB["推荐: MediumB (温纳β)"]
Q6 --> |是| RecommendCustom["推荐: MediumCustom2D"]
Q6 --> |否| RecommendLegacy["考虑: MediumX/Y/Z (通用脚本)"]
Q7 --> |是| RecommendC["推荐: MediumC (温纳γ)"]
Q7 --> |否| RecommendA
Recommend --> End
RecommendA --> End
RecommendB --> End
RecommendC --> End
RecommendD --> End
RecommendCustom --> End
RecommendLegacy --> End
End["完成选择"]
```
**图源**
- [MediumA.cpp](file://cpp\ProblemZone\MediumA.cpp)
- [MediumB.cpp](file://cpp\ProblemZone\MediumB.cpp)
- [MediumC.cpp](file://cpp\ProblemZone\MediumC.cpp)
- [MediumD.cpp](file://cpp\ProblemZone\MediumD.cpp)
- [MediumCrossHoleGeomative.cpp](file://cpp\ProblemZone\MediumCrossHoleGeomative.cpp)
- [MediumCustom2D.cpp](file://cpp\ProblemZone\MediumCustom2D.cpp)
## 结论
Medium系列类构成了Geomative Studio软件的核心测量引擎,通过面向对象的设计,为多种地球物理测量方法提供了清晰、可扩展的实现。从标准的温纳和施伦贝谢装置到复杂的跨孔测量和完全自定义的方案,这些类满足了不同勘探场景的需求。模型的参数(如电极间距、K值计算)直接影响最终的反演结果,因此用户应根据具体的地质条件和勘探目标谨慎选择合适的模型。未来的工作可以进一步优化这些模型的性能,并增加更多先进的测量方法。
@@ -0,0 +1,237 @@
# ProblemZone模块
<cite>
**本文档中引用的文件**
- [Project.cpp](file://cpp/ProblemZone/Project.cpp)
- [Project.h](file://h/Project.h)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
- [Device.h](file://h/Device.h)
- [Script.cpp](file://cpp/ProblemZone/Script.cpp)
- [Script.h](file://h/Script.h)
- [Medium.cpp](file://cpp/ProblemZone/Medium.cpp)
- [Medium.h](file://h/Medium.h)
- [Electrode.cpp](file://cpp/ProblemZone/Electrode.cpp)
- [Electrode.h](file://h/Electrode.h)
- [SP2DTd.h](file://h/SP2DTd.h)
- [SP2DTdRecord.h](file://h/SP2DTdRecord.h)
- [SP3DTd.h](file://h/SP3DTd.h)
- [SP3DTdRecord.h](file://h/SP3DTdRecord.h)
- [SPCETd.h](file://h/SPCETd.h)
- [SPCETdRecord.h](file://h/SPCETdRecord.h)
- [Rsp2DTd.h](file://h/Rsp2DTd.h)
- [Rsp2DTdRecord.h](file://h/Rsp2DTdRecord.h)
- [Rsp3DTd.h](file://h/Rsp3DTd.h)
- [Rsp3DTdRecord.h](file://h/Rsp3DTdRecord.h)
- [RspCETd.h](file://h/RspCETd.h)
- [RspCETdRecord.h](file://h/RspCETdRecord.h)
- [Ipsp2DTd.h](file://h/Ipsp2DTd.h)
- [Ipsp2DTdRecord.h](file://h/Ipsp2DTdRecord.h)
- [Ipsp3DTd.h](file://h/Ipsp3DTd.h)
- [Ipsp3DTdRecord.h](file://h/Ipsp3DTdRecord.h)
- [IpspCETd.h](file://h/IpspCETd.h)
- [IpspCETdRecord.h](file://h/IpspCETdRecord.h)
- [Channel.h](file://h/Channel.h)
- [DevLinkRecord.h](file://h/DevLinkRecord.h)
- [Res3DDatFileRecord.h](file://h/Res3DDatFileRecord.h)
- [SptRecord.h](file://h/SptRecord.h)
- [TdRecord.h](file://h/TdRecord.h)
</cite>
## 目录
1. [项目数据结构与管理](#项目数据结构与管理)
2. [设备属性与状态管理](#设备属性与状态管理)
3. [脚本配置与生成逻辑](#脚本配置与生成逻辑)
4. [地球物理测量模型实现](#地球物理测量模型实现)
5. [激电测量数据处理类](#激电测量数据处理类)
6. [数据记录类结构设计](#数据记录类结构设计)
7. [数据模型关联关系](#数据模型关联关系)
## 项目数据结构与管理
`CProject`类是系统中项目管理的核心数据模型,负责封装项目的基本信息和管理功能。该类通过数据库连接获取项目数据,包含项目编号、名称、描述、位置、日期、持续时间、项目负责人、客户、项目经理、质量保证标准等属性。`CProject`类提供了显示项目详细信息的功能,通过`ShowDetailInfo`方法将项目信息填充到列表控件中,便于用户查看。项目数据从数据库的`project`表中读取,使用SQL查询语句获取指定ID的项目记录,并将各字段值存储在相应的成员变量中。
**本节来源**
- [Project.cpp](file://cpp/ProblemZone/Project.cpp#L15-L81)
- [Project.h](file://h/Project.h#L14-L38)
## 设备属性与状态管理
`CDevice`类负责管理地球物理测量设备的属性和状态。该类包含设备ID、状态、类型、设备序列号、设备名称、型号、生产日期、硬件版本、软件版本、批次等属性。`CDevice`类提供了多种功能方法,包括设置设备状态、重置设备、显示设备详细信息(离线和在线)、显示接地电阻信息、显示视极化率信息等。设备信息从数据库的`device`表和`desetting`表中获取,通过`ShowFLDetailInfo``ShowOLDetailInfo`方法分别显示离线和在线设备的详细信息。类中还包含与设备通信相关的成员变量,如串口对象`m_sComPort`和日志文件指针`m_pLogFile`,用于设备通信和日志记录。
**本节来源**
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L42-L800)
- [Device.h](file://h/Device.h#L33-L125)
## 脚本配置与生成逻辑
`CScript`类是脚本管理的基础类,定义了脚本的核心属性和接口。该类包含脚本ID、电极数量、脚本类型和装置类型等属性。`CScript`类作为抽象基类,定义了显示脚本内容信息、显示脚本详情信息和显示通道列表的纯虚函数,由派生类具体实现。装置类型`m_iAR`是区分不同测量模式的关键参数,不同的装置类型对应不同的电极配置和测量方法。脚本类通过数据库连接获取相关数据,为上层应用提供脚本配置和生成的基础功能。
**本节来源**
- [Script.cpp](file://cpp/ProblemZone/Script.cpp#L18-L30)
- [Script.h](file://h/Script.h#L15-L38)
## 地球物理测量模型实现
`CMedium`类是地球物理测量模型的基类,为各种具体的测量装置类型提供通用的功能和接口。该类定义了生成脚本记录电极值、计算脚本测点位置、计算脚本记录层数、计算每层脚本记录位置、获取最大层数等纯虚函数,由具体的装置类型类(如`MediumA``MediumB`等)实现。`CMedium`类还提供了通用的测点位置计算、测点重排序、通用脚本信息生成等功能。类中包含装置类型`m_iAR`、电极偏移率`m_fEOffsetR`、层偏移率`m_fLOffsetR`、起始电极`m_iStartPole`和结束电极`m_iEndPole`等成员变量,用于描述测量模型的参数。`CMedium`类通过`std::map`容器`m_mapUniversalLayer`管理通用层信息,支持不同装置类型的层数计算和管理。
**本节来源**
- [Medium.cpp](file://cpp/ProblemZone/Medium.cpp#L12-L657)
- [Medium.h](file://h/Medium.h#L73-L115)
## 激电测量数据处理类
SP、Rsp、Ipsp系列类分别代表不同类型的激电测量数据处理功能。这些类按照2D、3D和CECross-Sectional)三种测量维度组织,每种维度都有对应的头文件和记录文件。SP系列处理自然电位测量数据,Rsp系列处理电阻率测量数据,Ipsp系列处理激发极化测量数据。每个系列都包含一个主处理类(如`SP2DTd`)和一个记录类(如`SP2DTdRecord`),分别负责数据处理逻辑和数据存储。这些类通过继承和实现`CMedium`类定义的接口,针对特定的测量方法和数据格式进行具体实现,构成了激电测量数据处理的核心框架。
```mermaid
classDiagram
class SP2DTd {
+GenerateSptRecElecVal()
+CalculateSptPtLoc()
+GenSptRecLevel()
+GenSptRecPosInLevel()
+GetMaxLevelByEAmount()
}
class SP2DTdRecord {
+m_iLevel
+m_iPosInLevel
+m_recPtArea
+m_fSptXPos
}
class Rsp2DTd {
+GenerateSptRecElecVal()
+CalculateSptPtLoc()
+GenSptRecLevel()
+GenSptRecPosInLevel()
+GetMaxLevelByEAmount()
}
class Rsp2DTdRecord {
+m_iLevel
+m_iPosInLevel
+m_recPtArea
+m_fSptXPos
}
class Ipsp2DTd {
+GenerateSptRecElecVal()
+CalculateSptPtLoc()
+GenSptRecLevel()
+GenSptRecPosInLevel()
+GetMaxLevelByEAmount()
}
class Ipsp2DTdRecord {
+m_iLevel
+m_iPosInLevel
+m_recPtArea
+m_fSptXPos
}
SP2DTd <|-- SP3DTd
SP2DTd <|-- SPCETd
Rsp2DTd <|-- Rsp3DTd
Rsp2DTd <|-- RspCETd
Ipsp2DTd <|-- Ipsp3DTd
Ipsp2DTd <|-- IpspCETd
SP2DTd --|> SP2DTdRecord : "creates"
Rsp2DTd --|> Rsp2DTdRecord : "creates"
Ipsp2DTd --|> Ipsp2DTdRecord : "creates"
```
**图表来源**
- [SP2DTd.h](file://h/SP2DTd.h)
- [SP2DTdRecord.h](file://h/SP2DTdRecord.h)
- [Rsp2DTd.h](file://h/Rsp2DTd.h)
- [Rsp2DTdRecord.h](file://h/Rsp2DTdRecord.h)
- [Ipsp2DTd.h](file://h/Ipsp2DTd.h)
- [Ipsp2DTdRecord.h](file://h/Ipsp2DTdRecord.h)
## 数据记录类结构设计
数据记录类包括`Channel``Electrode``TdRecord``SptRecord`等,用于存储测量过程中的具体数据。`Channel`类代表测量通道,`Electrode`类代表电极,包含电极编码、状态、测量日期、测量时间和测量值等属性。`TdRecord`是测量数据记录的基类,`SptRecord`是脚本记录类,存储脚本测点的详细信息,如测点序号、电极配置(C1, C2, P1, P2)、层数、层内位置等。`DevLinkRecord`类用于设备链接记录,`Res3DDatFileRecord`类用于3D电阻率数据文件记录。这些记录类通过指针数组`CPtrArray`进行管理,支持动态的数据存储和访问,构成了系统数据持久化的基础。
```mermaid
classDiagram
class Channel {
+m_iChannelID
+m_szChannelName
+m_bIsActive
}
class Electrode {
+m_szECode
+m_bCState
+m_szMDate
+m_szMTime
+m_fOMValue
}
class TdRecord {
+m_iRecordID
+m_szRecordTime
+m_fValue
}
class SptRecord {
+m_iTsn
+m_iC1
+m_iC2
+m_iP1
+m_iP2
+m_iLevel
+m_iPosInLevel
+m_fSptXPos
}
class DevLinkRecord {
+m_iLinkID
+m_dwDeviceID
+m_szLinkTime
}
class Res3DDatFileRecord {
+m_szFileName
+m_szFilePath
+m_iDataCount
}
Channel "1" -- "0..*" Electrode : "has"
TdRecord "1" -- "1" SptRecord : "corresponds to"
DevLinkRecord "1" -- "1" Device : "links"
Res3DDatFileRecord "1" -- "0..*" TdRecord : "contains"
```
**图表来源**
- [Channel.h](file://h/Channel.h)
- [Electrode.h](file://h/Electrode.h#L12-L23)
- [TdRecord.h](file://h/TdRecord.h)
- [SptRecord.h](file://h/SptRecord.h)
- [DevLinkRecord.h](file://h/DevLinkRecord.h)
- [Res3DDatFileRecord.h](file://h/Res3DDatFileRecord.h)
## 数据模型关联关系
系统中的数据模型通过层次化的关联关系组织。`Project`类作为顶级容器,包含多个`TestingZone`(测区)。每个测区包含多个`Script`(脚本),每个脚本定义了一组测量任务。脚本通过`CMedium`类的派生类(如`MediumA``MediumB`等)实现具体的测量模型,生成`SptRecord`(脚本记录)。每个脚本记录关联特定的电极配置,由`Electrode`类表示。测量执行时,生成`TdRecord`(测量数据记录),与脚本记录对应。设备`Device`通过`Channel`与电极连接,形成完整的测量链路。这种层次化的数据模型设计,清晰地表达了从项目规划到数据采集的完整流程,支持复杂的地球物理测量任务管理。
```mermaid
graph TD
Project --> TestingZone
TestingZone --> Script
Script --> MediumA
Script --> MediumB
Script --> MediumC
MediumA --> SptRecord
MediumB --> SptRecord
MediumC --> SptRecord
SptRecord --> Electrode
Electrode --> Channel
Channel --> Device
SptRecord --> TdRecord
Device --> DevLinkRecord
TdRecord --> Res3DDatFileRecord
style Project fill:#f9f,stroke:#333
style Device fill:#bbf,stroke:#333
style Res3DDatFileRecord fill:#f96,stroke:#333
```
**图表来源**
- [Project.h](file://h/Project.h#L16-L38)
- [Device.h](file://h/Device.h#L33-L125)
- [Script.h](file://h/Script.h#L15-L38)
- [Medium.h](file://h/Medium.h#L73-L115)
- [SptRecord.h](file://h/SptRecord.h)
- [Electrode.h](file://h/Electrode.h#L12-L23)
- [Channel.h](file://h/Channel.h)
- [TdRecord.h](file://h/TdRecord.h)
- [DevLinkRecord.h](file://h/DevLinkRecord.h)
- [Res3DDatFileRecord.h](file://h/Res3DDatFileRecord.h)
@@ -0,0 +1,306 @@
# Project数据模型
<cite>
**本文档中引用的文件**
- [Project.h](file://h/Project.h)
- [Project.cpp](file://cpp/ProblemZone/Project.cpp)
- [ProManager.h](file://h/ProManager.h)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [TestingZone.h](file://h/TestingZone.h)
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp)
- [DataMngStruct.h](file://h/DataMngStruct.h)
- [Script.h](file://h/Script.h)
- [TdRecord.h](file://h/TdRecord.h)
- [Device.h](file://h/Device.h)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 引言
Project类是GeomativeStudio系统中的核心数据模型,作为项目容器管理着测区、任务配置、脚本集合和测量数据记录等关键信息。该类通过与ProManager模块协作,实现了项目生命周期的完整管理,包括创建、加载、保存和关闭操作。Project类从数据库加载元数据,并通过XML缓存文件实现项目持久化,确保数据在不同会话间的连续性。作为系统中项目管理的中心实体,Project类在多项目环境中通过单例模式提供统一访问接口,协调与Device、Script、TdRecord等其他模型的交互关系。
## 项目结构
GeomativeStudio项目采用分层架构设计,将核心数据模型、管理器、操作员和视图组件分离。Project类位于ProblemZone目录中,作为CDataMngStruct的派生类实现项目数据管理功能。系统通过ProManager类统一管理项目生命周期,而项目相关的持久化操作通过XML文件在CACHE目录中实现。项目结构清晰地划分了数据访问、业务逻辑和用户界面层,确保了系统的可维护性和扩展性。
```mermaid
graph TB
subgraph "数据层"
DB[(数据库)]
CACHE[(缓存文件)]
end
subgraph "业务逻辑层"
ProManager[ProManager]
Project[Project]
TestingZone[TestingZone]
end
subgraph "数据访问层"
DataMngStruct[CDataMngStruct]
end
subgraph "用户界面层"
Views[视图组件]
end
DB --> Project
CACHE --> Project
Project --> ProManager
ProManager --> Views
DataMngStruct --> Project
DataMngStruct --> TestingZone
```
**图源**
- [Project.h](file://h/Project.h#L1-L41)
- [ProManager.h](file://h/ProManager.h#L1-L77)
- [DataMngStruct.h](file://h/DataMngStruct.h#L1-L23)
**本节来源**
- [Project.h](file://h/Project.h#L1-L41)
- [ProManager.h](file://h/ProManager.h#L1-L77)
## 核心组件
Project类作为系统核心数据模型,负责管理项目元数据和聚合相关实体。该类从数据库加载项目信息,包括名称、创建时间、坐标系统等属性,并通过成员函数实现与ProManager的协作。Project实例通过句柄机制在内存中管理,确保多项目环境下的高效访问。类的设计体现了数据封装原则,将数据库访问细节与业务逻辑分离,提供了清晰的接口供上层组件调用。
**本节来源**
- [Project.h](file://h/Project.h#L1-L41)
- [Project.cpp](file://cpp/ProblemZone/Project.cpp#L1-L81)
## 架构概述
Project类在GeomativeStudio系统架构中扮演着中心角色,作为项目容器协调多个子系统的交互。系统采用管理器模式,通过ProManager统一管理Project实例的生命周期。Project类与TestingZone、Script、TdRecord等模型形成聚合关系,构建了完整的项目数据结构。持久化机制通过XML文件实现,确保项目数据在设备间的同步和本地缓存。整个架构设计支持多项目并发操作,通过句柄处理器和状态处理器确保线程安全和数据一致性。
```mermaid
classDiagram
class CDataMngStruct {
+ShowDetailInfo(CListCtrl& dmsDetailList) bool
+CDataMngStruct()
+~CDataMngStruct()
}
class CProject {
+ShowDetailInfo(CListCtrl& proDetailList) bool
+CProject(DWORD dwID, _ConnectionPtr& pConnection)
+~CProject()
+DWORD m_dwID
-_ConnectionPtr m_pConnection
-CString m_szCN
-CString m_szPRname
-CString m_szDesc
-CString m_szLocation
-CString m_szPRdate
-CString m_szDuration
-CString m_szPS
-CString m_szCS
-CString m_szPM
-CString m_szQAS
-CString m_szStandard
}
class CTestingZone {
+ShowDetailInfo(CListCtrl& tzDetailList) bool
+CTestingZone(DWORD dwID, _ConnectionPtr& pConnection)
+~CTestingZone()
+DWORD m_dwID
-_ConnectionPtr m_pConnection
-CString m_szTZname
-CString m_szCDate
-CString m_szDesc
-CString m_szLocation
-CString m_szCN
-CString m_szTZtype
}
class CScript {
+CScript(DWORD dwID, _ConnectionPtr& pConnection)
+~CScript()
+DWORD m_dwID
+CHandleProcessor m_handleProcessor
+int m_iEAmount
+int m_iSType
+int m_iAR
+AdjustRecListColumn(int iAR, CListCtrl& sptConListInfo) void
+ShowSptConInfo(CListCtrl& sptConList) bool
+ShowSptDetailInfo(CListCtrl& sptDetailList) bool
+ShowChannelList(CListCtrl& sptChannelList) bool
-_ConnectionPtr m_pConnection
}
class CDevice {
+m_szDevSN CString
+m_dwID DWORD
+SendFile(CString szHostFilePath, CString szFilePath, CString szFileName) BOOL
}
class CTdRecord {
+m_dwTzID DWORD
+m_dwSCID DWORD
+m_pDevice CDevice*
}
CDataMngStruct <|-- CProject
CDataMngStruct <|-- CTestingZone
CProject "1" *-- "0..*" CTestingZone : 包含
CProject "1" *-- "0..*" CScript : 包含
CProject "1" *-- "0..*" CTdRecord : 包含
CTestingZone "1" *-- "0..*" CTdRecord : 包含
CTdRecord --> CDevice : 关联
```
**图源**
- [Project.h](file://h/Project.h#L1-L41)
- [TestingZone.h](file://h/TestingZone.h#L1-L33)
- [Script.h](file://h/Script.h#L1-L39)
- [Device.h](file://h/Device.h#L1-L50)
- [TdRecord.h](file://h/TdRecord.h#L1-L45)
## 详细组件分析
### Project类分析
Project类作为系统核心数据模型,实现了项目元数据的存储和管理功能。该类从数据库加载项目信息,包括项目编号(CN)、项目名称(PRname)、描述(PRdesc)、位置(location)、创建日期(PRdate)、持续时间(duration)、投影系统(PS)、坐标系统(CS)、项目经理(PM)、质量保证(QAS)和标准(standard)等属性。通过继承CDataMngStruct基类,Project类获得了统一的数据管理接口。
#### 类图
```mermaid
classDiagram
class CProject {
+ShowDetailInfo(CListCtrl& proDetailList) bool
+CProject(DWORD dwID, _ConnectionPtr& pConnection)
+~CProject()
+DWORD m_dwID
-_ConnectionPtr m_pConnection
-CString m_szCN
-CString m_szPRname
-CString m_szDesc
-CString m_szLocation
-CString m_szPRdate
-CString m_szDuration
-CString m_szPS
-CString m_szCS
-CString m_szPM
-CString m_szQAS
-CString m_szStandard
}
class CDataMngStruct {
+ShowDetailInfo(CListCtrl& dmsDetailList) bool
+CDataMngStruct()
+~CDataMngStruct()
}
CDataMngStruct <|-- CProject
```
**图源**
- [Project.h](file://h/Project.h#L1-L41)
- [DataMngStruct.h](file://h/DataMngStruct.h#L1-L23)
#### 项目生命周期管理
Project类的生命周期由ProManager模块管理,通过一系列协作方法实现完整的项目操作流程:
```mermaid
sequenceDiagram
participant UI as 用户界面
participant ProManager as ProManager
participant Project as Project
participant DB as 数据库
participant Cache as 缓存文件
UI->>ProManager : 创建项目请求
ProManager->>ProManager : 显示创建对话框
ProManager->>DB : 检查项目名称是否存在
DB-->>ProManager : 返回检查结果
alt 项目名称已存在
ProManager-->>UI : 显示错误消息
else 项目名称可用
ProManager->>DB : 插入项目记录
DB-->>ProManager : 返回项目ID
ProManager->>Project : 创建Project实例
Project->>DB : 加载项目数据
DB-->>Project : 返回项目信息
ProManager->>Cache : 生成project.xml
Cache-->>ProManager : 确认文件创建
ProManager->>UI : 返回成功状态
end
UI->>ProManager : 加载项目
ProManager->>DB : 查询项目列表
DB-->>ProManager : 返回项目数据
ProManager->>Project : 获取Project实例
Project-->>UI : 显示项目详情
```
**图源**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L249-L317)
- [Project.cpp](file://cpp/ProblemZone/Project.cpp#L19-L50)
**本节来源**
- [Project.h](file://h/Project.h#L1-L41)
- [Project.cpp](file://cpp/ProblemZone/Project.cpp#L1-L81)
- [ProManager.h](file://h/ProManager.h#L1-L77)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1-L2054)
### ProManager协作关系
ProManager作为项目管理器,与Project类形成紧密的协作关系。通过GetDMS方法,ProManager根据句柄获取相应的数据管理结构实例,实现了Project对象的单例访问模式。这种设计确保了在多项目环境中,每个项目实例在内存中只存在一个副本,提高了系统性能和数据一致性。
#### 单例访问模式
```mermaid
flowchart TD
Start([获取DMS实例]) --> CheckCache["检查缓存中是否存在"]
CheckCache --> |存在| ReturnInstance["返回缓存实例"]
CheckCache --> |不存在| CreateInstance["创建新实例"]
CreateInstance --> LoadFromDB["从数据库加载数据"]
LoadFromDB --> AddToCache["添加到缓存链表"]
AddToCache --> ReturnInstance
ReturnInstance --> End([返回DMS实例])
```
**图源**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L155-L182)
**本节来源**
- [ProManager.h](file://h/ProManager.h#L1-L77)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L155-L182)
## 依赖关系分析
Project类与系统中多个组件存在依赖关系,形成了复杂的交互网络。通过分析这些依赖关系,可以更好地理解系统的整体架构和数据流。
```mermaid
graph TD
ProManager --> Project : 创建/管理
Project --> TestingZone : 聚合
Project --> Script : 聚合
Project --> TdRecord : 聚合
Project --> DB : 数据持久化
Project --> Cache : XML缓存
TestingZone --> TdRecord : 聚合
TdRecord --> Device : 关联
Script --> TdRecord : 配置
ProManager --> DB : 数据访问
ProManager --> Device : 设备同步
style Project fill:#f9f,stroke:#333
style ProManager fill:#bbf,stroke:#333
```
**图源**
- [ProManager.h](file://h/ProManager.h#L1-L77)
- [Project.h](file://h/Project.h#L1-L41)
- [TestingZone.h](file://h/TestingZone.h#L1-L33)
**本节来源**
- [ProManager.h](file://h/ProManager.h#L1-L77)
- [Project.h](file://h/Project.h#L1-L41)
- [TestingZone.h](file://h/TestingZone.h#L1-L33)
## 性能考虑
Project类的设计考虑了性能优化,通过缓存机制减少数据库访问频率。ProManager维护的m_dmsLinkList链表缓存了已创建的Project实例,避免了重复创建和数据加载。在多项目环境下,这种缓存策略显著提高了系统响应速度。同时,XML缓存文件的使用减少了设备同步时的数据传输量,优化了I/O性能。线程安全通过句柄处理器和状态处理器实现,确保在并发访问时的数据一致性。
## 故障排除指南
在使用Project类时可能遇到的常见问题及解决方案:
1. **项目创建失败**:检查项目名称是否已存在,确保数据库连接正常
2. **数据加载异常**:验证数据库表结构是否匹配,检查XML缓存文件完整性
3. **设备同步问题**:确认设备连接状态,检查文件传输权限
4. **内存泄漏**:确保通过ProManager正确管理Project实例生命周期
5. **线程安全问题**:使用ProManager提供的同步机制,避免直接操作Project实例
**本节来源**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L249-L483)
- [Project.cpp](file://cpp/ProblemZone/Project.cpp#L19-L50)
## 结论
Project类作为GeomativeStudio系统的核心数据模型,成功实现了项目容器的功能,有效管理了项目元数据和相关实体。通过与ProManager模块的协作,该类提供了完整的项目生命周期管理功能,包括创建、加载、保存和关闭操作。基于XML的持久化机制确保了数据的可靠存储和设备同步。类的设计体现了良好的面向对象原则,通过继承、聚合和单例模式构建了清晰的架构。未来可进一步优化缓存策略和线程安全机制,以支持更大规模的项目管理和更高的并发性能。
@@ -0,0 +1,202 @@
# Script数据模型
<cite>
**本文档引用的文件**
- [Script.h](file://h/Script.h)
- [SptRecord.h](file://h/SptRecord.h)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [OpCreate3DSptDlg.cpp](file://cpp/Views/OpCreate3DSptDlg.cpp)
- [GD10OperCmd.h](file://h/GD10OperCmd.h)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp)
- [Script.cpp](file://cpp/ProblemZone/Script.cpp)
- [SptRecord.cpp](file://cpp/ProblemZone/SptRecord.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [Script类结构与功能](#script类结构与功能)
3. [SptRecord类数据结构](#sptrecord类数据结构)
4. [脚本生成与用户交互流程](#脚本生成与用户交互流程)
5. [脚本管理与增删改查操作](#脚本管理与增删改查操作)
6. [脚本与Medium模型的关联机制](#脚本与medium模型的关联机制)
7. [脚本文件(.urf)导出格式](#脚本文件urf导出格式)
8. [从脚本配置到设备指令的数据流](#从脚本配置到设备指令的数据流)
9. [结论](#结论)
## 引言
Script类及其相关SptRecord类是Geomative Studio系统中测量脚本管理的核心组件。这些类负责定义2D、3D及跨孔测量的任务序列,包括电极排列方式、测量模式(如温纳、施伦贝尔)、供电参数和采集频率等关键配置。本文档将深入分析Script类的实现机制,解释SptRecord作为脚本执行记录的数据结构,并结合UI组件说明脚本生成与编辑的用户交互流程。
**Section sources**
- [Script.h](file://h/Script.h#L1-L39)
- [SptRecord.h](file://h/SptRecord.h#L1-L57)
## Script类结构与功能
Script类是测量脚本的基类,定义了所有测量任务的通用属性和方法。该类通过继承机制支持不同类型的测量任务,包括2D、3D和跨孔测量。Script类的核心属性包括电极数量(m_iEAmount)、测量类型(m_iSType)和装置类型(m_iAR),这些属性共同定义了测量任务的基本特征。
Script类通过虚函数ShowSptConInfo、ShowSptDetailInfo和ShowChannelList提供了显示脚本信息的接口,允许子类根据具体测量类型定制信息展示方式。这种设计模式实现了代码的可扩展性和灵活性,使得系统能够轻松支持新的测量模式。
**Section sources**
- [Script.h](file://h/Script.h#L1-L39)
- [Script.cpp](file://cpp/ProblemZone/Script.cpp#L1-L30)
## SptRecord类数据结构
SptRecord类作为脚本执行记录的数据结构,包含了测量过程中的关键参数和状态信息。该类不仅存储了测量配置参数,如电极位置(m_iC1, m_iC2, m_iP1, m_iP2)、几何因子(m_fK)和迭代次数(m_iN),还包含了执行状态和异常标记。
SptRecord类的成员变量设计体现了对测量过程全面监控的需求。m_bIsSel标志位用于标记测点是否被选中,m_colorREF用于可视化显示,m_recPtArea、m_fPtCenterX、m_fPtCenterY和m_fPtRadius共同定义了测点的区域范围,支持空间查询和交互操作。
**Section sources**
- [SptRecord.h](file://h/SptRecord.h#L1-L57)
- [SptRecord.cpp](file://cpp/ProblemZone/SptRecord.cpp#L1-L54)
## 脚本生成与用户交互流程
脚本生成与编辑的用户交互主要通过OpCreate3DSptDlg类实现。该对话框提供了直观的界面,允许用户配置3D测量任务的关键参数,包括测量区域、电极间距、步长和装置类型。用户通过界面输入的参数被转换为Script3D对象的配置,最终生成具体的测量任务序列。
OpCreate3DSptDlg类的实现展示了复杂的用户交互逻辑,包括参数验证、装置类型选择和区域定义。当用户选择中梯装置时,界面会动态显示C1和C2电极的输入控件,确保用户能够正确配置测量参数。这种动态界面设计提高了用户体验和数据输入的准确性。
```mermaid
sequenceDiagram
participant 用户 as 用户
participant UI as OpCreate3DSptDlg
participant Script as Script3D
participant Medium as CMedium3D
用户->>UI : 输入测量参数
UI->>UI : 验证参数有效性
UI->>Script : 创建Script3D实例
Script->>Medium : 设置测量区域和参数
Medium->>Medium : 生成测量序列
Medium->>Script : 返回测量序列
Script->>UI : 存储测量序列
UI->>用户 : 显示生成结果
```
**Diagram sources**
- [OpCreate3DSptDlg.cpp](file://cpp/Views/OpCreate3DSptDlg.cpp#L1-L700)
- [Script.h](file://h/Script.h#L1-L39)
## 脚本管理与增删改查操作
脚本管理功能由SptManager类实现,该类提供了对测量脚本的增删改查操作。SptManager使用链接列表(m_sptLinkList)管理所有脚本实例,通过句柄机制实现脚本的快速查找和访问。这种设计模式确保了脚本管理的高效性和内存使用的合理性。
SptManager类的Create2DSConInDB和Delete2DSConInDB方法实现了脚本在数据库中的持久化存储和删除。这些方法通过ADO数据库操作,将脚本配置信息写入scon、channel和script2d等数据表,实现了配置数据的可靠存储和版本管理。
**Section sources**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L1-L800)
## 脚本与Medium模型的关联机制
Script类与Medium模型的关联是通过装置类型(m_iAR)和句柄处理器(m_handleProcessor)实现的。每种测量模式对应特定的Medium子类,如CMedium3D用于3D测量,CMediumCrossHoleGeomative用于跨孔测量。SptManager在创建脚本时,根据装置类型生成相应的Medium实例,并将其关联到脚本的通道中。
这种关联机制实现了测量逻辑与数据模型的解耦,使得系统能够灵活支持多种测量模式。当脚本执行时,相关的Medium实例负责生成具体的测量序列,而Script类则负责管理整体的测量流程和状态。
```mermaid
classDiagram
class Script {
+DWORD m_dwID
+int m_iEAmount
+int m_iSType
+int m_iAR
+CHandleProcessor m_handleProcessor
+_ConnectionPtr m_pConnection
}
class CScript2D {
+CList m_chaList
}
class CScript3D {
+CList m_chaList
}
class CScriptCE {
+CList m_chaList
}
class CChannel {
+int m_iChNumber
+CMedium* m_pMedium
+CArray m_sptRecArray
+int m_iPtAmount
}
class CMedium {
+int m_iAR
}
class CMedium3D {
+void create()
+bool generate()
+void GenerateSptRecElecVal3D()
}
class CMediumCrossHoleGeomative {
+void create()
+bool generate()
}
Script <|-- CScript2D
Script <|-- CScript3D
Script <|-- CScriptCE
CScript2D --> CChannel
CScript3D --> CChannel
CScriptCE --> CChannel
CChannel --> CMedium
CMedium <|-- CMedium3D
CMedium <|-- CMediumCrossHoleGeomative
```
**Diagram sources**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L1-L800)
- [Script.h](file://h/Script.h#L1-L39)
## 脚本文件(.urf)导出格式
脚本文件的导出格式采用XML结构,包含了测量任务的完整配置信息。导出的XML文件包含脚本名称、类型、描述、定义者、日期、测量区域、电极数量、通道信息和具体的测量序列。这种结构化的格式便于数据的交换和长期存储。
在跨孔测量等特殊情况下,系统还会生成额外的坐标文件,记录电极的三维位置信息。这些坐标文件通过C_H_Script标签在主脚本文件中引用,实现了测量配置与空间数据的分离管理。
```mermaid
flowchart TD
Start([开始导出]) --> CheckType["检查测量类型"]
CheckType --> |3D测量| GenerateXML["生成XML结构"]
CheckType --> |跨孔测量| GenerateCoord["生成坐标文件"]
GenerateXML --> AddHeader["添加XML头部"]
AddHeader --> AddBasicInfo["添加基本信息"]
AddBasicInfo --> AddChannelInfo["添加通道信息"]
AddChannelInfo --> AddLayout["添加测量序列"]
AddLayout --> SaveFile["保存文件"]
GenerateCoord --> SaveCoord["保存坐标文件"]
SaveCoord --> SaveMain["保存主脚本文件"]
SaveFile --> End([完成])
SaveMain --> End
```
**Diagram sources**
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L1-L800)
- [OpCreate3DSptDlg.cpp](file://cpp/Views/OpCreate3DSptDlg.cpp#L529-L633)
## 从脚本配置到设备指令的数据流
从脚本配置到设备指令的生成过程是一个复杂的数据转换流程。首先,用户通过UI界面配置测量参数,这些参数被封装为Script对象。然后,SptManager将Script对象的配置信息转换为数据库记录,实现持久化存储。
当测量任务执行时,系统从数据库读取脚本配置,通过GD10OperCmd类生成相应的设备指令。这些指令通过USB或蓝牙传输到GD10设备,控制其执行具体的测量操作。整个数据流确保了测量配置的准确传递和执行。
```mermaid
sequenceDiagram
participant UI as 用户界面
participant Script as Script类
participant DB as 数据库
participant GD10Cmd as GD10OperCmd
participant Device as GD10设备
UI->>Script : 输入测量配置
Script->>DB : 存储脚本配置
DB->>Script : 读取脚本配置
Script->>GD10Cmd : 请求生成指令
GD10Cmd->>GD10Cmd : 生成设备指令
GD10Cmd->>Device : 发送指令
Device->>Device : 执行测量
Device->>GD10Cmd : 返回结果
GD10Cmd->>Script : 处理结果
Script->>UI : 显示结果
```
**Diagram sources**
- [GD10OperCmd.h](file://h/GD10OperCmd.h#L1-L55)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L1-L800)
## 结论
Script类及其相关SptRecord类构成了Geomative Studio测量脚本管理的核心。通过精心设计的类结构和数据模型,系统实现了对2D、3D及跨孔测量任务的全面支持。从用户交互、数据存储到设备控制的完整数据流,确保了测量过程的准确性和可靠性。这种模块化的设计也为系统的扩展和维护提供了良好的基础。
@@ -0,0 +1,286 @@
# 测量数据模型
<cite>
**本文档引用的文件**
- [TestingData.cpp](file://cpp\ProblemZone\TestingData.cpp)
- [TestingData.h](file://h\TestingData.h)
- [TdRecord.cpp](file://cpp\ProblemZone\TdRecord.cpp)
- [TdRecord.h](file://h\TdRecord.h)
- [Channel.cpp](file://cpp\ProblemZone\Channel.cpp)
- [Channel.h](file://h\Channel.h)
- [Electrode.cpp](file://cpp\ProblemZone\Electrode.cpp)
- [Electrode.h](file://h\Electrode.h)
- [AppDataSP2DTdView.cpp](file://cpp\Views\AppDataSP2DTdView.cpp)
- [SP2DTd.h](file://h\SP2DTd.h)
- [SP2DTdRecord.h](file://h\SP2DTdRecord.h)
</cite>
## 目录
1. [引言](#引言)
2. [核心数据模型体系](#核心数据模型体系)
3. [TestingData类分析](#testingdata类分析)
4. [TdRecord类分析](#tdrecord类分析)
5. [通道与电极数据管理](#通道与电极数据管理)
6. [地球物理参数计算模型](#地球物理参数计算模型)
7. [视图组件与数据可视化](#视图组件与数据可视化)
8. [数据采集与处理流程](#数据采集与处理流程)
9. [数据校验与异常处理](#数据校验与异常处理)
## 引言
GeomativeStudio测量数据模型体系是一个完整的地球物理数据采集与处理框架,旨在管理从设备采集到的原始测量数据,并将其转换为可用于分析和可视化的地球物理参数。该体系以TestingData类为核心,通过聚合TdRecord、Channel和Electrode等组件,构建了一个层次化的数据容器结构。本文档将深入解析这一数据模型体系,重点阐述其核心组件的职责、相互关系以及数据处理流程。
## 核心数据模型体系
GeomativeStudio的测量数据模型采用面向对象的设计模式,构建了一个层次化的数据容器体系。该体系以TestingData类作为顶层数据容器,负责管理一次完整的测量任务的所有数据。TestingData类通过聚合关系管理多个Channel对象,每个Channel代表一个数据采集通道,负责管理该通道下的所有测量记录(TdRecord)。同时,TestingData类还管理着电极配置(Electrode)信息,定义了测量过程中的电极几何布局。
该数据模型体系支持多种地球物理测量方法,包括视电阻率(SP)、电阻率反演(Rsp)和激电二次场(Ipsp)等。每种测量方法都有对应的派生类,如SP2DTd、Rsp2DTd和Ipsp2DTd等,这些类继承自TestingData类并实现了特定的计算逻辑。这种设计模式使得系统能够灵活地支持不同的测量技术和数据处理算法。
**Section sources**
- [TestingData.h](file://h\TestingData.h#L158-L273)
- [Channel.h](file://h\Channel.h#L19-L34)
- [Electrode.h](file://h\Electrode.h#L12-L24)
## TestingData类分析
TestingData类是整个测量数据模型体系的核心,作为顶层数据容器负责管理一次测量任务的所有相关数据。该类在构造时接收一个数据库连接指针和任务ID,用于与数据库进行交互。类中定义了大量的成员变量,用于存储测量任务的元数据,包括任务名称、位置、测量类型、电极数量、测量模式等。
该类通过m_tdChaList成员变量管理多个Channel对象,形成了一对多的聚合关系。每个Channel对象代表一个独立的数据采集通道,可以同步采集多通道数据。TestingData类还提供了丰富的数据操作方法,包括数据加载(LoadData)、数据保存(SaveTdToExcelFile、SaveTdToRes2DFile等)和数据显示(ShowConList、ShowGrList等)。
特别值得注意的是,TestingData类中定义了复杂的时窗计算相关结构体,如_WinTime、_WinTimeList和_WaveCount,这些结构体用于存储和处理激电测量中的时域信息。类中的CalculateTWInfo和CalculateTimeWindows方法实现了激电数据的时窗积分和参数计算,这是激电测量数据处理的核心算法。
```mermaid
classDiagram
class CTestingData {
+DWORD m_dwID
+CString m_szTdName
+CString m_szTdCN
+int m_iSType
+int m_iTType
+int m_iEAmount
+float m_fESpace
+CString m_szEDistance
+CPtrList m_tdChaList
+_WaveCount* m_waveCount
+CTestingData(DWORD, _ConnectionPtr&)
+virtual ~CTestingData()
+bool ShowConListByPage(CListCtrl&, int)
+BOOL SaveOrgDataToDB(DWORD)
+bool CalculateTWInfo(CStringArray*, int)
+bool CalculateTimeWindows(_WinTimeList, CStringArray*, int, int, int, int, int)
}
class CChannel {
+int m_iChNumber
+int m_iMaxLevel
+int m_iPtAmount
+int m_iEAmount
+CMedium* m_pMedium
+CPtrArray m_sptRecArray
+CChannel()
+virtual ~CChannel()
+void ClearSptRecList()
}
class CElectrode {
+CString m_szECode
+BOOL m_bCState
+CString m_szMDate
+CString m_szMTime
+float m_fOMValue
+CElectrode()
+virtual ~CElectrode()
}
CTestingData --> CChannel : "聚合"
CTestingData --> CElectrode : "聚合"
```
**Diagram sources**
- [TestingData.h](file://h\TestingData.h#L158-L273)
- [Channel.h](file://h\Channel.h#L19-L34)
- [Electrode.h](file://h\Electrode.h#L12-L24)
**Section sources**
- [TestingData.cpp](file://cpp\ProblemZone\TestingData.cpp#L29-L85)
- [TestingData.h](file://h\TestingData.h#L158-L273)
## TdRecord类分析
TdRecord类是测量数据模型中的基本数据单元,代表一次具体的测量记录。该类作为抽象基类,定义了测量记录的基本结构和通用操作。每个TdRecord对象包含测量的基本参数,如通道ID(m_dwChID)、测点编号(m_iTsn)、电极配置参数(m_iN)、几何因子(m_fK)、电流(m_fI)、电压(m_fV)、视电阻率(m_fSP)等。
该类的核心功能是管理原始测量数据,通过m_saVRawData和m_saIRawData两个CStringArray成员变量存储电压和电流的原始波形数据。类中定义了LoadOrgData纯虚函数,由派生类实现具体的原始数据加载逻辑。同时,该类提供了ConvertVOrgData方法,用于将原始电压数据转换为实际物理值。
TdRecord类还实现了原始数据的可视化功能,通过DisplayRawDataSplines方法可以显示电压原始波形曲线。该方法首先调用LoadOrgData加载原始数据,然后创建CDispTdRecSplinesGrapDlg对话框来显示波形。类中还维护了m_fMaxAbsV变量,用于存储电压原始数据的最大绝对值,这在波形显示时用于确定Y轴的缩放比例。
```mermaid
classDiagram
class CTdRecord {
+DWORD m_dwChID
+int m_iTsn
+int m_iN
+float m_fK
+float m_fI
+float m_fV
+float m_fR0
+float m_fSP
+CString m_Datetime
+CStringArray m_saVRawData
+CStringArray m_saIRawData
+_ConnectionPtr m_pConnection
+CTdRecord(_ConnectionPtr&)
+virtual ~CTdRecord()
+float GetMaxAbsV()
+virtual void DisplayRawDataSplines()
+virtual BOOL LoadOrgData()
+virtual float ConvertVOrgData(float)
}
CTdRecord <|-- SP2DTdRecord : "继承"
CTdRecord <|-- Rsp2DTdRecord : "继承"
CTdRecord <|-- Ipsp2DTdRecord : "继承"
```
**Diagram sources**
- [TdRecord.h](file://h\TdRecord.h#L12-L46)
- [SP2DTdRecord.h](file://h\SP2DTdRecord.h)
**Section sources**
- [TdRecord.cpp](file://cpp\ProblemZone\TdRecord.cpp#L21-L325)
- [TdRecord.h](file://h\TdRecord.h#L12-L46)
## 通道与电极数据管理
通道(Channel)和电极(Electrode)是测量数据模型中的两个关键组件,分别负责管理数据采集通道和电极配置信息。Channel类作为数据采集通道的抽象,每个Channel对象代表一个独立的采集通道,可以同步采集多通道数据。类中通过m_sptRecArray成员变量管理多个SptRecord对象,这些对象代表了该通道下的所有测量脚本记录。
Channel类还与测量装置(Medium)相关联,通过m_pMedium指针引用具体的测量装置配置。不同的测量装置类型(如温纳装置、施伦贝谢装置等)决定了电极的排列方式和测量方法。类中定义了m_iEAmount成员变量来记录该通道使用的电极数量,m_iMaxLevel记录了测量的最大层级。
Electrode类则负责管理单个电极的配置信息,包括电极编码(m_szECode)、连接状态(m_bCState)、测量日期时间(m_szMDate, m_szMTime)和测量值(m_fOMValue)等。这些信息对于确保测量数据的准确性和可追溯性至关重要。在多通道同步采集场景中,多个Channel对象可以共享相同的电极配置,从而实现高效的多通道数据采集。
```mermaid
classDiagram
class CChannel {
+int m_iChNumber
+int m_iMaxLevel
+int m_iPtAmount
+int m_iEAmount
+CMedium* m_pMedium
+CPtrArray m_sptRecArray
+CChannel()
+virtual ~CChannel()
+void ClearSptRecList()
}
class CElectrode {
+CString m_szECode
+BOOL m_bCState
+CString m_szMDate
+CString m_szMTime
+float m_fOMValue
+CElectrode()
+virtual ~CElectrode()
}
class CMedium {
+int m_iType
+int m_iN
+float m_fK
+CMedium()
+virtual ~CMedium()
}
CChannel --> CMedium : "关联"
CChannel --> CElectrode : "使用"
```
**Diagram sources**
- [Channel.h](file://h\Channel.h#L19-L34)
- [Electrode.h](file://h\Electrode.h#L12-L24)
**Section sources**
- [Channel.cpp](file://cpp\ProblemZone\Channel.cpp#L11-L48)
- [Channel.h](file://h\Channel.h#L19-L34)
- [Electrode.cpp](file://cpp\ProblemZone\Electrode.cpp#L18-L27)
- [Electrode.h](file://h\Electrode.h#L12-L24)
## 地球物理参数计算模型
GeomativeStudio支持多种地球物理参数的计算,主要包括视电阻率(SP)、电阻率反演(Rsp)和激电二次场(Ipsp)等。这些参数的计算模型在相应的派生类中实现,如SP2DTd、Rsp2DTd和Ipsp2DTd等。这些类继承自TestingData类,并重写了特定的计算方法。
对于视电阻率(SP)计算,系统根据测量装置类型和电极配置,使用相应的几何因子(K)和测量得到的电压(V)、电流(I)值,通过公式ρa = K × (V/I)计算得到视电阻率。这一计算过程在SP2DTd类的实现中完成,该类还负责将计算结果保存到数据库中,并提供数据导出功能。
激电二次场(Ipsp)的计算更为复杂,涉及时域数据的处理。系统通过CalculateTWInfo方法对原始电压波形进行多项式拟合,然后在预定义的时窗内进行积分计算,得到二次场面积。再结合充电末期电压(Vp),通过公式M = 积分面积/Vp计算得到充电率(M)参数。这一过程充分利用了_WaveCount结构体来管理多时窗的计算结果。
```mermaid
flowchart TD
Start([开始]) --> LoadOrgData["加载原始数据"]
LoadOrgData --> Preprocess["数据预处理"]
Preprocess --> FitCurve["电压波形多项式拟合"]
FitCurve --> DefineTW["定义时窗"]
DefineTW --> Integrate["时窗内积分计算"]
Integrate --> CalcVp["计算充电末期电压Vp"]
CalcVp --> CalcM["计算充电率M = 积分面积/Vp"]
CalcM --> CalcETA["计算极化率η = 100×V2/Vp"]
CalcETA --> Output["输出Ipsp参数"]
Output --> End([结束])
```
**Diagram sources**
- [TestingData.cpp](file://cpp\ProblemZone\TestingData.cpp#L463-L566)
- [TestingData.h](file://h\TestingData.h#L171-L172)
**Section sources**
- [TestingData.cpp](file://cpp\ProblemZone\TestingData.cpp#L463-L566)
- [SP2DTd.h](file://h\SP2DTd.h#L17-L58)
## 视图组件与数据可视化
视图组件负责将测量数据转换为可视化图形,其中AppDataSP2DTdView是视电阻率2D测量数据的视图组件。该组件采用MFC的文档/视图架构,通过CSplitterWnd实现多窗格界面布局。在Create方法中,它创建了一个水平分割器(m_firstSplitter)和一个垂直分割器(m_secondSplitter),将视图窗口划分为三个区域。
左侧区域显示测量数据详情列表(CAppDataTdDetailListView),右侧上部区域显示数据内容列表(CAppDataSP2DTdConListView),右侧下部区域显示接地电阻列表(CAppDataTdGrListView)。这种布局使得用户可以同时查看测量数据的不同方面,提高了数据浏览的效率。
视图组件通过OnSize方法处理窗口大小调整事件,确保分割器能够正确地重新布局。当窗口大小改变时,它会调用RecalcLayout方法重新计算分割器的布局,保持界面的整洁和可用性。这种设计模式使得视图组件能够适应不同大小的显示区域,提供了良好的用户体验。
```mermaid
flowchart TD
A([AppDataSP2DTdView]) --> B["m_firstSplitter\n水平分割器"]
B --> C["左侧窗格\nCAppDataTdDetailListView"]
B --> D["右侧窗格"]
D --> E["m_secondSplitter\n垂直分割器"]
E --> F["上部窗格\nCAppDataSP2DTdConListView"]
E --> G["下部窗格\nCAppDataTdGrListView"]
```
**Diagram sources**
- [AppDataSP2DTdView.cpp](file://cpp\Views\AppDataSP2DTdView.cpp#L71-L107)
**Section sources**
- [AppDataSP2DTdView.cpp](file://cpp\Views\AppDataSP2DTdView.cpp#L25-L123)
## 数据采集与处理流程
测量数据的采集与处理流程从设备数据包接收开始,经过解析、存储到数据库,最终完成数据校验和异常值处理。流程首先通过设备对象的ReceiveFile方法从设备获取ORG格式的原始数据文件。这些文件包含了电压和电流的原始波形数据,以文本格式存储。
获取到ORG文件后,系统通过CMarkup类解析XML格式的数据,提取出每个测点的电压和电流原始数据。然后,通过SQL语句将这些原始数据更新到数据库的相应记录中。这一过程在TestingData类的SaveOrgDataToDB方法中实现,确保了原始数据的完整性和可追溯性。
数据处理阶段,系统从数据库中读取原始数据,通过SplitterString函数将其按分号分割成数组,然后对每个数据点进行转换和处理。电压数据会经过adc_calculate方法进行校准,将ADC值转换为实际的电压值。处理后的数据被存储在TdRecord对象中,供后续的参数计算和可视化使用。
```mermaid
sequenceDiagram
participant 设备 as "测量设备"
participant 应用程序 as "应用程序"
participant 数据库 as "数据库"
设备->>应用程序 : 发送ORG数据包
应用程序->>应用程序 : 接收并保存为本地文件
应用程序->>应用程序 : 使用CMarkup解析XML
应用程序->>数据库 : 执行SQL更新原始数据
数据库-->>应用程序 : 确认更新完成
应用程序->>应用程序 : 从数据库读取原始数据
应用程序->>应用程序 : 分割并转换数据
应用程序->>应用程序 : 存储处理后的数据
应用程序-->>用户 : 显示处理结果
```
**Diagram sources**
- [TestingData.cpp](file://cpp\ProblemZone\TestingData.cpp#L326-L420)
- [TdRecord.cpp](file://cpp\ProblemZone\TdRecord.cpp#L34-L211)
**Section sources**
- [TestingData.cpp](file://cpp\ProblemZone\TestingData.cpp#L326-L420)
- [TdRecord.cpp](file://cpp\ProblemZone\TdRecord.cpp#L34-L211)
## 数据校验与异常处理
系统实现了多层次的数据校验与异常处理机制,确保测量数据的准确性和系统的稳定性。在数据采集阶段,系统会检查接收到的ORG文件是否完整,如果接收失败会向用户显示错误信息。在数据解析阶段,系统会对原始数据进行有效性检查,如检查电压和电流数据的长度是否匹配。
在参数计算阶段,系统特别关注关键参数的合理性。例如,在计算充电率(M)时,系统会检查充电末期电压(Vp)是否为零,如果为零会弹出错误提示,因为这会导致除零错误。这种预防性检查避免了计算过程中的数值异常,保证了计算结果的可靠性。
异常处理主要通过C++的异常机制和MFC的消息框实现。对于数据库操作异常,系统捕获_com_error异常并显示详细的错误描述。对于用户可感知的错误,如Vp为零的情况,系统会根据当前语言设置显示中文或英文的错误消息,提高了系统的国际化支持能力。
**Section sources**
- [TestingData.cpp](file://cpp\ProblemZone\TestingData.cpp#L505-L512)
- [TdRecord.cpp](file://cpp\ProblemZone\TdRecord.cpp#L115-L118)
@@ -0,0 +1,218 @@
# 激电二次场数据模型
<cite>
**本文档引用文件**
- [Ipsp2DTd.cpp](file://cpp/ProblemZone/Ipsp2DTd.cpp)
- [Ipsp3DTd.cpp](file://cpp/ProblemZone/Ipsp3DTd.cpp)
- [IpspCETd.cpp](file://cpp/ProblemZone/IpspCETd.cpp)
- [Ipsp2DTd.h](file://h/Ipsp2DTd.h)
- [Ipsp3DTd.h](file://h/Ipsp3DTd.h)
- [IpspCETd.h](file://h/IpspCETd.h)
- [Ipsp2DTdRecord.h](file://h/Ipsp2DTdRecord.h)
- [Ipsp3DTdRecord.h](file://h/Ipsp3DTdRecord.h)
- [IpspCETdRecord.h](file://h/IpspCETdRecord.h)
- [TdChannel.h](file://h/TdChannel.h)
- [Channel.h](file://h/Channel.h)
- [AppDataIpspCETdView.cpp](file://cpp/Views/AppDataIpspCETdView.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [Ipsp系列类架构](#ipsp系列类架构)
3. [核心数据结构与物理参数](#核心数据结构与物理参数)
4. [供电周期与采样时序处理](#供电周期与采样时序处理)
5. [时序对齐机制](#时序对齐机制)
6. [可视化组件与剖面生成](#可视化组件与剖面生成)
7. [数据处理流程](#数据处理流程)
8. [数据质量控制](#数据质量控制)
## 引言
Ipsp系列类(Ipsp2DTd、Ipsp3DTd、IpspCETd)是Geomative Studio软件中用于处理时间域激电法(TDIP)二次场数据的核心组件。这些类定义了从数据采集、存储、处理到可视化的完整数据模型,支持二维、三维及一维中心激电(CEIP)等多种测量模式。该数据模型不仅管理原始电压信号,还负责计算关键的地球物理参数,如视极化率、半衰时和衰减系数,为地质解释提供基础数据。
## Ipsp系列类架构
Ipsp系列类继承自`CTestingData`基类,形成一个层次化的数据处理体系。每个类针对特定的测量模式进行优化,但共享统一的数据管理接口。
```mermaid
classDiagram
class CTestingData {
+DWORD m_dwID
+_ConnectionPtr& m_pConnection
+virtual BOOL LoadData(CLinkList<CMedium*>& m_medLinkList)
+virtual BOOL SaveData()
}
class CIpsp2DTd {
+BOOL ShowConList(CListCtrl &tdConList)
+BOOL ShowGrList(CListCtrl &tdGrList)
+int GetFitEquationInfo(int nTSN, double nPeriod)
}
class CIpsp3DTd {
+BOOL ShowConList(CListCtrl &tdConList)
+BOOL ShowGrList(CListCtrl &tdGrList)
+int GetFitEquationInfo(int nTSN, double nPeriod)
}
class CIpspCETd {
+BOOL ShowConList(CListCtrl &tdConList)
+BOOL ShowGrList(CListCtrl &tdGrList)
+int GetFitEquationInfo(int nTSN, double nPeriod)
+BOOL SaveCERSPSetInfo(COpExec2DRSPTestSetDlg* pOpExec2DRSPTestSetDlg, CLinkList<CMedium*>& m_medLinkList)
}
CTestingData <|-- CIpsp2DTd
CTestingData <|-- CIpsp3DTd
CTestingData <|-- CIpspCETd
```
**图源**
- [Ipsp2DTd.h](file://h/Ipsp2DTd.h)
- [Ipsp3DTd.h](file://h/Ipsp3DTd.h)
- [IpspCETd.h](file://h/IpspCETd.h)
**节源**
- [Ipsp2DTd.h](file://h/Ipsp2DTd.h)
- [Ipsp3DTd.h](file://h/Ipsp3DTd.h)
- [IpspCETd.h](file://h/IpspCETd.h)
## 核心数据结构与物理参数
Ipsp系列类通过`CIpspXDTdRecord`记录类管理每个测点的详细数据。这些记录类继承自`CTdRecord`,并根据测量模式定义了特定的数据结构。
### 数据结构定义
| 类型 | 字段 | 描述 | 物理意义 |
| :--- | :--- | :--- | :--- |
| **CIpsp2DTdRecord** | m_iC1, m_iC2 | 供电电极编号 | 电流电极A、B的位置 |
| | m_iP1, m_iP2 | 测量电极编号 | 电位电极M、N的位置 |
| | m_iLevel, m_iPosInLevel | 测点层级与位置 | 在二维剖面中的空间索引 |
| **CIpsp3DTdRecord** | m_iC1, m_iC2 | 供电电极编号 | 电流电极A、B的位置 |
| | m_iP1, m_iP2 | 测量电极编号 | 电位电极M、N的位置 |
| | m_iLevel, m_iPosInLevel | 测点层级与位置 | 在三维网格中的空间索引 |
| **CIpspCETdRecord** | m_fA, m_fB | 电极距 | AB/2和MN/2的距离 |
| | m_fX, m_fY | 坐标 | 测点在地表的平面位置 |
| | m_fDepth | 深度 | 当前测量的深度层 |
### 关键物理参数计算
#### 二次场电压与视极化率
二次场电压(V)和视极化率(SP)是直接从数据库中读取的核心参数。视极化率(SP)是二次场电压与一次场电压的比值,通常以毫秒(ms)或百分比(%)表示。
#### 半衰时(Half-Life Time
半衰时是激电响应衰减到其初始值一半所需的时间,是反映极化体弛豫特性的重要参数。其计算通过`GetFitEquationInfo`方法实现,该方法利用多项式拟合和二分法求解。
```mermaid
flowchart TD
Start([开始]) --> LoadData["加载原始数据"]
LoadData --> CalcPeriod["计算供电周期"]
CalcPeriod --> ExtractData["提取放电阶段数据"]
ExtractData --> FitCurve["多项式拟合衰减曲线"]
FitCurve --> SolveHL["二分法求解半衰时"]
SolveHL --> AverageHL["计算多次放电的平均半衰时"]
AverageHL --> Return["返回半衰时结果"]
```
**图源**
- [Ipsp2DTd.cpp](file://cpp/ProblemZone/Ipsp2DTd.cpp#L446-L509)
- [Ipsp3DTd.cpp](file://cpp/ProblemZone/Ipsp3DTd.cpp)
- [IpspCETd.cpp](file://cpp/ProblemZone/IpspCETd.cpp)
**节源**
- [Ipsp2DTd.cpp](file://cpp/ProblemZone/Ipsp2DTd.cpp#L446-L509)
#### 衰减系数
衰减系数描述了激电响应的衰减速率。虽然代码中未直接命名“衰减系数”,但通过多项式拟合得到的系数数组(`dCoefficient`)本质上包含了衰减的数学模型,可用于计算衰减率。
## 供电周期与采样时序处理
Ipsp系列类通过`GetCycle`函数将数据库中的`TRfrequency`值转换为实际的供电周期(秒)。该周期是计算半衰时等参数的关键输入。
```cpp
// 伪代码:供电周期处理
double dPeriod = GetCycle(nTmp); // 将频率索引转换为周期
int nDataNum = atoi(m_saVRawData.GetAt(3)); // 获取采样点数
double dSplit = dPeriod / (nDataNum - 1); // 计算时间间隔
```
采样时序数据存储在`m_saVRawData`字符串数组中,其中包含了完整的电压时间序列。数据处理时,根据供电周期将时间序列分割成多个时窗,分别对每个时窗进行分析。
**节源**
- [Ipsp2DTd.cpp](file://cpp/ProblemZone/Ipsp2DTd.cpp#L453-L454)
## 时序对齐机制
Ipsp系列类通过`CTdChannel`类与`Channel`类实现时序对齐。`CTdChannel``IpspXDTd`类的数据通道,它管理一个`m_tdRecArray`数组,该数组按测点编号(TSN)顺序存储`CIpspXDTdRecord`记录。
```mermaid
classDiagram
class CIpspCETd {
+CLinkList<CTdChannel*> m_tdChaList
}
class CTdChannel {
+DWORD m_dwID
+int m_iChNum
+CMedium* m_pMedium
+CPtrArray m_tdRecArray
+CTdRecord* GetTdRecord(int iTSN)
}
class CIpspCETdRecord {
+int m_iTSN
+CStringArray m_saVRawData
}
CIpspCETd --> CTdChannel : "包含"
CTdChannel --> CIpspCETdRecord : "包含"
```
**图源**
- [IpspCETd.h](file://h/IpspCETd.h)
- [TdChannel.h](file://h/TdChannel.h)
- [IpspCETdRecord.h](file://h/IpspCETdRecord.h)
**节源**
- [IpspCETd.h](file://h/IpspCETd.h)
- [TdChannel.h](file://h/TdChannel.h)
## 可视化组件与剖面生成
`AppDataIpspCETdView`类负责IpspCETd数据的可视化展示。它使用`CSplitterWnd`将视图分割为三个面板:详细信息、数据内容列表和接地电阻列表。
```mermaid
graph TB
AppDataIpspCETdView["CAppDataIpspCETdView"] --> m_firstSplitter["m_firstSplitter (1x2)"]
m_firstSplitter --> m_pDetailListView["m_pDetailListView (详情)"]
m_firstSplitter --> m_secondSplitter["m_secondSplitter (2x1)"]
m_secondSplitter --> m_pContentListView["m_pContentListView (数据内容)"]
m_secondSplitter --> m_pGrListView["m_pGrListView (接地电阻)"]
```
**图源**
- [AppDataIpspCETdView.cpp](file://cpp/Views/AppDataIpspCETdView.cpp)
**节源**
- [AppDataIpspCETdView.cpp](file://cpp/Views/AppDataIpspCETdView.cpp)
激电剖面的生成逻辑如下:
1. **数据加载**`CIpspCETd::LoadData`方法从数据库加载所有通道和测点数据。
2. **数据组织**:数据按通道和测点编号有序存储在`m_tdChaList``m_tdRecArray`中。
3. **参数计算**:调用`GetFitEquationInfo`等方法计算半衰时、视极化率等参数。
4. **视图更新**`ShowConList`方法将计算结果填充到`CListCtrl`控件中,形成可交互的剖面图。
## 数据处理流程
完整的数据处理流程涵盖了从原始信号到最终解释参数的转换。
```mermaid
flowchart TD
RawData["原始电压信号"] --> Filter["信号滤波"]
Filter --> BackgroundSub["背景噪声扣除"]
BackgroundSub --> ParameterExtract["参数提取"]
ParameterExtract --> HalfLife["半衰时计算"]
ParameterExtract --> DecayCoeff["衰减系数计算"]
ParameterExtract --> ApparentCharge["视极化率计算"]
HalfLife --> QC["数据质量控制"]
DecayCoeff --> QC
ApparentCharge --> QC
QC --> Output["输出结果"]
```
**节源**
- [Ipsp2DTd.cpp](file://cpp/ProblemZone/Ipsp2DTd.cpp#L446-L509)
## 数据质量控制
数据质量控制策略主要体现在以下几个方面:
1. **异常值处理**:在`ShowDetailInfo``ShowGrList`方法中,对数据库中的空值(`VT_NULL`)和特殊值(如"-9999")进行检查和处理,避免无效数据显示。
2. **数据完整性验证**:在`ShowConList`等方法中,通过检查`GetRecordCount()`确保数据库查询结果有效,若无数据则返回错误。
3. **错误捕获**:使用`try-catch`块捕获数据库操作中的`_com_error`异常,确保程序的健壮性。
4. **数据对齐**:通过`TSN`(测点编号)确保不同通道的数据在时间和空间上正确对齐。
**节源**
- [Ipsp2DTd.cpp](file://cpp/ProblemZone/Ipsp2DTd.cpp#L372-L395)
- [IpspCETd.cpp](file://cpp/ProblemZone/IpspCETd.cpp#L604-L610)
@@ -0,0 +1,208 @@
# 电阻率反演数据模型
<cite>
**本文档引用的文件**
- [Rsp2DTd.cpp](file://cpp\ProblemZone\Rsp2DTd.cpp)
- [Rsp3DTd.cpp](file://cpp\Views\Rsp3DTd.cpp)
- [RspCETd.cpp](file://cpp\ProblemZone\RspCETd.cpp)
- [AppDataRsp3DTdView.cpp](file://cpp\Views\AppDataRsp3DTdView.cpp)
- [Rsp3DTdRecord.cpp](file://cpp\Views\Rsp3DTdRecord.cpp)
- [Medium3D.h](file://h\Medium3D.h)
- [MediumCrossHoleGeomative.h](file://h\MediumCrossHoleGeomative.h)
</cite>
## 目录
1. [引言](#引言)
2. [核心数据结构与输入输出](#核心数据结构与输入输出)
3. [反演算法流程与中间数据存储](#反演算法流程与中间数据存储)
4. [反演结果精度评估指标](#反演结果精度评估指标)
5. [反演剖面图生成流程](#反演剖面图生成流程)
6. [SP原始数据依赖关系](#sp原始数据依赖关系)
7. [不同地质模型适配策略](#不同地质模型适配策略)
8. [反演流程数据流图](#反演流程数据流图)
9. [典型配置参数及其影响](#典型配置参数及其影响)
## 引言
本文档旨在全面解析Geomative Studio软件中Rsp系列类(`Rsp2DTd``Rsp3DTd``RspCETd`)实现的电阻率反演数据模型。该模型是地球物理勘探中用于解释野外采集的电阻率数据的核心算法,通过将观测到的视电阻率数据与理论正演模型进行对比,迭代更新地下电性结构模型,最终获得与实际地质情况相符的电阻率分布剖面。文档将重点阐述反演算法的数据结构、迭代过程、精度评估、可视化生成以及与不同地质模型的适配机制。
## 核心数据结构与输入输出
### 输入数据结构
反演模型的输入数据主要来源于野外采集的原始测量数据,其核心结构由`CTestingData`基类及其派生类(如`CRsp2DTd``CRsp3DTd`)定义。输入数据主要包括:
- **测量任务元数据**:存储在`td`数据库表中,包含任务名称(`TDname`)、位置(`Tlocation`)、设备信息(`DESN`)、脚本信息(`SCCN``Sname`)、测量模式(`Tmode`)、电极数量(`Eamount`)、电极间距(`Edistance`)等。
- **测量配置参数**:包括电流频率(`TRfrequency`)、工业频率(`Ifrequency`)、采样率(`SAfrequency`)、装置类型(`Clayout`)、气象信息(`weather``temperature`)等。
- **原始测量记录**:存储在`td2dcon``td3dcon``td1dcon`等数据库表中,每条记录包含电极配置(`C1`, `C2`, `P1`, `P2`)、几何因子(`K`)、测量电流(`I`)、测量电压(`V`)、计算得到的视电阻率(`R0`)和视极化率(`SP`)等。
### 输出数据结构
反演过程的输出是经过迭代优化后的地下电阻率模型,其数据结构体现在:
- **反演结果数据**:最终的电阻率模型以网格化数据的形式存储,每个网格单元包含其位置坐标和反演得到的电阻率值。这些数据通常通过`SaveHeadInfoToFile`方法以XML格式导出,文件中包含`measure`根节点下的`medium_set``pole_count``pole_distance`等关键信息。
- **中间迭代数据**:在迭代过程中,每次迭代的模型参数和拟合误差会被临时存储在内存中,以便进行收敛性判断和结果回溯。
**Section sources**
- [Rsp2DTd.cpp](file://cpp\ProblemZone\Rsp2DTd.cpp#L56-L57)
- [Rsp3DTd.cpp](file://cpp\Views\Rsp3DTd.cpp#L43-L44)
- [RspCETd.cpp](file://cpp\ProblemZone\RspCETd.cpp#L34-L35)
## 反演算法流程与中间数据存储
### 迭代过程
电阻率反演是一个非线性优化问题,通常采用最小二乘法或其变种(如阻尼最小二乘法)进行求解。其核心迭代流程如下:
1. **初始化**:根据用户输入的初始模型(通常为均匀半空间或简单分层模型)和测量数据,构建初始的地下电性结构模型。
2. **正演计算**:基于当前的模型,计算所有测量点的理论视电阻率值。
3. **误差计算**:将理论计算值与实际观测值进行对比,计算残差(Residual)和目标函数(如均方根误差RMSE)。
4. **模型更新**:根据残差和雅可比矩阵(Jacobian Matrix,描述模型参数变化对观测值的影响),计算模型参数的更新量,并更新地下模型。
5. **收敛判断**:检查目标函数是否小于预设阈值,或迭代次数是否达到上限。若未收敛,则返回步骤2继续迭代。
### 中间数据存储机制
在迭代过程中,关键的中间数据通过以下方式存储:
- **内存链表**`CTestingData`类使用`CLinkList<CTdChannel*> m_tdChaList`来管理所有通道(Channel)的数据。每个`CTdChannel`对象又通过`CPtrArray m_tdRecArray`来存储该通道下所有测量点(`CRsp3DTdRecord`等)的详细记录。
- **数据库持久化**:原始测量数据和部分中间结果(如每次迭代的模型快照)会持久化存储在Access数据库中,相关的表包括`td`(任务头信息)、`tdchannel`(通道信息)、`td3dcon`3D测量记录)等。
- **XML文件缓存**`SaveHeadInfoToFile`方法将当前的测量配置和模型信息序列化为XML文件,用于临时缓存和后续处理。
```mermaid
flowchart TD
A[初始化模型] --> B[正演计算]
B --> C[计算理论视电阻率]
C --> D[与观测值对比]
D --> E[计算残差和目标函数]
E --> F{是否收敛?}
F --> |否| G[计算模型更新量]
G --> H[更新地下模型]
H --> B
F --> |是| I[输出最终模型]
```
**Diagram sources **
- [Rsp3DTd.cpp](file://cpp\Views\Rsp3DTd.cpp#L43-L51)
- [Rsp3DTdRecord.cpp](file://cpp\Views\Rsp3DTdRecord.cpp#L18-L38)
## 反演结果精度评估指标
反演结果的精度主要通过以下指标进行评估:
- **均方根误差 (RMSE)**:这是最核心的评估指标,衡量反演模型预测值与实际观测值之间的平均差异。RMSE值越小,说明模型拟合度越高。其计算公式为:`RMSE = sqrt(Σ(observed_i - predicted_i)² / N)`,其中N为数据点总数。
- **拟合优度 (Goodness of Fit, GOF)**:通常以百分比形式表示,反映观测数据被模型解释的程度。GOF越高,模型越好。
- **模型光滑度 (Model Smoothness)**:在反演目标函数中通常会加入一个正则化项,用于控制模型的复杂度,防止出现过度拟合的“斑点”模型。一个合理的模型应在拟合度和光滑度之间取得平衡。
- **残差分布图**:通过绘制残差的空间分布图,可以直观地判断模型在哪些区域拟合不佳,从而指导模型的进一步调整。
**Section sources**
- [Rsp2DTd.cpp](file://cpp\ProblemZone\Rsp2DTd.cpp#L576-L798)
- [Rsp3DTd.cpp](file://cpp\Views\Rsp3DTd.cpp#L586-L798)
## 反演剖面图生成流程
反演剖面图的生成流程主要由`AppDataRsp3DTdView`类负责,其逻辑如下:
### 渲染逻辑
1. **视图创建**`AppDataRsp3DTdView::Create`方法在创建时,会初始化一个分割窗口(Splitter Window),将主视图划分为三个子视图。
2. **子视图布局**
- **左侧视图**:创建`CAppDataTdDetailListView`,用于显示任务的详细信息列表。
- **右侧上半部分**:创建`CAppDataRsp3DTdConListView`,用于显示测量数据的内容列表(即`ShowConList`方法填充的数据)。
- **右侧下半部分**:创建`CAppDataTdGrListView`,用于显示电极状态和质量控制(GR)信息列表。
3. **数据绑定与更新**:每个子视图在`OnInitialUpdate`时,会从其关联的文档(Document)中获取数据,并调用相应的`ShowDetailInfo``ShowConList``ShowGrList`方法来填充列表控件(`CListCtrl`)。
4. **动态调整**:当窗口大小改变时,`OnSize`方法会重新计算分割窗口的布局,确保各子视图按比例正确显示。
```mermaid
graph TB
subgraph "AppDataRsp3DTdView"
A[主视图] --> B[分割窗口1]
B --> C[左侧: 详情列表]
B --> D[右侧: 分割窗口2]
D --> E[上半: 数据内容列表]
D --> F[下半: GR信息列表]
end
C --> G[ShowDetailInfo]
E --> H[ShowConList]
F --> I[ShowGrList]
```
**Diagram sources **
- [AppDataRsp3DTdView.cpp](file://cpp\Views\AppDataRsp3DTdView.cpp#L69-L97)
## SP原始数据依赖关系
电阻率反演模型与SP(激发极化)原始数据存在紧密的依赖关系:
- **数据来源**SP原始数据是反演算法的直接输入。`CRspCETd``CRsp2DTd`等类通过`LoadData`方法从数据库(如`td1dcon``td2dcon`表)中加载包含视极化率(`SP`)字段的测量记录。
- **数据处理**:在`ShowConList`方法中,代码会从数据库读取`SP`字段的值,并将其格式化后显示在用户界面的列表控件中。这表明SP数据是整个数据处理流程中的一个关键环节。
- **联合反演**:虽然当前代码主要展示了电阻率反演,但SP数据的存在暗示了系统可能支持电阻率与激发极化数据的联合反演,以获得更全面的地下物性信息。
**Section sources**
- [RspCETd.cpp](file://cpp\ProblemZone\RspCETd.cpp#L501-L575)
- [Rsp2DTd.cpp](file://cpp\ProblemZone\Rsp2DTd.cpp#L297-L377)
## 不同地质模型适配策略
系统通过`Medium`类的继承体系来适配不同的地质模型,核心策略是**多态性**和**接口抽象**。
### 适配机制
- **基类定义接口**`CMedium`基类(或其子类如`CMedium3D`)定义了一系列纯虚函数(如`GenerateSptRecElecVal``CalculateSptPtLoc``GenSptRecLevel`),这些函数构成了一个抽象接口,规定了所有地质模型必须实现的行为。
- **具体模型实现**`Medium3D.cpp``MediumCrossHoleGeomative.cpp`等文件实现了具体的地质模型。例如,`CMedium3D`类会实现3D网格化模型的生成算法,而`CMediumCrossHoleGeomative`类则会实现跨孔(Cross-Hole)探测的特定几何计算。
- **运行时绑定**:在`CRsp2DTd::Save2DRSPSetInfo`等方法中,通过`m_handleProcessor.GenerateHandle`生成特定模型的句柄,并从`m_medLinkList`链表中查找对应的`CMedium`对象。由于`m_pMedium`是指向基类的指针,在调用`CalculateDepth`等方法时,会根据实际对象的类型自动调用其对应的实现,从而实现了对不同地质模型的无缝适配。
```mermaid
classDiagram
class CMedium {
<<abstract>>
+virtual void CalculateDepth(float fA, float fFactor)
+virtual void CalculateTdPtLoc(...)
+virtual void Destroy()
}
class CMedium3D {
+void SetPoleDistance(DOUBLE f_dis_x, DOUBLE f_dis_y)
+void SetPoleStep(int f_step_x, int f_step_y)
+void SetFlags(BOOL Flags)
+void create()
+void SetRect(int x0, int y0, int x1, int y1)
+BOOL setPoleStart(int startpole)
+BOOL generate()
}
class CMediumCrossHoleGeomative {
+void SetHoleDepth(float depth)
+void SetHoleSpacing(float spacing)
+void CalculateCrossHoleGeometry()
}
CMedium <|-- CMedium3D : "继承"
CMedium <|-- CMediumCrossHoleGeomative : "继承"
```
**Diagram sources **
- [Medium3D.h](file://h\Medium3D.h#L30-L77)
- [Rsp2DTd.cpp](file://cpp\ProblemZone\Rsp2DTd.cpp#L577-L582)
## 反演流程数据流图
以下数据流图概括了从数据输入到结果输出的完整反演流程。
```mermaid
flowchart LR
A[SP原始数据] --> B[数据库存储]
B --> C[加载数据 LoadData]
C --> D[初始化模型]
D --> E[正演计算 Forward Modeling]
E --> F[误差计算 Error Calculation]
F --> G{收敛?}
G --> |否| H[模型更新 Model Update]
H --> E
G --> |是| I[生成剖面图 Render View]
I --> J[用户界面显示]
K[配置参数] --> C
K --> D
```
**Diagram sources **
- [RspCETd.cpp](file://cpp\ProblemZone\RspCETd.cpp#L142-L195)
- [AppDataRsp3DTdView.cpp](file://cpp\Views\AppDataRsp3DTdView.cpp#L69-L97)
## 典型配置参数及其影响
| 配置参数 | 参数说明 | 对反演结果的影响 |
| :--- | :--- | :--- |
| `Eamount` | 电极总数 | 电极数越多,横向和纵向分辨率越高,但测量时间也越长。 |
| `Edistance` | 电极间距 | 间距越大,探测深度越深,但横向分辨率降低。 |
| `Clayout` | 装置类型 | 不同的装置(如温纳、施伦贝谢、偶极-偶极)具有不同的探测深度和灵敏度分布,直接影响反演结果的形态。 |
| `TRfrequency` | 发射频率 | 影响激发极化效应的测量,对SP数据反演至关重要。 |
| `Ifrequency` | 工业频率 | 用于选择滤波器,抑制50Hz或60Hz的工频干扰。 |
| `SAfrequency` | 采样率 | 采样率越高,数据质量越好,但数据量也越大。 |
**Section sources**
- [Rsp2DTd.cpp](file://cpp\ProblemZone\Rsp2DTd.cpp#L467-L565)
- [RspCETd.cpp](file://cpp\ProblemZone\RspCETd.cpp#L242-L337)
@@ -0,0 +1,346 @@
# 视电阻率数据模型
<cite>
**本文档引用文件**
- [SP2DTd.cpp](file://cpp\ProblemZone\SP2DTd.cpp)
- [SP2DTd.h](file://h\SP2DTd.h)
- [SP2DTdRecord.cpp](file://cpp\ProblemZone\SP2DTdRecord.cpp)
- [SP3DTd.cpp](file://cpp\ProblemZone\SP3DTd.cpp)
- [SP3DTd.h](file://h\SP3DTd.h)
- [SP3DTdRecord.cpp](file://cpp\ProblemZone\SP3DTdRecord.cpp)
- [SPCETd.cpp](file://cpp\ProblemZone\SPCETd.cpp)
- [SPCETd.h](file://h\SPCETd.h)
- [SPCETdRecord.cpp](file://cpp\ProblemZone\SPCETdRecord.cpp)
- [AppDataSP2DTdView.cpp](file://cpp\Views\AppDataSP2DTdView.cpp)
- [TestingData.h](file://h\TestingData.h)
- [TdRecord.cpp](file://cpp\ProblemZone\TdRecord.cpp)
- [TdRecord.h](file://h\TdRecord.h)
</cite>
## 目录
1. [引言](#引言)
2. [SP系列数据模型概述](#sp系列数据模型概述)
3. [二维视电阻率数据模型 (SP2DTd)](#二维视电阻率数据模型-sp2dtd)
4. [三维视电阻率数据模型 (SP3DTd)](#三维视电阻率数据模型-sp3dtd)
5. [跨孔视电阻率数据模型 (SPCETd)](#跨孔视电阻率数据模型-spcetd)
6. [视电阻率计算原理](#视电阻率计算原理)
7. [数据可视化流程](#数据可视化流程)
8. [数据采集与处理时序流程](#数据采集与处理时序流程)
9. [字段定义与单位说明](#字段定义与单位说明)
10. [典型应用场景](#典型应用场景)
11. [异常数据识别方法](#异常数据识别方法)
12. [核心计算逻辑代码片段](#核心计算逻辑代码片段)
## 引言
本文档旨在深入解析GeomativeStudio软件中SP系列类(SP2DTd、SP3DTd、SPCETd)所代表的视电阻率数据模型。这些模型是地球物理勘探中电阻率成像技术的核心,用于处理和分析从野外采集的原始电压和电流数据,进而计算出地下介质的视电阻率值。文档将详细阐述这些模型在二维、三维及跨孔测量中的数据结构设计、物理意义、计算方法以及可视化逻辑,并提供完整的数据处理流程。
## SP系列数据模型概述
SP系列数据模型是GeomativeStudio软件中用于处理视电阻率(Self-Potential, SP)数据的核心类体系。该系列包含三个主要类:`CSP2DTd``CSP3DTd``CSPCETd`,分别对应二维、三维和跨孔(一维)测量模式。这些类均继承自`CTestingData`基类,共享通用的数据结构和处理逻辑,同时根据各自的测量几何和物理特性,定义了特定的数据字段和方法。
**Section sources**
- [SP2DTd.h](file://h\SP2DTd.h#L17-L59)
- [SP3DTd.h](file://h\SP3DTd.h#L17-L53)
- [SPCETd.h](file://h\SPCETd.h#L18-L53)
- [TestingData.h](file://h\TestingData.h)
## 二维视电阻率数据模型 (SP2DTd)
`CSP2DTd`类是二维视电阻率数据模型的具体实现,专为沿一条测线进行的二维电阻率测量设计。其数据结构主要包含测点信息、电极配置和测量结果。
### 数据结构设计
该模型的核心数据存储在`td2dcon`数据库表中,主要字段包括:
- **C1, C2**: 供电电极编号。
- **P1, P2**: 测量电极编号。
- **N**: 叠加次数。
- **K**: 装置系数,由电极间距决定。
- **I**: 测量得到的电流值(单位:mA)。
- **V**: 测量得到的电压值(单位:mV)。
- **R0**: 接地电阻(单位:Ω)。
- **SP**: 计算得到的视电阻率值(单位:Ω·m)。
### 物理意义
二维模型假设地下电性结构在垂直于测线的方向上是无限延伸且不变的。通过沿测线移动电极阵列,可以获取一系列测点的视电阻率数据,这些数据经过反演处理后,可以生成反映地下电性分布的二维剖面图。
```mermaid
classDiagram
class CSP2DTd {
+DWORD m_dwID
+CString m_szTdName
+int m_iEAmount
+int m_iCHAmount
+float m_fESpace
+CString m_szEDistance
+CTypedPtrList< CObList, CTdChannel* > m_tdChaList
+BOOL SaveData()
+BOOL LoadData(CLinkList<CMedium*>&)
+BOOL ShowConList(CListCtrl&)
+BOOL SaveHeadInfoToFile(CString&, CString&)
}
class CTdChannel {
+DWORD m_dwID
+int m_iChNum
+int m_iEAmount
+CMedium* m_pMedium
}
class CSP2DTdRecord {
+int m_iTsn
+int m_iC1
+int m_iC2
+int m_iP1
+int m_iP2
+int m_iN
+float m_fK
+float m_fI
+float m_fV
+float m_fR0
+float m_fSP
+BOOL SaveData(DWORD)
+BOOL LoadOrgData()
}
CSP2DTd --> CTdChannel : "包含"
CTdChannel --> CSP2DTdRecord : "包含"
```
**Diagram sources **
- [SP2DTd.h](file://h\SP2DTd.h#L17-L59)
- [SP2DTdRecord.h](file://h\SP2DTdRecord.h#L12-L35)
- [SP2DTd.cpp](file://cpp\ProblemZone\SP2DTd.cpp#L40-L86)
- [SP2DTdRecord.cpp](file://cpp\ProblemZone\SP2DTdRecord.cpp#L18-L38)
**Section sources**
- [SP2DTd.cpp](file://cpp\ProblemZone\SP2DTd.cpp#L279-L341)
- [SP2DTdRecord.cpp](file://cpp\ProblemZone\SP2DTdRecord.cpp#L53-L80)
## 三维视电阻率数据模型 (SP3DTd)
`CSP3DTd`类用于处理三维视电阻率数据,适用于在二维测网内进行的测量。其数据结构与二维模型类似,但需要记录更复杂的电极空间位置。
### 数据结构设计
三维模型的核心数据存储在`td3dcon`数据库表中,其字段与`td2dcon`表基本相同(C1, C2, P1, P2, I, V, R0, SP等)。关键区别在于,三维测量的电极位置信息通常在脚本(Script)或装置(Medium)定义中管理,而`CSP3DTd`类通过`m_tdChaList`列表管理多个通道的数据,以支持更复杂的测量阵列。
### 物理意义
三维模型旨在获取地下电性结构的立体分布。通过在多个测线上进行测量,可以构建一个三维数据体。该模型能够更真实地反映地下异常体的形态和空间展布,但数据采集和处理的复杂度也显著增加。
```mermaid
classDiagram
class CSP3DTd {
+DWORD m_dwID
+CString m_szTdName
+int m_iEAmount
+int m_iCHAmount
+float m_fESpace
+CString m_szEDistance
+CTypedPtrList< CObList, CTdChannel* > m_tdChaList
+BOOL SaveData()
+BOOL LoadData(CLinkList<CMedium*>&)
+BOOL ShowConList(CListCtrl&)
+BOOL SaveHeadInfoToFile(CString&, CString&)
}
class CTdChannel {
+DWORD m_dwID
+int m_iChNum
+int m_iEAmount
+CMedium* m_pMedium
}
class CSP3DTdRecord {
+int m_iTsn
+int m_iC1
+int m_iC2
+int m_iP1
+int m_iP2
+int m_iN
+float m_fK
+float m_fI
+float m_fV
+float m_fR0
+float m_fSP
+BOOL SaveData(DWORD)
+BOOL LoadOrgData()
}
CSP3DTd --> CTdChannel : "包含"
CTdChannel --> CSP3DTdRecord : "包含"
```
**Diagram sources **
- [SP3DTd.h](file://h\SP3DTd.h#L17-L53)
- [SP3DTdRecord.h](file://h\SP3DTdRecord.h#L12-L35)
- [SP3DTd.cpp](file://cpp\ProblemZone\SP3DTd.cpp#L34-L80)
- [SP3DTdRecord.cpp](file://cpp\ProblemZone\SP3DTdRecord.cpp#L18-L38)
**Section sources**
- [SP3DTd.cpp](file://cpp\ProblemZone\SP3DTd.cpp#L272-L334)
- [SP3DTdRecord.cpp](file://cpp\ProblemZone\SP3DTdRecord.cpp#L53-L80)
## 跨孔视电阻率数据模型 (SPCETd)
`CSPCETd`类用于处理跨孔(或称一维)视电阻率数据,常用于垂直电测深(VES)或井间测量。
### 数据结构设计
该模型的核心数据存储在`td1dcon`数据库表中,其字段与二维/三维模型有显著不同:
- **a, b**: 供电电极间距(单位:m)。
- **x, y**: 测量电极间距(单位:m)。
- **N**: 叠加次数。
- **K**: 装置系数,由a、b、x、y计算得出。
- **I, V, R0, SP**: 与二维/三维模型相同。
### 物理意义
跨孔模型主要用于研究地下介质随深度的变化。通过固定测量电极并逐步增大供电电极间距,可以探测到不同深度的地下电性。该模型生成的数据通常用于绘制视电阻率曲线(如S-曲线、Q-曲线),以推断地层的分层结构。
```mermaid
classDiagram
class CSPCETd {
+DWORD m_dwID
+CString m_szTdName
+int m_iEAmount
+int m_iCHAmount
+float m_fESpace
+CString m_szEDistance
+CTypedPtrList< CObList, CTdChannel* > m_tdChaList
+BOOL SaveData()
+BOOL LoadData(CLinkList<CMedium*>&)
+BOOL ShowConList(CListCtrl&)
+BOOL SaveHeadInfoToFile(CString&, CString&)
}
class CTdChannel {
+DWORD m_dwID
+int m_iChNum
+int m_iEAmount
+CMedium* m_pMedium
}
class CSPCETdRecord {
+int m_iTsn
+float m_fA
+float m_fB
+float m_fX
+float m_fY
+int m_iN
+float m_fK
+float m_fI
+float m_fV
+float m_fR0
+float m_fSP
+BOOL SaveData(DWORD)
+BOOL LoadOrgData()
}
CSPCETd --> CTdChannel : "包含"
CTdChannel --> CSPCETdRecord : "包含"
```
**Diagram sources **
- [SPCETd.h](file://h\SPCETd.h#L18-L53)
- [SPCETdRecord.h](file://h\SPCETdRecord.h#L14-L37)
- [SPCETd.cpp](file://cpp\ProblemZone\SPCETd.cpp#L32-L80)
- [SPCETdRecord.cpp](file://cpp\ProblemZone\SPCETdRecord.cpp#L18-L38)
**Section sources**
- [SPCETd.cpp](file://cpp\ProblemZone\SPCETd.cpp#L498-L562)
- [SPCETdRecord.cpp](file://cpp\ProblemZone\SPCETdRecord.cpp#L44-L77)
## 视电阻率计算原理
视电阻率(Apparent Resistivity, ρa)的计算基于欧姆定律和特定的电极装置系数(K)。其基本公式为:
ρa = K * (V / I)
其中:
- **ρa**: 视电阻率,单位为欧姆·米(Ω·m)。
- **K**: 装置系数,单位为米(m),由所采用的电极排列方式(如温纳装置、施伦贝谢装置等)和电极间距决定。
- **V**: 测量得到的电压值,单位为伏特(V)。
- **I**: 测量得到的电流值,单位为安培(A)。
在代码实现中,`CSP2DTdRecord``CSP3DTdRecord``CSPCETdRecord`类的`SaveData`方法负责将计算出的`m_fSP`(即ρa)值保存到相应的数据库表(`td2dcon``td3dcon``td1dcon`)中。
**Section sources**
- [SP2DTdRecord.cpp](file://cpp\ProblemZone\SP2DTdRecord.cpp#L68-L80)
- [SP3DTdRecord.cpp](file://cpp\ProblemZone\SP3DTdRecord.cpp#L68-L80)
- [SPCETdRecord.cpp](file://cpp\ProblemZone\SPCETdRecord.cpp#L61-L77)
## 数据可视化流程
`AppDataSP2DTdView.cpp`文件定义了二维视电阻率数据的可视化界面。其核心是创建一个分栏视图,将数据详情、测量内容和接地电阻列表组织在一起。
### 可视化逻辑
1. **视图创建 (`Create`)**: 该方法使用`CSplitterWnd`创建一个静态分栏器,将主视图分为左右两部分。
2. **左侧面板**: 左侧创建一个`CAppDataTdDetailListView`视图,用于显示测试任务的详细信息(如任务名称、位置、设备型号等)。
3. **右侧面板**: 右侧再创建一个上下分栏的`CSplitterWnd`
- **上方面板**: 创建一个`CAppDataSP2DTdConListView`视图,用于显示所有测点的测量数据(即`td2dcon`表中的内容)。
- **下方面板**: 创建一个`CAppDataTdGrListView`视图,用于显示各电极的接地电阻测量结果。
4. **数据映射**: `CAppDataSP2DTdConListView`视图通过调用`CSP2DTd::ShowConList`方法,从数据库中查询数据并填充到列表控件中,实现了数据到曲线图的映射。
```mermaid
flowchart TD
A[AppDataSP2DTdView::Create] --> B[创建左右分栏]
B --> C[左侧面板: CAppDataTdDetailListView]
B --> D[右侧面板: 上下分栏]
D --> E[上方面板: CAppDataSP2DTdConListView]
D --> F[下方面板: CAppDataTdGrListView]
E --> G[调用 CSP2DTd::ShowConList]
G --> H[查询 td2dcon 表]
H --> I[填充列表控件]
F --> J[显示接地电阻]
```
**Diagram sources **
- [AppDataSP2DTdView.cpp](file://cpp\Views\AppDataSP2DTdView.cpp#L71-L103)
**Section sources**
- [AppDataSP2DTdView.cpp](file://cpp\Views\AppDataSP2DTdView.cpp#L71-L103)
- [SP2DTd.cpp](file://cpp\ProblemZone\SP2DTd.cpp#L279-L341)
## 数据采集与处理时序流程
从设备接收原始数据包到最终存储为视电阻率数据,整个流程遵循严格的时序。
### 处理路径
1. **数据包接收**: 设备通过串口或网络将原始数据包发送给软件。
2. **数据解析**: 软件解析数据包,提取出原始的电压(Vrawdata)和电流(Irawdata)序列。这些数据被存储在`td2dcon``td3dcon``td1dcon`表的相应字段中。
3. **数据加载**: `CTdRecord`类的`LoadOrgData`方法(如`Load2DOrgData`)被调用,从数据库中读取原始数据序列。
4. **数据处理**: 原始数据经过滤波、去噪等预处理,并计算出最终的电压值V和电流值I。
5. **视电阻率计算**: 根据公式 ρa = K * (V / I) 计算视电阻率值SP。
6. **数据存储**: 计算结果(I, V, R0, SP)通过`CSPxDTdRecord::SaveData`方法写回数据库。
```mermaid
sequenceDiagram
participant 设备 as "测量设备"
participant 软件 as "GeomativeStudio软件"
participant 数据库 as "数据库"
设备->>软件 : 发送原始数据包(Vrawdata, Irawdata)
软件->>数据库 : 解析并存储原始数据
软件->>数据库 : 查询原始数据(LoadOrgData)
软件->>软件 : 预处理并计算V, I
软件->>软件 : 计算视电阻率SP = K * (V/I)
软件->>数据库 : 存储最终结果(SaveData)
```
**Diagram sources **
- [TdRecord.cpp](file://cpp\ProblemZone\TdRecord.cpp#L34-L320)
- [SP2DTdRecord.cpp](file://cpp\ProblemZone\SP2DTdRecord.cpp#L53-L80)
## 字段定义与单位说明
| 字段名 | 中文名称 | 数据类型 | 单位 | 说明 |
| :--- | :--- | :--- | :--- | :--- |
| `C1`, `C2` | 供电电极 | int | 无 | 电极编号 |
| `P1`, `P2` | 测量电极 | int | 无 | 电极编号 |
| `a`, `b` | 供电电极间距 | float | 米 (m) | 仅SPCETd模型 |
| `x`, `y` | 测量电极间距 | float | 米 (m) | 仅SPCETd模型 |
| `I` | 电流 | float | 毫安 (mA) | 测量得到的电流值 |
| `V` | 电压 | float | 毫伏 (mV) | 测量得到的电压值 |
| `R0` | 接地电阻 | float | 欧姆 (Ω) | 电极接地电阻 |
| `SP` | 视电阻率 | float | 欧姆·米 (Ω·m) | 计算得到的视电阻率值 |
| `K` | 装置系数 | float | 米 (m) | 由电极排列方式决定 |
| `N` | 叠加次数 | int | 无 | 信号叠加次数 |
| `Espace` | 电极步长 | float | 米 (m) | 移动电极的步长 |
| `Edistance` | 电极距离 | float | 米 (m) | 电极间的距离 |
## 典型应用场景
- **SP2DTd**: 用于二维地质剖面调查,如滑坡体探测、地下水污染羽流成像、岩溶发育区调查等。
- **SP3DTd**: 用于三维地质体精细成像,如矿体圈定、地下空洞三维定位、复杂地质构造研究等。
- **SPCETd**: 用于地层垂向分层研究,如工程地质勘察中的土层划分、地下水含水层深度探测、基岩面起伏调查等。
## 异常数据识别方法
1. **接地电阻异常**: 通过`gr`表检查各电极的接地电阻`OMvalue`。若电阻值过高(如大于10kΩ)或为-9999(表示未测量),则表明电极接触不良。
2. **电压/电流值异常**: 检查`V``I`值是否为零或接近零。若`I`为零,则供电回路可能断开;若`V`为零而`I`正常,则测量回路可能断开。
3. **视电阻率值异常**: 检查`SP`值是否为负数或极大值。负值通常由电极极性接反或强电磁干扰引起;极大值可能由数据采集错误或极端地质条件导致。
4. **数据完整性检查**: 确保每个测点(TSN)都有对应的`C1, C2, P1, P2`配置和有效的`V, I`读数。
## 核心计算逻辑代码片段
视电阻率的计算和存储逻辑主要在`CSPxDTdRecord`类的`SaveData`方法中实现。该方法将计算结果插入到相应的数据库表中。
**Section sources**
- [SP2DTdRecord.cpp](file://cpp\ProblemZone\SP2DTdRecord.cpp#L53-L80)
- [SP3DTdRecord.cpp](file://cpp\ProblemZone\SP3DTdRecord.cpp#L53-L80)
- [SPCETdRecord.cpp](file://cpp\ProblemZone\SPCETdRecord.cpp#L44-L77)
@@ -0,0 +1,118 @@
# Views模块
<cite>
**Referenced Files in This Document**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [taskmngframe.cpp](file://cpp/Views/taskmngframe.cpp)
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp)
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp)
- [CDialogLoggingWnd.cpp](file://cpp/logging/CDialogLoggingWnd.cpp)
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp)
</cite>
## 目录
1. [简介](#简介)
2. [主框架窗口设计](#主框架窗口设计)
3. [设备管理框架](#设备管理框架)
4. [任务管理框架](#任务管理框架)
5. [数据管理框架](#数据管理框架)
6. [对话框用户交互逻辑](#对话框用户交互逻辑)
7. [跨孔测量UI组件](#跨孔测量ui组件)
8. [测井功能UI](#测井功能ui)
9. [自定义控件实现](#自定义控件实现)
10. [UI消息映射机制](#ui消息映射机制)
## 简介
Views模块是GeomativeStudio项目的核心用户界面组件集合,负责实现所有UI相关的功能。该模块包含主框架窗口、设备管理、任务管理、数据管理等多个框架窗口,以及各种对话框和自定义控件。这些组件共同构成了应用程序的用户交互界面,通过MFC框架实现丰富的图形用户界面功能。
## 主框架窗口设计
主框架窗口由MainFrm.cpp实现,作为应用程序的主容器,管理所有子窗口和UI元素。该窗口继承自CMDIFrameWnd,支持多文档界面(MDI)架构。在OnCreate方法中,初始化了工具栏和状态栏,并创建了启动画面。主框架窗口通过成员变量m_pDataMngFrm、m_pDevMngFrm和m_pSptMngFrm分别管理数据管理、设备管理和任务管理框架窗口的实例。
消息映射系统处理各种用户操作,如菜单命令IDM_MNG_DATA_WIN、IDM_MNG_EXEC_WIN和IDM_MNG_DEV_WIN,分别用于显示数据管理、执行管理和设备管理窗口。当用户选择这些菜单项时,框架会检查相应窗口是否已存在,如果不存在则创建新的子窗口,否则激活已存在的窗口。
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L1-L800)
## 设备管理框架
设备管理框架由devmngframe.cpp实现,继承自CMDIChildWnd,作为MDI子窗口运行。该框架采用分割窗口设计,左侧为导航视图(CNavDevView),右侧为内容视图,根据设备状态动态切换显示内容。
框架通过m_splitter对象创建静态分割窗口,左侧显示设备树形结构,右侧根据设备状态显示不同的视图:在线设备显示CAppDevOLView,离线设备显示CAppDevView,无选择状态显示CBlankView。这种设计实现了灵活的UI布局,能够根据设备连接状态动态调整界面内容。
消息映射系统处理设备管理相关的各种操作,如IDM_OP_DE_REG_O_UPG(设备升级)、IDM_OP_DE_REG_O_MP(修改设备参数)和IDM_REM_GD10_TASK_MANAGER(远程任务管理)。ShowAppView方法根据设备状态决定显示哪个视图,并调用相应的操作类方法更新界面内容。
**Section sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L1-L800)
## 任务管理框架
任务管理框架由taskmngframe.cpp实现,同样继承自CMDIChildWnd。该框架的实现相对简单,目前仅包含基本的框架结构和消息映射,没有具体的UI元素或业务逻辑实现。
从代码结构看,该框架预留了扩展空间,但当前版本中未实现具体的功能。这表明任务管理功能可能在其他模块中实现,或者该框架将在后续版本中进一步开发。
**Section sources**
- [taskmngframe.cpp](file://cpp/Views/taskmngframe.cpp#L1-L36)
## 数据管理框架
数据管理框架由datamngframe.cpp实现,继承自CMDIChildWnd,采用与设备管理框架类似的分割窗口设计。左侧为CNavDataView导航视图,右侧为内容视图,根据数据类型动态切换。
框架支持多种数据类型的管理,包括2D电阻率数据(CAppDataRsp2DTdView)、2D激电数据(CAppDataIpsp2DTdView)、3D电阻率数据(CAppDataRsp3DTdView)等。ShowAppView和ShowContentListByPageView方法根据数据类型和状态决定显示哪个视图,并调用CDataOperator操作类的方法加载和显示数据。
消息映射系统处理数据管理的各种操作,如IDM_OP_TD_2DRSP_DB_D(删除2D电阻率数据)、IDM_OP_TD_2DRSP_DB_EXCEL(导出2D电阻率数据到Excel)和IDM_OP_TD_2DRSP_DB_GRAP(显示2D电阻率数据图表)。这些操作通过CDataOperator类与后台数据管理器进行交互,实现数据的增删改查功能。
**Section sources**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L1-L800)
## 对话框用户交互逻辑
Views模块包含多个对话框实现,用于处理特定的用户交互场景。DialNew2DTask.cpp实现创建新2D任务的对话框,提供任务名称、测试地点、测试类型、装置类型等参数的输入界面。
对话框通过组合框控件实现选项选择,如m_cmbTestType用于选择测试方法(电阻率、激电、自电),m_cmbArray用于选择装置类型。OnInitDialog方法初始化界面元素,设置默认值和本地化文本。OnSelchangeCombo2dTestType等事件处理方法根据用户选择动态更新相关控件的状态。
DialCfgTaskPacket.cpp实现配置任务包的对话框,允许用户将多个任务组合成一个任务包,并设置循环次数、时间间隔等参数。对话框使用列表控件m_listTaskPacket显示已添加的任务,提供添加和删除功能。用户可以通过界面设置PLC ID、循环次数和时间间隔,然后保存到数据库。
**Section sources**
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L1-L665)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L301)
## 跨孔测量UI组件
跨孔测量功能由crossHole目录下的组件实现,主要包括CCrossHoleConfig2DMainDlg.cpp。该对话框提供跨孔测量的配置界面,包含电极坐标、井下、地面和参数四个选项卡页面。
通过m_tabChange选项卡控件实现多页面切换,每个页面对应不同的配置内容。井下和地面页面使用COption2DBoreholeDlg和COption2DSurfaceDlg等子对话框实现具体功能。CCrosshole2dDrawingBoardDlg用于显示和编辑电极坐标,C2DSimulationDlg用于模拟测量过程。
TwoBoreholeGenerateScript方法实现跨孔测量脚本的生成算法,根据两个孔的电极位置计算测量点的ABMN参数和几何因子K值。SaveTestPointToDB方法将生成的脚本保存到数据库,包括脚本基本信息、通道信息和测点信息。
**Section sources**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp#L1-L800)
## 测井功能UI
测井功能由logging目录下的组件实现,主要包括CDialogLoggingWnd.cpp。该对话框实现测井数据的显示界面,采用自定义绘制方式呈现测井曲线和岩性柱状图。
OnInitDialog方法初始化界面布局,设置各静态文本控件的位置。DrawFirstColumnStatic到DrawSixColumnStatic系列方法负责绘制界面的六个列区域,包括钻孔编号、探管型号、测量时间等基本信息。OnPaint方法实现自定义绘制,绘制测井曲线、深度刻度线和岩性柱状图。
UpdateLowHighValue方法更新各测量参数的最小值和最大值显示,用于指示数据范围。对话框支持加载测井数据文件,根据数据动态调整绘图区域大小,并在界面上绘制SP(自电)、长电位电阻率、短电位电阻率和梯度电阻率等测井曲线。
**Section sources**
- [CDialogLoggingWnd.cpp](file://cpp/logging/CDialogLoggingWnd.cpp#L1-L800)
## 自定义控件实现
ctrl目录包含自定义控件的实现,主要是CDragListCtrl.cpp。该控件继承自CListCtrl,扩展了拖拽功能,允许用户通过鼠标拖拽重新排序列表项。
控件通过重写OnLvnBegindrag、OnMouseMove和OnLButtonUp等消息处理方法实现拖拽逻辑。在OnLvnBegindrag中创建拖拽图像列表,并开始拖拽操作。OnMouseMove方法更新拖拽图像的位置,OnLButtonUp方法结束拖拽操作并清理资源。
CDragList辅助类提供拖拽操作的底层支持,BeginDrag、Dragging和EndDrag方法分别处理拖拽的开始、过程和结束阶段。这种设计实现了流畅的拖拽用户体验,允许用户直观地重新排列列表项。
**Section sources**
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp#L1-L260)
## UI消息映射机制
Views模块采用MFC的消息映射机制处理用户交互。每个UI类通过BEGIN_MESSAGE_MAP和END_MESSAGE_MAP宏定义消息映射表,将Windows消息或命令ID映射到相应的处理方法。
例如,主框架窗口的消息映射表将ON_COMMAND(IDM_MNG_DATA_WIN, OnMngDataWin)映射到OnMngDataWin方法,当用户点击"数据管理"菜单时触发该方法。设备管理框架通过ON_MESSAGE(WM_SCHEDULE, OnSchedule)处理自定义的WM_SCHEDULE消息,用于更新界面状态。
消息处理方法通常先进行参数验证和状态检查,然后调用相应的业务逻辑类完成具体操作。例如,OnDevieUpgrade方法先确认用户是否要进行升级,然后调用m_pDevOperator->DevieUpgrade方法执行升级操作。这种设计实现了UI层与业务逻辑层的分离,提高了代码的可维护性。
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L1-L800)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L1-L800)
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L1-L800)
@@ -0,0 +1,248 @@
# 专用功能界面
<cite>
**本文档引用的文件**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp)
- [CCrossHoleConfig3DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig3DMainDlg.cpp)
- [COption2DGeometryDlg.cpp](file://cpp/crossHole/COption2DGeometryDlg.cpp)
- [COption3DGeometryDlg.cpp](file://cpp/crossHole/COption3DGeometryDlg.cpp)
- [CDialogLoggingWnd.cpp](file://cpp/logging/CDialogLoggingWnd.cpp)
- [CDialogLoggingParameterSetting.cpp](file://cpp/logging/CDialogLoggingParameterSetting.cpp)
- [CDialogLoggingLithologicWnd.cpp](file://cpp/logging/CDialogLoggingLithologicWnd.cpp)
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp)
- [CListTextColorCtrl.cpp](file://cpp/ctrl/CListTextColorCtrl.cpp)
- [CCrosshole2dDrawingBoardDlg.cpp](file://cpp/crossHole/CCrosshole2dDrawingBoardDlg.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [跨孔测量配置对话框设计](#跨孔测量配置对话框设计)
3. [几何参数设置逻辑](#几何参数设置逻辑)
4. [测井功能用户界面实现](#测井功能用户界面实现)
5. [自定义控件绘制与交互机制](#自定义控件绘制与交互机制)
6. [专用UI与后台算法协同工作](#专用ui与后台算法协同工作)
7. [自定义控件消息处理与重绘逻辑](#自定义控件消息处理与重绘逻辑)
8. [复杂参数配置验证与默认值管理](#复杂参数配置验证与默认值管理)
9. [跨孔测量与测井功能操作流程](#跨孔测量与测井功能操作流程)
10. [自定义控件扩展最佳实践](#自定义控件扩展最佳实践)
## 引言
本项目Geomative Studio是一款专业的地质勘探软件,专注于跨孔测量和测井功能的实现。系统通过专用的UI组件为用户提供直观、高效的操作界面,支持2D和3D跨孔测量配置、测井参数设置、数据可视化等功能。核心功能模块包括跨孔测量配置对话框、几何参数设置、测井功能界面以及自定义控件等。这些组件通过精心设计的架构和交互逻辑,实现了从用户输入到数据处理再到结果展示的完整工作流。系统采用MFC框架开发,利用对话框、列表控件等标准UI元素,并结合自定义绘制和消息处理机制,提供了高度可定制的用户界面体验。
**Section sources**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp#L1-L50)
- [CDialogLoggingWnd.cpp](file://cpp/logging/CDialogLoggingWnd.cpp#L1-L50)
## 跨孔测量配置对话框设计
跨孔测量配置对话框是系统的核心功能之一,提供2D和3D两种模式的测量配置。`CCrossHoleConfig2DMainDlg``CCrossHoleConfig3DMainDlg`两个类分别实现了2D和3D模式的对话框功能。对话框采用标签页(Tab)设计,包含"电极坐标"、"井下"、"地面"和"参数"四个主要页面。用户可以通过标签页切换不同的配置视图。对话框初始化时,会创建并管理多个子对话框,如`CCrosshole2dDrawingBoardDlg`用于2D绘图,`C2DSimulationDlg`用于模拟显示,以及`COption2DGeometryDlg``COption2DBoreholeDlg`等用于具体参数设置。这种设计实现了功能的模块化和界面的层次化,提高了代码的可维护性和用户体验。
```mermaid
classDiagram
class CCrossHoleConfig2DMainDlg {
+m_tabChange CTabCtrl
+m_pConnection _ConnectionPtr
+m_vecAllBoreholeABMNInfo vector<STDatabaseABMNInfo>
+m_mapDatabaseABMNInfo map<int, map<int, map<int, STDatabaseABMNInfo>>>
+GetInstance() CCrossHoleConfig2DMainDlg*
+OnInitDialog() BOOL
+OnBnClickedBtnCreate() void
+OnBnClickedBtnLoadGeometry() void
+SaveTestPointToDB() BOOL
}
class CCrossHoleConfig3DMainDlg {
+m_tabChange CTabCtrl
+m_pConnection _ConnectionPtr
+m_vecAllBoreholeABMNInfo vector<STDatabaseABMNInfo>
+m_mapDatabaseABMNInfo map<int, map<int, map<int, STDatabaseABMNInfo>>>
+GetInstance() CCrossHoleConfig3DMainDlg*
+OnInitDialog() BOOL
+OnBnClickedBtnCreate() void
+OnBnClickedBtnLoadGeometry() void
+SaveTestPointToDB() BOOL
}
class COption2DGeometryDlg {
+m_geometryList CListCtrl
+m_vecNoSortAllPoints vector<STBoreHolePoints>
+m_mapBoreholeCoordinates map<STWellPoints, vector<STBoreHolePoints>>
+m_vecSurfaceCoordinates vector<STBoreHolePoints>
+GetInstance() COption2DGeometryDlg*
+AddCoordinatesPoints() void
+DeleteCoordinatesPoint() void
+ShowCoordinatesPoints() void
}
class COption3DGeometryDlg {
+m_geometryList CListCtrl
+m_vecNoSortAllPoints vector<STBoreHolePoints>
+m_mapBoreholeCoordinates map<STWellPoints, vector<STBoreHolePoints>>
+m_mapSurfaceXCoordinates map<float, vector<STBoreHolePoints>>
+m_mapSurfaceYCoordinates map<float, vector<STBoreHolePoints>>
+GetInstance() COption3DGeometryDlg*
+AddCoordinatesPoints() void
+DeleteCoordinatesPoint() void
+ShowCoordinatesPoints() void
}
CCrossHoleConfig2DMainDlg --> COption2DGeometryDlg : "包含"
CCrossHoleConfig3DMainDlg --> COption3DGeometryDlg : "包含"
CCrossHoleConfig2DMainDlg --> CCrosshole2dDrawingBoardDlg : "包含"
CCrossHoleConfig3DMainDlg --> CCrosshole3dDrawingBoardDlg : "包含"
```
**Diagram sources **
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp#L15-L20)
- [CCrossHoleConfig3DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig3DMainDlg.cpp#L15-L20)
- [COption2DGeometryDlg.cpp](file://cpp/crossHole/COption2DGeometryDlg.cpp#L19-L20)
- [COption3DGeometryDlg.cpp](file://cpp/crossHole/COption3DGeometryDlg.cpp#L19-L20)
**Section sources**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp#L11-L800)
- [CCrossHoleConfig3DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig3DMainDlg.cpp#L11-L800)
## 几何参数设置逻辑
几何参数设置是跨孔测量配置的核心环节,主要由`COption2DGeometryDlg``COption3DGeometryDlg`两个类实现。这两个类负责管理电极的坐标信息,包括井下电极和地表电极。`COption2DGeometryDlg`使用`CListCtrl`控件`m_geometryList`以列表形式展示所有电极的ID、地址、X、Y、Z坐标。用户可以通过"加载坐标"按钮从`.geomative`文件中导入坐标数据,系统会解析CSV格式的文件内容,将电极信息存储在`m_vecNoSortAllPoints`向量中,并同步更新列表显示。对于3D模式,`COption3DGeometryDlg`还支持X方向和Y方向的电缆测线,使用`m_mapSurfaceXCoordinates``m_mapSurfaceYCoordinates`两个映射来分别管理不同方向的测线数据。当用户添加或删除坐标点时,系统会自动调用`AddCoordinatesPoints``DeleteCoordinatesPoint`方法更新内部数据结构,并通知绘图板进行重绘。
```mermaid
flowchart TD
Start([开始]) --> LoadGeometry["加载坐标文件"]
LoadGeometry --> ParseFile["解析.geomative文件"]
ParseFile --> ExtractPoints["提取电极坐标点"]
ExtractPoints --> ClassifyPoints{"分类坐标点"}
ClassifyPoints --> |地表| AddToSurface["添加到地表集合"]
ClassifyPoints --> |井下| AddToBorehole["添加到井下集合"]
AddToSurface --> UpdateList["更新列表显示"]
AddToBorehole --> UpdateList
UpdateList --> NotifyDrawingBoard["通知绘图板更新"]
NotifyDrawingBoard --> End([结束])
```
**Diagram sources **
- [COption2DGeometryDlg.cpp](file://cpp/crossHole/COption2DGeometryDlg.cpp#L78-L103)
- [COption3DGeometryDlg.cpp](file://cpp/crossHole/COption3DGeometryDlg.cpp#L78-L108)
**Section sources**
- [COption2DGeometryDlg.cpp](file://cpp/crossHole/COption2DGeometryDlg.cpp#L1-L309)
- [COption3DGeometryDlg.cpp](file://cpp/crossHole/COption3DGeometryDlg.cpp#L1-L396)
## 测井功能用户界面实现
测井功能的用户界面由`CDialogLoggingWnd``CDialogLoggingParameterSetting``CDialogLoggingLithologicWnd`三个主要对话框构成。`CDialogLoggingWnd`是主窗口,负责展示测井数据的完整报告,包括公司名称、钻孔编号、井深、测井方向等基本信息,以及自电、长电位、短电位和梯度电阻率的曲线图。`CDialogLoggingParameterSetting`用于设置测井参数,如任务名、测试地点、测井类型、采样间隔、初始深度、结束深度等。`CDialogLoggingLithologicWnd`则用于编辑和管理岩性剖面,用户可以添加、删除和修改不同深度范围的岩性信息。这些对话框通过消息映射(`BEGIN_MESSAGE_MAP`)处理用户的交互操作,如按钮点击、下拉框选择等,并通过`CMarkup`类解析和加载XML格式的参数文件和DAT格式的数据文件。
```mermaid
sequenceDiagram
participant User as "用户"
participant ParamDlg as "CDialogLoggingParameterSetting"
participant MainWnd as "CDialogLoggingWnd"
participant DataOper as "CLoggingDataOper"
User->>ParamDlg : 打开参数设置对话框
ParamDlg->>DataOper : 查询任务列表
DataOper-->>ParamDlg : 返回任务信息
ParamDlg->>ParamDlg : 填充下拉框
User->>ParamDlg : 选择任务并修改参数
ParamDlg->>DataOper : 更新任务信息到数据库
DataOper-->>ParamDlg : 返回操作结果
ParamDlg->>MainWnd : 传递测井参数
User->>MainWnd : 打开测井文件
MainWnd->>MainWnd : 加载XML参数文件
MainWnd->>MainWnd : 加载DAT数据文件
MainWnd->>MainWnd : 解析并绘制曲线图
MainWnd-->>User : 显示测井报告
```
**Diagram sources **
- [CDialogLoggingParameterSetting.cpp](file://cpp/logging/CDialogLoggingParameterSetting.cpp#L34-L37)
- [CDialogLoggingWnd.cpp](file://cpp/logging/CDialogLoggingWnd.cpp#L45-L51)
- [CDialogLoggingLithologicWnd.cpp](file://cpp/logging/CDialogLoggingLithologicWnd.cpp#L50-L59)
**Section sources**
- [CDialogLoggingWnd.cpp](file://cpp/logging/CDialogLoggingWnd.cpp#L1-L1222)
- [CDialogLoggingParameterSetting.cpp](file://cpp/logging/CDialogLoggingParameterSetting.cpp#L1-L356)
- [CDialogLoggingLithologicWnd.cpp](file://cpp/logging/CDialogLoggingLithologicWnd.cpp#L1-L304)
## 自定义控件绘制与交互机制
系统实现了两个重要的自定义控件:`CDragListCtrl``CListTextColorCtrl``CDragListCtrl`继承自`CListCtrl`,支持列表项的拖拽操作。它通过重写`OnLvnBegindrag``OnMouseMove``OnLButtonUp`消息处理函数,实现了拖拽的开始、移动和结束逻辑。当用户开始拖拽时,系统创建一个`CImageList`作为拖拽图像,并调用`DragEnter`方法显示拖拽效果。在鼠标移动过程中,`DragMove`方法会实时更新拖拽图像的位置。`CListTextColorCtrl`则是一个支持自定义文本颜色和背景颜色的列表控件。它通过将控件设置为`LVS_OWNERDRAWFIXED`风格,并重写`DrawItem`方法,实现了对每个列表项的自定义绘制。控件内部维护了`m_colTextColor``m_ItemTextColor`等链表,用于存储列和单元格的文本颜色,从而实现灵活的样式控制。
```mermaid
classDiagram
class CDragListCtrl {
+m_nSelItem int
+m_pDragImageList CImageList*
+m_bDragging BOOL
+OnLvnBegindrag() void
+OnMouseMove() void
+OnLButtonUp() void
}
class CListTextColorCtrl {
+m_nRowHeight int
+m_fontHeight int
+m_fontWith int
+m_color COLORREF
+m_ptrListCol CPtrList
+m_ptrListItem CPtrList
+m_colTextColor CPtrList
+m_ItemTextColor CPtrList
+DrawItem() void
+MeasureItem() void
+SetColTextColor() void
+SetItemTextColor() void
}
CDragListCtrl --|> CListCtrl : "继承"
CListTextColorCtrl --|> CListCtrl : "继承"
```
**Diagram sources **
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp#L9-L17)
- [CListTextColorCtrl.cpp](file://cpp/ctrl/CListTextColorCtrl.cpp#L16-L21)
**Section sources**
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp#L1-L260)
- [CListTextColorCtrl.cpp](file://cpp/ctrl/CListTextColorCtrl.cpp#L1-L399)
## 专用UI与后台算法协同工作
专用UI组件与后台算法模块通过数据结构和函数调用紧密协同工作。以跨孔测量配置为例,用户在`COption2DGeometryDlg`中设置的电极坐标,会通过`AddCoordinatesPoints`方法传递给`CCrossHoleConfig2DMainDlg`。当用户点击"创建"按钮时,`CCrossHoleConfig2DMainDlg`会调用`TwoBoreholeGenerateScript`等算法函数,根据电极的相对位置和间距,计算出测点的ABMN参数和几何因子K值。这些计算结果被存储在`m_vecAllBoreholeABMNInfo`向量中,最终通过`SaveTestPointToDB`方法写入数据库。对于测井功能,`CDialogLoggingParameterSetting`收集的参数被封装成`STLoggingParamSettingReq`结构体,传递给数据采集模块。采集到的数据则由`CDialogLoggingWnd`负责解析和可视化,实现了从用户配置到数据采集再到结果展示的完整闭环。
**Section sources**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp#L734-L736)
- [CDialogLoggingParameterSetting.cpp](file://cpp/logging/CDialogLoggingParameterSetting.cpp#L353-L356)
## 自定义控件消息处理与重绘逻辑
自定义控件的消息处理和重绘逻辑是其核心功能的实现基础。`CListTextColorCtrl`通过`PreSubclassWindow`方法将控件风格修改为`LVS_OWNERDRAWFIXED`,这表示控件将自行负责绘制其内容。当需要重绘时,系统会调用`DrawItem`方法。该方法首先获取要绘制的列表项信息,然后根据项的状态(选中或未选中)设置不同的背景色。接着,它会遍历所有列,计算每列的显示位置,并从`m_colTextColor``m_ItemTextColor`链表中查找对应的文本颜色,最后使用`DrawText`函数将文本绘制到指定位置。为了支持行高设置,控件重写了`MeasureItem`方法,根据`m_nRowHeight`成员变量的值来确定每一行的高度。这种机制使得控件能够灵活地适应不同的显示需求。
**Section sources**
- [CListTextColorCtrl.cpp](file://cpp/ctrl/CListTextColorCtrl.cpp#L62-L69)
- [CListTextColorCtrl.cpp](file://cpp/ctrl/CListTextColorCtrl.cpp#L71-L234)
## 复杂参数配置验证与默认值管理
系统对复杂参数配置进行了严格的验证和默认值管理。在`CDialogLoggingParameterSetting`中,当用户点击"确定"按钮时,`OnBnClickedOk`方法会执行一系列验证检查。例如,它会检查任务名、采样间隔、初始深度等必填字段是否为空,以及测井类型是否已选择。如果验证失败,会弹出相应的错误提示。对于数值型参数,系统会使用`atof`函数将其从字符串转换为浮点数,并进行范围检查。此外,系统还实现了默认值管理,例如在`OnInitDialog`方法中,会将"迭代次数"的默认值设置为0,并将"发射波形"的默认选项设置为"0+0-"。对于跨孔测量配置,系统会根据电极的Z坐标自动计算L值的取值范围,并确保生成的测点符合物理规律。
**Section sources**
- [CDialogLoggingParameterSetting.cpp](file://cpp/logging/CDialogLoggingParameterSetting.cpp#L174-L351)
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp#L302-L349)
## 跨孔测量与测井功能操作流程
对于初学者,跨孔测量和测井功能的操作流程如下:
1. **跨孔测量配置**
* 打开"跨孔测量配置"对话框。
* 切换到"井下"或"地面"标签页,通过"加载坐标"按钮导入电极坐标。
* 切换到"参数"标签页,输入脚本名称、时间间隔等信息。
* 点击"创建"按钮生成测点脚本。
* 点击"开始模拟"按钮进行模拟运行。
2. **测井功能使用**
* 在主界面选择"测井"功能。
* 点击"参数设置"按钮,配置任务名、测井类型、深度范围等参数。
* 开始数据采集。
* 采集完成后,点击"打开文件"按钮加载测井数据。
* 在主窗口查看自电、电阻率等曲线图,并通过"岩性编辑"功能添加岩性剖面。
**Section sources**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp#L734-L736)
- [CDialogLoggingParameterSetting.cpp](file://cpp/logging/CDialogLoggingParameterSetting.cpp#L174-L351)
## 自定义控件扩展最佳实践
对于高级开发者,扩展自定义控件的最佳实践包括:
1. **继承与重写**:从标准MFC控件(如`CListCtrl`)继承,并重写关键的虚函数,如`DrawItem``PreSubclassWindow`等。
2. **消息映射**:使用`BEGIN_MESSAGE_MAP`宏将Windows消息(如`WM_PAINT``WM_LBUTTONDOWN`)映射到自定义的消息处理函数。
3. **状态管理**:在控件类中定义私有成员变量来管理控件的内部状态,如选中的项、拖拽状态、自定义颜色等。
4. **资源管理**:注意GDI对象(如`CPen``CBrush``CFont`)的创建和销毁,避免资源泄漏。通常在`OnPaint`等函数中创建,并在函数结束前通过`SelectObject`恢复旧对象。
5. **性能优化**:对于复杂的绘制操作,考虑使用双缓冲技术(Double Buffering)来减少屏幕闪烁。可以通过在内存DC上先绘制,再一次性拷贝到屏幕DC上来实现。
**Section sources**
- [CListTextColorCtrl.cpp](file://cpp/ctrl/CListTextColorCtrl.cpp#L1-L399)
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp#L1-L260)
@@ -0,0 +1,410 @@
# 主界面
<cite>
**本文档中引用的文件**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp)
- [ChildView.cpp](file://cpp/Views/ChildView.cpp)
- [Splash.cpp](file://cpp/Views/Splash.cpp)
- [MainFrm.h](file://h/MainFrm.h)
- [ChildFrm.h](file://h/ChildFrm.h)
- [ChildView.h](file://h/ChildView.h)
- [Splash.h](file://h/Splash.h)
- [GeoMative.rc2](file://res/GeoMative.rc2)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp)
</cite>
## 目录
1. [主界面架构概述](#主界面架构概述)
2. [主窗口初始化流程](#主窗口初始化流程)
3. [菜单栏、工具栏与状态栏构建](#菜单栏工具栏与状态栏构建)
4. [多文档界面(MDI)组织方式](#多文档界面mdi组织方式)
5. [子窗口创建与管理逻辑](#子窗口创建与管理逻辑)
6. [启动画面显示控制](#启动画面显示控制)
7. [UI元素资源定义与消息映射](#ui元素资源定义与消息映射)
8. [用户操作路由机制](#用户操作路由机制)
9. [主界面与其他管理模块的数据交互](#主界面与其他管理模块的数据交互)
10. [MFC框架下的窗口生命周期管理](#mfc框架下的窗口生命周期管理)
11. [性能优化建议](#性能优化建议)
## 主界面架构概述
Geomative Studio主界面采用MFCMicrosoft Foundation Classes)框架实现,基于多文档界面(MDI)架构。系统通过`CMainFrame`类作为主框架窗口,继承自`CMDIFrameWnd`,负责管理整个应用程序的主窗口、菜单栏、工具栏和状态栏。主界面通过消息映射机制处理用户交互,并与设备管理、项目管理和数据管理器等模块进行数据交互。
主界面架构采用分层设计,包括:
- **主框架层**`CMainFrame`负责整体布局和核心功能调度
- **子框架层**`CChildFrame`用于管理多文档界面中的子窗口
- **视图层**`CChildView`提供客户端区域的显示功能
- **辅助组件层**:如启动画面`CSplashWnd`等提供辅助功能
该架构支持模块化扩展,通过消息驱动机制实现各组件间的松耦合通信。
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L56-L94)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L18-L27)
- [ChildView.cpp](file://cpp/Views/ChildView.cpp#L26-L30)
## 主窗口初始化流程
主窗口的初始化流程始于`CGeoMativeApp::InitInstance()`方法,在`GeoMative.cpp`中创建`CMainFrame`实例并加载框架。初始化过程包含以下关键步骤:
1. **主框架创建**:通过`new CMainFrame`实例化主窗口对象
2. **框架加载**:调用`LoadFrame(IDR_MAINFRAME)`加载资源定义的框架结构
3. **窗口显示**:设置为最大化显示并通过`ShowWindow``UpdateWindow`呈现
4. **数据库连接**:初始化ADO连接,打开GeoMativeDB.accdb数据库
5. **系统初始化**:创建系统时间获取线程,初始化诊断信息等
`CMainFrame::OnCreate`方法中,进一步完成工具栏、状态栏的创建和初始化,并显示启动画面。整个初始化流程确保了应用程序在启动时能够正确配置所有必要的UI组件和系统资源。
```mermaid
sequenceDiagram
participant App as CGeoMativeApp
participant MainFrame as CMainFrame
participant Splash as CSplashWnd
App->>MainFrame : new CMainFrame()
App->>MainFrame : LoadFrame(IDR_MAINFRAME)
App->>MainFrame : ShowWindow(SW_SHOWMAXIMIZED)
App->>MainFrame : UpdateWindow()
MainFrame->>MainFrame : OnCreate()
MainFrame->>Splash : CSplashWnd : : ShowSplashScreen()
MainFrame->>MainFrame : 创建工具栏和状态栏
MainFrame->>MainFrame : 初始化设备检测
```
**Diagram sources**
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L208-L227)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L164-L223)
- [Splash.cpp](file://cpp/Views/Splash.cpp#L45-L55)
**Section sources**
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L208-L399)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L111-L135)
- [Splash.cpp](file://cpp/Views/Splash.cpp#L19-L55)
## 菜单栏、工具栏与状态栏构建
主界面的菜单栏、工具栏和状态栏通过MFC的标准机制构建。在`MainFrm.cpp`中,`BEGIN_MESSAGE_MAP`宏定义了这些控件的创建和管理。
**工具栏**通过`CToolBar::CreateEx`方法创建,使用`TBSTYLE_FLAT|TBSTYLE_TOOLTIPS`样式实现扁平化外观和工具提示功能。工具栏加载`IDR_MAINFRAME`资源中的工具栏定义,并通过`EnableDocking(CBRS_ALIGN_ANY)`启用任意方向停靠。
**状态栏**通过`CStatusBar::Create`方法创建,使用预定义的指示器数组`indicators`来显示状态信息。该数组包含分隔符、大写锁定、数字锁定和滚动锁定等标准状态指示器。
```mermaid
classDiagram
class CMainFrame {
+CStatusBar m_wndStatusBar
+CToolBar m_wndToolBar
+LoadFrame()
+OnCreate()
+PreCreateWindow()
}
class CToolBar {
+CreateEx()
+LoadToolBar()
+EnableDocking()
+DockControlBar()
}
class CStatusBar {
+Create()
+SetIndicators()
}
CMainFrame --> CToolBar : 包含
CMainFrame --> CStatusBar : 包含
```
**Diagram sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L169-L189)
- [MainFrm.h](file://h/MainFrm.h#L56-L57)
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L164-L190)
- [MainFrm.h](file://h/MainFrm.h#L56-L57)
## 多文档界面(MDI)组织方式
Geomative Studio采用标准的MFC多文档界面(MDI)架构,通过`CMDIFrameWnd``CMDIChildWnd`类实现。主框架`CMainFrame`继承自`CMDIFrameWnd`,负责管理多个子窗口。
MDI架构的核心组件包括:
- **主框架窗口**`CMainFrame`,作为所有子窗口的容器
- **子框架窗口**`CChildFrame`,继承自`CMDIChildWnd`,每个子窗口的容器
- **视图窗口**`CChildView`,继承自`CWnd`,提供实际内容显示区域
子窗口的创建通过`CreateNewChild`方法实现,该方法使用运行时类信息创建指定类型的子框架。例如,在`OnMngDataWin`方法中,通过`CreateNewChild(RUNTIME_CLASS(CDataMngFrame), IDR_MAINFRAME)`创建数据管理框架。
```mermaid
graph TD
A[CMainFrame] --> B[CChildFrame]
A --> C[CChildFrame]
A --> D[CChildFrame]
B --> E[CChildView]
C --> F[CChildView]
D --> G[CChildView]
style A fill:#f9f,stroke:#333
style B fill:#bbf,stroke:#333
style C fill:#bbf,stroke:#333
style D fill:#bbf,stroke:#333
```
**Diagram sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L624-L667)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L17-L27)
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L624-L667)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L17-L118)
- [ChildFrm.h](file://h/ChildFrm.h#L14-L54)
## 子窗口创建与管理逻辑
子窗口的创建与管理由`CChildFrame``CChildView`类共同实现。`CChildFrame`作为子框架窗口,负责管理子窗口的生命周期和布局,而`CChildView`则负责客户端区域的内容显示。
`CChildFrame::OnCreate`方法中,通过`m_wndView.Create()`创建`CChildView`实例,并将其作为子窗口的视图组件。`OnCmdMsg`方法实现了命令消息的传递机制,确保视图能够优先处理命令消息。
子窗口的关闭通过`OnFileClose`方法实现,该方法发送`WM_CLOSE`消息来关闭窗口。`OnSetFocus`方法确保当子窗口获得焦点时,其内部的视图组件也能获得焦点。
```mermaid
flowchart TD
Start([子窗口创建]) --> PreCreateWindow["CChildFrame::PreCreateWindow"]
PreCreateWindow --> OnCreate["CChildFrame::OnCreate"]
OnCreate --> CreateView["创建CChildView"]
CreateView --> SetStyle["设置窗口样式"]
SetStyle --> Complete([子窗口创建完成])
CloseStart([子窗口关闭]) --> OnFileClose["CChildFrame::OnFileClose"]
OnFileClose --> SendClose["发送WM_CLOSE消息"]
SendClose --> CompleteClose([窗口关闭])
```
**Diagram sources**
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L85-L98)
- [ChildView.cpp](file://cpp/Views/ChildView.cpp#L36-L47)
**Section sources**
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L33-L118)
- [ChildView.cpp](file://cpp/Views/ChildView.cpp#L17-L58)
- [ChildView.h](file://h/ChildView.h#L15-L52)
## 启动画面显示控制
启动画面由`CSplashWnd`类实现,遵循MFC向导添加的典型启动画面模式。该类继承自`CWnd`,通过静态方法`ShowSplashScreen`控制启动画面的显示。
启动画面的显示控制流程如下:
1. 调用`CSplashWnd::ShowSplashScreen(this)`显示启动画面
2. `Create`方法加载`IDB_SPLASH`位图资源并创建弹出式窗口
3. `OnCreate`方法调用`CenterWindow`居中显示,并设置2秒定时器
4. `OnPaint`方法使用`BitBlt`绘制启动画面位图
5. `OnTimer`方法触发`HideSplashScreen`隐藏并销毁窗口
启动画面具有用户交互感知能力,通过`PreTranslateAppMessage`方法检测键盘或鼠标消息,一旦用户交互即立即隐藏启动画面,提升用户体验。
```mermaid
stateDiagram-v2
[*] --> Hidden
Hidden --> Creating : ShowSplashScreen()
Creating --> Displayed : Create()
Displayed --> Hiding : OnTimer() or 用户交互
Hiding --> Hidden : DestroyWindow()
note right of Displayed
定时器设置为2秒
或等待用户交互
end note
```
**Diagram sources**
- [Splash.cpp](file://cpp/Views/Splash.cpp#L45-L55)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L193-L194)
**Section sources**
- [Splash.cpp](file://cpp/Views/Splash.cpp#L1-L142)
- [Splash.h](file://h/Splash.h#L12-L56)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L193-L194)
## UI元素资源定义与消息映射
UI元素的资源定义主要通过`.rc`资源文件实现,尽管`GeoMative.rc2`文件当前为空,但系统使用`IDR_MAINFRAME`等资源ID引用主框架资源。菜单、工具栏和对话框等UI元素在资源编辑器中定义,并通过资源ID在代码中引用。
消息映射机制是MFC的核心特性,通过`BEGIN_MESSAGE_MAP``END_MESSAGE_MAP`宏定义消息处理函数。在`MainFrm.cpp`中,消息映射表将WM_CREATE、菜单命令ID和自定义消息映射到相应的处理方法。
例如,菜单命令`IDM_MNG_DATA_WIN`映射到`OnMngDataWin`方法,自定义消息`WM_SCHEDULE`映射到`OnSchedule`方法。这种声明式的消息映射机制使得UI事件处理清晰且易于维护。
```mermaid
erDiagram
RESOURCE : "资源定义" {
string 资源类型
string 资源ID
string 资源数据
}
MESSAGE_MAP : "消息映射" {
string 消息ID
string 处理函数
string 消息类型
}
HANDLER : "处理函数" {
string 函数名
string 参数
string 返回值
}
RESOURCE ||--o{ MESSAGE_MAP : "通过ID关联"
MESSAGE_MAP }o--|| HANDLER : "映射到"
```
**Diagram sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L58-L94)
- [GeoMative.rc2](file://res/GeoMative.rc2#L1-L14)
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L58-L94)
- [GeoMative.rc2](file://res/GeoMative.rc2#L1-L14)
## 用户操作路由机制
用户操作路由机制基于MFC的消息映射系统实现。`ON_COMMAND`宏将菜单项和工具栏按钮的命令ID映射到特定的处理函数。当用户点击菜单项或工具栏按钮时,MFC框架自动调用相应的处理方法。
例如,`ON_COMMAND(IDM_MNG_DATA_WIN, OnMngDataWin)`将数据管理窗口命令映射到`OnMngDataWin`方法。该方法检查`m_pDataMngFrm`是否已创建,若未创建则通过`CreateNewChild`创建新的子框架,否则激活现有窗口。
自定义消息通过`ON_MESSAGE`宏处理,如`ON_MESSAGE(WM_SCHEDULE, OnSchedule)`处理调度消息。这种机制支持应用程序内部组件间的通信,实现了松耦合的设计。
```mermaid
sequenceDiagram
participant User as 用户
participant Frame as CMainFrame
participant Handler as 处理函数
User->>Frame : 点击菜单项IDM_MNG_DATA_WIN
Frame->>Frame : 查找消息映射表
Frame->>Handler : 调用OnMngDataWin()
Handler->>Handler : 检查m_pDataMngFrm
alt 窗口未创建
Handler->>Handler : CreateNewChild()
Handler->>Handler : ShowWindow(SW_SHOWMAXIMIZED)
else 窗口已存在
Handler->>Handler : ActivateFrame()
end
Handler-->>Frame : 返回
```
**Diagram sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L60-L63)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L624-L636)
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L60-L63)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L624-L667)
## 主界面与其他管理模块的数据交互
主界面通过成员变量和消息机制与设备管理、项目管理和数据管理器等模块进行数据交互。`CMainFrame`类定义了指向这些管理框架的指针,如`m_pDevMngFrm``m_pDataMngFrm``m_pSptMngFrm`
数据交互主要通过以下方式实现:
- **直接方法调用**:通过管理框架指针调用其公开方法
- **消息传递**:使用`SendMessage`发送`WM_REFRESH`等自定义消息
- **共享数据对象**:通过应用程序对象`theApp`访问全局管理器
例如,在设备连接时,主框架通过`m_pDevMngFrm->SendMessage(WM_REFRESH_NAV_DEVICE)`通知设备管理框架刷新设备列表。文件导入导出操作通过`theApp.m_pIOManager`执行,并在完成后发送刷新消息。
```mermaid
classDiagram
class CMainFrame {
+CDevMngFrame* m_pDevMngFrm
+CDataMngFrame* m_pDataMngFrm
+CSptMngFrame* m_pSptMngFrm
+OnRefresh()
+OnFileExp()
+OnFileImp()
}
class CDevMngFrame {
+OnRefreshNavDevice()
}
class CDataMngFrame {
+OnRefresh()
}
class CIOManager {
+Export()
+Import()
}
CMainFrame --> CDevMngFrame : 持有引用
CMainFrame --> CDataMngFrame : 持有引用
CMainFrame --> CIOManager : 通过theApp访问
CMainFrame ..> CDevMngFrame : 发送WM_REFRESH_NAV_DEVICE
CMainFrame ..> CDataMngFrame : 发送WM_REFRESH
```
**Diagram sources**
- [MainFrm.h](file://h/MainFrm.h#L40-L42)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L554-L555)
**Section sources**
- [MainFrm.h](file://h/MainFrm.h#L40-L42)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L554-L555)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L69-L72)
## MFC框架下的窗口生命周期管理
MFC框架通过一系列虚拟方法和消息处理机制管理窗口生命周期。窗口的创建、销毁和消息处理遵循特定的顺序和模式。
**创建过程**
1. 构造函数:`CMainFrame()`进行成员变量初始化
2. `PreCreateWindow`:修改窗口样式和类属性
3. `OnCreate`:创建子控件(工具栏、状态栏)
4. `LoadFrame`:加载框架资源并显示窗口
**销毁过程**
1. `WM_CLOSE`消息:触发窗口关闭
2. 析构函数:`~CMainFrame()`清理资源
3. `PostNcDestroy`:删除C++对象(在`CSplashWnd`中实现)
子窗口通过`OnCmdMsg`方法实现命令消息的传递,确保视图能够优先处理命令。这种分层的消息处理机制是MFC框架的核心特性之一。
```mermaid
flowchart TB
subgraph 创建流程
A[构造函数] --> B[PreCreateWindow]
B --> C[OnCreate]
C --> D[LoadFrame]
D --> E[ShowWindow]
end
subgraph 销毁流程
F[WM_CLOSE] --> G[析构函数]
G --> H[PostNcDestroy]
H --> I[对象删除]
end
```
**Diagram sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L111-L127)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L33-L43)
- [Splash.cpp](file://cpp/Views/Splash.cpp#L100-L104)
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L111-L127)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L33-L43)
- [Splash.cpp](file://cpp/Views/Splash.cpp#L100-L104)
## 性能优化建议
针对Geomative Studio主界面的性能优化,建议从以下几个方面着手:
**减少重绘开销**
- 使用双缓冲技术减少闪烁
- 仅重绘无效区域而非整个窗口
- 延迟更新,批量处理UI变更
**减少消息处理延迟**
- 避免在消息处理函数中执行耗时操作
- 将长时间运行的任务移至工作线程
- 使用定时器分批处理大量数据更新
**内存管理优化**
- 及时释放不再使用的子窗口
- 使用智能指针管理动态创建的对象
- 缓存频繁访问的资源
**启动性能优化**
- 延迟加载非关键模块
- 优化数据库连接和初始化流程
- 减少启动时的同步操作
通过实施这些优化措施,可以显著提升主界面的响应速度和用户体验。
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp)
- [Splash.cpp](file://cpp/Views/Splash.cpp)
@@ -0,0 +1,269 @@
# 数据管理界面
<cite>
**本文档引用的文件**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp)
- [DialListMeasuData.cpp](file://cpp/Views/DialListMeasuData.cpp)
- [DialListMeasuGR.cpp](file://cpp/Views/DialListMeasuGR.cpp)
- [DialListRealTimeMeasuData.cpp](file://cpp/Views/DialListRealTimeMeasuData.cpp)
- [DialListRealTimeMeasuGR.cpp](file://cpp/Views/DialListRealTimeMeasuGR.cpp)
- [DialMeasureData.cpp](file://cpp/Views/DialMeasureData.cpp)
- [DialMeasureDetailInfo.cpp](file://cpp/Views/DialMeasureDetailInfo.cpp)
- [DialRealTimeMeasureData.cpp](file://cpp/Views/DialRealTimeMeasureData.cpp)
- [TdManager.h](file://h/TdManager.h)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
- [DataOperator.h](file://h/DataOperator.h)
- [TaskDataOper.h](file://h/TaskDataOper.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
</cite>
## 目录
1. [数据管理框架](#数据管理框架)
2. [测量数据列表展示](#测量数据列表展示)
3. [实时数据刷新机制](#实时数据刷新机制)
4. [测量详情查看功能](#测量详情查看功能)
5. [实时监控界面行为](#实时监控界面行为)
6. [数据查询、过滤与导出](#数据查询过滤与导出)
7. [大数据量列表优化](#大数据量列表优化)
8. [操作指南](#操作指南)
9. [高级开发者指南](#高级开发者指南)
## 数据管理框架
数据管理框架的核心是`CDataMngFrame`类,它负责组织和管理数据管理界面的整体结构。该框架采用MDI(多文档界面)设计,通过分割窗口(Splitter Window)将界面分为左右两个视图:左侧为导航数据视图(`CNavDataView`),右侧为应用数据视图(`CAppDataView`)。
框架通过消息映射(`BEGIN_MESSAGE_MAP`)处理各种数据管理操作,如创建、删除、导出和刷新数据。当用户在导航树中选择一个数据项时,框架会根据数据类型(如2D电阻率、3D激电等)动态创建相应的应用视图,并加载和显示数据。
```mermaid
classDiagram
class CDataMngFrame {
+m_pNavDataView : CView*
+m_pAppDataView : CView*
+m_pDataOperator : CDataOperator*
+OnCreateClient() bool
+OnSchedule() LRESULT
+ShowAppView() bool
+ShowContentListByPageView() bool
}
class CDataOperator {
+ShowRsp2DTdInfo() void
+ShowIps2DpTdInfo() void
+ShowSP2DTdInfo() void
+LoadRsp2dRecordbyPage() void
+LoadIpsp2dRecordbyPage() void
+LoadSP2dRecordbyPage() void
}
CDataMngFrame --> CDataOperator : "使用"
CDataMngFrame --> CView : "包含 m_pNavDataView"
CDataMngFrame --> CView : "包含 m_pAppDataView"
```
**Diagram sources**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L49-L602)
**Section sources**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L1-L800)
## 测量数据列表展示
测量数据列表的展示逻辑主要由`CDialListMeasuData``CDialListMeasuGR`两个类实现。`CDialListMeasuData`负责显示测量数据,而`CDialListMeasuGR`负责显示接地电阻信息。
`CDialListMeasuData``OnInitDialog`方法中初始化列表控件,设置列标题(如ID、A、B、M、N、Stack、K、V(mV)、I(mA)、R0(Ohm*m)等),并从数据库查询数据填充列表。它支持分页显示,通过“上一页”和“下一页”按钮进行导航。
```mermaid
flowchart TD
A[初始化对话框] --> B[设置列表控件样式]
B --> C[插入列标题]
C --> D[查询数据库获取数据]
D --> E{数据是否为空?}
E --> |否| F[调用OnShowTdData显示数据]
E --> |是| G[返回]
F --> H[遍历数据向量]
H --> I[格式化并插入列表项]
I --> J[设置列表项文本]
J --> K{是否遍历完成?}
K --> |否| H
K --> |是| L[结束]
```
**Diagram sources**
- [DialListMeasuData.cpp](file://cpp/Views/DialListMeasuData.cpp#L52-L120)
**Section sources**
- [DialListMeasuData.cpp](file://cpp/Views/DialListMeasuData.cpp#L1-L333)
- [DialListMeasuGR.cpp](file://cpp/Views/DialListMeasuGR.cpp#L1-L113)
## 实时数据刷新机制
实时数据的刷新机制由`CDialListRealTimeMeasureData``CDialListRealTimeMeasuGR`类实现。与静态数据列表不同,实时数据需要在测量过程中动态更新。
`CDialListRealTimeMeasureData`提供了三种数据更新方法:
1. `OnShowTdData`: 一次性清空并重新填充整个列表。
2. `OnShowTdDataAppend`: 在列表末尾追加新数据。
3. `OnShowTdDataUpdate`: 智能更新,先查找是否存在该数据,存在则更新,不存在则追加。
这种设计确保了在高频率数据更新场景下的流畅性和准确性。
```mermaid
sequenceDiagram
participant Device as "测量设备"
participant App as "应用程序"
participant List as "实时数据列表"
Device->>App : 发送测量数据包
App->>App : 解析数据包
App->>List : 调用OnShowTdDataUpdate
List->>List : 查找ID匹配的列表项
alt 找到匹配项
List->>List : 更新现有项的数据
else 未找到匹配项
List->>List : 在末尾追加新项
end
List->>List : 确保新项可见(EnsureVisible)
List->>List : 更新界面
```
**Diagram sources**
- [DialListRealTimeMeasuData.cpp](file://cpp/Views/DialListRealTimeMeasuData.cpp#L171-L332)
- [DialListRealTimeMeasuData.cpp](file://cpp/Views/DialListRealTimeMeasuData.cpp#L251-L332)
**Section sources**
- [DialListRealTimeMeasuData.cpp](file://cpp/Views/DialListRealTimeMeasuData.cpp#L1-L486)
- [DialListRealTimeMeasuGR.cpp](file://cpp/Views/DialListRealTimeMeasuGR.cpp#L1-L244)
## 测量详情查看功能
测量详情的查看功能由`CDialMeasureDetailInfo`类实现。该类提供了一个包含“数据”和“接地电阻”两个标签页的对话框,允许用户在一个界面中查看任务的详细信息。
其核心逻辑在`OnInitDialog`方法中:
1. 根据传入的任务参数(`STRemTaskArg`),创建并初始化`CDialListMeasuTask``CDialListMeasuGR`两个子控件。
2. 分别调用`ShowPage(1)``GetGRRequest(m_stTaskArg)`从云端获取任务数据和接地电阻信息。
3. 通过标签页的切换事件(`OnSelchangeTabChg`)来显示或隐藏相应的子控件。
```mermaid
classDiagram
class CDialMeasureDetailInfo {
+m_dialListMeasuTask : CDialListMeasuTask
+m_dialListMeasuGR : CDialListMeasuGR
+OnInitDialog() bool
+OnSelchangeTabChg() void
}
class CDialListMeasuTask {
+ShowPage() void
}
class CDialListMeasuGR {
+GetGRRequest() void
}
CDialMeasureDetailInfo --> CDialListMeasuTask
CDialMeasureDetailInfo --> CDialListMeasuGR
```
**Diagram sources**
- [DialMeasureDetailInfo.cpp](file://cpp/Views/DialMeasureDetailInfo.cpp#L56-L104)
**Section sources**
- [DialMeasureData.cpp](file://cpp/Views/DialMeasureData.cpp#L1-L2262)
- [DialMeasureDetailInfo.cpp](file://cpp/Views/DialMeasureDetailInfo.cpp#L1-L186)
## 实时监控界面行为
实时监控界面由`CDialRealTimeMeasureData`类控制。该类不仅管理数据列表,还处理用户与测量过程的交互,如开始测量、暂停测量、单点测量等。
其行为逻辑如下:
- **按钮状态管理**: 通过`SetBtnStatus`方法根据当前测量状态(如`EN_MEASU_BTN_MEASU_ALL`)启用或禁用按钮,防止用户进行无效操作。
- **测量命令发送**: 当用户点击“开始测量”时,`OnMeasureAll`方法会构造一个`STTrusteeTaskTable`结构体,并通过`PostNetRequest`发送到设备,启动测量任务。
- **数据接收与处理**: 重写`ProcRcvMeasuData`等方法来处理从设备接收的实时数据,并更新UI。
**Section sources**
- [DialRealTimeMeasureData.cpp](file://cpp/Views/DialRealTimeMeasureData.cpp#L1-L1879)
## 数据查询、过滤与导出
数据查询、过滤和导出功能主要由`CTdManager``CDataOperator`两个核心类实现。
`CTdManager`作为数据管理器,提供了与数据库交互的底层接口:
- **查询**: `ShowTdListByTz``ShowTdListByProject`等方法用于从数据库查询任务列表。
- **删除**: `DeleteRsp2DTd``DeleteIpsp2DTd`等方法用于删除不同类型的数据。
- **导入/导出**: `Import2DTdConToDB``ExportRsp2DTdToDAT`等方法用于数据的导入和导出。
`CDataOperator`则作为`CTdManager`的上层封装,为UI提供更便捷的调用接口。例如,`ExportRsp2DTdToExcel`方法会调用`CTdManager`的底层功能,将2D电阻率数据导出为Excel文件。
```mermaid
classDiagram
class CDataOperator {
+ExportRsp2DTdToExcel() UINT
+ExportRsp2DTdToDAT() UINT
+ExportRsp2DTdToCSV() UINT
+ShowRsp2DTdInfo() void
+LoadRsp2dRecordbyPage() void
}
class CTdManager {
+ShowTdListByTz() bool
+DeleteRsp2DTd() void
+Import2DTdConToDB() bool
+ExportRsp2DTdToDAT() UINT
}
CDataOperator --> CTdManager : "使用"
```
**Diagram sources**
- [DataOperator.h](file://h/DataOperator.h#L29-L87)
- [TdManager.h](file://h/TdManager.h#L33-L87)
**Section sources**
- [TdManager.h](file://h/TdManager.h#L1-L109)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L1-L6839)
- [DataOperator.h](file://h/DataOperator.h#L1-L174)
## 大数据量列表优化
在处理大数据量时,直接加载所有数据会导致界面卡顿。项目通过以下两种技术进行优化:
1. **分页加载**: `CDataOperator`类中的`LoadRsp2dRecordbyPage`等方法实现了分页查询。它接收一个起始ID和页大小,只从数据库加载指定范围的数据,显著减少了内存占用和加载时间。
2. **虚拟列表**: 虽然代码中未直接体现,但`CListCtrl`控件支持虚拟列表(Virtual List)模式。在这种模式下,控件不会存储所有数据,而是通过`LVN_GETDISPINFO`消息在需要显示某一行时,由程序动态提供该行的数据。这是一种处理海量数据的高效方式。
**Section sources**
- [DataOperator.h](file://h/DataOperator.h#L76-L83)
- [TaskDataOper.h](file://h/TaskDataOper.h#L378-L382)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L418-L513)
## 操作指南
### 初学者:数据查看与导出
1. **查看数据**:
* 打开“数据管理”界面。
* 在左侧导航树中选择一个任务。
* 右侧会自动显示该任务的测量数据列表。
* 使用“上一页”和“下一页”按钮浏览不同页面的数据。
2. **导出数据**:
* 在导航树中右键点击要导出的任务。
* 选择“导出”菜单下的格式,如“导出为Excel”或“导出为DAT文件”。
* 在弹出的对话框中选择保存路径,点击“保存”即可。
## 高级开发者指南
### 高频率数据更新场景下的UI线程安全处理
在实时监控等高频率数据更新场景下,数据接收通常在后台线程中进行,而UI更新必须在主线程(UI线程)中完成。为确保线程安全,项目采用了以下方案:
1. **消息传递机制**: 后台线程不直接操作UI控件,而是通过`PostMessage``PostNetRequest`向UI线程发送自定义消息(如`WM_MSG_UPDATE_TASK_LIST`)。
2. **UI线程处理**: UI线程的消息循环接收到消息后,调用相应的消息处理函数(如`OnShowTdDataUpdate`)来安全地更新列表控件。
这种“生产者-消费者”模式有效地隔离了数据处理和UI更新,避免了多线程访问共享资源导致的竞态条件和崩溃。
```mermaid
sequenceDiagram
participant WorkerThread as "工作线程"
participant UIThread as "UI线程"
participant ListCtrl as "列表控件"
WorkerThread->>WorkerThread : 接收测量数据
WorkerThread->>UIThread : PostMessage(WM_SHOW_TD_DATA_UPDATE, 数据指针)
UIThread->>UIThread : 消息循环接收到消息
UIThread->>UIThread : 调用OnShowTdDataUpdate
UIThread->>ListCtrl : 安全地更新列表项
ListCtrl->>UIThread : 更新完成
```
**Section sources**
- [DialListRealTimeMeasuData.cpp](file://cpp/Views/DialListRealTimeMeasuData.cpp#L344-L343)
- [DialRealTimeMeasureData.cpp](file://cpp/Views/DialRealTimeMeasureData.cpp#L593-L594)
@@ -0,0 +1,266 @@
# 设备管理界面
<cite>
**本文档引用的文件**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DailLogin.cpp](file://cpp/Views/DailLogin.cpp)
- [DialFindComShow.cpp](file://cpp/Views/DialFindComShow.cpp)
- [DialShowDevParam.cpp](file://cpp/Views/DialShowDevParam.cpp)
- [DialPlcStatusShow.cpp](file://cpp/Views/DialPlcStatusShow.cpp)
- [DialDevStatusTimerShow.cpp](file://cpp/Views/DialDevStatusTimerShow.cpp)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
- [NetRequestDialog.cpp](file://cpp/socket/NetRequestDialog.cpp)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 简介
本文档深入分析GeomativeStudio项目中设备管理相关的UI组件实现。重点介绍devmngframe.cpp中设备管理框架的布局结构与消息响应机制,DailLogin.cpp中的登录验证流程,DialFindComShow.cpp中的串口检测对话框逻辑,DialShowDevParam.cpp中的设备参数展示机制。解释DialPlcStatusShow.cpp和DialDevStatusTimerShow.cpp中PLC状态与定时状态的实时更新策略。结合MFC消息映射机制,说明用户操作如何触发CDevManager的接口调用。为初学者提供UI与设备通信协同工作的概念性解释,为高级开发者提供多线程环境下UI刷新的最佳实践。
## 项目结构
项目采用典型的MFC应用程序结构,设备管理相关的UI组件主要位于cpp/Views目录下。核心的设备管理框架由devmngframe.cpp实现,负责整体布局和消息分发。各个功能模块如登录、串口检测、设备参数展示等通过独立的对话框类实现。业务逻辑与数据管理由cpp/Managers和cpp/Operator目录下的类负责,形成清晰的分层架构。
**Section sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DailLogin.cpp](file://cpp/Views/DailLogin.cpp)
## 核心组件
设备管理界面的核心组件包括设备管理框架、登录验证、串口检测、设备参数展示和状态监控等模块。这些组件通过MFC的消息映射机制协同工作,实现用户与设备的交互。CDevManager类作为设备管理的核心,负责设备的生命周期管理和状态维护。
**Section sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp)
## 架构概述
系统采用MFC文档/视图架构,设备管理功能通过CMDIChildWnd派生的CDevMngFrame类实现。该框架使用CSplitterWnd进行界面分割,左侧为导航树视图,右侧为内容显示区域。通过消息映射机制处理用户操作,调用CDevOperator和CDevManager类完成具体业务逻辑。
```mermaid
graph TB
subgraph "UI层"
A[CDevMngFrame] --> B[CNavDevView]
A --> C[CAppDevView]
A --> D[CAppDevOLView]
end
subgraph "业务逻辑层"
E[CDevOperator] --> F[CDevManager]
E --> G[CDevice]
end
subgraph "数据层"
F --> H[数据库]
G --> I[串口通信]
end
A --> E
B --> E
C --> E
D --> E
```
**Diagram sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
## 详细组件分析
### 设备管理框架分析
CDevMngFrame类实现了设备管理的主框架,负责界面布局和消息处理。通过CSplitterWnd将界面分为导航区域和内容显示区域,支持动态切换视图以显示不同状态的设备信息。
#### 布局结构
```mermaid
classDiagram
class CDevMngFrame {
+CSplitterWnd m_splitter
+CView* m_pAppDevView
+CView* m_pNavDevView
+OnCreateClient()
+ShowAppView()
}
class CNavDevView {
+CTreeCtrl m_devTree
}
class CAppDevView {
+CListCtrl m_devDetailList
}
class CAppDevOLView {
+CListCtrl m_devOLDetailList
+CListCtrl m_devOLGRList
+CListCtrl m_devOLACList
}
CDevMngFrame --> CNavDevView : "包含"
CDevMngFrame --> CAppDevView : "包含"
CDevMngFrame --> CAppDevOLView : "包含"
```
**Diagram sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [navdevview.h](file://h/navdevview.h)
- [appdevview.h](file://h/appdevview.h)
#### 消息响应机制
```mermaid
sequenceDiagram
participant 用户
participant CDevMngFrame
participant CDevOperator
participant CDevManager
用户->>CDevMngFrame : 点击"修改设备参数"
CDevMngFrame->>CDevMngFrame : OnModifyDeviceParameter()
CDevMngFrame->>CDevOperator : ModifyDeviceParameter()
CDevOperator->>CDevManager : GetDeviceByID()
CDevManager-->>CDevOperator : 返回CDevice对象
CDevOperator->>CDevice : ModifyParameter()
CDevice-->>CDevOperator : 显示参数对话框
CDevOperator->>CDevice : ShowOLDetailInfo()
CDevice-->>CDevOperator : 更新UI
CDevOperator-->>CDevMngFrame : 返回结果
CDevMngFrame-->>用户 : 显示更新后的界面
```
**Diagram sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
### 登录验证流程分析
DailLogin.cpp实现了系统的登录验证功能,包括用户身份验证、密码保存和自动登录等特性。
#### 登录验证流程
```mermaid
flowchart TD
Start([开始]) --> ValidateInput["验证输入参数"]
ValidateInput --> InputValid{"输入有效?"}
InputValid --> |否| ReturnError["显示错误信息"]
InputValid --> |是| CheckUserID["验证用户ID"]
CheckUserID --> UserIDValid{"ID正确?"}
UserIDValid --> |否| ReturnError
UserIDValid --> |是| CheckPassword["验证密码"]
CheckPassword --> PasswordValid{"密码正确?"}
PasswordValid --> |否| ReturnError
PasswordValid --> |是| SaveSettings["保存设置"]
SaveSettings --> CheckSave["是否保存密码?"]
CheckSave --> |是| SavePassword["写入config.ini"]
CheckSave --> |否| SkipSave
SkipSave --> CheckAutoLogin["是否自动登录?"]
CheckAutoLogin --> |是| SaveAutoLogin["写入config.ini"]
CheckAutoLogin --> |否| SkipAutoLogin
SkipAutoLogin --> Complete["登录成功"]
ReturnError --> End([结束])
Complete --> End
```
**Diagram sources**
- [DailLogin.cpp](file://cpp/Views/DailLogin.cpp)
### 串口检测对话框逻辑
DialFindComShow.cpp实现了串口检测结果的显示功能,用于向用户展示串口连接状态。
#### 串口检测逻辑
```mermaid
classDiagram
class CDialFindComShow {
+CString m_strShowCom
+OnInitDialog()
}
CDialFindComShow --> CDialog : "继承"
```
**Diagram sources**
- [DialFindComShow.cpp](file://cpp/Views/DialFindComShow.cpp)
### 设备参数展示机制
DialShowDevParam.cpp实现了设备参数的展示和修改功能,支持参数的本地编辑和云端同步。
#### 参数展示与同步
```mermaid
sequenceDiagram
participant CDevMngFrame
participant CDialShowDevParam
participant Network
CDevMngFrame->>CDialShowDevParam : OnShowDevParam()
CDialShowDevParam->>CDialShowDevParam : 显示参数对话框
CDialShowDevParam->>CDialShowDevParam : 用户修改参数
CDialShowDevParam->>CDialShowDevParam : 验证输入
CDialShowDevParam->>Network : 发送修改请求
Network-->>CDialShowDevParam : 接收响应
CDialShowDevParam-->>CDevMngFrame : 返回结果
```
**Diagram sources**
- [DialShowDevParam.cpp](file://cpp/Views/DialShowDevParam.cpp)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
### PLC状态与定时状态实时更新
DialPlcStatusShow.cpp和DialDevStatusTimerShow.cpp实现了PLC状态和定时状态的实时监控功能。
#### 状态更新策略
```mermaid
classDiagram
class CDialPlcStatusShow {
+STRemPlcData* m_pRemPlcData
+OnInitDialog()
}
class CDialDevStatusTimerShow {
+CListCtrl m_listData
+ShowPlcStatusData()
}
class CTaskDataOper {
+QueryPlcStatusData()
}
CDialDevStatusTimerShow --> CTaskDataOper : "使用"
CDialPlcStatusShow --> CDialDevStatusTimerShow : "关联"
```
**Diagram sources**
- [DialPlcStatusShow.cpp](file://cpp/Views/DialPlcStatusShow.cpp)
- [DialDevStatusTimerShow.cpp](file://cpp/Views/DialDevStatusTimerShow.cpp)
- [TaskDataOper.h](file://h/TaskDataOper.h)
**Section sources**
- [DialPlcStatusShow.cpp](file://cpp/Views/DialPlcStatusShow.cpp)
- [DialDevStatusTimerShow.cpp](file://cpp/Views/DialDevStatusTimerShow.cpp)
## 依赖关系分析
系统各组件之间存在清晰的依赖关系,UI组件依赖于业务逻辑组件,业务逻辑组件又依赖于数据访问组件。这种分层架构有助于代码的维护和扩展。
```mermaid
graph TD
A[devmngframe.cpp] --> B[DevOperator.cpp]
B --> C[DevManager.cpp]
C --> D[Device.cpp]
D --> E[SComPort.cpp]
A --> F[DialShowDevParam.cpp]
F --> G[NetRequestDialog.cpp]
A --> H[DialPlcStatusShow.cpp]
H --> I[DialDevStatusTimerShow.cpp]
I --> J[TaskDataOper.cpp]
```
**Diagram sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
## 性能考虑
在多线程环境下进行UI刷新时,应避免在主线程中执行耗时操作。建议使用工作线程处理设备通信,通过PostMessage或SendMessage将结果发送回UI线程进行界面更新。对于频繁的状态更新,可以采用定时器机制,避免过度刷新导致的性能问题。
## 故障排除指南
常见问题包括设备连接失败、参数同步异常和界面刷新延迟等。检查网络连接状态、验证设备ID和类型、确认串口配置正确性是解决问题的关键步骤。使用日志文件可以帮助定位具体的问题根源。
**Section sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
## 结论
本文档详细分析了GeomativeStudio项目中设备管理相关的UI组件实现。通过MFC框架实现了功能完整的设备管理界面,各组件之间通过清晰的消息传递机制协同工作。系统架构合理,代码组织规范,为类似应用的开发提供了有价值的参考。
@@ -0,0 +1,358 @@
# 项目管理界面
<cite>
**本文档引用的文件**
- [taskmngframe.cpp](file://cpp/Views/taskmngframe.cpp)
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp)
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp)
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp)
- [DialTaskTree.cpp](file://cpp/Views/DialTaskTree.cpp)
- [DialTaskManager.cpp](file://cpp/Views/DialTaskManager.cpp)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
</cite>
## 目录
1. [任务管理框架与导航逻辑](#任务管理框架与导航逻辑)
2. [测量任务创建流程](#测量任务创建流程)
3. [任务包配置机制](#任务包配置机制)
4. [地形参数设置逻辑](#地形参数设置逻辑)
5. [任务树形视图构建与交互](#任务树形视图构建与交互)
6. [项目数据持久化与加载](#项目数据持久化与加载)
7. [任务参数验证与数据传递](#任务参数验证与数据传递)
8. [任务配置工作流](#任务配置工作流)
9. [UI响应性能优化建议](#ui响应性能优化建议)
## 任务管理框架与导航逻辑
任务管理框架由`taskmngframe.cpp`实现,作为MDI子窗口继承自`CMDIChildWnd`。该框架负责组织和管理所有与任务相关的UI组件,提供统一的导航界面。框架通过消息映射处理窗口激活、关闭等事件,确保在用户切换不同任务管理视图时能够正确更新状态和界面元素。
**Section sources**
- [taskmngframe.cpp](file://cpp/Views/taskmngframe.cpp#L1-L36)
## 测量任务创建流程
### 1D测量任务创建
`DialNew1DTask.cpp`实现了1D测量任务的创建对话框。该对话框初始化时会根据当前UI语言设置控件文本,并从`CTaskDataOper`操作类查询可用的介质类型和脚本信息。用户选择测试类型(电阻率、激电、自电)后,系统会动态更新发射波形和发射周期的选项。在用户点击"创建"按钮后,系统会执行完整的参数验证,包括任务名、测试方式、装置类型、脚本、迭代次数等,确保所有必填项都已正确填写且符合取值范围。
```mermaid
flowchart TD
Start([开始创建1D任务]) --> Init["初始化对话框\n设置语言、加载介质和脚本"]
Init --> SelectType["用户选择测试类型\n(电阻率/激电/自电)"]
SelectType --> UpdateOptions["更新发射波形和周期选项"]
UpdateOptions --> UserInput["用户输入任务参数\n任务名、位置、脚本等"]
UserInput --> Validate["点击创建时验证参数"]
Validate --> CheckName{"任务名为空?"}
CheckName --> |是| ShowError1["显示错误提示"]
CheckName --> |否| CheckType{"测试方式未选?"}
CheckType --> |是| ShowError2["显示错误提示"]
CheckType --> |否| CheckArray{"装置类型未选?"}
CheckArray --> |是| ShowError3["显示错误提示"]
CheckArray --> |否| CheckScript{"脚本未选?"}
CheckScript --> |是| ShowError4["显示错误提示"]
CheckScript --> |否| CheckStacking{"迭代次数有效?"}
CheckStacking --> |否| ShowError5["显示错误提示"]
CheckStacking --> |是| CreateTask["调用CTaskDataOper::Create1DTask\n创建任务"]
CreateTask --> Success{"创建成功?"}
Success --> |是| CloseDialog["关闭对话框"]
Success --> |否| Return["返回等待用户修正"]
ShowError1 --> Return
ShowError2 --> Return
ShowError3 --> Return
ShowError4 --> Return
ShowError5 --> Return
```
**Diagram sources**
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L1-L381)
### 2D测量任务创建
`DialNew2DTask.cpp`实现了2D测量任务的创建对话框。与1D任务相比,2D任务需要更多的参数配置,包括电缆布线方式、起始/结束电极、电极间距、孔间距(对于交叉孔装置)等。对话框在初始化时会根据装置类型动态显示或隐藏相关控件,例如交叉孔装置会显示孔间距输入框。当用户选择不同的测试类型时,系统会过滤可用的电缆布线方式,确保选择的配置是有效的。
```mermaid
flowchart TD
Start([开始创建2D任务]) --> Init["初始化对话框\n加载介质、脚本、电缆布局"]
Init --> SelectType["用户选择测试类型"]
SelectType --> FilterLayout["根据测试类型过滤\n电缆布线方式"]
FilterLayout --> UserInput["用户输入任务参数\n包括电极间距、起始/结束电极等"]
UserInput --> Validate["点击创建时验证参数"]
Validate --> CheckCommon["验证通用参数\n(任务名、测试方式等)"]
CheckCommon --> CheckSpace{"电极间距为零?"}
CheckSpace --> |是| ShowError1["显示错误提示"]
CheckSpace --> |否| CheckHole{"交叉孔装置且孔间距为零?"}
CheckHole --> |是| ShowError2["显示错误提示"]
CheckHole --> |否| CheckRange{"起始/结束电极越界?"}
CheckRange --> |是| ShowError3["显示错误提示"]
CheckRange --> |否| CreateTask["调用CTaskDataOper::Create2DTask\n创建任务"]
CreateTask --> Success{"创建成功?"}
Success --> |是| CloseDialog["关闭对话框"]
Success --> |否| Return["返回等待用户修正"]
ShowError1 --> Return
ShowError2 --> Return
ShowError3 --> Return
```
**Diagram sources**
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L1-L665)
### 3D测量任务创建
`DialNew3DTask.cpp`实现了3D测量任务的创建对话框。3D任务的配置最为复杂,需要设置网格大小、X/Y方向电极步长和距离等参数。当用户选择脚本时,系统会自动查询并显示网格信息(X和Y方向的点数),帮助用户理解测量范围。对话框还提供了发射周期的"自动"选项,为用户提供更灵活的配置选择。
```mermaid
flowchart TD
Start([开始创建3D任务]) --> Init["初始化对话框\n加载介质、脚本、电缆布局"]
Init --> SelectScript["用户选择脚本"]
SelectScript --> QueryGrid["查询并显示网格信息\n(X方向点数, Y方向点数)"]
QueryGrid --> UserInput["用户输入任务参数\n包括步长、距离等"]
UserInput --> Validate["点击创建时验证参数"]
Validate --> CheckCommon["验证通用参数\n(任务名、测试方式等)"]
CheckCommon --> CheckStep{"步长为空?"}
CheckStep --> |是| ShowError["显示错误提示"]
CheckStep --> |否| CreateTask["调用CTaskDataOper::Create3DTask\n创建任务"]
CreateTask --> Success{"创建成功?"}
Success --> |是| CloseDialog["关闭对话框"]
Success --> |否| Return["返回等待用户修正"]
ShowError --> Return
```
**Diagram sources**
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L1-L570)
## 任务包配置机制
`DialCfgTaskPacket.cpp`实现了任务包的配置对话框,允许用户将多个任务组织成一个任务包进行循环执行。对话框包含一个任务选择下拉框和一个任务列表,用户可以将选中的任务添加到列表中,也可以从列表中删除任务。系统会检查重复添加的任务,避免同一个任务被多次执行。
在用户点击"保存"时,系统会对输入的参数进行严格验证:
- 循环次数必须在1-60000之间
- 时间间隔必须在1-60000之间
- PLC ID不能为空
验证通过后,系统会将任务列表和属性信息保存到数据库中,供后续执行使用。
```mermaid
classDiagram
class CDialCfgTaskPacket {
+m_cmbTaskName : CComboBox
+m_listTaskPacket : CListCtrl
+m_cmbTaskName : CComboBox
+OnButtonAdd() void
+OnButtonDel() void
+OnOK() void
+IsRepeatTask(int) bool
+InitialTaskList() void
}
class CTaskDataOper {
+QueryTdBrowseInfo() void
+QueryTaskPacketAttr() bool
+InsertTaskPacketInfo() bool
}
CDialCfgTaskPacket --> CTaskDataOper : "使用"
```
**Diagram sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L301)
## 地形参数设置逻辑
`DialCfgTerrain.cpp`实现了地形参数的配置对话框,允许用户导入DAT文件并编辑地形数据点。对话框提供了添加、修改、删除地形数据点的功能,并支持从文件导入地形数据。用户可以设置地形数据标志(水平距离或垂直距离)和第一个电极对应的地形数据点编号。
在保存地形数据时,系统会执行严格的验证:
- 必须已导入DAT文件
- 必须选择地形数据标志
- 必须输入至少一个地形数据点
- 第一个电极对应的地形数据点编号必须在有效范围内
验证通过后,系统会将地形数据写入原DAT文件的末尾,遵循特定的文件格式要求。
```mermaid
flowchart TD
Start([开始配置地形]) --> ImportFile["用户导入DAT文件"]
ImportFile --> EditData["编辑地形数据点\n添加、修改、删除"]
EditData --> SetParams["设置地形参数\n标志、第一个电极编号"]
SetParams --> Save["点击保存"]
Save --> Validate["验证参数"]
Validate --> CheckFile{"已导入文件?"}
CheckFile --> |否| ShowError1["显示错误提示"]
CheckFile --> |是| CheckFlag{"选择数据标志?"}
CheckFlag --> |否| ShowError2["显示错误提示"]
CheckFlag --> |是| CheckData{"输入地形数据?"}
CheckData --> |否| ShowError3["显示错误提示"]
CheckData --> |是| CheckIndex{"第一个电极编号有效?"}
CheckIndex --> |否| ShowError4["显示错误提示"]
CheckIndex --> |是| WriteFile["将地形数据写入DAT文件"]
WriteFile --> Success{"写入成功?"}
Success --> |是| ShowSuccess["显示成功提示"]
Success --> |否| ShowFail["显示失败提示"]
ShowError1 --> Return["返回等待用户修正"]
ShowError2 --> Return
ShowError3 --> Return
ShowError4 --> Return
```
**Diagram sources**
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L1-L843)
## 任务树形视图构建与交互
### 任务树形视图构建
`DialTaskTree.cpp`实现了任务树形视图,使用`CTreeCtrl`控件显示任务列表。视图支持复选框功能,允许用户选择多个任务进行批量操作。视图初始化时会根据任务类型(2D或3D)从服务器获取任务数据,并构建树形结构。
```mermaid
classDiagram
class CDialTaskTree {
+m_treeTask : CTreeCtrl
+m_iSptType : int
+m_pParentWnd : CWnd*
+ShowTaskTree(int, time_t, time_t) void
+OnClickTreeTaskList() void
+OnNMRClickTreeTaskList() void
+OnAddNewItemToTaskList() bool
+OnClearTaskList() void
}
class CTaskDataOper {
+InitOnLineTaskTreeCtrl() void
+SetCurrentTimeRange() void
}
CDialTaskTree --> CTaskDataOper : "使用"
```
**Diagram sources**
- [DialTaskTree.cpp](file://cpp/Views/DialTaskTree.cpp#L1-L686)
### 任务树形视图交互
任务树形视图支持丰富的交互功能:
- 点击复选框:选择或取消选择任务,同时更新父节点的选中计数
- 右键点击:显示上下文菜单,提供创建任务、删除任务、取消测试、刷新列表等操作
- 点击任务节点:通知父窗口当前选中的任务
上下文菜单的选项会根据当前UI语言动态调整文本内容,确保用户界面的国际化支持。
```mermaid
sequenceDiagram
participant User as "用户"
participant Tree as "任务树"
participant Parent as "父窗口"
User->>Tree : 右键点击任务节点
Tree->>Tree : 显示上下文菜单
User->>Tree : 选择"删除任务"
Tree->>Parent : 发送WM_MSG_DELETE_TASK消息
Parent->>Parent : 处理删除任务逻辑
Parent->>Tree : 刷新任务列表
Tree->>User : 显示操作结果
```
**Diagram sources**
- [DialTaskTree.cpp](file://cpp/Views/DialTaskTree.cpp#L1-L686)
## 项目数据持久化与加载
`ProManager.cpp`实现了项目管理器,负责项目数据的持久化与加载。项目管理器通过`CProManager`类与数据库交互,实现项目和测区的创建、查询和同步功能。
项目创建流程包括:
1. 在数据库中创建项目记录
2. 在设备上创建项目文件夹和配置文件
3. 同步项目数据到设备
```mermaid
sequenceDiagram
participant UI as "用户界面"
participant ProMgr as "CProManager"
participant DB as "数据库"
participant Dev as "设备"
UI->>ProMgr : 创建项目
ProMgr->>ProMgr : 显示创建对话框
ProMgr->>ProMgr : 验证项目名称唯一性
ProMgr->>DB : 插入项目记录
DB-->>ProMgr : 返回项目ID
ProMgr->>Dev : 在设备上创建项目文件夹
Dev-->>ProMgr : 文件夹创建成功
ProMgr->>Dev : 发送项目配置文件
Dev-->>ProMgr : 文件发送成功
ProMgr->>DB : 记录同步状态
DB-->>ProMgr : 同步记录创建成功
ProMgr-->>UI : 显示创建成功
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1-L2054)
## 任务参数验证与数据传递
### 任务参数验证
系统在创建任务时执行严格的参数验证,确保所有输入都符合业务规则:
- **必填项验证**:任务名、测试方式、装置类型、脚本等必须填写
- **取值范围验证**:迭代次数(1-255)、采样间隔(0-30000)、电极间距(>0)等
- **逻辑关系验证**:交叉孔装置的孔间距必须大于电极间距
- **唯一性验证**:任务包中不能包含重复任务
### 跨对话框数据传递
系统通过多种机制实现跨对话框的数据传递:
- **构造函数传递**:在创建对话框时通过构造函数传递必要的操作对象(如`CTaskDataOper`
- **成员变量共享**:父窗口与子窗口通过成员变量共享数据
- **消息机制**:使用Windows消息在不同窗口间传递数据和状态
例如,在`DialTaskManager.cpp`中,创建任务时会根据任务类型显示相应的创建对话框,并将创建好的任务参数传递给上传逻辑:
```cpp
// 伪代码示例
if (0 == m_iSelTaskType) {
iRet = m_dialNew2DTask.DoModal();
if (IDOK == iRet) {
// 从对话框获取创建好的任务参数
strTaskCN = m_dialNew2DTask.m_strTaskCN;
// 构造任务参数结构体
strcpy(m_TaskArg.ucTaskID, strTmp);
strcpy(m_TaskArg.ucTDName, m_dialNew2DTask.m_strTaskName);
// ... 其他参数
// 上传任务数据
CDownloadDataProgressDlg uploadDlg(&m_TaskArg, &m_taskOper,this);
uploadDlg.DoModal();
}
}
```
**Section sources**
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L1-L381)
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L1-L665)
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L1-L570)
- [DialTaskManager.cpp](file://cpp/Views/DialTaskManager.cpp#L1-L2242)
## 任务配置工作流
对于初学者,任务配置的工作流可以概括为以下步骤:
1. **创建项目**:通过项目管理器创建新的项目,填写项目基本信息
2. **创建测区**:在项目中创建测区,定义测量区域
3. **创建任务**
- 选择任务类型(1D、2D或3D)
- 选择测试方式(电阻率、激电或自电)
- 选择装置类型和测量脚本
- 设置任务参数(迭代次数、发射周期等)
- 点击"创建"完成任务创建
4. **配置地形**(可选):为任务配置地形数据,导入或手动输入地形点
5. **组织任务包**(可选):将多个任务组织成任务包,设置循环执行参数
6. **执行任务**:在任务管理器中选择任务并开始测量
每个步骤都有相应的对话框引导用户完成配置,系统会在关键操作前进行参数验证,确保配置的正确性。
## UI响应性能优化建议
针对大型项目下的UI响应性能,建议采取以下优化措施:
1. **分页加载任务数据**:避免一次性加载所有任务,采用分页或按时间范围加载的方式,减少内存占用和UI阻塞
2. **异步数据加载**:将耗时的数据查询操作放在后台线程执行,避免阻塞UI线程
3. **虚拟化列表控件**:对于包含大量任务的列表,使用虚拟化技术,只渲染可见区域的项目
4. **缓存常用数据**:将频繁访问的数据(如介质类型、脚本列表)缓存到内存中,减少数据库查询次数
5. **优化数据库查询**:为常用查询字段建立索引,优化SQL查询语句,减少查询时间
6. **延迟加载**:对于非关键信息,在用户需要时才进行加载,提高初始加载速度
7. **批量操作优化**:对于批量删除等操作,使用事务处理,减少数据库交互次数
这些优化措施可以显著提升大型项目下的UI响应速度,改善用户体验。
@@ -0,0 +1,243 @@
# 代码结构
<cite>
**本文档引用的文件**
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp)
- [Global.cpp](file://cpp/Main/Global.cpp)
- [Constant.h](file://h/Constant.h)
- [GeoMative.h](file://h/GeoMative.h)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [Project.h](file://h/Project.h)
- [Device.h](file://h/Device.h)
- [Script.h](file://h/Script.h)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp)
- [MainFrm.h](file://h/MainFrm.h)
</cite>
## 目录
1. [项目结构概述](#项目结构概述)
2. [核心模块职责划分](#核心模块职责划分)
3. [应用程序对象与管理器协调](#应用程序对象与管理器协调)
4. [常量与枚举的广泛应用](#常量与枚举的广泛应用)
5. [模块间调用关系示例](#模块间调用关系示例)
6. [系统架构图](#系统架构图)
## 项目结构概述
GeomativeStudio项目的代码结构清晰地划分为多个目录,每个目录承担特定的职责。`cpp``h`目录下分别存放C++源文件和头文件,其子目录体现了系统的分层架构。`Main`目录包含应用程序入口和全局对象;`Managers`目录包含设备、项目、脚本、测试数据和I/O管理器等核心业务逻辑组件;`Operator`目录包含具体操作实现;`ProblemZone`目录包含项目、设备、脚本点等核心数据模型;`Views`目录包含所有UI视图和对话框实现。
**Section sources**
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L1-L800)
- [Global.cpp](file://cpp/Main/Global.cpp#L1-L800)
## 核心模块职责划分
### Main目录
`Main`目录是应用程序的入口点,主要包含`GeoMative.cpp``Global.cpp`两个核心文件。`GeoMative.cpp`定义了`CGeoMativeApp`类,该类继承自`CWinApp`,负责应用程序的初始化、运行和退出。它在`InitInstance`方法中创建并初始化所有核心管理器对象,并建立与数据库的连接。`Global.cpp`则定义了全局变量和函数,如`theApp`全局应用程序对象实例、`aDevLinkTable`设备链接表以及各种工具函数。
### Managers目录
`Managers`目录包含了系统的核心业务逻辑组件,即各种管理器(Manager)。这些管理器负责处理特定领域的业务逻辑和数据持久化。
- **DevManager**:设备管理器,负责管理所有设备的生命周期,包括设备的注册、连接、状态更新和信息获取。它通过`m_devLinkList`链表维护所有设备对象,并提供`GetDevice``GetDeviceByID`等方法来检索设备。
- **ProManager**:项目管理器,负责管理项目(Project)和测区(TestingZone)的层次结构。它通过`m_dmsLinkList`链表管理数据管理结构(DMS),并提供`ShowProList``ShowTzList`等方法来展示项目和测区列表。
- **SptManager**:脚本管理器,负责管理脚本(Script)的创建、加载和同步。
- **TdManager**:测试数据管理器,负责管理测试数据(Testing Data)的存储和检索。
- **ExecManager**:执行管理器,负责管理执行任务和流程。
- **IOManager**I/O管理器,负责处理输入输出操作。
**Section sources**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L1-L200)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1-L200)
### Operator目录
`Operator`目录包含了具体操作的实现类。这些类通常封装了复杂的业务逻辑或与外部系统的交互。例如,`DataOperator.cpp`实现了数据操作相关的功能,如文件导入导出、数据同步等。`DevOperator.cpp``SptOperator.cpp`则分别处理设备和脚本的具体操作。
### ProblemZone目录
`ProblemZone`目录包含了系统的核心数据模型,这些模型代表了业务领域中的实体。
- **Project**:项目类,继承自`CDataMngStruct`,代表一个工程项目,包含项目名称、描述、位置等属性。
- **Device**:设备类,代表一个物理设备,包含设备序列号、型号、软硬件版本、MAC地址等属性,并提供与设备通信的方法。
- **Script**:脚本类,代表一个测量脚本,包含电极数量、测量类型等属性,并提供显示脚本内容和详情的方法。
- **TestingZone**:测区类,代表项目下的一个具体测量区域。
**Section sources**
- [Project.h](file://h/Project.h#L1-L41)
- [Device.h](file://h/Device.h#L1-L128)
- [Script.h](file://h/Script.h#L1-L39)
### Views目录
`Views`目录包含了所有用户界面(UI)的实现,包括主框架窗口、各种管理窗口和对话框。
- **MainFrm**:主框架窗口,是应用程序的主界面,负责管理MDI子窗口的创建和布局。
- **devmngframe**:设备管理框架,用于显示和管理设备。
- **datamngframe**:数据管理框架,用于显示和管理项目、测区和测试数据。
- **sptmngframe**:脚本管理框架,用于显示和管理脚本。
- **各种对话框**:如`DailLogin`(登录对话框)、`OpCreateProjectDlg`(创建项目对话框)等,用于用户交互。
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L1-L200)
- [MainFrm.h](file://h/MainFrm.h#L1-L120)
## 应用程序对象与管理器协调
`CGeoMativeApp`应用程序对象是整个系统的协调中心。它在`InitInstance`方法中创建并初始化所有核心管理器对象,并将它们作为成员变量存储。这些管理器通过`m_pConnection`共享同一个数据库连接,确保了数据的一致性。
```mermaid
classDiagram
class CGeoMativeApp {
+CDevManager* m_pDevManager
+CTdManager* m_pTdManager
+CProManager* m_pProManager
+CExecManager* m_pExecManager
+CSptManager* m_pSptManager
+CIOManager* m_pIOManager
+_ConnectionPtr m_pConnection
+InitInstance() bool
+ExitInstance() int
}
class CDevManager {
+CLinkList<CDevice*> m_devLinkList
+_ConnectionPtr m_pConnection
+GetDevice(DWORD) CDevice*
+InitialDevLinkList() void
}
class CProManager {
+CLinkList<CDataMngStruct*> m_dmsLinkList
+_ConnectionPtr m_pConnection
+GetDMS(DWORD) CDataMngStruct*
+ShowProList(DWORD, CListCtrl&) bool
}
class CDevice {
+DWORD m_dwID
+UINT m_uState
+CString m_szDevSN
+CString m_szMacAddress
+_ConnectionPtr m_pConnection
+GetDevInfo() bool
+Reset() bool
}
class CProject {
+DWORD m_dwID
+CString m_szPRname
+CString m_szDesc
+_ConnectionPtr m_pConnection
+ShowDetailInfo(CListCtrl&) bool
}
CGeoMativeApp --> CDevManager : "拥有"
CGeoMativeApp --> CProManager : "拥有"
CGeoMativeApp --> CDevice : "通过m_pDevManager访问"
CGeoMativeApp --> CProject : "通过m_pProManager访问"
CDevManager --> CDevice : "管理"
CProManager --> CProject : "管理"
CDevManager --> _ConnectionPtr : "使用"
CProManager --> _ConnectionPtr : "使用"
CGeoMativeApp --> _ConnectionPtr : "拥有"
```
**Diagram sources**
- [GeoMative.h](file://h/GeoMative.h#L115-L182)
- [DevManager.h](file://h/DevManager.h#L16-L68)
- [ProManager.h](file://h/ProManager.h#L30-L76)
- [Device.h](file://h/Device.h#L33-L127)
- [Project.h](file://h/Project.h#L16-L40)
## 常量与枚举的广泛应用
`Constant.h`头文件定义了系统中广泛使用的常量和枚举,为代码提供了清晰的语义和类型安全。
- **语言常量**`LANG_ZHCN``LANG_ENUS`用于标识当前用户界面语言。
- **状态常量**`PZ_STATE_OFFLINE``PZ_STATE_ONLINE`等用于表示设备、项目等实体的状态。
- **样式常量**`PZ_STYLE_PRO``PZ_STYLE_TZ``PZ_STYLE_DEV`等用于区分不同类型的实体。
- **枚举**`EN_TRANSFER_FILE_METHOD`枚举定义了文件传输方式(COM、USB、云端、WiFi),`EN_CHANNEL_INFO`枚举定义了通道信息(单通道、多通道)。
这些常量和枚举在系统各处被引用,例如在`CGeoMativeApp``InitInstance`方法中,根据`g_iTransFileMode`(其值来自`EN_TRANSFER_FILE_METHOD`)决定初始化不同的网络连接逻辑。
**Section sources**
- [Constant.h](file://h/Constant.h#L1-L266)
## 模块间调用关系示例
用户操作通过UI层触发Manager层的业务逻辑处理,这是一个典型的模块间调用流程。以用户在主界面点击“设备管理”菜单为例:
1. **UI层 (Views)**`MainFrm.cpp`中的`OnMngDevWin`消息处理函数被调用。
2. **协调层 (Main)**`OnMngDevWin`函数负责创建或激活`CDevMngFrame`设备管理窗口。
3. **业务逻辑层 (Managers)**`CDevMngFrame`在初始化时,会调用`CGeoMativeApp`的全局实例`theApp`中的`m_pDevManager`管理器的`ShowTzList``GetDevice`等方法来获取设备数据。
4. **数据模型层 (ProblemZone)**`CDevManager`通过其`m_devLinkList`链表或直接查询数据库,获取`CDevice`对象的数据。
5. **返回UI层**:获取的数据被返回给`CDevMngFrame`,并在其UI控件(如`CListCtrl`)中显示。
```mermaid
sequenceDiagram
participant User as 用户
participant MainFrm as MainFrm.cpp
participant DevMngFrame as CDevMngFrame
participant DevManager as CDevManager
participant Device as CDevice
User->>MainFrm : 点击“设备管理”
MainFrm->>DevMngFrame : 创建/激活设备管理窗口
DevMngFrame->>DevManager : 调用ShowTzList(dwProHandle, tzList)
DevManager->>DevManager : 查询数据库获取测区列表
DevManager->>Device : 通过m_devLinkList.Find()获取设备
Device-->>DevManager : 返回CDevice对象
DevManager-->>DevMngFrame : 返回测区和设备数据
DevMngFrame-->>MainFrm : 在UI上显示数据
MainFrm-->>User : 显示设备管理界面
```
**Diagram sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L58-L94)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L48-L80)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L53-L92)
## 系统架构图
```mermaid
graph TD
subgraph "UI层 (Views)"
A[MainFrm]
B[CDevMngFrame]
C[CDataMngFrame]
D[对话框]
end
subgraph "协调层 (Main)"
E[CGeoMativeApp]
end
subgraph "业务逻辑层 (Managers)"
F[CDevManager]
G[CProManager]
H[CSptManager]
I[CTdManager]
end
subgraph "数据模型层 (ProblemZone)"
J[CDevice]
K[CProject]
L[CScript]
M[CTestingZone]
end
subgraph "数据访问层"
N[数据库]
end
A --> E
B --> E
C --> E
D --> E
E --> F
E --> G
E --> H
E --> I
F --> J
G --> K
G --> M
H --> L
F --> N
G --> N
H --> N
I --> N
J --> N
K --> N
L --> N
M --> N
```
**Diagram sources**
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L56-L67)
- [DevManager.h](file://h/DevManager.h#L63-L65)
- [ProManager.h](file://h/ProManager.h#L72-L73)
- [Project.h](file://h/Project.h#L24)
- [Device.h](file://h/Device.h#L103)